[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\"@babel/env\"],\n  \"env\": {\n    \"test\": {\n      \"plugins\": [\"istanbul\"]\n    }\n  }\n}\n"
  },
  {
    "path": ".editorconfig",
    "content": "# EditorConfig is awesome: http://EditorConfig.org\n\nroot = true;\n\n[*]\n#  Ensure there's no lingering whitespace\ntrim_trailing_whitespace = true\n# Ensure a newline at the end of each file\ninsert_final_newline = true\n\n[*.js]\ncharset = utf-8\nindent_style = space\nindent_size = 2"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"extends\": \"eslint:recommended\",\n  \"parserOptions\": {\n    \"ecmaVersion\": 6,\n    \"sourceType\": \"module\"\n  },\n  \"env\": {\n    \"browser\": true,\n    \"node\": true\n  },\n  \"rules\": {\n    \"array-bracket-spacing\": [ 2, \"never\" ],\n    \"block-scoped-var\": 2,\n    \"brace-style\": [ 2, \"1tbs\", { \"allowSingleLine\": true } ],\n    \"camelcase\": [ 2, { \"properties\": \"always\" } ],\n    \"curly\": [ 2,  \"all\" ],\n    \"dot-notation\": [ 2, { \"allowKeywords\": true } ],\n    \"eol-last\": 2,\n    \"eqeqeq\": [ 2, \"allow-null\" ],\n    \"guard-for-in\": 2,\n    \"indent\": [ 2, 2, { \"SwitchCase\": 1 } ],\n    \"key-spacing\": [ 2,\n    {\n        \"beforeColon\": false,\n        \"afterColon\": true\n    }\n    ],\n    \"keyword-spacing\": [ 2 ],\n    \"new-cap\": 2,\n    \"no-bitwise\": 2,\n    \"no-caller\": 2,\n    \"no-eval\": 2,\n    \"no-extend-native\": 2,\n    \"no-iterator\": 2,\n    \"no-loop-func\": 2,\n    \"no-multi-spaces\": \"error\",\n    \"no-multi-str\": 2,\n    \"no-multiple-empty-lines\": 2,\n    \"no-new\": 2,\n    \"no-proto\": 2,\n    \"no-script-url\": 2,\n    \"no-sequences\": 2,\n    \"no-shadow\": 2,\n    \"no-spaced-func\": 2,\n    \"no-trailing-spaces\": 2,\n    \"no-unused-vars\": [ 1, { \"args\": \"none\" } ],\n    \"no-var\": 2,\n    \"no-with\": 2,\n    \"object-shorthand\": [ 2, \"methods\" ],\n    \"operator-linebreak\": [ 2, \"after\" ],\n    \"quotes\": [ 2, \"single\" ],\n    \"semi\": [ 0, \"never\" ],\n    \"space-before-blocks\": [ 2, \"always\" ],\n    \"space-before-function-paren\": [ 2, \"never\" ],\n    \"space-in-parens\": [ 2, \"never\" ],\n    \"space-infix-ops\": 2,\n    \"space-unary-ops\": [ 2,\n    {\n        \"nonwords\": false,\n        \"overrides\": {}\n    }\n    ],\n    \"strict\": 0,\n    \"valid-jsdoc\": 2,\n    \"wrap-iife\": [ 2, \"inside\" ]\n  }\n}\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n*.swp\n*.swo\n*.orig\n.idea\next/\n\n# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Dependency directory\nnode_modules\n\n# Testing\ncoverage\ntest/tmp\n.nyc_output\n\n# Users Environment Variables\n.lock-wscript\n"
  },
  {
    "path": ".npmignore",
    "content": "bower_components\ncoverage\ndocs\nsrc\ntest\ntmp\n.babelrc\n.editorconfig\n.eslintrc\n.gitignore\n.nyc_output\n.travis.yml\nbower.json\nCONTRIBUTING.md\nISSUE_TEMPLATE.md\nmarionette-logo.png\nPULL_REQUEST_TEMPLATE.md\ntrigger-deploy-mn-com.js\nupgradeGuide.md\nyarn.lock\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - \"10\"\ncache: yarn\nenv:\n  - TEST_SUITE=coverage\n  - TEST_SUITE=browser\n  - TEST_SUITE=lodash USE_LODASH=1\nafter_install:\n  - yarn install travis-ci\nscript:\n  - if [[ $TEST_SUITE = \"coverage\" ]]; then yarn run coveralls; fi\n  - if [[ $TEST_SUITE = \"browser\" ]]  && [[ $SAUCE_USERNAME ]]; then yarn run test-cross-browser; fi\n  - if [[ $TEST_SUITE = \"lodash\" ]]; then yarn run test-lodash; fi\nafter_success:\n  - if [[ $TRAVIS_BRANCH = \"master\" ]] && [[ $TRAVIS_PULL_REQUEST = \"false\" ]]; then node trigger-deploy-mn-com.js; fi\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Marionette has a few guidelines to facilitate your contribution and streamline\nthe process of getting changes merged in and released.\n\n1. [Setting up Marionette locally](#setting-up-marionette-locally)\n2. [Reporting a bug](#reporting-a-bug)\n3. [Submitting patches and fixes](#submitting-patches-and-fixes)\n4. [Running Tests](#running-tests)\n\n\n## Setting up Marionette locally\n\n* Fork the Marionette repo.\n* `git clone` your fork onto your computer.\n* Run `yarn install` to make sure you have all Marionette dependencies locally.\n* Run `yarn build` to build source files.\n\n## Reporting a bug\n\nIn order to best help out with bugs, we need to know the following information\nin your bug submission:\n\n* Marionette version #.\n* Backbone version #.\n\nIncluding this information in a submission will help us test the problem and\nensure that the bug is both reproduced and corrected on the platforms /\nversions that you are having issues with.\n\n<a name=\"format-desc\"></a>**Provide A Meaningful Description**\n\nIt is very important to provide a meaningful description with your bug reports\nand pull requests. A good format for these descriptions will include the\nfollowing things:\n\n1. The problem you are facing (in as much detail as is necessary to describe\nthe problem to someone who doesn't know anything about the system you're\nbuilding)\n\n2. A summary of the proposed solution\n\n3. A description of how this solution solves the problem, in more detail than\nitem #2\n\n4. Any additional discussion on possible problems this might introduce,\nquestions that you have related to the changes, etc.\n\nFor a PR, we need at least the first 2 items to understand why you are changing\nthe code. If not, we will ask that you add the necessary information.\n\nPlease refrain from giving code examples in altJS languages like CoffeeScript,\netc. Marionette is written in plain-old JavaScript and is generally easier for all\nmembers in the community to read.\n\n### When you don't have a bug fix\n\nIf you are stuck in a scenario that fails in your app, but you don't know how to\nfix it, submit a failing spec to show the failing scenario. Follow the\nguidelines for a pull request submission, but don't worry about fixing the\nproblem. A failing spec to show that a problem exists is a very very very\nhelpful pull request for us.\n\nWe'll even accept a failing test pasted into the ticket description instead of a\nPR. That would at least get us started on creating the failing test in the code.\n\n## Submitting patches and fixes\n\nSee [Github's documentation for pull\nrequests](https://help.github.com/articles/using-pull-requests).\n\nPull requests are by far the best way to contribute to Marionette. They are by\nfar the easiest way to demonstrate issues and your proposed resolution. To\nreally help us evaluate your pull request and bring it into Marionette, please\nprovide as much information as possible and follow the guidelines below:\n\n1. Determine the branch as your base: `next` or `master`\n2. Provide a brief summary of what your pull request is doing\n3. Reference any relevant Github issue numbers\n4. Include any extra detail you feel will help provide context\n\n### Determining your branch\n\nWhen submitting your pull request, you need to determine whether to base off\n`next` or `master`:\n\n* If you're submitting a bug fix, base off `next`\n* If you're submitting a new feature, base off `next`\n* If you're submitting documentation for a new feature, base off `next`\n* If you're submitting documentation for the current release, base off `master`\n\n### Submitting a Great Patch\n\nWe want Marionette to provide a great experience to developers and help you\nwrite great applications using it. To help us achieve this goal, please follow\nthese guidelines when submitting your patches.\n\n#### Solving Issues\n\nWhen you're submitting a bug fix, include spec tests, where applicable, showing\nthe issue and the resolution. We strive to maintain 100% code coverage in our\ntesting.\n\n#### Coding Guidelines\n\nThe Marionette coding conventions are provided in the ESLint configuration\nincluded in the repository. Most IDEs and text editors will provide, or allow\nfor, a plugin for ESLint to read the `.eslintrc` file.\nFor areas where the configuration provides no guidance, try to stick to the\nconventions in the file you're editing.\n\n#### How we Approve Pull Requests\n\nWe utilise Github's review approach. When receiving your pull request, we will\ncomment inline and provide guidance to help you get your pull request merged\ninto Marionette. This is not a one-way process and we're more than happy to\ndiscuss the context of your decisions.\n\nOnce two Marionette.js members approve the pull request, we will then merge it\ninto the base branch.\n\nPlease remember that Marionette is a community-maintained project and, as such,\nmany of us are working on this in our spare time. If we haven't commented on\nyour pull request, please be patient. We may be available on our Gitter channel\nto discuss further.\n\n## Running Tests\n\n* via command-line by running `yarn test`\n* in the browser by running `yarn test-browser`\n\nTo see the test matrix - run `yarn coverage`\n\n## Writing Tests and Code Style\n\n[More information]('test/unit/README.md')\n"
  },
  {
    "path": "ISSUE_TEMPLATE.md",
    "content": "### Description\n\n 1. The problem you are facing (in as much detail as is necessary to describe the problem to someone who doesn't know anything about the system you're building)\n 2. A summary of the proposed solution\n 3. A description of how this solution solves the problem, in more detail than item #2\n 4. Any additional discussion on possible problems this might introduce, questions that you have related to the changes, etc.\n\n### Expected behavior\n\nTell us what you think should happen.\n\n### Actual behavior\n\nIf possible, please create a small demo that demonstrates the issue.\nYou can fork https://jsfiddle.net/marionettejs/adhv48ky/ for quick demo setup.  \nPlease refrain from giving code examples in altJS languages like CoffeeScript, etc. Marionette is written in plain-old JavaScript and is generally easier for all members in the community to read.\n\n### Environment\n\n1. Marionette version:\n2. Backbone version:\n3. Additional build tools, etc:\n"
  },
  {
    "path": "PULL_REQUEST_TEMPLATE.md",
    "content": "### Proposed changes\n -\n -\n -\n\nLink to the issue:\n"
  },
  {
    "path": "bower.json",
    "content": "{\n  \"name\": \"backbone.marionette\",\n  \"description\": \"The Backbone Framework\",\n  \"homepage\": \"https://marionettejs.com/\",\n  \"version\": \"4.1.3\",\n  \"main\": \"./lib/backbone.marionette.js\",\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"backbone\",\n    \"framework\",\n    \"client\",\n    \"browser\",\n    \"composite\"\n  ],\n  \"author\": {\n    \"name\": \"Derick Bailey\",\n    \"email\": \"derickbailey@gmail.com\"\n  },\n  \"ignore\": [\n    \"docs\",\n    \"src\",\n    \"test\",\n    \".babelrc\",\n    \".editorconfig\",\n    \".eslintrc\",\n    \".gitignore\",\n    \".jscsrc\",\n    \".npmignore\",\n    \".travis.yml\",\n    \"CONTRIBUTING.md\",\n    \"upgradeGuide.md\"\n  ],\n  \"dependencies\": {\n    \"backbone.radio\": \"^2.0.0\"\n  }\n}\n"
  },
  {
    "path": "changelog.md",
    "content": "### v4.1.3 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v4.1.2...v4.1.3)\n\n#### Fixes\n* unbindRequests now passes context.\n\n### v4.1.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v4.1.1...v4.1.2)\n\n#### Fixes\n* Error in the build's version number.\n\n### v4.1.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v4.1.0...v4.1.1)\n\n#### Fixes\n* Error in the build\n\n### v4.1.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v4.0.0...v4.1.0)\n\n#### Features\n* `CollectionView#addChildView` now accepts a `preventRender` option.\n* Marionette now uses `el.ownerDocument.documentElement;` by default instead of `document.documentElement` for querying, customizable via `DomApi.getDocumentEl`.\n* The UMD build now reinstates `noConflict` for using multiple versions on the global scope.\n\n#### Fixes\n* Fixed a case where a child view could potentially get multiple `destroy` events.\n* Pre-rendered views from outside of a region will now correctly empty an current view in a region if shown.\n* `CollectionView`'s `emptyView` will now respect the `childViewContainer` for attachment.\n\n#### Misc\n* Updated backbone dependency to allow for 1.4 without a warning.\n* Tooling and testing was updated and improved removing gulp.\n* `Region._setElement` was added for internal use, but may be made public in a future release.\n\n### v4.0.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v3.5.1...v4.0.0)\n\n#### Breaking Changes\nThe breaking changes are documented in the [upgrade guide](https://marionettejs.com/docs/v4.0.0/upgrade-v3-v4.html).\n\n#### Features\n* `CollectionView` can now render a template in the same fashion of the removed `CompositeView`.\n* `View#triggers` now passes the originating DOM event object as the final argument of the triggered Mn event.\n* View classes now have the `bindRequests` and `unbindRequests` API.\n* The ES6 package was exposed in `package.json` on `jsnext:main`\n* The underscore dependency was updated to include 1.8.3 - 1.9.x.\n\n#### Documentation\nThe documentation structure was overhauled to provide a flow to reading through the docs.\n\n### v3.5.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v3.5.0...v3.5.1)\n\n#### Fixes\n* `View` entity events set in `initialize` were being undelegated if `modelEvents` or `collectionEvents` were undefined.\n\n### v3.5.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v3.4.4...v3.5.0)\n\n#### Features\n* `NextCollectionView`'s `filter` event now returns the attaching and detached views.\n* `unbindEvents` and `unbindRequests` can now be called without handlers to remove all handlers from an entity.\n\n#### Fixes\n* If an event handler on a behavior was undefined it would remove any prior defined handler.\n* When a behavior is destroyed it will now undelegate the behavior events and triggers.\n* When a view was added a performance check on `NextCollectionView` would sometimes prevent existing views from sorting correctly.\n* `NextCollectionView` `viewFilter` will now be called with the same arguments with underscore or lodash.\n\n#### Deprecations\n* Multiple handlers for a single event. If needed, use a single handler to call multiple methods.\n\n### v3.4.4 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v3.4.3...v3.4.4)\n\n#### Fixes\n* Prevent exception when a view is instantiated with a non-existing selector `el`.\n* When a collection defines the `NextCollectionView` sort order, the add at end performance improvement was removed to prevent edge case errors.\n* `NextCollectionView` no longer sorts according to the collection if `sortWithCollection` is set to false.\n* When views added to `NextCollectionView` from a collection don't have a matching model, removing the model no longer throws an error.\n\n#### Misc\n* `NextCollectionView` now uses backbone update flags instead of calculating changes for sorting\n\n### v3.4.3 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v3.4.2...v3.4.3)\n\n#### Fixes\n* `NextCollectionView` collection single model remove no longer incorrectly removes all children\n* `EmptyView` will correctly display if a `NextCollectionView` is rendered in `initialize`\n\n### v3.4.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v3.4.1...v3.4.2)\n\n#### Fixes\n* Regions will now ensure there is only one node in its `$el`\n* Regions will not query outside of the parent view if the selector is not found in its context\n* The `setDomApi` and `setRenderer` class methods now correctly return the prototype when called\n\n### v3.4.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v3.4.0...v3.4.1)\n\n#### Fixes\n* Options passed to a behavior are now correctly passed to the behavior\n* The ES6 module is no longer exposed in `package.json` as this was breaking for some builds\n* The `detachContents` will now correctly detach when using `monitorViewEvents: false` on a `NextCollectionView`\n\n### v3.4.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v3.3.1...v3.4.0)\n\n#### Features\n* A new build of Marionette supporting ES6 modules was added\n* Added DOM API to encapsulate DOM interactions in the views and region\n* `monitorViewEvents` was added as an option to all Views to disable DOM lifecycle events\n* Added `swapChildViews` to `NextCollectionView`\n* Added `viewComparator: false` option to `NextCollectionView` for disabling the default sort\n\n#### Experimental API Breaking Changes\n* DOM Mixin was removed (replaced with DOM API)\n* `NextCollectionView` `attachHtml` no longer receives the view as the first argument\n\n#### Fixes\n* A region's currentView will now be set during that view's initial `dom:refresh` event\n* A view will now be considered rendered if its `el` has contents and not only if it has an `el`\n\n#### Misc\n* While `Backbone.Radio` is still a dependency, it will no longer cause Marionette to error if nonexistent\n* Various performance improvements\n\n### v3.3.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v3.3.0...v3.3.1)\n\n#### Fixes\n* Behavior `defaults` deprecation notice was always triggering\n* Regions threw an error if a childview destroy resulted in a parent view destroy\n\n### v3.3.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v3.2.0...v3.3.0)\n\n#### Features\n* Added `removeView` and `isSwapping` to `Region` to better support animation\n* `NextCollectionView` added as a potential replacement for `CollectionView` in v4\n* Added view `initialize` event to behaviors\n* `getRegion` will now render the region's view if it is currently not rendered\n* If a `behavior` or a `region` is destroyed it will now be removed from the view\n* Added `onDomRemove` event for better clean up of things added in `onDomRefresh`\n* `childViewEventPrefix` feature flag to allow for `false` by default\n* Support custom renderers per view prototype\n\n#### Fixes\n* Trigger `detach` events when restoring el\n\n#### Deprecations\n* `template: false` deprecated in favor of `template: _.noop`\n* Behavior `defaults` deprecated in favor of setting `options` on the Behavior definition\n* `Marionette.Renderer` in favor of new custom view renderer.\n\n#### Misc\n* Update babel and build tools\n* Fix tests runner for IE11\n\n### v3.2.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v3.1.0...v3.2.0)\n\n#### Features\n* Separate Mn DOM interaction into a mixin for DOM plugin ease\n* `View.childViewEvents` should support `trigger`\n* Allow showing a template or static string in a region\n* Feature/trigger method event args\n\n#### Fixes\n* Custom `CollectionView.viewComparator` no longer sorts `collection.models`\n* `CollectionView` re-indexes correctly when removing views.\n* `CollectionView.filter` can filter by `View` child index\n* `Region` will no longer detach pre-existing HTML when `View`'s el is already in the region\n* Fix `Region` clean up when `View` is `destroy`ed\n* Destroy `CollectionView.children` by `View` and not `Model`\n\n#### Misc\n* Remove `MarionetteError` \"ViewDestroyError\" from `View`'s\n\n### v3.1.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v3.0.0...v3.1.0)\n\n#### General\n* Performance optimizations for `triggerMethod`, `mergeOptions` and other internal event handlers\n* Significant render and removal optimizations for CollectionView utilizing Backbone's `update` event\n\n#### Features\n* `Region.detachView` and `View.detachChildView` were added for removing a view from a region without destroying it. This is preferred to the now deprecated `preventDestroy` region show/empty option\n* `childViewEventPrefix: false` will disable auto-proxying of child events to the parent view\n* `Application` will now accept a region definition object literal as an instantiation option\n* Regions are now destroyed when removed from a View\n\n#### Fixes\n* Fixed an issue with Lodash 4 compatibility related to behavior events\n\n#### Deprecations\n* Region `empty`'s `preventDestroy` option was deprecated in favor of `detachView`\n* A region definition object literal's `selector` key was deprecated due to redundacy in favor of the existing key `el`\n\n#### Misc\n* Many documentation fixes for v3\n* Removed shouldReplace logic from `attachHtml` so overriding no longer breaks `replaceElement` functionality\n* Exposed `View.normalizeUIString` for external libraries\n* Improvements were made for Views initialized with existing DOM elements\n\n### v3.0.0\n\nVersion 3.0.0 of Marionette has arrived and contains many improvements over version\n2.x but also some API Changes. Below is a list of the changes made to each component.\n\nTo help the community transition over we have released a v2 patch tool to assist\nthe upgrade. [Marionette Patch Tool] (https://github.com/marionettejs/marionette-v3-compat)\n\n#### View\n* `LayoutView` + `ItemView` merge and rename to `View`.\n* `Marionette.View` -> `ViewMixin`\n* Added `LayoutView` shortcut methods such as `showChildView`.\n* `isDestroyed` and `isRendered` made private with a public accessor method.\n* Now set `_isDestroyed` to false by default\n* Call `Backbone.View` with result of options (163188eeb8)\n* `CompositeView`'s `renderChildren` is now public.\n* Renamed `childEvents` to `childViewEvents`.\n* Removed passing view options as a function\n* Renamed `templateHelpers` to `templateContext`\n* Made sure `before:render` is triggered before emptying regions.\n* Regions are not attached directly to the layout. Use `getRegion` to access the region or `showChildView` to show a `View` within it.\n* Allowed `CompositeView` to attach to existing HTML with `template:false`\n* Added `hasRegion` for layouts\n* Enabled passing `preventDestroy` to `region.empty`.\n* `View` now removes its element before destroying child regions. There was an option to turn it on, but now it’s available by default. This helps remove all of the synchronous paints going up the tree.\n\n#### CollectionView\n* The `childView` attribute now accepts a function\n* `getChildView` was removed\n* `emptyView` now accepts a function as an arg.\n* Proxied events do not append “this” as an argument\n* Removed the `apply:filter` event from `CollectionView`.\n* `removeChildView` now returns the removed view.\n\n#### Regions\n* Fixed inconsistency in `addRegion`, it now behaves like `addRegions` and adds the region to internal this.regions.\n* `View` can replace regions's el.\n* Replaced region manager with `region-mixin`.\n* Removed static `buildRegion`\n* Removed `swap` events.\n\n#### Application\n* Introduced region to `Application` (`rootRegion`)\n* Removed regions\n* Removed Initializers and Finalizers Callbacks\n* Removed Application `vent`, `commands`, `requests`\n\n#### Object\n* Added support for `Object.isDestroyed`\n\n#### ES6\n* Added Rest & Spread ES6 syntax\n* using ES6 Modules\n* Replaced `var` and `let` with `const`.\n\n#### General Enhancements\n* Added `DEV_MODE`\n* Changed `_.rest` multiple arg usage to drop for lodash 3 support.\n* Behavior, View Mixins.\n* Added `cid` field to object, application, behavior, and region\n* Added `TemplateCache` options.\n* Allow a user to define trigger handlers in options.\n* Increased Lodash compatibility, (now supports upto lodash 4)\n* Added first class support for Backbone.Radio in Mn.Object\n* Updated BB and _ deps to modern versions\n* Updated Radio from 0.9 to 2.0\n* `delegateEntityEvents`. Delegate Events used to set delegate entity events, it was extracted because now backbone calls delegateEvent everytime the element is set.\n* Added `Backbone.Babysitter` to `Mn` and removed the Babysitter dependency.\n\n#### Deprecations\n* Deprecated `CompositeView`\n* Deprecated `Behavior` Lookups.\n\n#### Removed\n* Removed `Marionette.Module` - there’s a shim that you can pull in to get Module and Deferred\n* Removed `Marionette.Deferred`\n* Removed `component.json`\n* Removed `Controller`\n* Removed `Callbacks`\n* Removed `Wreqr` (replaced with `Radio`)\n* Removed `actAsCollection`\n* Removed `_getValue`.\n\n#### API Renames\n* Renamed `render:collection` => `render:children`\n* Renamed `bindEntityEvents` => `bindEvents`.\n\n### v3.0.0-pre5\n\n#### Documentation\n\n* Improved installation docs.\n* Updated `CollectionView` docs to reflect API changes.\n* Improved `Behavior` docs.\n* Improved functions docs.\n* Improved update guide.\n* Added \"basics\" docs.\n\n#### API Changes\n\n* `emptyView` now accepts a function as an arg.\n* Removed the `apply:filter` event from `CollectionView`.\n* `removeChildView` now returns the removed view.\n* `bindEntityEvents` renamed `bindEvents`.\n* Deprecated Behavior Lookups.\n* Added Backbone.Babysitter to Mn and removed the Babysitter dependency.\n\n#### Bug fixes\n\n* `CollectionView` now only triggers `destroy:children` if it has been rendered.\n* Parent views will now successfully listen for `destroy` in `childViewEvents`.\n\n#### Misc\n\n* Replaced `var` and `let` with `const`.\n* Added consistent function declarations and added rules to eslint.\n* Tweaked peerDependencies to only allow patch versions.\n* Directory structure changes and file naming consistency.\n* Improved test coverage.\n* Removed bundled build.\n\n### v3.0.0-pre4\n\n#### Documentation\n\n* Improved `View` documentation.\n* Added `Backbone.Radio` integration documentation.\n* Fixed broken links in `CollectionView` documentation.\n* Removed `Marionette.Module` documentation.\n* Add installation documentation.\n* Removed outdated API documentation.\n* Added Upgrade Guide.\n\n#### API Changes\n\n* return `this` from all functions that do not return anything, useful for chaining.\n* Removed `getValue` and internal `getOption`.\n\n#### Bug fixes\n\n* CollectionView#reorder will no longer remove an already displayed emptyView.\n* Calling `Backbone.View` constructor with arguments consistently across all views.\n* Monitor for child already attached.\n* When a view is attached to an existing element, `isRendered()` should reflect `true`.\n* Region empty edge-case fix that prevents view destroy handlers calling `empty`.\n* Region now detaches previous html if there is no view.\n\n#### Misc\n\n* Build browser tests with rollup.\n* Fix bundled build.\n* Linter fixes.\n\nAlso, [please help us finish v3](https://github.com/marionettejs/backbone.marionette/milestones/v3.0.0)!\n\n### v3.0.0-pre3\n\n#### Dependency Updates\n\n* Backbone and Underscore moved to peerDependencies to solve dependency conflicts for browserify and webpack users.\n* Added support for Lodash 4.\n\n#### Documentation\n\n* Application documentation updates.\n\n#### API Changes\n\n* Removed unused `collection` parameter from `CollectionView.isEmpty`.\n\n#### Bug fixes\n\n* `replaceElement` and `allowMissingEl` are now able to be overridden in `Region.show`.\n\n#### Misc\n\n* Gulp test-browser task fixed.\n* es-lint fixes.\n* Added more es6 syntax.\n* Fixed the UMD exported build.\n\nAlso, [please help us finish v3](https://github.com/marionettejs/backbone.marionette/milestones/v3.0.0)!\n\n### v3.0.0-pre2\n\nExtra release to remove public release of v3.0.0-pre.1, this release is available via the `prerelease` tag on npm.\n\n### v3.0.0-pre.1\n\nThis is a \"family and friends\" release. The documentation is still mostly for 2.4.4.\nPlease let us know if you run into any issues. Also, [please help us finish v3](https://github.com/marionettejs/backbone.marionette/milestones/v3.0.0)!\n\n### v2.4.7 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.4.6...v2.4.7)\n\n#### Fixes\n\n* CollectionView#reorder will no longer remove an already displayed emptyView.\n* Fixed build of sourcemap files.\n\n### v2.4.6 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.4.5...v2.4.6)\n\n#### Misc\n\n* Updated Backbone dependency to 1.3.x.\n\n### v2.4.5 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.4.4...v2.4.5)\n\n#### Fixes\n\n* `Marionette.View#ui` will now bind events when names are hyphenated.\n* Nonexistent event handlers now fail silently.\n\n#### Misc\n\n* Updated Backbone dependency to 1.3.3.\n* devDependencies updated.\n* Updated uglify to fix deprecated sourcemap pragma //@ replaced with //#.\n\n### v2.4.4 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.4.3...v2.4.4)\n\n#### Fixes\n\n* `Region#empty` will return the region instance whether or not it has a current view.\n* `CollectionView#reorder` will now correctly respect any set filter.\n* Fixed `childEvents` failing to trigger during showing a view in a region.\n* Stop deleting the `currentView._parent` if showing the same view in a region.\n\n#### Misc\n\n* `LayoutView#showChildView` new `options` argument passed to underlying `Region#show` to enable full `show` functionality.\n* Added support for passing down arguments to `Object#destroy`.\n\n### v2.4.3 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.4.2...v2.4.3)\n\n#### Fixes\n\n* `TemplateCache#loadTemplate` accepts empty script-tag templates.\n* Parent LayoutView's `childEvents` continue working with views attached manually using `Region#attachView`.\n* When an array of items (length > 1) are added to a collection backing a CollectionView using the `at` option, the child views are appended to the DOM in the proper order.\n* When models are added to a collection backing a CollectionView with the `at` option, the child views are rendered in the proper order even when the CollectionView has a filter.\n* `CollectionView#isEmpty` respects a `false` return value even when there are no child views.\n* `Region#empty` reliably destroys views when called with options.\n* CollectionView child views can, in turn, render children within `onBeforeShow` as documented.\n* CollectionView `childView` and `emptyView` can be pure `Backbone.View` classes.\n\n#### Docs\n\n* Better documentation around view `childEvents` that reinforces the distinction between child view `triggers` and `events`.\n* Guidance on achieving full event lifecycle while using `Backbone.View` as the child view within CollectionViews or LayoutViews/Regions.\n\n#### Misc\n\n* Allow `Application` to be initialized with multiple arguments for consistency with earlier releases.\n* More comprehensive support for Backbone child views, including a more rigorous test suite and support for `render`, `destroy`, and `dom:refresh` lifecycle events when shown by CollectionViews or LayoutViews/Regions.\n* Bumped Backbone dependency to 1.2.3\n\n### v2.4.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.4.1...v2.4.2)\n\n#### Fixes\n\n* Fixed a bug where `reorderOnSort` would not reorder back to the original order.\n* Stop deleting `$childViewContainer` so that it can be accessed in behaviors.\n* Ensure `before:show` and `show` events are triggered on `CollectionView` children.\n* Ensure `onBeforeAttach` and `onAttach` are called for `CollectionView` children.\n* Allow for disabling of `triggerBeforeAttach` and `triggerAttach` via `show()` options.\n* Added the documented `buffer` argument to `attachBuffer` and changed implementation so this was used rather than `_createBuffer`.\n* Fixed potential memory leak when destroying children on `CollectionView` by making the `checkEmpty` call optional.\n\n#### Docs\n\n* Improve documentation around the requirement for an initial render to bind events in `CollectionView`.\n* Add documentation around UI interpolation usage.\n* Add documentation to warn about the full re-render of a `CollectionView` or `CompositeView` if `reorderOnSort` is not set.\n\n#### Misc\n\n* Bumped Underscore and Backbone dependencies to 1.8.3 and 1.2.1 respectively.\n\n### v2.4.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.4.0...v2.4.1)\n\n#### Fixes\n\n* Fixed a nasty bug where `reorderOnSort` when used on a `CompositeView` would not respect the `childViewContainer`.\n\n#### General\n\n* Add JSCS for style linting and consistency.\n\n#### Docs\n\n* Improve internal linking across docs, to make it easier for people to understand how pieces relate to each other.\n\n### v2.4.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.3.2...v2.4.0)\n\n#### 2.4 In Overview\n\nThe Marionette 2.4 release is primarily focused around adding power and performance to `Marionette.CollectionView’s` and `CompositeViews`. It is now possible for users to declaratively sort, filter, and reorder in a performant and clear way on the view layer. Prior to this work it was difficult and required significant workarounds.\n\nAs well as working on the `CollectionView` layer we have added full support for lodash and multiple builds of backbone, underscore and lodash. Allowing the user to pick whatever tools they wish.\n\nThe other powerful feature that we introduced in this release is the concept of `childEvents` for `LayoutView` and their subviews. Prior to this release there was never a great way to listen or react to events that were triggered on subviews, like when something was rendered or destroyed. Now we have brought over the declarative `childEvents` hash from `CollectionView` into the `LayoutView`.\n\nAs always come and join us in [chat](https://gitter.im/marionettejs/backbone.marionette/)\n\n#### Features\n\n* CollectionView\n  * You can now set a filter method on a `CollectionView` or `CompositeView` to filter what views are show. This is useful for when you are displaying a list that a user can filter.\n  * Add the `reorderOnSort` option to `CollectionView` and `CompositeView` to use jQuery to move child nodes around without having to re-render the entire tree. This is a massive perf boost and is an easy win if you are sorting your collections.\n  * The `CollectionView` now has a `viewComparator`, to enable custom sorting on a per view basis regardless of what how your backing collection is sorted.\n  * Refactor sort param lookup to use `Marionette.getOption`.\n  * **Fix** childViews now fire a `before:show` event even if the childView is inserted after the parent `CollectionView` or `CompositeView` has been shown.\n\n* Regions\n  * The `empty` method now takes an optional `preventDestroy` flag to prevent the destruction of the view shown within.\n  * `this.myRegion.empty({preventDestroy: true})`\n\n* TemplateCache\n  * The templateCache `get` method now takes a second param of options to enable passing options to the loading of templates.\n\n* LayoutView\n  * Add a new helper method for easier showing of child nodes `showChildView`\n  *  `this.showChildView('sidebar', new SidebarView());`\n  *  Add a new helper method of easier retrieving of child nodes `getChildView`\n  *  `this.getChildView(‘sidebar’)`\n  *  Add a `destroyImmediate` option to the `LayoutView`, to destroy the layout view element and then remove the child nodes. This is a perf optimization that you can now opt into.\n  *  `@ui` interpolation is now supported within region definitions on a `LayoutView`\n  *  `regionEvent` support was added\n  *  you can access this functionality via `onChildViewX` or via the declarative `childEvents` hash\n\n* ItemViews\n  * the `isRendered` property is now set to `true` after render, even if no template is set.\n  * Views\n  * The `destroy` method now returns this instance that was destroyed to enable easier chaining of view actions.\n  * If you define the options hash on your `Marionette.View` or if you pass options as a function to your `Marionette.View`, pass the result of options down to the backbone view constructor.\n  * All views now have a `isRendered` property, that is updated after `render` and `destroy`.\n\n* Object\n  * The `destroy` method now returns this instance that was destroyed to enable easier chaining of object actions.\n\n* Behavior\n  * The `destroy` method now returns this instance that was destroyed to enable easier chaining of behavior actions.\n  * Expose the `UI` hash to a behavior instance. The behavior `UI` hash is a composite of the view hash and the behavior hash merged with the behavior hash tasking precedence.\n\n#### Util\n\n* `Marionette._getValue` will now use `call` under the hood if no arguments are passed (micro optimization).\n* Add `Marionette.mergeOptions` to `Marionette.View*` classes, `Marionette.Object`. `Marionette.AppRouter`, `Marionette.Controller`\n* `mergeOptions` is a handy function to pluck certain `options` and attach them directly to an instance.\n\n#### Docs\n\n* Minor documentation cleanups and fixes\n\n#### Deprecation Notices\n\n* Deprecate `Marionette.Controller`, Use `Marionette.Object` instead.\n\n#### Misc\n\n* YAML api documentation is now linted on each PR.\n* Add `Marionette.FEATURES` flag.\n* Refactor several methods to enable 100% compatibility with lodash.\n\n### v2.3.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.3.1...v2.3.2)\n\n#### 2.3.2 in overview:\n\n##### Bug Fixes\n\n* Fix IE8 regression in `Marionette._getValue` to always call `apply` with either an array of params or an empty array.\n\n### v2.3.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.3.0...v2.3.1)\n\n#### 2.3.1 in overview:\n\n##### Features\n\n* Regions can set a `parentEl` as a way of specifying the DOM tree (default `body`) that they are scoped with. (useful for instance in `LayoutView`).\n\n```js\n  var region = new Region({parentEl: $(“#sub-tree”)})\n```\n\n##### Bug Fixes\n\n* Layout region lookups are now scoped to the layout and not to the entire DOM.\n\n* Calling `delegateEvents` after the `ui` hash has been modified now works.\n\n* Prevent unsetting event listeners on region swap when a view is swapped out from a region, but not destroyed, its DOM events will not be removed.\n\n* A view's `isDestroyed` state is now explicitly set to `false` when the view is created.\n\n##### Refactors\n\n* Added `Marionette._getValue`. This method is similar to `_.result`. If a function is provided we call it with context otherwise just return the value. If the value is undefined return a default value. This method is private and should not be used directly in your code.\n\n* Various other code refactors.\n\n### v2.3.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.2.2...v2.3.0)\n\n#### 2.3.0 in overview:\n\nThis release of Marionette contains a significant amount of code optimizations and refactors. These changes will not be visible to you as end user however as they improve the underlying base of Marionette and speed up your app to improve consistency across the base classes. Such speed ups are most visible in the great work @megawac has been doing in both [serializeData](https://github.com/marionettejs/backbone.marionette/commit/62f15dc7ec880631a0bb79b18470c94b0a0ad086) and [triggerMethod](https://github.com/marionettejs/backbone.marionette/commit/e5957dde9a9a48eeb8097a0ce2f628d795668e64)\n\nAs always you can come chat with us in the main chatroom at https://gitter.im/marionettejs/backbone.marionette/\n\nWork has been continuing on improving the documentation of Marionette, via an external custom JSDOC tool that @ChetHarrison has been spear heading via https://github.com/ChetHarrison/jsdoccer\n\nIf you have not already checked out Marionette Inspector, it is a great tool that Jason Laster has been working on to make debugging and working with marionette much easier. https://github.com/MarionetteLabs/marionette.inspector\n\n##### Features\n\n* Marionette.isNodeAttached\n  * Determines whether the passed-in node is a child of the `document` or not.\n* View \"attach\" / onAttach event\n  * Triggered anytime that showing the view in a Region causes it to be attached to the `document`. Like other Marionette events, it also executes a callback method, `onAttach`, if you've specified one.\n* View \"before:attach\" / onBeforeAttach\n  * This is just like the \"attach\" event described above, but it's triggered right before the view is attached to the `document`.\n* AppRouter Enhancements\n  * `triggerMethod`, `bindEntityEvents`, and `unbindEntityEvents` are now available on AppRouter\n* Marionette.Application is now a subclass of Marionette.Object\n* Marionette.Behavior is now a subclass of Marionette.Object\n* Marionette.Region is now a subclass of Marionette.Object\n* CompositeView’s `getChildViewContainer` now receives `childView` as a second argument.\n* Region Triggers now pass the view, region instance, and trigger options to all handler methods\n* CollectionView `emptyViewOption` method now receives the model and index as options.\n* Allow non-DOM-backed regions with `allowMissingEl`\n  * `allowMissingEl` option is respected by `_ensureElement`\n  * `_ensureElement` returns a boolean, indicating whether or not element is available\n  * Region#show early-terminates on missing element\n* Regions now ensure the view being shown is valid\n  * Allowing you to handle the error of a region.show without the region killing the currentView and breaking without recourse.\n  * Appending isDestroyed to a Backbone.View on region empty now adds the same safety for not re-showing a removed Backbone view.\n* Marionette is now aliased as Mn on the `window`.\n* Collection/Composite Views now support passing in 'sort' as both a class property and as an option.\n* RegionManager will now auto instantiate regions that are attached to the regionManager instance.\n\n```js\nnew Marionette.RegionManager({\n  regions: {\n    \"aRegion\": \"#bar\"\n  }\n});\n```\n\n##### Fixes\n\n* Region now uses `$.el.html(‘’)` instead of `.innerHTML` to clear contents.\n  * We can not use `.innerHTML` due to the fact that IE will not let us clear the html of tables and selects. We also do not want to use the more declarative `empty` method that jquery exposes since `.empty` loops over all of the children DOM nodes and unsets the listeners on each node. While this seems like a desirable thing, it comes at quite a high performance cost. For that reason we are simply clearing the html contents of the node.\n* Destroying an old view kept alive by `{preventDestroy: true}` no longer empties its former region.\n  * Now the destroy listener from previous view is removed on region show\n* AppRouter `this.options` now assigned prior to `initialize` being called.\n\n\n##### Deprecation Warnings\n\n* Marionette.Application.addInitializer\n* Marionette.Application Channel\n* Marionette.Application Regions\n* Marionette.Callbacks\n* Marionette.Deferred\n* Marionette.Module.addInitializer\n* Marionette.Module.addFinalizer\n\n\n### v2.2.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.2.1...v2.2.2)\n\n* Fixes\n\n  * Remove duplicate call to region.empty on view destroy.\n  * Fix call time of `swapOut`.\n  * Fix broken link in Marionette Error messages\n\n### v2.2.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.2.0...v2.2.1)\n\n* Fixes\n\n  * Revert collection type checking for `collectionView`.\n\n### v2.2.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.1.0...v2.2.0)\n\n* Features\n\n  * Normalize region selectors hash to allow a user to use the `@ui.` syntax\n  * `Marionette.triggerMethodOn`\n    * `triggerMethodOn` invokes `triggerMethod` on a specific context\n  * Marionette.Error\n    * `captureStackTrace` cleans up stack traces\n  * add view _behaviors reference to associated behaviors\n    * enabling you to easily test and spy on your behaviors\n  * CollectionViews now receive events from emptyViews in the childEvents hash\n  * Regions now receive `swapOut` and `beforeSwapOut` events.\n  * Application has `this.options`\n  * Application has `initialize` method\n  * Behaviors no longer wrap view methods\n\n* Bug Fixes\n\n  * LayoutView’s regions are scoped inside its `el`\n  * Fix inconsistent Marionette.Object constructor implementation.\n  * emptyView instances now proxy their events up to the collection / compositeView\n  * collection / compositeView does not listen to collection add/remove/reset events until after render.\n  * Marionette.normalizeUIKeys no longer mutates UI hash\n\n* Better Errors\n\n  * View destroyed error now includes the view cid in the error message.\n  * Throw an error when Marionette.bindEntityEvents is not an object or function\n  * Throw a descriptive error for `collectionViews`\n    * If you do not pass a valid `collectionView` instance you are now given a logical error.\n\n* Documentation Improvements\n\n  * New API docs are in progress\n  * Examples have been cleaned up\n\n### v2.2.0-pre.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.1.0...v2.2.0-pre.2)\n\n### v2.2.0-pre [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.1.0...v2.2.0-pre)\n\n### v2.1.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.0.3...v2.1.0)\n\n* Features\n\n  * Marionette.Object\n    * A base class which other classes can extend from. Marionette.Object incorporates many Backbone conventions and utilities like `initialize` and `Backbone.Events`. It is a user friendly class to base your classes on to get Backbone conventions on any generic class.\n\n  * Add a `el` reference to the views `el` from within a `behavior` instance.\n\n  * `ItemView`s can now have no template by setting `template: false`\n\n  * Application objects can now configure their default message channel.\n    * This will allow you to configure multiple applications to exist at the same time within an app without their event bus colliding.\n\n  * Application objects now have the `getOption` method.\n\n  * Regions now have a `hasView` method to determine if there is a view within a given region.\n\n  * Views no longer use toJSON directly on models. Instead they call into the new overridable methods `serializeModel` and `serializeCollection` via `serializeData`\n\n  * Return chainable objects from more methods to be consistent\n\n    * Application: emptyRegions\n    * Application: removeRegion\n    * CollectionView renderChildView\n\n    * Controller new\n    * LayoutView destroy\n\n    * Region reset\n    * Region attachView\n    * Region empty\n\n    * RegionManager destroy\n    * RegionManager emptyRegions (now returns regions)\n    * RegionManager removeRegions (now returns regions)\n    * RegionManager removeRegion (now returns region)\n    * View destroy\n    * View undelegateEvents\n    * View delegateEvents\n\n  * RegionManager `addRegions` now accepts a function that returns a region definition in addition to a region definition object\n    * This extends to Marionette.Application’s and CompositeView’s `regions` properties\n\n  * Added CollectionView `resortView`\n    * Override this method on a subclass of CollectionView to provide custom logic for rendering after sorting the collection.\n\n  * View instance is now passed as a third argument to `Marionette.Renderer.render`\n\n  * Add `getRegionManager` to Application\n\n* Fixes\n\n  * CollectionView now maintains proper order when adding a mode\n  * Fix component.js path\n  * Prevent AppRouter from erroring when appRoutes are passed into the router constructor as an option.\n  * UI hash keys now only allow documented syntax, enforcing `@ui.stuff` instead of `@ui<ANY_CHAR>stuff`\n\n### v2.1.0-pre [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.0.3...v2.1.0-pre)\n\n### v2.0.3 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.0.2...v2.0.3)\n\n  * Bug Fixes\n\n    * Fixed an issue where `before:show` was not triggered on a view's behavior when shown within a region.\n\n    * Destroying a view outside of its region will now cause the region to remove its reference to that view.\n\n### v2.0.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.0.1...v2.0.2)\n\n  * Bug Fixes\n    * Fixed issue where `render:collection` called before the entire collection and children had been rendered.\n\n  * General\n    * Remove bundled main entry point for bower.\n\n### v2.0.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.0.0...v2.0.1)\n  * Fix missing Wreqr and Babysitter in Core AMD definition.\n\n### v2.0.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.8.8...v2.0.0)\n  * This is a breaking release and contains many API updates and changes, thus changelog is quite large for this release, please refer to the [google doc](https://docs.google.com/document/d/1fuXb9N5LwmdPn-teMwAo3c8JTx6ifUowbqFY1NNSdp8/edit#) for the full details of what is new and what has changed.\n\n### v2.0.0-pre.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v2.0.0-pre.1...v2.0.0-pre.2)\n  * The changelog is quite large for this release, please refer to the [google doc](https://docs.google.com/document/d/1fuXb9N5LwmdPn-teMwAo3c8JTx6ifUowbqFY1NNSdp8/edit#)\n\n### v2.0.0-pre.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.8.5...v2.0.0-pre.1)\n  * The changelog is quite large for this release, please refer to the [google doc](https://docs.google.com/document/d/1fuXb9N5LwmdPn-teMwAo3c8JTx6ifUowbqFY1NNSdp8/edit#)\n\n### v1.8.8 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.8.7...v1.8.8)\n\n  * Fixes\n    * Fixed the case where `onShow` was not called on child view behaviors when inside a `Collection` or `Composite` view.\n\n### v1.8.7 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.8.6...v1.8.7)\n\n  * Fixes\n    * Fixed nasty ui interpolation bug with behaviors.\n\n  * General\n    * Minor Doc cleanup\n\n### v1.8.6 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.8.5...v1.8.6)\n\n  * Regions\n    * `Region.show` now returns the region instance to allow for region operation chaining.\n    * `Region.show` triggers the view's native `triggerMethod` if it exists. This is to handle the case that triggerMethod is wrapped by a `Marionette.Behavior`.\n\n  * General\n    * Update jquery 2.x upper bound dependency restrictions.\n    * The grunt test command will now complain if you do not have bower components installed.\n    * Readme cleanups.\n\n### v1.8.5 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.8.4...v1.8.5)\n\n  * Fixes\n    * Update the UMD build to be inline with the 2.x branch UMD implementation.\n\n### v1.8.4 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.8.3...v1.8.4)\n\n  * General\n    * Update bundled build to use the latest version of babysitter and wreqr.\n\n### v1.8.3 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.8.2...v1.8.3)\n\n  * Fixes\n    * Behaviors now have access to the views options and events during their initialize.\n\n### v1.8.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.8.0...v1.8.2)\n\n  * Fixes\n    * Behaviors now calls `stopListening` on close.\n    * Behaviors now undelegate `modelEvents` and `collectionEvents` when the parent view calls `undelegateEvents`.\n\n### v1.8.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.7.4...v1.8.0)\n\n  * General\n    * Update Gruntfile.\n    * The default task (`grunt`) now runs tests.\n    * `$ grunt dev` watch for watching.\n    * `$ grunt build` runs the tests and compiles.\n    * Add better inline documentation for module implementation.\n    * Add better inline behavior documentation.\n\n  * Fixes\n    * Behaviors now correctly lookup methods for `modelEvents` and `collectionEvents`.\n    * The `CollectionView` now triggers close on its children in the correct order.\n\n  * Features\n    * Add `onRoute` to the `appRouter`.\n    ```js\n      Marionette.AppRouter.extend({\n        onRoute: function(route, params) {\n        }\n      })\n    ```\n    * `Region.show` now takes an option to prevent closing the previous view in the region. By default a region will automatically close the previous view, however you can prevent this behavior by passing `{preventDestroy: true}` in the options parameter.\n    ```js\n    myRegion.show(view2, { preventDestroy: true })\n    ```\n    * Add a `getRegion` method to `Layout`. This is in line with the eventual goal of not attaching regions to the root layout object.\n    * Behavior instances now extend from Backbone.Events, allowing you to use `.listenTo` and `.on`.\n\n    * Allow Behaviors to have a functional hash lookup.\n    ```js\n      Marionette.ItemView.extend({\n        behaviors: function() {\n          // “this” will refer to the view instance\n          return : {\n            BehaviorA: {}\n          }\n        }\n      })\n    ```\n    * RegionManagers now calls `stopListening` on a regions on removal.\n\n  * Refactors\n    * Abstract underscore collection method mixin into a generic helper.\n    * Use built in marionette extend for behaviors.\n\n  * Tests\n    * Add a whitespace linter to the text coverage. Trailing whitespace now causes travis.ci to fail.\n    * Add test coverage for `bindEntitiyEvents` and `unbindEntityEvents`.\n    * Test public API for the `regionManager`.\n    * Improve view trigger tests for better control when testing.\n\n### v1.7.4 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.7.3...v1.7.4)\n\n* General\n  * Update bower dependencies to take advantage of the fact that marionette repos follow semver.\n\n* Fixes\n  * Behaviors events no longer collide with each other.\n  * Revert `stopListening` call on `stop` for modules. While this was a \"fix\", the docs were quite vague leading to breaking changes for many people.\n  * `startWithParent` is now respected when using a `moduleClass` property.\n\n### v1.7.3 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.7.2...v1.7.3)\n\n* Behaviors\n  * Adds the ability to use `@ui` interpolation within the events hash on a behavior.\n\n* Fixes\n  * Corrects broken view $el proxy in behaviors.\n\n### v1.7.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.7.1...v1.7.2)\n\n* Fixes\n  * Binds behavior events to the behavior instance, as compared to the view.\n\n### v1.7.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.7...v1.7.1)\n\n* Fixes\n  * Enables the use of string based behavior event methods.\n\n### v1.7.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.6.4...v1.7)\n\nVersion 1.7 represents a significant step in formalizing the ways to improve your `view` code though reusable `behaviors`. Say goodbye to custom mixin strategies and welcome `behaviors` into town.\n\n* Behaviors\n\n    A `Behavior` is an isolated set of DOM / user interactions that can be mixed into any `View`. `Behaviors` allow you to blackbox `View` specific interactions into portable logical chunks, keeping your `views` simple and your code DRY. **[Read the docs here.](https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.behavior.md)**\n\n* Modules\n    * Call stop listening on module stop.\n\n* Events\n    * add a before:show event for views and regions\n\n* Docs\n    * Entire refactor of application docs.\n\n* Tests\n    * Rework the module tests to improve readability and consistency.\n\n* General\n    * switch from `~` to `^` for *trusted* dependencies.\n\n### v1.6.4 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.6.3...v1.6.4)\n  * Fixes\n    * Patches a bug that would cause modules to be initialized twice when a custom module class is passed\n\n### v1.6.3 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.6.2...v1.6.3)\n  * Improvements\n    * Enable more direct module instantiation on `Marionette.App`.\n      ```js\n        var ItemModule = Marionette.Module.extend({\n          startWithParent: false,\n          initialize: function(options) {},\n          onStart: function() {}\n        });\n\n        // ...\n\n        this.app.module('Items', ItemModule);\n      ```\n    * `ui` hash interpolation now supports a functional `ui` hash.\n\n      ```js\n        ui: function() {\n          return {\n            \"foo\": \".foo\"\n          }\n        }\n      ```\n  * Fixes\n    * Fix `@ui` interpolation for handling complex selectors.\n\n      ```js\n        {\n          \"click div:not(@ui.bar)\": \"tapper\"\n        }\n      ```\n    * Bump `backbone.babysitter` and `backbone.wreqr` versions.\n  * General\n    * Improve readme docs for `CollectionView`, `AppRouter` and `ItemView`.\n    * Handle THE [npm self sign cert problem](http://blog.npmjs.org/post/78085451721/npms-self-signed-certificate-is-no-more)\n    * Replace unneeded argument slicing.\n    * Normalize error throwing to use internal `throwError` helper method.\n    * Use `_` type checks for non performant code to improve readability and consistency.\n\n### v1.6.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.6.1...v1.6.2)\n  * CollectionView/CompositeView\n    * allow `itemEvents` to use string based method names [PR 875](https://github.com/marionettejs/backbone.marionette/pull/875)\n  * Modules\n\t* update module initialize to include moduleName and app [PR 898](https://github.com/marionettejs/backbone.marionette/pull/898)\n  * General\n  \t* significantly improve module documentation [PR 897](https://github.com/marionettejs/backbone.marionette/pull/897)\n\n### v1.6.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.6.0...v1.6.1)\n  * Modules\n    * Fix a bug where a module would not start by default when defined as an object literal\n\n### v1.6.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.5.1...v1.6.0)\n  * CompositeView\n    * add a `composite:collection:before:render` event\n\n  * CollectionView\n    * `checkEmpty` can now be overridden\n\n  * Modules\n    * `Modules` can now be created using the extend method, and then attached to an [Application](https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.application.module.md#extending-modules).\n\n  * General\n    * add a component.json file\n    * update bower.json\n    * add AMD build in bower.json\n\n  * Tests\n    * general clean up\n    * add sinon.js for test spys\n\n### v1.5.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.5.0...v1.5.1)\n  * CollectionView/CompositeView\n    * Fix bug where `show` and `onDomRefresh` was not called on `itemViews` in certain [conditions](https://github.com/marionettejs/backbone.marionette/pull/866)\n\n### v1.5.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.4.1...v1.5.0)\n  * Views\n    * View `options` can now be a [function](https://github.com/marionettejs/backbone.marionette/pull/819)\n    * `onDomRefresh` is now only called when said `view` is in the [DOM](https://github.com/marionettejs/backbone.marionette/pull/855)\n\n  * CollectionView/CompositeView\n    * `itemViewContainer` is now called with the correct [context](https://github.com/marionettejs/backbone.marionette/pull/841)\n    * Fix bug where reseting a `collection` within a `collectionView` would cause `onShow` and `onDomRefresh` to be called [incorrectly](https://github.com/marionettejs/backbone.marionette/pull/849) on the itemViews.\n    * `addItemView` now returns the `view` that was [added](https://github.com/marionettejs/backbone.marionette/pull/851)\n    * You can now specify an `itemEvents` hash or method which allows you to capture all bubbling itemEvents without having to [manually set bindings](https://github.com/marionettejs/backbone.marionette/pull/861).\n\n    ```js\n    itemEvents: {\n      \"render\": function() {\n        console.log(\"an itemView has been rendered\");\n      }\n    }\n    ```\n\n  * Regions\n    * Region `close` event now passes the `view` being closed with the [event](https://github.com/marionettejs/backbone.marionette/pull/834).\n\n  * General\n    * Updated bower ignore folder\n    * Added an editor config file\n\n### v1.4.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.4.0...v1.4.1)\n* Views\n  * fix for inital view class options. Now retains set options at class instantiation\n\n### v1.4.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.3.0...v1.4.0)\n* Views\n  * adds the ability to use the new ```@ui.``` syntax within the events and triggers hash to prevent selector duplication\n\n### v1.3.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.2.3...v1.3.0)\n* CompositeView / CollectionView\n  * Massive perf boost in rendering collection and composite views by using document fragments [jsPerf](http://jsperf.com/marionette-documentfragment-collectionview/5)\n\n### v1.2.3 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.2.2...v1.2.3)\n* CompositeView\n  * Fixed bug where ```child views``` were being added before the initial render, thus raising errors.\n\n### v1.2.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.2.1...v1.2.2)\n* Views\n\t* Move the instantiation of ```view``` options above the ```constructor``` This allows for view options to be accessed from within the ```initialize``` method for a given ```view```\nThis is needed since backbone views no longer set the view options in the constructor\n\n### v1.2.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.2.0...v1.2.1)\n* Views\n  * fixed a bug so now view options are {} by default and not undefined.\n  * fixed a bug where the triggers preventDefault and stopPropagation were executing in the wrong context – triggers now prevent default and stop propagation by default once more.\n\n### v1.2.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.1.0...v1.2.0)\n* Update Backbone to [1.1.0](https://github.com/jashkenas/backbone/compare/1.0.0...1.1.0)\n\n* Views\n  * added the ability to customize the behavior of `triggers` preventDefault and stopPropagation\n\n* Collection View / CompositeView\n  * added the ability to specifiy `getEmptyView` for dynamic `emptyView` lookups\n\n### v1.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.4...v1.1.0)\n\n* Marionette.View / All Views\n  * Fix for `ui` bindings to not be removed from view prototype, if unrendered view is closed\n  * Template helpers can now be provided as a constructor function option\n\n* Layout\n  * Will properly attach regions if the layout's `close` method was called prior to `render`\n  * Calling `.addRegions` will correctly modify the layout instance' region list instead of the prototype's\n  * Fixed bug that prevented default `regionType` from being used\n\n* CompositeView\n  * The `itemViewContainer` can be supplied in the constructor function options\n\n* Application\n  * Added `closeRegions` method to close all regions on the app instance\n  * Added `getRegion` method to retrieve a region by name\n\n* AppRouter\n  * Added `appRoute` method to create app router handlers at runtime\n  * Added ability to set `appRoutes` in constructor function options\n\n* Marionette.triggerMethod\n  * Calls to the `Marionette.triggerMethod` can be made on objects that do not have a `trigger` method\n\n### v1.0.4 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.3...v1.0.4)\n\n* ItemView\n  * Added needed `constructor` function back - it added lots of things and needed to be there\n\n* CompositeView\n  * Added explicit call to CollectionView constructor to allow for inheritance overriding\n\n* Layout\n  * Small clarification for consistency on call to ItemView constructor\n\n### v1.0.3 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.2...v1.0.3)\n\n* ItemView\n  * Deleted unneeded `constructor` function - it added nothing and didn't need to be there\n\n* CompositeView\n  * Added `index` parameter to method signature, to show that it is available\n  * Deleted unneeded `constructor` function and removed call to `getItemView` as it was causing problems and was not needed in the constructor.\n\n* All Views\n  * Fixed a bug in the entity and collection event bindings, where `stopListening` would not unbind the event handlers\n\n* Renderer / All Views\n  * The `Renderer.render` method will throw a more meaningful error if the supplied template is falsey\n\n* Region\n  * Re-showing a closed view now works by re-rendering and re-inserting the view in to the DOM\n  * Region will trigger a `show` event when showing a view (updated the code to work like the docs already said)\n  * Set the `currentView` before triggering the `show` events from the region / view\n\n* RegionManager\n  * Fixed a bug to decrement the `.length` when a region is removed\n\n### v1.0.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.1...v1.0.2)\n\n* UI Elements\n  * Fix bug to unbind them after the \"close\" event / `onClose` method, so the `ui` elements are available during these\n\n* AppRouter\n  * Fix bug that was reversing the order of routes, causing the wrong route to be fired in many cases\n\n### v1.0.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.0...v1.0.1)\n\n* AMD build: Removed `require('jQuery')` as Marionette now pulled `Backbone.$` as\n    `Marionette.$`.\n\n* Fixed RegionManager to allow region types to be specified again, not just\n  region instances.\n\n* NPM: Removed hard dependency on jQuery from the dependency list. This will\n  be pulled in by other libs, or should be pulled in manually, to get the\n  right version.\n\n### v1.0.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.0-rc6...v1.0.0)\n\n* RegionManager\n  * Created new `Marionette.RegionManager` object to manage a set of regions\n\n* Region\n  * Region will call the `close` method on a view, or the `remove` method if `close` is not found, when closing a view\n  * When calling the `show` method with the same view instance multiple times, subsequent calls will only re-render the view and not close / re-open it\n\n* Application\n  * Now uses `Marionette.RegionManager` to manage regions\n\n* Layout\n  * Now uses `Marionette.RegionManager` to manage regions\n  * Now supports dynamic add / remove of regions\n  * Can specify `regions` as a function that takes an `options` argument (the view's constructor options)\n\n* CollectionView / CompositeView\n  * When specifying `itemViewOptions` as a function, an item `index` argument will be passed as the second parameter\n  * Will call the `close` or `remove` method when closing a view, with `close` method taking precedence\n\n* CompositeView\n  * Fixed a bug that caused an error when the collection was `reset` (loaded) before the view was rendered\n\n* All Views\n  * Closing a view will properly unbind `ui` elements\n  * Closing and then re-rendering a view will re-bind the `ui` elements\n\n* Functions\n  * Removed the `Marionette.createObject` function - it was never used by Marionette, directly\n\n* jQuery\n  * Replaced direct calls to `$` with new `Marionette.$`, which is assigned to\n    `Backbone.$` for consistency w/ Backbone.\n\n* Backbone.Wreqr\n  * Updated to v0.2.0\n  * Renamed `addHandler` method to `setHandler`\n  * For more information, see the [Wreqr changelog](https://github.com/marionettejs/backbone.wreqr/blob/master/CHANGELOG.md)\n\n* Code Cleanup\n  * Replaced `that = this` with the `context` param of several calls to `_.each` to clean up the code\n  * Removed an unused method from the CompositeView implementation\n\n* Build process\n  * Updated to Grunt v0.4.x\n  * Added code coverage and other analysis reports\n\n### v1.0.0-rc6 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.0-rc5...v1.0.0-rc6)\n\n* CompositeView\n  * Corrected the timing of the \"before:render\" event / `onBeforeRender` callback, so that it will be called before serializing the data for the model / template\n\n### v1.0.0-rc5 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.0-rc4...v1.0.0-rc5)\n\n* CollectionView / ItemView\n  * Corrected the timing on the \"show\" event / `onShow` callback for itemView instances that are added after the CollectionView is in the DOM\n\n### v1.0.0-rc4 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.0-rc3...v1.0.0-rc4)\n\n* EventBinder\n  * **BREAKING:** Removed `Marionette.addEventBinder` function.\n\n* EventAggregator\n  * **BREAKING:** Removed `Marionette.EventAggregator` object. Use `Backbone.Wreqr.EventAggregator` instead\n\n* CollectionView / CompositeView\n  * Fixed several issues related to resetting the collection, and producing zombie \"empty\" views\n  * Fixed a bug that caused multiple emptyView instances when resetting the collection\n  * Forwarded events from child views are now called with `triggerMethod`, meaning they trigger the event and call the corresponding \"onEventName\" method\n\n* Modules\n  * Finalizers now run with the module as the `this` context\n\n* Marionette.getOption\n  * Fixed support for \"falsey\" values in an object's `options`\n\n* Build process\n  * Fixed build process to work on case-sensitive file systems (Linux, for example)\n\n### v1.0.0-rc3 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.0-rc2...v1.0.0-rc3)\n\n* Updated Backbone v0.9.10\n\n* Updated jQuery to v1.9.0\n  * Fixed a few minor unit test issues w/ jQuery update\n\n* Read [the upgrade guide](https://github.com/marionettejs/backbone.marionette/blob/master/upgradeGuide.md) for upgrading from v1.0.0-rc2 to v1.0.0-rc3\n\n### v1.0.0-rc3 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.0-rc2...v1.0.0-rc3)\n\n* **IMPORTANT:** Be sure to read [the upgrade guide](https://github.com/marionettejs/backbone.marionette/blob/master/upgradeGuide.md) for upgrading from v1.0.0-rc2 to v1.0.0-rc3\n\n* Backbone v0.9.9\n  * **BREAKING:** Backbone v0.9.2 is no longer supported\n  * Backbone v0.9.9 is now supported\n\n* Marionette.Async\n  * **BREAKING:** Marionette.Async is no longer supported\n\n* Backbone.EventBinder / Marionette.EventBinder\n  * **BREAKING:** Marionette.EventBinder / Backbone.EventBinder have been removed entirely.\n  * Backbone.Events supercedes the older objects\n  * Backbone.Wreqr.EventAggregator also supercedes Marionette.EventBinder\n\n* EventBinder -> EventAggregator\n  * **BREAKING:** Backbone.Werqr.EventAggregator largely replaces Backbone.EventBinder\n  * **BREAKING:** `bindTo` has been replaced with `listenTo`\n  * **BREAKING:** `unbindAll` has been replaced with `stopListening`\n  * **BREAKING:** `unbindFrom` has been removed and will not be replaced\n\n* Marionette.addEventBinder\n  * **BREAKING:** This function will mix in Backbone.Events to the target object if it does not exist\n  * **BREAKING:** This function will alter the `listenTo` method of the target to accept a `context` parameter as the 4th parameter of the method\n\n* All Views, Controller, etc\n  * **BREAKING:** Backbone.EventBinder is no longer mixed in\n  * **BREAKING:** See 'EventBinder -> EventAggregator' changes regarding method names to use for binding / unbinding events\n\n* CollectionView\n  * Added `removeChildView` to remove a specific view instance\n  * Fixed event handler leak for child views that have been removed\n  * Changed the implementation for triggering the \"show\" event / \"onShow\" method call, to avoid memory leaks\n  * Fixed the `index` parameter for adding a model to the collection, and getting the view in to the right place\n\n* All Views\n  * **BREAKING:** The `initialEvents` method has been removed. Use the `initialize` method, the `collectionEvents` or `modelEvents` configuration instead.\n  * Allow `modelEvents` and `collectionEvents` to be a function that returns a hash\n  * Allow `ui` configuration to be a function that returns a hash\n  * `modelEvents` and `collectionEvents` are now delegated / undelegated with Backbone.View's `.delegateEvents` and `.undelegateEvents` method calls\n  * View `triggers` now include an `args` object with `args.view`, `args.model` and `args.collection`\n\n* Modules\n  * Added alternate syntax for specifying `startWithParent` option\n  * Fixed a bug where a module would not be started without an explicit definition for that module (#388 & #400)\n\n### v1.0.0-rc2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.0-rc1...v1.0.0-rc2)\n\n* CollectionView / CompositeView\n  * **BREAKING: ** Changed the `item:added` event to `before:item:added` and `after:item:added`\n  * Fixed the `onShow` callbacks, so they can be used in the `initialize` method\n\n* AMD build\n  * Fixed the AMD build by adding Backbone.BabySitter to the AMD dependency list\n\n* All Views\n  * All views (include Marionette.View) now have a \"dom:refresh\" and `onDomRefresh` event / method triggered\n\n### v1.0.0-rc1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.0-beta6...v1.0.0-rc1)\n\n* Fixed IE < 9 support w/ calls to `.apply` when `arguments` was null or undefined\n\n* Module\n  * **BREAKING:** Renamed \"initialize:before\" event to \"before:start\", for consistency\n  * **BREAKING:** Renamed \"initialize:after\" event to \"start\", for consistency\n  * Triggers a \"before:stop\" event/method before the module is stopped\n  * Triggers a \"stop\" event/method after the module has been stopped\n\n* Marionette.View\n  * **BREAKING**: The `bindBackboneEntityTo` method has been removed from Marionette.View and replaced with `Marionette.bindEntityEvents` function.\n\n* Marionette.bindEntityEvents\n  * This function has been extracted from Marionette.View, and will bind an events hash to the events from an entity (model or collection), using the supplied EventBinder object (or any object with a bindTo method)\n\n* Marionette.EventBinder\n  * The context of the callback method defaults to the object w/ the `bindTo` method\n\n* CollectionView / CompositeView\n  * The \"item:added\"/`onItemAdded` callback method are now fired after an item view has been rendered and added to it's parent collection view\n  * The \"itemview:\" events - events that are forwarded from item views - can now have a custom prefix with the `itemViewEventPrefix` setting\n\n* ItemView\n  * Added a \"dom:refresh\" event/callback method that fires after a view has been rendered, placed in the DOM with a Marionette.Region, and is re-rendered\n\n* All Views\n  * The `modelEvents` and `collectionEvents` can now have a function configured as the value in the `{ \"event:name\": \"value\" }` configuration hash\n  * A view that uses `bindTo` for its own \"close\" event will have it's close handler called correctly\n  * Returning `false` from the `onBeforeClose` method will prevent the view from being closed\n\n### v1.0.0-beta6 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.0-beta5...v1.0.0-beta6)\n\n* CollectionView / CompositeView\n  * **BREAKING:** The `.children` attribute, used to store child views, is no longer an object literal. It is now an instance of `Backbone.ChildViewContainer` from Backbone.BabySitter\n  * Updated to use [Backbone.BabySitter](https://github.com/marionettejs/backbone.babysitter) to store and manage child views\n\n* Controller\n  * Added a default `close` method to unbind all events on the controller instance and controller event binder\n  * Trigger a \"close\"/onClose event/method when closing\n  * Fixed initialize method so `options` parameter is always a valid object\n\n* Modules\n  * Fixed an issue with grand-child modules being defined with a non-existent direct parent, and starting the top level parent directly\n\n### v1.0.0-beta5 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.0-beta4...v1.0.0-beta5)\n\n* Modules\n  * Fixed the `startWithParent` option so that you only have to specify `startWithParent: false` once, no matter how many files the module definition is split in to\n\n### v1.0.0-beta4 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.0-beta3...v1.0.0-beta4)\n\n* CollectionView / CompositeView\n  * **BREAKING:** Changed when the `itemViewOptions` gets called, in order to simplify the `buildItemView` method and make it easier to override\n  * **BREAKING:** The `storeChild` method now requires an instance of the item being rendered, as well as the view that was rendered for it\n\n* CompositeView / templateHelpers\n  * **BREAKING:** Fixed the `CompositeView` so that `serializeData` is no longer responsible for mixing in the `templateHelpers`\n\n* Controller\n  * Added a very basic `Marionette.Controller` object, and basic documentation for it\n\n* Marionette.getOption\n  * Added a convience method to get an object's options either from the object directly, or from it's `this.options`, with `this.options` taking precedence\n  * Converted use of `this.options` to use `Marionette.getOption` through most of the code\n\n* Marionette.createObject\n  * Added a convience method to create an object that inherits from another, as a wrapper / shim around `Object.create`\n\n### v1.0.0-beta3 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.0-beta2...v1.0.0-beta3)\n\n* Region\n  * Fixed \"show\" method so that it includes the view instance being shown, again\n\n### v1.0.0-beta2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v1.0.0-beta1...v1.0.0-beta2)\n\n* templateHelpers\n  * **BREAKING:** Changed when the templateHelpers is mixed in to the data for a view, so that it is no longer dependent on the `serializeData` implementation\n\n* Region\n  * **BREAKING:** Changed \"view:show\" event to \"show\"\n  * **BREAKING:** Changed \"view:closed\" event to \"close\"\n  * All region events and events that the triggers from a view are now triggered via Marionette.triggerMethod.\n\n* Marionette.EventAggregator\n  * **BREAKING:** The `bindTo` method no longer assumes you are binding to the EventAggregator instance. You must specify the object that is triggering the event: `ea.bindto(ea, \"event\", callback, context)`\n  * Marionette.EventAggregator combines Backbone.Wreqr.EventAggregator with Backbone.EventBinder, allowing the event aggregator to act as it's own event binder\n\n* CollectionView\n  * Fixed bug where adding an item to a collection would not allow the CollectionView to propagate the itemView's events\n  * Allow `itemViewOptions` to be specified in CollectionView constructor options\n\n* Application\n  * The events triggered from the Application object instance are now triggered with corresponding \"on{EventName}\" method calls\n\n* Backbone.EventBinder\n  * Updated to v0.1.0 of Backbone.EventBinder, allowing for jQuery/DOM events to be handled within the EventBinder instances / `bindTo` methods\n\n* AMD Wrapper\n  * The \"core\" AMD wrapper specifies Backbone.Wreqr and Backbone.EventBinder\n  * The \"standard\" AMD wrapper does not specify Backbone.Wreqr / EventBinder, as these are built in\n\n* Build / downloads\n  * The standard and AMD versions of `backbone.marionette.js` and `backbone.marionette.min.js` include all dependencies (EventBinder, Wreqr)\n  * The \"core\" versions of `backbone.marionette.js` and `backbone.marionette.min.js` do not include any dependencies (EventBinder, Wreqr)\n\n### v1.0.0-beta1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.10.2...v1.0.0-beta1)\n\n* Backbone.EventBinder\n  * **BREAKING:** Marionette's EventBinder has been extracted to the Backbone.EventBinder repository and plugin. You must include this file in your app, available at https://github.com/marionettejs/backbone.eventbinder\n\n* Backbone.Wreqr\n  * **BREAKING:** Marionette's EventAggregator has been extracted to the Backbone.Wreqr repository and plugin. You must include this file in your app, available at https://github.com/marionettejs/backbone.wreqr\n\n* All Views\n  * **BREAKING:** `beforeRender` method is now `onBeforeRender`\n  * **BREAKING:** `beforeClose` method is now `onBeforeClose`\n  * **BREAKING:** The `render` method for all Marionette views is bound to the view instance\n  * All view events are now triggered with `triggerMethod`, calling their corresponding method on the view if it exists\n  * All views now have an `isClosed` attribute on them, which is set to `true` when calling the `close()` method and reset to `false` when calling the `render()` method\n  * EventBinder is now attached to the views with the `Marionette.addEventBinder` method call\n\n* CompositeView\n  * **BREAKING:** CompositeView will only render a model in to it's template, instead of a model or collection. It will still render the collection as itemView instances.\n\n* Modules\n  * **BREAKING:** Split module definitions can now receive custom args per module definition, instead of sharing / replacing them across all definitions\n\n* CollectionView / CompositeView\n  * Cleaned up the `getItemViewContainer` code, and improved the error that is thrown when the specified container element is not found\n  * Can attach existing view instance w/ existing DOM element as child of collection view / composite view, in parent's `initialize` function\n  * Fixed a bug where an undefined `this.options` would prevent child views from being rendered, trying to find the index of the view\n\n* Layout\n  * Allow a Layout to be defined without `regions`, using Underscore v1.4.x\n\n* View / ItemView / CompositeView\n  * Removed the `serializeData` method and added directly to `ItemView` and `CompositeView` as needed\n\n* Application\n  * Application regions can now be specified as a jQuery selector string, a region type, or an object literal with a selector and type: `{selector: \"#foo\", regionType: MyCustomRegion}`\n  * added `.commands` as instance of Backbone.Wreqr.Commands, to facilitate command execution\n  * added `.execute` method for direct command execution\n  * added `.reqres` as instance of Backbone.Wreqr.RequestResponse, to facilitate request/response execution\n  * added `.request` method for direct requesting of a response\n\n* Marionette.triggerMethod\n  * Added `Marionette.triggerMethod` method to trigger an event and call the corresponding method. For example, `view.triggetMethod(\"before:render\")` will trigger the \"before:render\" event and call the `onBeforeRender` method.\n\n* Marionette.addEventBinder\n  * Added `Marionette.addEventBinder` method to add all of the Backbone.Wreqr.EventBinder methods to a specified target object\n\n* Misc\n  * Added `Marionette.extend` as alias to Backbone's `extend` method for more consistent use\n  * jQuery ($) support now works from global `$` or `window.jQuery`\n  * Updated to Underscore.js v1.4.1\n  * Updated to jQuery v1.8.2\n\n### v0.10.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.10.1...v0.10.2)\n\n* Callbacks\n  * Fixed a bug that caused callbacks to fire multiple times after calling `reset`\n\n* Layout\n  * Fixed a bug that prevented the regions from being re-initialized correctly, when using `render` as a callback method for an event\n\n### v0.10.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.10.0...v0.10.1)\n\n* Modules\n  * Fixed a bug when defining modules in reverse order, that prevented `startWithParent` from working correctly\n\n### v0.10.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.9.13...v0.10.0)\n\n* Modules\n  * **BREAKING:** Module definition functions are executed immediately and only once, not every time you call `start`\n  * **BREAKING:** Renamed `startWithApp` to `startWithParent` in module definitions\n  * **BREAKING:** Sub-modules rely on the parent module to start them, by default, but can be started manually\n  * **BREAKING:** Sub-modules default to starting with their parent module start\n  * **BREAKING:** Specifying `startWithParent: false` for a sub-module will prevent the module from being started when the parent starts\n  * **BREAKING:** Specifying `startWithParent: false` for a top-level module will prevent the module from being started when the parent `Application` starts\n  * **BREAKING:** When starting a module, sub-modules will be started / initialized before parent modules (depth-first hierarchy traversal)\n  * **BREAKING:** When stopping a module, sub-modules will be stopped / finalized before parent modules (depth-first hierarchy traversal)\n  * Fixed: retrieving a module by name (`var foo = MyApp.module(\"Foo\");`) will not change the module's definition or `startWithParent` setting\n\n* CollectionView\n  * Allow `itemViewOptions` to be a function, which recieves the `item` as an argument\n\n* Callbacks\n  * Added `reset` method to reset the list of callbacks and allow them to be run again, when needed\n\n### v0.9.13 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.9.12...v0.9.13)\n\n* CollectionView\n  * Fixed bug that prevented \"collection:closed\" event from being triggered\n  * Allow different item view to be rendered for each item in collection by overriding `getItemView` method\n\n* CompositeView\n  * Allow different item view to be rendered for each item in collection by overriding `getItemView` method\n\n* Layout\n  * Regions are initialized before prototype constructor, or `initialize` function are called\n\n* All Views\n  * Adds declarative event binding for models and collections. See [Marionette.View documentation](https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.view.md) for more information.\n\n* Build and test\n  * Removed all dependencies on Ruby, in favor of NodeJS and Grunt\n\n### v0.9.12 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.9.11...v0.9.12)\n\n* Moved [Marionette.Async](https://github.com/marionettejs/backbone.marionette.async) to it's own repository\n* De-linted source code\n* Corrected throwing an \"Exception\" to throwing an \"Error\"\n\n### v0.9.11 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.9.10...v0.9.11)\n\n* JamJS Support\n  * Updated the `package.json` file with more detail and support for [JamJS](http://jamjs.org/).\n\n* Layout\n  * Fixed a global variable leak\n\n### v0.9.10 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.9.9...v0.9.10)\n\n* ItemView and Layout\n  * **BREAKING:** Removed the default implementation of `initialEvents`, so that a collection \"reset\" event won't cause the ItemView or Layout to re-render\n* Build Process\n  * Changed from Anvil.js to Grunt.js for the build process\n\n### v0.9.9 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.9.8...v0.9.9)\n\n* Regions\n  * Added a `reset` method to regions, which closes the open view and deletes the region's cached `el`\n\n### v0.9.8 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.9.7...v0.9.8)\n\n* Modules\n  * Fixed a bug that ensures modules will start and stop the correct number of times, instead of always stopping immediately after they have been stopped once\n\n### v0.9.7 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.9.6...v0.9.7)\n\n* Modules\n  * Fixed a bug to ensure modules are only started once, no matter how many definitions the module is split in to\n\n* View Templates\n  * Better support for pre-compiled templates - can specify a function as the `template` setting for a view, and the function will be run as the template, directly.\n\n### v0.9.6 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.9.5...v0.9.6)\n\n* All Marionette Views\n  * Fixed bug that prevented `bindTo` function and other `EventBinder` functions from being available in `initialize` method of views\n\n### v0.9.5 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.9.4...v0.9.5)\n\n* Layout\n  * Fixed a typo / bug in default Region type used for layouts\n\n### v0.9.4 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.9.3...v0.9.5)\n\n* BindTo -> EventBindings\n  * **BREAKING:** Renamed `Marionette.BindTo` to `Marionette.EventBindings` and made it a constructor function instead of an object literal\n\n* Modules\n  * **BREAKING:** Changed the API of `Module.create` to be more clear and explicit about `app` parameter\n  * **BREAKING:** Defer module definition until module is started\n  * Modules now have `addInitializer` method to add initializers\n  * Modules can be started (run the initializers) with `start` method\n  * Modules are automatically started when Marionette.Application `start` method is called\n  * App.start sends options to module initializers\n  * Modules that are defined (or loaded from external source) afer app is started will auto-start by default\n  * Can specify a module is not started with the app, to prevent the module from being started when app.start is called\n  * Calling `start` on a module will start all of the sub-modules for that module\n\n* CollectionView/CompositeView\n  * Correctly handles non-existent collection and removing child item views that were added manually\n  * Corrected showing empty view and closing empty view when resetting collection and adding items\n  * Fixed bug to prevent showing the empty view more than once when rendering the collection view\n\n* Application\n  * Added a `removeRegion` method to close / remove regions, as a counter-function to the `addRegions` method\n\n* Marionette.View (all views / base view)\n  * Can specify a set of `ui` elements that are cached jQuery selectors\n\n* Layout\n  * An already closed layout can be re-rendered, and the regions will regenerate\n  * Allow a custom region type to be specified for all regions, as well as per-region instance\n\n### v0.9.3 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.9.2...v0.9.3)\n\n* CompositeView\n  * Cleaned up the method to get / cache the `itemViewContainer`\n  * Allow `itemViewContainer` to be a function that return a jQuery selector string\n\n* View `render` methods all return `this` in the standard Marionette views (the async views still return a deferred object).\n\n### v0.9.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.9.1...v0.9.2)\n\n* CompositeView\n  * Added `itemViewContainer` to specify which element children / itemView instances should be appended to\n\n* CollectionView\n  * Now triggers \"before:render\" and \"render\" events\n\n* Region\n  * Returns a deferred/promise from the `show` method, with Marionette.Async\n\n* Fixed bug in template cache for Marionette.Async\n\n* Marionette can now be installed with [Volo](https://github.com/volojs/volo)\n\n### v0.9.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.9.0...v0.9.1)\n\n* CollectionView and CompositeView properly close their `emptyView` instance when an item is added to the view's collection\n* CollectionView and CompositeView will show their `emptyView` after the last item has been removed from the collection\n\n### v0.9.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.8.4...v0.9.0)\n\n* **BREAKING** Async Support Removed From Core Marionette\n  * Marionette no longer supports asynchronous / deferred rendering in any view, by default\n  * Async / deferred rendering are now provided via `backbone.marionette.async.js` add-on\n\n* Split the single src/backbone.marionette.js file into multiple files for easier maintenance\n\n* Marionette.Async:\n  * Added `Marionette.Async` add-on which provides support for rendering and retrieving templates asynchronously\n\n* Marionette.View:\n  * **BREAKING** Renamed the `getTemplateSelector` method to `getTemplate`\n  * Call `unbindAll` to unbind all bound events, later in the close process, so the `close` event can be listened to\n\n* ItemView:\n  * **BREAKING** The `template` attribute no longer allows you to specify a function that returns a jQuery selector. Override `getTemplate` to do this.\n  * **BREAKING** The `renderHtml` method has been removed from the ItemView\n  * **BREAKING** Async support removed\n\n* CollectionView:\n  * **BREAKING** Async support removed\n  * Now supports optional `emptyView` attribute, to specify what view to render when no items exist in the collection\n  * Fixed a memory leak for closed item views\n  * ItemView is now guaranteed to have it's \"onRender\" and \"onShow\" methods called, when rendering the collection and when adding a new item to the collection / rendering the new item view\n  * Calls an `onItemAdded` method when adding an item/item view, just prior to rendering the item view\n  * Can now specify an `itemViewOptions` object literal on your collection view definition, and the data will be passed to each itemView instance as part of the itemView's options\n  * The `appendHtml` method receives a third argument of the itemView's \"index\" for sorted collections\n\n* CompositeView:\n  * **BREAKING** When a CompositeView's collection is reset, only the collection will be re-rendered. It will no longe re-render the composite's template/model, just the collection.\n  * **BREAKING** Async support removed\n  * (see change list for `CollectionView`)\n\n* Layout:\n  * **BREAKING** Regions specified within a layout are now available immediately after creating a layout instance\n  * **BREAKING** Re-rendering a layout will close all regions and reset them to the new DOM elements that were rendered\n  * **BREAKING** Layouts no longer have a `.vent` event aggregator hanging off them\n  * **BREAKING** Async support removed\n\n* Region:\n  * **BREAKING** Removed the ability to send a second parameter to a regions' \"show\" method\n  * **BREAKING** Changed the implementation of `Region` to allow easier overriding of how the new view is added to the DOM\n  * **BREAKING** Async support removed\n\n* TemplateCache:\n  * **BREAKING** Moved TemplateCache to object instances instead of single object literal\n  * **BREAKING** Moved the `loadTemplate` and `compileTemplate` to `TemplateCache.prototype`\n  * **BREAKING** `TemplateCache.get` no longer accepts a callback method. It always returns jQuery promise\n\n* Renderer:\n  * **BREAKING** Removed the `renderHtml` method\n  * Rendering a pre-compiled template function is now much easier - just override the `Renderer.render` method.\n\n* Modules:\n  * **BREAKING** Modules must be defined on an instance of a Marionette.Application, and cannot be defined from another module directly\n  * **BREAKING** Modules no longer allow you to return a custom module object from the module definition function\n  * **BREAKING** Modules no longer allow you to add initializers to them\n  * **BREAKING** Modules no longer have a `.vent` event aggregator hanging off them\n  * Extracted `Marionette.Module` in to it's own constructor function to be used as modules, instead of Marionette.Application\n  * Modules allow you to pass in any arbirary arguments, after the module definition function, and they will be supplied to the module definition function\n  * The `this` argument in a module definition function is now the module itself\n\n* Callbacks:\n  * **BREAKING** Switched the order of parameters for the `run` method to `args, context`\n\n* BindTo:\n  * The unbinding of an event now considers the `context` parameter when unbinding, allowing multiple handers to be bound to the same event from the same object, and unbinding only one of them\n\n### v0.8.4 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.8.3...v0.8.4)\n\n* Fixed: A call to `.module` will correctly pass the `Application` instance from which `.module` was called, as the second parameter of the module definition function\n\n### v0.8.3 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.8.2...v0.8.3)\n\n* Module definitions can be split across multiple files and/or multiple calls to define the module\n\n### v0.8.2 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.8.1...v0.8.2)\n\n* Views now have the ability to define `triggers` which will convert a DOM event in to a `view.trigger` event\n\n### v0.8.1 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.8.0...v0.8.1)\n\n* Module definition functions will only be applied to the last module in the . chain\n\n### v0.8.0 [view commit logs](https://github.com/marionettejs/backbone.marionette/compare/v0.7.6...v0.8.0)\n\n* Added modules and sub-modules through the Application object\n\n### v0.7.6\n\n* An `itemView` instance as part of a Collection View or Composite View, will have it's events bubbled up through the parent view, prepended with \"itemview:\" as the event name\n\n### v0.7.5\n\n* The `onBefore` method of ItemView can now return a deferred object\n* Code cleanup for rendering methods\n\n### v0.7.4\n\n* Fixed issue with `unbindAll` in BindTo, that was skipping some items\n\n### v0.7.3\n\n* The `bindTo` method on the `EventAggregator` now returns a binding configuration object\n* Automatic mixing in of `templateMethods` as template / view helper methods, in views that use the `serializeData` function\n* A friendlier error message will be thrown from an appRouter if a route is configured with a method that does not exist on the controller\n\n### v0.7.2\n\n* Extracted `compileTemplate` method in TemplateCache for clarity and easier modification\n* ItemView will wait until `onRender` has completed before triggering other rendered events\n* Region now supports an `onShow` method, when defining a custom region\n* Moved the default `serializeData` method to the base Marionette.View\n* CompositeView now calls the `serializeData` method to get the model's data for the view\n* `BindTo` changes:\n  * The `bindTo` method returns a \"binding\" object so that it can be unbound easily\n  * Now has an `unbindFrom` method that will unbind a binding object\n\n### v0.7.1\n\n* ItemView now has a `renderHtml` method that can be overriden to render the item view's data\n* Region now supports an `initialize` function when extending a region to your own object type\n* CollectionView correctly defers until all children are rendered\n* Underscore templates are cached as pre-compiled templates, instead of re-compiling them on every render\n* Updating AMD support to also work with CommonJS / NodeJS\n* Correctiong build to include header / license info for all output files\n* Pass JSLint with no warnings (run w/ Anvil.js build process)\n* Removed GZip release files, as they were broken anyways\n\n### v0.7.0\n\n* **BREAKING**: The `renderTemplate` method has moved from the `ItemView` prototype on to the `Renderer` object\n* **BREAKING**: The `appendHtml` method of the `CollectionView` now takes `collectionView, itemView` as the arguments, instead of `el, html`\n* Added `Marionette.View` object, to contain a few basic parts of every Marionette view\n* Added `Marionette.Renderer` object, to handle template rendering\n* Views correctly trigger the \"close\" events before unbinding event subscribers\n* Additional `CollectionView` changes:\n  * Extracted `getItemView` method to retrieve the `itemView` type, either from `this.itemView` or `this.options.itemView`\n  * Extracted `buildItemView` method to build each item's view\n  * Renamed `removeChildView` to `removeItemView` to make the language consistent\n  * Triggers \"item:added\" event after each item has been added\n  * Triggers \"item:removed\" event after an item has been removed\n* `CompositeView` changes:\n  * No longer takes a `modelView`. Now directly renders the `template` specified\n  * Defaults to a recurive structure, where `itemView` is the current composite view type\n* A `Region` will trigger a `show` event from any view that it shows\n* Added common \"render\" event to all the view types\n* Updated to Backbone v0.9.2\n* Updated to jQuery v1.7.2\n* AMD / RequireJS compliant version is provided\n* Now using [Anvil.js](https://github.com/arobson/anvil.js) for builds\n\n#### v0.6.4\n\n* CollectionView and CompositeView can render without a collection\n\n#### v0.6.3\n\n* `ItemView` changes\n  * Calls a `beforeRender` and `beforeClose` method on the view, if it exists\n  * Triggers a `item:before:render` event, just prior to rendering\n  * Triggers a `item:before:close` and `item:closed` events, around the view's `close` method\n* `CollectionView` changes\n  * Calls a `beforeRender` and `beforeClose` method on the view, if it exists\n  * Triggers a `collection:before:render` event before rendering\n  * Triggers a `collection:before:close` and `collection:closed` event, surrounding closing of the view\n* The `CollectionView` and `CompositeView` now close child views before closing itself\n\n#### v0.6.2\n\n* **BREAKING:** The `CollectionView` no longer has a `reRender` method. Call `render` instead\n* **BREAKING:** The `TemplateCache.get` method now returns a plain string instead of a jQuery selector object\n* Fixed a bug with closing and then re-using a Layout with defined regions\n* Fixed a potential race condition for loading / caching templates where a template would be loaded multiple times instead of just once\n\n#### v0.6.1\n\n* Fixed the composite view so that it renders the collection correctly when the collection is \"reset\"\n* Fixed the composite view so that it re-renders correctly\n* Fixed various deferred usages to only return promises, instead of the full deferred object\n\n#### v0.6.0\n\n* **BREAKING:** Renamed `LayoutManager` to `Layout`\n* **BREAKING:** Renamed `RegionManager` to `Region`\n* **BREAKING:** Renamed `TemplateManager` to `TemplateCache`\n\n* **Layout**\n  * **BREAKING:** `Layout.render` no longer returns the view itself, now returns a jQuery deferred object\n  * The `.vent` attribute is now available in the `initializer` method\n  * Ensures that regions select the `$el` within the Layout's `$el` instead of globally on the page\n  * Initialize the regions before the layout, allowing access to the regions in the `onRender` method of the layout\n  * Close the Layout's regions before closing the layout itself\n\n* **CompositeView**\n  * **BREAKING:** `CompositeView.render` no longer returns the view itself, now returns a jQuery deffered object\n  * Will only render the collection once. You can call `renderCollection` explicitly to re-render the entire collection\n  * Will only render the model view once. You can call `renderModel` explicitly to re-render the model\n  * Correctly close and dispose of the model view\n  * Triggers various events during rendering of model view and collection view\n  * Calls 'onRender' method of composite view, if it exists\n\n* **ItemView**\n  * **BREAKING:** `ItemView.render` no longer returns the view itself, now returns a jQuery deferred object\n  * Optimization to only call `.toJSON` on either model or collection, not both\n  * Trigger \"item:rendered\" method after rendering (in addition to calling onRender method of the view)\n\n* **CollectionView**\n  * **BREAKING:** `CollectionView.render` no longer returns the view itself, now returns a jQuery deferred object\n  * Trigger \"collection:rendered\" method after rendering (in addition to calling onRender method)\n\n* Large updates to the readme/documentation\n* Heavy use of `jQuery.Deferred()` and `jQuery.when/then` to better support asynchronous templates and rendering\n\n#### v0.5.2\n\n* **BREAKING:** Renamed `CompositeRegion` to `LayoutManager`\n* Aliased CompsiteRegion to LayoutManager for backwards compatibility\n* Bug fix for correctly initializing LayoutManager with specified options in constructor\n\n#### v0.5.1\n\n* Controller methods fired from an `AppRouter` are now called with `this` set to the controller, instead of the router\n* Fixed a bug in the CompositeView where the list wouldn't render when passing in a populated collection\n\n#### v0.5.0\n\n* **BREAKING:** Extraced `CompositeView` out of the collection view\n* Added `CompositeView` for managing leaf-branch/composite model structures\n* Added `CompositeRegion` for managing nested views and nested region managers\n* Added `attachView` method to `RegionManager` to attach existing view without rendering / replacing\n* Specify how to attach HTML to DOM in region manager's `show` method\n\n#### v0.4.8\n\n* Don't re-render an ItemView when the view's model \"change\" event is triggered\n\n#### v0.4.7\n\n* Allow `RegionManager` to be instantiated with an `el` specified in the options\n* Change how RegionManagers are added to an Application instance, to reduce memory usage from extraneous types\n\n#### v0.4.6\n\n* AppRouter can have it's `controller` specified directly in the router definition or in the construction function call\n* Extracted `Marionette.EventAggregator` out in to it's own explicit object\n\n#### v0.4.5\n\n* CollectionView closes existing child views before re-rendering itself, when \"reset\"\nevent of collection is triggered\n* CollectionView now has \"initialEvents\" method which configures it's initial events\n* ItemView now has \"initialEvents\" method which configures it's initial events\n\n#### v0.4.4\n\n* CollectionView renders itself when the view's collection \"reset\" event is fired\n* ItemView renders itself when the view's model \"change\" event is fired\n* ItemView renders itself when the view's collection \"reset\" event is fired\n\n#### v0.4.3\n\n* Fixed bug with RegionManagers trying to select element before DOM is ready, to lazy-select the element on first use of `show`\n\n#### v0.4.2\n\n* **BREAKING:** Removed the `setOptions` method from the `Callbacks` object\n* Refactored `Callbacks` object to use a jQuery Deferred instead of my own code\n* Fixed template manager's `clear` so it properly clears a single template, when only one is specified\n* Refactored the `RegionManager` code to support several new features\n  * now support returning a jQuery deferred object from a view's `render` method\n  * now have a `close` method that you can call to close the current view\n  * now trigger a \"view:show\" and \"view:close\" event\n  * correctly remove reference to previous views, allowing garbage collection of the view\n  * now support the `bindTo` and `unbindAll` methods, for binding/unbinding region manager events\n\n#### v0.4.1\n\n* Minor fix to context of template manager callback, to fix issue w/ async template loading\n\n#### v0.4.0\n\n* **BREAKING:** Rewrote the template manager to be async-template loading friendly\n* **BREAKING:** Dropping support for Backbone v0.5.3 and below\n* Added `Marionette.Callbacks` to manage a collection of callbacks in an async-friendly way\n* Guarantee the execution of app initializer functions, even if they are added after the app\nhas been started.\n* App triggers \"start\" event after initializers and initializer events\n* Updated to Backbone v0.9.1\n\n#### v0.3.1\n\n* Make region managers initialize immediately when calling `app.addRegions`\n\n#### v0.3.0\n\n* **BREAKING:** `view.el` for `ItemView` and `CollectionView` is no longer a jQuery selector object. Use `view.$el` instead\n* **BREAKING:** `regionManger.el` is no longer a jQuery selector object. Use `regionManager.$el` instead\n* Updated to use Backbone v0.9.0\n* Updated to use Underscore v1.3.1\n* Removed default `itemView` from the `CollectionView` definition\n* `CollectionView` now explicitly checks for an `itemView` defined on it, and throws an error if it's not found\n\n#### v0.2.6\n\n* Bind the context (`this`) of application initializer functions to the application object\n\n#### v0.2.5\n\n* Added `AppRouter`, to reduce boilerplate routers down to simple configuration\n* `CollectionView` can be treated as a composite view, rendering an `model` and a `collection` of models\n* Now works with either jQuery, Zepto, or enter.js\n* `ItemView` will throw an error is no template is specified\n\n#### v0.2.4\n\n* Return `this` (the view itself) from `ItemView` and `CollectionView` `render` method\n* Call `onRender` after the `CollectionView` has rendered itself\n\n#### v0.2.3\n\n* Fixed global variable leaks\n* Removed declared, but unused variables\n\n#### v0.2.2\n\n* Fixed binding events in the collection view to use `bindTo` (#6)\n* Updated specs for collection view\n* Documentation fixes (#7)\n\n#### v0.2.1\n\n* Added `TemplateManager` to cache templates\n* CollectionView binds to add/remove and updates rendering appropriately\n* ItemView uses `TemplateManager` for template retrieval\n* ItemView and CollectionView set `this.el = $(this.el)` in constructor\n\n#### v0.2.0\n\n* Added `ItemView`\n* Added `CollectionView`\n* Added `BindTo`\n* Simplified the way `extend` is pulled from Backbone\n\n#### v0.1.0\n\n* Initial release\n* Created documentation\n* Generated annotated source code\n"
  },
  {
    "path": "docs/backbone.radio.md",
    "content": "# Backbone Radio\n\nThe Backbone Radio provides easy support for a number of messaging patterns for\nBackbone and Marionette. This is provided through two basic constructs:\n\n* Events - trigger events on a global object\n* Requests - a global request/reply implementation\n\nRadio takes these two constructs and adds the channel implementation - providing\nnamespaces for events and requests. In short, Radio is a global, namespaced,\nmessage bus system designed to allow two otherwise unrelated objects to\ncommunicate and share information.\n\n## Documentation Index\n\n* [Radio Concepts](#radio-concepts)\n  * [Channel](#channel)\n  * [Event](#event)\n    * [When to use Events](#when-to-use-events)\n  * [Request](#request)\n    * [Returning Values from Reply](#returning-values-from-reply)\n    * [When to use Requests](#when-to-use-requests)\n* [Marionette Integration](#marionette-integration)\n  * [API](#api)\n  * [Examples](#examples)\n    * [Listening to Events](#listening-to-events)\n    * [Replying to Requests](#replying-to-requests)\n    * [Events and Requests](#events-and-requests)\n\n\n## Radio Concepts\n\nThe `Radio` message bus exposes some core concepts:\n\n* `Channel` - a namespace mechanism.\n* `Event` - alert other parts of your application that something happened.\n* `Request` - execute single functions in a different part of your application.\n\n### Channel\n\nThe `channel` is the biggest reason to use `Radio` as our event aggregator - it\nprovides a clean point for dividing global events. To retrieve a channel, use\n`Radio.channel(channelName)`:\n\n```javascript\nimport Radio from 'backbone.radio';\n\nconst myChannel = Radio.channel('basic');\n\nmyChannel.on('some:event', function() {\n  // ...\n});\n```\n\nThe channel is accessible everywhere in your application. Simply import Radio\nand call `channel()` to add listeners, fire callbacks, or send requests.\n\n```javascript\nimport Radio from 'backbone.radio';\n\nconst someChannel = Radio.channel('basic');  // Exactly the same channel as above\n\nsomeChannel.trigger('some:event');  // Will fire the function call above\n```\n\n[Live example](https://jsfiddle.net/marionettejs/0bejfju0/)\n\n\n### Event\n\nThe `Radio Event` works exactly the same way as regular `Backbone Events`\nlike model/collection events. In fact, it uses the `Backbone.Events` mixin\ninternally, exposing its API:\n\n* `channel.on('event', callback, [context])` - when `event` fires, call `callback`\n* `channel.once('event', callback, [context])` - same as `on`, but triggered only once\n* `channel.off('event')` - stop listening to event\n* `channel.trigger('event', ..args)` - fires `event` and passes  args into the\n  resulting `callback`\n\nEvents are typically used to alert other parts of the system that something\nhappened. For example, a user login expired or the user performed a specific\naction.\n\nAs the Radio can be imported anywhere, we can use it as a global event\naggregator as such:\n\n```javascript\nimport Radio from 'backbone.radio';\n\nconst myChannel = Radio.channel('star');\n\nmyChannel.on('left:building', function(person) {\n  console.log(person.get('name') + ' has left the building!');\n});\n\nconst elvis = new Bb.Model({name: 'Elvis'});\nmyChannel.trigger('left:building', elvis);\n\nmyChannel.off('left:building');\n```\n\nJust like Backbone Events, the Radio respects the `listenTo` handler as well:\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\nimport Radio from 'backbone.radio';\n\nconst starChannel = Radio.channel('star');\n\nconst Star = MnObject.extend({\n\n  initialize() {\n    this.listenTo(starChannel, 'left:building', this.leftBuilding);\n    this.listenTo(starChannel, 'enter:building', function(person) {\n       console.log(person.get('name') + ' has entered the building!');\n    });\n  },\n\n  leftBuilding(person) {\n    console.log(person.get('name') + ' has left the building!');\n  }\n});\n```\n\nNote that the event handler can be defined as a method like used for\n`'left:building'` event or inline like used in `'enter:building'`.\n\n[Live example](https://jsfiddle.net/marionettejs/s8nff8vz/)\n\nAs in Backbone, the event handler is called with `this` bound to the `Star` instance. See the\n[Backbone documentation](http://backbonejs.org/#Events) for the full list of\nEvent handling methods.\n\n#### When to use Events\n\nThe Event is a simple notification that _something happened_ and you may or may\nnot want other objects in your application to react to that. A few key\nprinciples to bear in mind are:\n\n* If you don't know what could act on the event, or don't care, use an `Event`\n* If you find yourself calling it an action that occurred, use an `Event`\n* If it's fine for many objects to perform an action, use an `Event`\n* If you don't mind that no objects react, use an `Event`\n\nIf your use case isn't covered here, consider whether you want to\n[use a request](#when-to-use-requests) instead.\n\n### Request\n\nThe Request API provides a uniform way for unrelated parts of the system to\ncommunicate with each other. For example, displaying notifications in response\nto system activity. To attach a listener to a request channel, use `reply` or\n`replyOnce` to attach a listener that immediately detaches after one call.\n\nAs with request, any arguments passed in `channel.request` will be passed into\nthe callback.\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\nimport Radio from 'backbone.radio';\n\nconst channel = Radio.channel('notify');\n\nconst Notification = MnObject.extend({\n\n  initialize() {\n    channel.reply('show:success', this.showSuccessMessage);\n    channel.reply('show:error', function(msg) {\n       // ...\n    });\n  },\n\n  showSuccessMessage(msg) {\n    // ...\n  }\n});\n```\n\nSo, for example, when a model sync fails:\n\n```javascript\nimport { View } from 'backbone.marionette';\nimport Radio from 'backbone.radio';\n\nconst channel = Radio.channel('notify');\n\nconst ModelView = View.extend({\n  modelEvents: {\n    error: 'showErrorMessage'\n  },\n\n  showErrorMessage() {\n    channel.request('show:error', 'An error occurred contacting the server');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/4uuyLe1q/)\n\nNow, whenever the model attached to this View is unable to sync with the server,\nwe can display an error message to the user.\n\n### Returning Values from Reply\n\nThe Request API is also able to return values, making it extremely useful for\naccessing objects that would be otherwise difficult to access. As an example,\nlet's assume we attach the currently logged-in user to the `Application` object\nand we want to know if they're still logged-in.\n\n```javascript\nimport { Application } from 'backbone.marionette';\nimport Radio from 'backbone.radio';\n\nconst channel = Radio.channel('user');\n\nconst App = Application.extend({\n  initialize() {\n    channel.reply('user:loggedIn', this.isLoggedIn);\n  },\n\n  isLoggedIn() {\n    return this.model.getLoggedIn();\n  }\n});\n```\n\nThen, from another view, instead of trying to find the User model. we simply\n`request` it:\n\n```javascript\nconst Radio = require('backbone.radio');\n\nconst channel = Radio.channel('user');\n\nconst loggedIn = channel.request('user:loggedIn');  // App.model.getLoggedIn()\n```\n\n[Live example](https://jsfiddle.net/marionettejs/zaje1rLj/)\n\n### When to use Requests\n\nA Request is, as you might guess, a request for information or for something to\nhappen. You will probably want to use requests when:\n\n* You call the request an action to perform e.g. `show:notification`\n* You want to get the return value of the request\n* You want to call _exactly one_ function\n\n\nIn addition to this documentation, the Radio documentation can be found on\n[Github](https://github.com/marionettejs/backbone.radio).\n\n\n## Marionette Integration\n\nThe [`Application`](./marionette.application.md) and [`MnObject`](./marionette.mnobject.md) classes\nprovide bindings to provide automatic event listeners and / or request handlers on your object\ninstances. This works with a bound `channelName` to let us provide listeners using the `radioEvents`\nand `radioRequests` properties.\n\n**Errors** An error will be thrown if using the radio integration unless `backbone.radio` is setup\nas a dependency.\n\n### API\n\n * `channelName` - defines the Radio channel that will be used for the requests and/or events\n * `getChannel()` - returns a Radio.Channel instance using `channelName`\n * `radioEvents` - defines an events hash with the events to be listened and its respective handlers\n * `radioRequests` - defines an events hash with the requests to be replied and its respective handlers\n\n### Examples\n\n#### Listening to events\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\n\nconst Star = MnObject.extend({\n  channelName: 'star',\n\n  radioEvents: {\n    'left:building': 'leftBuilding'\n  },\n\n  leftBuilding(person) {\n    console.log(person.get('name') + ' has left the building!');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/tf9467x4/)\n\nThis gives us a clear definition of how this object interacts with the `star`\nradio channel.\n\n\n#### Replying to requests\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\n\nconst Notification = MnObject.extend({\n  channelName: 'notify',\n\n  radioRequests: {\n    'show:success': 'showSuccessMessage',\n    'show:error': 'showErrorMessage'\n  },\n\n  showSuccessMessage(msg) {\n    // ...\n  },\n\n  showErrorMessage(msg) {\n    // ...\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/j2qgfk3s/)\n\nWe now have a clear API for communicating with the `Notification` across the\napplication. Don't forget to define the `channelName` on your `MnObject`\ndefinition.\n\nAs with a normal request/reply, we can return values from these bound handlers:\n\n```javascript\nimport { Application } from 'backbone.marionette';\n\nconst App = Application.extend({\n  channelName: 'user',\n\n  radioRequests: {\n    'user:loggedIn': 'isLoggedIn'\n  },\n\n  isLoggedIn() {\n    return this.model.getLoggedIn();\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/52rpd3zg/)\n\n\n#### Events and requests\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\n\nconst NotificationHandler = MnObject.extend({\n  channelName: 'notify',\n\n  radioRequests: {\n    'show:success': 'showSuccessMessage',\n    'show:error': 'showErrorMessage'\n  },\n\n  radioEvents: {\n    'login:user': 'showProfileButton',\n    'logout:user': 'hideProfileButton'\n  },\n\n  showSuccessMessage(message) {\n    // ...\n  },\n\n  showErrorMessage(message) {\n    // ...\n  },\n\n  showProfileButton(user) {\n    // ...\n  },\n\n  hideProfileButton(user) {\n    // ...\n  }\n});\n```\n\nIn an unrelated module:\n\n```javascript\nimport Radio from 'backbone.radio';\nimport User from './models/user';\n\nconst notifyChannel = Radio.channel('notify');\nconst userModel = new User();\n\n// The following will call Notification.showErrorMessage(message)\nnotifyChannel.request('show:error', 'A generic error occurred!');\n\n// The following will call Notification.showProfileButton(user)\nnotifyChannel.trigger('login:user', userModel);\n```\n\n[Live example](https://jsfiddle.net/marionettejs/dv40a0t2/)\n"
  },
  {
    "path": "docs/basics.md",
    "content": "# Common Marionette Concepts\n\nThis document covers the basic usage patterns and concepts across Marionette.\nThis includes things like calling conventions, setting attributes, common option\npatterns etc.\n\n## Documentation Index\n\n* [Using ES6 Modules](#using-es6-modules)\n* [Class-based Inheritance](#class-based-inheritance)\n  * [Value Attributes](#value-attributes)\n  * [Functions Returning Values](#functions-returning-values)\n  * [Binding Attributes on Instantiation](#binding-attributes-on-instantiation)\n* [Common Marionette Functionality](./common.md)\n\n## Using ES6 Modules\n\nMarionette still supports using the library via an inline script.\nThe UMD build supports `noConflict()`.\n\n```html\n<script src=\"./backbone.marionette.js\"></script>\n<script>const MyMarionette = Marionette.noConflict();</script>\n<script>new MyMarionette.View({ el: 'body' });</script>\n```\n\nThe recommended solution is to choose a solution like a [package manager](./installation.md)\nto allow for ES6 module importing of the library. The best way to import is using name imports.\n\n```javascript\nimport { View } from 'backbone.marionette';\nimport * as Mn from 'backbone.marionette';\n\nnew View({ el: 'body' });\nnew Mn.Application();\n```\n\nHowever to support backwards compatibility Marionette exports all of its classes and\nfunctions on a default object. This default export may be removed in a future version of\nMarionette and it is recommend to migrate to a named imports.\n\n```javascript\nimport Marionette from 'backbone.marionette';\n\nnew Marionette.Application();\n```\n\n## Class-based Inheritance\n\nLike [Backbone](http://backbonejs.org/#Model-extend), Marionette utilizes the\n[`_.extend`](http://underscorejs.org/#extend) function to simulate class-based\ninheritance. [All built-in classes](./classes.md), such as `Marionette.View`, `Marionette.MnObject`\nand everything that extend these provide an `extend` method for just this purpose.\n\nIn the example below, we create a new pseudo-class called `MyView`:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({});\n```\n\nYou can now create instances of `MyView` with JavaScript's `new` keyword:\n\n```javascript\nconst view = new MyView();\n```\n\n### Value Attributes\n\nWhen we extend classes, we can provide class attributes with specific values by\ndefining them in the object we pass as the `extend` parameter:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  className: 'bg-success',\n\n  template: '#template-identifier',\n\n  regions: {\n    myRegion: '.my-region'\n  },\n\n  modelEvents: {\n    change: 'removeBackground'\n  },\n\n  removeBackground() {\n    this.$el.removeClass('bg-success');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/k93pejyb/)\n\nWhen we instantiate `MyView`, each instance will be given a `.bg-success` class\nwith a `myRegion` region created on the `.my-region` element.\n\n### Functions Returning Values\n\nIn almost every instance where we can set a value, we can also assign a function\nto figure out the value at runtime. In this case, Marionette will run the\nfunction on instantiation and use the returned value:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  className() {\n    return this.model.successful() ? 'bg-success' : 'bg-error';\n  },\n\n  template: '#template-identifier',\n\n  regions() {\n    return {\n      myRegion: '.my-region'\n    };\n  },\n\n  modelEvents() {\n    const wasSuccessful = this.model.successful();\n    return {\n      change: wasSuccessful ? 'removeBackground' : 'alert'\n    };\n  },\n\n  removeBackground() {\n    this.$el.removeClass('bg-success');\n  },\n\n  alert() {\n    console.log('model changed');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/nn1754fc/)\n\nAs we can see, almost all of the attributes here can be worked out dynamically.\nIn most cases, Marionette will call the function once at instantiation, or first\nrender, and preserve the value throughout the lifetime of the View. There are\nsome exceptions to this rule - these will be referred to with their respective\ndocumentation.\n\n### Function Context\n\nWhen using functions to set attributes, Marionette will assign the instance of\nyour new class as `this`. You can use this feature to ensure you're able to\naccess your object in cases where `this` isn't what you might expect it to be.\n\n### Binding Attributes on Instantiation\n\nIn Marionette, most attributes can be bound on class instantiation in addition\nto being set when the [class is defined](#class-based-inheritance). You can use\nthis to bind events, triggers, models, and collections at runtime:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  template: '#template-identifier'\n});\n\nconst myView = new MyView({\n  triggers: {\n    'click a': 'show:link'\n  }\n});\n```\n\nThis will set a trigger called `show:link` that will be fired whenever the user\nclicks an `<a>` inside the view.\n\nOptions set here will override options set on class definition. So, for example:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  template: '#template-identifier',\n\n  triggers: {\n    'click @ui.save': 'save:form'\n  }\n});\n\nconst myView = new MyView({\n  triggers: {\n    'click a': 'show:link'\n  }\n});\n```\n\nIn this example, the trigger for `save:form` will no longer be fired, as the\ntrigger for `show:link` completely overrides it.\n\n## Setting Options\n\nMarionette can set options when you instantiate a class. This lets you override\nmany class-based attributes when you need to. You can also pass new information\nspecific to the object in question that it can access through special helper\nmethods.\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  checkOption() {\n    console.log(this.getOption('foo'));\n  }\n});\n\nconst view = new MyView({\n  foo: 'some text'\n});\n\nview.checkOption();  // prints 'some text'\n```\n\n[Live example](https://jsfiddle.net/marionettejs/6n02ex1m/)\n\n## Common Marionette Functionality\n\nMarionette has a few methods and core functionality that are common to [all classes](./classes.md).\n\n[Continue Reading...](./common.md).\n"
  },
  {
    "path": "docs/classes.md",
    "content": "# Marionette Classes\n\nMarionette follows Backbone's [pseudo-class architecture](./basics.md#class-based-inheritance).\nThis documentation is meant to provide a comprehensive listing of those classes so that\nthe reader can have a high-level view and understand functional similarities between the classes.\nAll of these classes share a [common set of functionality](./common.md).\n\n### [Marionette.View](./marionette.view.md)\n\nA `View` is used for managing portions of the DOM via a single parent DOM element or `el`.\nIt provides a consistent interface for managing the content of the `el` which is typically\nadministered by serializing a `Backbone.Model` or `Backbone.Collection` and rendering\na template with the serialized data into the `View`s `el`.\n\nThe `View` provides event delegation for capturing and handling DOM interactions as well as\nthe ability to separate concerns into smaller, managed child views.\n\n`View` includes:\n- [The DOM API](./dom.api.md)\n- [Class Events](./events.class.md#view-events)\n- [DOM Interactions](./dom.interactions.md)\n- [Child Event Bubbling](./events.md#event-bubbling)\n- [Entity Events](./events.entity.md)\n- [View Rendering](./view.rendering.md)\n- [Prerendered Content](./dom.prerendered.md)\n- [View Lifecycle](./view.lifecycle.md)\n\nA `View` can have [`Region`s](#marionetteregion) and [`Behavior`s](#marionettebehavior)\n\n### [Marionette.CollectionView](./marionette.collectionview.md)\n\nA `CollectionView` like `View` manages a portion of the DOM via a single parent DOM element\nor `el`. This view manages an ordered set of child views that are shown within the view's `el`.\nThese children are most often created to match the models of a `Backbone.Collection` though a\n`CollectionView` does not require a `collection` and can manage any set of views.\n\n`CollectionView` includes:\n- [The DOM API](./dom.api.md)\n- [Class Events](./events.class.md#collectionview-events)\n- [DOM Interactions](./dom.interactions.md)\n- [Child Event Bubbling](./events.md#event-bubbling)\n- [Entity Events](./events.entity.md)\n- [View Rendering](./view.rendering.md)\n- [Prerendered Content](./dom.prerendered.md)\n- [View Lifecycle](./view.lifecycle.md)\n\nA `CollectionView` can have [`Behavior`s](#marionettebehavior).\n\n### [Marionette.Region](./marionette.region.md)\n\nRegions provide consistent methods to manage, show and destroy views in your\napplications and views.\n\n`Region` includes:\n- [Class Events](./events.class.md#region-events)\n- [The DOM API](./dom.api.md)\n\n### [Marionette.Behavior](marionette.behavior.md)\n\nA `Behavior` provides a clean separation of concerns to your view logic, allowing you to\nshare common user-facing operations between your views.\n\n`Behavior` includes:\n- [Class Events](./events.class.md#behavior-events)\n- [DOM Interactions](./dom.interactions.md)\n- [Entity Events](./events.entity.md)\n\n### [Marionette.Application](marionette.application.md)\n\nAn `Application` provides hooks for organizing and initiating other elements and a view tree.\n\n`Application` includes:\n- [Class Events](./events.class.md#application-events)\n- [Radio API](./backbone.radio.md#marionette-integration)\n- [MnObject's API](./marionette.mnobject.md)\n\nAn `Application` can have a single [region](./marionette.application.md#application-region).\n\n### [Marionette.MnObject](marionette.mnobject.md)\n\n`MnObject` incorporates backbone conventions `initialize`, `cid` and `extend`.\n\n`MnObject` includes:\n- [Class Events](./events.class.md#mnobject-events)\n- [Radio API](./backbone.radio.md#marionette-integration).\n\n## Routing in Marionette\n\nUsers of versions of Marionette prior to v4 will notice that a router is no longer bundled.\nThe [Marionette.AppRouter](https://github.com/marionettejs/marionette.approuter) was extracted\nand the core library will no longer hold an opinion on routing.\n\n[Continue Reading](./routing.md) about routing in Marionette.\n"
  },
  {
    "path": "docs/common.md",
    "content": "# Common Marionette Functionality\n\nMarionette has a few methods that are common to [all classes](./classes.md).\n\n## Documentation Index\n\n* [initialize](#initialize)\n* [extend](#extend)\n* [Events API](#events-api)\n* [triggerMethod](#triggermethod)\n* [bindEvents](#bindevents)\n* [unbindEvents](#unbindevents)\n* [bindRequests](#bindrequests)\n* [unbindRequests](#unbindrequests)\n* [normalizeMethods](#normalizemethods)\n* [getOption](#getoption)\n* [mergeOptions](#mergeoptions)\n* [The `options` Property](#the-options-property)\n\n### `initialize`\n\nLike the backbone classes, `initialize` is a method you can define on any Marionette class\nthat will be called when the class is instantiated and will be passed any arguments passed\nat instantiation.  The first argument may contain [options](#getoption) the class attaches\nto the instance.\n\n```js\nimport { MnObject } from 'backbone.marionette';\n\nconst MyObject = MnObject.extend({\n  initialize(options, arg2) {\n    console.log(options.foo, this.getOption('foo'), arg2);\n  }\n});\n\nconst myObject = new MyObject({ foo: 'bar' }, 'baz'); // logs \"bar\" \"bar\" \"baz\"\n```\n\n[Live example](https://jsfiddle.net/marionettejs/1ytrwyog/)\n\n### `extend`\n\nBorrowed from backbone, `extend` is available on all class definitions for\n[class based inheritance](./basics.md#class-based-inheritance)\n\n### Events API\n\nThe [Backbone.Events API](http://backbonejs.org/#Events) is available to all classes.\nEach Marionette class can both `listenTo` any object with this API and have events\ntriggered on the instance.\n\n**Note** The events API should not be confused with [view `events`](/.dom.interactions.md#view-events)\nwhich capture DOM events.\n\n### `triggerMethod`\n\nTrigger an event and [a corresponding method](./events.md#onevent-binding) on the object.\nIt is the same as `Backbone`'s [`trigger`](http://backbonejs.org/#Events-trigger)\nbut with the additional method handler.\n\nWhen an event is triggered, the first letter of each section of the\nevent name is capitalized, and the word \"on\" is prepended to the front\nof it. Examples:\n\n* `triggerMethod('foo')` fires the \"onFoo\" function\n* `triggerMethod('before:foo')` fires the \"onBeforeFoo\" function\n\nAll arguments that are passed to the `triggerMethod` call are passed along\nto both the event and the method, with the exception of the event name not\nbeing passed to the corresponding method.\n\n`triggerMethod('foo', bar)` will call `onFoo(bar){...})`\n\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\n\nconst MyObject = MnObject.extend({\n  initialize(){\n    this.triggerMethod('foo', 'baz');\n  },\n  onFoo(bar){\n    console.log(bar);\n  }\n});\n\nconst myObj = new MyObject(); // console.log \"baz\"\n\nmyObj.triggerMethod('foo', 'qux'); // console.log \"qux\"\n```\n\nMore information on `triggerMethod` can be found in the [Marionette events documentation](./events.md#triggermethod).\n\n### `bindEvents`\n\nThis method is used to bind any object that works with the [`Backbone.Events` API](#events-api).\nThis includes all Backbone classes, Marionette classes and [Radio](./backbone.radio.md) channels.\n\n```javascript\nimport Radio from 'backbone.radio';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  fooEvents: {\n    'change:foo': 'doSomething'\n  },\n  initialize(){\n    this.fooChannel = Radio.channel('foo');\n    this.bindEvents(this.fooChannel, this.fooEvents);\n  },\n  doSomething(){\n    // the \"change:foo\" event was fired from the radio channel\n    // respond to it appropriately, here.\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/L640ecac/)\n\nThe first parameter is the `entity` (Backbone.Model, Backbone.Collection or\nany object that has Backbone.Events mixed in) to bind the events from.\n\nThe second parameter is a hash of `{ 'event:name': 'eventHandler' }`\nconfiguration. A function can be supplied instead of a string handler name.\n\n**Errors** An error will be thrown if the second parameter is not an object.\n\n### `unbindEvents`\n\nThis method is used to unbind any object that works with the [`Backbone.Events` API](#events-api).\nThis includes all Backbone classes, Marionette classes and [Radio](./backbone.radio.md) channels.\n\nCalling this method without a events hash will unbind all events from the channel.\n\n```javascript\nimport Radio from 'backbone.radio';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  fooEvents: {\n    'change:foo': 'onChangeFoo',\n    'stop': 'onStop'\n  },\n  initialize(){\n    this.fooChannel = Radio.channel('foo');\n    this.bindEvents(this.fooChannel, this.fooEvents);\n  },\n  onChangeFoo(){\n    // the \"change:foo\" event was fired from the radio channel\n    // respond to it appropriately, here.\n\n    // Doing something\n    this.listenTo(this.fooChannel, 'adhoc', this.render);\n  },\n  onStop() {\n    // Removes all fooEvents\n    this.unbindEvents(this.fooChannel, this.fooEvents);\n\n    // Removes all bound fooChannel events including `adhoc`\n    this.unbindEvents(this.fooChannel);\n  }\n});\n```\n\nThe first parameter is the `entity` (Backbone.Model, Backbone.Collection or\nany object that has Backbone.Events mixed in) to bind the events from.\n\nThe second parameter is a hash of `{ 'event:name': 'eventHandler' }`\nconfiguration. A function can be supplied instead of a string handler name.\nIf the second paramater is not supplied, all listeners are removed.\n\n[Live example](https://jsfiddle.net/marionettejs/yvsfm65c/)\n\n### `bindRequests`\n\nThis method is used to bind any object that works with the [`Backbone.Radio` Request API](https://github.com/marionettejs/backbone.radio#backboneradiorequests).\nThis includes [Radio](./backbone.radio.md) channels.\n\n```javascript\nimport Radio from 'backbone.radio';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  channelName: 'myChannelName',\n  radioRequests: {\n    'foo:bar': 'doFooBar'\n  },\n  initialize() {\n    const channel = Radio.channel(this.channelName);\n    this.bindRequests(channel, this.radioRequests);\n  },\n  doFooBar() {\n    console.log('foo:bar');\n    return 'bar';\n  }\n });\n\nconst myView = new MyView();\nconst channel = Radio.channel('myChannelName');\nchannel.request('foo:bar'); // Logs 'foo:bar' and returns 'bar'\n```\n\n[Live example](https://jsfiddle.net/marionettejs/hmjgkg7w/)\n\nThe first parameter, `channel`, is an instance from `Radio`.\n\nThe second parameter is a hash of `{ 'request:name': 'replyHandler' }`\nconfiguration. A function can be supplied instead of a string handler name.\n\n**Errors** An error will be thrown if the second parameter is not an object.\n\n### `unbindRequests`\n\nThis method is used to unbind any object that works with the [`Backbone.Radio` Request API](https://github.com/marionettejs/backbone.radio#backboneradiorequests).\n\nCalling this method without a radio requests hash will unbind all requests\nfrom the channel.\n\n**NOTE: To avoid memory leaks, `unbindRequests` should be called\nin or before `onBeforeDestroy`.**\n\n```javascript\nimport Radio from 'backbone.radio';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  channelName: 'myChannelName',\n  radioRequests: {\n    'foo:bar': 'doFooBar'\n  },\n  onAttach() {\n    const channel = Radio.channel(this.channelName);\n    this.bindRequests(channel, this.radioRequests);\n  },\n  onBeforeDetach() {\n    const channel = Radio.channel(this.channelName);\n    this.unbindRequests(channel, this.radioRequests);\n  }\n });\n```\n\n[Live examples](https://jsfiddle.net/marionettejs/r5kmwwke/)\n\nThe first parameter, `channel`, is an instance from `Radio`.\n\nThe second parameter is a hash of `{ 'request:name': 'replyHandler' }`\nconfiguration. A function can be supplied instead of a string handler name.\nIf the second paramater is not supplied, all handlers are removed.\n\n### `normalizeMethods`\n\nReceives a hash of event names and functions and/or function names, and returns the\nsame hash with the function names replaced with the function references themselves.\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  initialize() {\n    const hash = {\n      'action:one': 'handleActionOne', // This will become a reference to `this.handleActionOne`\n      'action:two': this.handleActionTwo\n    };\n\n    this.normalizedHash = this.normalizeMethods(hash);\n  },\n\n  do(action) {\n    this.normalizedHash[action]();\n  },\n\n  handleActionOne() {\n    console.log('action:one was fired');\n  },\n\n  handleActionTwo() {\n    console.log('action:two was fired');\n  }\n\n});\n\nconst myView = new MyView();\nmyView.do('action:one');\nmyView.do('action:two');\n```\n\n[Live example](https://jsfiddle.net/marionettejs/zzjhm4p1/)\n\n### `getOption`\n\nTo access an option, we use the `getOption` method. `getOption` will fall back\nto the value of the same name defined on the instance if not defined in the options.\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst View = View.extend({\n  classVal: 'class value',\n  initialize(){\n    this.instanceVal = 'instance value'\n  }\n});\n\nconst view = new View({ optVal: 'option value' });\n\nview.getOption('instanceVal'); // instance value\nview.getOption('classVal'); // class value\nview.getOption('optVal'); // option value\n\nconst view2 = new View({ instanceVal: 'foo', classVal: 'bar', optVal: 'baz' });\n\nview.getOption('instanceVal'); // foo\nview.getOption('classVal'); // bar\nview.getOption('optVal'); // baz\n```\n\n[Live example](https://jsfiddle.net/marionettejs/ekvb8wwa/)\n\n#### Falsey values\n\nThe `getOption` function will return any falsey value from the `options`,\nother than `undefined`. If an object's options has an undefined value, it will\nattempt to read the value from the object directly.\n\nFor example:\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\n\nconst MyObject = MnObject.extend({\n  foo: 'bar',\n\n  initialize() {\n    console.log(this.getOption('foo'));\n  }\n});\n\nconst model1 = new MyObject(); // => \"bar\"\n\nconst myObj = {};\nconsole.log(myObj.foo); // undefined\nconst model2 = new MyObject({ foo: myObj.foo }); // => \"bar\"\n```\n\n[Live example](https://jsfiddle.net/marionettejs/2ddk28ap/)\n\nIn this example, \"bar\" is returned both times because the second\nexample has an undefined value for `f`.\n\n### `mergeOptions`\n\nThe `mergeOptions` method takes two arguments: an `options` object and `keys` to\npull from the options object. Any matching `keys` will be merged onto the\nclass instance. For example:\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\n\nconst MyObject = MnObject.extend({\n  initialize(options) {\n    this.mergeOptions(options, ['model', 'something']);\n    // this.model and this.something will now be available\n  }\n});\n\nconst myObject = new MyObject({\n  model: new Backbone.Model(),\n  something: 'test',\n  another: 'value'\n});\n\nconsole.log(myObject.model);\nconsole.log(myObject.something);\nconsole.log(myObject.getOption('another'));\n```\n\n[Live example](https://jsfiddle.net/marionettejs/ub510cbx/)\n\nIn this example, `model` and `something` are directly available on the\n`MyObject` instance, while `another` must be accessed via `getOption`. This is\nhandy when you want to add extra keys that will be used heavily throughout the\ndefined class.\n\n### The `options` Property\n\nThe Marionette classes accept an `options` property in the class definition\nwhich is merged with the `options` argument passed at instantiation. The\nvalues from the passed in `options` overrides the property values.\n\n> The `options` argument passed in `initialize` method is equal to the passed at\n> class instantiation. To get the option inside initialize considering the\n> `options` property is necessary to use `getOption`\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\n\nconst MyObject = MnObject.extend({\n  options: {\n    foo: 'bar',\n    another: 'thing'\n  },\n\n  initialize(options) {\n    console.log(options.foo) // undefined\n    console.log(this.getOption('foo')) // 'bar'\n    console.log(this.getOption('another')) // 'value'\n  }\n});\n\nconst myObject = new MyObject({\n  another: 'value'\n});\n```\n\n## Marionette Classes\n\nMarionette provides a few classes for building your view tree and\napplication structure.\n\n[Continue Reading...](./classes.md).\n"
  },
  {
    "path": "docs/dom.api.md",
    "content": "# The DOM API\n\nWith the release of Marionette 3.2, developers can remove the dependency on\njQuery and integrate with the DOM using a custom api.\n\n## API Methods\n\nThe DOM API manages the DOM on behalf of [each view class and `Region`](./classes.md).\nIt defines the methods that actually attach and remove views and children.\n\n[The default API](#the-default-api) depends on Backbone's jQuery `$` object however it does not\nrely on jQuery-specific behavior. This should make it easier to develop your own\nAPI. You will, however, [need to also handle Backbone's jQuery integration](#backbone-jquery-integration).\n\n### `createBuffer()`\n\nReturns a new HTML DOM node instance. The resulting node can be passed into the\nother DOM functions.\n\n### `getDocumentEl(el)`\n\nLook up the top level element of `el`. Used by Marionette to determine attachment.\n\n```javascript\nconst elIsAttached = this.Dom.hasEl(this.Dom.getDocumentEl(this.el), this.el);\n```\n\n### `getEl(selector)`\n\nLookup the `selector` string withing the DOM. The `selector` may also be a DOM element.\nIt should return an array-like object of the node.\n\n### `findEl(el, selector)`\n\nLookup the `selector` string within the DOM node `el`. It should return an array-like object of nodes.\n\n### `hasEl(el, childEl)`\n\nReturns true if the el contains the node childEl\n\n### `detachEl(el)`\n\nDetach `el` from the DOM without removing listeners.\n\n### `replaceEl(newEl, oldEl)`\n\nRemove `oldEl` from the DOM and put `newEl` in its place.\n\n### `swapEl(el1, el2)`\n\nSwaps the location of `el1` and `el2` in the DOM.\nBoth els must have a parentNode to be able to swap.\n\n### `setContents(el, html)`\n\nReplace the contents of `el` with the HTML string of `html`. Unlike other DOM\nfunctions, this only takes a literal string for its second argument.\n\n### `appendContents(el, contents)`\n\nTakes the DOM node `el` and appends the DOM node `contents` to the end of the\nelement's contents.\n\n### `hasContents(el)`\n\nReturns a boolean indicating if the `el` has child nodes.\n\n### `detachContents(el)`\n\nRemove the inner contents of `el` from the DOM while leaving `el` itself in the\nDOM.\n\n## The default API\n\nThe API used by Marionette by default is attached as `Marionette.DomApi`.\nThis is useful if you [change the API](#providing-your-own-dom-api) globally,\nbut want to reuse the default in certain cases.\n\n```javascript\nimport { setDomApi, DomApi } from 'backbone.marionette';\n\nimport MyDOMApi from './mydom';\n\nsetDomApi(MyDOMApi);\n\n// Use MyDOMApi everywhere but `Marionette.View`\nView.setDomApi(DomApi);\n```\n\n## Providing Your Own DOM API\n\nTo implement your own DOM API use `setDomApi`:\n\n```javascript\nimport { setDomApi } from 'backbone.marionette';\nimport MyDOMApi from './mydom';\n\nsetDomApi(MyDOMApi);\n```\n\nYou can also implement a different DOM API for a particular class:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nView.setDomApi(MyDOMApi);\n```\n\n`CollectionView`, `Region`, and `View`\nall have `setDomApi`. Each extended class may have their own DOM API.\n\nAdditionally a DOM API can be partially set:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend();\n\nMyView.setDomApi({\n  setContents(el, html) {\n    el.innerHTML = html;\n  }\n});\n```\n\n### Backbone jQuery Integration\n\nBackbone.js is tied to jQuery's API for managing DOM manipulation. If you want\nto completely remove jQuery from your Marionette app, you'll also have to\nprovide your own versions of the following methods:\n\n* [`_setAttributes`](http://backbonejs.org/docs/backbone.html#section-170)\n* [`delegate`](http://backbonejs.org/docs/backbone.html#section-165)\n* [`undelegate`](http://backbonejs.org/docs/backbone.html#section-167)\n\n#### See Also\n\nThe DOM API takes care of the other DOM manipulation methods for you. The\n[Backbone Wiki](https://github.com/jashkenas/backbone/wiki/using-backbone-without-jquery)\nhas a good reference for removing jQuery from the app, including Browserify and\nWebpack configuration hooks.\n"
  },
  {
    "path": "docs/dom.interactions.md",
    "content": "# DOM Interactions\n\nIn addition to what Backbone provides the views, Marionette has additional API\nfor DOM interactions available to all Marionette [view classes](./classes.md).\n\n### DOM Interactions in a Backbone.View\n\nMarionette's Views extend [`Backbone.View`](http://backbonejs.org/#View) and\nso have references to the view's `el`, `$el`, and `this.$()` as well as\ndefining an `events` hash.\n\nThese methods provide ways for interacting with the view scoped to it's `el`\n_and_ all of the view's children. To restate `events` and `this.$()` will query\nthe view's template and all of the children. Marionette's added interfaces\nattempt to scope interactions with only the view's template, leaving the\nchildren to handle themselves.\n\n### Binding To User Input\n\nViews can bind custom events whenever users perform some interaction with the\nDOM. Using the view [`events`](#view-events) and [`triggers`](#view-triggers)\nhandlers lets us either bind user input directly to an action or fire a generic\ntrigger that may or may not be handled.\n\n#### Event and Trigger Mapping\n\nThe `events` and `triggers` attributes bind DOM events to actions to perform on\nthe view. They each take a DOM event key and a mapping to the handler.\n\nWe'll cover a simple example:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  events: {\n    'drop': 'onDrop',\n    'click .btn-show-modal': 'onShowModal',\n    'click @ui.save': 'onSave'\n  },\n\n  triggers: {\n    'click @ui.close': 'close'\n  },\n\n  ui: {\n    save: '.btn-save',\n    close: '.btn-cancel'\n  },\n\n  onShowModal() {\n    console.log('Show the modal');\n  },\n\n  onSave() {\n    console.log('Save the form');\n  },\n\n  onDrop() {\n    console.log('Handle a drop event anywhere in the element');\n  }\n});\n```\n\nEvent listeners are constructed by:\n\n```javascript\n'<dom event> [dom node]': 'listener'\n```\n\nThe `dom event` can be a jQuery DOM event - such as `click` - or another custom\nevent, such as Bootstrap's `show.bs.modal`.\n\nThe `dom node` represents a jQuery selector or a `ui` key prefixed by `@.`.\nThe `dom node` is optional, and if omitted, the view's `$el` will be used as the\nselector.  For more information about the `ui` object, and how it works, see\n[the documentation on ui](#organizing-your-view).\n\n#### View `events`\n\nThe view `events` attribute binds DOM events to functions or methods on the\nview. The simplest form is to reference a method on the view:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  events: {\n    'click a': 'onShowModal'\n  },\n\n  onShowModal(event) {\n    console.log('Show the modal');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/jfxwtmxj/)\n\nThe DOM event gets passed in as the first argument, allowing you to see any\ninformation passed as part of the event.\n\n**When passing a method reference, the method must exist on the View.**\n\nThe `events` attribute can also directly bind functions:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  events: {\n    'click a'(event) {\n      console.log('Show the modal');\n    }\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/obt5vt09/)\n\nAs when passing a string reference to a view method, the `events` attribute\npasses in the `event` as the argument to the function called.\n\n**Note** Backbone `events` are delegated to the view's `el`. This means that\nevents with a dom node selector will be handled for the view and any descendants.\nSo if you attach a child with the same selector as the parent event handler, the\nparent will handle the event for both views.\n\n#### View `triggers`\n\nThe view `triggers` attribute binds DOM events to Marionette events that\ncan be responded to at the view or parent level. For more information on events,\nsee the [events documentation](./events.md). This section will just\ncover how to bind these events to views.\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  triggers: {\n    'click a': 'click:link'\n  },\n\n  onClickLink(view, event) {\n    console.log('Show the modal');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/exu2s3tL/)\n\nWhen the `a` tag is clicked here, the `link:click` event is fired. This event\ncan be listened to using the [`onEvent` Binding](./events.md#onevent-binding)\ntechnique discussed in the [events documentation](./events.md).\n\nThe major benefit of the `triggers` attribute over `events` is that triggered\nevents can bubble up to any parent views. For a full explanation of bubbling\nevents and listening to child events, see the\n[event bubbling documentation](./events.md#event-bubbling)..\n\n#### View `triggers` Event Object\n\nEvent handlers will receive the triggering view as the first argument and the\nDOM Event object as the second followed by any extra parameters triggered by the event.\n\n**NOTE** It is _strongly recommended_ that View's handle their own DOM event objects. It should\nbe considered a best practice to not utilize the DOM event in external listeners.\n\nBy default all trigger events are stopped with [`preventDefault`](./features.md#triggerspreventdefault)\nand [`stopPropagation`](./features.md#triggersstoppropagating) methods. This by nature artificially\nscopes event handling to the view's template preventing event handling of the same selectors in\nchild views. However you can manually configurethe triggers using a hash instead of an event name.\nThe example below triggers an event and prevents default browser behaviour using `preventDefault`.\n\n```js\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  triggers: {\n    'click a': {\n      event: 'link:clicked',\n      preventDefault: true, // this param is optional and will default to true\n      stopPropagation: false\n    }\n  }\n});\n```\n\nThe default behavior for calling `preventDefault` can be changed with the feature flag\n[`triggersPreventDefault`](./features.md#triggerspreventdefault), and `stopPropagation`\ncan be changed with the feature flag [`triggersStopPropagation`](./features.md#triggersstoppropagating).\n\n## Organizing Your View\n\nThe `View` provides a mechanism to name parts of your template to be used\nthroughout the view with the `ui` attribute. This provides a number of benefits:\n\n1. Provide a single defined reference to commonly used UI elements\n2. Cache the jQuery selector\n3. Query from only the view's template and not the children\n\n### Defining `ui`\n\nTo define your `ui` hash, just set an object of named jQuery selectors to the\n`ui` attribute of your View:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  template: MyTemplate,\n  ui: {\n    save: '#save-button',\n    close: '.close-button'\n  }\n});\n```\n\nInside your view, the `save` and `close` references will point to the jQuery\nselectors `#save-button` and `.close-button`respectively found only in the\nrendered `MyTemplate`.\n\n### Accessing UI Elements\n\nTo get the handles to your UI elements, use the `getUI(ui)` method:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  template: MyTemplate,\n  ui: {\n    save: '#save-button',\n    close: '.close-button'\n  },\n\n  onFooEvent() {\n    const $saveButton = this.getUI('save');\n    $saveButton.addClass('disabled');\n    $saveButton.attr('disabled', 'disabled');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/rpa58v0g/)\n\nAs `$saveButton` here is a jQuery selector, you can call any jQuery methods on\nit, according to the jQuery documentation.\n\n#### Referencing UI in `events` and `triggers`\n\nThe UI attribute is especially useful when setting handlers in the\n[`events`](#view-events) and [`triggers`](#view-triggers) objects - simply use\nthe `@ui.` prefix:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  template: MyTemplate,\n  ui: {\n    save: '#save-button',\n    close: '.close-button'\n  },\n\n  events: {\n    'click @ui.save': 'onSave'\n  },\n\n  triggers: {\n    'click @ui.close': 'close'\n  },\n\n  onSave() {\n    this.model.save();\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/f2k0wu05/)\n\nIn this example, when the user clicks on `#save-button`, `onSave` will be\ncalled. If the user clicks on `.close-button`, then the event `close:view` will\nbe fired on `MyView`.\n\nBy prefixing with `@ui`, we can change the underlying template without having to\nhunt through our view for every place where that selector is referenced - just\nupdate the `ui` object.\n"
  },
  {
    "path": "docs/dom.prerendered.md",
    "content": "# Prerendered Content\n\n[View classes](./classes.md) can be initialized with pre-rendered DOM.\n\nThis can be HTML that's currently in the DOM:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst myView = new View({ el: $('#foo-selector') });\n\nmyView.isRendered(); // true if '#foo-selector` exists and has content\nmyView.isAttached(); // true if '#foo-selector` is in the DOM\n```\n\nOr it can be DOM created in memory:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst $inMemoryHtml = $('<div>Hello World!</div>');\n\nconst myView = new View({ el: $inMemoryHtml });\n```\n\n[Live example](https://jsfiddle.net/marionettejs/b2yz38gj/)\n\nIn both of the cases at instantiation the view will determine\n[its state](./view.lifecycle.md) as to whether the el is rendered\nor attached.\n\n**Note** `render` and `attach` events will not fire for the initial\nstate as the state is set already at instantiation and is not changing.\n\n## Managing `View` children\n\nWith [`View`](./marionette.view.md) in most cases the [`render` event](./events.class.md#render-and-beforerender-events)\nis the best place to show child views [for best performance](./marionette.view.md#efficient-nested-view-structures).\n\nHowever with pre-rendered DOM you may need to show child views in `initialize`\nas the view will already be rendered.\n\n```javascript\nimport { View } from 'backbone.marionette';\nimport HeaderView from './header-view';\n\nconst MyBaseLayout = View.extend({\n  regions: {\n    header: '#header-region',\n    content: '#content-region'\n  },\n  el: $('#base-layout'),\n  initialize() {\n   this.showChildView('header', new HeaderView());\n  }\n});\n```\n\n### Managing a Pre-existing View Tree.\n\nIt may be the case that you need child views of already existing DOM as well.\nTo set this up you'll need to query for `el`s down the tree:\n\n```javascript\nimport { View } from 'backbone.marionette';\nimport HeaderView from './header-view';\n\nconst MyBaseLayout = View.extend({\n  regions: {\n    header: '#header-region',\n    content: '#content-region'\n  },\n  el: $('#base-layout'),\n  initialize() {\n    this.showChildView('header', new HeaderView({\n      el: this.getRegion('header').$el.contents()\n    }));\n  }\n});\n```\n\nThe same can be done with [`CollectionView`](./marionette.collectionview.md):\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\nimport ItemView from './item-view';\n\nconst MyList = CollectionView.extend({\n  el: $('#base-table'),\n  childView: ItemView,\n  childViewContainer: 'tbody',\n  buildChildView(model, ChildView) {\n    const index = this.collection.indexOf(model);\n    const childEl = this.$('tbody').contents()[index];\n\n    return new ChildView({\n      model,\n      el: childEl\n    });\n  }\n});\n\nconst myList = new MyList({ collection: someCollection });\n\n// Unlike `View`, `CollectionView` should be rendered to build the `children`\nmyList.render();\n```\n\nhttps://github.com/marionettejs/backbone.marionette/issues/3128\n\n## Re-rendering children of a view with preexisting DOM.\n\nYou may be instantiating a `View` with existing HTML, but if you re-render the view,\nlike any other view, your view will render the `template` into the view's `el` and\nany children will need to be re-shown.\n\nSo your view will need to be prepared to handle both scenarios.\n\n```javascript\nimport _ from 'underscore';\nimport { View } from 'backbone.marionette';\nimport HeaderView from './header-view';\n\nconst MyBaseLayout = View.extend({\n  regions: {\n    header: '#header-region',\n    content: '#content-region'\n  },\n  el: $('#base-layout'),\n  initialize() {\n    this.showChildView('header', new HeaderView({\n      el: this.getRegion('header').$el.contents()\n    }));\n  },\n  template: _.template('<div id=\"header-region\"></div><div id=\"content-region\"></div>'),\n  onRender() {\n    this.showChildView('header', new HeaderView());\n  }\n});\n```\n"
  },
  {
    "path": "docs/events.class.md",
    "content": "# Class Events\n\nMarionette uses [`triggerMethod`](./events.md#triggermethod) internally to trigger various\nevents used within the [classes](./classes.md). This provides ['onEvent' binding](./events.md#onevent-binding)\nproviding convenient hooks for handling class events. Notably all internally triggered events\nwill pass the triggering class instance as the first argument of the event.\n\n## Documentation Index\n\n* [Application Events](#application-events)\n  * [`before:start` event](#before-start-event)\n  * [`start` event](#start-event)\n* [Behavior Events](#behavior-events)\n  * [`initialize` event](#initialize-event)\n  * [Proxied Events](#proxied-events)\n* [Region Events](#region-events)\n  * [`show` and `before:show` events](#show-and-beforeshow-events)\n  * [`empty` and `before:empty` events](#empty-and-beforeempty-events)\n* [MnObject Events](#mnobject-events)\n* [View Events](#view-events)\n  * [`add:region` and `before:add:region` events](#addregion-and-beforeaddregion-events)\n  * [`remove:region` and `before:remove:region` events](#removeregion-and-beforeremoveregion-events)\n* [CollectionView Events](#collectionview-events)\n  * [`add:child` and `before:add:child` events](#addchild-and-beforeaddchild-events)\n  * [`remove:child` and `before:remove:child` events](#removechild-and-beforeremovechild-events)\n  * [`sort` and `before:sort` events](#sort-and-beforesort-events)\n  * [`filter` and `before:filter` events](#filter-and-beforefilter-events)\n  * [`render:children` and `before:render:children` events](#renderchildren-and-beforerenderchildren-events)\n  * [`destroy:children` and `before:destroy:children` events](#destroychildren-and-beforedestroychildren-events)\n  * [CollectionView EmptyView Region Events](#collectionview-emptyview-region-events)\n* [DOM Change Events](#dom-change-events)\n  * [`render` and `before:render` events](#render-and-beforerender-events)\n  * [`attach` and `before:attach` events](#attach-and-beforeattach-events)\n  * [`detach` and `before:detach` events](#detach-and-beforedetach-events)\n  * [`dom:refresh` event](#domrefresh-event)\n  * [`dom:remove` event](#domremove-event)\n  * [Advanced Event Settings](#advanced-event-settings)\n* [Destroy Events](#destroy-events)\n  * [`destroy` and `before:destroy` events](#destroy-and-beforedestroy-events)\n* [Supporting Backbone Views](#supporting-backbone-views)\n  * [`Marionette.Events` and `triggerMethod`](#marionetteevents-and-triggermethod)\n  * [Lifecycle Events](#lifecycle-events)\n\n## Application Events\n\nThe `Application` object will fire two events:\n\n### `before:start` event\n\nFired just before the application is started. Use this to prepare the\napplication with anything it will need to start, for example instantiating\nrouters, models, and collections.\n\n### `start` event\n\nFired as part of the application startup. This is where you should be showing\nyour views and starting `Backbone.history`.\n\n```javascript\nimport Bb from 'backbone';\nimport { Application } from 'backbone.marionette';\n\nimport MyModel from './mymodel';\nimport MyView from './myview';\n\nconst MyApp = Application.extend({\n  region: '#root-element',\n\n  initialize(options) {\n    console.log('Initialize' + options.foo);\n  },\n\n  onBeforeStart(app, options) {\n    this.model = new MyModel(options.data);\n  },\n\n  onStart(app, options) {\n    this.showView(new MyView({model: this.model}));\n    Bb.history.start();\n  }\n});\n\nconst myApp = new MyApp({ foo: 'My App' });\nmyApp.start({ data: { bar: true } });\n```\n\n[Live example](https://jsfiddle.net/marionettejs/ny59rs7b/)\n\nAs shown the `options` object is passed into the `Application` as the\nsecond argument to `start`.\n\n#### Application `destroy` events\n\nThe `Application` class also triggers [Destroy Events](#destroy-and-beforedestroy-events).\n\n## Behavior Events\n\n### `initialize` event\n\nAfter the view and behavior are [constructed and initialized](./marionette.behavior.md#events--initialize-order),\nthe last event to occur is an `initialize` event on the behavior which is passed\nthe view instance and any options passed to the view at instantiation.\n\n```javascript\nimport { Behavior, View } from 'backbone.marionette';\n\nconst MyBehavior = Behavior.extend({\n  onInitialize(view, options) {\n    console.log(options.msg);\n  }\n});\n\nconst MyView = View.extend({\n  behaviors: [MyBehavior]\n});\n\nconst myView = new MyView({ msg: 'view initialized' });\n```\n\n**Note** This event is unique in that the triggering class instance (the view) is not the same instance\nas the handler (the behavior). In most cases internally triggered events are triggered and handled by\nthe same instance, but this is an exception.\n\n### Proxied Events\n\nA `Behavior`'s view events [are proxied directly on the behavior](./marionette.behavior.md#proxy-handlers).\n\n**Note** In order to prevent conflict `Behavior` does not trigger [destroy events](#destroy-and-beforedestroy-events)\nwith its own destruction. A `destroy` event occurring on the `Behavior` will have originated from the related view.\n\n## Region Events\n\nWhen you show a view inside a region - either using [`region.show(view)`](./marionette.region.md#showing-a-view) or\n[`showChildView('region', view)`](./marionette.view.md#showing-a-view) - the `Region` will emit events around the view\nevents that you can hook into.\n\nThe `Region` class also triggers [Destroy Events](#destroy-and-beforedestroy-events).\n\n### `show` and `before:show` events\n\nThese events fire before (`before:show`) and after (`show`) showing anything in a region.\nA view may or may not be rendered during `before:show`, but a view will be rendered by `show`.\n\nThe `show` events will receive the region instance, the view being shown, and any options passed to `region.show`.\n\n```javascript\nimport { Region, View } from 'backbone.marionette';\n\nconst MyRegion = Region.extend({\n  onBeforeShow(myRegion, view, options) {\n    console.log(myRegion.hasView()); //false\n    console.log(view.isRendered()); // false\n    console.log(options.foo === 'bar'); // true\n  },\n  onShow(myRegion, view, options) {\n    console.log(myRegion.hasView()); //true\n    console.log(view.isRendered()); // true\n    console.log(options.foo === 'bar'); // true\n  }\n});\n\nconst MyView = View.extend({\n  template: _.template('hello')\n});\n\nconst myRegion = new MyRegion({ el: '#dom-hook' });\n\nmyRegion.show(new MyView(), { foo: 'bar' });\n```\n\n### `empty` and `before:empty` events\n\nThese events fire before (`before:empty`) and after (`empty`) emptying a region's view.\nThese events will not fire if there is no view in the region, even if the region detaches\nDOM from within the region's `el`.\nThe view will not be detached or destroyed during `before:empty`,\nbut will be detached or destroyed during the `empty`.\n\nThe empty events will receive the region instance, the view leaving the region.\n\n```javascript\nimport { Region, View } from 'backbone.marionette';\n\nconst MyRegion = Region.extend({\n  onBeforeEmpty(myRegion, view) {\n    console.log(myRegion.hasView()); //true\n    console.log(view.isDestroyed()); // false\n  },\n  onEmpty(myRegion, view) {\n    console.log(myRegion.hasView()); //false\n    console.log(view.isDestroyed()); // true\n  }\n});\n\nconst MyView = View.extend({\n  template: _.template('hello')\n});\n\nconst myRegion = new MyRegion({ el: '#dom-hook' });\n\nmyRegion.empty(); // no events, no view emptied\n\nmyRegion.show(new MyView());\n\nmyRegion.empty();\n```\n## MnObject Events\n\nThe `MnObject` class triggers [Destroy Events](#destroy-and-beforedestroy-events).\n\n## View Events\n\n### `add:region` and `before:add:region` events\n\nThese events fire before (`before:add:region`) and after (`add:region`) a region is added to a view.\nThis event handler will receive the view instance, the region name string, and the region instance as\nevent arguments. The region is fully instantiated for both events.\n\n### `remove:region` and `before:remove:region` events\n\nThese events fire before (`before:remove:region`) and after (`remove:region`) a region is removed from a view.\nThis event handler will receive the view instance, the region name string, and the region instance as\nevent arguments. The region will be not be destroyed in the before event, but is destroyed by `remove:region`.\n\n**Note** Currently these events are only triggered using the `view.removeRegion` API and not when the region\nis destroyed directly. https://github.com/marionettejs/backbone.marionette/issues/3602\n\n## CollectionView Events\n\nThe `CollectionView` triggers unique events specifically related to child management.\n\n### `add:child` and `before:add:child` events\n\nThese events fire before (`before:add:child`) and after (`add:child`) each child view\nis instantiated and added to the [`children`](./collectionview.md#collectionviews-children).\nThese will fire once for each item in the attached collection or for any view added using\n[`addChildView`](./collectionview.md#adding-a-child-view).\n\n### `remove:child` and `before:remove:child` events\n\nThese events fire before (`before:remove:child`) and after (`remove:child`) each child view\nis removed to the [`children`](./collectionview.md#collectionviews-children).\nA view may be removed from the `children` if it is destroyed, if it is removed\nfrom the `collection` or if it is removed with [`removeChildView`](./collectionview.md#removing-a-child-view).\n\n**NOTE** A childview may or may not be destroyed by this point.\n\n**NOTE** When a `CollectionView` is destroyed it will not individually remove its `children`.\nEach childview will be destroyed, but any needed clean up during the `CollectionView`'s destruction\nshould happen in [`before:destroy:children`](#destroychildren-and-beforedestroychildren-events).\n\n### `sort` and `before:sort` events\n\nThese events fire before (`before:sort`) and after (`sort`) sorting the children in the `CollectionView`.\nThese events will only fire if there are [`children`](./collectionview.md#collectionviews-children)\nand a [`viewComparator`](./collectionview.md#defining-the-viewcomparator)\n\n### `filter` and `before:filter` events\n\nThese events fire before (`before:filter`) and after (`filter`) filtering the children in the `CollectionView`.\nThis event will only fire if there are [`children`](./collectionview.md#collectionviews-children)\nand a [`viewFilter`](./collectionview.md#defining-the-viewfilter).\n\nWhen the `filter` event is fired the children filtered out will have already been\ndetached from the view's `el`, but new children will not yet have been rendered.\nThe `filter` event not only receives the view instance, but also arrays of attached views,\nand detached views.\n\n```javascript\nconst MyCollectionView = CollectionView.extend({\n  onBeforeFilter(myCollectionView) {\n   console.log('Nothing has changed yet!');\n  },\n  onFilter(myCollectionView, attachedViews, detachedViews) {\n    console.log('Array of attached views', attachedViews);\n    console.log('Array of detached views', detachedViews);\n  }\n});\n```\n\n### `render:children` and `before:render:children` events\n\nSimilar to [`Region` `show` and `before:show` events](#show-and-beforeshow-events) these events fire\nbefore (`before:render:children`) and after (`render:children`) the `children` of the `CollectionView`\nare attached to the `CollectionView`'s `el` or `childViewContainer`.\n\nThese events will be passed the `CollectionView` instance and the array of views being attached.\nThe views in the array may or may not be rendered or attached for `before:render:children`,\nbut will be rendered and attached by `render:children`.\n\nIf the `CollectionView` can determine that added views will only be appended to the end, only the appended views\nwill be passed to the event. Otherwise all of the `children` views will be passed.\n\n**Note** if you consistently need all of the views within this event use [`children`](./marionette.collectionview.md#collectionviews-children)\n\n### `destroy:children` and `before:destroy:children` events\n\nThese events fire before (`before:destroy:children`) and after (`destroy:children`) destroying the children\nin the `CollectionView`. These events will only fire if there are [`children`](./collectionview.md#collectionviews-children).\n\n### CollectionView EmptyView Region Events\n\nThe `CollectionView` uses a region internally that can be used to know when the empty view is show or destroyed.\nSee [Region Events](#region-events).\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst MyView = CollectionView.extend({\n  emptyView: MyEmptyView\n});\n\nconst myView = new MyView();\n\nmyView.getEmptyRegion().on({\n  'show'() {\n    console.log('CollectionView is empty!');\n  },\n  'before:empty'() {\n    if (this.hasView()) {\n      console.log('CollectionView is removing the emptyView');\n    }\n  }\n});\n\nmyView.render();\n```\n\n## DOM Change Events\n\n### `render` and `before:render` events\n\nReflects when a view's template is being rendered into its `el`.\n\n`before:render` will occur prior to removing any current child views.\n`render` is an ideal event for attaching child views to the view's template as the first\nrender _generally_ occurs prior to the view attaching to the DOM.\n\n```javascript\nimport { View, CollectionView } from 'backbone.marionette';\nimport MyChildView from './MyChildView';\n\nconst MyView = View.extend({\n  template: _.template('<div class=\"foo-region\"></div>'),\n  regions: {\n    'foo': '.foo-region'\n  },\n  onRender() {\n    this.showChildView('foo', new MyChildView());\n  }\n});\n\nconst MyCollectionView = CollectionView.extend({\n  childView: MyChildView,\n  onRender() {\n    // Add a child not from the `collection`\n    this.addChildView(new MyChildView());\n  }\n})\n```\n\n**Note** This event is only triggered when rendering a template into a view. A view that\nis pre-rendered will not have this event triggered unless re-rendered. [Pre-rendered views](./dom.prerendered.md)\nshould use `initialize` for attaching child views and the `render` event if the view is re-rendered.\n\n**Note** If a view's `template` is set to `false` this event will not trigger.\n\n### `attach` and `before:attach` events\n\nReflects when the `el` of a view is attached to the DOM. These events will not trigger when\na view is re-rendered as the `el` itself does not change.\n\n`attach` is the ideal event to setup any external DOM listeners such as `jQuery` plugins\nthat use the view's `el`, but _not_ its contents.\n\n### `detach` and `before:detach` events\n\nReflects when the `el` of a view is detached from the DOM. These events will not trigger when\na view is re-rendered as the `el` itself does not change.\n\n`before:detach` is the ideal event to clean up any external DOM listeners such as `jQuery` plugins\nthat use the view's `el`, but _not_ its contents.\n\n### `dom:refresh` event\n\nReflects when the _contents_ of a view's `el` change in the DOM.\nThis event will fire when the view is first [`attach`ed](#attach-and-beforeattach-events).\nIt will also fire if an attached view is re-rendered.\n\nThis is the ideal event to setup any external DOM listeners such as `jQuery` plugins\nthat use DOM _within_ the `el` of the view and not the view's `el` itself.\n\n**NOTE** This event will not fire if the view has no template to render unless it contains\nprerendered html.\n\n### `dom:remove` event\n\nReflects when the _contents_ of a view's `el` are about to change in the DOM.\nThis event will fire when the view is about to be [`detach`ed](#detach-and-beforedetach-events).\nIt will also fire before an attached view is re-rendered.\n\nThis is the ideal event to clean up any external DOM listeners such as `jQuery` plugins\nthat use DOM _within_ the `el` of the view and not the view's `el` itself.\n\n**NOTE** This event will not fire if the view has no template to render unless it contains\nprerendered html.\n\n### Advanced Event Settings\n\nMarionette is able to trigger `attach`/`detach` events down the view tree along with\ntriggering the `dom:refresh`/`dom:remove` events because of the view event monitor.\nThis monitor starts when a view is created or shown in a region (to handle non-Marionette views).\n\nIn some cases it may be a useful performance improvement to disable this functionality.\nDoing so is as easy as setting `monitorViewEvents: false` on the view class.\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst NonMonitoredView = View.extend({\n  monitorViewEvents: false\n});\n```\n\n**Note**: Disabling the view monitor will break the monitor generated events for this view\n_and all child views_ of this view. Disabling should be done carefully.\n\n## Destroy Events\n\n### `destroy` and `before:destroy` events\n\nEvery class has a `destroy` method which can be used to clean up the instance.\nWith the exception of `Behavior`'s each of these methods triggers a `before:destroy`\nand a `destroy` event.\n\nAs a general rule, `onBeforeDestroy` is the best handler for cleanup as the instance\nand any internally created children are already destroyed by the time `onDestroy` is called.\n\n**Note** For views this is not the ideal location for clean up of anything touching the DOM.\nSee [`dom:remove`](#domremove-event) or [`before:detach`] for DOM related clean up.\n\n```javascript\nimport { Application, View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  onBeforeDestroy(options) {\n    console.log(options.foo);\n  }\n});\n\nconst myView = new MyView();\n\nmvView.destroy({ foo: 'destroy view' });\n\nconst MyApp = Application.extend({\n  onBeforeDestroy(options) {\n    console.log(options.foo);\n  }\n});\n\nconst myApp = new MyApp();\n\nmyApp.destroy({ foo: 'destroy app' });\n```\n\n#### `CollectionView` `destroy:children` and `before:destroy:children` events\n\nSimilar to `destroy`, `CollectionView` has events for when all of its children\nare destroyed. See [the CollectionView's events](#destroychildren-and-beforedestroychildren-events)\nfor more information.\n\n## Supporting Backbone Views\n\n### `Marionette.Events` and `triggerMethod`\n\nInternally Marionette uses [`triggerMethod`](./common.md#triggermethod) for event triggering.\nThis API is not available to `Backbone.View`s so in order to support `Backbone.View`s in Marionette v4+,\n`Marionette.Events` must be mixed into the non-Marionette view.\n\nThis can be done for an individual view definition:\n```javascript\nimport { Events } from 'backbone.marionette';\n\nconst MyBbView = Backbone.View.extend(Events);\n```\nor for all `Backbone.View`s\n```javascript\n_.extend(Backbone.View.prototype, Events);\n```\n\n### Lifecycle Events\n\n#### `render` and `destroy`\n\nTo support non-Marionette Views, Marionette uses two flags to determine if it should trigger\n`render` and `destroy` events on the view. If a custom view throws it's own `render` or `destroy`\nevents, the related flag should be set to `true` to avoid Marionette duplicating these events.\n\n```javascript\n// Add support for triggerMethod\nimport { Events } from 'backbone.marionette';\n\n_.extend(Backbone.View.prototype, Events);\n\nconst MyCustomView = Backbone.View.extend({\n  supportsRenderLifecycle: true,\n  supportsDestroyLifecycle: true,\n  render() {\n    this.triggerMethod('before:render');\n\n    this.$el.html('render html');\n\n    // Since render is being triggered here set the\n    // supportsRenderLifecycle flag to true to avoid duplication\n    this.triggerMethod('render');\n  },\n  destroy() {\n    this.triggerMethod('before:destroy');\n\n    this.remove();\n\n    // Since destroy is being triggered here set the\n    // supportsDestroyLifecycle flag to true to avoid duplication\n    this.triggerMethod('destroy');\n  }\n});\n```\n\n#### DOM Change Lifecycle Events\n\nAs mentioned in [Advanced Event Settings](#advanced-event-settings) some DOM events\nare triggers from the view event monitor that will handle DOM attachment related events\ndown the view tree. Backbone View's won't have the functionality unless the monitor is\nadded. This will include all [DOM Change Events](#dom-change-events) other than render.\n\nYou can add the view events monitor to any non-Marionette view:\n```javascript\nimport { monitorViewEvents, Events } from 'backbone.marionette';\n\n// Add support for triggerMethod\n_.extend(Backbone.View.prototype, Events);\n\nconst MyCustomView = Backbone.View.extend({\n  initialize() {\n    monitorViewEvents(this);\n    // Ideally this happens first prior to any rendering\n    // or attaching that might occur in the initialize\n  }\n});\n```\n"
  },
  {
    "path": "docs/events.entity.md",
    "content": "# Entity events\n\nThe [`View`, `CollectionView` and `Behavior`](./classes.md) can bind to events that occur on attached models and\ncollections - this includes both [standard backbone-events](http://backbonejs.org/#Events-catalog) and custom events.\n\nEvent handlers are called with the same arguments as if listening to the entity directly\nand called with the context of the view instance.\n\n### Model Events\n\nFor example, to listen to a model's events:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  modelEvents: {\n    'change:attribute': 'onChangeAttribute'\n  },\n\n  onChangeAttribute(model, value) {\n    console.log('New value: ' + value);\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/auvk4hps/)\n\nThe `modelEvents` attribute passes through all the arguments that are passed\nto `model.trigger('event', arguments)`.\n\nThe `modelEvents` attribute can also take a\n[function returning an object](basics.md#functions-returning-values).\n\n#### Function Callback\n\nYou can also bind a function callback directly in the `modelEvents` attribute:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  modelEvents: {\n    'change:attribute'() {\n      console.log('attribute was changed');\n    }\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/zaxLe6au/)\n\n### Collection Events\n\nCollection events work exactly the same way as [`modelEvents`](#model-events)\nwith their own `collectionEvents` key:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  collectionEvents: {\n    sync: 'onSync'\n  },\n\n  onSync(collection) {\n    console.log('Collection was synchronised with the server');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/7qyfeh9r/)\n\nThe `collectionEvents` attribute can also take a\n[function returning an object](basics.md#functions-returning-values).\n\nJust as in `modelEvents`, you can bind function callbacks directly inside the\n`collectionEvents` object:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  collectionEvents: {\n    'update'() {\n      console.log('the collection was updated');\n    }\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/ze8po0x5/)\n\n### Listening to Both\n\nIf your view has a `model` and `collection` attached, it will listen for events\non both:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n\n  modelEvents: {\n    'change:someattribute': 'onChangeSomeattribute'\n  },\n\n  collectionEvents: {\n    'update': 'onCollectionUpdate'\n  },\n\n  onChangeSomeattribute() {\n    console.log('someattribute was changed');\n  },\n\n  onCollectionUpdate() {\n    console.log('models were added or removed in the collection');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/h9ub5hp3/)\n\nIn this case, Marionette will bind event handlers to both.\n"
  },
  {
    "path": "docs/events.md",
    "content": "# Marionette Events\n\nThe Marionette Event system provides a system for objects to communicate with\neach other in a uniform way. In Marionette, this involves one object triggering\nan event that another listens to. This is an extended from of the\n[event handling system in Backbone](http://backbonejs.org/#Events), and is\ndifferent than [DOM related events](./dom.interactions.md#binding-to-user-input).\nIt is mixed in to every [Marionette class](./classes.md).\n\n## Documentation Index\n\n* [Triggering and Listening to Events](#triggering-and-listening-to-events)\n  * [`triggerMethod`](#triggermethod)\n  * [Listening to Events](#listening-to-events)\n    * [`onEvent` Binding](#onevent-binding)\n  * [View events and triggers](#view-events-and-triggers)\n  * [View entity events](#view-entity-events)\n* [Child View Events](#child-view-events)\n  * [Event Bubbling](#event-bubbling)\n    * [Using CollectionView](#using-collectionview)\n  * [A Child View's Event Prefix](#a-child-views-event-prefix)\n  * [Explicit Event Listeners](#explicit-event-listeners)\n    * [Attaching Functions](#attaching-functions)\n    * [Using `CollectionView`'s `childViewEvents`](#using-collectionviews-childviewevents)\n  * [Triggering Events on Child Events](#triggering-events-on-child-events)\n    * [Using `CollectionView`'s `childViewTriggers`](#using-collectionviews-childviewtriggers)\n* [Lifecycle Events](#lifecycle-events)\n\n\n## Triggering and Listening to Events\n\nThe traditional [event handling system in Backbone](http://backbonejs.org/#Events)\nis fully supported in Marionette. Marionette, however, provides an additional\nevent API using the `triggerMethod` method - the key difference between the two\nis that `triggerMethod` automatically calls specially named event handlers.\n\n### `triggerMethod`\n\nJust like `Backbone`'s [`trigger`](http://backbonejs.org/#Events-trigger) the\n`triggerMethod` method fires the named event on the instance - any listeners will then\nbe triggered on the event. If there are no listeners, this call will still succeed.\nAll arguments after the first event name string will be passed to all event handlers.\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  callMethod(myString) {\n    console.log(myString + ' was passed');\n  }\n});\n\nconst myView = new MyView();\n/* See Backbone.listenTo */\nmyView.on('something:happened', myView.callMethod);\n\n/* Calls callMethod('foo'); */\nmyView.triggerMethod('something:happened', 'foo');\n```\n\n[Live example](https://jsfiddle.net/marionettejs/whvgao7o/)\n\n**The `triggerMethod` method is available to [all Marionette classes](./common.md#triggermethod).**\n\n### Listening to Events\n\nMarionette's event triggers work just like regular Backbone events - you can\nuse `myView.on` and `myObject.listenTo` to act on events:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  initialize() {\n    this.on('event:happened', this.logCall);\n  },\n\n  logCall(myVal) {\n    console.log(myVal);\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/90Larbty/)\n\nYou can also use `listenTo` as in Backbone:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst OtherView = View.extend({\n  initialize(someView) {\n    this.listenTo(someView, 'event:happened', this.logCall);\n  },\n\n  logCall(myVal) {\n    console.log(myVal);\n  }\n});\n\nconst MyView = View.extend();\n\nconst myView = new MyView();\n\nconst otherView = new OtherView(myView);\n\nmyView.triggerMethod('event:happened', 'someValue'); // Logs 'someValue'\n```\n\n[Live examples](https://jsfiddle.net/marionettejs/cm2rczqz/)\n\nAs in [Backbone](http://backbonejs.org/#Events), `listenTo` will pass the object\nit is called on in as the context variable. These behave exactly as in Backbone,\nso using `object.on` will require you to unhook any event handlers yourself to\nprevent memory leaks. Marionette, however, does provide extra helpers as part of\nthe view lifecycle that bind and unbind event handlers for you. this is the\ncore of `onEvent` Binding.\n\n#### `onEvent` Binding\n\nThe major difference between `Backbone.trigger` and `triggerMethod` is\nthat `triggerMethod` can fire specially named events on the instance. For\nexample, a view that has been rendered will internally fire `view.triggerMethod('render')`\nand call `onRender` - providing a handy way to add behavior to your views.\n\nDetermining what method an event will call is easy, we will outline this with an\nexample using `before:dom:refresh` though this also works with any custom events\nyou want to fire:\n\n1. Split the words around the `:` characters - so `before`, `dom`, `refresh`\n2. Capitalize the first letter of each word - `Before`, `Dom`, `Refresh`\n3. Add a leading `on` - `on`, `Before`, `Dom`, `Refresh`\n4. Mash it into a single call - `onBeforeDomRefresh`\n\nUsing this process, `before:dom:refresh` will call the `onBeforeDomRefresh`\nmethod. Let's see it in action with a custom event:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  onMyEvent(myVal) {\n    console.log(myVal);\n  }\n});\n\nconst myView = new MyView();\n\nmyView.triggerMethod('my:event', 'someValue'); // Logs 'someValue'\n```\n\n[Live example](https://jsfiddle.net/marionettejs/oc8wwcnx/)\n\nAs before, all arguments passed into `triggerMethod` after the event name will make\ntheir way into the event handler. Using this method ensures there will be no unexpected\nmemory leaks.\n\n### View `events` and `triggers`\n\nViews can automatically bind DOM events to methods and View events with [`events`](./dom.interactions.md#view-events)\nand [`triggers`](./dom.interactions.md#view-triggers) respectively:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  events: {\n    'click a': 'showModal'\n  },\n\n  triggers: {\n    'keyup input': 'data:entered'\n  },\n\n  showModal(event) {\n    console.log('Show the modal');\n  },\n\n  onDataEntered(view, event) {\n    console.log('Data was entered');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/pq4xfchk/)\n\nFor more information, see the [DOM interactions documentation](./dom.interactions.md#binding-to-user-input).\n\n### View entity events\n\nViews can automatically bind to its model or collection with [`modelEvents`](./events.entity.md#model-events)\nand [`collectionEvents`](./events.entity.md#collection-events) respectively.\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  modelEvents: {\n    'change:someattribute': 'onChangeSomeattribute'\n  },\n\n  collectionEvents: {\n    'update': 'onCollectionUpdate'\n  },\n\n  onChangeSomeattribute() {\n    console.log('someattribute was changed');\n  },\n\n  onCollectionUpdate() {\n    console.log('models were added or removed in the collection');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/h9ub5hp3/)\n\nFor more information, see the [Entity events documentation](./events.entity.md).\n\n## Child View Events\n\nThe [`View`](marionette.view.md) and [`CollectionView`](marionette.collectionview.md)\nare able to monitor and act on events on any of their direct children. Any events fired\non a view are automatically propagated to their direct parents as well. Let's\nsee a quick example:\n\n```javascript\nimport { View, CollectionView } from 'backbone.marionette';\n\nconst Item = View.extend({\n  tagName: 'li',\n\n  triggers: {\n    'click a': 'select:item'\n  }\n});\n\nconst Collection = CollectionView.extend({\n  tagName: 'ul',\n\n  childViewEvents: {\n    'select:item': 'itemSelected'\n  },\n\n  itemSelected(childView) {\n    console.log('item selected: ' + childView.model.id);\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/opyfvsfx/)\n\n### Event Bubbling\n\nEvents fired on a view bubble up to their direct parent views, calling any\nevent methods using the `childview:` prefix (more on that shortly) and any\nmethods bound to the `childViewEvents` attribute. This works for built-in\nevents, custom events fired with `triggerMethod` and bound events using\n`triggers`.\n\n**NOTE** Automatic event bubbling can be disabled by setting\n[`childViewEventPrefix`](#a-child-views-event-prefix) to `false`.\n\nWhen using implicit listeners, the [`childview:*` event prefix](#a-child-views-event-prefix) is used which\nneeds to be included as part of the handler:\n\n```javascript\nimport { View, } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  triggers: {\n    click: 'click:view'\n  },\n\n  doSomething() {\n    this.triggerMethod('did:something', this);\n  }\n});\n\nconst ParentView = View.extend({\n  regions: {\n    foo: '.foo-hook'\n  },\n\n  onRender() {\n    this.showChildView('foo', new MyView());\n  },\n\n  onChildviewClickView(childView) {\n    console.log('View clicked ' + childView);\n  },\n\n  onChildviewDidSomething(childView) {\n    console.log('Something was done to ' + childView);\n  }\n})\n```\n\n**NOTE** `triggers` will automatically pass the child view as an argument to the parent view, however `triggerMethod` will not, and so notice that in the above example, the `triggerMethod` explicitly passes the child view.\n\n[Live example](https://jsfiddle.net/marionettejs/oquea4uy/)\n\n#### Using `CollectionView`\n\nThis works exactly the same way for the `CollectionView` and its `childView`:\n\n```javascript\nimport { View, CollectionView } from 'backbone.marionette';\n\nconst MyChild = View.extend({\n  triggers: {\n    click: 'click:child'\n  }\n});\n\nconst MyList = CollectionView.extend({\n  onChildviewClickChild(childView) {\n    console.log('Childview ' + childView + ' was clicked');\n  }\n});\n```\n\n[Live examples](https://jsfiddle.net/marionettejs/za27jys1/)\n\n### A Child View's Event Prefix\n\nYou can customize the event prefix for events that are forwarded\nthrough the view. To do this, set the `childViewEventPrefix`\non the view or collectionview. For more information on the `childViewEventPrefix` see\n[Event bubbling](#event-bubbling).\n\nThe default value for `childViewEventPrefix` is `false`. Setting this property to\n`false` will disable [automatic event bubbling](#event-bubbling).\n\n```javascript\nimport Backbone from 'backbone';\nimport { CollectionView } from 'backbone.marionette';\nimport MyChildView from './my-child-view';\n\nconst myCollection = new Backbone.Collection([{}]);\n\nconst CollectionView = CollectionView.extend({\n  childViewEventPrefix: 'some:prefix',\n  childView: MyChildView\n});\n\nconst collectionView = new CollectionView({\n  collection: myCollection\n});\n\ncollectionView.on('some:prefix:render', function(){\n  // child view was rendered\n});\n\ncollectionView.render();\n```\n\n[Live example](https://jsfiddle.net/marionettejs/as33hnk1/)\n\nThe `childViewEventPrefix` can be provided in the view definition or\nin the constructor function call, to get a view instance.\n\n### Explicit Event Listeners\n\nTo call specific functions on event triggers, use the `childViewEvents`\nattribute to map child events to methods on the parent view. This takes events\nfired on child views - _without the `childview:` prefix_ - and calls the\nmethod referenced or attached function.\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  triggers: {\n    click: 'view:clicked'\n  }\n});\n\nconst ParentView = View.extend({\n  regions: {\n    foo: '.foo-hook'\n  },\n\n  childViewEvents: {\n    'view:clicked': 'displayMessage'\n  },\n\n  onRender() {\n    this.showChildView('foo', new MyView());\n  },\n\n  displayMessage(childView) {\n    console.log('Displaying message for ' + childView);\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/y92r99p2/)\n\n#### Attaching Functions\n\nThe `childViewEvents` attribute can also attach functions directly to be event\nhandlers:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  triggers: {\n    click: 'view:clicked'\n  }\n});\n\nconst ParentView = View.extend({\n  regions: {\n    foo: '.foo-hook'\n  },\n\n  childViewEvents: {\n    'view:clicked'(childView) {\n      console.log('Function called for ' + childView);\n    }\n  },\n\n  onRender() {\n    this.showChildView('foo', new MyView());\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/pnp1dd8j/)\n\n#### Using `CollectionView`'s `childViewEvents`\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\n// childViewEvents can be specified as a hash...\nconst MyCollectionView = CollectionView.extend({\n  childViewEvents: {\n    // This callback will be called whenever a child is rendered or emits a `render` event\n    render() {\n      console.log('A child view has been rendered.');\n    }\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/a2uvcfrp/)\n\n### Triggering Events on Child Events\n\nA `childViewTriggers` hash or method permits proxying of child view events without manually\nsetting bindings. The values of the hash should be a string of the event to trigger on the parent.\n\n`childViewTriggers` is sugar on top of [`childViewEvents`](#explicit-event-listeners) much\nin the same way that [view `triggers`](./dom.interaction.md#view-triggers) are sugar for [view `events`](./dom.interactions.md#view-events).\n\n```javascript\nimport { View, CollectionView } from 'backbone.marionette';\n\n// The child view fires a custom event, `show:message`\nconst ChildView = View.extend({\n\n  // Events hash defines local event handlers that in turn may call `triggerMethod`.\n  events: {\n    'click .button': 'onClickButton'\n  },\n\n  triggers: {\n    'submit form': 'submit:form'\n  },\n\n  onClickButton () {\n    // Both `trigger` and `triggerMethod` events will be caught by parent.\n    this.trigger('show:message', 'foo');\n    this.triggerMethod('show:message', 'bar');\n  }\n});\n\n// The parent uses childViewEvents to catch the child view's custom event\nconst ParentView = CollectionView.extend({\n  childView: ChildView,\n\n  childViewTriggers: {\n    'show:message': 'child:show:message',\n    'submit:form': 'child:submit:form'\n  },\n\n  onChildShowMessage (message) {\n    console.log('A child view fired show:message with ' + message);\n  },\n\n  onChildSubmitForm (childView) {\n    console.log('A child view fired submit:form');\n  }\n});\n\nconst GrandParentView = View.extend({\n  regions: {\n    list: '.list'\n  },\n\n  onRender() {\n    this.showChildView('list', new ParentView({\n      collection: this.collection\n    }));\n  },\n\n  childViewEvents: {\n    'child:show:message': 'showMessage'\n  },\n\n  showMessage(childView) {\n    console.log('A child (' + childView + ') fired an event');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/8eq7vca5/)\n\n#### Using `CollectionView`'s `childViewTriggers`\n\n```javascript\nimport { View, CollectionView } from 'backbone.marionette';\n\n// The child view fires a custom event, `show:message`\nconst ChildView = View.extend({\n\n  // Events hash defines local event handlers that in turn may call `triggerMethod`.\n  events: {\n    'click .button': 'onClickButton'\n  },\n\n  // Triggers hash converts DOM events directly to view events catchable on the parent.\n  // Note that `triggers` automatically pass the first argument as the child view.\n  triggers: {\n    'submit form': 'submit:form'\n  },\n\n  onClickButton () {\n    // Both `trigger` and `triggerMethod` events will be caught by parent.\n    this.trigger('show:message', 'foo');\n    this.triggerMethod('show:message', 'bar');\n  }\n});\n\n// The parent uses childViewEvents to catch the child view's custom event\nconst ParentView = CollectionView.extend({\n\n  childView: ChildView,\n\n  childViewTriggers: {\n    'show:message': 'child:show:message',\n    'submit:form': 'child:submit:form'\n  },\n\n  onChildShowMessage (message) {\n    console.log('A child view fired show:message with ' + message);\n  },\n\n  onChildSubmitForm (childView) {\n    console.log('A child view fired submit:form');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/edhqd2h8/)\n\n## Lifecycle Events\n\nMarionette Views fire events during their creation and destruction lifecycle.\nFor more information see the documentation covering the\n[`View` Lifecycle](./view.lifecycle.md).\n"
  },
  {
    "path": "docs/features.md",
    "content": "# Features\n\nMarionette Features are opt-in functionality that you can enable by utilizing [`setEnabled`](#setting-a-feature-flag) in your app.\nIt is a good practice to set these flags only once prior to instantiating any Marionette class.\n\n## Documentation Index\n\n* [Goals](#goals)\n* [Checking a Feature Flag state](#checking-a-feature-flag-state)\n* [Setting a Feature Flag](#setting-a-feature-flag)\n* [Current Features](#current-features)\n\n## Goals:\n+ make it possible to add breaking changes in a minor release\n+ give community members a chance to provide feedback for new functionality\n\n## Checking a Feature Flag State\n\nUse `isEnabled` if you need to know the state of a feature flag programmatically.\n\n```javascript\nimport { isEnabled } from 'backbone.marionette';\n\nisEnabled('fooFlag'); // false\n```\n\n## Setting a Feature Flag\n\nUse `setEnabled` to change the value of a flag.\nWhile setting a flag at any point may work, these flags are designed to be set before\nany functionality of Marionette is used. Change flags after at your own risk.\n\n```javascript\nimport { setEnabled } from 'backbone.marionette';\n\nsetEnabled('fooFlag', true);\n\nconst myApp = new MyApp({\n  region: '#app-hook'\n});\n\nmyApp.start();\n```\n\n## Current Features\n\n### `childViewEventPrefix`\n\n*Default:* `false`\n\nThis flag indicates whether [`childViewEventPrefix`](./events.md#a-child-views-event-prefix)\nfor all views will return the default value of `'childview'` or if it will return `false`\ndisabling [automatic event bubbling](./events.md#event-bubbling).\n\n### `triggersPreventDefault`\n\n*Default:* `true`\n\nIt indicates the whether or not [`View.triggers` will call `event.preventDefault()`](./dom.interactions.md#view-triggers-event-object) if not explicitly defined by the trigger.\nThe default has been true, but for a future version [`false` is being considered](https://github.com/marionettejs/backbone.marionette/issues/2926).\n\n### `triggersStopPropagating`\n\n*Default:* `true`\n\nIt indicates the whether or not [`View.triggers` will call `event.stopPropagating()`](./dom.interactions.md#view-triggers-event-object) if not explicitly defined by the trigger.\nThe default has been true, but for a future version [`false` is being considered](https://github.com/marionettejs/backbone.marionette/issues/2926).\n\n### DEV_MODE\n\n*Default:* `false`\n\nIf `true`, deprecation console warnings are issued at runtime.\n"
  },
  {
    "path": "docs/installation.md",
    "content": "# Installing Marionette\n\nAs with all JavaScript libraries, there are a number of ways to get started with\na Marionette application. In this section we'll cover the most common ways.\nWhile some integrations are listed here, more resources are available in the integrations repo:\n[marionette-integrations](https://github.com/marionettejs/marionette-integrations)\n\n## Documentation Index\n\n* [NPM and Webpack](#quick-start-using-npm-and-webpack)\n* [NPM and Brunch](#quick-start-using-npm-and-brunch)\n* [NPM and Browserify](#quick-start-using-npm-and-browserify)\n* [Browserify and Grunt](#browserify-and-grunt)\n* [Browserify and Gulp](#browserify-and-gulp)\n* [Getting Started](./basics.md)\n\n## Quick start using NPM and Webpack\n[NPM](https://www.npmjs.com/) is the package manager for JavaScript.\n\nInstalling with NPM through command-line interface\n```\nnpm install backbone.marionette\n```\n\n[Webpack][webpack] is a build tool that makes it easy to pull your dependencies\ntogether into a single bundle to be delivered to your browser's `<script>` tag.\nIt works particularly well with Marionette and jQuery.\n\n[Here](https://github.com/marionettejs/marionette-integrations/tree/master/webpack)\nwe prepared simple marionettejs skeleton with Webpack.\n\n\n## Quick start using NPM and Brunch\n\n[Brunch][brunch] is fast front-end web app build tool with simple declarative config,\nseamless incremental compilation for rapid development, an opinionated pipeline\nand workflow, and core support for source maps.\n\n[Here](https://github.com/marionettejs/marionette-integrations/tree/master/brunch)\nwe prepared simple marionettejs skeleton with Brunch.\n\n\n## Quick start using NPM and Browserify\n\n[Browserify][browserify] is a build tool that makes it easy to bundle NPM\nmodules into your application, so you can `require` them as you would import\ndependencies in any other language.\n\n[Here](https://github.com/marionettejs/marionette-integrations/tree/master/browserify)\nwe prepared simple marionettejs skeleton with Browserify.\n\n### Browserify and Grunt\n\n[Grunt][grunt] is task runner. [Here](https://github.com/marionettejs/marionette-integrations/tree/master/browserify-grunt) is simple Browserify + Grunt skeleton.\n\n### Browserify and Gulp\n\n[Gulp][gulp] is streaming build system. [Here](https://github.com/marionettejs/marionette-integrations/tree/master/browserify-gulp) is simple Browserify + Gulp skeleton.\n\n\n[browserify]: http://browserify.org/\n[webpack]: https://webpack.github.io/\n[brunch]: http://brunch.io/\n[grunt]: http://gruntjs.com/\n[gulp]: http://gulpjs.com/\n\n## Getting Started\n\nAfter installing Marionette you might want to check out the basics.\n\n[Continue Reading...](./basics.md).\n\nAdditionally check out [features](./features.md) for some configurable options.\n"
  },
  {
    "path": "docs/marionette.application.md",
    "content": "# Marionette.Application\n\nThe `Application` provides hooks for organizing and initiating other elements\nand a view tree.\n\n`Application` includes:\n- [Common Marionette Functionality](./common.md)\n- [Class Events](./events.class.md#application-events)\n- [Radio API](./backbone.radio.md#marionette-integration)\n- [MnObject's API](./marionette.mnobject.md)\n\nIn addition to `MnObject`'s API, Application provides two significant additions.\nA simple lifecycle hook with [`start`](#starting-an-application) and a [single region](#application-region)\nfor attaching a view tree.\n\nOne additional difference is the `Application` [`cidPrefix`](./marionette.mnobject.md#unique-client-id) is `mna`.\n\n## Documentation Index\n\n* [Instantiating An Application](#instantiating-an-application)\n* [Starting An Application](#starting-an-application)\n* [Application Region](#application-region)\n* [Application Region Methods](#application-region-methods)\n\n## Instantiating an Application\n\nWhen instantiating a `Application` there are several properties, if passed,\nthat will be attached directly to the instance:\n`channelName`, `radioEvents`, `radioRequests`, `region`, `regionClass`\n\n```javascript\nimport { Application } from 'backbone.marionette';\n\nconst myApplication = new Application({ ... });\n```\n\n## Starting An Application\n\nOnce you have your application configured, you can kick everything off by\ncalling: `myApp.start(options)`.\n\nThis function takes a single optional argument to pass along to the events.\n\n```javascript\nimport Bb from 'backbone';\nimport { Application } from 'backbone.marionette';\n\nconst MyApp = Application.extend({\n  region: '#root-element',\n\n  initialize(options) {\n    console.log('Initialize');\n  },\n\n  onBeforeStart(app, options) {\n    this.model = new MyModel(options.data);\n  },\n\n  onStart(app, options) {\n    this.showView(new MyView({model: this.model}));\n    Bb.history.start();\n  }\n});\n\nconst myApp = new MyApp();\n\nmyApp.start({\n  data: {\n    id: 1,\n    text: 'value'\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/k05dctyt/)\n\n## Application Region\n\nAn `Application` provides a single [region](./marionette.region.md) for attaching a view tree.\nThe `region` property can be [defined in multiple ways](./marionette.region.md#defining-regions)\n\n```javascript\nimport { Application } from 'backbone.marionette';\nimport RootView from './views/root';\n\nconst MyApp = Application.extend({\n  region: '#root-element',\n\n  onStart() {\n    this.showView(new RootView());\n  }\n});\n\nconst myApp = new MyApp();\nmyApp.start();\n```\n\n[Live example](https://jsfiddle.net/marionettejs/uzc8or6u/)\n\nThis will immediately render `RootView` and fire the usual triggers such as\n`before:attach` and `attach` in addition to the `before:render` and `render`\ntriggers.\n\n`region` can also be passed as an option during instantiation.\n\n### `regionClass`\n\nBy default the [`Region`](./marionette.region.md) is used to instantiate the `Application`'s region.\nAn extended Region can be provided to the `Application` definition to override the default.\n\n```javascript\nimport { Application, Region } from 'backbone.marionette';\n\nconst MyRegion = Region.extend({\n  isSpecial: true\n});\n\nconst MyApp = Application.extend({\n  regionClass: MyRegion\n});\n\nconst myApp = new Application({ region: '#foo' });\n\nmyApp.getRegion().isSpecial; // true\n```\n\n`regionClass` can also be passed as an option during instantiation.\n\n## Application Region Methods\n\nThe Marionette Application provides helper methods for managing its attached region.\n\n### `getRegion()`\n\nReturn the attached [region object](./marionette.region.md) for the Application.\n\n### `showView(view)`\n\nDisplay a `View` instance in the region attached to the Application. This runs the [`View lifecycle`](./view.lifecycle.md).\n\n### `getView()`\n\nReturn the view currently being displayed in the Application's attached\n`region`. If the Application is not currently displaying a view, this method\nreturns `undefined`.\n"
  },
  {
    "path": "docs/marionette.behavior.md",
    "content": "# Marionette.Behavior\n\nA `Behavior` provides a clean separation of concerns to your view logic,\nallowing you to share common user-facing operations between your views.\n\n`Behavior` includes:\n- [Common Marionette Functionality](./common.md)\n- [Class Events](./events.class.md#behavior-events)\n- [DOM Interactions](./dom.interactions.md)\n- [Entity Events](./events.entity.md)\n\n`Behavior`s are particularly good at factoring out the common user, model and\ncollection interactions to be utilized across your application. Unlike the other\nMarionette classes, `Behavior`s are not meant to be instantiated directly.\nInstead a `Behavior` should be instantiated by the view it is related to by\n[attaching the a behavior class definition to the view](#using-behaviors).\n\n## Documentation Index\n\n* [Instantiating a Behavior](#instantiating-a-behavior)\n* [Using Behaviors](#using-behaviors)\n  * [Defining and Attaching Behaviors](#defining-and-attaching-behaviors)\n  * [Behavior Options](#behavior-options)\n* [Nesting Behaviors](#nesting-behaviors)\n* [The Behavior's `view`](#the-behaviors-view)\n* [View Proxy](#view-proxy)\n  * [Listening to View Events](#listening-to-view-events)\n  * [Proxy Handlers](#proxy-handlers)\n  * [Events / Initialize Order](#events--initialize-order)\n  * [Using `ui`](#using-ui)\n  * [View DOM proxies](#view-dom-proxies)\n* [Destroying a Behavior](#destroying-a-behavior)\n\n\n## Instantiating a Behavior\n\nUnlike other [Marionette classes](./classes.md), `Behavior`s are not meant to\nbe instantiated except by a view.\n\n## Using Behaviors\n\nThe easiest way to see how to use the `Behavior` class is to take an example\nview and factor out common behavior to be shared across other views.\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  ui: {\n    destroy: '.destroy-btn'\n  },\n\n  events: {\n    'click @ui.destroy': 'warnBeforeDestroy'\n  },\n\n  warnBeforeDestroy() {\n    alert('You are about to destroy all your data!');\n    this.destroy();\n  },\n\n  onRender() {\n    this.ui.destroy.tooltip({\n      text: 'What a nice mouse you have.'\n    });\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/pa8ryv03/)\n\nInteraction points, such as tooltips and warning messages, are generic concepts.\nThere is no need to recode them within your Views so they are prime candidates\nto be extracted into `Behavior` classes.\n\n### Defining and Attaching Behaviors\n\n```javascript\nimport { Behavior, View } from 'backbone.marionette';\n\nconst DestroyWarn = Behavior.extend({\n  // You can set default options\n  // They will be overridden if you pass in an option with the same key.\n  options: {\n    message: 'You are destroying!'\n  },\n\n  ui: {\n    destroy: '.destroy-btn'\n  },\n\n  // Behaviors have events that are bound to the views DOM.\n  events: {\n    'click @ui.destroy': 'warnBeforeDestroy'\n  },\n\n  warnBeforeDestroy() {\n    const message = this.getOption('message');\n    window.alert(message);\n    // Every Behavior has a hook into the\n    // view that it is attached to.\n    this.view.destroy();\n  }\n});\n\nconst ToolTip = Behavior.extend({\n  options: {\n    text: 'Tooltip text'\n  },\n\n  ui: {\n    tooltip: '.tooltip'\n  },\n\n  onRender() {\n    this.ui.tooltip.tooltip({\n      text: this.getOption('text')\n    });\n  }\n});\n\nconst MyView = View.extend({\n  behaviors: [DestroyWarn, ToolTip]\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/b1awta6u/)\n\nEach behavior will now be able to respond to user interactions as though the\nevent handlers were attached to the view directly. In addition to using array\nnotation, Behaviors can be attached using an object:\n\n```javascript\nconst MyView = View.extend({\n  behaviors: {\n    destroy: DestroyWarn,\n    tooltip: ToolTip\n  }\n});\n```\n\n#### Behavior Options\n\nWhen we attach behaviors to views, we can also pass in options to add to the\nbehavior. This tends to be static information relating to what the behavior\nshould do. In our above example, we want to override the message to our\n`DestroyWarn` and `Tooltip` behaviors to match the original message on the View:\n\n```javascript\nconst MyView = View.extend({\n  behaviors: [\n    {\n      behaviorClass: DestroyWarn,\n      message: 'You are about to destroy all your data!'\n    },\n    {\n      behaviorClass: ToolTip,\n      text: 'What a nice mouse you have.'\n    }\n  ]\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/vq9k3c69/)\n\nThere are several properties, if passed, that will be attached directly to the instance:\n`collectionEvents`, `events`, `modelEvents`, `triggers`, `ui`\n\nUsing an object, we must define the `behaviorClass` attribute to refer to our\nbehaviors and then add any extra options with keys matching the option we want\nto override. Any passed options will override the values from `options` property.\n\n**Errors** An error will be thrown if the `Behavior` class is not passed.\n\n## Nesting Behaviors\n\nIn addition to extending a `View` with `Behavior`, a `Behavior` can itself use\nother Behaviors. The syntax is identical to that used for a `View`:\n\n```javascript\nimport { Behavior } from 'backbone.marionette';\n\nconst Modal = Behavior.extend({\n  behaviors: [\n    {\n      behaviorClass: DestroyWarn,\n      message: 'Whoa! You sure about this?'\n    }\n  ]\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/7ffnqff3/)\n\nNested Behaviors act as if they were direct Behaviors of the parent `Behavior`'s\nview instance.\n\n## The Behavior's `view`\nThe `view` is a reference to the `View` instance that the `Behavior` is attached to.\n\n```javascript\nimport { Behavior } from 'backbone.marionette';\n\nBehavior.extend({\n  handleDestroyClick() {\n    this.view.destroy();\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/p8vymo4j/)\n\n## View Proxy\n\nThe `Behavior` class provides proxies for a selection of `View` functionality.\nThis includes [listening to events on the view](), being able to [handle events on\nmodels and collections](), and being able to directly [interact with the attached\ntemplate]().\n\n### Listening to View Events\n\nBehaviors are powered by an event proxy. This means that any events that are\ntriggered on a `View` are passed to all attached `behaviors`. This includes:\n\n* Events fired by `triggerMethod`\n* Events fired from `triggers`\n* Events fired by `childViewTriggers`\n* Events fired from `childView`\n\nThese handlers work exactly as they do on `View` -\n[see the `View` documentation](./marionette.view.md#events)\n\n> Be default all events triggered on the behavior come from the view or the view's entities.\n> Events triggered in the behavior instance are not executed in the view. To notify\n> the view, the behavior must trigger an event in its view property, e.g, `this.view.trigger('my:event')`\n\n### Proxy Handlers\n\nBehaviors provide proxies to a number of the view event handling attributes\nincluding:\n\n* [`events`](./dom.interactions.md#view-events)\n* [`triggers`](./dom.interactions.md#view-triggers)\n* [`modelEvents`](./events.entity.md#model-events)\n* [`collectionEvents`](./events.entity.md#collection-events)\n\n```javascript\nimport { Behavior } from 'backbone.marionette';\n\nBehavior.extend({\n  events: {\n    'click .foo-button': 'onClickFooButton'\n  },\n  triggers: {\n    'click .bar-button': 'click:barButton'\n  },\n  modelEvents: {\n    'change': 'onChangeModel'\n  },\n  collectionEvents: {\n    'change': 'onChangeCollection'\n  },\n  onClickFooButton(evt) {\n    // ..\n  },\n  onClickBarButton(view, evt) {\n    // ..\n  },\n  onChangeModel(model, opts) {\n    // ..\n  },\n  onChangeCollection(model, opts) {\n    // ..\n  }\n});\n```\n\n### Events / Initialize Order\n\nIf both view and behavior are listening for the same event, this will be executed\nfirst in the view then in the behavior as below.\n\nThe View + Behavior initialize process is as follows:\n\n1. View is constructed\n2. Behavior is constructed\n3. Behavior is initialized with view property set\n4. View is initialized\n5. View triggers an `initialize` event on the behavior.\n\nThis means that the behavior can access the view during its own `initialize` method.\nThe view `initialize` is called later with the information eventually injected by the behavior.\nThe `initialize` event is triggered on the behavior indicating that the view is fully initialized.\n\n[Live example](https://jsfiddle.net/marionettejs/qb9go1y3/)\n\n#### Using `ui`\n\nAs in views, `events` and `triggers` can use the `ui` references in their\nlisteners. For more details, see the [`ui` documentation](./dom.interactions.md#organizing-your-view).\nThese can be defined on either the Behavior or the View:\n\n```javascript\nimport { Behavior } from 'backbone.marionette';\n\nconst MyBehavior = Behavior.extend({\n  ui: {\n    saveForm: '.btn-save'\n  },\n\n  events: {\n    'click @ui.saveForm': 'saveForm'\n  },\n\n  modelEvents: {\n    invalid: 'showError'\n  },\n\n  saveForm() {\n    this.view.model.save();\n  },\n\n  showError() {\n    alert('You have errors');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/6b8o3pmz/)\n\nIf your `ui` keys clash with keys on the attached view, the view's `ui`\ndeclarations will take precidence over the behavior's `ui`.\nThis allows for behaviors to be more easily reused without dictating\nnecessary structures within the view itself.\n\n```javascript\nimport { Behavior, View } from 'backbone.marionette';\n\nconst MyBehavior = Behavior.extend({\n  ui: {\n    saveForm: '.btn-save'\n  },\n\n  events: {\n    'click @ui.saveForm': 'saveForm'  // .btn-primary when used with `FirstView`\n  },\n\n  saveForm() {\n    this.view.model.save();\n  }\n});\n\nconst FirstView = View.extend({\n  behaviors: [MyBehavior],\n\n  ui: {\n    saveForm: '.btn-primary'\n  },\n\n  events: {\n    'click @ui.saveForm': 'checkForm'  // .btn-primary\n  },\n\n  checkForm() {\n    // ...\n  }\n});\n```\n\n### View DOM proxies\n\nThe `Behavior` has a number of proxies attributes that directly refer to the\nrelated attribute on a view:\n\n* `$`\n* `el`\n* `$el`\n\nIn addition, each behavior is able to reference the view they are attached to\nthrough the `view` attribute:\n\n```javascript\nimport { Behavior } from 'backbone.marionette';\n\nconst ViewBehavior = Behavior.extend({\n  onRender() {\n    const shouldHighlight = this.view.model.get('selected');\n    this.$el.toggleClass('highlight', shouldHighlight);\n    this.$('.view-class').addClass('highlighted-icon');\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/8dmk30Lq/)\n\n**Note** in rare cases when a view's `el` is modified via `setElement` if utilizing\nthese proxies they will need to be manually updated by calling\n`myBehavior.proxyViewProperties();`\n\n## Destroying a Behavior\n\n`myBehavior.destroy()` will call `stopListening` on the behavior instance, and it will\nremove the behavior from the view.\n"
  },
  {
    "path": "docs/marionette.collectionview.md",
    "content": "# Marionette.CollectionView\n\nA `CollectionView` like `View` manages a portion of the DOM via a single parent DOM element\nor `el`. This view manages an ordered set of child views that are shown within the view's `el`.\nThese children are most often created to match the models of a `Backbone.Collection` though a\n`CollectionView` does not require a `collection` and can manage any set of views.\n\n`CollectionView` includes:\n- [The DOM API](./dom.api.md)\n- [Class Events](./events.class.md#collectionview-events)\n- [DOM Interactions](./dom.interactions.md)\n- [Child Event Bubbling](./events.md#event-bubbling)\n- [Entity Events](./events.entity.md)\n- [View Rendering](./view.rendering.md)\n- [Prerendered Content](./dom.prerendered.md)\n- [View Lifecycle](./view.lifecycle.md)\n\nA `CollectionView` can have [`Behavior`s](./marionette.behavior.md).\n\n## Documentation Index\n\n* [Instantiating a CollectionView](#instantiating-a-collectionview)\n* [Rendering a CollectionView](#rendering-a-collectionview)\n  * [Rendering a Template](#rendering-a-template)\n  * [Defining the `childViewContainer`](#defining-the-childviewcontainer)\n  * [Re-rendering the CollectionView](#re-rendering-the-collectionview)\n* [View Lifecycle and Events](#view-lifecycle-and-events)\n* [Entity Events](#entity-events)\n* [DOM Interactions](#dom-interactions)\n* [Behaviors](#behaviors)\n* [Managing Children](#managing-children)\n  * [Attaching `children` within the `el`](#attaching-children-within-the-el)\n  * [Destroying All `children`](#destroying-all-children)\n* [CollectionView's `childView`](#collectionviews-childview)\n  * [Building the `children`](#building-the-children)\n  * [Passing Data to the `childView`](#passing-data-to-the-childview)\n* [CollectionView's `emptyView`](#collectionviews-emptyview)\n  * [CollectionView's `getEmptyRegion`](#collectionviews-getemptyregion)\n  * [Passing Data to the `emptyView`](#passing-data-to-the-emptyview)\n  * [Defining When an `emptyView` shows](#defining-when-an-emptyview-shows)\n* [Accessing a Child View](#accessing-a-child-view)\n  * [CollectionView `children` Iterators And Collection Functions](collectionview-children-iterators-and-collection-functions)\n* [Listening to Events on the `children`](#listening-to-events-on-the-children)\n* [Self Managed `children`](#self-managed-children)\n  * [Adding a Child View](#adding-a-child-view)\n  * [Removing a Child View](#removing-a-child-view)\n  * [Detaching a Child View](#detaching-a-child-view)\n  * [Swapping Child Views](#swapping-child-views)\n* [Sorting the `children`](#sorting-the-children)\n  * [Defining the `viewComparator`](#defining-the-viewcomparator)\n  * [Maintaining the `collection`'s sort](#maintaining-the-collections-sort)\n* [Filtering the `children`](#filtering-the-children)\n  * [Defining the `viewFilter`](#defining-the-viewfilter)\n\n## Instantiating a CollectionView\n\nWhen instantiating a `CollectionView` there are several properties, if passed,\nthat will be attached directly to the instance:\n`attributes`, `behaviors`, `childView`, `childViewContainer`, `childViewEventPrefix`,\n`childViewEvents`, `childViewOptions`, `childViewTriggers`, `className`, `collection`,\n`collectionEvents`, `el`, `emptyView`, `emptyViewOptions`, `events`, `id`, `model`,\n`modelEvents`, `sortWithCollection`, `tagName`, `template`, `templateContext`,\n`triggers`, `ui`, `viewComparator`, `viewFilter`\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst myCollectionView = new CollectionView({ ... });\n```\n\nSome of these properties come from Marionette, but many are inherited from\n[`Backbone.View`](http://backbonejs.org/#View-constructor).\n\n## Rendering a CollectionView\n\nThe `render` method of the `CollectionView` is primarily responsible\nfor rendering the entire collection. It loops through each of the\nchildren in the collection and renders them individually as a\n`childView`.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst MyCollectionView = CollectionView.extend({...});\n\n// all of the children views will now be rendered.\nnew MyCollectionView().render();\n```\n\n### Rendering a Template\n\nIn addition to rendering children, the `CollectionView` may have a\n`template`.  The child views can be rendered within a DOM element of\nthis template. The `CollectionView` will serialize either the `model`\nor `collection` along with context for the `template` to render.\n\nFor more detail on how to render templates, see\n[View Template Rendering](./view.rendering.md).\n\n### Defining the `childViewContainer`\n\nBy default the `CollectionView` will render the children into the `el`\nof the `CollectionView`. If you are rendering a template you will want\nto set the `childViewContainer` to be a selector for an element within\nthe template for child view attachment.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst MyCollectionView = CollectionView.extend({\n  childViewContainer: '.js-widgets',\n  template: _.template('<h1>Widgets</h1><ul class=\"js-widgets\"></ul>')\n});\n```\n\n**Errors** An error will throw if the childViewContainer can not be found.\n\n### Re-rendering the CollectionView\n\nIf you need to re-render the entire collection or the template, you can call the\n`collectionView.render` method. This method will destroy all of\nthe child views that may have previously been added.\n\n## View Lifecycle and Events\n\nAn instantiated `CollectionView` is aware of its lifecycle state and will throw events related\nto when that state changes. The view states indicate whether the view is rendered, attached to\nthe DOM, or destroyed.\n\nRead More:\n- [View Lifecycle](./view.lifecycle.md)\n- [View DOM Change Events](./events.class.md#dom-change-events)\n- [View Destroy Events](./events.class.md#destroy-events)\n\n## Entity Events\n\nThe `CollectionView` can bind to events that occur on the attached `model` and `collection` - this\nincludes both [standard backbone-events](http://backbonejs.org/#Events-catalog) and custom events.\n\nRead More:\n- [Entity Events](./events.entity.md)\n\n## DOM Interactions\n\nIn addition to what Backbone provides the views, Marionette has additional API\nfor DOM interactions: `events`, `triggers`, and `ui`.\n\nBy default `ui` is only bound to the elements within the [template](#rendering-a-template).\nHowever as `events` and `triggers` are delegated to the view's `el` they will apply to any children.\nThere may be instances where binding `ui` is helpful when you want to access elements inside\n`CollectionView`s children with [`getUI()`](./dom.interactions.md#accessing-ui-elements). For these\ncases you will need to bind `ui` yourself. To do so run `bindUIElements` on the `CollectionView`:\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst MyCollectionView = CollectionView.extend({\n  // ...\n\n  ui: {\n    checkbox: 'input[type=\"checkbox\"]'\n  }\n});\n\nconst collectionView = new MyCollectionView();\n\ncollectionView.bindUIElements();\n\nconsole.log(collectionView.getUI('checkbox')); // Output all checkboxes.\n```\n\nRead More:\n- [DOM Interactions](./dom.interactions.md)\n\n## Behaviors\n\nA `Behavior` provides a clean separation of concerns to your view logic,\nallowing you to share common user-facing operations between your views.\n\nRead More:\n- [Using `Behavior`s](./marionette.behavior.md#using-behaviors)\n\n## Managing Children\n\nChildren are automatically managed once the `CollectionView` is\n[rendered](#rendering-a-collectionview). For each model within the\n`collection` the `CollectionView` will build and store a `childView`\nwithin its `children` object. This allows you to easily access\nthe views within the collection view, iterate them, find them by\na given indexer such as the view's model or id and more.\n\nAfter the initial `render` the `CollectionView` binds to the `update`\nand `reset` events of the `collection`.\n\nWhen the `collection` for the view is `reset`, the view will destroy all\nchildren and re-render the entire collection.\n\nWhen a model is added to the `collection`, the `CollectionView` will render that\none model into the `children`.\n\nWhen a model is removed from the `collection` (or destroyed / deleted), the `CollectionView`\nwill destroy and remove that model's child view.\n\nWhen the `collection` for the view is sorted, the view by default automatically re-sorts\nits child views unless the `sortWithCollection` attribute on the `CollectionView` is set\nto `false`, or the `viewComparator` is `false`.\n\n```javascript\nimport Backbone from 'backbone';\nimport { View, CollectionView } from 'backbone.marionette';\n\nconst collection = new Backbone.Collection();\n\nconst MyChildView = View.extend({\n  template: false\n});\n\nconst MyCollectionView = CollectionView.extend({\n  childView: MyChildView,\n  collection,\n});\n\nconst myCollectionView = new MyCollectionView();\n\n// Collection view will not re-render as it has not been rendered\ncollection.reset([{foo: 'foo'}]);\n\nmyCollectionView.render();\n\n// Collection view will effectively re-render displaying the new model\ncollection.reset([{foo: 'bar'}]);\n```\n\nWhen the children are rendered the\n[`render:children` and `before:render:children` events](./events.class.md#renderchildren-and-beforerenderchildren-events)\nwill trigger.\n\nWhen a childview is added to the children\n[`add:child` and `before:add:child` events](./events.class.md#addchild-and-beforeaddchild-events)\nwill trigger\n\nWhen a childview is removed from the children\n[`remove:child` and `before:remove:child` events](./events.class.md#removechild-and-beforeremovechild-events)\nwill trigger.\n\n### Attaching `children` within the `el`\n\nBy default the `CollectionView` will add the HTML of each ChildView\ninto an element buffer array, and then call the DOM API's\n[appendContents](./dom.api.md#appendcontentsel-contents) once at the end\nto move all of the HTML within the collection view's `el`.\n\nYou can override this by specifying an `attachHtml` method in your\nview definition. This method takes two parameters and has no return value.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nCollectionView.extend({\n\n  // The default implementation:\n  attachHtml(els, $container){\n    // Unless childViewContainer, $container === this.$el\n    this.Dom.appendContents(this.el, els);\n  }\n});\n```\n\nThe first parameter is the HTML buffer, and the second parameter\nis the expected container for the children which by default equates\nto the view's `el` unless a [`childViewContainer`](#defining-the-childViewContainer)\nis set.\n\n### Destroying All `children`\n\n`CollectionView` implements a `destroy` method which automatically\ndestroys its children and cleans up listeners.\n\nWhen the children are destroyed the\n[`destroy:children` and `before:destroy:children` events](./events.class.md#destroychildren-and-beforedestroychildren-events)\nwill trigger.\n\nRead More:\n- [View Destroy Events](./events.class.md#destroy-events)\n\n## CollectionView's `childView`\n\nWhen using a `collection` to manage the children of `CollectionView`,\nspecify a `childView` for your `CollectionView`. This must be\na Backbone view class definition, not an instance. It can be any\n`Backbone.View` related class including both Marionette's `View` and\n`CollectionView`.\n\n```javascript\nimport { View, CollectionView } from 'backbone.marionette';\n\nconst MyChildView = View.extend({});\n\nconst MyCollectionView = CollectionView.extend({\n  childView: MyChildView\n});\n```\n\n**Errors** If you do not specify a `childView`, an exception will be thrown\nstating that you must specify a `childView`.\n\nYou can also define `childView` as a function. In this form, the value\nreturned by this method is the `ChildView` class that will be instantiated\nwhen a `Model` needs to be initially rendered. This method also gives you\nthe ability to customize per `Model` `ChildViews`.\n\n```javascript\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport { View, CollectionView } from 'backbone.marionette';\n\nconst FooView = View.extend({\n  template: _.template('foo')\n});\n\nconst BarView = View.extend({\n  bar\n});\n\nconst MyCollectionView = CollectionView.extend({\n  collection: new Backbone.Collection(),\n  childView(item) {\n    // Choose which view class to render,\n    // depending on the properties of the item model\n    if  (item.get('isFoo')) {\n      return FooView;\n    }\n    else {\n      return BarView;\n    }\n  }\n});\n\nconst collectionView = new MyCollectionView();\n\nconst foo = new Backbone.Model({\n  isFoo: true\n});\n\nconst bar = new Backbone.Model({\n  isFoo: false\n});\n\n// Renders a FooView\ncollectionView.collection.add(foo);\n\n// Renders a BarView\ncollectionView.collection.add(bar);\n```\n\n**Errors** If `childView` is a function that does not return a view class\nan error will be thrown.\n\n### Building the `children`\n\nThe `buildChildView` method is responsible for taking the ChildView class and\ninstantiating it with the appropriate data. This method takes three\nparameters and returns a view instance to be used as the child view.\n\n```javascript\nbuildChildView(child, ChildViewClass, childViewOptions){\n  // build the final list of options for the childView class\n  const options = _.extend({model: child}, childViewOptions);\n  // create the child view instance\n  const view = new ChildViewClass(options);\n  // return it\n  return view;\n},\n```\n\nOverride this method when you need a more complicated build, but use [`childView`](#collectionviews-childview)\nif you need to determine _which_ View class to instantiate.\n\n```javascript\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport { CollectionView } from 'backbone.marionette';\nimport MyListView from './my-list-view';\nimport MyView from './my-view';\n\nconst MyCollectionView = CollectionView.extend({\n  childView(child) {\n    if (child.get('type') === 'list') {\n      return MyListView;\n    }\n\n    return MyView;\n  },\n  buildChildView(child, ChildViewClass, childViewOptions) {\n    const options = {};\n\n    if (child.get('type') === 'list') {\n      const childList = new Backbone.Collection(child.get('list'));\n      options = _.extend({collection: childList}, childViewOptions);\n    } else {\n      options = _.extend({model: child}, childViewOptions);\n    }\n\n    // create the child view instance\n    const view = new ChildViewClass(options);\n    // return it\n    return view;\n  }\n});\n```\n\n### Passing Data to the `childView`\n\nThere may be scenarios where you need to pass data from your parent\ncollection view in to each of the childView instances. To do this, provide\na `childViewOptions` definition on your collection view as an object\nliteral. This will be passed to the constructor of your childView as part\nof the `options`.\n\n```javascript\nimport { View, CollectionView } from 'backbone.marionette';\n\nconst ChildView = View.extend({\n  initialize(options) {\n    console.log(options.foo); // => \"bar\"\n  }\n});\n\nconst MyCollectionView = CollectionView.extend({\n  childView: ChildView,\n\n  childViewOptions: {\n    foo: 'bar'\n  }\n});\n```\n\nYou can also specify the `childViewOptions` as a function, if you need to\ncalculate the values to return at runtime. The model will be passed into\nthe function should you need access to it when calculating\n`childViewOptions`. The function must return an object, and the attributes\nof the object will be copied to the `childView` instance's options.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst MyCollectionView = CollectionView.extend({\n  childViewOptions(model) {\n    // do some calculations based on the model\n    return {\n      foo: 'bar'\n    };\n  }\n});\n```\n\n## CollectionView's `emptyView`\n\nWhen a collection has no children, and you need to render a view other than\nthe list of childViews, you can specify an `emptyView` attribute on your\ncollection view. The `emptyView` just like the [`childView`](#collectionviews-childview) can also be passed as an option on instantiation or can be a\nfunction that returns the `emptyView`.\n\n```javascript\nimport _ from 'underscore';\nimport { View, CollectionView } from 'backbone.marionette';\n\nconst MyEmptyView = View.extend({\n  template: _.template('Nothing to display.')\n});\n\nconst MyCollectionView = CollectionView.extend({\n  // ...\n\n  emptyView: MyEmptyView\n});\n```\n\n### CollectionView's `getEmptyRegion`\n\nWhen a `CollectionView` is instantiated it creates a region for showing the [`emptyView`](#collectionviews-emptyview).\nThis region can be requested using the `getEmptyRegion` method. The region will share the `el` with the `CollectionView`\nand is shown with [`replaceElement: false`](./marionette.region.md#additional-options).\n\n**Note** The `CollectionView` expects to be the only entity managing the region.\nShowing things in this region directly is not advised.\n\n```javascript\nconst isEmptyShowing = myCollectionView.getEmptyRegion().hasView();\n```\n\nThis region can be useful for handling the\n[EmptyView Region Events](./events.class.md#collectionview-emptyview-region-events).\n\n### Passing Data to the `emptyView`\n\nSimilar to [`childView`](#collectionviews-childview) and [`childViewOptions`](#padding-data-to-the-childview),\nthere is an `emptyViewOptions` property that will be passed to the `emptyView` constructor.\nIt can be provided as an object literal or as a function.\n\nIf `emptyViewOptions` aren't provided the `CollectionView` will default to passing the `childViewOptions` to the `emptyView`.\n\n```javascript\nimport { View, CollectionView } from 'backbone.marionette';\n\nconst EmptyView = View.extend({\n  initialize(options){\n    console.log(options.foo); // => \"bar\"\n  }\n});\n\nconst MyCollectionView = CollectionView.extend({\n  emptyView: EmptyView,\n\n  emptyViewOptions: {\n    foo: 'bar'\n  }\n});\n```\n\n### Defining When an `emptyView` shows\n\nIf you want to control when the empty view is rendered, you can override\n`isEmpty`:\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst MyCollectionView = CollectionView.extend({\n  isEmpty() {\n    // some logic to calculate if the view should be rendered as empty\n    return this.collection.length < 2;\n  }\n});\n```\n\nThe default implementation of `isEmpty` returns `!this.children.length`.\n\nYou can also use this method to determine when the empty view was shown:\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst MyCollectionView = CollectionView.extend({\n  // ...\n  onRenderChildren() {\n    if (this.isEmpty()) { console.log('Empty View Shown'); }\n  }\n});\n```\n\n## Accessing a Child View\n\nYou can retrieve a view by a number of methods. If the findBy* method cannot find the view,\nit will return `undefined`.\n\n**Note** That `children` represents the views rendered that are or will be\nattached within the view's `el`.\n\n#### CollectionView `children`'s: `findByCid`\nFind a view by its cid.\n\n```javascript\nconst bView = myCollectionView.children.findByCid(buttonView.cid);\n```\n\n#### CollectionView `children`'s: `findByModel`\nFind a view by model.\n\n```javascript\nconst bView = myCollectionView.children.findByModel(buttonView.model);\n```\n\n#### CollectionView `children`'s: `findByModelCid`\nFind a view by model cid.\n\n```javascript\nconst bView = myCollectionView.children.findByModelCid(buttonView.model.cid);\n```\n\n#### CollectionView `children`'s: `findByIndex`\n\nFind by numeric index (unstable)\n\n```javascript\nconst bView = myCollectionView.children.findByIndex(0);\n```\n\n#### CollectionView `children`'s: `findIndexByView`\n\nFind the index of the view inside the children\n\n```javascript\nconst index = myCollectionView.children.findIndexByView(bView);\n```\n\n### CollectionView `children` Iterators And Collection Functions\n\nThe container object borrows several functions from\n[Underscore.js](http://underscorejs.org/), to provide iterators and other\ncollection functions, including:\n\n* [each](http://underscorejs.org/#each)\n* [map](http://underscorejs.org/#map)\n* [reduce](http://underscorejs.org/#reduce)\n* [find](http://underscorejs.org/#find)\n* [filter](http://underscorejs.org/#filter)\n* [reject](http://underscorejs.org/#reject)\n* [every](http://underscorejs.org/#every)\n* [some](http://underscorejs.org/#some)\n* [contains](http://underscorejs.org/#contains)\n* [invoke](http://underscorejs.org/#invoke)\n* [toArray](http://underscorejs.org/#toArray)\n* [first](http://underscorejs.org/#first)\n* [initial](http://underscorejs.org/#initial)\n* [rest](http://underscorejs.org/#rest)\n* [last](http://underscorejs.org/#last)\n* [without](http://underscorejs.org/#without)\n* [isEmpty](http://underscorejs.org/#isEmpty)\n* [pluck](http://underscorejs.org/#pluck)\n* [partition](http://underscorejs.org/#partition)\n\nThese methods can be called directly on the container, to iterate and process\nthe views held by the container.\n\n```javascript\nimport Backbone from 'backbone';\nimport { CollectionView } from 'backbone.marionette';\n\nconst collectionView = new CollectionView({\n  collection: new Backbone.Collection()\n});\n\ncollectionView.render();\n\n// iterate over all of the views and process them\ncollectionView.children.each(function(childView) {\n  // process the `childView` here\n});\n```\n\n## Listening to Events on the `children`\n\nThe `CollectionView` can take action depending on what\nevents are triggered in its `children`.\n\nRead More:\n- [Child Event Bubbling](./events.md#event-bubbling)\n\n## Self-Managed `children`\n\nIn addition to children added by Marionette matching the model of a `collection`,\nthe `children` of the `CollectionView` can be manually managed.\n\n### Adding a Child View\n\nThe `addChildView` method can be used to add a view that is independent of your\n`Backbone.Collection`. This method takes three parameters, the child view instance,\noptionally the index for where it should be placed within the\n[CollectionView's `children`](#managing-children), and an options hash.\nIt returns the added view.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\nimport ButtonView from './button-view';\n\nconst MyCollectionView = CollectionView.extend({\n  onRender() {\n    View = new ButtonView();\n    this.addChildView(buttonView, this.children.length);\n  }\n});\n\nconst myCollectionView = new MyCollectionView();\n\nmyCollectionView.render();\n```\n**Note** Unless an index is specified, this added view will be subject to filtering\nand sorting and may be difficult to manage in complex situations. Use with care.\n\n**Errors** An error will be thrown if the view is already shown in a Region or CollectionView.\n\n#### `preventRender` option\n\nIf you wish to add a child view to the children without the collectionview rendering\nthe children use the `preventRender` option.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\nimport ButtonView from './button-view';\n\nconst myCollectionView = new CollectionView({...});\n\nconst insertIndex = 0; // Add to the top\n\nmyCollectionView.addChildView(new ButtonView(), { preventRender: true, index: insertIndex });\nmyCollectionView.addChildView(new ButtonView(), insertIndex, { preventRender: true });\nmyCollectionView.addChildView(new ButtonView());  // renders all three children\n```\n\n### Removing a Child View\n\nThe `removeChildView` method is useful if you need to remove and destroy a view from\nthe `CollectionView` without affecting the view's collection.  In most cases it is\nbetter to use the data to determine what the `CollectionView` should display.\n\nThis method accepts the child view instance to remove as its parameter. It returns\nthe removed view.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst MyCollectionView = CollectionView.extend({\n  onChildViewFooEvent(childView, model) {\n    // NOTE: we must wait for the server to confirm\n    // the destroy PRIOR to removing it from the collection\n    model.destroy({wait: true});\n\n    // but go ahead and remove it visually\n    this.removeChildView(childView);\n  }\n});\n```\n\n### Detaching a Child View\n\nThe `detachChildView` method is the same as [`removeChildView`](#removing-a-child-view)\nwith the exception that the removed view is not destroyed.\n\n### Swapping Child Views\n\nSwap the location of two views in the `CollectionView` `children` and in the `el`.\nThis can be useful when sorting is arbitrary or is not performant.\n\n**Errors** If either of the two views aren't part of the `CollectionView` an error will be thrown.\n\nIf one child is in the `el` but the other is not, [filter](#filtering-the-children) will be called.\n\n```javascript\nimport Backbone from 'backbone';\nimport { CollectionView } from 'backbone.marionette';\nimport MyChildView from './my-child-view';\n\nconst collection = new Backbone.Collection([\n  { name: 'first' },\n  { name: 'middle' },\n  { name: 'last' }\n]);\n\nconst myColView = new CollectionView({\n  collection: collection,\n  childView: MyChildView\n});\n\nmyColView.swapChildViews(myColView.children.first(), myColView.children.last());\n\nmyColView.children.first().model.get('name'); // \"last\"\nmyColView.children.last().model.get('name'); // \"first\"\n```\n\n## Sorting the `children`\n\nThe `sort` method will loop through the `CollectionView` `children` prior to filtering\nand sort them with the [`viewComparator`](#defining-the-viewcomparator).\nBy default, if a `viewComparator` is not set, the `CollectionView` will sort\nthe views by the order of the models in the `collection`. If set to `false` view\nsorting will be disabled.\n\nThis method is called internally when rendering and\n[`sort` and `before:sort` events](./events.class.md#sort-and-beforesort-events)\nwill trigger.\n\nBy default the `CollectionView` will maintain a sorted collection's order\nin the DOM. This behavior can be disabled by specifying `{sortWithCollection: false}`\non initialize.\n\n### Defining the `viewComparator`\n\n`CollectionView` allows for a custom `viewComparator` option if you want your\n`CollectionView`'s children to be rendered with a different sort order than the\nunderlying Backbone collection uses.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst myCollectionView = new CollectionView({\n  collection: someCollection,\n  viewComparator: 'otherFieldToSortOn'\n});\n```\n\n```javascript\nimport Backbone from 'backbone';\nimport { CollectionView } from 'backbone.marionette';\n\nconst myCollection = new Backbone.Collection([\n  { id: 1 },\n  { id: 4 },\n  { id: 3 },\n  { id: 2 }\n]);\n\nmyCollection.comparator = 'id';\n\nconst mySortedColView = new CollectionView({\n  //...\n  collection: myCollection\n});\n\nconst myUnsortedColView = new CollectionView({\n  //...\n  collection: myCollection,\n  viewComparator: false\n});\n\nmySortedColView.render(); // 1 4 3 2\nmyUnsortedColView.render(); // 1 4 3 2\n\nmyCollection.sort();\n// mySortedColView auto-renders 1 2 3 4\n// myUnsortedColView has no change\n```\n\nThe `viewComparator` can take any of the acceptable `Backbone.Collection`\n[comparator formats](http://backbonejs.org/#Collection-comparator) -- a sortBy\n(pass a function that takes a single argument), as a sort (pass a comparator\nfunction that expects two arguments), or as a string indicating the attribute to\nsort by.\n\n#### `getComparator`\n\nOverride this method to determine which `viewComparator` to use.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst MyCollectionView = CollectionView.extend({\n  sortAsc(model) {\n    return -model.get('order');\n  },\n  sortDesc(model) {\n    return model.get('order');\n  },\n  getComparator() {\n    // The collectionView's model\n    if (this.model.get('sorted') === 'ASC') {\n      return this.sortAsc;\n    }\n\n    return this.sortDesc;\n  }\n});\n```\n\n#### `setComparator`\n\nThe `setComparator` method modifies the `CollectionView`'s `viewComparator`\nattribute and re-sorts. Passing `{ preventRender: true }` in the options argument\nwill prevent the view being rendered.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst cv = new CollectionView({\n  collection: someCollection\n});\n\ncv.render();\n\n// Note: the setComparator is preventing the automatic re-render\ncv.setComparator('orderBy', { preventRender: true });\n\n// Render the children ordered by the orderBy attribute\ncv.render();\n```\n\n#### `removeComparator`\n\nThis function is actually an alias of `setComparator(null, options)`. It is useful\nfor removing the comparator. `removeComparator` also accepts `preventRender` as a option.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst cv = new CollectionView({\n  collection: someCollection\n});\n\ncv.render();\n\ncv.setComparator('orderBy');\n\n//Remove the current comparator without rendering again.\ncv.removeComparator({ preventRender: true });\n```\n\n### Maintaining the `collection`'s sort\n\nBy default the `CollectionView` will maintain a sorted collection's order\nin the DOM. This behavior can be disabled by specifying `{sortWithCollection: false}`\non initialize or on the view definition.\n\n```javascript\nimport Backbone from 'backbone';\nimport { CollectionView } from 'backbone.marionette';\n\nconst myCollection = new Backbone.Collection([\n  { id: 1 },\n  { id: 4 },\n  { id: 3 },\n  { id: 2 }\n]);\n\nmyCollection.comparator = 'id';\n\nconst mySortedColView = new CollectionView({\n  //...\n  collection: myCollection\n});\n\nconst myUnsortedColView = new CollectionView({\n  //...\n  collection: myCollection,\n  sortWithCollection: false\n});\n\nmySortedColView.render(); // 1 4 3 2\nmyUnsortedColView.render(); // 1 4 3 2\n\nmyCollection.sort();\n// mySortedColView auto-renders 1 2 3 4\n// myUnsortedColView has no change\n```\n\n## Filtering the `children`\n\nThe `filter` method will loop through the `CollectionView`'s sorted `children`\nand test them against the [`viewFilter`](#defining-the-viewfilter).\nThe views that pass the `viewFilter`are rendered if necessary and attached\nto the CollectionView and the views that are filtered out will be detached.\nAfter filtering the `children` will only contain the views to be attached.\n\nIf a `viewFilter` exists the\n[`filter` and `before:filter` events](./events.class.md#filter-and-beforefilter-events)\nwill trigger.\n\nBy default the CollectionView will refilter when views change or when the\nCollectionView is sorted.\n\n**Note** This is a presentation functionality used to easily filter in and out\nconstructed children. All children of a `collection` will be instantiated once\nregardless of their filtered status. If you would prefer to manage child view\ninstantiation, you should filter the `collection` itself.\n\n### Defining the `viewFilter`\n\n`CollectionView` allows for a custom `viewFilter` option if you want to prevent\nsome of the underlying `children` from being attached to the DOM.\nA `viewFilter` can be a function, predicate object. or string.\n\n**Errors** An error will be thrown if the `ViewFilter` is not one of these options.\n\n#### `viewFilter` as a function\n\nThe `viewFilter` function takes a view from the `children` and returns a truthy\nvalue if the child should be attached, and a falsey value if it should not.\n\n```javascript\nimport Backbone from 'backbone';\nimport { CollectionView } from 'backbone.marionette';\n\nconst cv = new CollectionView({\n  childView: SomeChildView,\n  emptyView: SomeEmptyView,\n  collection: new Bb.Collection([\n    { value: 1 },\n    { value: 2 },\n    { value: 3 },\n    { value: 4 }\n  ]),\n\n  // Only show views with even values\n  viewFilter(view, index, children) {\n    return view.model.get('value') % 2 === 0;\n  }\n});\n\n// renders the views with values '2' and '4'\ncv.render();\n```\n\n#### `viewFilter` as a predicate object\n\nThe `viewFilter` predicate object will filter against the view's model attributes.\n\n```javascript\nimport Backbone from 'backbone';\nimport { CollectionView } from 'backbone.marionette';\n\nconst cv = new CollectionView({\n  childView: SomeChildView,\n  emptyView: SomeEmptyView,\n  collection: new Bb.Collection([\n    { value: 1 },\n    { value: 2 },\n    { value: 3 },\n    { value: 4 }\n  ]),\n\n  // Only show views with value 2\n  viewFilter: { value: 2 }\n});\n\n// renders the view with values '2'\ncv.render();\n```\n\n#### `viewFilter` as a string\n\nThe `viewFilter` string represents the view's model attribute and will filter\ntruthy values.\n\n```javascript\nimport Backbone from 'backbone';\nimport { CollectionView } from 'backbone.marionette';\n\nconst cv = new CollectionView({\n  childView: SomeChildView,\n  emptyView: SomeEmptyView,\n  collection: new Bb.Collection([\n    { value: 0 },\n    { value: 1 },\n    { value: 2 },\n    { value: null },\n    { value: 4 }\n  ]),\n\n  // Only show views 1,2, and 4\n  viewFilter: 'value'\n});\n\n// renders the view with values '1', '2', and '4'\ncv.render();\n```\n\n#### `getFilter`\n\nOverride this function to programatically decide which\n`viewFilter` to use when `filter` is called.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst MyCollectionView = CollectionView.extend({\n  summaryFilter(view) {\n    return view.model.get('type') === 'summary';\n  },\n  getFilter() {\n    if (this.collection.length > 100) {\n      return this.summaryFilter;\n    }\n    return this.viewFilter;\n  }\n});\n```\n\n#### `setFilter`\n\nThe `setFilter` method modifies the `CollectionView`'s `viewFilter` attribute and filters.\nPassing `{ preventRender: true }` in the options argument will prevent the view\nbeing rendered.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst cv = new CollectionView({\n  collection: someCollection\n});\n\ncv.render();\n\nconst newFilter = function(view, index, children) {\n  return view.model.get('value') % 2 === 0;\n};\n\n// Note: the setFilter is preventing the automatic re-render\ncv.setFilter(newFilter, { preventRender: true });\n\n// Render the new state of the ChildViews instead of the whole DOM.\ncv.render();\n```\n\n#### `removeFilter`\n\nThis function is actually an alias of `setFilter(null, options)`. It is useful\nfor removing filters. `removeFilter` also accepts `preventRender` as a option.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst cv = new CollectionView({\n  collection: someCollection\n});\n\ncv.render();\n\ncv.setFilter(function(view, index, children) {\n  return view.model.get('value') % 2 === 0;\n});\n\n// Remove the current filter without rendering again.\ncv.removeFilter({ preventRender: true });\n```\n"
  },
  {
    "path": "docs/marionette.mnobject.md",
    "content": "# Marionette.MnObject\n\n`MnObject` incorporates backbone conventions `initialize`, `cid` and `extend`.\n`MnObject` includes:\n- [Common Marionette Functionality](./common.md)\n- [Class Events](./events.class.md#mnobject-events)\n- [Radio API](./backbone.radio.md#marionette-integration)\n\n## Documentation Index\n\n* [Instantiating a MnObject](#instantiating-a-mnobject)\n* [Unique Client ID](#unique-client-id)\n* [Destroying a MnObject](#destroying-a-mnobject)\n* [Basic Use](#basic-use)\n* [Backwards Compatibility](#backwards-compatibility)\n\n## Instantiating a MnObject\n\nWhen instantiating a `MnObject` there are several properties, if passed,\nthat will be attached directly to the instance:\n`channelName`, `radioEvents`, `radioRequests`\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\n\nconst myObject = new MnObject({ ... });\n```\n\n## Unique Client ID\nThe `cid` or client id is a unique identifier automatically assigned to MnObjects\nwhen they're first created and by default is prefixed with `mno`.\nYou can modify the prefix for `MnObject`s you `extend` by setting the `cidPrefix`.\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\n\nconst MyFoo = MnObject.extend({\n  cidPrefix: 'foo'\n});\n\nconst foo = new MyFoo();\n\nconsole.log(foo.cid); // foo1234\n```\n\n## Destroying a MnObject\n\n### `destroy`\nMnObjects have a `destroy` method that unbind the events that are directly attached to the\ninstance. `destroy` returns the MnObject.\n\nInvoking the `destroy` method will trigger `before:destroy` and `destroy` events and their [corresponding methods](./marionette.functions.md#marionettetriggermethod).\n\n**Note** The event handlers will pass the `options` argument `destroy` was invoked with.\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\n\n// define a mnobject with an onBeforeDestroy method\nconst MyObject = MnObject.extend({\n\n  onBeforeDestroy(options){\n    // put other custom clean-up code here\n  }\n});\n\n// create a new mnobject instance\nconst obj = new MyObject();\n\n// add some event handlers\nobj.on('before:destroy', function(options){ ... });\nobj.listenTo(something, 'bar', function(){...});\n\n// destroy the mnobject: unbind all of the\n// event handlers, trigger the \"destroy\" event and\n// call the onBeforeDestroy method\nobj.destroy({ foo: 'bar' });\n```\n\n### `isDestroyed`\n\nThis method will return a boolean indicating if the mnobject has been destroyed.\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\n\nconst obj = new MnObject();\nobj.isDestroyed(); // false\nobj.destroy();\nobj.isDestroyed(); // true\n```\n\n## Basic Use\n\nSelections is a simple MnObject that manages a selection of things.\nBecause Selections extends from MnObject, it gets `initialize` and `Events`\nfor free.\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\n\nconst Selections = MnObject.extend({\n\n  initialize(options){\n    this.selections = {};\n  },\n\n  select(key, item){\n    this.selections[key] = item;\n    this.triggerMethod('select', key, item);\n  },\n\n  deselect(key, item) {\n    delete this.selections[key];\n    this.triggerMethod('deselect', key, item);\n  }\n\n});\n\nconst selections = new Selections({\n  filters: Filters\n});\n\n// use the built in EventBinder\nselections.listenTo(selections, 'select', function(key, item){\n  console.log(item);\n});\n\nselections.select('toy', Truck);\n```\n\n## Backwards Compatibility\n\nIn versions previous to v4, `MnObject` was simply named `Object`. This naming is still supported\nvia the default export of the library, but should be considered **deprecated** and is scheduled for\nremoval in an upcoming version.\n\n\n```javascript\nimport { MnObject } from 'backbone.marionette';\nimport Marionette from 'backbone.marionette';\n\nconsole.log(MnObject === Marionette.Object === Marionette.MnObject); // true\n```\n"
  },
  {
    "path": "docs/marionette.region.md",
    "content": "# Marionette.Region\n\nRegions provide consistent methods to manage, show and destroy\nviews in your applications and views.\n\n`Region` includes:\n- [Common Marionette Functionality](./common.md)\n- [Class Events](./events.class.md#region-events)\n- [The DOM API](./dom.api.md)\n\nSee the documentation for [laying out views](./marionette.view.md#laying-out-views---regions) for an introduction in\nmanaging regions throughout your application.\n\nRegions maintain the [View's lifecycle](./view.lifecycle.md) while showing or emptying a view.\n\n## Documentation Index\n\n* [Instantiating a Region](#instantiating-a-region)\n* [Defining the Application Region](#defining-the-application-region)\n* [Defining Regions](#defining-regions)\n  * [String Selector](#string-selector)\n  * [Additional Options](#additional-options)\n  * [Specifying `regions` as a Function](#specifying-regions-as-a-function)\n  * [Using a RegionClass](#using-a-regionclass)\n  * [Referencing UI in `regions`](#referencing-ui-in-regions)\n* [Adding Regions](#adding-regions)\n* [Removing Regions](#removing-regions)\n* [Using Regions on a view](#using-regions-on-a-view)\n* [Showing a View](#showing-a-view)\n  * [Checking whether a region is showing a view](#checking-whether-a-region-is-showing-a-view)\n  * [Non-Marionette Views](#non-marionette-views)\n    * [Partially-rendered Views](#partially-rendered-views)\n* [Showing a Template](#showing-a-template)\n* [Emptying a Region](#emptying-a-region)\n  * [Preserving Existing Views](#preserving-existing-views)\n  * [Detaching Existing Views](#detaching-existing-views)\n* [`reset` A Region](#reset-a-region)\n* [`destroy` A Region](#destroy-a-region)\n* [Check If View Is Being Swapped By Another](#check-if-view-is-being-swapped-by-another)\n* [Set How View's `el` Is Attached](#set-how-views-el-is-attached)\n* [Configure How To Remove View](#configure-how-to-remove-view)\n\n## Instantiating a Region\n\nWhen instantiating a `Region` there are two properties, if passed,\nthat will be attached directly to the instance:\n`el`, and `replaceElement`.\n\n```javascript\nimport { Region } from 'backbone.marionette';\n\nconst myRegion = new Region({ ... });\n```\n\nWhile regions may be instantiated and useful on their own, their primary use case is through\nthe [`Application`](#defining-the-application-region) and [`View`](#defining-regions) classes.\n\n## Defining the Application Region\n\nThe Application defines a single region `el` using the `region` attribute. This\ncan be accessed through `getRegion()` or have a view displayed directly with\n`showView()`. Below is a short example:\n\n```javascript\nimport { Application } from 'backbone.marionette';\nimport SomeView from './view';\n\nconst MyApp = Application.extend({\n  region: '#main-content',\n\n  onStart() {\n    const mainRegion = this.getRegion();  // Has all the properties of a `Region`\n    mainRegion.show(new SomeView());\n  }\n});\n```\n\n[Live example](http://jsfiddle.net/marionettejs/9fburmb8/)\n\nFor more information, see the\n[Application docs](./marionette.application.md#application-region).\n\n## Defining Regions\n\nIn Marionette you can define a region with a string selector or an object literal\non your `Application` or `View`. This section will document the two types as applied\nto `View`, although they will work for `Application` as well - just replace `regions`\nwith `region` in your definition.\n\n**Errors** An error will be thrown for an incorrect region configuration.\n\n### String Selector\n\nYou can use a jQuery string selector to define regions.\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  regions: {\n    mainRegion: '#main'\n  }\n});\n```\n\n### Additional Options\n\nYou can define regions with an object literal. Object literal definitions expect\nan `el` property - the selector string to hook the region into. With this\nformat is possible to define whether showing the region overwrites the `el` or\njust overwrites the content (the default behavior).\n\nTo overwrite the parent `el` of the region with the rendered contents of the\ninner View, use `replaceElement` as so:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst OverWriteView = View.extend({\n  className: '.new-class'\n});\n\nconst MyView = View.extend({\n  regions: {\n    main: {\n      el: '.overwrite-me',\n      replaceElement: true\n    }\n  }\n});\nconst view = new MyView();\nview.render();\n\nconsole.log(view.$('.overwrite-me').length); // 1\nconsole.log(view.$('.new-class').length); // 0\n\nview.showChildView('main', new OverWriteView());\n\nconsole.log(view.$('.overwrite-me').length); // 0\nconsole.log(view.$('.new-class').length); // 1\n```\n\nWhen the instance of `MyView` is rendered, the `.overwrite-me` element will be\nremoved from the DOM and replaced with an element of `.new-class` - this lets\nus do things like rendering views inside `table` or `select` more easily -\nthese elements are usually very strict on what content they will allow.\n\n\n```js\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  regions: {\n    regionDefinition: {\n      el: '.bar',\n      replaceElement: true\n    }\n  }\n});\n```\n\n**Errors** An error will be thrown in the regions `el` is not specified,\nor if the `el` does not exist in the html.\n\n### Specifying `regions` as a Function\n\nOn a `View` the `regions` attribute can also be a\n[function returning an object](./basics.md#functions-returning-values):\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  regions(){\n    return {\n      firstRegion: '#first-region'\n    };\n  }\n});\n```\n\n### Using a RegionClass\n\nIf you've created a custom region class, you can use it to define your region.\n\n```javascript\nimport { Application, Region, View } from 'backbone.marionette';\n\nconst MyRegion = Region.extend({\n  onShow(){\n    // Scroll to the middle\n    this.$el.scrollTop(this.currentView.$el.height() / 2 - this.$el.height() / 2);\n  }\n});\n\nconst MyApp = Application.extend({\n  regionClass: MyRegion,\n  region: '#first-region'\n})\n\nconst MyView = View.extend({\n  regionClass: MyRegion,\n  regions: {\n    firstRegion: {\n      el: '#first-region',\n      regionClass: Region // Don't scroll this to the top\n    },\n    secondRegion: '#second-region'\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/oLLrzx8g/)\n\n### Referencing UI in `regions`\n\nThe UI attribute can be useful when setting region selectors - simply use\nthe `@ui.` prefix:\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  ui: {\n    region: '#first-region'\n  },\n  regions: {\n    firstRegion: '@ui.region'\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/ey1od1g8/)\n\n## Adding Regions\n\nTo add regions to a view after it has been instantiated, simply use the\n`addRegion` method:\n\n```javascript\nimport MyView from './myview';\n\nconst myView = new MyView();\nmyView.addRegion('thirdRegion', '#third-region');\n```\n\nNow we can access `thirdRegion` as we would the others.\n\nYou can also add multiple regions using `addRegions`.\n\n```javascript\nimport MyView from './myview';\n\nconst myView = new MyView();\nmyView.addRegions({\n  main: {\n    el: '.overwrite-me',\n    replaceElement: true\n  },\n  sidebar: '.sidebar'\n});\n```\n\n[Live example](http://jsfiddle.net/marionettejs/kjvzdyd6/)\n\n## Removing Regions\n\nYou can remove all of the regions from a view by calling `removeRegions` or you can remove a\nregion by name using `removeRegion`. When a region is removed the region will be destroyed.\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  regions: {\n    main: '.main',\n    sidebar: '.sidebar',\n    header: '.header'\n  }\n});\n\nconst myView = new MyView();\n\n// remove only the main region\nconst mainRegion = myView.removeRegion('main');\n\nmainRegion.isDestroyed(); // -> true\n\n// remove all regions\nmyView.removeRegions();\n```\n\n## Using Regions on a view\n\nIn addition to adding and removing regions there are a few\nmethods to help utilize regions. All of these methods will first\nrender an unrendered view so that regions are properly initialized.\n\n- `getRegion(name)` - Request a region from a view by name.\n- `getRegions()` - Returns an object literal of all regions on the view organized by name.\n- `hasRegion(name)` - Check if a view has a region.\n- `emptyRegions()` - Empty all of the regions on a view.\n\n## Showing a View\n\nOnce a region is defined, you can call its `show` method to display the view:\n\n```javascript\nconst myView = new MyView();\nconst childView = new MyChildView();\nconst mainRegion = myView.getRegion('main');\n\n// render and display the view\nmainRegion.show(childView, { fooOption: 'bar' });\n```\n\nThis is equivalent to a view's `showChildView` which can be used as:\n\n```javascript\nconst myView = new MyView();\nconst childView = new MyChildView();\n\n// render and display the view\nmyView.showChildView('main', childView, { fooOption: 'bar' });\n```\n\nBoth forms take an `options` object that will be passed to the\n[events fired during `show`](./events.class.md#show-and-beforeshow-events).\n\nFor more information on `showChildView` and `getChildView`, see the\n[Documentation for Views](./marionette.view.md#managing-children)\n\n**Errors**\n- An error will be thrown if the view is falsy or destroyed.\n- An error will be thrown if the view is already shown in a Region or CollectionView.\n\n### Checking whether a region is showing a view\n\nIf you wish to check whether a region has a view, you can use the `hasView`\nfunction. This will return a boolean value depending whether or not the region\nis showing a view.\n\n```javascript\nconst myView = new MyView();\nconst mainRegion = myView.getRegion('main');\n\nmainRegion.hasView() // false\nmainRegion.show(new OtherView());\nmainRegion.hasView() // true\n```\n\nIf you show a view in a region with an existing view, Marionette will\n[remove the existing View](#emptying-a-region) before showing the new one.\n\n### Non-Marionette Views\n\nMarionette Regions aren't just for showing Marionette Views - they can also\ndisplay instances of a [`Backbone.View`](http://backbonejs.org/#View).\nTo do this, ensure your view defines a `render()` method and just treat it like\na regular Marionette View:\n\n```javascript\nimport _ from 'underscore';\nimport Bb from 'backbone';\nimport { View } from 'backbone.marionette';\n\nconst MyChildView = Bb.View.extend({\n  render() {\n    this.$el.append('<p>Some text</p>');\n  },\n\n  onRender() {\n    console.log('Regions also fire Lifecycle events on Backbone.View!');\n  }\n});\n\nconst MyParentView = View.extend({\n  regions: {\n    child: '.child-view'\n  },\n\n  template: _.template('<div class=\"child-view\"></div>'),\n\n  onRender() {\n    this.showChildView('child', new MyChildView());\n  }\n});\n```\n\nAs you can see above, you can listen to [Lifecycle Events](./view.lifecycle.md)\non `Backbone.View` and Marionette will fire the events for you.\n\n## Showing a Template\n\nYou can show a template or a string directly into a region. Additionally you can pass an object\nliteral containing a template and any other view options. Under the hood a `Marionette.View` is\ninstantiated using the template.\n\n```javascript\nconst myView = new MyView();\n\nmyView.showChildView('main', {\n  template: _.template('This is the <%- section %> page'),\n  templateContext: { section: 'main' }\n});\n\nmyView.showChildView('header', _.template('Welcome to the site'));\n\nmyView.getRegion('other').show('This text is in another region');\n```\n\n## Emptying a Region\n\nYou can remove a view from a region (effectively \"unshowing\" it) with\n`region.empty()` on a region:\n\n```javascript\nconst myView = new MyView();\n\nmyView.showChildView('main', new OtherView());\nconst mainRegion = myView.getRegion('main');\nmainRegion.empty();\n```\n\nThis will destroy the view, clean up any event handlers and remove it from\nthe DOM. When a region is emptied [empty events are triggered](./events.class.md#empty-and-beforeempty-events).\n\n**NOTE** If the region does _not_ currently contain a View it will detach\nany HTML inside the region when emptying. If the region _does_ contain a\nView [any HTML that doesn't belong to the View will remain](./upgrade.md#changes-to-regionshow).\n\n### Preserving Existing Views\n\nIf you replace the current view with a new view by calling `show`, it will\nautomatically destroy the previous view. You can prevent this behavior by\n[detaching the view](#detaching-existing-views) before showing another one.\n\n### Detaching Existing Views\n\nIf you want to detach an existing view from a region, use `detachView`.\n\n```javascript\nconst myView = new MyView();\n\nconst myOtherView = new MyView();\n\nconst childView = new MyChildView();\n\n// render and display the view\nmyView.showChildView('main', childView);\n\n// ... somewhere down the line\nmyOtherView.showChildView('main', myView.getRegion('main').detachView());\n```\n\n**Note** When detaching a view you must pass it to a new region so Marionette\ncan handle its life cycle automatically or `destroy` it manually to prevent memory leaks.\n\n## `reset` A Region\n\nA region can be `reset` at any time. This destroys any existing view\nbeing displayed, and deletes the cached `el`. The next time the\nregion shows a view, the region's `el` is queried from the DOM.\n\n```javascript\nconst myView = new MyView();\nmyView.showChildView('main', new OtherView());\nconst myRegion = myView.getRegion('main');\nmyRegion.reset();\n```\n\nThis can be useful in unit testing your views.\n\n## `destroy` A Region\n\nA region can be destroyed which will `reset` the region, remove it from any parent view,\nand stop any internal region listeners. A destroyed region should not be reused.\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  regions: {\n    mainRegion: '#main'\n  }\n});\n\nconst myView = new MyView();\n\nconst myRegion = myView.getRegion('mainRegion');\n\nmyRegion.show(new ChildView());\n\nmyRegion.destroy();\n\nmyRegion.isDestroyed(); // true\nmyRegion.hasView(); // false\nmyView.hasRegion('mainRegion'); // false\n```\n\n## Check If View Is Being Swapped By Another\n\nThe `isSwappingView` method returns if a view is being swapped by another one. It's useful\ninside region lifecycle events / methods.\n\nThe example will show an message when the region is empty:\n\n```javascript\nimport { Region } from 'backbone.marionette';\n\nconst EmptyMsgRegion = Region.extend({\n  onEmpty() {\n    if (!this.isSwappingView()) {\n      this.$el.append('Empty Region');\n    }\n  }\n});\n```\n[Live example](https://jsfiddle.net/marionettejs/c1nacq0c/)\n\n## Set How View's `el` Is Attached and Detached\n\nOverride the region's `attachHtml` method to change how the view is attached\nto the DOM (when not using `replaceElement: true`. This method receives one\nparameter - the view to show.\n\nThe default implementation of `attachHtml` is essentially:\n\n```javascript\nimport { Region } from 'backbone.marionette';\n\nRegion.prototype.attachHtml = function(view){\n  this.el.appendChild(view.el);\n}\n```\n\nSimilar to `attachHtml`, override `detachHtml` to determine how the region detaches\nthe contents from its `el`. This method receives no parameters.\n\nFor most cases you will want to use the [DOM API](./dom.api.md) to determine how\na region html is attached, but in some cases you may want to override a single Region\nclass for situations like animation where you want to control both attaching and\n[view removal](#configure-how-to-remove-view).\n\nThis example will make a view slide down from the top of the screen instead of just\nappearing in place:\n\n```javascript\nimport { Region, View } from 'backbone.marionette';\n\nconst ModalRegion = Region.extend({\n  attachHtml(view){\n    // Some effect to show the view:\n    this.$el.empty().append(view.el);\n    this.$el.hide().slideDown('fast');\n  }\n});\n\nconst MyView = View.extend({\n  regions: {\n    mainRegion: '#main-region',\n    modalRegion: {\n      regionClass: ModalRegion,\n      el: '#modal-region'\n    }\n  }\n});\n```\n\n## Configure How To Remove View\n\nOverride the region's `removeView` method to change how and when the view is destroyed / removed\nfrom the DOM. This method receives one parameter - the view to remove.\n\nThe default implementation of `removeView` is:\n\n```javascript\nimport { Region } from 'backbone.marionette';\n\nRegion.prototype.removeView = function(view){\n  this.destroyView(view);\n}\n```\n\n> `destroyView` method destroys the view taking into consideration if is\n> a Marionette.View descendant or vanilla Backbone view. It can be replaced\n> by a `view.destroy()` call if is ensured that view descends from Marionette.View\n\nThis example will animate with a fade effect showing and hiding the view:\n\n```javascript\nimport { Region, View } from 'backbone.marionette';\n\nconst AnimatedRegion = Region.extend({\n  attachHtml(view) {\n    view.$el\n      .css({display: 'none'})\n      .appendTo(this.$el);\n    if (!this.isSwappingView()) view.$el.fadeIn('slow');\n  },\n\n  removeView(view) {\n    view.$el.fadeOut('slow', () => {\n      this.destroyView(view);\n      if (this.currentView) this.currentView.$el.fadeIn('slow');\n    });\n  }\n});\n\nconst MyView = View.extend({\n  regions: {\n    animatedRegion: {\n      regionClass: AnimatedRegion,\n      el: '#animated-region'\n    }\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/qtvjLu70/)\n\nUsing a similar approach is possible to create a region animated with CSS:\n\n[Live example](https://jsfiddle.net/marionettejs/8uoabg7c/)\n"
  },
  {
    "path": "docs/marionette.view.md",
    "content": "# Marionette.View\n\nA `View` is used for managing portions of the DOM via a single parent DOM element or `el`.\nIt provides a consistent interface for managing the content of the `el` which is typically\nadministered by serializing a `Backbone.Model` or `Backbone.Collection` and rendering\na template with the serialized data into the `View`s `el`.\n\nThe `View` provides event delegation for capturing and handling DOM interactions as well as\nthe ability to separate concerns into smaller, managed child views.\n\n`View` includes:\n- [The DOM API](./dom.api.md)\n- [Class Events](./events.class.md#view-events)\n- [DOM Interactions](./dom.interactions.md)\n- [Child Event Bubbling](./events.md#event-bubbling)\n- [Entity Events](./events.entity.md)\n- [View Rendering](./view.rendering.md)\n- [Prerendered Content](./dom.prerendered.md)\n- [View Lifecycle](./view.lifecycle.md)\n\nA `View` can have [`Region`s](./marionette.region.md) and [`Behavior`s](./marionette.behavior.md)\n\n## Documentation Index\n\n* [Instantiating a View](#instantiating-a-view)\n* [Rendering a View](#rendering-a-view)\n  * [Using a View Without a Template](#using-a-view-without-a-template)\n* [View Lifecycle and Events](#view-lifecycle-and-events)\n* [Entity Events](#entity-events)\n* [DOM Interactions](#dom-interactions)\n* [Behaviors](#behaviors)\n* [Managing Children](#managing-children)\n  * [Laying Out Views - Regions](#laying-out-views---regions)\n  * [Showing a Child View](#showing-a-child-view)\n  * [Attaching a Child View](#attaching-a-child-view)\n  * [Detaching a Child View](#detaching-a-child-view)\n  * [Destroying a Child View](#destroying-a-child-view)\n  * [Region Availability](#region-availability)\n* [Efficient Nested View Structures](#efficient-nested-view-structures)\n* [Listening to Events on Children](#listening-to-events-on-children)\n\n## Instantiating a View\n\nWhen instantiating a `View` there are several properties, if passed,\nthat will be attached directly to the instance:\n`attributes`, `behaviors`, `childViewEventPrefix`, `childViewEvents`,\n`childViewTriggers`, `className`, `collection`, `collectionEvents`, `el`,\n`events`, `id`, `model`, `modelEvents`, `regionClass`, `regions`,\n`tagName`, `template`, `templateContext`, `triggers`, `ui`\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst myView = new View({ ... });\n```\n\nSome of these properties come from Marionette, but many are inherited from\n[`Backbone.View`](http://backbonejs.org/#View-constructor).\n\n## Rendering a View\n\nThe Marionette View implements a powerful render method which, given a\n[`template`](./view.rendering.md#setting-a-view-template), will build your\nHTML from that template, mixing in `model` or `collection` data and any\nextra [template context](./view.rendering.md#adding-context-data).\n\nUnlike `Backbone.View` Marionette defines `render` and this method should\nnot be overridden. To add functionality to the render use the\n[`render` and `before:render` events](./events.class.md#render-and-beforerender-events).\n\n[Live example](https://jsfiddle.net/marionettejs/dhsjcka4/)\n\nFor more detail on how to render templates, see\n[View Template Rendering](./view.rendering.md).\n\n### Using a View Without a Template\n\nBy setting [`template` to `false`](./view.rendering.md#using-a-view-without-a-template) you can entirely disable\nthe view rendering and events. This may be useful for cases where you only need the `el` or have\n[`prerendered content`](./dom.prerendered.md) that you do not intend to re-render.\n\n## View Lifecycle and Events\n\nAn instantiated `View` is aware of its lifecycle state and will throw events related to when that state changes.\n\nThe view states indicate whether the view is rendered, attached to the DOM, or destroyed.\n\nRead More:\n- [View Lifecycle](./view.lifecycle.md)\n- [View DOM Change Events](./events.class.md#dom-change-events)\n- [View Destroy Events](./events.class.md#destroy-events)\n\n## Entity Events\n\nThe `View` can bind to events that occur on the attached `model` and `collection` - this\nincludes both [standard backbone-events](http://backbonejs.org/#Events-catalog) and custom events.\n\nRead More:\n- [Entity Events](./events.entity.md)\n\n## DOM Interactions\n\nIn addition to what Backbone provides the views, Marionette has additional API\nfor DOM interactions: `events`, `triggers`, and `ui`.\n\nRead More:\n- [DOM Interactions](./dom.interactions.md)\n\n## Behaviors\n\nA `Behavior` provides a clean separation of concerns to your view logic,\nallowing you to share common user-facing operations between your views.\n\nRead More:\n- [Using `Behavior`s](./marionette.behavior.md#using-behaviors)\n\n## Managing Children\n\n`View` provides a simple interface for managing child-views with\n[`showChildView`](#showing-a-child-view), [`getChildView`](#accessing-a-child-view), and\n[`detachChildView`](#detaching-a-child-view).\nThese methods all access `regions` within the view.\nWe will cover this here but for more advanced information, see the\n[documentation for regions](./marionette.region.md).\n\n### Laying Out Views - Regions\n\nThe `Marionette.View` class lets us manage a hierarchy of views using `regions`.\nRegions are a hook point that lets us show views inside views, manage the\nshow/hide lifecycles, and act on events inside the children.\n\n**This Section only covers the basics. For more information on regions, see the\n[Regions Documentation.](./marionette.region.md)**\n\nRegions are ideal for rendering application layouts by isolating concerns inside\nanother view. This is especially useful for independently re-rendering chunks\nof your application without having to completely re-draw the entire screen every\ntime some data is updated.\n\nRegions can be added to a View at class definition, with [`regions`](./marionette.region.md#defining-regions),\nor at runtime using [`addRegion`](./marionette.region.md#adding-regions).\n\nWhen you extend `View`, we use the `regions` attribute to point to the selector\nwhere the new view will be displayed:\n\n```javascript\nimport _ from 'underscore';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  template: _.template(`\n    <div id=\"first-region\"></div>\n    <div id=\"second-region\"></div>\n    <div id=\"third-region\"></div>\n  `),\n  regions: {\n    firstRegion: '#first-region',\n    secondRegion: '#second-region'\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/4e3qdgwr/)\n\nWhen we show views in the region, the contents of `#first-region` and\n`#second-region` will be replaced with the contents of the view we show. The\nvalue in the `regions` hash is just a jQuery selector, and any valid jQuery\nsyntax will suffice.\n\n### Showing a Child View\n\nTo show a view inside a region, simply call `showChildView(regionName, view)`. This\nwill handle rendering the view's HTML and attaching it to the DOM for you:\n\n```javascript\nimport _ from 'underscore';\nimport { View } from 'backbone.marionette';\nimport SubView from './subview';\n\nconst MyView = View.extend({\n  template: _.template('<h1>Title</h1><div id=\"first-region\"></div>'),\n\n  regions: {\n    firstRegion: '#first-region'\n  },\n\n  onRender() {\n    this.showChildView('firstRegion', new SubView());\n  }\n});\n```\n\nNote: If `view.showChildView(region, subView)` is invoked before the `view` has been rendered, it will automatically render the `view` so the region's `el` exists in the DOM.\n\n[Live example](https://jsfiddle.net/marionettejs/98u073m0/)\n\n### Accessing a Child View\n\nTo access the child view of a `View` - use the `getChildView(regionName)` method.\nThis will return the view instance that is currently being displayed at that\nregion, or `null`:\n\n```javascript\nimport _ from 'underscore';\nimport { View } from 'backbone.marionette'\nimport SubView from './subview';\n\nconst MyView = View.extend({\n  template: _.template('<h1>Title</h1><div id=\"first-region\"></div>'),\n\n  regions: {\n    firstRegion: '#first-region'\n  },\n\n  onRender() {\n    this.showChildView('firstRegion', new SubView());\n  },\n\n  onSomeEvent() {\n    const first = this.getChildView('firstRegion');\n    first.doSomething();\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/b12kgq3t/)\n\nIf no view is available, `getChildView` returns `null`.\n\n### Detaching a Child View\n\nYou can detach a child view from a region through `detachChildView(region)`\n\n```javascript\nimport _ from 'underscore';\nimport { View } from 'backbone.marionette'\nimport SubView from './subview';\n\nconst MyView = View.extend({\n  template: _.template(`\n    <h1>Title</h1>\n    <div id=\"first-region\"></div>\n    <div id=\"second-region\"></div>\n  `),\n  regions: {\n    firstRegion: '#first-region',\n    secondRegion: '#second-region'\n  },\n\n  onRender() {\n    this.showChildView('firstRegion', new SubView());\n  },\n\n  onMoveView() {\n    const view = this.detachChildView('firstRegion');\n    this.showChildView('secondRegion', view);\n  }\n});\n```\nThis is a proxy for [region.detachView()](./marionette.region.md#detaching-existing-views)\n\n### Destroying a Child View\n\nThere are two ways to easily destroy a child view.\n\n```javascript\n// Directly\nmyChildView.getChildView('regionName').destroy();\n\n// Indirectly\nmyChildView.getRegion('regionName').empty();\n```\n\n### Region Availability\n\nAny defined regions within a `View` will be available to the `View` or any\ncalling code immediately after rendering the `View`. Using `getRegion` or any\nof the child view methods above will first render the view so that the region is\navailable.\n\n## Efficient Nested View Structures\n\nWhen your views get some more regions, you may want to think of the most\nefficient way to render your views. Since manipulating the DOM is performance\nheavy, it's best practice to render most of your views at once.\n\nMarionette provides a simple mechanism to infinitely nest views in a single\npaint: just render all of the children in the `onRender` callback for the\n[`render` event](./events.class.md#render-and-beforerender-events).\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst ParentView = View.extend({\n  // ...\n  onRender() {\n    this.showChildView('header', new HeaderView());\n    this.showChildView('footer', new FooterView());\n  }\n});\n\nmyRegion.show(new ParentView());\n```\n\nIn this example, the doubly-nested view structure will be rendered in a single paint.\n\nThis system is recursive, so it works for any deeply nested structure. The child\nviews you show can render their own child views within their onRender callbacks!\n\n## Listening to Events on Children\n\nUsing regions lets you listen to the events that fire on child views - views\nattached inside a region. This lets a parent view take action depending on what\nevents are triggered in views it directly owns.\n\nRead More:\n- [Child Event Bubbling](./events.md#event-bubbling)\n"
  },
  {
    "path": "docs/readme.md",
    "content": "## Documentation\n\nAll of the documentation for Marionette can be found on the website at\n##### [marionettejs.com/docs/current](http://marionettejs.com/docs/current)\n"
  },
  {
    "path": "docs/routing.md",
    "content": "# Routing in Marionette\n\nUsers of versions of Marionette prior to v4 will notice that a router is no longer a [bundled class](./classes.md).\nThe [Marionette.AppRouter](https://github.com/marionettejs/marionette.approuter) was extracted\nand the core library will no longer hold an opinion on routing.\n\n## Some Routing Solutions\n\nBesides the router [bundled with Backbone](http://backbonejs.org/#Router) there are many viable\nrouting solutions available.  Some specifically designed for Backbone or Marionette and some\nthat are generic solutions for any framework.  Here are a few of those options.\n\n## Marionette Community Routers\n\n### [Marionette.AppRouter](https://github.com/marionettejs/marionette.approuter)\n\nPreviously bundled router. Extends [backbone.router](http://backbonejs.org/#Router) and is helpful\nfor breaking a large amount of routes on a single backbone.router instance into smaller more managable\napprouters.\n\n### [Marionette.Routing](https://github.com/blikblum/marionette.routing)\n\nAn advanced router for MarionetteJS applications. Includes nested routes, states, rendering,\nasync operations, lazy loading routes, Radio channel eventing, and inherits most of CherryTree\nfeatures while maintaining a similar to Marionette API.\n\n### [Backbone.Eventrouter](https://github.com/RoundingWellOS/backbone.eventrouter)\n\nA highly opinionated, simplistic Backbone.Router coupled with a Backbone.Radio.Channel.\nWhen an event is triggered on the channel, it will set the route URL, or when a URL matches\na route it will throw an event on the channel.\n\n## Generic Routers\n\n[Stateman](https://github.com/leeluolee/stateman)\nAngular-UI style routing, without the Angular\n\n[Cherrytree](https://github.com/QubitProducts/cherrytree)\nNested routes, like Ember, but without the transition lifecycle.\n\n[router.js](https://github.com/tildeio/router.js)\nThis is what Ember's router is built on top of. It has all of the features needed for good routing\n\n## Know of other routers that should be listed here?\n[Add them!](https://github.com/marionettejs/backbone.marionette/edit/next/docs/routing.md)\n"
  },
  {
    "path": "docs/upgrade-v2-v3.md",
    "content": "# Upgrade Guide from v2 to v3\n\nMarionette 3 introduces a number of breaking changes. This upgrade guide will go\nthrough the major changes and describe how to change your application to\naccommodate them.\n\nAn [upgrade tool](https://github.com/marionettejs/marionette-v3-compat) is available\nand covers the breaking changes in detail.\n\nWhere possible, we will document how to make the changes in Marionette 2.x so\nthat your applications can continue to work and to ease the burden of upgrading\nto Marionette 3.\n\nYou can run Marionette 3 alongside Marionette 2 with the Marionette.noConflict() function.\n\n## Views\n\nThe most noticeable change to Marionette 3 is the consolidation of `ItemView`\nand `LayoutView` into `View`. In addition, `CompositeView` has been removed and\nits functionality merged into `CollectionView` and `View`.\n\n### Removing `LayoutView` and `ItemView`\n\nUsing separate `View` `LayoutView` and `ItemView` was complicating the API for\nMarionette needlessly. The new `View` replaces all of this and sets a clear\nrecommendation for building layout trees.\n\n#### Upgrading for Marionette 2.x\n\nFor updating in Marionette 2.x, it is recommended you change all instances of\n`ItemView` to `LayoutView`.\n\n#### Upgrading to Marionette 3\n\nChange all instances of `LayoutView` and `ItemView` to `View`. Any views that\npreviously extended `View` with a custom `render` should work relatively\nunchanged.\n\n### Removing `CompositeView`\n\nThe `CompositeView` was deprecated in favor of using `View` and\n`CollectionView`. The `CompositeView` will be completely removed in Marionette\n4.\n\nSee [`CollectionView`](./marionette.collectionview.md#rendering-collectionviews)\nfor detail on upgrading to Marionette 3. This technique works in both Marionette\n2.x and Marionette 3.\n\n### Removing `CollectionView.getChildView()`\n\nThe `getChildView` method has been removed in favor of the `childView` property,\n[which now accepts a function](basics.md#functions-returning-values).\n\n#### Upgrading to Marionette 3\n\nSimply replace all instances of `getChildView` with `childView`.\n\n### Removing `CollectionView.getEmptyView()`\n\nThe `getEmptyView` method has been removed in favor of the `emptyView` property,\n[which now accepts a function](basics.md#functions-returning-values).\n\n#### Upgrading to Marionette 3\n\nSimply replace all instances of `getEmptyView` with `emptyView`.\n\n### Child event handlers\n\nThe `childEvents` attribute was renamed to `childViewEvents`.\n\nChild event bubbling above one level is now removed in most instances and\ndeprecated pending removal everywhere else. This can no longer be relied upon.\nTo pass events further up the chain, you must explicitly using\n`childViewTriggers` to convert the event from the child into an event on the\nparent. These can be chained all the way up to the level you require them to be.\n\nBubbled child events no longer pass the `childView` implicitly and only pass the\narguments passed as part of `triggerMethod`. This means that the arguments\npassed to `onEvent` and `onChildviewEvent` are now identical. See the\n[documentation on event lifecycles](./view.lifecycle.md) for more information.\n\nIn Marionette 2, `childEvents` were bound on every event. In Marionette 3,\n`childViewEvents` are bound once and cached. This means that you cannot add new\nevents after the view has been created.\n\n### View `triggers`\n\nThe view `triggers` attribute no longer passes an `options` attribute to event\nhandlers, instead passing the view instance that triggered the event.\n\n### View `isRendered`\n\nThe view `isRendered` attribute is no longer a boolean, but a function that\nreturns a boolean.\n\n### View `isDestroyed`\n\nThe view `isDestroyed` attribute is no longer a boolean, but a function that\nreturns a boolean.\n\n## Events\n\nA number of lifecycle events were changed or removed from Marionette 3.\nInformation on which ones were removed, changed, or added will be found here\nwith recommendations on how to update your code.\n\n### `show` and `before:show`\n\nThe `show` events were removed completely as they were redundant and were being\nused incorrectly to show child regions. The `show` event was fired after the\nview had been attached, meaning the DOM was being constantly updated, leading to\ndeteriorated performance.\n\n#### Upgrading for Marionette 2.x\n\nReplace all instances of `onShow`, `on('show')`, `onBeforeShow` and\n`on('before:show')` to use the `render` and `before:render` events. This is the\nrecommendation for Marionette 3 and ensures the DOM tree is built in-memory\nbefore modifying the DOM.\n\n#### Upgrading to Marionette 3\n\nReplace all instances of `show` and `before:show` with `render` and\n`before:render`. If you want the view to be visible in the DOM, then listen to\nthe `dom:refresh` event.\n\n### Changes to `region.show()`\n\nThe `region.show()` method (that also backs `showChildView()`) was changed to\nnot remove HTML outside the `$el` of the displayed view. In Marionette 2,\nthe `region.show()` method would call `region.$el.empty()` before showing the\nnew HTML.\n\nIn Marionette 3, this was changed to unhook `region.currentView` from the DOM,\nremove all event handlers, then delete it. Any HTML added to the region that\nisn't contained in the DOM of the View won't be removed.\n\nFor example:\n\n```javascript\nvar _ = require('underscore');\nvar Mn = require('backbone.marionette');\n\nvar app = require('./app');\n\nvar MyView = Mn.View.extend({\n  template: _.template('View contents')\n});\n\nvar ParentView = Mn.View.extend({\n  template: _.template('<div class=\"view-hook\"></div>'),\n  regions: {\n    child: '.view-hook'\n  }\n});\n\nvar parent = new ParentView();\napp.showView(parent);\n\nvar child = new MyView();\n\nparent.showChildView('child', child);\nparent.getRegion('child').$el.append('<p>Not removed</p>');\nparent.showChildView('child', new MyView());\n```\n\nIn Marionette 2, the HTML output will be:\n\n```html\n<div class=\"view-hook\">\n  <div>View contents</div>\n</div>\n```\n\nIn Marionette 3, the HTML will be:\n\n```html\n<div class=\"view-hook\">\n  <p>Not Removed</p>\n  <div>View contents</div>\n</div>\n```\n\n### Arguments for Lifecycle Events\n\nThe arguments for a number of lifecycle events were changed. For consistency,\nall events will now receive the view that is emitting the event as the first\nargument. See the [documentation for view lifecycles](./view.lifecycle.md) for\nmore complete information.\n\n#### Upgrading to Marionette 3\n\nThe following events, with their accompanying `before:` event were changed and\nmay need to be updated:\n\n|      Class       |              Event               |\n|------------------|----------------------------------|\n|     `Object`     |           `destroy`              |\n|     `Region`     |            `show`                |\n|      `View`      | `add:region` and `remove:region` |\n| `CollectionView` |  `add:child` and `remove:child`  |\n|   `Application`  |            `start`               |\n\n## Templates\n\nThe biggest change to templates is renaming `templateHelpers` to\n`templateContext` - the aim is to be more in-line with terminology from other\nframeworks.\n\n### Upgrading to Marionette 3\n\nSimply replace all instances of `templateHelpers` with `templateContext`\n\n## Regions\n\nThere are a number of changes to how regions behave - the biggest change being\nthe removal of the ability to access regions as attributes\n\n### Removing `view.region`\n\nThe `view.<region_name>` syntax has been removed in favor of `view.getRegion()`,\n`view.getChildView()` and `view.showChildView()`.\n\n#### Upgrading for Marionette 2.x\n\nChange all references to `view.region` to `view.getRegion('region')`. For\nexample, in Mn 2.x and below:\n\n```javascript\nvar AnotherView = require('./anotherview');\n\nvar MyView = Mn.LayoutView.extend({\n  regions: {\n    myregion: '.regionname'\n  },\n\n  onRender: function() {\n    this.myregion.show(new AnotherView());\n  }\n});\n```\n\nThis does not work in Mn 3 - instead do:\n\n```javascript\nvar AnotherView = require('./anotherview');\n\n/* In Mn 2.x we can just use LayoutView */\nvar MyView = Mn.View.extend({\n  regions: {\n    myregion: '.regionname'\n  },\n\n  onRender: function() {\n    this.showChildView('myregion', new AnotherView());\n  }\n});\n```\n\nSee the documentation for [views](marionette.view.md#laying-out-views---regions)\nto learn more about how to manage regions in Marionette 3.\n\n## Modules\n\nMarionette Modules have been completely removed in favor of using the more\nstandard JavaScript module loaders e.g.\n[Webpack](./installation.md#quick-start-using-npm-and-webpack) or\n[Browserify](./installation.md#quick-start-using-npm-and-browserify). See the\n[installation](./installation.md) documentation for a list of potential options.\n\n## Backbone.Babysitter\n\nThe dependency on `Backbone.Babysitter` has been removed in favour of an\nin-built implementation that is maintained within the main Marionette codebase.\n\nBabySitter provides a simple way to manage child views in Backbone/Marionette or\nany object that manages lists of views. The external Babysitter library was used\nin Marionette to manage the `CollectionView` children.\n\n### Main Differences\n\nThe main difference between Babysitter and the Marionette implementation is the\nremoval of `.call` and `.apply` on `CollectionView.children`. Instead you should\nuse `.invoke` or\n[any of the methods provided](./marionette.collectionview.md#collectionview-childview-iterators-and-collection-functions).\n\nFor example:\n\n```javascript\nvar MyCollectionView = require('./views');\nvar MyCollection = require('./collections');\n\nvar collection = new MyCollection();\ncollection.fetch();\n\nvar myView = new MyCollectionView({collection: collection});\nmyView.children.invoke('render');\nmyView.children.map(function(view) {\n  view.doMethod();\n});\n```\n"
  },
  {
    "path": "docs/upgrade-v3-v4.md",
    "content": "# Upgrade Guide from v3 to v4\n\nMarionette 4 introduces a number of breaking changes. This upgrade guide will go\nthrough the major changes and describe how to change your application to\naccommodate them.\n\n## Required changes\nThese are breaking changes that need to be handled when migrating from Marionette v3 to v4\n\n#### CompositeView was removed\n * **Old behavior:** `CompositeView` class was provided\n * **New behavior:** `CompositeView` does not exists\n * **Reason:** API simplification\n * **Remedy:** Use `CollectionView` instead. Most features of `CompositeView` were added to `CollectionView`\n   and in common cases a class rename is enough. The old `CompositeView` was abstracted to a\n   [separate library](https://github.com/marionettejs/marionette.oldcollectionview).\n\nOne of the required changes is to explicitly define the `childView` when implementing a recursive (tree) view\n\n   ```javascript\n   // with compositeview\n   const TreeView = CompositeView.extend({\n     template: 'node-template'\n   })\n\n   // with collectionview\n   const TreeView = CollectionView.extend({\n     template: 'node-template',\n     childView () {\n       return TreeView\n     }\n   })\n   ```\n\n#### NextCollectionView was renamed to CollectionView\n * **Old behavior:** Both `NextCollectionView` and `CollectionView` were provided\n * **New behavior:** Only `CollectionView`, based on `NextCollectionView` is provided. The old `CollectionView` implementation was removed\n * **Reason:** API simplification\n * **Remedy:** Use `CollectionView` instead. The old `CollectionView` was abstracted to a\n   [separate library](https://github.com/marionettejs/marionette.oldcollectionview).\n\n#### `childViewEventPrefix` flag is set to false by default\n * **Old behavior:** `childViewEventPrefix` flag was set to true\n * **New behavior:** `childViewEventPrefix` flag was set to false\n * **Reason:** Performance Improvement\n * **Remedy:** It is recommended that child view events are proxied only when necessary.\n   Rather than turning it on globally, set the `childViewEventPrefix` per view that needs it.\n   Even better explictly define the proxies via `childViewEvents` and `childViewTriggers`.\n\n#### Marionette global instance is not attached to Backbone global instance\n * **Old behavior:** Marionette could be accessed using `Backbone.Marionette`\n * **New behavior:** Marionette is not attached to `Backbone` global instance\n * **Reason:** Support named exports\n * **Remedy:** Import Marionette classes directly or use global Marionette instance (when using as a standalone script)\n\n#### `noConflict` was removed\n * **Old behavior:** `noConflict` allowed for multiple installs of Marionette to be installed\n * **New behavior:** Marionette no longer handles conflicts internally.\n * **Reason:** Isn't useful with ES6\n * **Remedy:** Use package managers if multiple versions are needed.\n\n#### AppRouter was removed\n * **Old behavior:** Marionette included a router\n * **New behavior:** Marionette no longer includes a router\n * **Reason:** AppRouter was used by a minority of cases\n * **Remedy:** Use any router including the extract AppRouter https://github.com/marionettejs/marionette.approuter\n\n#### Renderer class was removed\n * **Old behavior:** The default renderer could be changed by setting `Renderer.render`\n * **New behavior:** `Renderer` does not exists\n * **Reason:** API simplification\n * **Remedy:** Use `Marionette.setRenderer` which accepts a function with same signature as expected by `Renderer.render`\n\n#### `TemplateCache` render removed\n * **Old behavior:** Rendered templates using the `TemplateCache`\n * **New behavior:** Renders templates directly `template(data);`\n * **Reason:** TemplateCache is only used by a minority of users.\n * **Remedy:** If needed use https://github.com/marionettejs/marionette.templatecache\n\n#### Behavior Lookup was removed\n * **Old behavior:** View behaviors could optionally be looked up via the global lookup naming scheme.\n * **New behavior:** Behavior definitions must be defined on the view.\n * **Reason:** Simplify API and no global Marionette instance\n * **Remedy:** Attach behaviors to view definitions.\n   In v3\n   ```javascript\n   const MyBehavior = Marionette.Behavior.extend({...});\n\n   Marionette.Behaviors.behaviorsLookup = function() {\n     return {\n       FooBehavior: MyBehavior\n     };\n   };\n\n   const V3View = Marionette.View.extend({\n     behaviors: {\n       FooBehavior: {}\n     }\n   });\n   ```\n\n   In v4\n   ```javascript\n   const MyBehavior = Behavior.extend({...});\n\n   const V3View = View.extend({\n     behaviors: {\n       FooBehavior: MyBehavior\n     }\n   });\n   ```\n\n#### `attachElContent` not called unless the View renderer returns a value\n * **Old behavior:** `attachElContent` was always called\n * **New behavior:** `attachElContent` not called if the render doesn't return a value.\n * **Reason:** Useful for renderers that modify the content directly.\n * **Remedy:** Return at least an empty string if you need to have `attachElContent` called\n\n#### Support for vanilla Backbone.View has changed\n * **Old behavior:** `Backbone.View` instances were supported as is\n * **New behavior:** To support `Backbone.View` is necessary to apply `Marionette.Events` mixin\n * **Reason:** Improve performance\n * **Remedy:** If vanilla `Backbone.View` is not used there's no required change, otherwise, apply the `Marionette.Events` mixin to the\n   prototype of the view class intended to be used with `Marionette`. Example:\n   ```javascript\n   // once, in the application start\n   import _ from 'underscore';\n   import {Events} from 'backbone.marionette';\n   _.extend(Backbone.View.prototype, Events);\n   ```\n\n#### `triggerMethodOn` was removed\n * **Old behavior:** This method was use to `triggerMethod` on an object that did not have the method\n * **New behavior:** Objects that need this functionality should mixin `Marionette.Events`\n * **Reason:** Improve performance\n * **Remedy:** Same as supporting a vanilla Backbone.View mentioned above\n\n#### Function isNodeAttached was removed\n * **Old behavior:** Utility function `isNodeAttached` was provided\n * **New behavior:** `isNodeAttached` does not exists\n * **Reason:** API simplification\n * **Remedy:** Use native code: `document.documentElement.contains(el)`\n\n#### View's `template: false` now no-ops the render\n * **Old behavior:** Template was not rendered, but render events were triggered\n * **New behavior:** No render events will occur\n * **Reason:** Prevents incorrect usage of `render`\n * **Remedy:** `template: false` was often used to generate render events when no render was performed.\n   Use other hooks or methods when no template will be rendered.\n\n#### View.showChildView and Application.showView now return the shown view\n * **Old behavior:** These methods returned the region\n * **New behavior:** These methods now return the shown view\n * **Reason:** More useful return\n * **Remedy:** Use `getRegion` if the region is needed after this method\n\n#### View data serialization no longer clones the data\n * **Old behavior:** model attributes were always cloned prior to template rendering\n * **New behavior:** model attributes are no longer cloned\n * **Reason:** Improve performance\n * **Remedy:** Unlikely to be an issue but if no `templateContext` is defined templates can modify the actual model data if not careful. Clone if necessary.\n\n#### View `render` is no longer bound to the view\n * **Old behavior:** view.render was bound to the view\n * **New behavior:** view.render is no longer bound to the view\n * **Reason:** Improve performance\n * **Remedy:** In most all cases this won't matter but if you need to call the render function out of the context, use `call` or `apply`.\n\n#### Region no longer supports the `selector` property\n * **Old behavior:** The `selector` or `el` property could be used to set the region `el`.\n * **New behavior:** The `el` property can be used to set the `el`.\n * **Reason:** Simplify API\n * **Remedy:** Rename any `selector` used with Region to `el`.\n\n#### Region `preventDestroy` option was removed from `show` and `empty`\n * **Old behavior:** Option could be used to prevent destroying a leaving view\n * **New behavior:** Option is no longer available\n * **Reason:** Simplify API\n * **Remedy:** Use `detachView` first if you need to remove a shown view without destroying.\n\n#### Internally `_.bind` was replaced with `Function.prototype.bind`\n * **Old behavior:** `_.bind` was used\n * **New behavior:** `Function.prototype.bind` is used\n * **Reason:** Preparing for lodash 5\n * **Remedy:** This may affect anyone hoping to squeeze < IE9 support out of Marionette.\n\n#### `Application`, `Behavior`, and `Region` no longer extend `MnObject`\n * **Old behavior:** These classes extended `Mn.Object`.\n * **New behavior:** These classes no longer extend anything.\n * **Reason:** Shallow inheritance\n * **Remedy:** If modifying the `Object` prototype you may need to modify the others too.\n\n#### `destroy` functions only proxy a single argument\n * **Old behavior:** Any number of arguments passed to a `destroy` functions were passed along to events.\n * **New behavior:** Only one argument is passed\n * **Reason:** Performance Improvement\n * **Remedy:** If you need to pass multiple pieces of data through `destroy` use an object.\n\n#### `defaults` was removed from Behavior\n * **Old behavior:** Both `options` and `defaults` defined on Behavior are default options.\n * **New behavior:** Only `options` define the Behavior's default options\n * **Reason:** Simplify API\n * **Remedy:** Rename any use of `defaults` to `options`.\n\n#### View definition options will not be passed to the view `initialize`.\n * **Old behavior:** `options` defined on the view definition were merged into `options` and passed to the Backbone.View constructor\n * **New behavior:** Only `options` passed in at construction will be passed to the Backbone.View constructor.\n * **Reason:** Performance Improvement\n * **Remedy:** Define any default Backbone.View options on the view instance directly instead of in a nested `options` on the definition.\n\n#### `Error` utility was made private\n * **Old behavior:** The Marionette.Error class was publicly available.\n * **New behavior:** There is no accessible Error class.\n * **Reason:** Simplify API and maintenance\n\n#### `DEV_MODE` which shows deprecation warnings was made a feature flag.\n * **Old behavior:** `DEV_MODE` was set on the global `Marionette` object.\n * **New behavior:** Use `setEnabled` to set the `DEV_MODE` feature flag.\n * **Reason:** There is no longer a global `Marionette` object.\n\n## Recommended changes (deprecations)\nThese changes are optional, although recommended to make future upgrades easy\n\n#### The default export has been deprecated\n * **Old behavior:** The package was exported as an UMD module with all classes / functions as a property of the default export\n * **New behavior:** Package is exported as a ECMAScript module using named exports. The default export with all classes still\n * **Reason:** Align with current JS standard practice, allow tree shaking\n * **Remedy:** Import each Marionette classses / functions separatedly or with `*` keyword\n   Examples:\n   ```javascript\n   // using ES module syntax\n   // old behavior\n   import Mn from 'backbone.marionette';\n   const MyView = Mn.View.extend({});\n\n   // new behaviors\n   // import only needed class/function\n   import {View} from 'backbone.marionette';\n   const MyView = View.extend({});\n\n   // or import all (kills any chance of tree shaking)\n   import * as Mn from 'backbone.marionette';\n   const MyView = Mn.View.extend({});\n\n   // or create a module that default exports all functions/classes\n   // mymarionette.js -> can be configured as an alias for marionette or any other module name with webpack\n   import * as Mn from 'backbone.marionette';\n   export default Mn;\n\n   // myview.js\n   import Mn from './mymarionette';\n   const MyView = Mn.View.extend({});\n\n\n   // using CommonJS syntax\n\n   // old behavior\n   const Mn = require('backbone.marionette');\n   const MyView = Mn.View.extend({});\n\n   // new behavior\n   const {View} = require('backbone.marionette');\n   const MyView = View.extend({});\n   ```\n\n#### `Marionette.Object` was renamed to `Marionette.MnObject`\n\n * **Old behavior:** The Marionette Object class was exported as `Marionette.Object`\n * **New behavior:** The Marionette Object class is exported as `MnObject`\n * **Reason:** Avoid collision with native `Object` class when using with ES imports\n * **Remedy:** Rename `Marionette.Object` to `MnObject`. To easy transition the Object will still be available on default Marionette export\n\n```javascript\n   // using ES module syntax\n   // old behavior\n   import Mn from 'backbone.marionette';\n   const MyObj = Mn.Object.extend({});\n\n   // new behaviors\n   // import only needed class/function\n   import {MnObject} from 'backbone.marionette';\n   const MyView = MnObject.extend({});\n   ```\n"
  },
  {
    "path": "docs/utils.md",
    "content": "# Marionette Utility Functions\n\nMarionette provides a set of utility / helper functions that are used to\nfacilitate common behaviors throughout the framework. These functions may\nbe useful to those that are building on top of Marionette, as they provide\na way to get the same behaviors and conventions from your own code.\n\n## Documentation Index\n\n* [extend](#extend)\n* [Common Method Utilities](#common-method-utilities)\n* [VERSION](#version)\n\n## extend\n\nBackbone's `extend` function is a useful utility to have, and is used in\nvarious places in Marionette. To make the use of this method more consistent,\nBackbone's `extend` has been exported `extend`. This allows you to get the\nextend functionality for your object without having to decide if you want to\nuse Backbone.View or Backbone.Model or another Backbone object to grab the\nmethod from.\n\n```javascript\nimport { extend } from 'backbone.marionette';\n\nconst Foo = function(){};\n\n// use Marionette.extend to make Foo extendable, just like other\n// Backbone and Marionette objects\nFoo.extend = extend;\n\n// Now Foo can be extended to create a new class, with methods\nconst Bar = Foo.extend({\n\n  someMethod(){ ... }\n\n  // ...\n});\n\n// Create an instance of Bar\nconst b = new Bar();\n```\n\n[Live example](https://jsfiddle.net/marionettejs/w5avq89r/)\n\n## Common Method Utilities\n\nThese [common utilities](./common.md) are available to all Marionette classes and exported\nso that the functionality can be used elsewhere. Each method has the same arguments as documented\nin [common utilities](./common.md) except that the target of the method is added as the first argument.\n\nFor instance:\n```javascript\nimport { View, triggerMethod, getOption } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  initialize() {\n    this.triggerMethod('foo', this.getOption('foo'));\n  },\n  onFoo() {\n    console.log('bar');\n  }\n});\n\n// logs \"bar\"\nconst myView = new MyView({ foo: 'bar' });\n\n// Same as initialize, logs \"bar\"\ntriggerMethod(myView, 'foo', getOption(myView, 'foo'));\n```\n\n* [triggerMethod](./common.md#triggermethod)\n  - Trigger an event and a corresponding method on the target object.\n* [bindEvents](./common.md#bindevents)\n  - This method is used to bind a backbone \"entity\" to methods on a target object.\n* [unbindEvents](./common.md#unbindevents)\n  - This method can be used to unbind callbacks from entities' events.\n* [bindRequests](./common.md#bindrequests)\n  - This method is used to bind backbone radio replies to methods on a target object.\n* [unbindRequests](./common.md#unbindrequests)\n  - This method can be used to unbind radio reply handler from entities' events.\n* [normalizeMethods](./common.md#normalizemethods)\n  - Receives a hash of event names and functions and/or function names,\n    and returns the same hash with the function names replaced with the function references themselves.\n* [getOption](./common.md#getoption)\n  - Retrieve an object's attribute either directly from the object, or from the object's `this.options`.\n* [mergeOptions](./common.md#mergeoptions)\n  - A handy function to pluck certain `options` and attach them directly to an instance.\n\n## VERSION\n\nMaintains a reference to the version of a Marionette instance.\n`VERSION` is used to direct users to the correctly versioned documentation when errors are thrown.\n"
  },
  {
    "path": "docs/view.lifecycle.md",
    "content": "# View Lifecycle\n\nBoth [`View` and `CollectionView`](./classes.md) are aware of their lifecycle state\nwhich indicates if the view is rendered, attached to the DOM or destroyed.\n\n## Documentation Index\n\n* [View Lifecycle](#view-lifecycle)\n* [Lifecycle State Methods](#lifecycle-state-methods)\n  * [`isRendered()`](#isrendered)\n  * [`isAttached()`](#isattached)\n  * [`isDestroyed()`](#isdestroyed)\n* [Instantiating a View](#instantiating-a-view)\n  * [Using `setElement`](#using-setelement)\n* [Rendering a View](#rendering-a-view)\n  * [`View` Rendering](#view-rendering)\n  * [`CollectionView` Rendering](#collectionview-rendering)\n* [Rendering Children](#rendering-children)\n* [Attaching a View](#attaching-a-view)\n* [Detaching a View](#detaching-a-view)\n* [Destroying a View](#destroying-a-view)\n* [Destroying Children](#rendering-children)\n\n## Lifecycle State Methods\n\nBoth `View` and `CollectionView` share methods for checking lifecycle state.\n\n### `isRendered()`\n\nReturns a boolean value reflecting if the view is considered rendered.\n\n### `isAttached()`\n\nReturns a boolean value reflecting if the view is considered attached to the DOM.\n\n### `isDestroyed()`\n\nReturns a boolean value reflecting if the view has been destroyed.\n\n## Instantiating a View\n\nMarionette Views are Backbone Views and so when they are instantiated the view\nhas an `el`. That `el` will be the root node for the view and other than its contents it\nwill not change for the life of the view unless directly manipulated (ie: `view.$el.addClass`)\n\nThe view can be passed an existing `el` either in the DOM (ie: `el: $('.foo-selector')`)\nor in memory (ie: `el: $('<div></div>')`) or most commonly, the view constructs\nits own `el` at instantiation as [documented on backbonejs.org](http://backbonejs.org/#View-el).\n\nMarionette will determine the initial state of the view as to whether the view is considered\nalready [rendered](#rendering-a-view) or [attached](#attaching-a-view). If a view is already\nrendered or attached its [state](#lifecycle-state-methods) will reflect that status, but the\n[related events](./events.class.md#dom-change-events) will not have fired.\n\nFor more information on instanting a view with pre-rendered DOM see: [Prerendered Content](./dom.prerendered.md).\n\n### Using `setElement`\n\n`Backbone.View` allows the user to change the view's `el` after instantiation using\n[`setElement`](http://backbonejs.org/#View-setElement). This method can be used in Marionette\nas well, but should be done with caution. `setElement` will redelegate view events, but it will\nessentially ignore children of the view, whether through `regions` or through `children` and the\nview's `behaviors` will also be unaware of the change. It is likely better to reconstuct a new\nview with the new `el` than to try to change the `el` of an existing view.\n\n## Rendering a View\n\nIn Marionette [rendering a view](./view.rendering.md) is changing a view's `el`'s contents.\n\nWhat rendering indicates varies slightly between the two Marionette views.\n\n**Note** Once a view is considered \"rendered\" it cannot be unrendered until it is [destroyed](#destroying-a-view).\n\n### `View` Rendering\n\nFor [`View`](./marionette.view.md), rendering entails serializing the view's data, passing it to a template,\nand taking the results of that template and replacing the contents of the view's `el`. So when a `View` is\ninstantiated it is considered rendered if the `el` node contains any content. However after instantiation\na template may render empty in which case the `View` will still be considered \"rendered\" even though it\ncontains no content.\n\n### `CollectionView` Rendering\n\nFor [`CollectionView`](./marionette.collectionview.md), rendering signifies that the view's\n[`children`](./marionette.collectionview.md#collectionviews-children) were created and attached to the\nview's `el`. So unlike `View` a `CollectionView` can be instantiated with content in its `el`, but until\nthe `children` are \"rendered\" the entire view is not considered rendered.\n\nNotably if there are no `children` when rendering, the view will still be considered rendered. This is\ntrue whether or not an [`emptyView`](./marionette.collectionview.md#collectionviews-emptyview) is rendered.\nSo it is possible for a `CollectionView` to be \"rendered\" but the `el` to only be an empty tag.\nAlso note that just like `View` a `CollectionView` may have a `template` which is rendered and attached to\nthe `el` during the `render`, but the template rendering itself has no bearing on the status of the `CollectionView`.\n\n## Rendering Children\n\nRendering child views is often best accomplish after the view render as typically the first render happens prior to\nthe view entering the DOM. This helps to prevent unnecessary repaints and reflows by making the DOM insert at the\nhighest possible view in the view tree.\n\nThe exception is views with [prerendered content](./dom.prerendered.md). In the case that the view is instantiated\nrendered, child views are best managed in the view's [`initialize`](./common.md#initialize).\n\n### `View` Children\n\nIn general the best method for adding a child view to a `View` is to use [`showChildView`](./marionette.view.md#showing-a-view)\nin the [`render` event](./events.class.md#render-and-beforerender-events).\n\nView regions will be emptied on each render so views shown outside of the `render` event will still need be reshown\non subsequent renders.\n\n### `CollectionView` Children\n\nThe primary use case for a `CollectionView` is maintaining child views to match the state of a Backbone Collection.\nBy default children will be added or removed to match the models within the collection.\nHowever a `CollectionView` can have children in addition to, or instead of, views matching the `collection`.\n\n#### Adding managed children\n\nIf you add a view to a `CollectionView`s children by default it will treat it as any other view added from the `collection`.\nThis means it is subject to the [`viewComparator`](./marionette.collectionview.md#defining-the-viewcomparator) and\n[`viewFilter`](./marionette.collectionview.md#defining-the-viewfilter).\n\nSo if you are accounting for added views in your `viewFilter` and `viewComparator` the best place to add these children is\nlikely in the [`render` event](./events.class.md#render-and-beforerender-events) as the views will only be added once\n(or re-added if the children are rebuilt in a subsequent `render`) and managed in the sort or filter as the `collection` is updated.\n\n#### Adding unmanaged children\n\nUnlike managed children there may be cases where you want to insert views to the results of the `CollectionView` after the\n`collection` changes, or after sorting and/or filtering. In these cases the solution might depend slightly on the features\nused on the `CollectionView`.\n\nThe goal will be to add the unmanaged views after other views are added and to remove any unmanaged views prior to any\nmanaged `children` changes. To do so you must understand which [`CollectionView` event](./events.class.md#collectionview-events)\nwill occur prior to changes to the `children` for your particular use case. By default a `CollectionView` sorts according\nto the `collection` sort, so unless `viewComparator` is disabled, the best event for removing unmanaged views is the\n[`before:sort` event](./events.class.md#sort-and-beforesort-events), but if `viewComparator` is false the next event\nto consider is the [`before:filter` event](./events.class.md#filter-and-beforefilter-events) if your `CollectionView` has\na `viewFilter`, otherwise the [`before:render:children` event](./events.class.md#renderchildren-and-beforerenderchildren-events)\nis ideal.\n\nOnce you have determined the best strategy for removing your unmanaged child views, adding them is best handled in the\n[`render:children` event](./events.class.md#renderchildren-and-beforerenderchildren-events). Additionally adding a child\nwith `addChildView` will itself cause these events to occur, so to prevent stack overflows, it is best to use a flag to guard\nthe adds and to insert a new view at a specified index.\n\nThe following simplistic example will add an unmanaged view at the 5th index and remove it prior to any changes to the `children`.\nIn a real world scenario it will likely be more complicated to keep track of which view to remove in the `onBeforeSort`.\n\n```javascript\nimport { CollectionView } from 'backbone.marionette';\n\nconst MyCollectionView = CollectionView.extend({\n  childView: MyChildView,\n  onBeforeSort() {\n    this.removeChildView(this.children.findByIndex(5));\n  },\n  onRenderChildren() {\n    this.addFooView();\n  },\n  addFooView() {\n    if (this.addingFooView) {\n      return;\n    }\n\n    this.addingFooView = true;\n    this.addChildView(new FooView(), 5);\n    this.addingFooView = false;\n  }\n});\n```\n\n## Attaching a View\n\nIn Marionette a view is attached if the view's `el` can be found in the DOM.\nThe best time to add listeners to the view's `el` is likely in the [`attach` event](./events.class.md#attach-and-beforeattach-events).\n\nWhile the `el` of the view can be attached the contents of the view can be removed and added to\nduring the lifetime of the view. If you are adding listeners to the contents of the view rather than\n`attach` the [`dom:refresh` event](./events.class.md#domrefresh-event) would be best.\n\nThe attached state is maintained when attaching a view with a `Region` or as a child of a `CollectionView`\nor during [view instantiation](#instantiating-a-view).\nIf a view is attached by other means like `$.append` [`isAttached`] may not reflect the actual state of attachment.\n\n## Detaching a View\n\nA view is detached when its `el` is removed from the DOM.\nThe best time to clean up any listeners added to the `el` is in the [`before:detach` event](./events.class.md#detach-and-beforedetach-events).\n\nWhile the `el` of the view may remain attached, its contents will be removed on render.\nIf you have added listeners to the contents of the view rather than `before:detach` the\n[`dom:remove` event](./events.class.md#domremove-event) would be best.\n\n## Destroying a View\n\nDestroying a view (ie: `myView.destroy()`) cleans up anything constucted within Marionette so that if\na view's instance is no longer referenced the view can be cleaned up by the browser's garbage collector.\n\nThe [`before:destroy` event](./events.class.md#destroy-and-beforedestroy-events) is the best place to clean\nup any added listeners not related to the view's DOM.\n\nThe state of the view after the destroy is not attached and not rendered although the `el` is not emptied.\n\n## Destroying Children\n\nChildren added to a `View`'s region or through a `CollectionView` will be automatically destroyed if the\nview is re-rendered, if the view is destroyed, or for `CollectionView` if the `collection` is reset.\n\n**Note** Children are removed after the DOM detach of the parent to prevent multiple reflows or repaints.\n"
  },
  {
    "path": "docs/view.rendering.md",
    "content": "# View Template Rendering\n\nUnlike [`Backbone.View`](http://backbonejs.org/#View-template), [Marionette views](./classes.md)\nprovide a customizable solution for rendering a template with data and placing the\nresults in the DOM.\n\n```javascript\nimport _ from 'underscore';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  tagName: 'h1',\n  template: _.template('Contents')\n});\n\nconst myView = new MyView();\nmyView.render();\n```\n\nIn the above example the contents of the `template` attribute will be rendered inside\na `<h1>` tag available at `myView.el`.\n\n[Live example](https://jsfiddle.net/marionettejs/h762zjua/)\n\n## Documentation Index\n\n* [What is a template](#what-is-a-template)\n* [Setting a View Template](#setting-a-view-template)\n  * [Using a View Without a Template](#using-a-view-without-a-template)\n* [Rendering the Template](#rendering-the-template)\n  * [Using a Custom Renderer](#using-a-custom-renderer)\n  * [Rendering to HTML](#rendering-to-html)\n  * [Rendering to DOM](#rendering-to-dom)\n* [Serializing Data](#serializing-data)\n  * [Serializing a Model](#serializing-a-model)\n  * [Serializing a Collection](#serializing-a-collection)\n  * [Serializing with a `CollectionView`](#serializing-with-a-collectionview)\n* [Adding Context Data](#adding-context-data)\n  * [What is Context Data?](#what-is-context-data)\n\n## What is a template?\n\nA template is a function that given data returns either an HTML string or DOM.\n[The default renderer](#rendering-the-template) in Marionette expects the template to\nreturn an HTML string. Marionette's dependency Underscore comes with an HTML string\n[template compiler](http://underscorejs.org/#template).\n\n```javascript\nimport _ from 'underscore';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  template: _.template('<h1>Hello, world</h1>')\n});\n```\nThis doesn't have to be an underscore template, you can pass your own rendering\nfunction:\n\n```javascript\nimport Handlebars from 'handlebars';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  template: Handlebars.compile('<h1>Hello, {{ name }}')\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/ep0e4qkt/)\n\n## Setting a View Template\n\nMarionette views use the `getTemplate` method to determine which template to use for\nrendering into its `el`. By default `getTemplate` is predefined on the view as simply:\n\n```javascript\ngetTemplate() {\n  return this.template\n}\n```\n\nIn most cases by using the default `getTemplate` you can simply set the `template` on the\nview to define the view's template, but in some circumstances you may want to set the template\nconditionally.\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  template: _.template('Hello World!'),\n  getTemplate() {\n    if (this.model.has('user')) {\n      return _.template('Hello User!');\n    }\n\n    return this.template;\n  }\n});\n```\n\n[Live example](https://jsfiddle.net/marionettejs/9k5v4p92/)\n\n### Using a View Without a Template\n\nBy default `CollectionView` has no defined `template` and will only attempt to render the `template`\nif one is defined. For `View` there may be some situations where you do not intend to use a `template`.\nPerhaps you only need the view's `el` or you are using [prerendered content](./dom.prerendered.md).\n\nIn this case setting `template` to `false` will prevent the template render. In the case of `View`\nit will also prevent the [`render` events](./events.class.md#render-and-beforerender-events).\n\n```javascript\nimport { View } from 'backbone.marionette';\n\nconst MyIconButtonView = View.extend({\n  template: false,\n  tagName: 'button',\n  className: '.icon-button',\n  triggers: {\n    'click': 'click'\n  },\n  onRender() {\n    console.log('You will never see me!');\n  }\n});\n```\n\n## Rendering the Template\n\nEach view class has a renderer which by default passes the [view data](#serializing-data)\nto the template function and returns the html string it generates.\n\nThe current default renderer is essentially the following:\n```javascript\nimport { View, CollectionView } from 'backbone.marionette';\n\nfunction renderer(template, data) {\n  return template(data);\n}\n\nView.setRenderer(renderer);\nCollectionView.setRenderer(renderer);\n```\n\nPrevious to Marionette v4 the default renderer was the `TemplateCache`. This renderer has been extracted\nto a separate library: https://github.com/marionettejs/marionette.templatecache and can be used with v4.\n\n### Using a Custom Renderer\n\nYou can set the renderer for a view class by using the class method `setRenderer`.\nThe renderer accepts two arguments. The first is the template passed to the view,\nand the second argument is the data to be rendered into the template.\n\nHere's an example that allows for the `template` of a view to be an underscore template string.\n\n```javascript\nimport _ from 'underscore';\nimport { View } from 'backbone.marionette';\n\nView.setRenderer(function(template, data) {\n  return _.template(template)(data);\n});\n\nconst myView = new View({\n  template: 'Hello <%- name %>!',\n  model: new Backbone.Model({ name: 'World' })\n});\n\nmyView.render();\n\n// myView.el is <div>Hello World!</div>\n```\n\nThe renderer can also be customized separately on any extended View.\n\n```javascript\nconst MyHBSView = View.extend();\n\n// Similar example as above but for handlebars\nMyHBSView.setRenderer(function(template, data) {\n  return Handlebars.compile(template)(data);\n});\n\nconst myHBSView = new MyHBSView({\n  template: 'Hello {{ name }}!',\n  model: new Backbone.Model({ name: 'World' })\n});\n\nmyHBSView.render();\n\n// myView.el is <div>Hello World!</div>\n```\n\n**Note** These examples while functional may not be ideal. If possible it is recommend to\nprecompile your templates which can be done for a number of templating using various plugins\nfor bundling tools such as [Browserify or Webpack](./installation.md).\n\n### Rendering to HTML\n\nThe default Marionette renders return the HTML as a string. This string is passed to the view's\n`attachElContents` method which in turn uses the DOM API's [`setContents`](./dom.api.md#setcontentsel-html).\nto set the contents of the view's `el` with DOM from the string.\n\n#### Customizing `attachElContents`\n\nYou can modify the way any particular view attaches a compiled template to the `el` by overriding `attachElContents`.\nThis method receives only the results of the view's renderer and is only called if the renderer returned a value.\n\nFor instance, perhaps for one particular view you need to bypass the [DOM API](./dom.api.md) and set the html directly:\n\n```javascript\nattachElContent(html) {\n  this.el.innerHTML = html;\n}\n```\n\n### Rendering to DOM\n\nMarionette also supports templates that render to DOM instead of html strings by using a custom render.\n\nIn the following example the `template` method passed to the renderer will return a DOM element, and then\nif the view is already rendered utilize [morphdom](https://github.com/patrick-steele-idem/morphdom) to patch\nthe DOM or otherwise it will set the view's `el` to the result of the template. (Note in this case the view's\n`el` created at instantiation would be overridden).\n\n```javascript\nimport morphdom from 'morphdom';\nimport { View } from 'backbone.marionette';\n\nconst VDomView = View.extend();\n\nVDomView.setRenderer(function(template, data) {\n  const el = template(data);\n\n  if (this.isRendered()) {\n    // Patch the view's el contents in the DOM\n    morphdom(this.el, el, { childrenOnly: true });\n    return;\n  }\n\n  this.setElement(el.cloneNode(true));\n});\n```\n\nIn this case because the renderer is modifying the `el` directly, there is no need to return the result\nof the template rendering for the view to handle in [`attachElContents`](#customizing-attachelcontents).\nIt is certainly an option to return the compiled DOM and modify [`attachElContents`](#customizing-attachelcontents)\nto handle a DOM object instead of a string literal, but in many cases it may be overcomplicated to do so.\n\nThere are a variety of possibilities for rendering with Marionette. If you are looking into alternatives\nfrom the default this may be a useful resource: https://github.com/blikblum/marionette.renderers#renderers\n\n## Serializing Data\n\nMarionette will automatically serialize the data from its `model` or `collection` for the template to use\nat [rendering](#rendering-the-template). You can override this logic and provide serialization of other\ndata with the `serializeData` method. The method is called with no arguments, but has the context of the\nview and should return a javascript object for the template to consume. If `serializeData` does not return\ndata the template may still receive [added context](#adding-context-data) or an empty object for rendering.\n\n```javascript\nimport _ from 'underscore';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  template: _.template(`\n    <div><% user.name %></div>\n    <ul>\n    <% _.each(groups, function(group) { %>\n      <li><%- group.name %></li>\n    <% }) %>\n    </ul>\n  `),\n  serializeData() {\n    // For this view I need both the\n    // model and collection serialized\n    return {\n      user: this.serializeModel(),\n      groups: this.serializeCollection(),\n    };\n  }\n});\n```\n\n**Note** You should not use this method to add arbitrary extra data to your template.\nInstead use `templateContext` to [add context data to your template](#adding-context-data).\n\n### Serializing a Model\n\nIf the view has a `model` it will pass that model's attributes\nto the template.\n\n```javascript\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport { View } from 'backbone.marionette';\n\nconst MyModel = Backbone.Model.extend({\n  defaults: {\n    name: 'world'\n  }\n});\n\nconst MyView = View.extend({\n  template: _.template('<h1>Hello, <%- name %></h1>')\n});\n\nconst myView = new MyView({ model: new MyModel() });\n```\n\n[Live example](https://jsfiddle.net/marionettejs/warfa6rL/)\n\nHow the `model` is serialized can also be customized per view.\n\n```javascript\nimport _ from 'underscore';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  serializeModel() {\n    const data = _.clone(this.model.attributes);\n\n    // serialize nested model data\n    data.sub_model = data.sub_model.attributes;\n\n    return data;\n  }\n});\n```\n\n### Serializing a Collection\n\nIf the view does not have a `model` but has a `collection` the collection's models will\nbe serialized to an array provided as an `items` attribute to the template.\n\n```javascript\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  template: _.template(`\n    <ul>\n    <% _.each(items, function(item) { %>\n      <li><%- item.name %></li>\n    <% }) %>\n    </ul>\n  `)\n});\n\nconst collection = new Backbone.Collection([\n  {name: 'Steve'}, {name: 'Helen'}\n]);\n\nconst myView = new MyView({ collection });\n```\n\n[Live example](https://jsfiddle.net/marionettejs/qyodkakf/)\n\nHow the `collection` is serialized can also be customized per view.\n\n```javascript\nimport _ from 'underscore';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  serializeCollection() {\n    return _.map(this.collection.models, model => {\n      const data = _.clone(model.attributes);\n\n      // serialize nested model data\n      data.sub_model = data.sub_model.attributes;\n\n      return data;\n    });\n  }\n});\n```\n\n### Serializing with a `CollectionView`\n\nif you are using a `template` with a `CollectionView` that is not also given a `model`, your `CollectionView`\nwill [serialize the collection](serializing-a-collection) for the template. This could be costly and unnecessary.\nIf your `CollectionView` has a `template` it is advised to either use an empty `model` or override the\n[`serializeData`](#serializing-data) method.\n\n## Adding Context Data\n\nMarionette views provide a `templateContext` attribute that is used to add\nextra information to your templates. This can be either an object, or a function\nreturning an object. The keys on the returned object will be mixed into the\nmodel or collection keys and made available to the template.\n\n```javascript\nimport _ from 'underscore';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  template: _.template('<h1>Hello, <%- name %></h1>'),\n  templateContext: {\n    name: 'World'\n  }\n});\n```\n\nAdditionally context data overwrites the serialized data\n\n```javascript\nimport _ from 'underscore';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  template: _.template('<h1>Hello, <%- name %></h1>'),\n  templateContext() {\n    return {\n      name: this.model.get('name').toUpperCase()\n    };\n  }\n});\n```\n\nYou can also define a template context value as a method. How this method is called is determined\nby your templating solution. For instance with handlebars a method is called with the context of\nthe data passed to the template.\n\n```javascript\nimport Handlebars from 'handlebars';\nimport Backbone from 'backbone';\nimport { View } from 'backbone.marionette';\n\nconst MyView = View.extend({\n  template: Handlebars.compile(`\n    <h1{{#if isDr}} class=\"dr\"{{/if}}>Hello {{ fullName }}</h1>,\n  `),\n  templateContext: {\n    isDr() {\n      return (this.degree) === 'phd';\n    },\n    fullName() {\n      // Because of Handlebars `this` here is the data object\n      // passed to the template which is the result of the\n      // templateContext mixed with the serialized data of the view\n      return this.isDr() ? `Dr. { this.name }` : this.name;\n    }\n  }\n});\n\nconst myView = new MyView({\n  model: new Backbone.Model({ degree: 'masters', name: 'Joe' });\n});\n```\n\n**Note** the data object passed to the template is not deeply cloned and in some cases is not cloned at all.\nTake caution when modifying the data passed to the template, that you are not also modifying your model's\ndata indirectly.\n\n### What is Context Data?\n\nWhile [serializing data](#serializing-data) deals more with getting the data belonging to the view\ninto the template, template context mixes in other needed data, or in some cases, might do extra\ncomputations that go beyond simply \"serializing\" the view's `model` or `collection`\n\n```javascript\nimport _ from 'underscore'\nimport { CollectionView } from 'backbone.marionette';\nimport GroupView from './group-view';\n\nconst MyCollectionView = CollectionView.extend({\n  tagName: 'div',\n  childViewContainer: 'ul',\n  childView: GroupView,\n  template: _.template(`\n    <h1>Hello <% name %> of <% orgName %></h1>\n    <div>You have <% stats.public %> group(s).</div>\n    <div>You have <% stats.private %> group(s).</div>\n    <h3>Groups:</h3>\n    <ul></ul>\n  `),\n  templateContext() {\n    const user = this.model;\n    const organization = user.getOrganization();\n    const groups = this.collection;\n\n    return {\n      orgName: organization.get('name'),\n      name: user.getFullName(),\n      stats: groups.countBy('type')\n    };\n  }\n})\n```\n"
  },
  {
    "path": "lib/backbone.marionette.esm.js",
    "content": "import Backbone from 'backbone';\nimport _ from 'underscore';\nimport Radio from 'backbone.radio';\n\nvar version = \"4.1.3\";\n\n//Internal utility for creating context style global utils\nvar proxy = function proxy(method) {\n  return function (context) {\n    for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n      args[_key - 1] = arguments[_key];\n    }\n\n    return method.apply(context, args);\n  };\n};\n\n// Marionette.extend\n\nvar extend = Backbone.Model.extend;\n\n// ----------------------\n// Pass in a mapping of events => functions or function names\n// and return a mapping of events => functions\n\nvar normalizeMethods = function normalizeMethods(hash) {\n  var _this = this;\n\n  if (!hash) {\n    return;\n  }\n\n  return _.reduce(hash, function (normalizedHash, method, name) {\n    if (!_.isFunction(method)) {\n      method = _this[method];\n    }\n\n    if (method) {\n      normalizedHash[name] = method;\n    }\n\n    return normalizedHash;\n  }, {});\n};\n\n// Error\nvar errorProps = ['description', 'fileName', 'lineNumber', 'name', 'message', 'number', 'url'];\nvar MarionetteError = extend.call(Error, {\n  urlRoot: \"http://marionettejs.com/docs/v\".concat(version, \"/\"),\n  url: '',\n  constructor: function constructor(options) {\n    var error = Error.call(this, options.message);\n\n    _.extend(this, _.pick(error, errorProps), _.pick(options, errorProps));\n\n    if (Error.captureStackTrace) {\n      this.captureStackTrace();\n    }\n\n    this.url = this.urlRoot + this.url;\n  },\n  captureStackTrace: function captureStackTrace() {\n    Error.captureStackTrace(this, MarionetteError);\n  },\n  toString: function toString() {\n    return \"\".concat(this.name, \": \").concat(this.message, \" See: \").concat(this.url);\n  }\n});\n\n// Bind Entity Events & Unbind Entity Events\n\nfunction normalizeBindings(context, bindings) {\n  if (!_.isObject(bindings)) {\n    throw new MarionetteError({\n      message: 'Bindings must be an object.',\n      url: 'common.html#bindevents'\n    });\n  }\n\n  return normalizeMethods.call(context, bindings);\n}\n\nfunction bindEvents(entity, bindings) {\n  if (!entity || !bindings) {\n    return this;\n  }\n\n  this.listenTo(entity, normalizeBindings(this, bindings));\n  return this;\n}\n\nfunction unbindEvents(entity, bindings) {\n  if (!entity) {\n    return this;\n  }\n\n  if (!bindings) {\n    this.stopListening(entity);\n    return this;\n  }\n\n  this.stopListening(entity, normalizeBindings(this, bindings));\n  return this;\n} // Export Public API\n\n// Bind/Unbind Radio Requests\n\nfunction normalizeBindings$1(context, bindings) {\n  if (!_.isObject(bindings)) {\n    throw new MarionetteError({\n      message: 'Bindings must be an object.',\n      url: 'common.html#bindrequests'\n    });\n  }\n\n  return normalizeMethods.call(context, bindings);\n}\n\nfunction bindRequests(channel, bindings) {\n  if (!channel || !bindings) {\n    return this;\n  }\n\n  channel.reply(normalizeBindings$1(this, bindings), this);\n  return this;\n}\n\nfunction unbindRequests(channel, bindings) {\n  if (!channel) {\n    return this;\n  }\n\n  if (!bindings) {\n    channel.stopReplying(null, null, this);\n    return this;\n  }\n\n  channel.stopReplying(normalizeBindings$1(this, bindings), this);\n  return this;\n}\n\n// Marionette.getOption\n// --------------------\n// Retrieve an object, function or other value from the\n// object or its `options`, with `options` taking precedence.\nvar getOption = function getOption(optionName) {\n  if (!optionName) {\n    return;\n  }\n\n  if (this.options && this.options[optionName] !== undefined) {\n    return this.options[optionName];\n  } else {\n    return this[optionName];\n  }\n};\n\nvar mergeOptions = function mergeOptions(options, keys) {\n  var _this = this;\n\n  if (!options) {\n    return;\n  }\n\n  _.each(keys, function (key) {\n    var option = options[key];\n\n    if (option !== undefined) {\n      _this[key] = option;\n    }\n  });\n};\n\n// DOM Refresh\n\nfunction triggerMethodChildren(view, event, shouldTrigger) {\n  if (!view._getImmediateChildren) {\n    return;\n  }\n\n  _.each(view._getImmediateChildren(), function (child) {\n    if (!shouldTrigger(child)) {\n      return;\n    }\n\n    child.triggerMethod(event, child);\n  });\n}\n\nfunction shouldTriggerAttach(view) {\n  return !view._isAttached;\n}\n\nfunction shouldAttach(view) {\n  if (!shouldTriggerAttach(view)) {\n    return false;\n  }\n\n  view._isAttached = true;\n  return true;\n}\n\nfunction shouldTriggerDetach(view) {\n  return view._isAttached;\n}\n\nfunction shouldDetach(view) {\n  view._isAttached = false;\n  return true;\n}\n\nfunction triggerDOMRefresh(view) {\n  if (view._isAttached && view._isRendered) {\n    view.triggerMethod('dom:refresh', view);\n  }\n}\n\nfunction triggerDOMRemove(view) {\n  if (view._isAttached && view._isRendered) {\n    view.triggerMethod('dom:remove', view);\n  }\n}\n\nfunction handleBeforeAttach() {\n  triggerMethodChildren(this, 'before:attach', shouldTriggerAttach);\n}\n\nfunction handleAttach() {\n  triggerMethodChildren(this, 'attach', shouldAttach);\n  triggerDOMRefresh(this);\n}\n\nfunction handleBeforeDetach() {\n  triggerMethodChildren(this, 'before:detach', shouldTriggerDetach);\n  triggerDOMRemove(this);\n}\n\nfunction handleDetach() {\n  triggerMethodChildren(this, 'detach', shouldDetach);\n}\n\nfunction handleBeforeRender() {\n  triggerDOMRemove(this);\n}\n\nfunction handleRender() {\n  triggerDOMRefresh(this);\n} // Monitor a view's state, propagating attach/detach events to children and firing dom:refresh\n// whenever a rendered view is attached or an attached view is rendered.\n\n\nfunction monitorViewEvents(view) {\n  if (view._areViewEventsMonitored || view.monitorViewEvents === false) {\n    return;\n  }\n\n  view._areViewEventsMonitored = true;\n  view.on({\n    'before:attach': handleBeforeAttach,\n    'attach': handleAttach,\n    'before:detach': handleBeforeDetach,\n    'detach': handleDetach,\n    'before:render': handleBeforeRender,\n    'render': handleRender\n  });\n}\n\n// Trigger Method\n\nvar splitter = /(^|:)(\\w)/gi; // Only calc getOnMethodName once\n\nvar methodCache = {}; // take the event section (\"section1:section2:section3\")\n// and turn it in to uppercase name onSection1Section2Section3\n\nfunction getEventName(match, prefix, eventName) {\n  return eventName.toUpperCase();\n}\n\nvar getOnMethodName = function getOnMethodName(event) {\n  if (!methodCache[event]) {\n    methodCache[event] = 'on' + event.replace(splitter, getEventName);\n  }\n\n  return methodCache[event];\n}; // Trigger an event and/or a corresponding method name. Examples:\n//\n// `this.triggerMethod(\"foo\")` will trigger the \"foo\" event and\n// call the \"onFoo\" method.\n//\n// `this.triggerMethod(\"foo:bar\")` will trigger the \"foo:bar\" event and\n// call the \"onFooBar\" method.\n\n\nfunction triggerMethod(event) {\n  // get the method name from the event name\n  var methodName = getOnMethodName(event);\n  var method = getOption.call(this, methodName);\n  var result; // call the onMethodName if it exists\n\n  if (_.isFunction(method)) {\n    // pass all args, except the event name\n    result = method.apply(this, _.drop(arguments));\n  } // trigger the event\n\n\n  this.trigger.apply(this, arguments);\n  return result;\n}\n\nvar Events = {\n  triggerMethod: triggerMethod\n};\n\nvar CommonMixin = {\n  // Imports the \"normalizeMethods\" to transform hashes of\n  // events=>function references/names to a hash of events=>function references\n  normalizeMethods: normalizeMethods,\n  _setOptions: function _setOptions(options, classOptions) {\n    this.options = _.extend({}, _.result(this, 'options'), options);\n    this.mergeOptions(options, classOptions);\n  },\n  // A handy way to merge passed-in options onto the instance\n  mergeOptions: mergeOptions,\n  // Enable getting options from this or this.options by name.\n  getOption: getOption,\n  // Enable binding view's events from another entity.\n  bindEvents: bindEvents,\n  // Enable unbinding view's events from another entity.\n  unbindEvents: unbindEvents,\n  // Enable binding view's requests.\n  bindRequests: bindRequests,\n  // Enable unbinding view's requests.\n  unbindRequests: unbindRequests,\n  triggerMethod: triggerMethod\n};\n\n_.extend(CommonMixin, Backbone.Events);\n\nvar DestroyMixin = {\n  _isDestroyed: false,\n  isDestroyed: function isDestroyed() {\n    return this._isDestroyed;\n  },\n  destroy: function destroy(options) {\n    if (this._isDestroyed) {\n      return this;\n    }\n\n    this.triggerMethod('before:destroy', this, options);\n    this._isDestroyed = true;\n    this.triggerMethod('destroy', this, options);\n    this.stopListening();\n    return this;\n  }\n};\n\n// - channelName\n// - radioEvents\n// - radioRequests\n\nvar RadioMixin = {\n  _initRadio: function _initRadio() {\n    var channelName = _.result(this, 'channelName');\n\n    if (!channelName) {\n      return;\n    }\n    /* istanbul ignore next */\n\n\n    if (!Radio) {\n      throw new MarionetteError({\n        message: 'The dependency \"backbone.radio\" is missing.',\n        url: 'backbone.radio.html#marionette-integration'\n      });\n    }\n\n    var channel = this._channel = Radio.channel(channelName);\n\n    var radioEvents = _.result(this, 'radioEvents');\n\n    this.bindEvents(channel, radioEvents);\n\n    var radioRequests = _.result(this, 'radioRequests');\n\n    this.bindRequests(channel, radioRequests);\n    this.on('destroy', this._destroyRadio);\n  },\n  _destroyRadio: function _destroyRadio() {\n    this._channel.stopReplying(null, null, this);\n  },\n  getChannel: function getChannel() {\n    return this._channel;\n  }\n};\n\n// Object\nvar ClassOptions = ['channelName', 'radioEvents', 'radioRequests']; // Object borrows many conventions and utilities from Backbone.\n\nvar MarionetteObject = function MarionetteObject(options) {\n  this._setOptions(options, ClassOptions);\n\n  this.cid = _.uniqueId(this.cidPrefix);\n\n  this._initRadio();\n\n  this.initialize.apply(this, arguments);\n};\n\nMarionetteObject.extend = extend; // Object Methods\n// --------------\n\n_.extend(MarionetteObject.prototype, CommonMixin, DestroyMixin, RadioMixin, {\n  cidPrefix: 'mno',\n  // This is a noop method intended to be overridden\n  initialize: function initialize() {}\n});\n\n// Implementation of the invoke method (http://underscorejs.org/#invoke) with support for\nvar _invoke = _.invokeMap || _.invoke;\n\n// - behaviors\n// Takes care of getting the behavior class\n// given options and a key.\n// If a user passes in options.behaviorClass\n// default to using that.\n// If a user passes in a Behavior Class directly, use that\n// Otherwise an error is thrown\n\nfunction getBehaviorClass(options) {\n  if (options.behaviorClass) {\n    return {\n      BehaviorClass: options.behaviorClass,\n      options: options\n    };\n  } //treat functions as a Behavior constructor\n\n\n  if (_.isFunction(options)) {\n    return {\n      BehaviorClass: options,\n      options: {}\n    };\n  }\n\n  throw new MarionetteError({\n    message: 'Unable to get behavior class. A Behavior constructor should be passed directly or as behaviorClass property of options',\n    url: 'marionette.behavior.html#defining-and-attaching-behaviors'\n  });\n} // Iterate over the behaviors object, for each behavior\n// instantiate it and get its grouped behaviors.\n// This accepts a list of behaviors in either an object or array form\n\n\nfunction parseBehaviors(view, behaviors, allBehaviors) {\n  return _.reduce(behaviors, function (reducedBehaviors, behaviorDefiniton) {\n    var _getBehaviorClass = getBehaviorClass(behaviorDefiniton),\n        BehaviorClass = _getBehaviorClass.BehaviorClass,\n        options = _getBehaviorClass.options;\n\n    var behavior = new BehaviorClass(options, view);\n    reducedBehaviors.push(behavior);\n    return parseBehaviors(view, _.result(behavior, 'behaviors'), reducedBehaviors);\n  }, allBehaviors);\n}\n\nvar BehaviorsMixin = {\n  _initBehaviors: function _initBehaviors() {\n    this._behaviors = parseBehaviors(this, _.result(this, 'behaviors'), []);\n  },\n  _getBehaviorTriggers: function _getBehaviorTriggers() {\n    var triggers = _invoke(this._behaviors, '_getTriggers');\n\n    return _.reduce(triggers, function (memo, _triggers) {\n      return _.extend(memo, _triggers);\n    }, {});\n  },\n  _getBehaviorEvents: function _getBehaviorEvents() {\n    var events = _invoke(this._behaviors, '_getEvents');\n\n    return _.reduce(events, function (memo, _events) {\n      return _.extend(memo, _events);\n    }, {});\n  },\n  // proxy behavior $el to the view's $el.\n  _proxyBehaviorViewProperties: function _proxyBehaviorViewProperties() {\n    _invoke(this._behaviors, 'proxyViewProperties');\n  },\n  // delegate modelEvents and collectionEvents\n  _delegateBehaviorEntityEvents: function _delegateBehaviorEntityEvents() {\n    _invoke(this._behaviors, 'delegateEntityEvents');\n  },\n  // undelegate modelEvents and collectionEvents\n  _undelegateBehaviorEntityEvents: function _undelegateBehaviorEntityEvents() {\n    _invoke(this._behaviors, 'undelegateEntityEvents');\n  },\n  _destroyBehaviors: function _destroyBehaviors(options) {\n    // Call destroy on each behavior after\n    // destroying the view.\n    // This unbinds event listeners\n    // that behaviors have registered for.\n    _invoke(this._behaviors, 'destroy', options);\n  },\n  // Remove a behavior\n  _removeBehavior: function _removeBehavior(behavior) {\n    // Don't worry about the clean up if the view is destroyed\n    if (this._isDestroyed) {\n      return;\n    } // Remove behavior-only triggers and events\n\n\n    this.undelegate(\".trig\".concat(behavior.cid, \" .\").concat(behavior.cid));\n    this._behaviors = _.without(this._behaviors, behavior);\n  },\n  _bindBehaviorUIElements: function _bindBehaviorUIElements() {\n    _invoke(this._behaviors, 'bindUIElements');\n  },\n  _unbindBehaviorUIElements: function _unbindBehaviorUIElements() {\n    _invoke(this._behaviors, 'unbindUIElements');\n  },\n  _triggerEventOnBehaviors: function _triggerEventOnBehaviors(eventName, view, options) {\n    _invoke(this._behaviors, 'triggerMethod', eventName, view, options);\n  }\n};\n\n// - collectionEvents\n// - modelEvents\n\nvar DelegateEntityEventsMixin = {\n  // Handle `modelEvents`, and `collectionEvents` configuration\n  _delegateEntityEvents: function _delegateEntityEvents(model, collection) {\n    if (model) {\n      this._modelEvents = _.result(this, 'modelEvents');\n      this.bindEvents(model, this._modelEvents);\n    }\n\n    if (collection) {\n      this._collectionEvents = _.result(this, 'collectionEvents');\n      this.bindEvents(collection, this._collectionEvents);\n    }\n  },\n  // Remove any previously delegate entity events\n  _undelegateEntityEvents: function _undelegateEntityEvents(model, collection) {\n    if (this._modelEvents) {\n      this.unbindEvents(model, this._modelEvents);\n      delete this._modelEvents;\n    }\n\n    if (this._collectionEvents) {\n      this.unbindEvents(collection, this._collectionEvents);\n      delete this._collectionEvents;\n    }\n  },\n  // Remove cached event handlers\n  _deleteEntityEventHandlers: function _deleteEntityEventHandlers() {\n    delete this._modelEvents;\n    delete this._collectionEvents;\n  }\n};\n\n// - template\n// - templateContext\n\nvar TemplateRenderMixin = {\n  // Internal method to render the template with the serialized data\n  // and template context\n  _renderTemplate: function _renderTemplate(template) {\n    // Add in entity data and template context\n    var data = this.mixinTemplateContext(this.serializeData()) || {}; // Render and add to el\n\n    var html = this._renderHtml(template, data);\n\n    if (typeof html !== 'undefined') {\n      this.attachElContent(html);\n    }\n  },\n  // Get the template for this view instance.\n  // You can set a `template` attribute in the view definition\n  // or pass a `template: TemplateFunction` parameter in\n  // to the constructor options.\n  getTemplate: function getTemplate() {\n    return this.template;\n  },\n  // Mix in template context methods. Looks for a\n  // `templateContext` attribute, which can either be an\n  // object literal, or a function that returns an object\n  // literal. All methods and attributes from this object\n  // are copies to the object passed in.\n  mixinTemplateContext: function mixinTemplateContext(serializedData) {\n    var templateContext = _.result(this, 'templateContext');\n\n    if (!templateContext) {\n      return serializedData;\n    }\n\n    if (!serializedData) {\n      return templateContext;\n    }\n\n    return _.extend({}, serializedData, templateContext);\n  },\n  // Serialize the view's model *or* collection, if\n  // it exists, for the template\n  serializeData: function serializeData() {\n    // If we have a model, we serialize that\n    if (this.model) {\n      return this.serializeModel();\n    } // Otherwise, we serialize the collection,\n    // making it available under the `items` property\n\n\n    if (this.collection) {\n      return {\n        items: this.serializeCollection()\n      };\n    }\n  },\n  // Prepares the special `model` property of a view\n  // for being displayed in the template. Override this if\n  // you need a custom transformation for your view's model\n  serializeModel: function serializeModel() {\n    return this.model.attributes;\n  },\n  // Serialize a collection\n  serializeCollection: function serializeCollection() {\n    return _.map(this.collection.models, function (model) {\n      return model.attributes;\n    });\n  },\n  // Renders the data into the template\n  _renderHtml: function _renderHtml(template, data) {\n    return template(data);\n  },\n  // Attaches the content of a given view.\n  // This method can be overridden to optimize rendering,\n  // or to render in a non standard way.\n  //\n  // For example, using `innerHTML` instead of `$el.html`\n  //\n  // ```js\n  // attachElContent(html) {\n  //   this.el.innerHTML = html;\n  // }\n  // ```\n  attachElContent: function attachElContent(html) {\n    this.Dom.setContents(this.el, html, this.$el);\n  }\n};\n\n// Borrow event splitter from Backbone\nvar delegateEventSplitter = /^(\\S+)\\s*(.*)$/; // Set event name to be namespaced using a unique index\n// to generate a non colliding event namespace\n// http://api.jquery.com/event.namespace/\n\nvar getNamespacedEventName = function getNamespacedEventName(eventName, namespace) {\n  var match = eventName.match(delegateEventSplitter);\n  return \"\".concat(match[1], \".\").concat(namespace, \" \").concat(match[2]);\n};\n\n// Add Feature flags here\n// e.g. 'class' => false\nvar FEATURES = {\n  childViewEventPrefix: false,\n  triggersStopPropagation: true,\n  triggersPreventDefault: true,\n  DEV_MODE: false\n};\n\nfunction isEnabled(name) {\n  return !!FEATURES[name];\n}\n\nfunction setEnabled(name, state) {\n  return FEATURES[name] = state;\n}\n\n// 'click:foo'\n\nfunction buildViewTrigger(view, triggerDef) {\n  if (_.isString(triggerDef)) {\n    triggerDef = {\n      event: triggerDef\n    };\n  }\n\n  var eventName = triggerDef.event;\n  var shouldPreventDefault = !!triggerDef.preventDefault;\n\n  if (isEnabled('triggersPreventDefault')) {\n    shouldPreventDefault = triggerDef.preventDefault !== false;\n  }\n\n  var shouldStopPropagation = !!triggerDef.stopPropagation;\n\n  if (isEnabled('triggersStopPropagation')) {\n    shouldStopPropagation = triggerDef.stopPropagation !== false;\n  }\n\n  return function (event) {\n    if (shouldPreventDefault) {\n      event.preventDefault();\n    }\n\n    if (shouldStopPropagation) {\n      event.stopPropagation();\n    }\n\n    for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n      args[_key - 1] = arguments[_key];\n    }\n\n    view.triggerMethod.apply(view, [eventName, view, event].concat(args));\n  };\n}\n\nvar TriggersMixin = {\n  // Configure `triggers` to forward DOM events to view\n  // events. `triggers: {\"click .foo\": \"do:foo\"}`\n  _getViewTriggers: function _getViewTriggers(view, triggers) {\n    var _this = this;\n\n    // Configure the triggers, prevent default\n    // action and stop propagation of DOM events\n    return _.reduce(triggers, function (events, value, key) {\n      key = getNamespacedEventName(key, \"trig\".concat(_this.cid));\n      events[key] = buildViewTrigger(view, value);\n      return events;\n    }, {});\n  }\n};\n\n// a given key for triggers and events\n// swaps the @ui with the associated selector.\n// Returns a new, non-mutated, parsed events hash.\n\nvar _normalizeUIKeys = function normalizeUIKeys(hash, ui) {\n  return _.reduce(hash, function (memo, val, key) {\n    var normalizedKey = _normalizeUIString(key, ui);\n\n    memo[normalizedKey] = val;\n    return memo;\n  }, {});\n};\n\nvar uiRegEx = /@ui\\.[a-zA-Z-_$0-9]*/g; // utility method for parsing @ui. syntax strings\n// into associated selector\n\nvar _normalizeUIString = function normalizeUIString(uiString, ui) {\n  return uiString.replace(uiRegEx, function (r) {\n    return ui[r.slice(4)];\n  });\n}; // allows for the use of the @ui. syntax within\n// a given value for regions\n// swaps the @ui with the associated selector\n\n\nvar _normalizeUIValues = function normalizeUIValues(hash, ui, property) {\n  _.each(hash, function (val, key) {\n    if (_.isString(val)) {\n      hash[key] = _normalizeUIString(val, ui);\n    } else if (val) {\n      var propertyVal = val[property];\n\n      if (_.isString(propertyVal)) {\n        val[property] = _normalizeUIString(propertyVal, ui);\n      }\n    }\n  });\n\n  return hash;\n};\n\nvar UIMixin = {\n  // normalize the keys of passed hash with the views `ui` selectors.\n  // `{\"@ui.foo\": \"bar\"}`\n  normalizeUIKeys: function normalizeUIKeys(hash) {\n    var uiBindings = this._getUIBindings();\n\n    return _normalizeUIKeys(hash, uiBindings);\n  },\n  // normalize the passed string with the views `ui` selectors.\n  // `\"@ui.bar\"`\n  normalizeUIString: function normalizeUIString(uiString) {\n    var uiBindings = this._getUIBindings();\n\n    return _normalizeUIString(uiString, uiBindings);\n  },\n  // normalize the values of passed hash with the views `ui` selectors.\n  // `{foo: \"@ui.bar\"}`\n  normalizeUIValues: function normalizeUIValues(hash, property) {\n    var uiBindings = this._getUIBindings();\n\n    return _normalizeUIValues(hash, uiBindings, property);\n  },\n  _getUIBindings: function _getUIBindings() {\n    var uiBindings = _.result(this, '_uiBindings');\n\n    return uiBindings || _.result(this, 'ui');\n  },\n  // This method binds the elements specified in the \"ui\" hash inside the view's code with\n  // the associated jQuery selectors.\n  _bindUIElements: function _bindUIElements() {\n    var _this = this;\n\n    if (!this.ui) {\n      return;\n    } // store the ui hash in _uiBindings so they can be reset later\n    // and so re-rendering the view will be able to find the bindings\n\n\n    if (!this._uiBindings) {\n      this._uiBindings = this.ui;\n    } // get the bindings result, as a function or otherwise\n\n\n    var bindings = _.result(this, '_uiBindings'); // empty the ui so we don't have anything to start with\n\n\n    this._ui = {}; // bind each of the selectors\n\n    _.each(bindings, function (selector, key) {\n      _this._ui[key] = _this.$(selector);\n    });\n\n    this.ui = this._ui;\n  },\n  _unbindUIElements: function _unbindUIElements() {\n    var _this2 = this;\n\n    if (!this.ui || !this._uiBindings) {\n      return;\n    } // delete all of the existing ui bindings\n\n\n    _.each(this.ui, function ($el, name) {\n      delete _this2.ui[name];\n    }); // reset the ui element to the original bindings configuration\n\n\n    this.ui = this._uiBindings;\n    delete this._uiBindings;\n    delete this._ui;\n  },\n  _getUI: function _getUI(name) {\n    return this._ui[name];\n  }\n};\n\n// DomApi\n\nfunction _getEl(el) {\n  return el instanceof Backbone.$ ? el : Backbone.$(el);\n} // Static setter\n\n\nfunction setDomApi(mixin) {\n  this.prototype.Dom = _.extend({}, this.prototype.Dom, mixin);\n  return this;\n}\nvar DomApi = {\n  // Returns a new HTML DOM node instance\n  createBuffer: function createBuffer() {\n    return document.createDocumentFragment();\n  },\n  // Returns the document element for a given DOM element\n  getDocumentEl: function getDocumentEl(el) {\n    return el.ownerDocument.documentElement;\n  },\n  // Lookup the `selector` string\n  // Selector may also be a DOM element\n  // Returns an array-like object of nodes\n  getEl: function getEl(selector) {\n    return _getEl(selector);\n  },\n  // Finds the `selector` string with the el\n  // Returns an array-like object of nodes\n  findEl: function findEl(el, selector) {\n    return _getEl(el).find(selector);\n  },\n  // Returns true if the el contains the node childEl\n  hasEl: function hasEl(el, childEl) {\n    return el.contains(childEl && childEl.parentNode);\n  },\n  // Detach `el` from the DOM without removing listeners\n  detachEl: function detachEl(el) {\n    var _$el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _getEl(el);\n\n    _$el.detach();\n  },\n  // Remove `oldEl` from the DOM and put `newEl` in its place\n  replaceEl: function replaceEl(newEl, oldEl) {\n    if (newEl === oldEl) {\n      return;\n    }\n\n    var parent = oldEl.parentNode;\n\n    if (!parent) {\n      return;\n    }\n\n    parent.replaceChild(newEl, oldEl);\n  },\n  // Swaps the location of `el1` and `el2` in the DOM\n  swapEl: function swapEl(el1, el2) {\n    if (el1 === el2) {\n      return;\n    }\n\n    var parent1 = el1.parentNode;\n    var parent2 = el2.parentNode;\n\n    if (!parent1 || !parent2) {\n      return;\n    }\n\n    var next1 = el1.nextSibling;\n    var next2 = el2.nextSibling;\n    parent1.insertBefore(el2, next1);\n    parent2.insertBefore(el1, next2);\n  },\n  // Replace the contents of `el` with the HTML string of `html`\n  setContents: function setContents(el, html) {\n    var _$el = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _getEl(el);\n\n    _$el.html(html);\n  },\n  // Takes the DOM node `el` and appends the DOM node `contents`\n  // to the end of the element's contents.\n  appendContents: function appendContents(el, contents) {\n    var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},\n        _ref$_$el = _ref._$el,\n        _$el = _ref$_$el === void 0 ? _getEl(el) : _ref$_$el,\n        _ref$_$contents = _ref._$contents,\n        _$contents = _ref$_$contents === void 0 ? _getEl(contents) : _ref$_$contents;\n\n    _$el.append(_$contents);\n  },\n  // Does the el have child nodes\n  hasContents: function hasContents(el) {\n    return !!el && el.hasChildNodes();\n  },\n  // Remove the inner contents of `el` from the DOM while leaving\n  // `el` itself in the DOM.\n  detachContents: function detachContents(el) {\n    var _$el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _getEl(el);\n\n    _$el.contents().detach();\n  }\n};\n\n// ViewMixin\n// - behaviors\n// - childViewEventPrefix\n// - childViewEvents\n// - childViewTriggers\n// - collectionEvents\n// - modelEvents\n// - triggers\n// - ui\n\nvar ViewMixin = {\n  Dom: DomApi,\n  _isElAttached: function _isElAttached() {\n    return !!this.el && this.Dom.hasEl(this.Dom.getDocumentEl(this.el), this.el);\n  },\n  supportsRenderLifecycle: true,\n  supportsDestroyLifecycle: true,\n  _isDestroyed: false,\n  isDestroyed: function isDestroyed() {\n    return !!this._isDestroyed;\n  },\n  _isRendered: false,\n  isRendered: function isRendered() {\n    return !!this._isRendered;\n  },\n  _isAttached: false,\n  isAttached: function isAttached() {\n    return !!this._isAttached;\n  },\n  // Overriding Backbone.View's `delegateEvents` to handle\n  // `events` and `triggers`\n  delegateEvents: function delegateEvents(events) {\n    this._proxyBehaviorViewProperties();\n\n    this._buildEventProxies();\n\n    var combinedEvents = _.extend({}, this._getBehaviorEvents(), this._getEvents(events), this._getBehaviorTriggers(), this._getTriggers());\n\n    Backbone.View.prototype.delegateEvents.call(this, combinedEvents);\n    return this;\n  },\n  // Allows Backbone.View events to utilize `@ui.` selectors\n  _getEvents: function _getEvents(events) {\n    if (events) {\n      return this.normalizeUIKeys(events);\n    }\n\n    if (!this.events) {\n      return;\n    }\n\n    return this.normalizeUIKeys(_.result(this, 'events'));\n  },\n  // Configure `triggers` to forward DOM events to view\n  // events. `triggers: {\"click .foo\": \"do:foo\"}`\n  _getTriggers: function _getTriggers() {\n    if (!this.triggers) {\n      return;\n    } // Allow `triggers` to be configured as a function\n\n\n    var triggers = this.normalizeUIKeys(_.result(this, 'triggers')); // Configure the triggers, prevent default\n    // action and stop propagation of DOM events\n\n    return this._getViewTriggers(this, triggers);\n  },\n  // Handle `modelEvents`, and `collectionEvents` configuration\n  delegateEntityEvents: function delegateEntityEvents() {\n    this._delegateEntityEvents(this.model, this.collection); // bind each behaviors model and collection events\n\n\n    this._delegateBehaviorEntityEvents();\n\n    return this;\n  },\n  // Handle unbinding `modelEvents`, and `collectionEvents` configuration\n  undelegateEntityEvents: function undelegateEntityEvents() {\n    this._undelegateEntityEvents(this.model, this.collection); // unbind each behaviors model and collection events\n\n\n    this._undelegateBehaviorEntityEvents();\n\n    return this;\n  },\n  // Handle destroying the view and its children.\n  destroy: function destroy(options) {\n    if (this._isDestroyed || this._isDestroying) {\n      return this;\n    }\n\n    this._isDestroying = true;\n    var shouldTriggerDetach = this._isAttached && !this._disableDetachEvents;\n    this.triggerMethod('before:destroy', this, options);\n\n    if (shouldTriggerDetach) {\n      this.triggerMethod('before:detach', this);\n    } // unbind UI elements\n\n\n    this.unbindUIElements(); // remove the view from the DOM\n\n    this._removeElement();\n\n    if (shouldTriggerDetach) {\n      this._isAttached = false;\n      this.triggerMethod('detach', this);\n    } // remove children after the remove to prevent extra paints\n\n\n    this._removeChildren();\n\n    this._isDestroyed = true;\n    this._isRendered = false; // Destroy behaviors after _isDestroyed flag\n\n    this._destroyBehaviors(options);\n\n    this._deleteEntityEventHandlers();\n\n    this.triggerMethod('destroy', this, options);\n\n    this._triggerEventOnBehaviors('destroy', this, options);\n\n    this.stopListening();\n    return this;\n  },\n  // Equates to this.$el.remove\n  _removeElement: function _removeElement() {\n    this.$el.off().removeData();\n    this.Dom.detachEl(this.el, this.$el);\n  },\n  // This method binds the elements specified in the \"ui\" hash\n  bindUIElements: function bindUIElements() {\n    this._bindUIElements();\n\n    this._bindBehaviorUIElements();\n\n    return this;\n  },\n  // This method unbinds the elements specified in the \"ui\" hash\n  unbindUIElements: function unbindUIElements() {\n    this._unbindUIElements();\n\n    this._unbindBehaviorUIElements();\n\n    return this;\n  },\n  getUI: function getUI(name) {\n    return this._getUI(name);\n  },\n  // Cache `childViewEvents` and `childViewTriggers`\n  _buildEventProxies: function _buildEventProxies() {\n    this._childViewEvents = this.normalizeMethods(_.result(this, 'childViewEvents'));\n    this._childViewTriggers = _.result(this, 'childViewTriggers');\n    this._eventPrefix = this._getEventPrefix();\n  },\n  _getEventPrefix: function _getEventPrefix() {\n    var defaultPrefix = isEnabled('childViewEventPrefix') ? 'childview' : false;\n\n    var prefix = _.result(this, 'childViewEventPrefix', defaultPrefix);\n\n    return prefix === false ? prefix : prefix + ':';\n  },\n  _proxyChildViewEvents: function _proxyChildViewEvents(view) {\n    if (this._childViewEvents || this._childViewTriggers || this._eventPrefix) {\n      this.listenTo(view, 'all', this._childViewEventHandler);\n    }\n  },\n  _childViewEventHandler: function _childViewEventHandler(eventName) {\n    var childViewEvents = this._childViewEvents; // call collectionView childViewEvent if defined\n\n    for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n      args[_key - 1] = arguments[_key];\n    }\n\n    if (childViewEvents && childViewEvents[eventName]) {\n      childViewEvents[eventName].apply(this, args);\n    } // use the parent view's proxyEvent handlers\n\n\n    var childViewTriggers = this._childViewTriggers; // Call the event with the proxy name on the parent layout\n\n    if (childViewTriggers && childViewTriggers[eventName]) {\n      this.triggerMethod.apply(this, [childViewTriggers[eventName]].concat(args));\n    }\n\n    if (this._eventPrefix) {\n      this.triggerMethod.apply(this, [this._eventPrefix + eventName].concat(args));\n    }\n  }\n};\n\n_.extend(ViewMixin, BehaviorsMixin, CommonMixin, DelegateEntityEventsMixin, TemplateRenderMixin, TriggersMixin, UIMixin);\n\nfunction renderView(view) {\n  if (view._isRendered) {\n    return;\n  }\n\n  if (!view.supportsRenderLifecycle) {\n    view.triggerMethod('before:render', view);\n  }\n\n  view.render();\n  view._isRendered = true;\n\n  if (!view.supportsRenderLifecycle) {\n    view.triggerMethod('render', view);\n  }\n}\nfunction destroyView(view, disableDetachEvents) {\n  if (view.destroy) {\n    // Attach flag for public destroy function internal check\n    view._disableDetachEvents = disableDetachEvents;\n    view.destroy();\n    return;\n  } // Destroy for non-Marionette Views\n\n\n  if (!view.supportsDestroyLifecycle) {\n    view.triggerMethod('before:destroy', view);\n  }\n\n  var shouldTriggerDetach = view._isAttached && !disableDetachEvents;\n\n  if (shouldTriggerDetach) {\n    view.triggerMethod('before:detach', view);\n  }\n\n  view.remove();\n\n  if (shouldTriggerDetach) {\n    view._isAttached = false;\n    view.triggerMethod('detach', view);\n  }\n\n  view._isDestroyed = true;\n\n  if (!view.supportsDestroyLifecycle) {\n    view.triggerMethod('destroy', view);\n  }\n}\n\n// Region\nvar classErrorName = 'RegionError';\nvar ClassOptions$1 = ['allowMissingEl', 'parentEl', 'replaceElement'];\n\nvar Region = function Region(options) {\n  this._setOptions(options, ClassOptions$1);\n\n  this.cid = _.uniqueId(this.cidPrefix); // getOption necessary because options.el may be passed as undefined\n\n  this._initEl = this.el = this.getOption('el'); // Handle when this.el is passed in as a $ wrapped element.\n\n  this.el = this.el instanceof Backbone.$ ? this.el[0] : this.el;\n  this.$el = this._getEl(this.el);\n  this.initialize.apply(this, arguments);\n};\n\nRegion.extend = extend;\nRegion.setDomApi = setDomApi; // Region Methods\n// --------------\n\n_.extend(Region.prototype, CommonMixin, {\n  Dom: DomApi,\n  cidPrefix: 'mnr',\n  replaceElement: false,\n  _isReplaced: false,\n  _isSwappingView: false,\n  // This is a noop method intended to be overridden\n  initialize: function initialize() {},\n  // Displays a view instance inside of the region. If necessary handles calling the `render`\n  // method for you. Reads content directly from the `el` attribute.\n  show: function show(view, options) {\n    if (!this._ensureElement(options)) {\n      return;\n    }\n\n    view = this._getView(view, options);\n\n    if (view === this.currentView) {\n      return this;\n    }\n\n    if (view._isShown) {\n      throw new MarionetteError({\n        name: classErrorName,\n        message: 'View is already shown in a Region or CollectionView',\n        url: 'marionette.region.html#showing-a-view'\n      });\n    }\n\n    this._isSwappingView = !!this.currentView;\n    this.triggerMethod('before:show', this, view, options); // Assume an attached view is already in the region for pre-existing DOM\n\n    if (this.currentView || !view._isAttached) {\n      this.empty(options);\n    }\n\n    this._setupChildView(view);\n\n    this.currentView = view;\n    renderView(view);\n\n    this._attachView(view, options);\n\n    this.triggerMethod('show', this, view, options);\n    this._isSwappingView = false;\n    return this;\n  },\n  _getEl: function _getEl(el) {\n    if (!el) {\n      throw new MarionetteError({\n        name: classErrorName,\n        message: 'An \"el\" must be specified for a region.',\n        url: 'marionette.region.html#additional-options'\n      });\n    }\n\n    return this.getEl(el);\n  },\n  _setEl: function _setEl() {\n    this.$el = this._getEl(this.el);\n\n    if (this.$el.length) {\n      this.el = this.$el[0];\n    } // Make sure the $el contains only the el\n\n\n    if (this.$el.length > 1) {\n      this.$el = this.Dom.getEl(this.el);\n    }\n  },\n  // Set the `el` of the region and move any current view to the new `el`.\n  _setElement: function _setElement(el) {\n    if (el === this.el) {\n      return this;\n    }\n\n    var shouldReplace = this._isReplaced;\n\n    this._restoreEl();\n\n    this.el = el;\n\n    this._setEl();\n\n    if (this.currentView) {\n      var view = this.currentView;\n\n      if (shouldReplace) {\n        this._replaceEl(view);\n      } else {\n        this.attachHtml(view);\n      }\n    }\n\n    return this;\n  },\n  _setupChildView: function _setupChildView(view) {\n    monitorViewEvents(view);\n\n    this._proxyChildViewEvents(view); // We need to listen for if a view is destroyed in a way other than through the region.\n    // If this happens we need to remove the reference to the currentView since once a view\n    // has been destroyed we can not reuse it.\n\n\n    view.on('destroy', this._empty, this);\n  },\n  _proxyChildViewEvents: function _proxyChildViewEvents(view) {\n    var parentView = this._parentView;\n\n    if (!parentView) {\n      return;\n    }\n\n    parentView._proxyChildViewEvents(view);\n  },\n  // If the regions parent view is not monitoring its attach/detach events\n  _shouldDisableMonitoring: function _shouldDisableMonitoring() {\n    return this._parentView && this._parentView.monitorViewEvents === false;\n  },\n  _isElAttached: function _isElAttached() {\n    return this.Dom.hasEl(this.Dom.getDocumentEl(this.el), this.el);\n  },\n  _attachView: function _attachView(view) {\n    var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n        replaceElement = _ref.replaceElement;\n\n    var shouldTriggerAttach = !view._isAttached && this._isElAttached() && !this._shouldDisableMonitoring();\n    var shouldReplaceEl = typeof replaceElement === 'undefined' ? !!_.result(this, 'replaceElement') : !!replaceElement;\n\n    if (shouldTriggerAttach) {\n      view.triggerMethod('before:attach', view);\n    }\n\n    if (shouldReplaceEl) {\n      this._replaceEl(view);\n    } else {\n      this.attachHtml(view);\n    }\n\n    if (shouldTriggerAttach) {\n      view._isAttached = true;\n      view.triggerMethod('attach', view);\n    } // Corresponds that view is shown in a marionette Region or CollectionView\n\n\n    view._isShown = true;\n  },\n  _ensureElement: function _ensureElement() {\n    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n    if (!_.isObject(this.el)) {\n      this._setEl();\n    }\n\n    if (!this.$el || this.$el.length === 0) {\n      var allowMissingEl = typeof options.allowMissingEl === 'undefined' ? !!_.result(this, 'allowMissingEl') : !!options.allowMissingEl;\n\n      if (allowMissingEl) {\n        return false;\n      } else {\n        throw new MarionetteError({\n          name: classErrorName,\n          message: \"An \\\"el\\\" must exist in DOM for this region \".concat(this.cid),\n          url: 'marionette.region.html#additional-options'\n        });\n      }\n    }\n\n    return true;\n  },\n  _getView: function _getView(view) {\n    if (!view) {\n      throw new MarionetteError({\n        name: classErrorName,\n        message: 'The view passed is undefined and therefore invalid. You must pass a view instance to show.',\n        url: 'marionette.region.html#showing-a-view'\n      });\n    }\n\n    if (view._isDestroyed) {\n      throw new MarionetteError({\n        name: classErrorName,\n        message: \"View (cid: \\\"\".concat(view.cid, \"\\\") has already been destroyed and cannot be used.\"),\n        url: 'marionette.region.html#showing-a-view'\n      });\n    }\n\n    if (view instanceof Backbone.View) {\n      return view;\n    }\n\n    var viewOptions = this._getViewOptions(view);\n\n    return new View(viewOptions);\n  },\n  // This allows for a template or a static string to be\n  // used as a template\n  _getViewOptions: function _getViewOptions(viewOptions) {\n    if (_.isFunction(viewOptions)) {\n      return {\n        template: viewOptions\n      };\n    }\n\n    if (_.isObject(viewOptions)) {\n      return viewOptions;\n    }\n\n    var template = function template() {\n      return viewOptions;\n    };\n\n    return {\n      template: template\n    };\n  },\n  // Override this method to change how the region finds the DOM element that it manages. Return\n  // a jQuery selector object scoped to a provided parent el or the document if none exists.\n  getEl: function getEl(el) {\n    var context = _.result(this, 'parentEl');\n\n    if (context && _.isString(el)) {\n      return this.Dom.findEl(context, el);\n    }\n\n    return this.Dom.getEl(el);\n  },\n  _replaceEl: function _replaceEl(view) {\n    // Always restore the el to ensure the regions el is present before replacing\n    this._restoreEl();\n\n    view.on('before:destroy', this._restoreEl, this);\n    this.Dom.replaceEl(view.el, this.el);\n    this._isReplaced = true;\n  },\n  // Restore the region's element in the DOM.\n  _restoreEl: function _restoreEl() {\n    // There is nothing to replace\n    if (!this._isReplaced) {\n      return;\n    }\n\n    var view = this.currentView;\n\n    if (!view) {\n      return;\n    }\n\n    this._detachView(view);\n\n    this._isReplaced = false;\n  },\n  // Check to see if the region's el was replaced.\n  isReplaced: function isReplaced() {\n    return !!this._isReplaced;\n  },\n  // Check to see if a view is being swapped by another\n  isSwappingView: function isSwappingView() {\n    return !!this._isSwappingView;\n  },\n  // Override this method to change how the new view is appended to the `$el` that the\n  // region is managing\n  attachHtml: function attachHtml(view) {\n    this.Dom.appendContents(this.el, view.el, {\n      _$el: this.$el,\n      _$contents: view.$el\n    });\n  },\n  // Destroy the current view, if there is one. If there is no current view,\n  // it will detach any html inside the region's `el`.\n  empty: function empty() {\n    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {\n      allowMissingEl: true\n    };\n    var view = this.currentView; // If there is no view in the region we should only detach current html\n\n    if (!view) {\n      if (this._ensureElement(options)) {\n        this.detachHtml();\n      }\n\n      return this;\n    }\n\n    this._empty(view, true);\n\n    return this;\n  },\n  _empty: function _empty(view, shouldDestroy) {\n    view.off('destroy', this._empty, this);\n    this.triggerMethod('before:empty', this, view);\n\n    this._restoreEl();\n\n    delete this.currentView;\n\n    if (!view._isDestroyed) {\n      if (shouldDestroy) {\n        this.removeView(view);\n      } else {\n        this._detachView(view);\n      }\n\n      view._isShown = false;\n\n      this._stopChildViewEvents(view);\n    }\n\n    this.triggerMethod('empty', this, view);\n  },\n  _stopChildViewEvents: function _stopChildViewEvents(view) {\n    var parentView = this._parentView;\n\n    if (!parentView) {\n      return;\n    }\n\n    this._parentView.stopListening(view);\n  },\n  // Non-Marionette safe view.destroy\n  destroyView: function destroyView$1(view) {\n    if (view._isDestroyed) {\n      return view;\n    }\n\n    destroyView(view, this._shouldDisableMonitoring());\n\n    return view;\n  },\n  // Override this method to determine what happens when the view\n  // is removed from the region when the view is not being detached\n  removeView: function removeView(view) {\n    this.destroyView(view);\n  },\n  // Empties the Region without destroying the view\n  // Returns the detached view\n  detachView: function detachView() {\n    var view = this.currentView;\n\n    if (!view) {\n      return;\n    }\n\n    this._empty(view);\n\n    return view;\n  },\n  _detachView: function _detachView(view) {\n    var shouldTriggerDetach = view._isAttached && !this._shouldDisableMonitoring();\n    var shouldRestoreEl = this._isReplaced;\n\n    if (shouldTriggerDetach) {\n      view.triggerMethod('before:detach', view);\n    }\n\n    if (shouldRestoreEl) {\n      this.Dom.replaceEl(this.el, view.el);\n    } else {\n      this.detachHtml();\n    }\n\n    if (shouldTriggerDetach) {\n      view._isAttached = false;\n      view.triggerMethod('detach', view);\n    }\n  },\n  // Override this method to change how the region detaches current content\n  detachHtml: function detachHtml() {\n    this.Dom.detachContents(this.el, this.$el);\n  },\n  // Checks whether a view is currently present within the region. Returns `true` if there is\n  // and `false` if no view is present.\n  hasView: function hasView() {\n    return !!this.currentView;\n  },\n  // Reset the region by destroying any existing view and clearing out the cached `$el`.\n  // The next time a view is shown via this region, the region will re-query the DOM for\n  // the region's `el`.\n  reset: function reset(options) {\n    this.empty(options);\n    this.el = this._initEl;\n    delete this.$el;\n    return this;\n  },\n  _isDestroyed: false,\n  isDestroyed: function isDestroyed() {\n    return this._isDestroyed;\n  },\n  // Destroy the region, remove any child view\n  // and remove the region from any associated view\n  destroy: function destroy(options) {\n    if (this._isDestroyed) {\n      return this;\n    }\n\n    this.triggerMethod('before:destroy', this, options);\n    this._isDestroyed = true;\n    this.reset(options);\n\n    if (this._name) {\n      this._parentView._removeReferences(this._name);\n    }\n\n    delete this._parentView;\n    delete this._name;\n    this.triggerMethod('destroy', this, options);\n    this.stopListening();\n    return this;\n  }\n});\n\nfunction buildRegion (definition, defaults) {\n  if (definition instanceof Region) {\n    return definition;\n  }\n\n  if (_.isString(definition)) {\n    return buildRegionFromObject(defaults, {\n      el: definition\n    });\n  }\n\n  if (_.isFunction(definition)) {\n    return buildRegionFromObject(defaults, {\n      regionClass: definition\n    });\n  }\n\n  if (_.isObject(definition)) {\n    return buildRegionFromObject(defaults, definition);\n  }\n\n  throw new MarionetteError({\n    message: 'Improper region configuration type.',\n    url: 'marionette.region.html#defining-regions'\n  });\n}\n\nfunction buildRegionFromObject(defaults, definition) {\n  var options = _.extend({}, defaults, definition);\n\n  var RegionClass = options.regionClass;\n  delete options.regionClass;\n  return new RegionClass(options);\n}\n\n// - regions\n// - regionClass\n\nvar RegionsMixin = {\n  regionClass: Region,\n  // Internal method to initialize the regions that have been defined in a\n  // `regions` attribute on this View.\n  _initRegions: function _initRegions() {\n    // init regions hash\n    this.regions = this.regions || {};\n    this._regions = {};\n    this.addRegions(_.result(this, 'regions'));\n  },\n  // Internal method to re-initialize all of the regions by updating\n  // the `el` that they point to\n  _reInitRegions: function _reInitRegions() {\n    _invoke(this._regions, 'reset');\n  },\n  // Add a single region, by name, to the View\n  addRegion: function addRegion(name, definition) {\n    var regions = {};\n    regions[name] = definition;\n    return this.addRegions(regions)[name];\n  },\n  // Add multiple regions as a {name: definition, name2: def2} object literal\n  addRegions: function addRegions(regions) {\n    // If there's nothing to add, stop here.\n    if (_.isEmpty(regions)) {\n      return;\n    } // Normalize region selectors hash to allow\n    // a user to use the @ui. syntax.\n\n\n    regions = this.normalizeUIValues(regions, 'el'); // Add the regions definitions to the regions property\n\n    this.regions = _.extend({}, this.regions, regions);\n    return this._addRegions(regions);\n  },\n  // internal method to build and add regions\n  _addRegions: function _addRegions(regionDefinitions) {\n    var _this = this;\n\n    var defaults = {\n      regionClass: this.regionClass,\n      parentEl: _.partial(_.result, this, 'el')\n    };\n    return _.reduce(regionDefinitions, function (regions, definition, name) {\n      regions[name] = buildRegion(definition, defaults);\n\n      _this._addRegion(regions[name], name);\n\n      return regions;\n    }, {});\n  },\n  _addRegion: function _addRegion(region, name) {\n    this.triggerMethod('before:add:region', this, name, region);\n    region._parentView = this;\n    region._name = name;\n    this._regions[name] = region;\n    this.triggerMethod('add:region', this, name, region);\n  },\n  // Remove a single region from the View, by name\n  removeRegion: function removeRegion(name) {\n    var region = this._regions[name];\n\n    this._removeRegion(region, name);\n\n    return region;\n  },\n  // Remove all regions from the View\n  removeRegions: function removeRegions() {\n    var regions = this._getRegions();\n\n    _.each(this._regions, this._removeRegion.bind(this));\n\n    return regions;\n  },\n  _removeRegion: function _removeRegion(region, name) {\n    this.triggerMethod('before:remove:region', this, name, region);\n    region.destroy();\n    this.triggerMethod('remove:region', this, name, region);\n  },\n  // Called in a region's destroy\n  _removeReferences: function _removeReferences(name) {\n    delete this.regions[name];\n    delete this._regions[name];\n  },\n  // Empty all regions in the region manager, but\n  // leave them attached\n  emptyRegions: function emptyRegions() {\n    var regions = this.getRegions();\n\n    _invoke(regions, 'empty');\n\n    return regions;\n  },\n  // Checks to see if view contains region\n  // Accepts the region name\n  // hasRegion('main')\n  hasRegion: function hasRegion(name) {\n    return !!this.getRegion(name);\n  },\n  // Provides access to regions\n  // Accepts the region name\n  // getRegion('main')\n  getRegion: function getRegion(name) {\n    if (!this._isRendered) {\n      this.render();\n    }\n\n    return this._regions[name];\n  },\n  _getRegions: function _getRegions() {\n    return _.clone(this._regions);\n  },\n  // Get all regions\n  getRegions: function getRegions() {\n    if (!this._isRendered) {\n      this.render();\n    }\n\n    return this._getRegions();\n  },\n  showChildView: function showChildView(name, view, options) {\n    var region = this.getRegion(name);\n    region.show(view, options);\n    return view;\n  },\n  detachChildView: function detachChildView(name) {\n    return this.getRegion(name).detachView();\n  },\n  getChildView: function getChildView(name) {\n    return this.getRegion(name).currentView;\n  }\n};\n\n// Static setter for the renderer\nfunction setRenderer(renderer) {\n  this.prototype._renderHtml = renderer;\n  return this;\n}\n\n// View\nvar ClassOptions$2 = ['behaviors', 'childViewEventPrefix', 'childViewEvents', 'childViewTriggers', 'collectionEvents', 'events', 'modelEvents', 'regionClass', 'regions', 'template', 'templateContext', 'triggers', 'ui']; // Used by _getImmediateChildren\n\nfunction childReducer(children, region) {\n  if (region.currentView) {\n    children.push(region.currentView);\n  }\n\n  return children;\n} // The standard view. Includes view events, automatic rendering\n// templates, nested views, and more.\n\n\nvar View = Backbone.View.extend({\n  constructor: function constructor(options) {\n    this._setOptions(options, ClassOptions$2);\n\n    monitorViewEvents(this);\n\n    this._initBehaviors();\n\n    this._initRegions();\n\n    Backbone.View.prototype.constructor.apply(this, arguments);\n    this.delegateEntityEvents();\n\n    this._triggerEventOnBehaviors('initialize', this, options);\n  },\n  // Overriding Backbone.View's `setElement` to handle\n  // if an el was previously defined. If so, the view might be\n  // rendered or attached on setElement.\n  setElement: function setElement() {\n    Backbone.View.prototype.setElement.apply(this, arguments);\n    this._isRendered = this.Dom.hasContents(this.el);\n    this._isAttached = this._isElAttached();\n\n    if (this._isRendered) {\n      this.bindUIElements();\n    }\n\n    return this;\n  },\n  // If a template is available, renders it into the view's `el`\n  // Re-inits regions and binds UI.\n  render: function render() {\n    var template = this.getTemplate();\n\n    if (template === false || this._isDestroyed) {\n      return this;\n    }\n\n    this.triggerMethod('before:render', this); // If this is not the first render call, then we need to\n    // re-initialize the `el` for each region\n\n    if (this._isRendered) {\n      this._reInitRegions();\n    }\n\n    this._renderTemplate(template);\n\n    this.bindUIElements();\n    this._isRendered = true;\n    this.triggerMethod('render', this);\n    return this;\n  },\n  // called by ViewMixin destroy\n  _removeChildren: function _removeChildren() {\n    this.removeRegions();\n  },\n  _getImmediateChildren: function _getImmediateChildren() {\n    return _.reduce(this._regions, childReducer, []);\n  }\n}, {\n  setRenderer: setRenderer,\n  setDomApi: setDomApi\n});\n\n_.extend(View.prototype, ViewMixin, RegionsMixin);\n\n// shut down child views.\n\nvar Container = function Container() {\n  this._init();\n}; // Mix in methods from Underscore, for iteration, and other\n// collection related features.\n// Borrowing this code from Backbone.Collection:\n// https://github.com/jashkenas/backbone/blob/1.1.2/backbone.js#L962\n\n\nvar methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter', 'select', 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke', 'toArray', 'first', 'initial', 'rest', 'last', 'without', 'isEmpty', 'pluck', 'reduce', 'partition'];\n\n_.each(methods, function (method) {\n  Container.prototype[method] = function () {\n    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n      args[_key] = arguments[_key];\n    }\n\n    return _[method].apply(_, [this._views].concat(args));\n  };\n});\n\nfunction stringComparator(comparator, view) {\n  return view.model && view.model.get(comparator);\n} // Container Methods\n// -----------------\n\n\n_.extend(Container.prototype, {\n  // Initializes an empty container\n  _init: function _init() {\n    this._views = [];\n    this._viewsByCid = {};\n    this._indexByModel = {};\n\n    this._updateLength();\n  },\n  // Add a view to this container. Stores the view\n  // by `cid` and makes it searchable by the model\n  // cid (and model itself). Additionally it stores\n  // the view by index in the _views array\n  _add: function _add(view) {\n    var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this._views.length;\n\n    this._addViewIndexes(view); // add to end by default\n\n\n    this._views.splice(index, 0, view);\n\n    this._updateLength();\n  },\n  _addViewIndexes: function _addViewIndexes(view) {\n    // store the view\n    this._viewsByCid[view.cid] = view; // index it by model\n\n    if (view.model) {\n      this._indexByModel[view.model.cid] = view;\n    }\n  },\n  // Sort (mutate) and return the array of the child views.\n  _sort: function _sort(comparator, context) {\n    if (typeof comparator === 'string') {\n      comparator = _.partial(stringComparator, comparator);\n      return this._sortBy(comparator);\n    }\n\n    if (comparator.length === 1) {\n      return this._sortBy(comparator.bind(context));\n    }\n\n    return this._views.sort(comparator.bind(context));\n  },\n  // Makes `_.sortBy` mutate the array to match `this._views.sort`\n  _sortBy: function _sortBy(comparator) {\n    var sortedViews = _.sortBy(this._views, comparator);\n\n    this._set(sortedViews);\n\n    return sortedViews;\n  },\n  // Replace array contents without overwriting the reference.\n  // Should not add/remove views\n  _set: function _set(views, shouldReset) {\n    this._views.length = 0;\n\n    this._views.push.apply(this._views, views.slice(0));\n\n    if (shouldReset) {\n      this._viewsByCid = {};\n      this._indexByModel = {};\n\n      _.each(views, this._addViewIndexes.bind(this));\n\n      this._updateLength();\n    }\n  },\n  // Swap views by index\n  _swap: function _swap(view1, view2) {\n    var view1Index = this.findIndexByView(view1);\n    var view2Index = this.findIndexByView(view2);\n\n    if (view1Index === -1 || view2Index === -1) {\n      return;\n    }\n\n    var swapView = this._views[view1Index];\n    this._views[view1Index] = this._views[view2Index];\n    this._views[view2Index] = swapView;\n  },\n  // Find a view by the model that was attached to it.\n  // Uses the model's `cid` to find it.\n  findByModel: function findByModel(model) {\n    return this.findByModelCid(model.cid);\n  },\n  // Find a view by the `cid` of the model that was attached to it.\n  findByModelCid: function findByModelCid(modelCid) {\n    return this._indexByModel[modelCid];\n  },\n  // Find a view by index.\n  findByIndex: function findByIndex(index) {\n    return this._views[index];\n  },\n  // Find the index of a view instance\n  findIndexByView: function findIndexByView(view) {\n    return this._views.indexOf(view);\n  },\n  // Retrieve a view by its `cid` directly\n  findByCid: function findByCid(cid) {\n    return this._viewsByCid[cid];\n  },\n  hasView: function hasView(view) {\n    return !!this.findByCid(view.cid);\n  },\n  // Remove a view and clean up index references.\n  _remove: function _remove(view) {\n    if (!this._viewsByCid[view.cid]) {\n      return;\n    } // delete model index\n\n\n    if (view.model) {\n      delete this._indexByModel[view.model.cid];\n    } // remove the view from the container\n\n\n    delete this._viewsByCid[view.cid];\n    var index = this.findIndexByView(view);\n\n    this._views.splice(index, 1);\n\n    this._updateLength();\n  },\n  // Update the `.length` attribute on this container\n  _updateLength: function _updateLength() {\n    this.length = this._views.length;\n  }\n});\n\n// Collection View\nvar classErrorName$1 = 'CollectionViewError';\nvar ClassOptions$3 = ['behaviors', 'childView', 'childViewContainer', 'childViewEventPrefix', 'childViewEvents', 'childViewOptions', 'childViewTriggers', 'collectionEvents', 'emptyView', 'emptyViewOptions', 'events', 'modelEvents', 'sortWithCollection', 'template', 'templateContext', 'triggers', 'ui', 'viewComparator', 'viewFilter']; // A view that iterates over a Backbone.Collection\n// and renders an individual child view for each model.\n\nvar CollectionView = Backbone.View.extend({\n  // flag for maintaining the sorted order of the collection\n  sortWithCollection: true,\n  // constructor\n  constructor: function constructor(options) {\n    this._setOptions(options, ClassOptions$3);\n\n    monitorViewEvents(this);\n\n    this._initChildViewStorage();\n\n    this._initBehaviors();\n\n    Backbone.View.prototype.constructor.apply(this, arguments); // Init empty region\n\n    this.getEmptyRegion();\n    this.delegateEntityEvents();\n\n    this._triggerEventOnBehaviors('initialize', this, options);\n  },\n  // Internal method to set up the `children` object for storing all of the child views\n  // `_children` represents all child views\n  // `children` represents only views filtered to be shown\n  _initChildViewStorage: function _initChildViewStorage() {\n    this._children = new Container();\n    this.children = new Container();\n  },\n  // Create an region to show the emptyView\n  getEmptyRegion: function getEmptyRegion() {\n    var $emptyEl = this.$container || this.$el;\n\n    if (this._emptyRegion && !this._emptyRegion.isDestroyed()) {\n      this._emptyRegion._setElement($emptyEl[0]);\n\n      return this._emptyRegion;\n    }\n\n    this._emptyRegion = new Region({\n      el: $emptyEl[0],\n      replaceElement: false\n    });\n    this._emptyRegion._parentView = this;\n    return this._emptyRegion;\n  },\n  // Configured the initial events that the collection view binds to.\n  _initialEvents: function _initialEvents() {\n    if (this._isRendered) {\n      return;\n    }\n\n    this.listenTo(this.collection, {\n      'sort': this._onCollectionSort,\n      'reset': this._onCollectionReset,\n      'update': this._onCollectionUpdate\n    });\n  },\n  // Internal method. This checks for any changes in the order of the collection.\n  // If the index of any view doesn't match, it will re-sort.\n  _onCollectionSort: function _onCollectionSort(collection, _ref) {\n    var add = _ref.add,\n        merge = _ref.merge,\n        remove = _ref.remove;\n\n    if (!this.sortWithCollection || this.viewComparator === false) {\n      return;\n    } // If the data is changing we will handle the sort later in `_onCollectionUpdate`\n\n\n    if (add || remove || merge) {\n      return;\n    } // If the only thing happening here is sorting, sort.\n\n\n    this.sort();\n  },\n  _onCollectionReset: function _onCollectionReset() {\n    this._destroyChildren();\n\n    this._addChildModels(this.collection.models);\n\n    this.sort();\n  },\n  // Handle collection update model additions and  removals\n  _onCollectionUpdate: function _onCollectionUpdate(collection, options) {\n    var changes = options.changes; // Remove first since it'll be a shorter array lookup.\n\n    var removedViews = changes.removed.length && this._removeChildModels(changes.removed);\n\n    this._addedViews = changes.added.length && this._addChildModels(changes.added);\n\n    this._detachChildren(removedViews);\n\n    this.sort(); // Destroy removed child views after all of the render is complete\n\n    this._removeChildViews(removedViews);\n  },\n  _removeChildModels: function _removeChildModels(models) {\n    var _this = this;\n\n    return _.reduce(models, function (views, model) {\n      var removeView = _this._removeChildModel(model);\n\n      if (removeView) {\n        views.push(removeView);\n      }\n\n      return views;\n    }, []);\n  },\n  _removeChildModel: function _removeChildModel(model) {\n    var view = this._children.findByModel(model);\n\n    if (view) {\n      this._removeChild(view);\n    }\n\n    return view;\n  },\n  _removeChild: function _removeChild(view) {\n    this.triggerMethod('before:remove:child', this, view);\n\n    this.children._remove(view);\n\n    this._children._remove(view);\n\n    this.triggerMethod('remove:child', this, view);\n  },\n  // Added views are returned for consistency with _removeChildModels\n  _addChildModels: function _addChildModels(models) {\n    return _.map(models, this._addChildModel.bind(this));\n  },\n  _addChildModel: function _addChildModel(model) {\n    var view = this._createChildView(model);\n\n    this._addChild(view);\n\n    return view;\n  },\n  _createChildView: function _createChildView(model) {\n    var ChildView = this._getChildView(model);\n\n    var childViewOptions = this._getChildViewOptions(model);\n\n    var view = this.buildChildView(model, ChildView, childViewOptions);\n    return view;\n  },\n  _addChild: function _addChild(view, index) {\n    this.triggerMethod('before:add:child', this, view);\n\n    this._setupChildView(view);\n\n    this._children._add(view, index);\n\n    this.children._add(view, index);\n\n    this.triggerMethod('add:child', this, view);\n  },\n  // Retrieve the `childView` class\n  // The `childView` property can be either a view class or a function that\n  // returns a view class. If it is a function, it will receive the model that\n  // will be passed to the view instance (created from the returned view class)\n  _getChildView: function _getChildView(child) {\n    var childView = this.childView;\n\n    if (!childView) {\n      throw new MarionetteError({\n        name: classErrorName$1,\n        message: 'A \"childView\" must be specified',\n        url: 'marionette.collectionview.html#collectionviews-childview'\n      });\n    }\n\n    childView = this._getView(childView, child);\n\n    if (!childView) {\n      throw new MarionetteError({\n        name: classErrorName$1,\n        message: '\"childView\" must be a view class or a function that returns a view class',\n        url: 'marionette.collectionview.html#collectionviews-childview'\n      });\n    }\n\n    return childView;\n  },\n  // First check if the `view` is a view class (the common case)\n  // Then check if it's a function (which we assume that returns a view class)\n  _getView: function _getView(view, child) {\n    if (view.prototype instanceof Backbone.View || view === Backbone.View) {\n      return view;\n    } else if (_.isFunction(view)) {\n      return view.call(this, child);\n    }\n  },\n  _getChildViewOptions: function _getChildViewOptions(child) {\n    if (_.isFunction(this.childViewOptions)) {\n      return this.childViewOptions(child);\n    }\n\n    return this.childViewOptions;\n  },\n  // Build a `childView` for a model in the collection.\n  // Override to customize the build\n  buildChildView: function buildChildView(child, ChildViewClass, childViewOptions) {\n    var options = _.extend({\n      model: child\n    }, childViewOptions);\n\n    return new ChildViewClass(options);\n  },\n  _setupChildView: function _setupChildView(view) {\n    monitorViewEvents(view); // We need to listen for if a view is destroyed in a way other\n    // than through the CollectionView.\n    // If this happens we need to remove the reference to the view\n    // since once a view has been destroyed we can not reuse it.\n\n    view.on('destroy', this.removeChildView, this); // set up the child view event forwarding\n\n    this._proxyChildViewEvents(view);\n  },\n  // used by ViewMixin's `_childViewEventHandler`\n  _getImmediateChildren: function _getImmediateChildren() {\n    return this.children._views;\n  },\n  // Overriding Backbone.View's `setElement` to handle\n  // if an el was previously defined. If so, the view might be\n  // attached on setElement.\n  setElement: function setElement() {\n    Backbone.View.prototype.setElement.apply(this, arguments);\n    this._isAttached = this._isElAttached();\n    return this;\n  },\n  // Render children views.\n  render: function render() {\n    if (this._isDestroyed) {\n      return this;\n    }\n\n    this.triggerMethod('before:render', this);\n\n    this._destroyChildren();\n\n    if (this.collection) {\n      this._addChildModels(this.collection.models);\n\n      this._initialEvents();\n    }\n\n    var template = this.getTemplate();\n\n    if (template) {\n      this._renderTemplate(template);\n\n      this.bindUIElements();\n    }\n\n    this._getChildViewContainer();\n\n    this.sort();\n    this._isRendered = true;\n    this.triggerMethod('render', this);\n    return this;\n  },\n  // Get a container within the template to add the children within\n  _getChildViewContainer: function _getChildViewContainer() {\n    var childViewContainer = _.result(this, 'childViewContainer');\n\n    this.$container = childViewContainer ? this.$(childViewContainer) : this.$el;\n\n    if (!this.$container.length) {\n      throw new MarionetteError({\n        name: classErrorName$1,\n        message: \"The specified \\\"childViewContainer\\\" was not found: \".concat(childViewContainer),\n        url: 'marionette.collectionview.html#defining-the-childviewcontainer'\n      });\n    }\n  },\n  // Sorts the children then filters and renders the results.\n  sort: function sort() {\n    this._sortChildren();\n\n    this.filter();\n    return this;\n  },\n  // Sorts views by viewComparator and sets the children to the new order\n  _sortChildren: function _sortChildren() {\n    if (!this._children.length) {\n      return;\n    }\n\n    var viewComparator = this.getComparator();\n\n    if (!viewComparator) {\n      return;\n    } // If children are sorted prevent added to end perf\n\n\n    delete this._addedViews;\n    this.triggerMethod('before:sort', this);\n\n    this._children._sort(viewComparator, this);\n\n    this.triggerMethod('sort', this);\n  },\n  // Sets the view's `viewComparator` and applies the sort if the view is ready.\n  // To prevent the render pass `{ preventRender: true }` as the 2nd argument.\n  setComparator: function setComparator(comparator) {\n    var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n        preventRender = _ref2.preventRender;\n\n    var comparatorChanged = this.viewComparator !== comparator;\n    var shouldSort = comparatorChanged && !preventRender;\n    this.viewComparator = comparator;\n\n    if (shouldSort) {\n      this.sort();\n    }\n\n    return this;\n  },\n  // Clears the `viewComparator` and follows the same rules for rendering as `setComparator`.\n  removeComparator: function removeComparator(options) {\n    return this.setComparator(null, options);\n  },\n  // If viewComparator is overridden it will be returned here.\n  // Additionally override this function to provide custom\n  // viewComparator logic\n  getComparator: function getComparator() {\n    if (this.viewComparator) {\n      return this.viewComparator;\n    }\n\n    if (!this.sortWithCollection || this.viewComparator === false || !this.collection) {\n      return false;\n    }\n\n    return this._viewComparator;\n  },\n  // Default internal view comparator that order the views by\n  // the order of the collection\n  _viewComparator: function _viewComparator(view) {\n    return this.collection.indexOf(view.model);\n  },\n  // This method filters the children views and renders the results\n  filter: function filter() {\n    if (this._isDestroyed) {\n      return this;\n    }\n\n    this._filterChildren();\n\n    this._renderChildren();\n\n    return this;\n  },\n  _filterChildren: function _filterChildren() {\n    var _this2 = this;\n\n    if (!this._children.length) {\n      return;\n    }\n\n    var viewFilter = this._getFilter();\n\n    if (!viewFilter) {\n      var shouldReset = this.children.length !== this._children.length;\n\n      this.children._set(this._children._views, shouldReset);\n\n      return;\n    } // If children are filtered prevent added to end perf\n\n\n    delete this._addedViews;\n    this.triggerMethod('before:filter', this);\n    var attachViews = [];\n    var detachViews = [];\n\n    _.each(this._children._views, function (view, key, children) {\n      (viewFilter.call(_this2, view, key, children) ? attachViews : detachViews).push(view);\n    });\n\n    this._detachChildren(detachViews); // reset children\n\n\n    this.children._set(attachViews, true);\n\n    this.triggerMethod('filter', this, attachViews, detachViews);\n  },\n  // This method returns a function for the viewFilter\n  _getFilter: function _getFilter() {\n    var viewFilter = this.getFilter();\n\n    if (!viewFilter) {\n      return false;\n    }\n\n    if (_.isFunction(viewFilter)) {\n      return viewFilter;\n    } // Support filter predicates `{ fooFlag: true }`\n\n\n    if (_.isObject(viewFilter)) {\n      var matcher = _.matches(viewFilter);\n\n      return function (view) {\n        return matcher(view.model && view.model.attributes);\n      };\n    } // Filter by model attribute\n\n\n    if (_.isString(viewFilter)) {\n      return function (view) {\n        return view.model && view.model.get(viewFilter);\n      };\n    }\n\n    throw new MarionetteError({\n      name: classErrorName$1,\n      message: '\"viewFilter\" must be a function, predicate object literal, a string indicating a model attribute, or falsy',\n      url: 'marionette.collectionview.html#defining-the-viewfilter'\n    });\n  },\n  // Override this function to provide custom\n  // viewFilter logic\n  getFilter: function getFilter() {\n    return this.viewFilter;\n  },\n  // Sets the view's `viewFilter` and applies the filter if the view is ready.\n  // To prevent the render pass `{ preventRender: true }` as the 2nd argument.\n  setFilter: function setFilter(filter) {\n    var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n        preventRender = _ref3.preventRender;\n\n    var filterChanged = this.viewFilter !== filter;\n    var shouldRender = filterChanged && !preventRender;\n    this.viewFilter = filter;\n\n    if (shouldRender) {\n      this.filter();\n    }\n\n    return this;\n  },\n  // Clears the `viewFilter` and follows the same rules for rendering as `setFilter`.\n  removeFilter: function removeFilter(options) {\n    return this.setFilter(null, options);\n  },\n  _detachChildren: function _detachChildren(detachingViews) {\n    _.each(detachingViews, this._detachChildView.bind(this));\n  },\n  _detachChildView: function _detachChildView(view) {\n    var shouldTriggerDetach = view._isAttached && this.monitorViewEvents !== false;\n\n    if (shouldTriggerDetach) {\n      view.triggerMethod('before:detach', view);\n    }\n\n    this.detachHtml(view);\n\n    if (shouldTriggerDetach) {\n      view._isAttached = false;\n      view.triggerMethod('detach', view);\n    }\n\n    view._isShown = false;\n  },\n  // Override this method to change how the collectionView detaches a child view\n  detachHtml: function detachHtml(view) {\n    this.Dom.detachEl(view.el, view.$el);\n  },\n  _renderChildren: function _renderChildren() {\n    // If there are unrendered views prevent add to end perf\n    if (this._hasUnrenderedViews) {\n      delete this._addedViews;\n      delete this._hasUnrenderedViews;\n    }\n\n    var views = this._addedViews || this.children._views;\n    this.triggerMethod('before:render:children', this, views);\n\n    if (this.isEmpty()) {\n      this._showEmptyView();\n    } else {\n      this._destroyEmptyView();\n\n      var els = this._getBuffer(views);\n\n      this._attachChildren(els, views);\n    }\n\n    delete this._addedViews;\n    this.triggerMethod('render:children', this, views);\n  },\n  // Renders each view and creates a fragment buffer from them\n  _getBuffer: function _getBuffer(views) {\n    var _this3 = this;\n\n    var elBuffer = this.Dom.createBuffer();\n\n    _.each(views, function (view) {\n      renderView(view); // corresponds that view is shown in a Region or CollectionView\n\n      view._isShown = true;\n\n      _this3.Dom.appendContents(elBuffer, view.el, {\n        _$contents: view.$el\n      });\n    });\n\n    return elBuffer;\n  },\n  _attachChildren: function _attachChildren(els, views) {\n    var shouldTriggerAttach = this._isAttached && this.monitorViewEvents !== false;\n    views = shouldTriggerAttach ? views : [];\n\n    _.each(views, function (view) {\n      if (view._isAttached) {\n        return;\n      }\n\n      view.triggerMethod('before:attach', view);\n    });\n\n    this.attachHtml(els, this.$container);\n\n    _.each(views, function (view) {\n      if (view._isAttached) {\n        return;\n      }\n\n      view._isAttached = true;\n      view.triggerMethod('attach', view);\n    });\n  },\n  // Override this method to do something other than `.append`.\n  // You can attach any HTML at this point including the els.\n  attachHtml: function attachHtml(els, $container) {\n    this.Dom.appendContents($container[0], els, {\n      _$el: $container\n    });\n  },\n  isEmpty: function isEmpty() {\n    return !this.children.length;\n  },\n  _showEmptyView: function _showEmptyView() {\n    var EmptyView = this._getEmptyView();\n\n    if (!EmptyView) {\n      return;\n    }\n\n    var options = this._getEmptyViewOptions();\n\n    var emptyRegion = this.getEmptyRegion();\n    emptyRegion.show(new EmptyView(options));\n  },\n  // Retrieve the empty view class\n  _getEmptyView: function _getEmptyView() {\n    var emptyView = this.emptyView;\n\n    if (!emptyView) {\n      return;\n    }\n\n    return this._getView(emptyView);\n  },\n  // Remove the emptyView\n  _destroyEmptyView: function _destroyEmptyView() {\n    var emptyRegion = this.getEmptyRegion(); // Only empty if a view is show so the region\n    // doesn't detach any other unrelated HTML\n\n    if (emptyRegion.hasView()) {\n      emptyRegion.empty();\n    }\n  },\n  //\n  _getEmptyViewOptions: function _getEmptyViewOptions() {\n    var emptyViewOptions = this.emptyViewOptions || this.childViewOptions;\n\n    if (_.isFunction(emptyViewOptions)) {\n      return emptyViewOptions.call(this);\n    }\n\n    return emptyViewOptions;\n  },\n  swapChildViews: function swapChildViews(view1, view2) {\n    if (!this._children.hasView(view1) || !this._children.hasView(view2)) {\n      throw new MarionetteError({\n        name: classErrorName$1,\n        message: 'Both views must be children of the collection view to swap.',\n        url: 'marionette.collectionview.html#swapping-child-views'\n      });\n    }\n\n    this._children._swap(view1, view2);\n\n    this.Dom.swapEl(view1.el, view2.el); // If the views are not filtered the same, refilter\n\n    if (this.children.hasView(view1) !== this.children.hasView(view2)) {\n      this.filter();\n    } else {\n      this.children._swap(view1, view2);\n    }\n\n    return this;\n  },\n  // Render the child's view and add it to the HTML for the collection view at a given index, based on the current sort\n  addChildView: function addChildView(view, index) {\n    var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n    if (!view || view._isDestroyed) {\n      return view;\n    }\n\n    if (view._isShown) {\n      throw new MarionetteError({\n        name: classErrorName$1,\n        message: 'View is already shown in a Region or CollectionView',\n        url: 'marionette.region.html#showing-a-view'\n      });\n    }\n\n    if (_.isObject(index)) {\n      options = index;\n    } // If options has defined index we should use it\n\n\n    if (options.index != null) {\n      index = options.index;\n    }\n\n    if (!this._isRendered) {\n      this.render();\n    }\n\n    this._addChild(view, index);\n\n    if (options.preventRender) {\n      this._hasUnrenderedViews = true;\n      return view;\n    }\n\n    var hasIndex = typeof index !== 'undefined';\n    var isAddedToEnd = !hasIndex || index >= this._children.length; // Only cache views if added to the end and there is no unrendered views\n\n    if (isAddedToEnd && !this._hasUnrenderedViews) {\n      this._addedViews = [view];\n    }\n\n    if (hasIndex) {\n      this._renderChildren();\n    } else {\n      this.sort();\n    }\n\n    return view;\n  },\n  // Detach a view from the children.  Best used when adding a\n  // childView from `addChildView`\n  detachChildView: function detachChildView(view) {\n    this.removeChildView(view, {\n      shouldDetach: true\n    });\n    return view;\n  },\n  // Remove the child view and destroy it.  Best used when adding a\n  // childView from `addChildView`\n  // The options argument is for internal use only\n  removeChildView: function removeChildView(view, options) {\n    if (!view) {\n      return view;\n    }\n\n    this._removeChildView(view, options);\n\n    this._removeChild(view);\n\n    if (this.isEmpty()) {\n      this._showEmptyView();\n    }\n\n    return view;\n  },\n  _removeChildViews: function _removeChildViews(views) {\n    _.each(views, this._removeChildView.bind(this));\n  },\n  _removeChildView: function _removeChildView(view) {\n    var _ref4 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n        shouldDetach = _ref4.shouldDetach;\n\n    view.off('destroy', this.removeChildView, this);\n\n    if (shouldDetach) {\n      this._detachChildView(view);\n    } else {\n      this._destroyChildView(view);\n    }\n\n    this.stopListening(view);\n  },\n  _destroyChildView: function _destroyChildView(view) {\n    if (view._isDestroyed) {\n      return;\n    }\n\n    var shouldDisableEvents = this.monitorViewEvents === false;\n    destroyView(view, shouldDisableEvents);\n  },\n  // called by ViewMixin destroy\n  _removeChildren: function _removeChildren() {\n    this._destroyChildren();\n\n    var emptyRegion = this.getEmptyRegion();\n    emptyRegion.destroy();\n    delete this._addedViews;\n  },\n  // Destroy the child views that this collection view is holding on to, if any\n  _destroyChildren: function _destroyChildren() {\n    if (!this._children.length) {\n      return;\n    }\n\n    this.triggerMethod('before:destroy:children', this);\n\n    if (this.monitorViewEvents === false) {\n      this.Dom.detachContents(this.el, this.$el);\n    }\n\n    this._removeChildViews(this._children._views); // After all children have been destroyed re-init the container\n\n\n    this._children._init();\n\n    this.children._init();\n\n    this.triggerMethod('destroy:children', this);\n  }\n}, {\n  setDomApi: setDomApi,\n  setRenderer: setRenderer\n});\n\n_.extend(CollectionView.prototype, ViewMixin);\n\n// Behavior\nvar ClassOptions$4 = ['collectionEvents', 'events', 'modelEvents', 'triggers', 'ui'];\n\nvar Behavior = function Behavior(options, view) {\n  // Setup reference to the view.\n  // this comes in handle when a behavior\n  // wants to directly talk up the chain\n  // to the view.\n  this.view = view;\n\n  this._setOptions(options, ClassOptions$4);\n\n  this.cid = _.uniqueId(this.cidPrefix); // Construct an internal UI hash using the behaviors UI\n  // hash combined and overridden by the view UI hash.\n  // This allows the user to use UI hash elements defined\n  // in the parent view as well as those defined in the behavior.\n  // This order will help the reuse and share of a behavior\n  // between multiple views, while letting a view override\n  // a selector under an UI key.\n\n  this.ui = _.extend({}, _.result(this, 'ui'), _.result(view, 'ui')); // Proxy view triggers\n\n  this.listenTo(view, 'all', this.triggerMethod);\n  this.initialize.apply(this, arguments);\n};\n\nBehavior.extend = extend; // Behavior Methods\n// --------------\n\n_.extend(Behavior.prototype, CommonMixin, DelegateEntityEventsMixin, TriggersMixin, UIMixin, {\n  cidPrefix: 'mnb',\n  // This is a noop method intended to be overridden\n  initialize: function initialize() {},\n  // proxy behavior $ method to the view\n  // this is useful for doing jquery DOM lookups\n  // scoped to behaviors view.\n  $: function $() {\n    return this.view.$.apply(this.view, arguments);\n  },\n  // Stops the behavior from listening to events.\n  destroy: function destroy() {\n    this.stopListening();\n\n    this.view._removeBehavior(this);\n\n    this._deleteEntityEventHandlers();\n\n    return this;\n  },\n  proxyViewProperties: function proxyViewProperties() {\n    this.$el = this.view.$el;\n    this.el = this.view.el;\n    return this;\n  },\n  bindUIElements: function bindUIElements() {\n    this._bindUIElements();\n\n    return this;\n  },\n  unbindUIElements: function unbindUIElements() {\n    this._unbindUIElements();\n\n    return this;\n  },\n  getUI: function getUI(name) {\n    return this._getUI(name);\n  },\n  // Handle `modelEvents`, and `collectionEvents` configuration\n  delegateEntityEvents: function delegateEntityEvents() {\n    this._delegateEntityEvents(this.view.model, this.view.collection);\n\n    return this;\n  },\n  undelegateEntityEvents: function undelegateEntityEvents() {\n    this._undelegateEntityEvents(this.view.model, this.view.collection);\n\n    return this;\n  },\n  _getEvents: function _getEvents() {\n    var _this = this;\n\n    if (!this.events) {\n      return;\n    } // Normalize behavior events hash to allow\n    // a user to use the @ui. syntax.\n\n\n    var behaviorEvents = this.normalizeUIKeys(_.result(this, 'events')); // binds the handler to the behavior and builds a unique eventName\n\n    return _.reduce(behaviorEvents, function (events, behaviorHandler, key) {\n      if (!_.isFunction(behaviorHandler)) {\n        behaviorHandler = _this[behaviorHandler];\n      }\n\n      if (!behaviorHandler) {\n        return events;\n      }\n\n      key = getNamespacedEventName(key, _this.cid);\n      events[key] = behaviorHandler.bind(_this);\n      return events;\n    }, {});\n  },\n  // Internal method to build all trigger handlers for a given behavior\n  _getTriggers: function _getTriggers() {\n    if (!this.triggers) {\n      return;\n    } // Normalize behavior triggers hash to allow\n    // a user to use the @ui. syntax.\n\n\n    var behaviorTriggers = this.normalizeUIKeys(_.result(this, 'triggers'));\n    return this._getViewTriggers(this.view, behaviorTriggers);\n  }\n});\n\n// Application\nvar ClassOptions$5 = ['channelName', 'radioEvents', 'radioRequests', 'region', 'regionClass'];\n\nvar Application = function Application(options) {\n  this._setOptions(options, ClassOptions$5);\n\n  this.cid = _.uniqueId(this.cidPrefix);\n\n  this._initRegion();\n\n  this._initRadio();\n\n  this.initialize.apply(this, arguments);\n};\n\nApplication.extend = extend; // Application Methods\n// --------------\n\n_.extend(Application.prototype, CommonMixin, DestroyMixin, RadioMixin, {\n  cidPrefix: 'mna',\n  // This is a noop method intended to be overridden\n  initialize: function initialize() {},\n  // Kick off all of the application's processes.\n  start: function start(options) {\n    this.triggerMethod('before:start', this, options);\n    this.triggerMethod('start', this, options);\n    return this;\n  },\n  regionClass: Region,\n  _initRegion: function _initRegion() {\n    var region = this.region;\n\n    if (!region) {\n      return;\n    }\n\n    var defaults = {\n      regionClass: this.regionClass\n    };\n    this._region = buildRegion(region, defaults);\n  },\n  getRegion: function getRegion() {\n    return this._region;\n  },\n  showView: function showView(view) {\n    var region = this.getRegion();\n\n    for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n      args[_key - 1] = arguments[_key];\n    }\n\n    region.show.apply(region, [view].concat(args));\n    return view;\n  },\n  getView: function getView() {\n    return this.getRegion().currentView;\n  }\n});\n\nvar bindEvents$1 = proxy(bindEvents);\nvar unbindEvents$1 = proxy(unbindEvents);\nvar bindRequests$1 = proxy(bindRequests);\nvar unbindRequests$1 = proxy(unbindRequests);\nvar mergeOptions$1 = proxy(mergeOptions);\nvar getOption$1 = proxy(getOption);\nvar normalizeMethods$1 = proxy(normalizeMethods);\nvar triggerMethod$1 = proxy(triggerMethod); // Configuration\n\nvar setDomApi$1 = function setDomApi(mixin) {\n  CollectionView.setDomApi(mixin);\n  Region.setDomApi(mixin);\n  View.setDomApi(mixin);\n};\nvar setRenderer$1 = function setRenderer(renderer) {\n  CollectionView.setRenderer(renderer);\n  View.setRenderer(renderer);\n};\nvar backbone_marionette = {\n  View: View,\n  CollectionView: CollectionView,\n  MnObject: MarionetteObject,\n  Object: MarionetteObject,\n  Region: Region,\n  Behavior: Behavior,\n  Application: Application,\n  isEnabled: isEnabled,\n  setEnabled: setEnabled,\n  monitorViewEvents: monitorViewEvents,\n  Events: Events,\n  extend: extend,\n  DomApi: DomApi,\n  VERSION: version\n};\n\nexport default backbone_marionette;\nexport { Application, Behavior, CollectionView, DomApi, Events, MarionetteObject as MnObject, Region, version as VERSION, View, bindEvents$1 as bindEvents, bindRequests$1 as bindRequests, extend, getOption$1 as getOption, isEnabled, mergeOptions$1 as mergeOptions, monitorViewEvents, normalizeMethods$1 as normalizeMethods, setDomApi$1 as setDomApi, setEnabled, setRenderer$1 as setRenderer, triggerMethod$1 as triggerMethod, unbindEvents$1 as unbindEvents, unbindRequests$1 as unbindRequests };\n"
  },
  {
    "path": "lib/backbone.marionette.js",
    "content": "/**\n* @license\n* MarionetteJS (Backbone.Marionette)\n* ----------------------------------\n* v4.1.3\n*\n* Copyright (c)2020 Derick Bailey, Muted Solutions, LLC.\n* Distributed under MIT license\n*\n* http://marionettejs.com\n*/\n\n\n(function (global, factory) {\n  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('backbone'), require('underscore'), require('backbone.radio')) :\n  typeof define === 'function' && define.amd ? define(['exports', 'backbone', 'underscore', 'backbone.radio'], factory) :\n  (global = global || self, (function () {\n    var current = global.Marionette;\n    var exports = global.Marionette = {};\n    factory(exports, global.Backbone, global._, global.Backbone.Radio);\n    exports.noConflict = function () { global.Marionette = current; return exports; };\n  }()));\n}(this, function (exports, Backbone, _, Radio) { 'use strict';\n\n  Backbone = Backbone && Backbone.hasOwnProperty('default') ? Backbone['default'] : Backbone;\n  _ = _ && _.hasOwnProperty('default') ? _['default'] : _;\n  Radio = Radio && Radio.hasOwnProperty('default') ? Radio['default'] : Radio;\n\n  var version = \"4.1.3\";\n\n  //Internal utility for creating context style global utils\n  var proxy = function proxy(method) {\n    return function (context) {\n      for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n        args[_key - 1] = arguments[_key];\n      }\n\n      return method.apply(context, args);\n    };\n  };\n\n  // Marionette.extend\n\n  var extend = Backbone.Model.extend;\n\n  // ----------------------\n  // Pass in a mapping of events => functions or function names\n  // and return a mapping of events => functions\n\n  var normalizeMethods = function normalizeMethods(hash) {\n    var _this = this;\n\n    if (!hash) {\n      return;\n    }\n\n    return _.reduce(hash, function (normalizedHash, method, name) {\n      if (!_.isFunction(method)) {\n        method = _this[method];\n      }\n\n      if (method) {\n        normalizedHash[name] = method;\n      }\n\n      return normalizedHash;\n    }, {});\n  };\n\n  // Error\n  var errorProps = ['description', 'fileName', 'lineNumber', 'name', 'message', 'number', 'url'];\n  var MarionetteError = extend.call(Error, {\n    urlRoot: \"http://marionettejs.com/docs/v\".concat(version, \"/\"),\n    url: '',\n    constructor: function constructor(options) {\n      var error = Error.call(this, options.message);\n\n      _.extend(this, _.pick(error, errorProps), _.pick(options, errorProps));\n\n      if (Error.captureStackTrace) {\n        this.captureStackTrace();\n      }\n\n      this.url = this.urlRoot + this.url;\n    },\n    captureStackTrace: function captureStackTrace() {\n      Error.captureStackTrace(this, MarionetteError);\n    },\n    toString: function toString() {\n      return \"\".concat(this.name, \": \").concat(this.message, \" See: \").concat(this.url);\n    }\n  });\n\n  // Bind Entity Events & Unbind Entity Events\n\n  function normalizeBindings(context, bindings) {\n    if (!_.isObject(bindings)) {\n      throw new MarionetteError({\n        message: 'Bindings must be an object.',\n        url: 'common.html#bindevents'\n      });\n    }\n\n    return normalizeMethods.call(context, bindings);\n  }\n\n  function bindEvents(entity, bindings) {\n    if (!entity || !bindings) {\n      return this;\n    }\n\n    this.listenTo(entity, normalizeBindings(this, bindings));\n    return this;\n  }\n\n  function unbindEvents(entity, bindings) {\n    if (!entity) {\n      return this;\n    }\n\n    if (!bindings) {\n      this.stopListening(entity);\n      return this;\n    }\n\n    this.stopListening(entity, normalizeBindings(this, bindings));\n    return this;\n  } // Export Public API\n\n  // Bind/Unbind Radio Requests\n\n  function normalizeBindings$1(context, bindings) {\n    if (!_.isObject(bindings)) {\n      throw new MarionetteError({\n        message: 'Bindings must be an object.',\n        url: 'common.html#bindrequests'\n      });\n    }\n\n    return normalizeMethods.call(context, bindings);\n  }\n\n  function bindRequests(channel, bindings) {\n    if (!channel || !bindings) {\n      return this;\n    }\n\n    channel.reply(normalizeBindings$1(this, bindings), this);\n    return this;\n  }\n\n  function unbindRequests(channel, bindings) {\n    if (!channel) {\n      return this;\n    }\n\n    if (!bindings) {\n      channel.stopReplying(null, null, this);\n      return this;\n    }\n\n    channel.stopReplying(normalizeBindings$1(this, bindings), this);\n    return this;\n  }\n\n  // Marionette.getOption\n  // --------------------\n  // Retrieve an object, function or other value from the\n  // object or its `options`, with `options` taking precedence.\n  var getOption = function getOption(optionName) {\n    if (!optionName) {\n      return;\n    }\n\n    if (this.options && this.options[optionName] !== undefined) {\n      return this.options[optionName];\n    } else {\n      return this[optionName];\n    }\n  };\n\n  var mergeOptions = function mergeOptions(options, keys) {\n    var _this = this;\n\n    if (!options) {\n      return;\n    }\n\n    _.each(keys, function (key) {\n      var option = options[key];\n\n      if (option !== undefined) {\n        _this[key] = option;\n      }\n    });\n  };\n\n  // DOM Refresh\n\n  function triggerMethodChildren(view, event, shouldTrigger) {\n    if (!view._getImmediateChildren) {\n      return;\n    }\n\n    _.each(view._getImmediateChildren(), function (child) {\n      if (!shouldTrigger(child)) {\n        return;\n      }\n\n      child.triggerMethod(event, child);\n    });\n  }\n\n  function shouldTriggerAttach(view) {\n    return !view._isAttached;\n  }\n\n  function shouldAttach(view) {\n    if (!shouldTriggerAttach(view)) {\n      return false;\n    }\n\n    view._isAttached = true;\n    return true;\n  }\n\n  function shouldTriggerDetach(view) {\n    return view._isAttached;\n  }\n\n  function shouldDetach(view) {\n    view._isAttached = false;\n    return true;\n  }\n\n  function triggerDOMRefresh(view) {\n    if (view._isAttached && view._isRendered) {\n      view.triggerMethod('dom:refresh', view);\n    }\n  }\n\n  function triggerDOMRemove(view) {\n    if (view._isAttached && view._isRendered) {\n      view.triggerMethod('dom:remove', view);\n    }\n  }\n\n  function handleBeforeAttach() {\n    triggerMethodChildren(this, 'before:attach', shouldTriggerAttach);\n  }\n\n  function handleAttach() {\n    triggerMethodChildren(this, 'attach', shouldAttach);\n    triggerDOMRefresh(this);\n  }\n\n  function handleBeforeDetach() {\n    triggerMethodChildren(this, 'before:detach', shouldTriggerDetach);\n    triggerDOMRemove(this);\n  }\n\n  function handleDetach() {\n    triggerMethodChildren(this, 'detach', shouldDetach);\n  }\n\n  function handleBeforeRender() {\n    triggerDOMRemove(this);\n  }\n\n  function handleRender() {\n    triggerDOMRefresh(this);\n  } // Monitor a view's state, propagating attach/detach events to children and firing dom:refresh\n  // whenever a rendered view is attached or an attached view is rendered.\n\n\n  function monitorViewEvents(view) {\n    if (view._areViewEventsMonitored || view.monitorViewEvents === false) {\n      return;\n    }\n\n    view._areViewEventsMonitored = true;\n    view.on({\n      'before:attach': handleBeforeAttach,\n      'attach': handleAttach,\n      'before:detach': handleBeforeDetach,\n      'detach': handleDetach,\n      'before:render': handleBeforeRender,\n      'render': handleRender\n    });\n  }\n\n  // Trigger Method\n\n  var splitter = /(^|:)(\\w)/gi; // Only calc getOnMethodName once\n\n  var methodCache = {}; // take the event section (\"section1:section2:section3\")\n  // and turn it in to uppercase name onSection1Section2Section3\n\n  function getEventName(match, prefix, eventName) {\n    return eventName.toUpperCase();\n  }\n\n  var getOnMethodName = function getOnMethodName(event) {\n    if (!methodCache[event]) {\n      methodCache[event] = 'on' + event.replace(splitter, getEventName);\n    }\n\n    return methodCache[event];\n  }; // Trigger an event and/or a corresponding method name. Examples:\n  //\n  // `this.triggerMethod(\"foo\")` will trigger the \"foo\" event and\n  // call the \"onFoo\" method.\n  //\n  // `this.triggerMethod(\"foo:bar\")` will trigger the \"foo:bar\" event and\n  // call the \"onFooBar\" method.\n\n\n  function triggerMethod(event) {\n    // get the method name from the event name\n    var methodName = getOnMethodName(event);\n    var method = getOption.call(this, methodName);\n    var result; // call the onMethodName if it exists\n\n    if (_.isFunction(method)) {\n      // pass all args, except the event name\n      result = method.apply(this, _.drop(arguments));\n    } // trigger the event\n\n\n    this.trigger.apply(this, arguments);\n    return result;\n  }\n\n  var Events = {\n    triggerMethod: triggerMethod\n  };\n\n  var CommonMixin = {\n    // Imports the \"normalizeMethods\" to transform hashes of\n    // events=>function references/names to a hash of events=>function references\n    normalizeMethods: normalizeMethods,\n    _setOptions: function _setOptions(options, classOptions) {\n      this.options = _.extend({}, _.result(this, 'options'), options);\n      this.mergeOptions(options, classOptions);\n    },\n    // A handy way to merge passed-in options onto the instance\n    mergeOptions: mergeOptions,\n    // Enable getting options from this or this.options by name.\n    getOption: getOption,\n    // Enable binding view's events from another entity.\n    bindEvents: bindEvents,\n    // Enable unbinding view's events from another entity.\n    unbindEvents: unbindEvents,\n    // Enable binding view's requests.\n    bindRequests: bindRequests,\n    // Enable unbinding view's requests.\n    unbindRequests: unbindRequests,\n    triggerMethod: triggerMethod\n  };\n\n  _.extend(CommonMixin, Backbone.Events);\n\n  var DestroyMixin = {\n    _isDestroyed: false,\n    isDestroyed: function isDestroyed() {\n      return this._isDestroyed;\n    },\n    destroy: function destroy(options) {\n      if (this._isDestroyed) {\n        return this;\n      }\n\n      this.triggerMethod('before:destroy', this, options);\n      this._isDestroyed = true;\n      this.triggerMethod('destroy', this, options);\n      this.stopListening();\n      return this;\n    }\n  };\n\n  // - channelName\n  // - radioEvents\n  // - radioRequests\n\n  var RadioMixin = {\n    _initRadio: function _initRadio() {\n      var channelName = _.result(this, 'channelName');\n\n      if (!channelName) {\n        return;\n      }\n      /* istanbul ignore next */\n\n\n      if (!Radio) {\n        throw new MarionetteError({\n          message: 'The dependency \"backbone.radio\" is missing.',\n          url: 'backbone.radio.html#marionette-integration'\n        });\n      }\n\n      var channel = this._channel = Radio.channel(channelName);\n\n      var radioEvents = _.result(this, 'radioEvents');\n\n      this.bindEvents(channel, radioEvents);\n\n      var radioRequests = _.result(this, 'radioRequests');\n\n      this.bindRequests(channel, radioRequests);\n      this.on('destroy', this._destroyRadio);\n    },\n    _destroyRadio: function _destroyRadio() {\n      this._channel.stopReplying(null, null, this);\n    },\n    getChannel: function getChannel() {\n      return this._channel;\n    }\n  };\n\n  // Object\n  var ClassOptions = ['channelName', 'radioEvents', 'radioRequests']; // Object borrows many conventions and utilities from Backbone.\n\n  var MarionetteObject = function MarionetteObject(options) {\n    this._setOptions(options, ClassOptions);\n\n    this.cid = _.uniqueId(this.cidPrefix);\n\n    this._initRadio();\n\n    this.initialize.apply(this, arguments);\n  };\n\n  MarionetteObject.extend = extend; // Object Methods\n  // --------------\n\n  _.extend(MarionetteObject.prototype, CommonMixin, DestroyMixin, RadioMixin, {\n    cidPrefix: 'mno',\n    // This is a noop method intended to be overridden\n    initialize: function initialize() {}\n  });\n\n  // Implementation of the invoke method (http://underscorejs.org/#invoke) with support for\n  var _invoke = _.invokeMap || _.invoke;\n\n  // - behaviors\n  // Takes care of getting the behavior class\n  // given options and a key.\n  // If a user passes in options.behaviorClass\n  // default to using that.\n  // If a user passes in a Behavior Class directly, use that\n  // Otherwise an error is thrown\n\n  function getBehaviorClass(options) {\n    if (options.behaviorClass) {\n      return {\n        BehaviorClass: options.behaviorClass,\n        options: options\n      };\n    } //treat functions as a Behavior constructor\n\n\n    if (_.isFunction(options)) {\n      return {\n        BehaviorClass: options,\n        options: {}\n      };\n    }\n\n    throw new MarionetteError({\n      message: 'Unable to get behavior class. A Behavior constructor should be passed directly or as behaviorClass property of options',\n      url: 'marionette.behavior.html#defining-and-attaching-behaviors'\n    });\n  } // Iterate over the behaviors object, for each behavior\n  // instantiate it and get its grouped behaviors.\n  // This accepts a list of behaviors in either an object or array form\n\n\n  function parseBehaviors(view, behaviors, allBehaviors) {\n    return _.reduce(behaviors, function (reducedBehaviors, behaviorDefiniton) {\n      var _getBehaviorClass = getBehaviorClass(behaviorDefiniton),\n          BehaviorClass = _getBehaviorClass.BehaviorClass,\n          options = _getBehaviorClass.options;\n\n      var behavior = new BehaviorClass(options, view);\n      reducedBehaviors.push(behavior);\n      return parseBehaviors(view, _.result(behavior, 'behaviors'), reducedBehaviors);\n    }, allBehaviors);\n  }\n\n  var BehaviorsMixin = {\n    _initBehaviors: function _initBehaviors() {\n      this._behaviors = parseBehaviors(this, _.result(this, 'behaviors'), []);\n    },\n    _getBehaviorTriggers: function _getBehaviorTriggers() {\n      var triggers = _invoke(this._behaviors, '_getTriggers');\n\n      return _.reduce(triggers, function (memo, _triggers) {\n        return _.extend(memo, _triggers);\n      }, {});\n    },\n    _getBehaviorEvents: function _getBehaviorEvents() {\n      var events = _invoke(this._behaviors, '_getEvents');\n\n      return _.reduce(events, function (memo, _events) {\n        return _.extend(memo, _events);\n      }, {});\n    },\n    // proxy behavior $el to the view's $el.\n    _proxyBehaviorViewProperties: function _proxyBehaviorViewProperties() {\n      _invoke(this._behaviors, 'proxyViewProperties');\n    },\n    // delegate modelEvents and collectionEvents\n    _delegateBehaviorEntityEvents: function _delegateBehaviorEntityEvents() {\n      _invoke(this._behaviors, 'delegateEntityEvents');\n    },\n    // undelegate modelEvents and collectionEvents\n    _undelegateBehaviorEntityEvents: function _undelegateBehaviorEntityEvents() {\n      _invoke(this._behaviors, 'undelegateEntityEvents');\n    },\n    _destroyBehaviors: function _destroyBehaviors(options) {\n      // Call destroy on each behavior after\n      // destroying the view.\n      // This unbinds event listeners\n      // that behaviors have registered for.\n      _invoke(this._behaviors, 'destroy', options);\n    },\n    // Remove a behavior\n    _removeBehavior: function _removeBehavior(behavior) {\n      // Don't worry about the clean up if the view is destroyed\n      if (this._isDestroyed) {\n        return;\n      } // Remove behavior-only triggers and events\n\n\n      this.undelegate(\".trig\".concat(behavior.cid, \" .\").concat(behavior.cid));\n      this._behaviors = _.without(this._behaviors, behavior);\n    },\n    _bindBehaviorUIElements: function _bindBehaviorUIElements() {\n      _invoke(this._behaviors, 'bindUIElements');\n    },\n    _unbindBehaviorUIElements: function _unbindBehaviorUIElements() {\n      _invoke(this._behaviors, 'unbindUIElements');\n    },\n    _triggerEventOnBehaviors: function _triggerEventOnBehaviors(eventName, view, options) {\n      _invoke(this._behaviors, 'triggerMethod', eventName, view, options);\n    }\n  };\n\n  // - collectionEvents\n  // - modelEvents\n\n  var DelegateEntityEventsMixin = {\n    // Handle `modelEvents`, and `collectionEvents` configuration\n    _delegateEntityEvents: function _delegateEntityEvents(model, collection) {\n      if (model) {\n        this._modelEvents = _.result(this, 'modelEvents');\n        this.bindEvents(model, this._modelEvents);\n      }\n\n      if (collection) {\n        this._collectionEvents = _.result(this, 'collectionEvents');\n        this.bindEvents(collection, this._collectionEvents);\n      }\n    },\n    // Remove any previously delegate entity events\n    _undelegateEntityEvents: function _undelegateEntityEvents(model, collection) {\n      if (this._modelEvents) {\n        this.unbindEvents(model, this._modelEvents);\n        delete this._modelEvents;\n      }\n\n      if (this._collectionEvents) {\n        this.unbindEvents(collection, this._collectionEvents);\n        delete this._collectionEvents;\n      }\n    },\n    // Remove cached event handlers\n    _deleteEntityEventHandlers: function _deleteEntityEventHandlers() {\n      delete this._modelEvents;\n      delete this._collectionEvents;\n    }\n  };\n\n  // - template\n  // - templateContext\n\n  var TemplateRenderMixin = {\n    // Internal method to render the template with the serialized data\n    // and template context\n    _renderTemplate: function _renderTemplate(template) {\n      // Add in entity data and template context\n      var data = this.mixinTemplateContext(this.serializeData()) || {}; // Render and add to el\n\n      var html = this._renderHtml(template, data);\n\n      if (typeof html !== 'undefined') {\n        this.attachElContent(html);\n      }\n    },\n    // Get the template for this view instance.\n    // You can set a `template` attribute in the view definition\n    // or pass a `template: TemplateFunction` parameter in\n    // to the constructor options.\n    getTemplate: function getTemplate() {\n      return this.template;\n    },\n    // Mix in template context methods. Looks for a\n    // `templateContext` attribute, which can either be an\n    // object literal, or a function that returns an object\n    // literal. All methods and attributes from this object\n    // are copies to the object passed in.\n    mixinTemplateContext: function mixinTemplateContext(serializedData) {\n      var templateContext = _.result(this, 'templateContext');\n\n      if (!templateContext) {\n        return serializedData;\n      }\n\n      if (!serializedData) {\n        return templateContext;\n      }\n\n      return _.extend({}, serializedData, templateContext);\n    },\n    // Serialize the view's model *or* collection, if\n    // it exists, for the template\n    serializeData: function serializeData() {\n      // If we have a model, we serialize that\n      if (this.model) {\n        return this.serializeModel();\n      } // Otherwise, we serialize the collection,\n      // making it available under the `items` property\n\n\n      if (this.collection) {\n        return {\n          items: this.serializeCollection()\n        };\n      }\n    },\n    // Prepares the special `model` property of a view\n    // for being displayed in the template. Override this if\n    // you need a custom transformation for your view's model\n    serializeModel: function serializeModel() {\n      return this.model.attributes;\n    },\n    // Serialize a collection\n    serializeCollection: function serializeCollection() {\n      return _.map(this.collection.models, function (model) {\n        return model.attributes;\n      });\n    },\n    // Renders the data into the template\n    _renderHtml: function _renderHtml(template, data) {\n      return template(data);\n    },\n    // Attaches the content of a given view.\n    // This method can be overridden to optimize rendering,\n    // or to render in a non standard way.\n    //\n    // For example, using `innerHTML` instead of `$el.html`\n    //\n    // ```js\n    // attachElContent(html) {\n    //   this.el.innerHTML = html;\n    // }\n    // ```\n    attachElContent: function attachElContent(html) {\n      this.Dom.setContents(this.el, html, this.$el);\n    }\n  };\n\n  // Borrow event splitter from Backbone\n  var delegateEventSplitter = /^(\\S+)\\s*(.*)$/; // Set event name to be namespaced using a unique index\n  // to generate a non colliding event namespace\n  // http://api.jquery.com/event.namespace/\n\n  var getNamespacedEventName = function getNamespacedEventName(eventName, namespace) {\n    var match = eventName.match(delegateEventSplitter);\n    return \"\".concat(match[1], \".\").concat(namespace, \" \").concat(match[2]);\n  };\n\n  // Add Feature flags here\n  // e.g. 'class' => false\n  var FEATURES = {\n    childViewEventPrefix: false,\n    triggersStopPropagation: true,\n    triggersPreventDefault: true,\n    DEV_MODE: false\n  };\n\n  function isEnabled(name) {\n    return !!FEATURES[name];\n  }\n\n  function setEnabled(name, state) {\n    return FEATURES[name] = state;\n  }\n\n  // 'click:foo'\n\n  function buildViewTrigger(view, triggerDef) {\n    if (_.isString(triggerDef)) {\n      triggerDef = {\n        event: triggerDef\n      };\n    }\n\n    var eventName = triggerDef.event;\n    var shouldPreventDefault = !!triggerDef.preventDefault;\n\n    if (isEnabled('triggersPreventDefault')) {\n      shouldPreventDefault = triggerDef.preventDefault !== false;\n    }\n\n    var shouldStopPropagation = !!triggerDef.stopPropagation;\n\n    if (isEnabled('triggersStopPropagation')) {\n      shouldStopPropagation = triggerDef.stopPropagation !== false;\n    }\n\n    return function (event) {\n      if (shouldPreventDefault) {\n        event.preventDefault();\n      }\n\n      if (shouldStopPropagation) {\n        event.stopPropagation();\n      }\n\n      for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n        args[_key - 1] = arguments[_key];\n      }\n\n      view.triggerMethod.apply(view, [eventName, view, event].concat(args));\n    };\n  }\n\n  var TriggersMixin = {\n    // Configure `triggers` to forward DOM events to view\n    // events. `triggers: {\"click .foo\": \"do:foo\"}`\n    _getViewTriggers: function _getViewTriggers(view, triggers) {\n      var _this = this;\n\n      // Configure the triggers, prevent default\n      // action and stop propagation of DOM events\n      return _.reduce(triggers, function (events, value, key) {\n        key = getNamespacedEventName(key, \"trig\".concat(_this.cid));\n        events[key] = buildViewTrigger(view, value);\n        return events;\n      }, {});\n    }\n  };\n\n  // a given key for triggers and events\n  // swaps the @ui with the associated selector.\n  // Returns a new, non-mutated, parsed events hash.\n\n  var _normalizeUIKeys = function normalizeUIKeys(hash, ui) {\n    return _.reduce(hash, function (memo, val, key) {\n      var normalizedKey = _normalizeUIString(key, ui);\n\n      memo[normalizedKey] = val;\n      return memo;\n    }, {});\n  };\n\n  var uiRegEx = /@ui\\.[a-zA-Z-_$0-9]*/g; // utility method for parsing @ui. syntax strings\n  // into associated selector\n\n  var _normalizeUIString = function normalizeUIString(uiString, ui) {\n    return uiString.replace(uiRegEx, function (r) {\n      return ui[r.slice(4)];\n    });\n  }; // allows for the use of the @ui. syntax within\n  // a given value for regions\n  // swaps the @ui with the associated selector\n\n\n  var _normalizeUIValues = function normalizeUIValues(hash, ui, property) {\n    _.each(hash, function (val, key) {\n      if (_.isString(val)) {\n        hash[key] = _normalizeUIString(val, ui);\n      } else if (val) {\n        var propertyVal = val[property];\n\n        if (_.isString(propertyVal)) {\n          val[property] = _normalizeUIString(propertyVal, ui);\n        }\n      }\n    });\n\n    return hash;\n  };\n\n  var UIMixin = {\n    // normalize the keys of passed hash with the views `ui` selectors.\n    // `{\"@ui.foo\": \"bar\"}`\n    normalizeUIKeys: function normalizeUIKeys(hash) {\n      var uiBindings = this._getUIBindings();\n\n      return _normalizeUIKeys(hash, uiBindings);\n    },\n    // normalize the passed string with the views `ui` selectors.\n    // `\"@ui.bar\"`\n    normalizeUIString: function normalizeUIString(uiString) {\n      var uiBindings = this._getUIBindings();\n\n      return _normalizeUIString(uiString, uiBindings);\n    },\n    // normalize the values of passed hash with the views `ui` selectors.\n    // `{foo: \"@ui.bar\"}`\n    normalizeUIValues: function normalizeUIValues(hash, property) {\n      var uiBindings = this._getUIBindings();\n\n      return _normalizeUIValues(hash, uiBindings, property);\n    },\n    _getUIBindings: function _getUIBindings() {\n      var uiBindings = _.result(this, '_uiBindings');\n\n      return uiBindings || _.result(this, 'ui');\n    },\n    // This method binds the elements specified in the \"ui\" hash inside the view's code with\n    // the associated jQuery selectors.\n    _bindUIElements: function _bindUIElements() {\n      var _this = this;\n\n      if (!this.ui) {\n        return;\n      } // store the ui hash in _uiBindings so they can be reset later\n      // and so re-rendering the view will be able to find the bindings\n\n\n      if (!this._uiBindings) {\n        this._uiBindings = this.ui;\n      } // get the bindings result, as a function or otherwise\n\n\n      var bindings = _.result(this, '_uiBindings'); // empty the ui so we don't have anything to start with\n\n\n      this._ui = {}; // bind each of the selectors\n\n      _.each(bindings, function (selector, key) {\n        _this._ui[key] = _this.$(selector);\n      });\n\n      this.ui = this._ui;\n    },\n    _unbindUIElements: function _unbindUIElements() {\n      var _this2 = this;\n\n      if (!this.ui || !this._uiBindings) {\n        return;\n      } // delete all of the existing ui bindings\n\n\n      _.each(this.ui, function ($el, name) {\n        delete _this2.ui[name];\n      }); // reset the ui element to the original bindings configuration\n\n\n      this.ui = this._uiBindings;\n      delete this._uiBindings;\n      delete this._ui;\n    },\n    _getUI: function _getUI(name) {\n      return this._ui[name];\n    }\n  };\n\n  // DomApi\n\n  function _getEl(el) {\n    return el instanceof Backbone.$ ? el : Backbone.$(el);\n  } // Static setter\n\n\n  function setDomApi(mixin) {\n    this.prototype.Dom = _.extend({}, this.prototype.Dom, mixin);\n    return this;\n  }\n  var DomApi = {\n    // Returns a new HTML DOM node instance\n    createBuffer: function createBuffer() {\n      return document.createDocumentFragment();\n    },\n    // Returns the document element for a given DOM element\n    getDocumentEl: function getDocumentEl(el) {\n      return el.ownerDocument.documentElement;\n    },\n    // Lookup the `selector` string\n    // Selector may also be a DOM element\n    // Returns an array-like object of nodes\n    getEl: function getEl(selector) {\n      return _getEl(selector);\n    },\n    // Finds the `selector` string with the el\n    // Returns an array-like object of nodes\n    findEl: function findEl(el, selector) {\n      return _getEl(el).find(selector);\n    },\n    // Returns true if the el contains the node childEl\n    hasEl: function hasEl(el, childEl) {\n      return el.contains(childEl && childEl.parentNode);\n    },\n    // Detach `el` from the DOM without removing listeners\n    detachEl: function detachEl(el) {\n      var _$el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _getEl(el);\n\n      _$el.detach();\n    },\n    // Remove `oldEl` from the DOM and put `newEl` in its place\n    replaceEl: function replaceEl(newEl, oldEl) {\n      if (newEl === oldEl) {\n        return;\n      }\n\n      var parent = oldEl.parentNode;\n\n      if (!parent) {\n        return;\n      }\n\n      parent.replaceChild(newEl, oldEl);\n    },\n    // Swaps the location of `el1` and `el2` in the DOM\n    swapEl: function swapEl(el1, el2) {\n      if (el1 === el2) {\n        return;\n      }\n\n      var parent1 = el1.parentNode;\n      var parent2 = el2.parentNode;\n\n      if (!parent1 || !parent2) {\n        return;\n      }\n\n      var next1 = el1.nextSibling;\n      var next2 = el2.nextSibling;\n      parent1.insertBefore(el2, next1);\n      parent2.insertBefore(el1, next2);\n    },\n    // Replace the contents of `el` with the HTML string of `html`\n    setContents: function setContents(el, html) {\n      var _$el = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _getEl(el);\n\n      _$el.html(html);\n    },\n    // Takes the DOM node `el` and appends the DOM node `contents`\n    // to the end of the element's contents.\n    appendContents: function appendContents(el, contents) {\n      var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},\n          _ref$_$el = _ref._$el,\n          _$el = _ref$_$el === void 0 ? _getEl(el) : _ref$_$el,\n          _ref$_$contents = _ref._$contents,\n          _$contents = _ref$_$contents === void 0 ? _getEl(contents) : _ref$_$contents;\n\n      _$el.append(_$contents);\n    },\n    // Does the el have child nodes\n    hasContents: function hasContents(el) {\n      return !!el && el.hasChildNodes();\n    },\n    // Remove the inner contents of `el` from the DOM while leaving\n    // `el` itself in the DOM.\n    detachContents: function detachContents(el) {\n      var _$el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _getEl(el);\n\n      _$el.contents().detach();\n    }\n  };\n\n  // ViewMixin\n  // - behaviors\n  // - childViewEventPrefix\n  // - childViewEvents\n  // - childViewTriggers\n  // - collectionEvents\n  // - modelEvents\n  // - triggers\n  // - ui\n\n  var ViewMixin = {\n    Dom: DomApi,\n    _isElAttached: function _isElAttached() {\n      return !!this.el && this.Dom.hasEl(this.Dom.getDocumentEl(this.el), this.el);\n    },\n    supportsRenderLifecycle: true,\n    supportsDestroyLifecycle: true,\n    _isDestroyed: false,\n    isDestroyed: function isDestroyed() {\n      return !!this._isDestroyed;\n    },\n    _isRendered: false,\n    isRendered: function isRendered() {\n      return !!this._isRendered;\n    },\n    _isAttached: false,\n    isAttached: function isAttached() {\n      return !!this._isAttached;\n    },\n    // Overriding Backbone.View's `delegateEvents` to handle\n    // `events` and `triggers`\n    delegateEvents: function delegateEvents(events) {\n      this._proxyBehaviorViewProperties();\n\n      this._buildEventProxies();\n\n      var combinedEvents = _.extend({}, this._getBehaviorEvents(), this._getEvents(events), this._getBehaviorTriggers(), this._getTriggers());\n\n      Backbone.View.prototype.delegateEvents.call(this, combinedEvents);\n      return this;\n    },\n    // Allows Backbone.View events to utilize `@ui.` selectors\n    _getEvents: function _getEvents(events) {\n      if (events) {\n        return this.normalizeUIKeys(events);\n      }\n\n      if (!this.events) {\n        return;\n      }\n\n      return this.normalizeUIKeys(_.result(this, 'events'));\n    },\n    // Configure `triggers` to forward DOM events to view\n    // events. `triggers: {\"click .foo\": \"do:foo\"}`\n    _getTriggers: function _getTriggers() {\n      if (!this.triggers) {\n        return;\n      } // Allow `triggers` to be configured as a function\n\n\n      var triggers = this.normalizeUIKeys(_.result(this, 'triggers')); // Configure the triggers, prevent default\n      // action and stop propagation of DOM events\n\n      return this._getViewTriggers(this, triggers);\n    },\n    // Handle `modelEvents`, and `collectionEvents` configuration\n    delegateEntityEvents: function delegateEntityEvents() {\n      this._delegateEntityEvents(this.model, this.collection); // bind each behaviors model and collection events\n\n\n      this._delegateBehaviorEntityEvents();\n\n      return this;\n    },\n    // Handle unbinding `modelEvents`, and `collectionEvents` configuration\n    undelegateEntityEvents: function undelegateEntityEvents() {\n      this._undelegateEntityEvents(this.model, this.collection); // unbind each behaviors model and collection events\n\n\n      this._undelegateBehaviorEntityEvents();\n\n      return this;\n    },\n    // Handle destroying the view and its children.\n    destroy: function destroy(options) {\n      if (this._isDestroyed || this._isDestroying) {\n        return this;\n      }\n\n      this._isDestroying = true;\n      var shouldTriggerDetach = this._isAttached && !this._disableDetachEvents;\n      this.triggerMethod('before:destroy', this, options);\n\n      if (shouldTriggerDetach) {\n        this.triggerMethod('before:detach', this);\n      } // unbind UI elements\n\n\n      this.unbindUIElements(); // remove the view from the DOM\n\n      this._removeElement();\n\n      if (shouldTriggerDetach) {\n        this._isAttached = false;\n        this.triggerMethod('detach', this);\n      } // remove children after the remove to prevent extra paints\n\n\n      this._removeChildren();\n\n      this._isDestroyed = true;\n      this._isRendered = false; // Destroy behaviors after _isDestroyed flag\n\n      this._destroyBehaviors(options);\n\n      this._deleteEntityEventHandlers();\n\n      this.triggerMethod('destroy', this, options);\n\n      this._triggerEventOnBehaviors('destroy', this, options);\n\n      this.stopListening();\n      return this;\n    },\n    // Equates to this.$el.remove\n    _removeElement: function _removeElement() {\n      this.$el.off().removeData();\n      this.Dom.detachEl(this.el, this.$el);\n    },\n    // This method binds the elements specified in the \"ui\" hash\n    bindUIElements: function bindUIElements() {\n      this._bindUIElements();\n\n      this._bindBehaviorUIElements();\n\n      return this;\n    },\n    // This method unbinds the elements specified in the \"ui\" hash\n    unbindUIElements: function unbindUIElements() {\n      this._unbindUIElements();\n\n      this._unbindBehaviorUIElements();\n\n      return this;\n    },\n    getUI: function getUI(name) {\n      return this._getUI(name);\n    },\n    // Cache `childViewEvents` and `childViewTriggers`\n    _buildEventProxies: function _buildEventProxies() {\n      this._childViewEvents = this.normalizeMethods(_.result(this, 'childViewEvents'));\n      this._childViewTriggers = _.result(this, 'childViewTriggers');\n      this._eventPrefix = this._getEventPrefix();\n    },\n    _getEventPrefix: function _getEventPrefix() {\n      var defaultPrefix = isEnabled('childViewEventPrefix') ? 'childview' : false;\n\n      var prefix = _.result(this, 'childViewEventPrefix', defaultPrefix);\n\n      return prefix === false ? prefix : prefix + ':';\n    },\n    _proxyChildViewEvents: function _proxyChildViewEvents(view) {\n      if (this._childViewEvents || this._childViewTriggers || this._eventPrefix) {\n        this.listenTo(view, 'all', this._childViewEventHandler);\n      }\n    },\n    _childViewEventHandler: function _childViewEventHandler(eventName) {\n      var childViewEvents = this._childViewEvents; // call collectionView childViewEvent if defined\n\n      for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n        args[_key - 1] = arguments[_key];\n      }\n\n      if (childViewEvents && childViewEvents[eventName]) {\n        childViewEvents[eventName].apply(this, args);\n      } // use the parent view's proxyEvent handlers\n\n\n      var childViewTriggers = this._childViewTriggers; // Call the event with the proxy name on the parent layout\n\n      if (childViewTriggers && childViewTriggers[eventName]) {\n        this.triggerMethod.apply(this, [childViewTriggers[eventName]].concat(args));\n      }\n\n      if (this._eventPrefix) {\n        this.triggerMethod.apply(this, [this._eventPrefix + eventName].concat(args));\n      }\n    }\n  };\n\n  _.extend(ViewMixin, BehaviorsMixin, CommonMixin, DelegateEntityEventsMixin, TemplateRenderMixin, TriggersMixin, UIMixin);\n\n  function renderView(view) {\n    if (view._isRendered) {\n      return;\n    }\n\n    if (!view.supportsRenderLifecycle) {\n      view.triggerMethod('before:render', view);\n    }\n\n    view.render();\n    view._isRendered = true;\n\n    if (!view.supportsRenderLifecycle) {\n      view.triggerMethod('render', view);\n    }\n  }\n  function destroyView(view, disableDetachEvents) {\n    if (view.destroy) {\n      // Attach flag for public destroy function internal check\n      view._disableDetachEvents = disableDetachEvents;\n      view.destroy();\n      return;\n    } // Destroy for non-Marionette Views\n\n\n    if (!view.supportsDestroyLifecycle) {\n      view.triggerMethod('before:destroy', view);\n    }\n\n    var shouldTriggerDetach = view._isAttached && !disableDetachEvents;\n\n    if (shouldTriggerDetach) {\n      view.triggerMethod('before:detach', view);\n    }\n\n    view.remove();\n\n    if (shouldTriggerDetach) {\n      view._isAttached = false;\n      view.triggerMethod('detach', view);\n    }\n\n    view._isDestroyed = true;\n\n    if (!view.supportsDestroyLifecycle) {\n      view.triggerMethod('destroy', view);\n    }\n  }\n\n  // Region\n  var classErrorName = 'RegionError';\n  var ClassOptions$1 = ['allowMissingEl', 'parentEl', 'replaceElement'];\n\n  var Region = function Region(options) {\n    this._setOptions(options, ClassOptions$1);\n\n    this.cid = _.uniqueId(this.cidPrefix); // getOption necessary because options.el may be passed as undefined\n\n    this._initEl = this.el = this.getOption('el'); // Handle when this.el is passed in as a $ wrapped element.\n\n    this.el = this.el instanceof Backbone.$ ? this.el[0] : this.el;\n    this.$el = this._getEl(this.el);\n    this.initialize.apply(this, arguments);\n  };\n\n  Region.extend = extend;\n  Region.setDomApi = setDomApi; // Region Methods\n  // --------------\n\n  _.extend(Region.prototype, CommonMixin, {\n    Dom: DomApi,\n    cidPrefix: 'mnr',\n    replaceElement: false,\n    _isReplaced: false,\n    _isSwappingView: false,\n    // This is a noop method intended to be overridden\n    initialize: function initialize() {},\n    // Displays a view instance inside of the region. If necessary handles calling the `render`\n    // method for you. Reads content directly from the `el` attribute.\n    show: function show(view, options) {\n      if (!this._ensureElement(options)) {\n        return;\n      }\n\n      view = this._getView(view, options);\n\n      if (view === this.currentView) {\n        return this;\n      }\n\n      if (view._isShown) {\n        throw new MarionetteError({\n          name: classErrorName,\n          message: 'View is already shown in a Region or CollectionView',\n          url: 'marionette.region.html#showing-a-view'\n        });\n      }\n\n      this._isSwappingView = !!this.currentView;\n      this.triggerMethod('before:show', this, view, options); // Assume an attached view is already in the region for pre-existing DOM\n\n      if (this.currentView || !view._isAttached) {\n        this.empty(options);\n      }\n\n      this._setupChildView(view);\n\n      this.currentView = view;\n      renderView(view);\n\n      this._attachView(view, options);\n\n      this.triggerMethod('show', this, view, options);\n      this._isSwappingView = false;\n      return this;\n    },\n    _getEl: function _getEl(el) {\n      if (!el) {\n        throw new MarionetteError({\n          name: classErrorName,\n          message: 'An \"el\" must be specified for a region.',\n          url: 'marionette.region.html#additional-options'\n        });\n      }\n\n      return this.getEl(el);\n    },\n    _setEl: function _setEl() {\n      this.$el = this._getEl(this.el);\n\n      if (this.$el.length) {\n        this.el = this.$el[0];\n      } // Make sure the $el contains only the el\n\n\n      if (this.$el.length > 1) {\n        this.$el = this.Dom.getEl(this.el);\n      }\n    },\n    // Set the `el` of the region and move any current view to the new `el`.\n    _setElement: function _setElement(el) {\n      if (el === this.el) {\n        return this;\n      }\n\n      var shouldReplace = this._isReplaced;\n\n      this._restoreEl();\n\n      this.el = el;\n\n      this._setEl();\n\n      if (this.currentView) {\n        var view = this.currentView;\n\n        if (shouldReplace) {\n          this._replaceEl(view);\n        } else {\n          this.attachHtml(view);\n        }\n      }\n\n      return this;\n    },\n    _setupChildView: function _setupChildView(view) {\n      monitorViewEvents(view);\n\n      this._proxyChildViewEvents(view); // We need to listen for if a view is destroyed in a way other than through the region.\n      // If this happens we need to remove the reference to the currentView since once a view\n      // has been destroyed we can not reuse it.\n\n\n      view.on('destroy', this._empty, this);\n    },\n    _proxyChildViewEvents: function _proxyChildViewEvents(view) {\n      var parentView = this._parentView;\n\n      if (!parentView) {\n        return;\n      }\n\n      parentView._proxyChildViewEvents(view);\n    },\n    // If the regions parent view is not monitoring its attach/detach events\n    _shouldDisableMonitoring: function _shouldDisableMonitoring() {\n      return this._parentView && this._parentView.monitorViewEvents === false;\n    },\n    _isElAttached: function _isElAttached() {\n      return this.Dom.hasEl(this.Dom.getDocumentEl(this.el), this.el);\n    },\n    _attachView: function _attachView(view) {\n      var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n          replaceElement = _ref.replaceElement;\n\n      var shouldTriggerAttach = !view._isAttached && this._isElAttached() && !this._shouldDisableMonitoring();\n      var shouldReplaceEl = typeof replaceElement === 'undefined' ? !!_.result(this, 'replaceElement') : !!replaceElement;\n\n      if (shouldTriggerAttach) {\n        view.triggerMethod('before:attach', view);\n      }\n\n      if (shouldReplaceEl) {\n        this._replaceEl(view);\n      } else {\n        this.attachHtml(view);\n      }\n\n      if (shouldTriggerAttach) {\n        view._isAttached = true;\n        view.triggerMethod('attach', view);\n      } // Corresponds that view is shown in a marionette Region or CollectionView\n\n\n      view._isShown = true;\n    },\n    _ensureElement: function _ensureElement() {\n      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n\n      if (!_.isObject(this.el)) {\n        this._setEl();\n      }\n\n      if (!this.$el || this.$el.length === 0) {\n        var allowMissingEl = typeof options.allowMissingEl === 'undefined' ? !!_.result(this, 'allowMissingEl') : !!options.allowMissingEl;\n\n        if (allowMissingEl) {\n          return false;\n        } else {\n          throw new MarionetteError({\n            name: classErrorName,\n            message: \"An \\\"el\\\" must exist in DOM for this region \".concat(this.cid),\n            url: 'marionette.region.html#additional-options'\n          });\n        }\n      }\n\n      return true;\n    },\n    _getView: function _getView(view) {\n      if (!view) {\n        throw new MarionetteError({\n          name: classErrorName,\n          message: 'The view passed is undefined and therefore invalid. You must pass a view instance to show.',\n          url: 'marionette.region.html#showing-a-view'\n        });\n      }\n\n      if (view._isDestroyed) {\n        throw new MarionetteError({\n          name: classErrorName,\n          message: \"View (cid: \\\"\".concat(view.cid, \"\\\") has already been destroyed and cannot be used.\"),\n          url: 'marionette.region.html#showing-a-view'\n        });\n      }\n\n      if (view instanceof Backbone.View) {\n        return view;\n      }\n\n      var viewOptions = this._getViewOptions(view);\n\n      return new View(viewOptions);\n    },\n    // This allows for a template or a static string to be\n    // used as a template\n    _getViewOptions: function _getViewOptions(viewOptions) {\n      if (_.isFunction(viewOptions)) {\n        return {\n          template: viewOptions\n        };\n      }\n\n      if (_.isObject(viewOptions)) {\n        return viewOptions;\n      }\n\n      var template = function template() {\n        return viewOptions;\n      };\n\n      return {\n        template: template\n      };\n    },\n    // Override this method to change how the region finds the DOM element that it manages. Return\n    // a jQuery selector object scoped to a provided parent el or the document if none exists.\n    getEl: function getEl(el) {\n      var context = _.result(this, 'parentEl');\n\n      if (context && _.isString(el)) {\n        return this.Dom.findEl(context, el);\n      }\n\n      return this.Dom.getEl(el);\n    },\n    _replaceEl: function _replaceEl(view) {\n      // Always restore the el to ensure the regions el is present before replacing\n      this._restoreEl();\n\n      view.on('before:destroy', this._restoreEl, this);\n      this.Dom.replaceEl(view.el, this.el);\n      this._isReplaced = true;\n    },\n    // Restore the region's element in the DOM.\n    _restoreEl: function _restoreEl() {\n      // There is nothing to replace\n      if (!this._isReplaced) {\n        return;\n      }\n\n      var view = this.currentView;\n\n      if (!view) {\n        return;\n      }\n\n      this._detachView(view);\n\n      this._isReplaced = false;\n    },\n    // Check to see if the region's el was replaced.\n    isReplaced: function isReplaced() {\n      return !!this._isReplaced;\n    },\n    // Check to see if a view is being swapped by another\n    isSwappingView: function isSwappingView() {\n      return !!this._isSwappingView;\n    },\n    // Override this method to change how the new view is appended to the `$el` that the\n    // region is managing\n    attachHtml: function attachHtml(view) {\n      this.Dom.appendContents(this.el, view.el, {\n        _$el: this.$el,\n        _$contents: view.$el\n      });\n    },\n    // Destroy the current view, if there is one. If there is no current view,\n    // it will detach any html inside the region's `el`.\n    empty: function empty() {\n      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {\n        allowMissingEl: true\n      };\n      var view = this.currentView; // If there is no view in the region we should only detach current html\n\n      if (!view) {\n        if (this._ensureElement(options)) {\n          this.detachHtml();\n        }\n\n        return this;\n      }\n\n      this._empty(view, true);\n\n      return this;\n    },\n    _empty: function _empty(view, shouldDestroy) {\n      view.off('destroy', this._empty, this);\n      this.triggerMethod('before:empty', this, view);\n\n      this._restoreEl();\n\n      delete this.currentView;\n\n      if (!view._isDestroyed) {\n        if (shouldDestroy) {\n          this.removeView(view);\n        } else {\n          this._detachView(view);\n        }\n\n        view._isShown = false;\n\n        this._stopChildViewEvents(view);\n      }\n\n      this.triggerMethod('empty', this, view);\n    },\n    _stopChildViewEvents: function _stopChildViewEvents(view) {\n      var parentView = this._parentView;\n\n      if (!parentView) {\n        return;\n      }\n\n      this._parentView.stopListening(view);\n    },\n    // Non-Marionette safe view.destroy\n    destroyView: function destroyView$1(view) {\n      if (view._isDestroyed) {\n        return view;\n      }\n\n      destroyView(view, this._shouldDisableMonitoring());\n\n      return view;\n    },\n    // Override this method to determine what happens when the view\n    // is removed from the region when the view is not being detached\n    removeView: function removeView(view) {\n      this.destroyView(view);\n    },\n    // Empties the Region without destroying the view\n    // Returns the detached view\n    detachView: function detachView() {\n      var view = this.currentView;\n\n      if (!view) {\n        return;\n      }\n\n      this._empty(view);\n\n      return view;\n    },\n    _detachView: function _detachView(view) {\n      var shouldTriggerDetach = view._isAttached && !this._shouldDisableMonitoring();\n      var shouldRestoreEl = this._isReplaced;\n\n      if (shouldTriggerDetach) {\n        view.triggerMethod('before:detach', view);\n      }\n\n      if (shouldRestoreEl) {\n        this.Dom.replaceEl(this.el, view.el);\n      } else {\n        this.detachHtml();\n      }\n\n      if (shouldTriggerDetach) {\n        view._isAttached = false;\n        view.triggerMethod('detach', view);\n      }\n    },\n    // Override this method to change how the region detaches current content\n    detachHtml: function detachHtml() {\n      this.Dom.detachContents(this.el, this.$el);\n    },\n    // Checks whether a view is currently present within the region. Returns `true` if there is\n    // and `false` if no view is present.\n    hasView: function hasView() {\n      return !!this.currentView;\n    },\n    // Reset the region by destroying any existing view and clearing out the cached `$el`.\n    // The next time a view is shown via this region, the region will re-query the DOM for\n    // the region's `el`.\n    reset: function reset(options) {\n      this.empty(options);\n      this.el = this._initEl;\n      delete this.$el;\n      return this;\n    },\n    _isDestroyed: false,\n    isDestroyed: function isDestroyed() {\n      return this._isDestroyed;\n    },\n    // Destroy the region, remove any child view\n    // and remove the region from any associated view\n    destroy: function destroy(options) {\n      if (this._isDestroyed) {\n        return this;\n      }\n\n      this.triggerMethod('before:destroy', this, options);\n      this._isDestroyed = true;\n      this.reset(options);\n\n      if (this._name) {\n        this._parentView._removeReferences(this._name);\n      }\n\n      delete this._parentView;\n      delete this._name;\n      this.triggerMethod('destroy', this, options);\n      this.stopListening();\n      return this;\n    }\n  });\n\n  function buildRegion (definition, defaults) {\n    if (definition instanceof Region) {\n      return definition;\n    }\n\n    if (_.isString(definition)) {\n      return buildRegionFromObject(defaults, {\n        el: definition\n      });\n    }\n\n    if (_.isFunction(definition)) {\n      return buildRegionFromObject(defaults, {\n        regionClass: definition\n      });\n    }\n\n    if (_.isObject(definition)) {\n      return buildRegionFromObject(defaults, definition);\n    }\n\n    throw new MarionetteError({\n      message: 'Improper region configuration type.',\n      url: 'marionette.region.html#defining-regions'\n    });\n  }\n\n  function buildRegionFromObject(defaults, definition) {\n    var options = _.extend({}, defaults, definition);\n\n    var RegionClass = options.regionClass;\n    delete options.regionClass;\n    return new RegionClass(options);\n  }\n\n  // - regions\n  // - regionClass\n\n  var RegionsMixin = {\n    regionClass: Region,\n    // Internal method to initialize the regions that have been defined in a\n    // `regions` attribute on this View.\n    _initRegions: function _initRegions() {\n      // init regions hash\n      this.regions = this.regions || {};\n      this._regions = {};\n      this.addRegions(_.result(this, 'regions'));\n    },\n    // Internal method to re-initialize all of the regions by updating\n    // the `el` that they point to\n    _reInitRegions: function _reInitRegions() {\n      _invoke(this._regions, 'reset');\n    },\n    // Add a single region, by name, to the View\n    addRegion: function addRegion(name, definition) {\n      var regions = {};\n      regions[name] = definition;\n      return this.addRegions(regions)[name];\n    },\n    // Add multiple regions as a {name: definition, name2: def2} object literal\n    addRegions: function addRegions(regions) {\n      // If there's nothing to add, stop here.\n      if (_.isEmpty(regions)) {\n        return;\n      } // Normalize region selectors hash to allow\n      // a user to use the @ui. syntax.\n\n\n      regions = this.normalizeUIValues(regions, 'el'); // Add the regions definitions to the regions property\n\n      this.regions = _.extend({}, this.regions, regions);\n      return this._addRegions(regions);\n    },\n    // internal method to build and add regions\n    _addRegions: function _addRegions(regionDefinitions) {\n      var _this = this;\n\n      var defaults = {\n        regionClass: this.regionClass,\n        parentEl: _.partial(_.result, this, 'el')\n      };\n      return _.reduce(regionDefinitions, function (regions, definition, name) {\n        regions[name] = buildRegion(definition, defaults);\n\n        _this._addRegion(regions[name], name);\n\n        return regions;\n      }, {});\n    },\n    _addRegion: function _addRegion(region, name) {\n      this.triggerMethod('before:add:region', this, name, region);\n      region._parentView = this;\n      region._name = name;\n      this._regions[name] = region;\n      this.triggerMethod('add:region', this, name, region);\n    },\n    // Remove a single region from the View, by name\n    removeRegion: function removeRegion(name) {\n      var region = this._regions[name];\n\n      this._removeRegion(region, name);\n\n      return region;\n    },\n    // Remove all regions from the View\n    removeRegions: function removeRegions() {\n      var regions = this._getRegions();\n\n      _.each(this._regions, this._removeRegion.bind(this));\n\n      return regions;\n    },\n    _removeRegion: function _removeRegion(region, name) {\n      this.triggerMethod('before:remove:region', this, name, region);\n      region.destroy();\n      this.triggerMethod('remove:region', this, name, region);\n    },\n    // Called in a region's destroy\n    _removeReferences: function _removeReferences(name) {\n      delete this.regions[name];\n      delete this._regions[name];\n    },\n    // Empty all regions in the region manager, but\n    // leave them attached\n    emptyRegions: function emptyRegions() {\n      var regions = this.getRegions();\n\n      _invoke(regions, 'empty');\n\n      return regions;\n    },\n    // Checks to see if view contains region\n    // Accepts the region name\n    // hasRegion('main')\n    hasRegion: function hasRegion(name) {\n      return !!this.getRegion(name);\n    },\n    // Provides access to regions\n    // Accepts the region name\n    // getRegion('main')\n    getRegion: function getRegion(name) {\n      if (!this._isRendered) {\n        this.render();\n      }\n\n      return this._regions[name];\n    },\n    _getRegions: function _getRegions() {\n      return _.clone(this._regions);\n    },\n    // Get all regions\n    getRegions: function getRegions() {\n      if (!this._isRendered) {\n        this.render();\n      }\n\n      return this._getRegions();\n    },\n    showChildView: function showChildView(name, view, options) {\n      var region = this.getRegion(name);\n      region.show(view, options);\n      return view;\n    },\n    detachChildView: function detachChildView(name) {\n      return this.getRegion(name).detachView();\n    },\n    getChildView: function getChildView(name) {\n      return this.getRegion(name).currentView;\n    }\n  };\n\n  // Static setter for the renderer\n  function setRenderer(renderer) {\n    this.prototype._renderHtml = renderer;\n    return this;\n  }\n\n  // View\n  var ClassOptions$2 = ['behaviors', 'childViewEventPrefix', 'childViewEvents', 'childViewTriggers', 'collectionEvents', 'events', 'modelEvents', 'regionClass', 'regions', 'template', 'templateContext', 'triggers', 'ui']; // Used by _getImmediateChildren\n\n  function childReducer(children, region) {\n    if (region.currentView) {\n      children.push(region.currentView);\n    }\n\n    return children;\n  } // The standard view. Includes view events, automatic rendering\n  // templates, nested views, and more.\n\n\n  var View = Backbone.View.extend({\n    constructor: function constructor(options) {\n      this._setOptions(options, ClassOptions$2);\n\n      monitorViewEvents(this);\n\n      this._initBehaviors();\n\n      this._initRegions();\n\n      Backbone.View.prototype.constructor.apply(this, arguments);\n      this.delegateEntityEvents();\n\n      this._triggerEventOnBehaviors('initialize', this, options);\n    },\n    // Overriding Backbone.View's `setElement` to handle\n    // if an el was previously defined. If so, the view might be\n    // rendered or attached on setElement.\n    setElement: function setElement() {\n      Backbone.View.prototype.setElement.apply(this, arguments);\n      this._isRendered = this.Dom.hasContents(this.el);\n      this._isAttached = this._isElAttached();\n\n      if (this._isRendered) {\n        this.bindUIElements();\n      }\n\n      return this;\n    },\n    // If a template is available, renders it into the view's `el`\n    // Re-inits regions and binds UI.\n    render: function render() {\n      var template = this.getTemplate();\n\n      if (template === false || this._isDestroyed) {\n        return this;\n      }\n\n      this.triggerMethod('before:render', this); // If this is not the first render call, then we need to\n      // re-initialize the `el` for each region\n\n      if (this._isRendered) {\n        this._reInitRegions();\n      }\n\n      this._renderTemplate(template);\n\n      this.bindUIElements();\n      this._isRendered = true;\n      this.triggerMethod('render', this);\n      return this;\n    },\n    // called by ViewMixin destroy\n    _removeChildren: function _removeChildren() {\n      this.removeRegions();\n    },\n    _getImmediateChildren: function _getImmediateChildren() {\n      return _.reduce(this._regions, childReducer, []);\n    }\n  }, {\n    setRenderer: setRenderer,\n    setDomApi: setDomApi\n  });\n\n  _.extend(View.prototype, ViewMixin, RegionsMixin);\n\n  // shut down child views.\n\n  var Container = function Container() {\n    this._init();\n  }; // Mix in methods from Underscore, for iteration, and other\n  // collection related features.\n  // Borrowing this code from Backbone.Collection:\n  // https://github.com/jashkenas/backbone/blob/1.1.2/backbone.js#L962\n\n\n  var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter', 'select', 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke', 'toArray', 'first', 'initial', 'rest', 'last', 'without', 'isEmpty', 'pluck', 'reduce', 'partition'];\n\n  _.each(methods, function (method) {\n    Container.prototype[method] = function () {\n      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n        args[_key] = arguments[_key];\n      }\n\n      return _[method].apply(_, [this._views].concat(args));\n    };\n  });\n\n  function stringComparator(comparator, view) {\n    return view.model && view.model.get(comparator);\n  } // Container Methods\n  // -----------------\n\n\n  _.extend(Container.prototype, {\n    // Initializes an empty container\n    _init: function _init() {\n      this._views = [];\n      this._viewsByCid = {};\n      this._indexByModel = {};\n\n      this._updateLength();\n    },\n    // Add a view to this container. Stores the view\n    // by `cid` and makes it searchable by the model\n    // cid (and model itself). Additionally it stores\n    // the view by index in the _views array\n    _add: function _add(view) {\n      var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this._views.length;\n\n      this._addViewIndexes(view); // add to end by default\n\n\n      this._views.splice(index, 0, view);\n\n      this._updateLength();\n    },\n    _addViewIndexes: function _addViewIndexes(view) {\n      // store the view\n      this._viewsByCid[view.cid] = view; // index it by model\n\n      if (view.model) {\n        this._indexByModel[view.model.cid] = view;\n      }\n    },\n    // Sort (mutate) and return the array of the child views.\n    _sort: function _sort(comparator, context) {\n      if (typeof comparator === 'string') {\n        comparator = _.partial(stringComparator, comparator);\n        return this._sortBy(comparator);\n      }\n\n      if (comparator.length === 1) {\n        return this._sortBy(comparator.bind(context));\n      }\n\n      return this._views.sort(comparator.bind(context));\n    },\n    // Makes `_.sortBy` mutate the array to match `this._views.sort`\n    _sortBy: function _sortBy(comparator) {\n      var sortedViews = _.sortBy(this._views, comparator);\n\n      this._set(sortedViews);\n\n      return sortedViews;\n    },\n    // Replace array contents without overwriting the reference.\n    // Should not add/remove views\n    _set: function _set(views, shouldReset) {\n      this._views.length = 0;\n\n      this._views.push.apply(this._views, views.slice(0));\n\n      if (shouldReset) {\n        this._viewsByCid = {};\n        this._indexByModel = {};\n\n        _.each(views, this._addViewIndexes.bind(this));\n\n        this._updateLength();\n      }\n    },\n    // Swap views by index\n    _swap: function _swap(view1, view2) {\n      var view1Index = this.findIndexByView(view1);\n      var view2Index = this.findIndexByView(view2);\n\n      if (view1Index === -1 || view2Index === -1) {\n        return;\n      }\n\n      var swapView = this._views[view1Index];\n      this._views[view1Index] = this._views[view2Index];\n      this._views[view2Index] = swapView;\n    },\n    // Find a view by the model that was attached to it.\n    // Uses the model's `cid` to find it.\n    findByModel: function findByModel(model) {\n      return this.findByModelCid(model.cid);\n    },\n    // Find a view by the `cid` of the model that was attached to it.\n    findByModelCid: function findByModelCid(modelCid) {\n      return this._indexByModel[modelCid];\n    },\n    // Find a view by index.\n    findByIndex: function findByIndex(index) {\n      return this._views[index];\n    },\n    // Find the index of a view instance\n    findIndexByView: function findIndexByView(view) {\n      return this._views.indexOf(view);\n    },\n    // Retrieve a view by its `cid` directly\n    findByCid: function findByCid(cid) {\n      return this._viewsByCid[cid];\n    },\n    hasView: function hasView(view) {\n      return !!this.findByCid(view.cid);\n    },\n    // Remove a view and clean up index references.\n    _remove: function _remove(view) {\n      if (!this._viewsByCid[view.cid]) {\n        return;\n      } // delete model index\n\n\n      if (view.model) {\n        delete this._indexByModel[view.model.cid];\n      } // remove the view from the container\n\n\n      delete this._viewsByCid[view.cid];\n      var index = this.findIndexByView(view);\n\n      this._views.splice(index, 1);\n\n      this._updateLength();\n    },\n    // Update the `.length` attribute on this container\n    _updateLength: function _updateLength() {\n      this.length = this._views.length;\n    }\n  });\n\n  // Collection View\n  var classErrorName$1 = 'CollectionViewError';\n  var ClassOptions$3 = ['behaviors', 'childView', 'childViewContainer', 'childViewEventPrefix', 'childViewEvents', 'childViewOptions', 'childViewTriggers', 'collectionEvents', 'emptyView', 'emptyViewOptions', 'events', 'modelEvents', 'sortWithCollection', 'template', 'templateContext', 'triggers', 'ui', 'viewComparator', 'viewFilter']; // A view that iterates over a Backbone.Collection\n  // and renders an individual child view for each model.\n\n  var CollectionView = Backbone.View.extend({\n    // flag for maintaining the sorted order of the collection\n    sortWithCollection: true,\n    // constructor\n    constructor: function constructor(options) {\n      this._setOptions(options, ClassOptions$3);\n\n      monitorViewEvents(this);\n\n      this._initChildViewStorage();\n\n      this._initBehaviors();\n\n      Backbone.View.prototype.constructor.apply(this, arguments); // Init empty region\n\n      this.getEmptyRegion();\n      this.delegateEntityEvents();\n\n      this._triggerEventOnBehaviors('initialize', this, options);\n    },\n    // Internal method to set up the `children` object for storing all of the child views\n    // `_children` represents all child views\n    // `children` represents only views filtered to be shown\n    _initChildViewStorage: function _initChildViewStorage() {\n      this._children = new Container();\n      this.children = new Container();\n    },\n    // Create an region to show the emptyView\n    getEmptyRegion: function getEmptyRegion() {\n      var $emptyEl = this.$container || this.$el;\n\n      if (this._emptyRegion && !this._emptyRegion.isDestroyed()) {\n        this._emptyRegion._setElement($emptyEl[0]);\n\n        return this._emptyRegion;\n      }\n\n      this._emptyRegion = new Region({\n        el: $emptyEl[0],\n        replaceElement: false\n      });\n      this._emptyRegion._parentView = this;\n      return this._emptyRegion;\n    },\n    // Configured the initial events that the collection view binds to.\n    _initialEvents: function _initialEvents() {\n      if (this._isRendered) {\n        return;\n      }\n\n      this.listenTo(this.collection, {\n        'sort': this._onCollectionSort,\n        'reset': this._onCollectionReset,\n        'update': this._onCollectionUpdate\n      });\n    },\n    // Internal method. This checks for any changes in the order of the collection.\n    // If the index of any view doesn't match, it will re-sort.\n    _onCollectionSort: function _onCollectionSort(collection, _ref) {\n      var add = _ref.add,\n          merge = _ref.merge,\n          remove = _ref.remove;\n\n      if (!this.sortWithCollection || this.viewComparator === false) {\n        return;\n      } // If the data is changing we will handle the sort later in `_onCollectionUpdate`\n\n\n      if (add || remove || merge) {\n        return;\n      } // If the only thing happening here is sorting, sort.\n\n\n      this.sort();\n    },\n    _onCollectionReset: function _onCollectionReset() {\n      this._destroyChildren();\n\n      this._addChildModels(this.collection.models);\n\n      this.sort();\n    },\n    // Handle collection update model additions and  removals\n    _onCollectionUpdate: function _onCollectionUpdate(collection, options) {\n      var changes = options.changes; // Remove first since it'll be a shorter array lookup.\n\n      var removedViews = changes.removed.length && this._removeChildModels(changes.removed);\n\n      this._addedViews = changes.added.length && this._addChildModels(changes.added);\n\n      this._detachChildren(removedViews);\n\n      this.sort(); // Destroy removed child views after all of the render is complete\n\n      this._removeChildViews(removedViews);\n    },\n    _removeChildModels: function _removeChildModels(models) {\n      var _this = this;\n\n      return _.reduce(models, function (views, model) {\n        var removeView = _this._removeChildModel(model);\n\n        if (removeView) {\n          views.push(removeView);\n        }\n\n        return views;\n      }, []);\n    },\n    _removeChildModel: function _removeChildModel(model) {\n      var view = this._children.findByModel(model);\n\n      if (view) {\n        this._removeChild(view);\n      }\n\n      return view;\n    },\n    _removeChild: function _removeChild(view) {\n      this.triggerMethod('before:remove:child', this, view);\n\n      this.children._remove(view);\n\n      this._children._remove(view);\n\n      this.triggerMethod('remove:child', this, view);\n    },\n    // Added views are returned for consistency with _removeChildModels\n    _addChildModels: function _addChildModels(models) {\n      return _.map(models, this._addChildModel.bind(this));\n    },\n    _addChildModel: function _addChildModel(model) {\n      var view = this._createChildView(model);\n\n      this._addChild(view);\n\n      return view;\n    },\n    _createChildView: function _createChildView(model) {\n      var ChildView = this._getChildView(model);\n\n      var childViewOptions = this._getChildViewOptions(model);\n\n      var view = this.buildChildView(model, ChildView, childViewOptions);\n      return view;\n    },\n    _addChild: function _addChild(view, index) {\n      this.triggerMethod('before:add:child', this, view);\n\n      this._setupChildView(view);\n\n      this._children._add(view, index);\n\n      this.children._add(view, index);\n\n      this.triggerMethod('add:child', this, view);\n    },\n    // Retrieve the `childView` class\n    // The `childView` property can be either a view class or a function that\n    // returns a view class. If it is a function, it will receive the model that\n    // will be passed to the view instance (created from the returned view class)\n    _getChildView: function _getChildView(child) {\n      var childView = this.childView;\n\n      if (!childView) {\n        throw new MarionetteError({\n          name: classErrorName$1,\n          message: 'A \"childView\" must be specified',\n          url: 'marionette.collectionview.html#collectionviews-childview'\n        });\n      }\n\n      childView = this._getView(childView, child);\n\n      if (!childView) {\n        throw new MarionetteError({\n          name: classErrorName$1,\n          message: '\"childView\" must be a view class or a function that returns a view class',\n          url: 'marionette.collectionview.html#collectionviews-childview'\n        });\n      }\n\n      return childView;\n    },\n    // First check if the `view` is a view class (the common case)\n    // Then check if it's a function (which we assume that returns a view class)\n    _getView: function _getView(view, child) {\n      if (view.prototype instanceof Backbone.View || view === Backbone.View) {\n        return view;\n      } else if (_.isFunction(view)) {\n        return view.call(this, child);\n      }\n    },\n    _getChildViewOptions: function _getChildViewOptions(child) {\n      if (_.isFunction(this.childViewOptions)) {\n        return this.childViewOptions(child);\n      }\n\n      return this.childViewOptions;\n    },\n    // Build a `childView` for a model in the collection.\n    // Override to customize the build\n    buildChildView: function buildChildView(child, ChildViewClass, childViewOptions) {\n      var options = _.extend({\n        model: child\n      }, childViewOptions);\n\n      return new ChildViewClass(options);\n    },\n    _setupChildView: function _setupChildView(view) {\n      monitorViewEvents(view); // We need to listen for if a view is destroyed in a way other\n      // than through the CollectionView.\n      // If this happens we need to remove the reference to the view\n      // since once a view has been destroyed we can not reuse it.\n\n      view.on('destroy', this.removeChildView, this); // set up the child view event forwarding\n\n      this._proxyChildViewEvents(view);\n    },\n    // used by ViewMixin's `_childViewEventHandler`\n    _getImmediateChildren: function _getImmediateChildren() {\n      return this.children._views;\n    },\n    // Overriding Backbone.View's `setElement` to handle\n    // if an el was previously defined. If so, the view might be\n    // attached on setElement.\n    setElement: function setElement() {\n      Backbone.View.prototype.setElement.apply(this, arguments);\n      this._isAttached = this._isElAttached();\n      return this;\n    },\n    // Render children views.\n    render: function render() {\n      if (this._isDestroyed) {\n        return this;\n      }\n\n      this.triggerMethod('before:render', this);\n\n      this._destroyChildren();\n\n      if (this.collection) {\n        this._addChildModels(this.collection.models);\n\n        this._initialEvents();\n      }\n\n      var template = this.getTemplate();\n\n      if (template) {\n        this._renderTemplate(template);\n\n        this.bindUIElements();\n      }\n\n      this._getChildViewContainer();\n\n      this.sort();\n      this._isRendered = true;\n      this.triggerMethod('render', this);\n      return this;\n    },\n    // Get a container within the template to add the children within\n    _getChildViewContainer: function _getChildViewContainer() {\n      var childViewContainer = _.result(this, 'childViewContainer');\n\n      this.$container = childViewContainer ? this.$(childViewContainer) : this.$el;\n\n      if (!this.$container.length) {\n        throw new MarionetteError({\n          name: classErrorName$1,\n          message: \"The specified \\\"childViewContainer\\\" was not found: \".concat(childViewContainer),\n          url: 'marionette.collectionview.html#defining-the-childviewcontainer'\n        });\n      }\n    },\n    // Sorts the children then filters and renders the results.\n    sort: function sort() {\n      this._sortChildren();\n\n      this.filter();\n      return this;\n    },\n    // Sorts views by viewComparator and sets the children to the new order\n    _sortChildren: function _sortChildren() {\n      if (!this._children.length) {\n        return;\n      }\n\n      var viewComparator = this.getComparator();\n\n      if (!viewComparator) {\n        return;\n      } // If children are sorted prevent added to end perf\n\n\n      delete this._addedViews;\n      this.triggerMethod('before:sort', this);\n\n      this._children._sort(viewComparator, this);\n\n      this.triggerMethod('sort', this);\n    },\n    // Sets the view's `viewComparator` and applies the sort if the view is ready.\n    // To prevent the render pass `{ preventRender: true }` as the 2nd argument.\n    setComparator: function setComparator(comparator) {\n      var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n          preventRender = _ref2.preventRender;\n\n      var comparatorChanged = this.viewComparator !== comparator;\n      var shouldSort = comparatorChanged && !preventRender;\n      this.viewComparator = comparator;\n\n      if (shouldSort) {\n        this.sort();\n      }\n\n      return this;\n    },\n    // Clears the `viewComparator` and follows the same rules for rendering as `setComparator`.\n    removeComparator: function removeComparator(options) {\n      return this.setComparator(null, options);\n    },\n    // If viewComparator is overridden it will be returned here.\n    // Additionally override this function to provide custom\n    // viewComparator logic\n    getComparator: function getComparator() {\n      if (this.viewComparator) {\n        return this.viewComparator;\n      }\n\n      if (!this.sortWithCollection || this.viewComparator === false || !this.collection) {\n        return false;\n      }\n\n      return this._viewComparator;\n    },\n    // Default internal view comparator that order the views by\n    // the order of the collection\n    _viewComparator: function _viewComparator(view) {\n      return this.collection.indexOf(view.model);\n    },\n    // This method filters the children views and renders the results\n    filter: function filter() {\n      if (this._isDestroyed) {\n        return this;\n      }\n\n      this._filterChildren();\n\n      this._renderChildren();\n\n      return this;\n    },\n    _filterChildren: function _filterChildren() {\n      var _this2 = this;\n\n      if (!this._children.length) {\n        return;\n      }\n\n      var viewFilter = this._getFilter();\n\n      if (!viewFilter) {\n        var shouldReset = this.children.length !== this._children.length;\n\n        this.children._set(this._children._views, shouldReset);\n\n        return;\n      } // If children are filtered prevent added to end perf\n\n\n      delete this._addedViews;\n      this.triggerMethod('before:filter', this);\n      var attachViews = [];\n      var detachViews = [];\n\n      _.each(this._children._views, function (view, key, children) {\n        (viewFilter.call(_this2, view, key, children) ? attachViews : detachViews).push(view);\n      });\n\n      this._detachChildren(detachViews); // reset children\n\n\n      this.children._set(attachViews, true);\n\n      this.triggerMethod('filter', this, attachViews, detachViews);\n    },\n    // This method returns a function for the viewFilter\n    _getFilter: function _getFilter() {\n      var viewFilter = this.getFilter();\n\n      if (!viewFilter) {\n        return false;\n      }\n\n      if (_.isFunction(viewFilter)) {\n        return viewFilter;\n      } // Support filter predicates `{ fooFlag: true }`\n\n\n      if (_.isObject(viewFilter)) {\n        var matcher = _.matches(viewFilter);\n\n        return function (view) {\n          return matcher(view.model && view.model.attributes);\n        };\n      } // Filter by model attribute\n\n\n      if (_.isString(viewFilter)) {\n        return function (view) {\n          return view.model && view.model.get(viewFilter);\n        };\n      }\n\n      throw new MarionetteError({\n        name: classErrorName$1,\n        message: '\"viewFilter\" must be a function, predicate object literal, a string indicating a model attribute, or falsy',\n        url: 'marionette.collectionview.html#defining-the-viewfilter'\n      });\n    },\n    // Override this function to provide custom\n    // viewFilter logic\n    getFilter: function getFilter() {\n      return this.viewFilter;\n    },\n    // Sets the view's `viewFilter` and applies the filter if the view is ready.\n    // To prevent the render pass `{ preventRender: true }` as the 2nd argument.\n    setFilter: function setFilter(filter) {\n      var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n          preventRender = _ref3.preventRender;\n\n      var filterChanged = this.viewFilter !== filter;\n      var shouldRender = filterChanged && !preventRender;\n      this.viewFilter = filter;\n\n      if (shouldRender) {\n        this.filter();\n      }\n\n      return this;\n    },\n    // Clears the `viewFilter` and follows the same rules for rendering as `setFilter`.\n    removeFilter: function removeFilter(options) {\n      return this.setFilter(null, options);\n    },\n    _detachChildren: function _detachChildren(detachingViews) {\n      _.each(detachingViews, this._detachChildView.bind(this));\n    },\n    _detachChildView: function _detachChildView(view) {\n      var shouldTriggerDetach = view._isAttached && this.monitorViewEvents !== false;\n\n      if (shouldTriggerDetach) {\n        view.triggerMethod('before:detach', view);\n      }\n\n      this.detachHtml(view);\n\n      if (shouldTriggerDetach) {\n        view._isAttached = false;\n        view.triggerMethod('detach', view);\n      }\n\n      view._isShown = false;\n    },\n    // Override this method to change how the collectionView detaches a child view\n    detachHtml: function detachHtml(view) {\n      this.Dom.detachEl(view.el, view.$el);\n    },\n    _renderChildren: function _renderChildren() {\n      // If there are unrendered views prevent add to end perf\n      if (this._hasUnrenderedViews) {\n        delete this._addedViews;\n        delete this._hasUnrenderedViews;\n      }\n\n      var views = this._addedViews || this.children._views;\n      this.triggerMethod('before:render:children', this, views);\n\n      if (this.isEmpty()) {\n        this._showEmptyView();\n      } else {\n        this._destroyEmptyView();\n\n        var els = this._getBuffer(views);\n\n        this._attachChildren(els, views);\n      }\n\n      delete this._addedViews;\n      this.triggerMethod('render:children', this, views);\n    },\n    // Renders each view and creates a fragment buffer from them\n    _getBuffer: function _getBuffer(views) {\n      var _this3 = this;\n\n      var elBuffer = this.Dom.createBuffer();\n\n      _.each(views, function (view) {\n        renderView(view); // corresponds that view is shown in a Region or CollectionView\n\n        view._isShown = true;\n\n        _this3.Dom.appendContents(elBuffer, view.el, {\n          _$contents: view.$el\n        });\n      });\n\n      return elBuffer;\n    },\n    _attachChildren: function _attachChildren(els, views) {\n      var shouldTriggerAttach = this._isAttached && this.monitorViewEvents !== false;\n      views = shouldTriggerAttach ? views : [];\n\n      _.each(views, function (view) {\n        if (view._isAttached) {\n          return;\n        }\n\n        view.triggerMethod('before:attach', view);\n      });\n\n      this.attachHtml(els, this.$container);\n\n      _.each(views, function (view) {\n        if (view._isAttached) {\n          return;\n        }\n\n        view._isAttached = true;\n        view.triggerMethod('attach', view);\n      });\n    },\n    // Override this method to do something other than `.append`.\n    // You can attach any HTML at this point including the els.\n    attachHtml: function attachHtml(els, $container) {\n      this.Dom.appendContents($container[0], els, {\n        _$el: $container\n      });\n    },\n    isEmpty: function isEmpty() {\n      return !this.children.length;\n    },\n    _showEmptyView: function _showEmptyView() {\n      var EmptyView = this._getEmptyView();\n\n      if (!EmptyView) {\n        return;\n      }\n\n      var options = this._getEmptyViewOptions();\n\n      var emptyRegion = this.getEmptyRegion();\n      emptyRegion.show(new EmptyView(options));\n    },\n    // Retrieve the empty view class\n    _getEmptyView: function _getEmptyView() {\n      var emptyView = this.emptyView;\n\n      if (!emptyView) {\n        return;\n      }\n\n      return this._getView(emptyView);\n    },\n    // Remove the emptyView\n    _destroyEmptyView: function _destroyEmptyView() {\n      var emptyRegion = this.getEmptyRegion(); // Only empty if a view is show so the region\n      // doesn't detach any other unrelated HTML\n\n      if (emptyRegion.hasView()) {\n        emptyRegion.empty();\n      }\n    },\n    //\n    _getEmptyViewOptions: function _getEmptyViewOptions() {\n      var emptyViewOptions = this.emptyViewOptions || this.childViewOptions;\n\n      if (_.isFunction(emptyViewOptions)) {\n        return emptyViewOptions.call(this);\n      }\n\n      return emptyViewOptions;\n    },\n    swapChildViews: function swapChildViews(view1, view2) {\n      if (!this._children.hasView(view1) || !this._children.hasView(view2)) {\n        throw new MarionetteError({\n          name: classErrorName$1,\n          message: 'Both views must be children of the collection view to swap.',\n          url: 'marionette.collectionview.html#swapping-child-views'\n        });\n      }\n\n      this._children._swap(view1, view2);\n\n      this.Dom.swapEl(view1.el, view2.el); // If the views are not filtered the same, refilter\n\n      if (this.children.hasView(view1) !== this.children.hasView(view2)) {\n        this.filter();\n      } else {\n        this.children._swap(view1, view2);\n      }\n\n      return this;\n    },\n    // Render the child's view and add it to the HTML for the collection view at a given index, based on the current sort\n    addChildView: function addChildView(view, index) {\n      var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n\n      if (!view || view._isDestroyed) {\n        return view;\n      }\n\n      if (view._isShown) {\n        throw new MarionetteError({\n          name: classErrorName$1,\n          message: 'View is already shown in a Region or CollectionView',\n          url: 'marionette.region.html#showing-a-view'\n        });\n      }\n\n      if (_.isObject(index)) {\n        options = index;\n      } // If options has defined index we should use it\n\n\n      if (options.index != null) {\n        index = options.index;\n      }\n\n      if (!this._isRendered) {\n        this.render();\n      }\n\n      this._addChild(view, index);\n\n      if (options.preventRender) {\n        this._hasUnrenderedViews = true;\n        return view;\n      }\n\n      var hasIndex = typeof index !== 'undefined';\n      var isAddedToEnd = !hasIndex || index >= this._children.length; // Only cache views if added to the end and there is no unrendered views\n\n      if (isAddedToEnd && !this._hasUnrenderedViews) {\n        this._addedViews = [view];\n      }\n\n      if (hasIndex) {\n        this._renderChildren();\n      } else {\n        this.sort();\n      }\n\n      return view;\n    },\n    // Detach a view from the children.  Best used when adding a\n    // childView from `addChildView`\n    detachChildView: function detachChildView(view) {\n      this.removeChildView(view, {\n        shouldDetach: true\n      });\n      return view;\n    },\n    // Remove the child view and destroy it.  Best used when adding a\n    // childView from `addChildView`\n    // The options argument is for internal use only\n    removeChildView: function removeChildView(view, options) {\n      if (!view) {\n        return view;\n      }\n\n      this._removeChildView(view, options);\n\n      this._removeChild(view);\n\n      if (this.isEmpty()) {\n        this._showEmptyView();\n      }\n\n      return view;\n    },\n    _removeChildViews: function _removeChildViews(views) {\n      _.each(views, this._removeChildView.bind(this));\n    },\n    _removeChildView: function _removeChildView(view) {\n      var _ref4 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n          shouldDetach = _ref4.shouldDetach;\n\n      view.off('destroy', this.removeChildView, this);\n\n      if (shouldDetach) {\n        this._detachChildView(view);\n      } else {\n        this._destroyChildView(view);\n      }\n\n      this.stopListening(view);\n    },\n    _destroyChildView: function _destroyChildView(view) {\n      if (view._isDestroyed) {\n        return;\n      }\n\n      var shouldDisableEvents = this.monitorViewEvents === false;\n      destroyView(view, shouldDisableEvents);\n    },\n    // called by ViewMixin destroy\n    _removeChildren: function _removeChildren() {\n      this._destroyChildren();\n\n      var emptyRegion = this.getEmptyRegion();\n      emptyRegion.destroy();\n      delete this._addedViews;\n    },\n    // Destroy the child views that this collection view is holding on to, if any\n    _destroyChildren: function _destroyChildren() {\n      if (!this._children.length) {\n        return;\n      }\n\n      this.triggerMethod('before:destroy:children', this);\n\n      if (this.monitorViewEvents === false) {\n        this.Dom.detachContents(this.el, this.$el);\n      }\n\n      this._removeChildViews(this._children._views); // After all children have been destroyed re-init the container\n\n\n      this._children._init();\n\n      this.children._init();\n\n      this.triggerMethod('destroy:children', this);\n    }\n  }, {\n    setDomApi: setDomApi,\n    setRenderer: setRenderer\n  });\n\n  _.extend(CollectionView.prototype, ViewMixin);\n\n  // Behavior\n  var ClassOptions$4 = ['collectionEvents', 'events', 'modelEvents', 'triggers', 'ui'];\n\n  var Behavior = function Behavior(options, view) {\n    // Setup reference to the view.\n    // this comes in handle when a behavior\n    // wants to directly talk up the chain\n    // to the view.\n    this.view = view;\n\n    this._setOptions(options, ClassOptions$4);\n\n    this.cid = _.uniqueId(this.cidPrefix); // Construct an internal UI hash using the behaviors UI\n    // hash combined and overridden by the view UI hash.\n    // This allows the user to use UI hash elements defined\n    // in the parent view as well as those defined in the behavior.\n    // This order will help the reuse and share of a behavior\n    // between multiple views, while letting a view override\n    // a selector under an UI key.\n\n    this.ui = _.extend({}, _.result(this, 'ui'), _.result(view, 'ui')); // Proxy view triggers\n\n    this.listenTo(view, 'all', this.triggerMethod);\n    this.initialize.apply(this, arguments);\n  };\n\n  Behavior.extend = extend; // Behavior Methods\n  // --------------\n\n  _.extend(Behavior.prototype, CommonMixin, DelegateEntityEventsMixin, TriggersMixin, UIMixin, {\n    cidPrefix: 'mnb',\n    // This is a noop method intended to be overridden\n    initialize: function initialize() {},\n    // proxy behavior $ method to the view\n    // this is useful for doing jquery DOM lookups\n    // scoped to behaviors view.\n    $: function $() {\n      return this.view.$.apply(this.view, arguments);\n    },\n    // Stops the behavior from listening to events.\n    destroy: function destroy() {\n      this.stopListening();\n\n      this.view._removeBehavior(this);\n\n      this._deleteEntityEventHandlers();\n\n      return this;\n    },\n    proxyViewProperties: function proxyViewProperties() {\n      this.$el = this.view.$el;\n      this.el = this.view.el;\n      return this;\n    },\n    bindUIElements: function bindUIElements() {\n      this._bindUIElements();\n\n      return this;\n    },\n    unbindUIElements: function unbindUIElements() {\n      this._unbindUIElements();\n\n      return this;\n    },\n    getUI: function getUI(name) {\n      return this._getUI(name);\n    },\n    // Handle `modelEvents`, and `collectionEvents` configuration\n    delegateEntityEvents: function delegateEntityEvents() {\n      this._delegateEntityEvents(this.view.model, this.view.collection);\n\n      return this;\n    },\n    undelegateEntityEvents: function undelegateEntityEvents() {\n      this._undelegateEntityEvents(this.view.model, this.view.collection);\n\n      return this;\n    },\n    _getEvents: function _getEvents() {\n      var _this = this;\n\n      if (!this.events) {\n        return;\n      } // Normalize behavior events hash to allow\n      // a user to use the @ui. syntax.\n\n\n      var behaviorEvents = this.normalizeUIKeys(_.result(this, 'events')); // binds the handler to the behavior and builds a unique eventName\n\n      return _.reduce(behaviorEvents, function (events, behaviorHandler, key) {\n        if (!_.isFunction(behaviorHandler)) {\n          behaviorHandler = _this[behaviorHandler];\n        }\n\n        if (!behaviorHandler) {\n          return events;\n        }\n\n        key = getNamespacedEventName(key, _this.cid);\n        events[key] = behaviorHandler.bind(_this);\n        return events;\n      }, {});\n    },\n    // Internal method to build all trigger handlers for a given behavior\n    _getTriggers: function _getTriggers() {\n      if (!this.triggers) {\n        return;\n      } // Normalize behavior triggers hash to allow\n      // a user to use the @ui. syntax.\n\n\n      var behaviorTriggers = this.normalizeUIKeys(_.result(this, 'triggers'));\n      return this._getViewTriggers(this.view, behaviorTriggers);\n    }\n  });\n\n  // Application\n  var ClassOptions$5 = ['channelName', 'radioEvents', 'radioRequests', 'region', 'regionClass'];\n\n  var Application = function Application(options) {\n    this._setOptions(options, ClassOptions$5);\n\n    this.cid = _.uniqueId(this.cidPrefix);\n\n    this._initRegion();\n\n    this._initRadio();\n\n    this.initialize.apply(this, arguments);\n  };\n\n  Application.extend = extend; // Application Methods\n  // --------------\n\n  _.extend(Application.prototype, CommonMixin, DestroyMixin, RadioMixin, {\n    cidPrefix: 'mna',\n    // This is a noop method intended to be overridden\n    initialize: function initialize() {},\n    // Kick off all of the application's processes.\n    start: function start(options) {\n      this.triggerMethod('before:start', this, options);\n      this.triggerMethod('start', this, options);\n      return this;\n    },\n    regionClass: Region,\n    _initRegion: function _initRegion() {\n      var region = this.region;\n\n      if (!region) {\n        return;\n      }\n\n      var defaults = {\n        regionClass: this.regionClass\n      };\n      this._region = buildRegion(region, defaults);\n    },\n    getRegion: function getRegion() {\n      return this._region;\n    },\n    showView: function showView(view) {\n      var region = this.getRegion();\n\n      for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n        args[_key - 1] = arguments[_key];\n      }\n\n      region.show.apply(region, [view].concat(args));\n      return view;\n    },\n    getView: function getView() {\n      return this.getRegion().currentView;\n    }\n  });\n\n  var bindEvents$1 = proxy(bindEvents);\n  var unbindEvents$1 = proxy(unbindEvents);\n  var bindRequests$1 = proxy(bindRequests);\n  var unbindRequests$1 = proxy(unbindRequests);\n  var mergeOptions$1 = proxy(mergeOptions);\n  var getOption$1 = proxy(getOption);\n  var normalizeMethods$1 = proxy(normalizeMethods);\n  var triggerMethod$1 = proxy(triggerMethod); // Configuration\n\n  var setDomApi$1 = function setDomApi(mixin) {\n    CollectionView.setDomApi(mixin);\n    Region.setDomApi(mixin);\n    View.setDomApi(mixin);\n  };\n  var setRenderer$1 = function setRenderer(renderer) {\n    CollectionView.setRenderer(renderer);\n    View.setRenderer(renderer);\n  };\n  var backbone_marionette = {\n    View: View,\n    CollectionView: CollectionView,\n    MnObject: MarionetteObject,\n    Object: MarionetteObject,\n    Region: Region,\n    Behavior: Behavior,\n    Application: Application,\n    isEnabled: isEnabled,\n    setEnabled: setEnabled,\n    monitorViewEvents: monitorViewEvents,\n    Events: Events,\n    extend: extend,\n    DomApi: DomApi,\n    VERSION: version\n  };\n\n  exports.Application = Application;\n  exports.Behavior = Behavior;\n  exports.CollectionView = CollectionView;\n  exports.DomApi = DomApi;\n  exports.Events = Events;\n  exports.MnObject = MarionetteObject;\n  exports.Region = Region;\n  exports.VERSION = version;\n  exports.View = View;\n  exports.bindEvents = bindEvents$1;\n  exports.bindRequests = bindRequests$1;\n  exports.default = backbone_marionette;\n  exports.extend = extend;\n  exports.getOption = getOption$1;\n  exports.isEnabled = isEnabled;\n  exports.mergeOptions = mergeOptions$1;\n  exports.monitorViewEvents = monitorViewEvents;\n  exports.normalizeMethods = normalizeMethods$1;\n  exports.setDomApi = setDomApi$1;\n  exports.setEnabled = setEnabled;\n  exports.setRenderer = setRenderer$1;\n  exports.triggerMethod = triggerMethod$1;\n  exports.unbindEvents = unbindEvents$1;\n  exports.unbindRequests = unbindRequests$1;\n\n  Object.defineProperty(exports, '__esModule', { value: true });\n\n}));\nthis && this.Marionette && (this.Mn = this.Marionette);\n//# sourceMappingURL=backbone.marionette.js.map\n"
  },
  {
    "path": "license.txt",
    "content": "MarionetteJS is distributed under [MIT license](http://mutedsolutions.mit-license.org/).\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"backbone.marionette\",\n  \"description\": \"The Backbone Framework\",\n  \"version\": \"4.1.3\",\n  \"homepage\": \"https://marionettejs.com/\",\n  \"browser\": \"lib/backbone.marionette.js\",\n  \"main\": \"lib/backbone.marionette.js\",\n  \"module\": \"lib/backbone.marionette.esm.js\",\n  \"jsnext:main\": \"lib/backbone.marionette.esm.js\",\n  \"sideEffects\": false,\n  \"browserslist\": [\n    \">0.5%\",\n    \"Explorer >= 10\",\n    \"not op_mini all\"\n  ],\n  \"nyc\": {\n    \"require\": [\n      \"@babel/register\"\n    ],\n    \"sourceMap\": false,\n    \"instrument\": false\n  },\n  \"keywords\": [\n    \"backbone\",\n    \"plugin\",\n    \"marionette\",\n    \"composite\",\n    \"architecture\",\n    \"single\",\n    \"page\",\n    \"app\",\n    \"client\",\n    \"browser\"\n  ],\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"build\": \"rollup -c --noConflict\",\n    \"coverage\": \"cross-env NODE_ENV=test nyc mocha --config ./test/.mocharc.json && nyc report --reporter=html\",\n    \"coveralls\": \"yarn coverage && nyc report --reporter=text-lcov | coveralls\",\n    \"lint\": \"eslint --fix src/ && eslint --fix test/unit/\",\n    \"test\": \"yarn lint && mocha -w --config ./test/.mocharc.json\",\n    \"test-browser\": \"rollup -c ./test/rollup.config.js -w\",\n    \"test-cross-browser\": \"cross-env NODE_ENV=sauce rollup -c ./test/rollup.config.js\",\n    \"test-lodash\": \"USE_LODASH=1 mocha --config ./test/.mocharc.json\"\n  },\n  \"author\": {\n    \"name\": \"Derick Bailey\",\n    \"email\": \"derickbailey@gmail.com\",\n    \"url\": \"http://derickbailey.com/\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/marionettejs/backbone.marionette/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/marionettejs/backbone.marionette.git\"\n  },\n  \"github\": \"https://github.com/marionettejs/backbone.marionette\",\n  \"dependencies\": {\n    \"backbone.radio\": \"^2.0.0\"\n  },\n  \"peerDependencies\": {\n    \"backbone\": \"^1.3.3\",\n    \"underscore\": \"^1.8.3\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"7.4.3\",\n    \"@babel/preset-env\": \"7.4.3\",\n    \"@babel/register\": \"7.4.0\",\n    \"babel-plugin-istanbul\": \"^5.1.0\",\n    \"backbone\": \"^1.3.3\",\n    \"chai\": \"4.2.0\",\n    \"chai-jq\": \"0.0.9\",\n    \"coveralls\": \"3.0.3\",\n    \"cross-env\": \"5.2.0\",\n    \"easy-sauce\": \"0.4.2\",\n    \"eslint\": \"5.16.0\",\n    \"jquery\": \"3.4.0\",\n    \"jsdom\": \"14.0.0\",\n    \"lodash\": \"^4.17.11\",\n    \"mocha\": \"6.1.3\",\n    \"nyc\": \"13.3.0\",\n    \"rollup\": \"1.10.0\",\n    \"rollup-plugin-babel\": \"4.3.2\",\n    \"rollup-plugin-browsersync\": \"1.0.0\",\n    \"rollup-plugin-commonjs\": \"9.3.4\",\n    \"rollup-plugin-eslint\": \"5.1.0\",\n    \"rollup-plugin-json\": \"4.0.0\",\n    \"rollup-plugin-multi-entry\": \"2.1.0\",\n    \"rollup-plugin-node-globals\": \"1.4.0\",\n    \"rollup-plugin-node-resolve\": \"4.2.3\",\n    \"rollup-plugin-terser\": \"4.0.4\",\n    \"sinon\": \"7.3.1\",\n    \"sinon-chai\": \"3.3.0\",\n    \"underscore\": \"^1.8.3\"\n  }\n}\n"
  },
  {
    "path": "readme.md",
    "content": "<h1 align=\"center\">Marionette.js</h1>\n<p align=\"center\">\n  <img title=\"backbone marionette\" src='https://github.com/marionettejs/backbone.marionette/raw/master/marionette-logo.png' />\n</p>\n<p align=\"center\">The Backbone Framework</p>\n<p align=\"center\">\n  <a title='Build Status' href=\"https://travis-ci.org/marionettejs/backbone.marionette\">\n    <img src='https://secure.travis-ci.org/marionettejs/backbone.marionette.svg?branch=master' />\n  </a>\n  <a href='https://coveralls.io/r/marionettejs/backbone.marionette'>\n    <img src='https://img.shields.io/coveralls/marionettejs/backbone.marionette.svg' alt='Coverage Status' />\n  </a>\n  <a href='https://gitter.im/marionettejs/backbone.marionette?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge'>\n    <img src='https://badges.gitter.im/Join%20Chat.svg' alt='Gitter Chat' />\n  </a>\n</p>\n<p align=\"center\">\n  <img src='https://saucelabs.com/browser-matrix/marionettejs.svg' alt='Cross Browser Testing' />\n</p>\n\n# Marionette v5\n\nMarionette is dropping its dependency on Backbone. That library is available here: https://github.com/marionettejs/marionette\nUntil further notices changes to `backbone.marionette` will be limited to fixes.  All new feature work will take place on `marionette`.\n\n## Marionette v4\n\nMarionette 4 is now available! See our\n[upgrade notes](https://marionettejs.com/docs/v4.0.0/upgrade-v3-v4.html) for the differences between\nv3 and v4. Please let us know if you encounter any issues so we can resolve\nthem and\n[help us continue work on Marionette!](https://github.com/marionettejs/backbone.marionette/milestones/v4.x)\n\n## About Marionette\n\nMarionette is a composite application library for Backbone.js that\naims to simplify the construction of large scale JavaScript applications.\nIt is a collection of common design and implementation patterns found in\napplications.\n\n## Documentation\n\nAll of the documentation for Marionette can be found at\n\n##### [marionettejs.com/docs/current](http://marionettejs.com/docs/current)\n\n### App Architecture On Backbone's Building Blocks\n\nBackbone provides a great set of building blocks for our JavaScript\napplications. It gives us the core constructs that are needed to build\nsmall apps, organize jQuery DOM events, or create single page apps that\nsupport mobile devices and large scale enterprise needs. But Backbone is\nnot a complete framework. It's a set of building blocks. It leaves\nmuch of the application design, architecture and scalability to the\ndeveloper, including memory management, view management, and more.\n\nMarionette brings an application architecture to Backbone, along with\nbuilt in view management and memory management. It's designed to be a\nlightweight and flexible library of tools that sits on top of Backbone,\nproviding the framework for building a scalable application.\n\nLike Backbone itself, you're not required to use all of Marionette just\nbecause you want to use some of it. You can pick and choose which features\nyou want to use. This allows you to work with other Backbone\nframeworks and plugins easily. It also means that you are not required\nto engage in an all-or-nothing migration to begin using Marionette.\n\n### Chat with us\n\nFind us [on gitter](https://gitter.im/marionettejs/backbone.marionette).\n\nWe're happy to discuss design patterns and learn how you're using Marionette.\n\n\n### Key Benefits\n\n* Scalable: applications built in modules with event-driven architecture\n* Sensible defaults: Underscore templates are used for view rendering\n* Easily modifiable: works with the specific needs of your application\n* Reduce boilerplate: for all views, including specialized types\n* Create: application visuals at runtime with `Region` and `View` objects\n* Nested: `View`s and `CollectionView`s within visual regions\n* Built-in: memory management and zombie-killing for `View`s, `CollectionViews`a and `Region`s\n* Event-driven architecture: utilizing `Backbone.Radio`\n* Flexible: \"as-needed\" architecture allowing you to pick and choose what you need\n* And much, much more\n\n## Source Code and Downloads\n\nYou can\n[download the latest builds directly](https://github.com/marionettejs/backbone.marionette/tree/master/lib)\nor visit the [downloads section on the Marionette website](http://marionettejs.com#download)\nfor more downloading options.\n\n#### [MarionetteJS.com](http://marionettejs.com#download)\n\n### NPM and Bower\n\nMarionette is available via bower and npm:\n\n```bash\n# NPM\nnpm install backbone.marionette\n\n# Bower\nbower install marionette\n```\n\n## Release Notes And Upgrade Guide\n\n**Changelog**: For change logs and release notes, see the\n[changelog](changelog.md) file.\n\n**Upgrade Guide**: Be sure to read [the upgrade guide](upgradeGuide.md)\nfor information on upgrading to the latest version of Marionette.\n\n\n### Annotated Source Code\n\nThe source code for Marionette is heavily documented.\nYou can read the annotations for all the details of how Marionette works and advice on which methods to override.\n\n##### [View the annotated source code](http://marionettejs.com/annotated-src/backbone.marionette)\n\n## Compatibility and Requirements\n\nMarionetteJS currently works with the following libraries:\n\n* [jQuery](http://jquery.com) v1.8+\n* [Underscore](http://underscorejs.org) v1.8.3 - v1.9.x\n* [Backbone](http://backbonejs.org) v1.3.3\n* [Backbone.Radio](https://github.com/marionettejs/backbone.radio) v2.0.0+\n\nMarionette has not been tested against any other versions of these\nlibraries. You may or may not have success if you use a version other\nthan what is listed here.\n\n## How to Contribute\n\nIf you would like to contribute to Marionette's source code, please read\nthe [guidelines for pull requests and contributions](CONTRIBUTING.md).\nFollowing these guidelines will help make your contributions easier to\nbring into the next release.\n\n### [Github Issues](https://github.com/marionettejs/backbone.marionette/issues)\n\nReport issues with Marionette, submit pull requests to fix problems, or to\ncreate summarized and documented feature requests (preferably with pull\nrequests that implement the feature).\n"
  },
  {
    "path": "rollup.config.js",
    "content": "import babel from 'rollup-plugin-babel';\nimport { eslint } from 'rollup-plugin-eslint';\nimport json from 'rollup-plugin-json';\nimport { terser } from 'rollup-plugin-terser';\nimport { version } from './package.json';\n\nconst globals = {\n  'backbone': 'Backbone',\n  'underscore': '_',\n  'backbone.radio': 'Backbone.Radio'\n};\n\nconst now = new Date();\nconst year = now.getFullYear();\n\nconst banner = `/**\n* @license\n* MarionetteJS (Backbone.Marionette)\n* ----------------------------------\n* v${version}\n*\n* Copyright (c)${year} Derick Bailey, Muted Solutions, LLC.\n* Distributed under MIT license\n*\n* http://marionettejs.com\n*/\\n\\n`;\n\nconst footer = 'this && this.Marionette && (this.Mn = this.Marionette);';\n\nexport default [\n  {\n    input: 'src/backbone.marionette.js',\n    external: ['underscore', 'backbone', 'backbone.radio'],\n    output: [\n      {\n        file: 'lib/backbone.marionette.js',\n        format: 'umd',\n        name: 'Marionette',\n        exports: 'named',\n        sourcemap: true,\n        globals,\n        banner,\n        footer\n      },\n      {\n        file: 'lib/backbone.marionette.esm.js',\n        format: 'es'\n      }\n    ],\n    plugins: [\n      eslint({ exclude: ['package.json'] }),\n      json(),\n      babel()\n    ]\n  },\n  {\n    input: 'src/backbone.marionette.js',\n    external: ['underscore', 'backbone', 'backbone.radio'],\n    output: [\n      {\n        file: 'lib/backbone.marionette.min.js',\n        format: 'umd',\n        name: 'Marionette',\n        exports: 'named',\n        sourcemap: true,\n        globals,\n        banner,\n        footer\n      }\n    ],\n    plugins: [\n      json(),\n      babel(),\n      terser({ output: { comments: /@license/ }})\n    ]\n  }\n]\n"
  },
  {
    "path": "src/application.js",
    "content": "// Application\n// -----------\n\nimport _ from 'underscore';\nimport extend from './utils/extend';\nimport buildRegion from './common/build-region';\nimport CommonMixin from './mixins/common';\nimport DestroyMixin from './mixins/destroy';\nimport RadioMixin from './mixins/radio';\nimport Region from './region';\n\nconst ClassOptions = [\n  'channelName',\n  'radioEvents',\n  'radioRequests',\n  'region',\n  'regionClass'\n];\n\nconst Application = function(options) {\n  this._setOptions(options, ClassOptions);\n  this.cid = _.uniqueId(this.cidPrefix);\n  this._initRegion();\n  this._initRadio();\n  this.initialize.apply(this, arguments);\n};\n\nApplication.extend = extend;\n\n// Application Methods\n// --------------\n\n_.extend(Application.prototype, CommonMixin, DestroyMixin, RadioMixin, {\n  cidPrefix: 'mna',\n\n  // This is a noop method intended to be overridden\n  initialize() {},\n\n  // Kick off all of the application's processes.\n  start(options) {\n    this.triggerMethod('before:start', this, options);\n    this.triggerMethod('start', this, options);\n    return this;\n  },\n\n  regionClass: Region,\n\n  _initRegion() {\n    const region = this.region;\n\n    if (!region) { return; }\n\n    const defaults = {\n      regionClass: this.regionClass\n    };\n\n    this._region = buildRegion(region, defaults);\n  },\n\n  getRegion() {\n    return this._region;\n  },\n\n  showView(view, ...args) {\n    const region = this.getRegion();\n    region.show(view, ...args);\n    return view;\n  },\n\n  getView() {\n    return this.getRegion().currentView;\n  }\n});\n\nexport default Application;\n"
  },
  {
    "path": "src/backbone.marionette.js",
    "content": "import {version as VERSION} from '../package.json';\n\nimport proxy from './utils/proxy';\nimport extend from './utils/extend';\n\nimport {\n  bindEvents as _bindEvents,\n  unbindEvents as _unbindEvents\n} from './common/bind-events';\nimport {\n  bindRequests as _bindRequests,\n  unbindRequests as _unbindRequests\n} from './common/bind-requests';\nimport _getOption from './common/get-option';\nimport _mergeOptions from './common/merge-options';\nimport monitorViewEvents from './common/monitor-view-events';\nimport _normalizeMethods from './common/normalize-methods';\nimport _triggerMethod from './common/trigger-method';\n\nimport Events from './mixins/events';\n\nimport MnObject from './object';\nimport View from './view';\nimport CollectionView from './collection-view';\nimport Behavior from './behavior';\nimport Region from './region';\nimport Application from './application';\n\nimport DomApi from './config/dom';\n\nimport {\n  isEnabled,\n  setEnabled\n} from './config/features';\n\n// Utilities\n\nexport const bindEvents = proxy(_bindEvents);\nexport const unbindEvents = proxy(_unbindEvents);\nexport const bindRequests = proxy(_bindRequests);\nexport const unbindRequests = proxy(_unbindRequests);\nexport const mergeOptions = proxy(_mergeOptions);\nexport const getOption = proxy(_getOption);\nexport const normalizeMethods = proxy(_normalizeMethods);\nexport const triggerMethod = proxy(_triggerMethod);\n\n\n// Configuration\n\nexport const setDomApi = function(mixin) {\n  CollectionView.setDomApi(mixin);\n  Region.setDomApi(mixin);\n  View.setDomApi(mixin);\n};\nexport const setRenderer = function(renderer) {\n  CollectionView.setRenderer(renderer);\n  View.setRenderer(renderer);\n};\n\nexport {\n  View,\n  CollectionView,\n  MnObject,\n  Region,\n  Behavior,\n  Application,\n  isEnabled,\n  setEnabled,\n  monitorViewEvents,\n  Events,\n  extend,\n  DomApi,\n  VERSION\n};\n\nexport default {\n  View,\n  CollectionView,\n  MnObject,\n  Object: MnObject,\n  Region,\n  Behavior,\n  Application,\n  isEnabled,\n  setEnabled,\n  monitorViewEvents,\n  Events,\n  extend,\n  DomApi,\n  VERSION\n};\n"
  },
  {
    "path": "src/behavior.js",
    "content": "// Behavior\n// --------\n\n// A Behavior is an isolated set of DOM /\n// user interactions that can be mixed into any View.\n// Behaviors allow you to blackbox View specific interactions\n// into portable logical chunks, keeping your views simple and your code DRY.\n\nimport _ from 'underscore';\nimport extend from './utils/extend';\nimport getNamespacedEventName from './utils/get-namespaced-event-name';\nimport CommonMixin from './mixins/common';\nimport DelegateEntityEventsMixin from './mixins/delegate-entity-events';\nimport TriggersMixin from './mixins/triggers';\nimport UIMixin from './mixins/ui';\n\nconst ClassOptions = [\n  'collectionEvents',\n  'events',\n  'modelEvents',\n  'triggers',\n  'ui'\n];\n\nconst Behavior = function(options, view) {\n  // Setup reference to the view.\n  // this comes in handle when a behavior\n  // wants to directly talk up the chain\n  // to the view.\n  this.view = view;\n\n  this._setOptions(options, ClassOptions);\n  this.cid = _.uniqueId(this.cidPrefix);\n\n  // Construct an internal UI hash using the behaviors UI\n  // hash combined and overridden by the view UI hash.\n  // This allows the user to use UI hash elements defined\n  // in the parent view as well as those defined in the behavior.\n  // This order will help the reuse and share of a behavior\n  // between multiple views, while letting a view override\n  // a selector under an UI key.\n  this.ui = _.extend({}, _.result(this, 'ui'), _.result(view, 'ui'));\n\n  // Proxy view triggers\n  this.listenTo(view, 'all', this.triggerMethod);\n\n  this.initialize.apply(this, arguments);\n};\n\nBehavior.extend = extend;\n\n// Behavior Methods\n// --------------\n\n_.extend(Behavior.prototype, CommonMixin, DelegateEntityEventsMixin, TriggersMixin, UIMixin, {\n  cidPrefix: 'mnb',\n\n  // This is a noop method intended to be overridden\n  initialize() {},\n\n  // proxy behavior $ method to the view\n  // this is useful for doing jquery DOM lookups\n  // scoped to behaviors view.\n  $() {\n    return this.view.$.apply(this.view, arguments);\n  },\n\n  // Stops the behavior from listening to events.\n  destroy() {\n    this.stopListening();\n\n    this.view._removeBehavior(this);\n\n    this._deleteEntityEventHandlers();\n\n    return this;\n  },\n\n  proxyViewProperties() {\n    this.$el = this.view.$el;\n    this.el = this.view.el;\n\n    return this;\n  },\n\n  bindUIElements() {\n    this._bindUIElements();\n\n    return this;\n  },\n\n  unbindUIElements() {\n    this._unbindUIElements();\n\n    return this;\n  },\n\n  getUI(name) {\n    return this._getUI(name);\n  },\n\n  // Handle `modelEvents`, and `collectionEvents` configuration\n  delegateEntityEvents() {\n    this._delegateEntityEvents(this.view.model, this.view.collection);\n\n    return this;\n  },\n\n  undelegateEntityEvents() {\n    this._undelegateEntityEvents(this.view.model, this.view.collection);\n\n    return this;\n  },\n\n  _getEvents() {\n    if (!this.events) { return; }\n\n    // Normalize behavior events hash to allow\n    // a user to use the @ui. syntax.\n    const behaviorEvents = this.normalizeUIKeys(_.result(this, 'events'));\n\n    // binds the handler to the behavior and builds a unique eventName\n    return _.reduce(behaviorEvents, (events, behaviorHandler, key) => {\n      if (!_.isFunction(behaviorHandler)) {\n        behaviorHandler = this[behaviorHandler];\n      }\n      if (!behaviorHandler) { return events; }\n      key = getNamespacedEventName(key, this.cid);\n      events[key] = behaviorHandler.bind(this);\n      return events;\n    }, {});\n  },\n\n  // Internal method to build all trigger handlers for a given behavior\n  _getTriggers() {\n    if (!this.triggers) { return; }\n\n    // Normalize behavior triggers hash to allow\n    // a user to use the @ui. syntax.\n    const behaviorTriggers = this.normalizeUIKeys(_.result(this, 'triggers'));\n\n    return this._getViewTriggers(this.view, behaviorTriggers);\n  }\n});\n\nexport default Behavior;\n"
  },
  {
    "path": "src/child-view-container.js",
    "content": "import _ from 'underscore';\n\n// Provide a container to store, retrieve and\n// shut down child views.\nconst Container = function() {\n  this._init();\n};\n\n// Mix in methods from Underscore, for iteration, and other\n// collection related features.\n// Borrowing this code from Backbone.Collection:\n// https://github.com/jashkenas/backbone/blob/1.1.2/backbone.js#L962\nconst methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter',\n  'select', 'reject', 'every', 'all', 'some', 'any', 'include',\n  'contains', 'invoke', 'toArray', 'first', 'initial', 'rest',\n  'last', 'without', 'isEmpty', 'pluck', 'reduce', 'partition'];\n\n_.each(methods, function(method) {\n  Container.prototype[method] = function(...args) {\n    return _[method].apply(_, [this._views].concat(args));\n  };\n});\n\nfunction stringComparator(comparator, view) {\n  return view.model && view.model.get(comparator);\n}\n\n// Container Methods\n// -----------------\n\n_.extend(Container.prototype, {\n\n  // Initializes an empty container\n  _init() {\n    this._views = [];\n    this._viewsByCid = {};\n    this._indexByModel = {};\n    this._updateLength();\n  },\n\n  // Add a view to this container. Stores the view\n  // by `cid` and makes it searchable by the model\n  // cid (and model itself). Additionally it stores\n  // the view by index in the _views array\n  _add(view, index = this._views.length) {\n    this._addViewIndexes(view);\n\n    // add to end by default\n    this._views.splice(index, 0, view);\n\n    this._updateLength();\n  },\n\n  _addViewIndexes(view) {\n    // store the view\n    this._viewsByCid[view.cid] = view;\n\n    // index it by model\n    if (view.model) {\n      this._indexByModel[view.model.cid] = view;\n    }\n  },\n\n  // Sort (mutate) and return the array of the child views.\n  _sort(comparator, context) {\n    if (typeof comparator === 'string') {\n      comparator = _.partial(stringComparator, comparator);\n      return this._sortBy(comparator);\n    }\n\n    if (comparator.length === 1) {\n      return this._sortBy(comparator.bind(context));\n    }\n\n    return this._views.sort(comparator.bind(context));\n  },\n\n  // Makes `_.sortBy` mutate the array to match `this._views.sort`\n  _sortBy(comparator) {\n    const sortedViews = _.sortBy(this._views, comparator);\n\n    this._set(sortedViews);\n\n    return sortedViews;\n  },\n\n  // Replace array contents without overwriting the reference.\n  // Should not add/remove views\n  _set(views, shouldReset) {\n    this._views.length = 0;\n\n    this._views.push.apply(this._views, views.slice(0));\n\n    if (shouldReset) {\n      this._viewsByCid = {};\n      this._indexByModel = {};\n\n      _.each(views, this._addViewIndexes.bind(this));\n\n      this._updateLength();\n    }\n  },\n\n  // Swap views by index\n  _swap(view1, view2) {\n    const view1Index = this.findIndexByView(view1);\n    const view2Index = this.findIndexByView(view2);\n\n    if (view1Index === -1 || view2Index === -1) {\n      return;\n    }\n\n    const swapView = this._views[view1Index];\n    this._views[view1Index] = this._views[view2Index];\n    this._views[view2Index] = swapView;\n  },\n\n  // Find a view by the model that was attached to it.\n  // Uses the model's `cid` to find it.\n  findByModel(model) {\n    return this.findByModelCid(model.cid);\n  },\n\n  // Find a view by the `cid` of the model that was attached to it.\n  findByModelCid(modelCid) {\n    return this._indexByModel[modelCid];\n  },\n\n  // Find a view by index.\n  findByIndex(index) {\n    return this._views[index];\n  },\n\n  // Find the index of a view instance\n  findIndexByView(view) {\n    return this._views.indexOf(view);\n  },\n\n  // Retrieve a view by its `cid` directly\n  findByCid(cid) {\n    return this._viewsByCid[cid];\n  },\n\n  hasView(view) {\n    return !!this.findByCid(view.cid);\n  },\n\n  // Remove a view and clean up index references.\n  _remove(view) {\n    if (!this._viewsByCid[view.cid]) {\n      return;\n    }\n\n    // delete model index\n    if (view.model) {\n      delete this._indexByModel[view.model.cid];\n    }\n\n    // remove the view from the container\n    delete this._viewsByCid[view.cid];\n\n    const index = this.findIndexByView(view);\n    this._views.splice(index, 1);\n\n    this._updateLength();\n  },\n\n  // Update the `.length` attribute on this container\n  _updateLength() {\n    this.length = this._views.length;\n  }\n});\n\nexport default Container;\n"
  },
  {
    "path": "src/collection-view.js",
    "content": "// Collection View\n// ---------------\n\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport MarionetteError from './utils/error';\nimport { renderView, destroyView } from './common/view';\nimport monitorViewEvents from './common/monitor-view-events';\nimport ChildViewContainer from './child-view-container';\nimport Region from './region';\nimport ViewMixin from './mixins/view';\nimport { setDomApi } from './config/dom';\nimport { setRenderer } from './config/renderer';\n\nconst classErrorName = 'CollectionViewError';\n\nconst ClassOptions = [\n  'behaviors',\n  'childView',\n  'childViewContainer',\n  'childViewEventPrefix',\n  'childViewEvents',\n  'childViewOptions',\n  'childViewTriggers',\n  'collectionEvents',\n  'emptyView',\n  'emptyViewOptions',\n  'events',\n  'modelEvents',\n  'sortWithCollection',\n  'template',\n  'templateContext',\n  'triggers',\n  'ui',\n  'viewComparator',\n  'viewFilter'\n];\n\n// A view that iterates over a Backbone.Collection\n// and renders an individual child view for each model.\nconst CollectionView = Backbone.View.extend({\n  // flag for maintaining the sorted order of the collection\n  sortWithCollection: true,\n\n  // constructor\n  constructor(options) {\n    this._setOptions(options, ClassOptions);\n\n    monitorViewEvents(this);\n\n    this._initChildViewStorage();\n    this._initBehaviors();\n\n    Backbone.View.prototype.constructor.apply(this, arguments);\n\n    // Init empty region\n    this.getEmptyRegion();\n\n    this.delegateEntityEvents();\n\n    this._triggerEventOnBehaviors('initialize', this, options);\n  },\n\n  // Internal method to set up the `children` object for storing all of the child views\n  // `_children` represents all child views\n  // `children` represents only views filtered to be shown\n  _initChildViewStorage() {\n    this._children = new ChildViewContainer();\n    this.children = new ChildViewContainer();\n  },\n\n  // Create an region to show the emptyView\n  getEmptyRegion() {\n    const $emptyEl = this.$container || this.$el;\n\n    if (this._emptyRegion && !this._emptyRegion.isDestroyed()) {\n      this._emptyRegion._setElement($emptyEl[0]);\n      return this._emptyRegion;\n    }\n\n    this._emptyRegion = new Region({ el: $emptyEl[0], replaceElement: false });\n\n    this._emptyRegion._parentView = this;\n\n    return this._emptyRegion;\n  },\n\n  // Configured the initial events that the collection view binds to.\n  _initialEvents() {\n    if (this._isRendered) { return; }\n\n    this.listenTo(this.collection, {\n      'sort': this._onCollectionSort,\n      'reset': this._onCollectionReset,\n      'update': this._onCollectionUpdate\n    });\n  },\n\n  // Internal method. This checks for any changes in the order of the collection.\n  // If the index of any view doesn't match, it will re-sort.\n  _onCollectionSort(collection, { add, merge, remove }) {\n    if (!this.sortWithCollection || this.viewComparator === false) {\n      return;\n    }\n\n    // If the data is changing we will handle the sort later in `_onCollectionUpdate`\n    if (add || remove || merge) {\n      return;\n    }\n\n    // If the only thing happening here is sorting, sort.\n    this.sort();\n  },\n\n  _onCollectionReset() {\n    this._destroyChildren();\n\n    this._addChildModels(this.collection.models);\n\n    this.sort();\n  },\n\n  // Handle collection update model additions and  removals\n  _onCollectionUpdate(collection, options) {\n    const changes = options.changes;\n\n    // Remove first since it'll be a shorter array lookup.\n    const removedViews = changes.removed.length && this._removeChildModels(changes.removed);\n\n    this._addedViews = changes.added.length && this._addChildModels(changes.added);\n\n    this._detachChildren(removedViews);\n\n    this.sort();\n\n    // Destroy removed child views after all of the render is complete\n    this._removeChildViews(removedViews);\n  },\n\n  _removeChildModels(models) {\n    return _.reduce(models, (views, model) => {\n      const removeView = this._removeChildModel(model);\n\n      if (removeView) { views.push(removeView); }\n\n      return views;\n    }, []);\n  },\n\n  _removeChildModel(model) {\n    const view = this._children.findByModel(model);\n\n    if (view) { this._removeChild(view); }\n\n    return view;\n  },\n\n  _removeChild(view) {\n    this.triggerMethod('before:remove:child', this, view);\n\n    this.children._remove(view);\n    this._children._remove(view);\n\n    this.triggerMethod('remove:child', this, view);\n  },\n\n  // Added views are returned for consistency with _removeChildModels\n  _addChildModels(models) {\n    return _.map(models, this._addChildModel.bind(this));\n  },\n\n  _addChildModel(model) {\n    const view = this._createChildView(model);\n\n    this._addChild(view);\n\n    return view;\n  },\n\n  _createChildView(model) {\n    const ChildView = this._getChildView(model);\n    const childViewOptions = this._getChildViewOptions(model);\n    const view = this.buildChildView(model, ChildView, childViewOptions);\n\n    return view;\n  },\n\n  _addChild(view, index) {\n    this.triggerMethod('before:add:child', this, view);\n\n    this._setupChildView(view);\n    this._children._add(view, index);\n    this.children._add(view, index);\n\n    this.triggerMethod('add:child', this, view);\n  },\n\n  // Retrieve the `childView` class\n  // The `childView` property can be either a view class or a function that\n  // returns a view class. If it is a function, it will receive the model that\n  // will be passed to the view instance (created from the returned view class)\n  _getChildView(child) {\n    let childView = this.childView;\n\n    if (!childView) {\n      throw new MarionetteError({\n        name: classErrorName,\n        message: 'A \"childView\" must be specified',\n        url: 'marionette.collectionview.html#collectionviews-childview'\n      });\n    }\n\n    childView = this._getView(childView, child);\n\n    if (!childView) {\n      throw new MarionetteError({\n        name: classErrorName,\n        message: '\"childView\" must be a view class or a function that returns a view class',\n        url: 'marionette.collectionview.html#collectionviews-childview'\n      });\n    }\n\n    return childView;\n  },\n\n  // First check if the `view` is a view class (the common case)\n  // Then check if it's a function (which we assume that returns a view class)\n  _getView(view, child) {\n    if (view.prototype instanceof Backbone.View || view === Backbone.View) {\n      return view;\n    } else if (_.isFunction(view)) {\n      return view.call(this, child);\n    }\n  },\n\n  _getChildViewOptions(child) {\n    if (_.isFunction(this.childViewOptions)) {\n      return this.childViewOptions(child);\n    }\n\n    return this.childViewOptions;\n  },\n\n  // Build a `childView` for a model in the collection.\n  // Override to customize the build\n  buildChildView(child, ChildViewClass, childViewOptions) {\n    const options = _.extend({model: child}, childViewOptions);\n    return new ChildViewClass(options);\n  },\n\n  _setupChildView(view) {\n    monitorViewEvents(view);\n\n    // We need to listen for if a view is destroyed in a way other\n    // than through the CollectionView.\n    // If this happens we need to remove the reference to the view\n    // since once a view has been destroyed we can not reuse it.\n    view.on('destroy', this.removeChildView, this);\n\n    // set up the child view event forwarding\n    this._proxyChildViewEvents(view);\n  },\n\n  // used by ViewMixin's `_childViewEventHandler`\n  _getImmediateChildren() {\n    return this.children._views;\n  },\n\n  // Overriding Backbone.View's `setElement` to handle\n  // if an el was previously defined. If so, the view might be\n  // attached on setElement.\n  setElement() {\n    Backbone.View.prototype.setElement.apply(this, arguments);\n\n    this._isAttached = this._isElAttached();\n\n    return this;\n  },\n\n  // Render children views.\n  render() {\n    if (this._isDestroyed) { return this; }\n    this.triggerMethod('before:render', this);\n\n    this._destroyChildren();\n\n    if (this.collection) {\n      this._addChildModels(this.collection.models);\n      this._initialEvents();\n    }\n\n    const template = this.getTemplate();\n\n    if (template) {\n      this._renderTemplate(template);\n      this.bindUIElements();\n    }\n    this._getChildViewContainer();\n    this.sort();\n\n    this._isRendered = true;\n\n    this.triggerMethod('render', this);\n    return this;\n  },\n\n  // Get a container within the template to add the children within\n  _getChildViewContainer() {\n    const childViewContainer = _.result(this, 'childViewContainer');\n    this.$container = childViewContainer ? this.$(childViewContainer) : this.$el;\n\n    if (!this.$container.length) {\n      throw new MarionetteError({\n        name: classErrorName,\n        message: `The specified \"childViewContainer\" was not found: ${childViewContainer}`,\n        url: 'marionette.collectionview.html#defining-the-childviewcontainer'\n      });\n    }\n  },\n\n  // Sorts the children then filters and renders the results.\n  sort() {\n    this._sortChildren();\n\n    this.filter();\n\n    return this;\n  },\n\n  // Sorts views by viewComparator and sets the children to the new order\n  _sortChildren() {\n    if (!this._children.length) { return; }\n\n    let viewComparator = this.getComparator();\n\n    if (!viewComparator) { return; }\n\n    // If children are sorted prevent added to end perf\n    delete this._addedViews;\n\n    this.triggerMethod('before:sort', this);\n\n    this._children._sort(viewComparator, this);\n\n    this.triggerMethod('sort', this);\n  },\n\n  // Sets the view's `viewComparator` and applies the sort if the view is ready.\n  // To prevent the render pass `{ preventRender: true }` as the 2nd argument.\n  setComparator(comparator, {preventRender} = {}) {\n    const comparatorChanged = this.viewComparator !== comparator;\n    const shouldSort = comparatorChanged && !preventRender;\n\n    this.viewComparator = comparator;\n\n    if (shouldSort) {\n      this.sort();\n    }\n\n    return this;\n  },\n\n  // Clears the `viewComparator` and follows the same rules for rendering as `setComparator`.\n  removeComparator(options) {\n    return this.setComparator(null, options);\n  },\n\n  // If viewComparator is overridden it will be returned here.\n  // Additionally override this function to provide custom\n  // viewComparator logic\n  getComparator() {\n    if (this.viewComparator) { return this.viewComparator }\n\n    if (!this.sortWithCollection || this.viewComparator === false || !this.collection) {\n      return false;\n    }\n\n    return this._viewComparator;\n  },\n\n  // Default internal view comparator that order the views by\n  // the order of the collection\n  _viewComparator(view) {\n    return this.collection.indexOf(view.model);\n  },\n\n  // This method filters the children views and renders the results\n  filter() {\n    if (this._isDestroyed) { return this; }\n\n    this._filterChildren();\n\n    this._renderChildren();\n\n    return this;\n  },\n\n  _filterChildren() {\n    if (!this._children.length) { return; }\n\n    const viewFilter = this._getFilter();\n\n    if (!viewFilter) {\n      const shouldReset = this.children.length !== this._children.length;\n\n      this.children._set(this._children._views, shouldReset);\n\n      return;\n    }\n\n    // If children are filtered prevent added to end perf\n    delete this._addedViews;\n\n    this.triggerMethod('before:filter', this);\n\n    const attachViews = [];\n    const detachViews = [];\n\n    _.each(this._children._views, (view, key, children) => {\n      (viewFilter.call(this, view, key, children) ? attachViews : detachViews).push(view);\n    });\n\n    this._detachChildren(detachViews);\n\n    // reset children\n    this.children._set(attachViews, true);\n\n    this.triggerMethod('filter', this, attachViews, detachViews);\n  },\n\n  // This method returns a function for the viewFilter\n  _getFilter() {\n    const viewFilter = this.getFilter();\n\n    if (!viewFilter) { return false; }\n\n    if (_.isFunction(viewFilter)) {\n      return viewFilter;\n    }\n\n    // Support filter predicates `{ fooFlag: true }`\n    if (_.isObject(viewFilter)) {\n      const matcher = _.matches(viewFilter);\n      return function(view) {\n        return matcher(view.model && view.model.attributes);\n      };\n    }\n\n    // Filter by model attribute\n    if (_.isString(viewFilter)) {\n      return function(view) {\n        return view.model && view.model.get(viewFilter);\n      };\n    }\n\n    throw new MarionetteError({\n      name: classErrorName,\n      message: '\"viewFilter\" must be a function, predicate object literal, a string indicating a model attribute, or falsy',\n      url: 'marionette.collectionview.html#defining-the-viewfilter'\n    });\n  },\n\n  // Override this function to provide custom\n  // viewFilter logic\n  getFilter() {\n    return this.viewFilter;\n  },\n\n  // Sets the view's `viewFilter` and applies the filter if the view is ready.\n  // To prevent the render pass `{ preventRender: true }` as the 2nd argument.\n  setFilter(filter, {preventRender} = {}) {\n    const filterChanged = this.viewFilter !== filter;\n    const shouldRender = filterChanged && !preventRender;\n\n    this.viewFilter = filter;\n\n    if (shouldRender) {\n      this.filter();\n    }\n\n    return this;\n  },\n\n  // Clears the `viewFilter` and follows the same rules for rendering as `setFilter`.\n  removeFilter(options) {\n    return this.setFilter(null, options);\n  },\n\n  _detachChildren(detachingViews) {\n    _.each(detachingViews, this._detachChildView.bind(this));\n  },\n\n  _detachChildView(view) {\n    const shouldTriggerDetach = view._isAttached && this.monitorViewEvents !== false;\n    if (shouldTriggerDetach) {\n      view.triggerMethod('before:detach', view);\n    }\n\n    this.detachHtml(view);\n\n    if (shouldTriggerDetach) {\n      view._isAttached = false;\n      view.triggerMethod('detach', view);\n    }\n\n    view._isShown = false;\n  },\n\n  // Override this method to change how the collectionView detaches a child view\n  detachHtml(view) {\n    this.Dom.detachEl(view.el, view.$el);\n  },\n\n  _renderChildren() {\n    // If there are unrendered views prevent add to end perf\n    if (this._hasUnrenderedViews) {\n      delete this._addedViews;\n      delete this._hasUnrenderedViews;\n    }\n\n    const views = this._addedViews || this.children._views;\n\n    this.triggerMethod('before:render:children', this, views);\n\n    if (this.isEmpty()) {\n      this._showEmptyView();\n    } else {\n      this._destroyEmptyView();\n\n      const els = this._getBuffer(views);\n\n      this._attachChildren(els, views);\n    }\n\n    delete this._addedViews;\n\n    this.triggerMethod('render:children', this, views);\n  },\n\n  // Renders each view and creates a fragment buffer from them\n  _getBuffer(views) {\n    const elBuffer = this.Dom.createBuffer();\n\n    _.each(views, view => {\n      renderView(view);\n      // corresponds that view is shown in a Region or CollectionView\n      view._isShown = true;\n      this.Dom.appendContents(elBuffer, view.el, {_$contents: view.$el});\n    });\n\n    return elBuffer;\n  },\n\n  _attachChildren(els, views) {\n    const shouldTriggerAttach = this._isAttached && this.monitorViewEvents !== false;\n\n    views = shouldTriggerAttach ? views : [];\n\n    _.each(views, view => {\n      if (view._isAttached) { return; }\n      view.triggerMethod('before:attach', view);\n    });\n\n    this.attachHtml(els, this.$container);\n\n    _.each(views, view => {\n      if (view._isAttached) { return; }\n      view._isAttached = true;\n      view.triggerMethod('attach', view);\n    });\n  },\n\n  // Override this method to do something other than `.append`.\n  // You can attach any HTML at this point including the els.\n  attachHtml(els, $container) {\n    this.Dom.appendContents($container[0], els, {_$el: $container});\n  },\n\n  isEmpty() {\n    return !this.children.length;\n  },\n\n  _showEmptyView() {\n    const EmptyView = this._getEmptyView();\n\n    if (!EmptyView) {\n      return;\n    }\n\n    const options = this._getEmptyViewOptions();\n\n    const emptyRegion = this.getEmptyRegion();\n\n    emptyRegion.show(new EmptyView(options));\n  },\n\n  // Retrieve the empty view class\n  _getEmptyView() {\n    const emptyView = this.emptyView;\n\n    if (!emptyView) { return; }\n\n    return this._getView(emptyView);\n  },\n\n  // Remove the emptyView\n  _destroyEmptyView() {\n    const emptyRegion = this.getEmptyRegion();\n    // Only empty if a view is show so the region\n    // doesn't detach any other unrelated HTML\n    if (emptyRegion.hasView()) {\n      emptyRegion.empty();\n    }\n  },\n\n  //\n  _getEmptyViewOptions() {\n    const emptyViewOptions = this.emptyViewOptions || this.childViewOptions;\n\n    if (_.isFunction(emptyViewOptions)) {\n      return emptyViewOptions.call(this);\n    }\n\n    return emptyViewOptions;\n  },\n\n  swapChildViews(view1, view2) {\n    if (!this._children.hasView(view1) || !this._children.hasView(view2)) {\n      throw new MarionetteError({\n        name: classErrorName,\n        message: 'Both views must be children of the collection view to swap.',\n        url: 'marionette.collectionview.html#swapping-child-views'\n      });\n    }\n\n    this._children._swap(view1, view2);\n    this.Dom.swapEl(view1.el, view2.el);\n\n    // If the views are not filtered the same, refilter\n    if (this.children.hasView(view1) !== this.children.hasView(view2)) {\n      this.filter();\n    } else {\n      this.children._swap(view1, view2);\n    }\n\n    return this;\n  },\n\n  // Render the child's view and add it to the HTML for the collection view at a given index, based on the current sort\n  addChildView(view, index, options = {}) {\n    if (!view || view._isDestroyed) {\n      return view;\n    }\n\n    if (view._isShown) {\n      throw new MarionetteError({\n        name: classErrorName,\n        message: 'View is already shown in a Region or CollectionView',\n        url: 'marionette.region.html#showing-a-view'\n      });\n    }\n\n    if (_.isObject(index)) {\n      options = index;\n    }\n\n    // If options has defined index we should use it\n    if (options.index != null) {\n      index = options.index;\n    }\n\n    if (!this._isRendered) {\n      this.render();\n    }\n\n    this._addChild(view, index);\n\n    if (options.preventRender) {\n      this._hasUnrenderedViews = true;\n      return view;\n    }\n\n    const hasIndex = (typeof index !== 'undefined');\n    const isAddedToEnd = !hasIndex || index >= this._children.length;\n\n    // Only cache views if added to the end and there is no unrendered views\n    if (isAddedToEnd && !this._hasUnrenderedViews) {\n      this._addedViews = [view];\n    }\n\n    if (hasIndex) {\n      this._renderChildren();\n    } else {\n      this.sort();\n    }\n\n    return view;\n  },\n\n  // Detach a view from the children.  Best used when adding a\n  // childView from `addChildView`\n  detachChildView(view) {\n    this.removeChildView(view, { shouldDetach: true });\n\n    return view;\n  },\n\n  // Remove the child view and destroy it.  Best used when adding a\n  // childView from `addChildView`\n  // The options argument is for internal use only\n  removeChildView(view, options) {\n    if (!view) {\n      return view;\n    }\n\n    this._removeChildView(view, options);\n\n    this._removeChild(view);\n\n    if (this.isEmpty()) {\n      this._showEmptyView();\n    }\n\n    return view;\n  },\n\n  _removeChildViews(views) {\n    _.each(views, this._removeChildView.bind(this));\n  },\n\n  _removeChildView(view, {shouldDetach} = {}) {\n    view.off('destroy', this.removeChildView, this);\n\n    if (shouldDetach) {\n      this._detachChildView(view);\n    } else {\n      this._destroyChildView(view);\n    }\n\n    this.stopListening(view);\n  },\n\n  _destroyChildView(view) {\n    if (view._isDestroyed) {\n      return;\n    }\n\n    const shouldDisableEvents = this.monitorViewEvents === false;\n    destroyView(view, shouldDisableEvents);\n  },\n\n  // called by ViewMixin destroy\n  _removeChildren() {\n    this._destroyChildren();\n    const emptyRegion = this.getEmptyRegion();\n    emptyRegion.destroy();\n    delete this._addedViews;\n  },\n\n  // Destroy the child views that this collection view is holding on to, if any\n  _destroyChildren() {\n    if (!this._children.length) {\n      return;\n    }\n\n    this.triggerMethod('before:destroy:children', this);\n    if (this.monitorViewEvents === false) {\n      this.Dom.detachContents(this.el, this.$el);\n    }\n\n    this._removeChildViews(this._children._views);\n\n    // After all children have been destroyed re-init the container\n    this._children._init();\n    this.children._init();\n\n    this.triggerMethod('destroy:children', this);\n  }\n}, {\n  setDomApi,\n  setRenderer\n});\n\n_.extend(CollectionView.prototype, ViewMixin);\n\nexport default CollectionView;\n"
  },
  {
    "path": "src/common/bind-events.js",
    "content": "// Bind Entity Events & Unbind Entity Events\n// -----------------------------------------\n//\n// These methods are used to bind/unbind a backbone \"entity\" (e.g. collection/model)\n// to methods on a target object.\n//\n// The first parameter, `target`, must have the Backbone.Events module mixed in.\n//\n// The second parameter is the `entity` (Backbone.Model, Backbone.Collection or\n// any object that has Backbone.Events mixed in) to bind the events from.\n//\n// The third parameter is a hash of { \"event:name\": \"eventHandler\" }\n// configuration. Multiple handlers can be separated by a space. A\n// function can be supplied instead of a string handler name.\n\nimport _ from 'underscore';\nimport normalizeMethods from './normalize-methods';\nimport MarionetteError from '../utils/error';\n\nfunction normalizeBindings(context, bindings) {\n  if (!_.isObject(bindings)) {\n    throw new MarionetteError({\n      message: 'Bindings must be an object.',\n      url: 'common.html#bindevents'\n    });\n  }\n\n  return normalizeMethods.call(context, bindings);\n}\n\nfunction bindEvents(entity, bindings) {\n  if (!entity || !bindings) { return this; }\n\n  this.listenTo(entity, normalizeBindings(this, bindings));\n\n  return this;\n}\n\nfunction unbindEvents(entity, bindings) {\n  if (!entity) { return this; }\n\n  if (!bindings) {\n    this.stopListening(entity);\n    return this;\n  }\n\n  this.stopListening(entity, normalizeBindings(this, bindings));\n\n  return this;\n}\n\n// Export Public API\nexport {\n  bindEvents,\n  unbindEvents\n};\n"
  },
  {
    "path": "src/common/bind-requests.js",
    "content": "// Bind/Unbind Radio Requests\n// -----------------------------------------\n//\n// These methods are used to bind/unbind a backbone.radio request\n// to methods on a target object.\n//\n// The first parameter, `target`, will set the context of the reply method\n//\n// The second parameter is the `Radio.channel` to bind the reply to.\n//\n// The third parameter is a hash of { \"request:name\": \"replyHandler\" }\n// configuration. A function can be supplied instead of a string handler name.\n\nimport _ from 'underscore';\nimport normalizeMethods from './normalize-methods';\nimport MarionetteError from '../utils/error';\n\nfunction normalizeBindings(context, bindings) {\n  if (!_.isObject(bindings)) {\n    throw new MarionetteError({\n      message: 'Bindings must be an object.',\n      url: 'common.html#bindrequests'\n    });\n  }\n\n  return normalizeMethods.call(context, bindings);\n}\n\nfunction bindRequests(channel, bindings) {\n  if (!channel || !bindings) { return this; }\n\n  channel.reply(normalizeBindings(this, bindings), this);\n\n  return this;\n}\n\nfunction unbindRequests(channel, bindings) {\n  if (!channel) { return this; }\n\n  if (!bindings) {\n    channel.stopReplying(null, null, this);\n    return this;\n  }\n\n  channel.stopReplying(normalizeBindings(this, bindings), this);\n\n  return this;\n}\n\nexport {\n  bindRequests,\n  unbindRequests\n};\n"
  },
  {
    "path": "src/common/build-region.js",
    "content": "import _ from 'underscore';\nimport MarionetteError from '../utils/error';\nimport Region from '../region';\n\n// return the region instance from the definition\nexport default function(definition, defaults) {\n  if (definition instanceof Region) {\n    return definition;\n  }\n\n  if (_.isString(definition)) {\n    return buildRegionFromObject(defaults, { el: definition });\n  }\n\n  if (_.isFunction(definition)) {\n    return buildRegionFromObject(defaults, { regionClass: definition });\n  }\n\n  if (_.isObject(definition)) {\n    return buildRegionFromObject(defaults, definition);\n  }\n\n  throw new MarionetteError({\n    message: 'Improper region configuration type.',\n    url: 'marionette.region.html#defining-regions'\n  });\n}\n\nfunction buildRegionFromObject(defaults, definition) {\n  const options = _.extend({}, defaults, definition);\n\n  const RegionClass = options.regionClass\n\n  delete options.regionClass;\n\n  return new RegionClass(options);\n}\n"
  },
  {
    "path": "src/common/get-option.js",
    "content": "// Marionette.getOption\n// --------------------\n\n// Retrieve an object, function or other value from the\n// object or its `options`, with `options` taking precedence.\nconst getOption = function(optionName) {\n  if (!optionName) { return; }\n  if (this.options && (this.options[optionName] !== undefined)) {\n    return this.options[optionName];\n  } else {\n    return this[optionName];\n  }\n};\n\nexport default getOption;\n"
  },
  {
    "path": "src/common/merge-options.js",
    "content": "import _ from 'underscore';\n\n// Merge `keys` from `options` onto `this`\nconst mergeOptions = function(options, keys) {\n  if (!options) { return; }\n\n  _.each(keys, (key) => {\n    const option = options[key];\n    if (option !== undefined) {\n      this[key] = option;\n    }\n  });\n};\n\nexport default mergeOptions;\n"
  },
  {
    "path": "src/common/monitor-view-events.js",
    "content": "// DOM Refresh\n// -----------\n\nimport _ from 'underscore';\n\n// Trigger method on children unless a pure Backbone.View\nfunction triggerMethodChildren(view, event, shouldTrigger) {\n  if (!view._getImmediateChildren) { return; }\n  _.each(view._getImmediateChildren(), child => {\n    if (!shouldTrigger(child)) { return; }\n    child.triggerMethod(event, child);\n  });\n}\n\nfunction shouldTriggerAttach(view) {\n  return !view._isAttached;\n}\n\nfunction shouldAttach(view) {\n  if (!shouldTriggerAttach(view)) { return false; }\n  view._isAttached = true;\n  return true;\n}\n\nfunction shouldTriggerDetach(view) {\n  return view._isAttached;\n}\n\nfunction shouldDetach(view) {\n  view._isAttached = false;\n  return true;\n}\n\nfunction triggerDOMRefresh(view) {\n  if (view._isAttached && view._isRendered) {\n    view.triggerMethod('dom:refresh', view);\n  }\n}\n\nfunction triggerDOMRemove(view) {\n  if (view._isAttached && view._isRendered) {\n    view.triggerMethod('dom:remove', view);\n  }\n}\n\nfunction handleBeforeAttach() {\n  triggerMethodChildren(this, 'before:attach', shouldTriggerAttach);\n}\n\nfunction handleAttach() {\n  triggerMethodChildren(this, 'attach', shouldAttach);\n  triggerDOMRefresh(this);\n}\n\nfunction handleBeforeDetach() {\n  triggerMethodChildren(this, 'before:detach', shouldTriggerDetach);\n  triggerDOMRemove(this);\n}\n\nfunction handleDetach() {\n  triggerMethodChildren(this, 'detach', shouldDetach);\n}\n\nfunction handleBeforeRender() {\n  triggerDOMRemove(this);\n}\n\nfunction handleRender() {\n  triggerDOMRefresh(this);\n}\n\n// Monitor a view's state, propagating attach/detach events to children and firing dom:refresh\n// whenever a rendered view is attached or an attached view is rendered.\nfunction monitorViewEvents(view) {\n  if (view._areViewEventsMonitored || view.monitorViewEvents === false) { return; }\n\n  view._areViewEventsMonitored = true;\n\n  view.on({\n    'before:attach': handleBeforeAttach,\n    'attach': handleAttach,\n    'before:detach': handleBeforeDetach,\n    'detach': handleDetach,\n    'before:render': handleBeforeRender,\n    'render': handleRender\n  });\n}\n\nexport default monitorViewEvents;\n"
  },
  {
    "path": "src/common/normalize-methods.js",
    "content": "import _ from 'underscore';\n\n// Marionette.normalizeMethods\n// ----------------------\n\n// Pass in a mapping of events => functions or function names\n// and return a mapping of events => functions\nconst normalizeMethods = function(hash) {\n  if (!hash) { return }\n\n  return _.reduce(hash, (normalizedHash, method, name) => {\n    if (!_.isFunction(method)) {\n      method = this[method];\n    }\n    if (method) {\n      normalizedHash[name] = method;\n    }\n    return normalizedHash;\n  }, {});\n};\n\nexport default normalizeMethods;\n"
  },
  {
    "path": "src/common/trigger-method.js",
    "content": "// Trigger Method\n// --------------\n\nimport _ from 'underscore';\nimport getOption from './get-option';\n\n// split the event name on the \":\"\nconst splitter = /(^|:)(\\w)/gi;\n\n// Only calc getOnMethodName once\nconst methodCache = {};\n\n// take the event section (\"section1:section2:section3\")\n// and turn it in to uppercase name onSection1Section2Section3\nfunction getEventName(match, prefix, eventName) {\n  return eventName.toUpperCase();\n}\n\nconst getOnMethodName = function(event) {\n  if (!methodCache[event]) {\n    methodCache[event] = 'on' + event.replace(splitter, getEventName);\n  }\n\n  return methodCache[event];\n};\n\n// Trigger an event and/or a corresponding method name. Examples:\n//\n// `this.triggerMethod(\"foo\")` will trigger the \"foo\" event and\n// call the \"onFoo\" method.\n//\n// `this.triggerMethod(\"foo:bar\")` will trigger the \"foo:bar\" event and\n// call the \"onFooBar\" method.\nexport default function triggerMethod(event) {\n  // get the method name from the event name\n  const methodName = getOnMethodName(event);\n  const method = getOption.call(this, methodName);\n  let result;\n\n  // call the onMethodName if it exists\n  if (_.isFunction(method)) {\n    // pass all args, except the event name\n    result = method.apply(this, _.drop(arguments));\n  }\n\n  // trigger the event\n  this.trigger.apply(this, arguments);\n\n  return result;\n}\n"
  },
  {
    "path": "src/common/view.js",
    "content": "export function renderView(view) {\n  if (view._isRendered) {\n    return;\n  }\n\n  if (!view.supportsRenderLifecycle) {\n    view.triggerMethod('before:render', view);\n  }\n\n  view.render();\n  view._isRendered = true;\n\n  if (!view.supportsRenderLifecycle) {\n    view.triggerMethod('render', view);\n  }\n}\n\nexport function destroyView(view, disableDetachEvents) {\n  if (view.destroy) {\n    // Attach flag for public destroy function internal check\n    view._disableDetachEvents = disableDetachEvents;\n    view.destroy();\n    return;\n  }\n\n  // Destroy for non-Marionette Views\n  if (!view.supportsDestroyLifecycle) {\n    view.triggerMethod('before:destroy', view);\n  }\n\n  const shouldTriggerDetach = view._isAttached && !disableDetachEvents;\n\n  if (shouldTriggerDetach) {\n    view.triggerMethod('before:detach', view);\n  }\n\n  view.remove();\n\n  if (shouldTriggerDetach) {\n    view._isAttached = false;\n    view.triggerMethod('detach', view);\n  }\n\n  view._isDestroyed = true;\n\n  if (!view.supportsDestroyLifecycle) {\n    view.triggerMethod('destroy', view);\n  }\n}\n"
  },
  {
    "path": "src/config/dom.js",
    "content": "// DomApi\n//  ---------\nimport _ from 'underscore';\nimport Backbone from 'backbone';\n\n// Performant method for returning the jQuery instance\nfunction getEl(el) {\n  return el instanceof Backbone.$ ? el : Backbone.$(el);\n}\n\n// Static setter\nexport function setDomApi(mixin) {\n  this.prototype.Dom = _.extend({}, this.prototype.Dom, mixin);\n  return this;\n}\n\nexport default {\n\n  // Returns a new HTML DOM node instance\n  createBuffer() {\n    return document.createDocumentFragment();\n  },\n\n  // Returns the document element for a given DOM element\n  getDocumentEl(el) {\n    return el.ownerDocument.documentElement;\n  },\n\n  // Lookup the `selector` string\n  // Selector may also be a DOM element\n  // Returns an array-like object of nodes\n  getEl(selector) {\n    return getEl(selector);\n  },\n\n  // Finds the `selector` string with the el\n  // Returns an array-like object of nodes\n  findEl(el, selector) {\n    return getEl(el).find(selector);\n  },\n\n  // Returns true if the el contains the node childEl\n  hasEl(el, childEl) {\n    return el.contains(childEl && childEl.parentNode);\n  },\n\n  // Detach `el` from the DOM without removing listeners\n  detachEl(el, _$el = getEl(el)) {\n    _$el.detach();\n  },\n\n  // Remove `oldEl` from the DOM and put `newEl` in its place\n  replaceEl(newEl, oldEl) {\n    if (newEl === oldEl) {\n      return;\n    }\n\n    const parent = oldEl.parentNode;\n\n    if (!parent) {\n      return;\n    }\n\n    parent.replaceChild(newEl, oldEl);\n  },\n\n  // Swaps the location of `el1` and `el2` in the DOM\n  swapEl(el1, el2) {\n    if (el1 === el2) {\n      return;\n    }\n\n    const parent1 = el1.parentNode;\n    const parent2 = el2.parentNode;\n\n    if (!parent1 || !parent2) {\n      return;\n    }\n\n    const next1 = el1.nextSibling;\n    const next2 = el2.nextSibling;\n\n    parent1.insertBefore(el2, next1);\n    parent2.insertBefore(el1, next2);\n  },\n\n  // Replace the contents of `el` with the HTML string of `html`\n  setContents(el, html, _$el = getEl(el)) {\n    _$el.html(html);\n  },\n\n  // Takes the DOM node `el` and appends the DOM node `contents`\n  // to the end of the element's contents.\n  appendContents(el, contents, {_$el = getEl(el), _$contents = getEl(contents)} = {}) {\n    _$el.append(_$contents);\n  },\n\n  // Does the el have child nodes\n  hasContents(el) {\n    return !!el && el.hasChildNodes();\n  },\n\n  // Remove the inner contents of `el` from the DOM while leaving\n  // `el` itself in the DOM.\n  detachContents(el, _$el = getEl(el)) {\n    _$el.contents().detach();\n  }\n};\n"
  },
  {
    "path": "src/config/features.js",
    "content": "// Add Feature flags here\n// e.g. 'class' => false\nconst FEATURES = {\n  childViewEventPrefix: false,\n  triggersStopPropagation: true,\n  triggersPreventDefault: true,\n  DEV_MODE: false\n};\n\nfunction isEnabled(name) {\n  return !!FEATURES[name];\n}\n\nfunction setEnabled(name, state) {\n  return FEATURES[name] = state;\n}\n\nexport {\n  FEATURES,\n  setEnabled,\n  isEnabled\n};\n"
  },
  {
    "path": "src/config/renderer.js",
    "content": "// Static setter for the renderer\nexport function setRenderer(renderer) {\n  this.prototype._renderHtml = renderer;\n  return this;\n}\n"
  },
  {
    "path": "src/mixins/behaviors.js",
    "content": "import _ from 'underscore';\nimport MarionetteError from '../utils/error';\nimport _invoke from '../utils/invoke';\n\n// MixinOptions\n// - behaviors\n\n// Takes care of getting the behavior class\n// given options and a key.\n// If a user passes in options.behaviorClass\n// default to using that.\n// If a user passes in a Behavior Class directly, use that\n// Otherwise an error is thrown\nfunction getBehaviorClass(options) {\n  if (options.behaviorClass) {\n    return { BehaviorClass: options.behaviorClass, options };\n  }\n\n  //treat functions as a Behavior constructor\n  if (_.isFunction(options)) {\n    return { BehaviorClass: options, options: {} };\n  }\n\n  throw new MarionetteError({\n    message: 'Unable to get behavior class. A Behavior constructor should be passed directly or as behaviorClass property of options',\n    url: 'marionette.behavior.html#defining-and-attaching-behaviors'\n  });\n}\n\n// Iterate over the behaviors object, for each behavior\n// instantiate it and get its grouped behaviors.\n// This accepts a list of behaviors in either an object or array form\nfunction parseBehaviors(view, behaviors, allBehaviors) {\n  return _.reduce(behaviors, (reducedBehaviors, behaviorDefiniton) => {\n    const { BehaviorClass, options } = getBehaviorClass(behaviorDefiniton);\n    const behavior = new BehaviorClass(options, view);\n    reducedBehaviors.push(behavior);\n\n    return parseBehaviors(view, _.result(behavior, 'behaviors'), reducedBehaviors);\n  }, allBehaviors);\n}\n\nexport default {\n  _initBehaviors() {\n    this._behaviors = parseBehaviors(this, _.result(this, 'behaviors'), []);\n  },\n\n  _getBehaviorTriggers() {\n    const triggers = _invoke(this._behaviors, '_getTriggers');\n    return _.reduce(triggers, function(memo, _triggers) {\n      return _.extend(memo, _triggers);\n    }, {});\n  },\n\n  _getBehaviorEvents() {\n    const events = _invoke(this._behaviors, '_getEvents');\n    return _.reduce(events, function(memo, _events) {\n      return _.extend(memo, _events);\n    }, {});\n  },\n\n  // proxy behavior $el to the view's $el.\n  _proxyBehaviorViewProperties() {\n    _invoke(this._behaviors, 'proxyViewProperties');\n  },\n\n  // delegate modelEvents and collectionEvents\n  _delegateBehaviorEntityEvents() {\n    _invoke(this._behaviors, 'delegateEntityEvents');\n  },\n\n  // undelegate modelEvents and collectionEvents\n  _undelegateBehaviorEntityEvents() {\n    _invoke(this._behaviors, 'undelegateEntityEvents');\n  },\n\n  _destroyBehaviors(options) {\n    // Call destroy on each behavior after\n    // destroying the view.\n    // This unbinds event listeners\n    // that behaviors have registered for.\n    _invoke(this._behaviors, 'destroy', options);\n  },\n\n  // Remove a behavior\n  _removeBehavior(behavior) {\n    // Don't worry about the clean up if the view is destroyed\n    if (this._isDestroyed) { return; }\n\n    // Remove behavior-only triggers and events\n    this.undelegate(`.trig${ behavior.cid } .${ behavior.cid }`);\n\n    this._behaviors = _.without(this._behaviors, behavior);\n  },\n\n  _bindBehaviorUIElements() {\n    _invoke(this._behaviors, 'bindUIElements');\n  },\n\n  _unbindBehaviorUIElements() {\n    _invoke(this._behaviors, 'unbindUIElements');\n  },\n\n  _triggerEventOnBehaviors(eventName, view, options) {\n    _invoke(this._behaviors, 'triggerMethod', eventName, view, options);\n  }\n};\n"
  },
  {
    "path": "src/mixins/common.js",
    "content": "import _ from 'underscore';\nimport Backbone from 'backbone';\n\nimport getOption from '../common/get-option';\nimport mergeOptions from '../common/merge-options';\nimport normalizeMethods from '../common/normalize-methods';\nimport triggerMethod from '../common/trigger-method';\nimport {\n  bindEvents,\n  unbindEvents\n} from '../common/bind-events';\nimport {\n  bindRequests,\n  unbindRequests\n} from '../common/bind-requests';\n\nconst CommonMixin = {\n\n  // Imports the \"normalizeMethods\" to transform hashes of\n  // events=>function references/names to a hash of events=>function references\n  normalizeMethods,\n\n  _setOptions(options, classOptions) {\n    this.options = _.extend({}, _.result(this, 'options'), options);\n    this.mergeOptions(options, classOptions);\n  },\n\n  // A handy way to merge passed-in options onto the instance\n  mergeOptions,\n\n  // Enable getting options from this or this.options by name.\n  getOption,\n\n  // Enable binding view's events from another entity.\n  bindEvents,\n\n  // Enable unbinding view's events from another entity.\n  unbindEvents,\n\n  // Enable binding view's requests.\n  bindRequests,\n\n  // Enable unbinding view's requests.\n  unbindRequests,\n\n  triggerMethod\n};\n\n_.extend(CommonMixin, Backbone.Events);\n\nexport default CommonMixin;\n"
  },
  {
    "path": "src/mixins/delegate-entity-events.js",
    "content": "import _ from 'underscore';\n\n// MixinOptions\n// - collectionEvents\n// - modelEvents\n\nexport default {\n  // Handle `modelEvents`, and `collectionEvents` configuration\n  _delegateEntityEvents(model, collection) {\n    if (model) {\n      this._modelEvents = _.result(this, 'modelEvents');\n      this.bindEvents(model, this._modelEvents);\n    }\n\n    if (collection) {\n      this._collectionEvents = _.result(this, 'collectionEvents');\n      this.bindEvents(collection, this._collectionEvents);\n    }\n  },\n\n  // Remove any previously delegate entity events\n  _undelegateEntityEvents(model, collection) {\n    if (this._modelEvents) {\n      this.unbindEvents(model, this._modelEvents);\n      delete this._modelEvents;\n    }\n\n    if (this._collectionEvents) {\n      this.unbindEvents(collection, this._collectionEvents);\n      delete this._collectionEvents;\n    }\n  },\n\n  // Remove cached event handlers\n  _deleteEntityEventHandlers() {\n    delete this._modelEvents;\n    delete this._collectionEvents;\n  }\n};\n"
  },
  {
    "path": "src/mixins/destroy.js",
    "content": "export default {\n  _isDestroyed: false,\n\n  isDestroyed() {\n    return this._isDestroyed;\n  },\n\n  destroy(options) {\n    if (this._isDestroyed) { return this; }\n\n    this.triggerMethod('before:destroy', this, options);\n    this._isDestroyed = true;\n    this.triggerMethod('destroy', this, options);\n    this.stopListening();\n\n    return this;\n  }\n};\n"
  },
  {
    "path": "src/mixins/events.js",
    "content": "import triggerMethod from '../common/trigger-method';\n\nexport default {\n  triggerMethod\n}\n"
  },
  {
    "path": "src/mixins/radio.js",
    "content": "import _ from 'underscore';\nimport Radio from 'backbone.radio';\nimport MarionetteError from '../utils/error';\n\n// MixinOptions\n// - channelName\n// - radioEvents\n// - radioRequests\n\nexport default {\n\n  _initRadio() {\n    const channelName = _.result(this, 'channelName');\n\n    if (!channelName) {\n      return;\n    }\n\n    /* istanbul ignore next */\n    if (!Radio) {\n      throw new MarionetteError({\n        message: 'The dependency \"backbone.radio\" is missing.',\n        url: 'backbone.radio.html#marionette-integration'\n      });\n    }\n\n    const channel = this._channel = Radio.channel(channelName);\n\n    const radioEvents = _.result(this, 'radioEvents');\n    this.bindEvents(channel, radioEvents);\n\n    const radioRequests = _.result(this, 'radioRequests');\n    this.bindRequests(channel, radioRequests);\n\n    this.on('destroy', this._destroyRadio);\n  },\n\n  _destroyRadio() {\n    this._channel.stopReplying(null, null, this);\n  },\n\n  getChannel() {\n    return this._channel;\n  }\n};\n"
  },
  {
    "path": "src/mixins/regions.js",
    "content": "import _ from 'underscore';\nimport _invoke from '../utils/invoke';\nimport buildRegion from '../common/build-region';\nimport Region from '../region';\n\n// MixinOptions\n// - regions\n// - regionClass\n\nexport default {\n  regionClass: Region,\n\n  // Internal method to initialize the regions that have been defined in a\n  // `regions` attribute on this View.\n  _initRegions() {\n\n    // init regions hash\n    this.regions = this.regions || {};\n    this._regions = {};\n\n    this.addRegions(_.result(this, 'regions'));\n  },\n\n  // Internal method to re-initialize all of the regions by updating\n  // the `el` that they point to\n  _reInitRegions() {\n    _invoke(this._regions, 'reset');\n  },\n\n  // Add a single region, by name, to the View\n  addRegion(name, definition) {\n    const regions = {};\n    regions[name] = definition;\n    return this.addRegions(regions)[name];\n  },\n\n  // Add multiple regions as a {name: definition, name2: def2} object literal\n  addRegions(regions) {\n    // If there's nothing to add, stop here.\n    if (_.isEmpty(regions)) {\n      return;\n    }\n\n    // Normalize region selectors hash to allow\n    // a user to use the @ui. syntax.\n    regions = this.normalizeUIValues(regions, 'el');\n\n    // Add the regions definitions to the regions property\n    this.regions = _.extend({}, this.regions, regions);\n\n    return this._addRegions(regions);\n  },\n\n  // internal method to build and add regions\n  _addRegions(regionDefinitions) {\n    const defaults = {\n      regionClass: this.regionClass,\n      parentEl: _.partial(_.result, this, 'el')\n    };\n\n    return _.reduce(regionDefinitions, (regions, definition, name) => {\n      regions[name] = buildRegion(definition, defaults);\n      this._addRegion(regions[name], name);\n      return regions;\n    }, {});\n  },\n\n  _addRegion(region, name) {\n    this.triggerMethod('before:add:region', this, name, region);\n\n    region._parentView = this;\n    region._name = name;\n\n    this._regions[name] = region;\n\n    this.triggerMethod('add:region', this, name, region);\n  },\n\n  // Remove a single region from the View, by name\n  removeRegion(name) {\n    const region = this._regions[name];\n\n    this._removeRegion(region, name);\n\n    return region;\n  },\n\n  // Remove all regions from the View\n  removeRegions() {\n    const regions = this._getRegions();\n\n    _.each(this._regions, this._removeRegion.bind(this));\n\n    return regions;\n  },\n\n  _removeRegion(region, name) {\n    this.triggerMethod('before:remove:region', this, name, region);\n\n    region.destroy();\n\n    this.triggerMethod('remove:region', this, name, region);\n  },\n\n  // Called in a region's destroy\n  _removeReferences(name) {\n    delete this.regions[name];\n    delete this._regions[name];\n  },\n\n  // Empty all regions in the region manager, but\n  // leave them attached\n  emptyRegions() {\n    const regions = this.getRegions();\n    _invoke(regions, 'empty');\n    return regions;\n  },\n\n  // Checks to see if view contains region\n  // Accepts the region name\n  // hasRegion('main')\n  hasRegion(name) {\n    return !!this.getRegion(name);\n  },\n\n  // Provides access to regions\n  // Accepts the region name\n  // getRegion('main')\n  getRegion(name) {\n    if (!this._isRendered) {\n      this.render();\n    }\n    return this._regions[name];\n  },\n\n  _getRegions() {\n    return _.clone(this._regions);\n  },\n\n  // Get all regions\n  getRegions() {\n    if (!this._isRendered) {\n      this.render();\n    }\n    return this._getRegions();\n  },\n\n  showChildView(name, view, options) {\n    const region = this.getRegion(name);\n    region.show(view, options);\n    return view;\n  },\n\n  detachChildView(name) {\n    return this.getRegion(name).detachView();\n  },\n\n  getChildView(name) {\n    return this.getRegion(name).currentView;\n  }\n\n};\n"
  },
  {
    "path": "src/mixins/template-render.js",
    "content": "import _ from 'underscore';\n\n// MixinOptions\n// - template\n// - templateContext\n\nexport default {\n\n  // Internal method to render the template with the serialized data\n  // and template context\n  _renderTemplate(template) {\n    // Add in entity data and template context\n    const data = this.mixinTemplateContext(this.serializeData()) || {};\n\n    // Render and add to el\n    const html = this._renderHtml(template, data);\n    if (typeof html !== 'undefined') {\n      this.attachElContent(html);\n    }\n  },\n\n  // Get the template for this view instance.\n  // You can set a `template` attribute in the view definition\n  // or pass a `template: TemplateFunction` parameter in\n  // to the constructor options.\n  getTemplate() {\n    return this.template;\n  },\n\n  // Mix in template context methods. Looks for a\n  // `templateContext` attribute, which can either be an\n  // object literal, or a function that returns an object\n  // literal. All methods and attributes from this object\n  // are copies to the object passed in.\n  mixinTemplateContext(serializedData) {\n    const templateContext = _.result(this, 'templateContext');\n    if (!templateContext) { return serializedData; }\n    if (!serializedData) { return templateContext; }\n    return _.extend({}, serializedData, templateContext);\n  },\n\n  // Serialize the view's model *or* collection, if\n  // it exists, for the template\n  serializeData() {\n    // If we have a model, we serialize that\n    if (this.model) {\n      return this.serializeModel();\n    }\n\n    // Otherwise, we serialize the collection,\n    // making it available under the `items` property\n    if (this.collection) {\n      return {\n        items: this.serializeCollection()\n      };\n    }\n  },\n\n  // Prepares the special `model` property of a view\n  // for being displayed in the template. Override this if\n  // you need a custom transformation for your view's model\n  serializeModel() {\n    return this.model.attributes;\n  },\n\n  // Serialize a collection\n  serializeCollection() {\n    return _.map(this.collection.models, model => model.attributes);\n  },\n\n  // Renders the data into the template\n  _renderHtml(template, data) {\n    return template(data);\n  },\n\n  // Attaches the content of a given view.\n  // This method can be overridden to optimize rendering,\n  // or to render in a non standard way.\n  //\n  // For example, using `innerHTML` instead of `$el.html`\n  //\n  // ```js\n  // attachElContent(html) {\n  //   this.el.innerHTML = html;\n  // }\n  // ```\n  attachElContent(html) {\n    this.Dom.setContents(this.el, html, this.$el);\n  }\n};\n"
  },
  {
    "path": "src/mixins/triggers.js",
    "content": "import _ from 'underscore';\nimport getNamespacedEventName from '../utils/get-namespaced-event-name';\nimport { isEnabled } from '../config/features';\n\n// Internal method to create an event handler for a given `triggerDef` like\n// 'click:foo'\nfunction buildViewTrigger(view, triggerDef) {\n  if (_.isString(triggerDef)) {\n    triggerDef = {event: triggerDef};\n  }\n\n  const eventName = triggerDef.event;\n\n  let shouldPreventDefault = !!triggerDef.preventDefault;\n\n  if (isEnabled('triggersPreventDefault')) {\n    shouldPreventDefault = triggerDef.preventDefault !== false;\n  }\n\n  let shouldStopPropagation = !!triggerDef.stopPropagation;\n\n  if (isEnabled('triggersStopPropagation')) {\n    shouldStopPropagation = triggerDef.stopPropagation !== false;\n  }\n\n  return function(event, ...args) {\n    if (shouldPreventDefault) {\n      event.preventDefault();\n    }\n\n    if (shouldStopPropagation) {\n      event.stopPropagation();\n    }\n\n    view.triggerMethod(eventName, view, event, ...args);\n  };\n}\n\nexport default {\n\n  // Configure `triggers` to forward DOM events to view\n  // events. `triggers: {\"click .foo\": \"do:foo\"}`\n  _getViewTriggers(view, triggers) {\n    // Configure the triggers, prevent default\n    // action and stop propagation of DOM events\n    return _.reduce(triggers, (events, value, key) => {\n      key = getNamespacedEventName(key, `trig${ this.cid }`);\n      events[key] = buildViewTrigger(view, value);\n      return events;\n    }, {});\n  }\n\n};\n"
  },
  {
    "path": "src/mixins/ui.js",
    "content": "import _ from 'underscore';\n// allows for the use of the @ui. syntax within\n// a given key for triggers and events\n// swaps the @ui with the associated selector.\n// Returns a new, non-mutated, parsed events hash.\nconst normalizeUIKeys = function(hash, ui) {\n  return _.reduce(hash, (memo, val, key) => {\n    const normalizedKey = normalizeUIString(key, ui);\n    memo[normalizedKey] = val;\n    return memo;\n  }, {});\n};\n\nconst uiRegEx = /@ui\\.[a-zA-Z-_$0-9]*/g;\n\n// utility method for parsing @ui. syntax strings\n// into associated selector\nconst normalizeUIString = function(uiString, ui) {\n  return uiString.replace(uiRegEx, (r) => {\n    return ui[r.slice(4)];\n  });\n};\n\n// allows for the use of the @ui. syntax within\n// a given value for regions\n// swaps the @ui with the associated selector\nconst normalizeUIValues = function(hash, ui, property) {\n  _.each(hash, (val, key) => {\n    if (_.isString(val)) {\n      hash[key] = normalizeUIString(val, ui);\n    } else if (val) {\n      const propertyVal = val[property];\n      if (_.isString(propertyVal)) {\n        val[property] = normalizeUIString(propertyVal, ui);\n      }\n    }\n  });\n  return hash;\n};\n\nexport default {\n\n  // normalize the keys of passed hash with the views `ui` selectors.\n  // `{\"@ui.foo\": \"bar\"}`\n  normalizeUIKeys(hash) {\n    const uiBindings = this._getUIBindings();\n    return normalizeUIKeys(hash, uiBindings);\n  },\n\n  // normalize the passed string with the views `ui` selectors.\n  // `\"@ui.bar\"`\n  normalizeUIString(uiString) {\n    const uiBindings = this._getUIBindings();\n    return normalizeUIString(uiString, uiBindings);\n  },\n\n  // normalize the values of passed hash with the views `ui` selectors.\n  // `{foo: \"@ui.bar\"}`\n  normalizeUIValues(hash, property) {\n    const uiBindings = this._getUIBindings();\n    return normalizeUIValues(hash, uiBindings, property);\n  },\n\n  _getUIBindings() {\n    const uiBindings = _.result(this, '_uiBindings');\n    return uiBindings || _.result(this, 'ui');\n  },\n\n  // This method binds the elements specified in the \"ui\" hash inside the view's code with\n  // the associated jQuery selectors.\n  _bindUIElements() {\n    if (!this.ui) { return; }\n\n    // store the ui hash in _uiBindings so they can be reset later\n    // and so re-rendering the view will be able to find the bindings\n    if (!this._uiBindings) {\n      this._uiBindings = this.ui;\n    }\n\n    // get the bindings result, as a function or otherwise\n    const bindings = _.result(this, '_uiBindings');\n\n    // empty the ui so we don't have anything to start with\n    this._ui = {};\n\n    // bind each of the selectors\n    _.each(bindings, (selector, key) => {\n      this._ui[key] = this.$(selector);\n    });\n\n    this.ui = this._ui;\n  },\n\n  _unbindUIElements() {\n    if (!this.ui || !this._uiBindings) { return; }\n\n    // delete all of the existing ui bindings\n    _.each(this.ui, ($el, name) => {\n      delete this.ui[name];\n    });\n\n    // reset the ui element to the original bindings configuration\n    this.ui = this._uiBindings;\n    delete this._uiBindings;\n    delete this._ui;\n  },\n\n  _getUI(name) {\n    return this._ui[name];\n  }\n};\n"
  },
  {
    "path": "src/mixins/view.js",
    "content": "// ViewMixin\n//  ---------\n\nimport Backbone from 'backbone';\nimport _ from 'underscore';\nimport BehaviorsMixin from './behaviors';\nimport CommonMixin from './common';\nimport DelegateEntityEventsMixin from './delegate-entity-events';\nimport TemplateRenderMixin from './template-render';\nimport TriggersMixin from './triggers';\nimport UIMixin from './ui';\nimport { isEnabled } from '../config/features';\nimport DomApi from '../config/dom';\n\n// MixinOptions\n// - behaviors\n// - childViewEventPrefix\n// - childViewEvents\n// - childViewTriggers\n// - collectionEvents\n// - modelEvents\n// - triggers\n// - ui\n\n\nconst ViewMixin = {\n  Dom: DomApi,\n\n  _isElAttached() {\n    return !!this.el && this.Dom.hasEl(this.Dom.getDocumentEl(this.el), this.el);\n  },\n\n  supportsRenderLifecycle: true,\n  supportsDestroyLifecycle: true,\n\n  _isDestroyed: false,\n\n  isDestroyed() {\n    return !!this._isDestroyed;\n  },\n\n  _isRendered: false,\n\n  isRendered() {\n    return !!this._isRendered;\n  },\n\n  _isAttached: false,\n\n  isAttached() {\n    return !!this._isAttached;\n  },\n\n  // Overriding Backbone.View's `delegateEvents` to handle\n  // `events` and `triggers`\n  delegateEvents(events) {\n    this._proxyBehaviorViewProperties();\n    this._buildEventProxies();\n\n    const combinedEvents = _.extend({},\n      this._getBehaviorEvents(),\n      this._getEvents(events),\n      this._getBehaviorTriggers(),\n      this._getTriggers()\n    );\n\n    Backbone.View.prototype.delegateEvents.call(this, combinedEvents);\n\n    return this;\n  },\n\n  // Allows Backbone.View events to utilize `@ui.` selectors\n  _getEvents(events) {\n    if (events) {\n      return this.normalizeUIKeys(events);\n    }\n\n    if (!this.events) { return; }\n\n    return this.normalizeUIKeys(_.result(this, 'events'));\n  },\n\n  // Configure `triggers` to forward DOM events to view\n  // events. `triggers: {\"click .foo\": \"do:foo\"}`\n  _getTriggers() {\n    if (!this.triggers) { return; }\n\n    // Allow `triggers` to be configured as a function\n    const triggers = this.normalizeUIKeys(_.result(this, 'triggers'));\n\n    // Configure the triggers, prevent default\n    // action and stop propagation of DOM events\n    return this._getViewTriggers(this, triggers);\n  },\n\n  // Handle `modelEvents`, and `collectionEvents` configuration\n  delegateEntityEvents() {\n    this._delegateEntityEvents(this.model, this.collection);\n\n    // bind each behaviors model and collection events\n    this._delegateBehaviorEntityEvents();\n\n    return this;\n  },\n\n  // Handle unbinding `modelEvents`, and `collectionEvents` configuration\n  undelegateEntityEvents() {\n    this._undelegateEntityEvents(this.model, this.collection);\n\n    // unbind each behaviors model and collection events\n    this._undelegateBehaviorEntityEvents();\n\n    return this;\n  },\n\n  // Handle destroying the view and its children.\n  destroy(options) {\n    if (this._isDestroyed || this._isDestroying) { return this; }\n    this._isDestroying = true;\n    const shouldTriggerDetach = this._isAttached && !this._disableDetachEvents;\n\n    this.triggerMethod('before:destroy', this, options);\n    if (shouldTriggerDetach) {\n      this.triggerMethod('before:detach', this);\n    }\n\n    // unbind UI elements\n    this.unbindUIElements();\n\n    // remove the view from the DOM\n    this._removeElement();\n\n    if (shouldTriggerDetach) {\n      this._isAttached = false;\n      this.triggerMethod('detach', this);\n    }\n\n    // remove children after the remove to prevent extra paints\n    this._removeChildren();\n\n    this._isDestroyed = true;\n    this._isRendered = false;\n\n    // Destroy behaviors after _isDestroyed flag\n    this._destroyBehaviors(options);\n\n    this._deleteEntityEventHandlers();\n\n    this.triggerMethod('destroy', this, options);\n    this._triggerEventOnBehaviors('destroy', this, options);\n\n    this.stopListening();\n\n    return this;\n  },\n\n  // Equates to this.$el.remove\n  _removeElement() {\n    this.$el.off().removeData();\n    this.Dom.detachEl(this.el, this.$el);\n  },\n\n  // This method binds the elements specified in the \"ui\" hash\n  bindUIElements() {\n    this._bindUIElements();\n    this._bindBehaviorUIElements();\n\n    return this;\n  },\n\n  // This method unbinds the elements specified in the \"ui\" hash\n  unbindUIElements() {\n    this._unbindUIElements();\n    this._unbindBehaviorUIElements();\n\n    return this;\n  },\n\n  getUI(name) {\n    return this._getUI(name);\n  },\n\n  // Cache `childViewEvents` and `childViewTriggers`\n  _buildEventProxies() {\n    this._childViewEvents = this.normalizeMethods(_.result(this, 'childViewEvents'));\n    this._childViewTriggers = _.result(this, 'childViewTriggers');\n    this._eventPrefix = this._getEventPrefix();\n  },\n\n  _getEventPrefix() {\n    const defaultPrefix = isEnabled('childViewEventPrefix') ? 'childview' : false;\n    const prefix = _.result(this, 'childViewEventPrefix', defaultPrefix);\n\n    return (prefix === false) ? prefix : prefix + ':';\n  },\n\n  _proxyChildViewEvents(view) {\n    if (this._childViewEvents || this._childViewTriggers || this._eventPrefix) {\n      this.listenTo(view, 'all', this._childViewEventHandler);\n    }\n  },\n\n  _childViewEventHandler(eventName, ...args) {\n    const childViewEvents = this._childViewEvents;\n\n    // call collectionView childViewEvent if defined\n    if (childViewEvents && childViewEvents[eventName]) {\n      childViewEvents[eventName].apply(this, args);\n    }\n\n    // use the parent view's proxyEvent handlers\n    const childViewTriggers = this._childViewTriggers;\n\n    // Call the event with the proxy name on the parent layout\n    if (childViewTriggers && childViewTriggers[eventName]) {\n      this.triggerMethod(childViewTriggers[eventName], ...args);\n    }\n\n    if (this._eventPrefix) {\n      this.triggerMethod(this._eventPrefix + eventName, ...args);\n    }\n  }\n};\n\n_.extend(ViewMixin, BehaviorsMixin, CommonMixin, DelegateEntityEventsMixin, TemplateRenderMixin, TriggersMixin, UIMixin);\n\nexport default ViewMixin;\n"
  },
  {
    "path": "src/object.js",
    "content": "// Object\n// ------\n\nimport _ from 'underscore';\nimport extend from './utils/extend';\nimport CommonMixin from './mixins/common';\nimport DestroyMixin from './mixins/destroy';\nimport RadioMixin from './mixins/radio';\n\nconst ClassOptions = [\n  'channelName',\n  'radioEvents',\n  'radioRequests'\n];\n\n// Object borrows many conventions and utilities from Backbone.\nconst MarionetteObject = function(options) {\n  this._setOptions(options, ClassOptions);\n  this.cid = _.uniqueId(this.cidPrefix);\n  this._initRadio();\n  this.initialize.apply(this, arguments);\n};\n\nMarionetteObject.extend = extend;\n\n// Object Methods\n// --------------\n\n_.extend(MarionetteObject.prototype, CommonMixin, DestroyMixin, RadioMixin, {\n  cidPrefix: 'mno',\n\n  // This is a noop method intended to be overridden\n  initialize() {}\n});\n\nexport default MarionetteObject;\n"
  },
  {
    "path": "src/region.js",
    "content": "// Region\n// ------\n\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport MarionetteError from './utils/error';\nimport extend from './utils/extend';\nimport monitorViewEvents from './common/monitor-view-events';\nimport { renderView, destroyView } from './common/view';\nimport CommonMixin from './mixins/common';\nimport View from './view';\nimport DomApi, { setDomApi } from './config/dom';\n\nconst classErrorName = 'RegionError';\n\nconst ClassOptions = [\n  'allowMissingEl',\n  'parentEl',\n  'replaceElement'\n];\n\nconst Region = function(options) {\n  this._setOptions(options, ClassOptions);\n\n  this.cid = _.uniqueId(this.cidPrefix);\n\n  // getOption necessary because options.el may be passed as undefined\n  this._initEl = this.el = this.getOption('el');\n\n  // Handle when this.el is passed in as a $ wrapped element.\n  this.el = this.el instanceof Backbone.$ ? this.el[0] : this.el;\n\n  this.$el = this._getEl(this.el);\n\n  this.initialize.apply(this, arguments);\n};\n\nRegion.extend = extend;\nRegion.setDomApi = setDomApi;\n\n// Region Methods\n// --------------\n\n_.extend(Region.prototype, CommonMixin, {\n  Dom: DomApi,\n\n  cidPrefix: 'mnr',\n  replaceElement: false,\n  _isReplaced: false,\n  _isSwappingView: false,\n\n  // This is a noop method intended to be overridden\n  initialize() {},\n\n  // Displays a view instance inside of the region. If necessary handles calling the `render`\n  // method for you. Reads content directly from the `el` attribute.\n  show(view, options) {\n    if (!this._ensureElement(options)) {\n      return;\n    }\n\n    view = this._getView(view, options);\n\n    if (view === this.currentView) { return this; }\n\n    if (view._isShown) {\n      throw new MarionetteError({\n        name: classErrorName,\n        message: 'View is already shown in a Region or CollectionView',\n        url: 'marionette.region.html#showing-a-view'\n      });\n    }\n\n    this._isSwappingView = !!this.currentView;\n\n    this.triggerMethod('before:show', this, view, options);\n\n    // Assume an attached view is already in the region for pre-existing DOM\n    if (this.currentView || !view._isAttached) {\n      this.empty(options);\n    }\n\n    this._setupChildView(view);\n\n    this.currentView = view;\n\n    renderView(view);\n\n    this._attachView(view, options);\n\n    this.triggerMethod('show', this, view, options);\n\n    this._isSwappingView = false;\n\n    return this;\n  },\n\n  _getEl(el) {\n    if (!el) {\n      throw new MarionetteError({\n        name: classErrorName,\n        message: 'An \"el\" must be specified for a region.',\n        url: 'marionette.region.html#additional-options'\n      });\n    }\n\n    return this.getEl(el);\n  },\n\n  _setEl() {\n    this.$el = this._getEl(this.el);\n\n    if (this.$el.length) {\n      this.el = this.$el[0];\n    }\n\n    // Make sure the $el contains only the el\n    if (this.$el.length > 1) {\n      this.$el = this.Dom.getEl(this.el);\n    }\n  },\n\n  // Set the `el` of the region and move any current view to the new `el`.\n  _setElement(el) {\n    if (el === this.el) { return this; }\n\n    const shouldReplace = this._isReplaced;\n\n    this._restoreEl();\n\n    this.el = el;\n\n    this._setEl();\n\n    if (this.currentView) {\n      const view = this.currentView;\n\n      if (shouldReplace) {\n        this._replaceEl(view);\n      } else {\n        this.attachHtml(view);\n      }\n    }\n\n    return this;\n  },\n\n  _setupChildView(view) {\n    monitorViewEvents(view);\n\n    this._proxyChildViewEvents(view);\n\n    // We need to listen for if a view is destroyed in a way other than through the region.\n    // If this happens we need to remove the reference to the currentView since once a view\n    // has been destroyed we can not reuse it.\n    view.on('destroy', this._empty, this);\n  },\n\n  _proxyChildViewEvents(view) {\n    const parentView = this._parentView;\n\n    if (!parentView) { return; }\n\n    parentView._proxyChildViewEvents(view);\n  },\n\n  // If the regions parent view is not monitoring its attach/detach events\n  _shouldDisableMonitoring() {\n    return this._parentView && this._parentView.monitorViewEvents === false;\n  },\n\n  _isElAttached() {\n    return this.Dom.hasEl(this.Dom.getDocumentEl(this.el), this.el);\n  },\n\n  _attachView(view, { replaceElement } = {}) {\n    const shouldTriggerAttach = !view._isAttached && this._isElAttached() && !this._shouldDisableMonitoring();\n    const shouldReplaceEl = typeof replaceElement === 'undefined' ? !!_.result(this, 'replaceElement') : !!replaceElement;\n\n    if (shouldTriggerAttach) {\n      view.triggerMethod('before:attach', view);\n    }\n\n    if (shouldReplaceEl) {\n      this._replaceEl(view);\n    } else {\n      this.attachHtml(view);\n    }\n\n    if (shouldTriggerAttach) {\n      view._isAttached = true;\n      view.triggerMethod('attach', view);\n    }\n\n    // Corresponds that view is shown in a marionette Region or CollectionView\n    view._isShown = true;\n  },\n\n  _ensureElement(options = {}) {\n    if (!_.isObject(this.el)) {\n      this._setEl();\n    }\n\n    if (!this.$el || this.$el.length === 0) {\n      const allowMissingEl = typeof options.allowMissingEl === 'undefined' ? !!_.result(this, 'allowMissingEl') : !!options.allowMissingEl;\n\n      if (allowMissingEl) {\n        return false;\n      } else {\n        throw new MarionetteError({\n          name: classErrorName,\n          message: `An \"el\" must exist in DOM for this region ${this.cid}`,\n          url: 'marionette.region.html#additional-options'\n        });\n      }\n    }\n    return true;\n  },\n\n  _getView(view) {\n    if (!view) {\n      throw new MarionetteError({\n        name: classErrorName,\n        message: 'The view passed is undefined and therefore invalid. You must pass a view instance to show.',\n        url: 'marionette.region.html#showing-a-view'\n      });\n    }\n\n    if (view._isDestroyed) {\n      throw new MarionetteError({\n        name: classErrorName,\n        message: `View (cid: \"${view.cid}\") has already been destroyed and cannot be used.`,\n        url: 'marionette.region.html#showing-a-view'\n      });\n    }\n\n    if (view instanceof Backbone.View) {\n      return view;\n    }\n\n    const viewOptions = this._getViewOptions(view);\n\n    return new View(viewOptions);\n  },\n\n  // This allows for a template or a static string to be\n  // used as a template\n  _getViewOptions(viewOptions) {\n    if (_.isFunction(viewOptions)) {\n      return { template: viewOptions };\n    }\n\n    if (_.isObject(viewOptions)) {\n      return viewOptions;\n    }\n\n    const template = function() { return viewOptions; };\n\n    return { template };\n  },\n\n  // Override this method to change how the region finds the DOM element that it manages. Return\n  // a jQuery selector object scoped to a provided parent el or the document if none exists.\n  getEl(el) {\n    const context = _.result(this, 'parentEl');\n\n    if (context && _.isString(el)) {\n      return this.Dom.findEl(context, el);\n    }\n\n    return this.Dom.getEl(el);\n  },\n\n  _replaceEl(view) {\n    // Always restore the el to ensure the regions el is present before replacing\n    this._restoreEl();\n\n    view.on('before:destroy', this._restoreEl, this);\n\n    this.Dom.replaceEl(view.el, this.el);\n\n    this._isReplaced = true;\n  },\n\n  // Restore the region's element in the DOM.\n  _restoreEl() {\n    // There is nothing to replace\n    if (!this._isReplaced) {\n      return;\n    }\n\n    const view = this.currentView;\n\n    if (!view) {\n      return;\n    }\n\n    this._detachView(view);\n\n    this._isReplaced = false;\n  },\n\n  // Check to see if the region's el was replaced.\n  isReplaced() {\n    return !!this._isReplaced;\n  },\n\n  // Check to see if a view is being swapped by another\n  isSwappingView() {\n    return !!this._isSwappingView;\n  },\n\n  // Override this method to change how the new view is appended to the `$el` that the\n  // region is managing\n  attachHtml(view) {\n    this.Dom.appendContents(this.el, view.el, {_$el: this.$el, _$contents: view.$el});\n  },\n\n  // Destroy the current view, if there is one. If there is no current view,\n  // it will detach any html inside the region's `el`.\n  empty(options = { allowMissingEl: true }) {\n    const view = this.currentView;\n\n    // If there is no view in the region we should only detach current html\n    if (!view) {\n      if (this._ensureElement(options)) {\n        this.detachHtml();\n      }\n      return this;\n    }\n\n    this._empty(view, true);\n    return this;\n  },\n\n  _empty(view, shouldDestroy) {\n    view.off('destroy', this._empty, this);\n    this.triggerMethod('before:empty', this, view);\n\n    this._restoreEl();\n\n    delete this.currentView;\n\n    if (!view._isDestroyed) {\n      if (shouldDestroy) {\n        this.removeView(view);\n      } else {\n        this._detachView(view);\n      }\n      view._isShown = false;\n      this._stopChildViewEvents(view);\n    }\n\n    this.triggerMethod('empty', this, view);\n  },\n\n  _stopChildViewEvents(view) {\n    const parentView = this._parentView;\n\n    if (!parentView) { return; }\n\n    this._parentView.stopListening(view);\n  },\n\n  // Non-Marionette safe view.destroy\n  destroyView(view) {\n    if (view._isDestroyed) {\n      return view;\n    }\n\n    destroyView(view, this._shouldDisableMonitoring());\n    return view;\n  },\n\n  // Override this method to determine what happens when the view\n  // is removed from the region when the view is not being detached\n  removeView(view) {\n    this.destroyView(view);\n  },\n\n  // Empties the Region without destroying the view\n  // Returns the detached view\n  detachView() {\n    const view = this.currentView;\n\n    if (!view) {\n      return;\n    }\n\n    this._empty(view);\n\n    return view;\n  },\n\n  _detachView(view) {\n    const shouldTriggerDetach = view._isAttached && !this._shouldDisableMonitoring();\n    const shouldRestoreEl = this._isReplaced;\n    if (shouldTriggerDetach) {\n      view.triggerMethod('before:detach', view);\n    }\n\n    if (shouldRestoreEl) {\n      this.Dom.replaceEl(this.el, view.el);\n    } else {\n      this.detachHtml();\n    }\n\n    if (shouldTriggerDetach) {\n      view._isAttached = false;\n      view.triggerMethod('detach', view);\n    }\n  },\n\n  // Override this method to change how the region detaches current content\n  detachHtml() {\n    this.Dom.detachContents(this.el, this.$el);\n  },\n\n  // Checks whether a view is currently present within the region. Returns `true` if there is\n  // and `false` if no view is present.\n  hasView() {\n    return !!this.currentView;\n  },\n\n  // Reset the region by destroying any existing view and clearing out the cached `$el`.\n  // The next time a view is shown via this region, the region will re-query the DOM for\n  // the region's `el`.\n  reset(options) {\n    this.empty(options);\n\n    this.el = this._initEl;\n\n    delete this.$el;\n    return this;\n  },\n\n  _isDestroyed: false,\n\n  isDestroyed() {\n    return this._isDestroyed;\n  },\n\n  // Destroy the region, remove any child view\n  // and remove the region from any associated view\n  destroy(options) {\n    if (this._isDestroyed) { return this; }\n\n    this.triggerMethod('before:destroy', this, options);\n    this._isDestroyed = true;\n\n    this.reset(options);\n\n    if (this._name) {\n      this._parentView._removeReferences(this._name);\n    }\n    delete this._parentView;\n    delete this._name;\n\n    this.triggerMethod('destroy', this, options);\n    this.stopListening();\n\n    return this;\n  }\n});\n\nexport default Region;\n"
  },
  {
    "path": "src/utils/deprecate.js",
    "content": "/* global console */\n\nimport _ from 'underscore';\n\nimport {isEnabled} from '../config/features';\n\nconst deprecate = function(message, test) {\n  if (_.isObject(message)) {\n    message = (\n      message.prev + ' is going to be removed in the future. ' +\n      'Please use ' + message.next + ' instead.' +\n      (message.url ? ' See: ' + message.url : '')\n    );\n  }\n\n  if (!isEnabled('DEV_MODE')) {\n    return;\n  }\n\n  if ((test === undefined || !test) && !deprecate._cache[message]) {\n    deprecate._warn('Deprecation warning: ' + message);\n    deprecate._cache[message] = true;\n  }\n};\n\n/* istanbul ignore next: can't clear console */\ndeprecate._console = typeof console !== 'undefined' ? console : {};\ndeprecate._warn = function() {\n  const warn = deprecate._console.warn || deprecate._console.log || _.noop;\n  return warn.apply(deprecate._console, arguments);\n};\ndeprecate._cache = {};\n\nexport default deprecate;\n"
  },
  {
    "path": "src/utils/error.js",
    "content": "// Error\n// -----\n\nimport _ from 'underscore';\nimport extend from './extend';\nimport {version} from '../../package.json';\n\nconst errorProps = ['description', 'fileName', 'lineNumber', 'name', 'message', 'number', 'url'];\n\nconst MarionetteError = extend.call(Error, {\n  urlRoot: `http://marionettejs.com/docs/v${version}/`,\n\n  url: '',\n\n  constructor(options) {\n    const error = Error.call(this, options.message);\n    _.extend(this, _.pick(error, errorProps), _.pick(options, errorProps));\n\n    if (Error.captureStackTrace) {\n      this.captureStackTrace();\n    }\n\n    this.url = this.urlRoot + this.url;\n  },\n\n  captureStackTrace() {\n    Error.captureStackTrace(this, MarionetteError);\n  },\n\n  toString() {\n    return `${ this.name }: ${ this.message } See: ${ this.url }`;\n  }\n});\n\nexport default MarionetteError;\n"
  },
  {
    "path": "src/utils/extend.js",
    "content": "// Marionette.extend\n// -----------------\n\nimport Backbone from 'backbone';\n\n// Borrow the Backbone `extend` method so we can use it as needed\nconst extend = Backbone.Model.extend;\n\nexport default extend;\n"
  },
  {
    "path": "src/utils/get-namespaced-event-name.js",
    "content": "// Borrow event splitter from Backbone\nconst delegateEventSplitter = /^(\\S+)\\s*(.*)$/;\n\n// Set event name to be namespaced using a unique index\n// to generate a non colliding event namespace\n// http://api.jquery.com/event.namespace/\nconst getNamespacedEventName = function(eventName, namespace) {\n  const match = eventName.match(delegateEventSplitter);\n  return `${ match[1] }.${ namespace } ${ match[2] }`;\n};\n\nexport default getNamespacedEventName;\n"
  },
  {
    "path": "src/utils/invoke.js",
    "content": "// Implementation of the invoke method (http://underscorejs.org/#invoke) with support for\n// lodash v3, v4, and underscore.js\nimport _ from 'underscore';\n\nexport default _.invokeMap || _.invoke;\n"
  },
  {
    "path": "src/utils/proxy.js",
    "content": "//Internal utility for creating context style global utils\nconst proxy = function(method) {\n  return function(context, ...args) {\n    return method.apply(context, args);\n  };\n};\n\nexport default proxy;\n"
  },
  {
    "path": "src/view.js",
    "content": "// View\n// ---------\n\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport monitorViewEvents from './common/monitor-view-events';\nimport ViewMixin from './mixins/view';\nimport RegionsMixin from './mixins/regions';\nimport { setDomApi } from './config/dom';\nimport { setRenderer } from './config/renderer';\n\nconst ClassOptions = [\n  'behaviors',\n  'childViewEventPrefix',\n  'childViewEvents',\n  'childViewTriggers',\n  'collectionEvents',\n  'events',\n  'modelEvents',\n  'regionClass',\n  'regions',\n  'template',\n  'templateContext',\n  'triggers',\n  'ui'\n];\n\n// Used by _getImmediateChildren\nfunction childReducer(children, region) {\n  if (region.currentView) {\n    children.push(region.currentView);\n  }\n\n  return children;\n}\n\n// The standard view. Includes view events, automatic rendering\n// templates, nested views, and more.\nconst View = Backbone.View.extend({\n\n  constructor(options) {\n    this._setOptions(options, ClassOptions);\n\n    monitorViewEvents(this);\n\n    this._initBehaviors();\n    this._initRegions();\n\n    Backbone.View.prototype.constructor.apply(this, arguments);\n\n    this.delegateEntityEvents();\n\n    this._triggerEventOnBehaviors('initialize', this, options);\n  },\n\n  // Overriding Backbone.View's `setElement` to handle\n  // if an el was previously defined. If so, the view might be\n  // rendered or attached on setElement.\n  setElement() {\n    Backbone.View.prototype.setElement.apply(this, arguments);\n\n    this._isRendered = this.Dom.hasContents(this.el);\n    this._isAttached = this._isElAttached();\n\n    if (this._isRendered) {\n      this.bindUIElements();\n    }\n\n    return this;\n  },\n\n  // If a template is available, renders it into the view's `el`\n  // Re-inits regions and binds UI.\n  render() {\n    const template = this.getTemplate();\n\n    if (template === false || this._isDestroyed) { return this; }\n\n    this.triggerMethod('before:render', this);\n\n    // If this is not the first render call, then we need to\n    // re-initialize the `el` for each region\n    if (this._isRendered) {\n      this._reInitRegions();\n    }\n\n    this._renderTemplate(template);\n    this.bindUIElements();\n\n    this._isRendered = true;\n    this.triggerMethod('render', this);\n\n    return this;\n  },\n\n  // called by ViewMixin destroy\n  _removeChildren() {\n    this.removeRegions();\n  },\n\n  _getImmediateChildren() {\n    return _.reduce(this._regions, childReducer, []);\n  }\n}, {\n  setRenderer,\n  setDomApi\n});\n\n_.extend(View.prototype, ViewMixin, RegionsMixin);\n\nexport default View;\n"
  },
  {
    "path": "test/.eslintrc",
    "content": "{\n  \"extends\": [\"../.eslintrc\", \"./.globals.json\"],\n  \"env\": {\n    \"mocha\": true\n  },\n  \"rules\": {\n    \"object-shorthand\": 0,\n    \"one-var\": [ 2, \"never\" ],\n    \"new-cap\": 0,\n    \"no-new\": 0\n  }\n}\n"
  },
  {
    "path": "test/.globals.json",
    "content": "{\n  \"globals\": {\n    \"chai\": true,\n    \"sinon\": true,\n    \"spy\": true,\n    \"expect\": true,\n    \"$\": true,\n    \"jQuery\": true,\n    \"_\": true,\n    \"Backbone\": true,\n    \"Marionette\": true\n  }\n}\n"
  },
  {
    "path": "test/.mocharc.json",
    "content": "{\n  \"checkLeaks\": true,\n  \"file\": \"./test/setup/node.js\",\n  \"recursive\": true,\n  \"reporter\": \"dot\",\n  \"require\": \"@babel/register\",\n  \"spec\": \"./test/unit/\",\n  \"ui\": \"bdd\"\n}\n"
  },
  {
    "path": "test/browsersync.html",
    "content": "<!doctype html>\n<html lang='en'>\n<head>\n  <meta charset='utf-8'>\n  <title>Tests</title>\n  <link rel='stylesheet' href='mocha/mocha.css' />\n\n  <!-- Testing libraries -->\n  <script src='mocha/mocha.js'></script>\n  <script src='chai/chai.js'></script>\n  <script src='sinon/pkg/sinon.js'></script>\n  <script src='sinon-chai/lib/sinon-chai.js'></script>\n  <script src='chai-jq/chai-jq.js'></script>\n\n  <!-- Load the built library -->\n  <script src='__spec-build.js'></script>\n</head>\n<body>\n  <!-- Required for browser reporter -->\n  <div id='mocha'></div>\n</body>\n</html>\n"
  },
  {
    "path": "test/rollup.config.js",
    "content": "import easySauce from 'easy-sauce';\n\nimport babel from 'rollup-plugin-babel';\nimport browsersync from 'rollup-plugin-browsersync';\nimport commonjs from 'rollup-plugin-commonjs';\nimport { eslint } from 'rollup-plugin-eslint';\nimport json from 'rollup-plugin-json';\nimport multiEntry from 'rollup-plugin-multi-entry';\nimport nodeResolve from 'rollup-plugin-node-resolve';\nimport nodeGlobals from 'rollup-plugin-node-globals';\n\nconst footer = 'this && this.Marionette && (this.Mn = this.Marionette);';\n\nconst isSauce = process.env.NODE_ENV === 'sauce';\n\nfunction runSauce() {\n  easySauce({\n    name: 'Marionette.js',\n    username: process.env.SAUCE_USERNAME,\n    key: process.env.SAUCE_ACCESS_KEY,\n    port: '8080',\n    testPath: '/test/runner.html',\n    framework: 'mocha',\n    platforms: [\n      ['Windows 10', 'internet explorer', 'latest'],\n      ['Windows 10', 'MicrosoftEdge', 'latest'],\n      ['Windows 10', 'chrome', 'latest'],\n      ['macOS 10.13', 'chrome', 'latest'],\n      ['macOS 10.13', 'firefox', 'latest']\n    ],\n    service: 'sauce-connect'\n  })\n    .on('message', message => {\n      // eslint-disable-next-line\n      console.log(message);\n    })\n    .on('update', job => {\n      // eslint-disable-next-line\n      console.log(job.status);\n    })\n    .on('done', (passed, jobs) => {\n      if (passed) {\n        // eslint-disable-next-line\n        console.log('All tests passed!');\n        process.exit(0);\n      } else {\n        // eslint-disable-next-line\n        console.error('Failures: ' + JSON.stringify(jobs, false, 2));\n        process.exit(1);\n      }\n    })\n    .on('error', error => {\n      // eslint-disable-next-line\n      console.error(error.message);\n      process.exit(1);\n    });\n}\n\nexport default {\n  input: ['./test/setup/browser.js', './test/unit/**/*.js'],\n  output: [\n    {\n      file: './test/tmp/__spec-build.js',\n      format: 'umd',\n      name: 'Marionette',\n      exports: 'named',\n      sourcemap: true,\n      footer\n    }\n  ],\n  plugins: [\n    eslint({ exclude: ['./package.json'] }),\n    commonjs(),\n    multiEntry(),\n    nodeGlobals(),\n    nodeResolve(),\n    json(),\n    babel(),\n    browsersync({\n      server: {\n        baseDir: ['test', 'test/tmp', 'node_modules'],\n        index: 'browsersync.html'\n      },\n      open: !isSauce,\n      callbacks: {\n        ready(err, bs) {\n          if (!isSauce) { return; }\n\n          runSauce();\n        }\n      }\n    })\n  ]\n}\n"
  },
  {
    "path": "test/runner.html",
    "content": "<!doctype html>\n<html lang='en'>\n<head>\n  <meta charset='utf-8'>\n  <title>Tests</title>\n  <link rel='stylesheet' href='../node_modules/mocha/mocha.css' />\n\n  <!-- Testing libraries -->\n  <script src='../node_modules/mocha/mocha.js'></script>\n  <script src='../node_modules/chai/chai.js'></script>\n  <script src='../node_modules/sinon/pkg/sinon.js'></script>\n  <script src='../node_modules/sinon-chai/lib/sinon-chai.js'></script>\n  <script src='../node_modules/chai-jq/chai-jq.js'></script>\n\n  <!-- Load the built library -->\n  <script src='tmp/__spec-build.js'></script>\n</head>\n<body>\n  <!-- Required for browser reporter -->\n  <div id='mocha'></div>\n</body>\n</html>\n"
  },
  {
    "path": "test/setup/browser.js",
    "content": "const mochaGlobals = require('../.globals.json').globals;\n\nglobal.mocha.setup('bdd');\nglobal.onload = function() {\n  global.mocha.checkLeaks();\n  global.mocha.globals(Object.keys(mochaGlobals));\n\n  const runner = global.mocha.run();\n\n  mochaResults(runner);\n  require('./setup')();\n};\n\nconst mochaResults = function(runner) {\n  const failedTests = [];\n\n  runner.on('end', function() {\n    global.mochaResults = runner.stats;\n    global.mochaResults.reports = failedTests;\n  });\n\n  runner.on('fail', function(test, err) {\n    failedTests.push({\n      title: test.title,\n      fullTitle: test.fullTitle(),\n      error: {\n        message: err.message,\n        stack: err.stack\n      }\n    });\n  });\n}\n"
  },
  {
    "path": "test/setup/node.js",
    "content": "var chai = require('chai');\nvar sinon = require('sinon');\nvar sinonChai = require('sinon-chai');\nvar chaiJq = require('chai-jq');\n\nchai.use(sinonChai);\nchai.use(chaiJq);\n\nglobal.chai = chai;\nglobal.sinon = sinon;\n\nif (!global.document || !global.window) {\n  const JSDOM = require('jsdom').JSDOM;\n\n  const opts = {\n    runScripts: 'dangerously',\n    url: 'http://localhost'\n  };\n\n  const dom = new JSDOM(`\n    <html>\n      <head><script></script></head>\n      <body></body>\n    </html>\n  `, opts);\n\n  global.window = dom.window;\n  global.document = global.window.document;\n  global.navigator = global.window.navigator;\n\n}\nrequire('./setup')();\n"
  },
  {
    "path": "test/setup/setup.js",
    "content": "module.exports = function() {\n\n  if (process.env.USE_LODASH) {\n    const pathScore = require.resolve('underscore');\n    const pathDash = require.resolve('lodash');\n    require(pathDash);\n\n    require.cache[pathScore] = require.cache[pathDash];\n  }\n\n  const lib = process.env.USE_LODASH ? 'lodash' : 'underscore';\n\n  const _ = require('underscore');\n\n  // eslint-disable-next-line\n  console.log('Using ' + lib + ': ' + _.VERSION);\n\n  const Backbone = require('backbone');\n  const jQuery = require('jquery');\n  Backbone.$ = jQuery;\n  Backbone.Radio = require('backbone.radio');\n  let Marionette = require('../../src/backbone.marionette');\n\n  Marionette = 'default' in Marionette ? Marionette.default : Marionette;\n\n  global.$ = global.jQuery = jQuery;\n  global._ = _;\n  global.Backbone = Backbone;\n  global.Marionette = Backbone.Marionette = Marionette;\n\n  global.expect = global.chai.expect;\n\n  let $fixtures;\n\n  function setFixtures() {\n    _.each(arguments, function(content) {\n      $fixtures.append(content);\n    });\n  }\n\n  function clearFixtures() {\n    $fixtures.empty();\n  }\n\n  before(function() {\n    $fixtures = $('<div id=\"fixtures\">');\n    $('body').append($fixtures);\n    this.setFixtures = setFixtures;\n    this.clearFixtures = clearFixtures;\n  });\n\n  beforeEach(function() {\n    this.sinon = global.sinon.createSandbox();\n  });\n\n  afterEach(function() {\n    this.sinon.restore();\n    window.location.hash = '';\n    Backbone.history.stop();\n    Backbone.history.handlers.length = 0;\n    clearFixtures();\n  });\n};\n"
  },
  {
    "path": "test/unit/README.md",
    "content": "### Unit Tests\n\n\n### Running unit tests\n\n1. Running just unit tests - `yarn test`\n\n2. Running coverage reporter - `yarn coverage`.\nTo check coverage, open `./coverage/lcov-report/index.html`.\n\n3. Running tests in browser - `yarn test-browser`.\n\n\n### Common concepts for writing tests\n\n1. Test suites should cover public API.\n\n> In most cases it will be public API testing,\nbut sometimes we should test something like: When models added to collection,\nhence, in this case we are adding needed suites.\n\n2. Code style.\n\n- Each `describe` should have name of tested method.\n\n> If it's possible, there should be not more then one nested describe for one method.\n\n_Wrong way_\n\n```javascript\n  describe('#MyClass', function() {\n    describe('some events in myMethod', function() {\n      describe('some logic', function() {\n        it('do something', function() {\n          ...\n        });\n\n        describe('some other logic', function() {\n          // other nested describes\n        });\n      });\n    });\n  });\n```\n\n\n**Correct way**\n\n```javascript\n  describe('#MyClass', function() {\n    describe('#myMethod', function() {\n      describe('when some logic', function() {\n        it('should do something', function() {\n          ...\n        });\n      });\n\n      describe('when some other logic', function() {\n        it('should do something', function() {\n          ...\n        });\n      });\n    });\n  });\n```\n\n- In case of testing some behavior\n\n> behavior means not Marionette Behavior class\n\n**Correct way**\n\n```javascript\n  describe('#MyClass', function() {\n    describe('when some data was changed', function() {\n      it('should do something', function() {\n        ...\n      });\n    });\n  });\n```\n\n- `before/beforeEach` should consist only some preparation logic\nbut inside it should not present calling methods you expect to test.\n\n_Wrong way_\n\n```javascript\n  describe('#MyClass', function() {\n    describe('#myMethod', function() {\n      let myInstance;\n\n      beforeEach(function() {\n        myInstance = new MyClass({\n          render: this.sinon.spy\n        });\n        myInstance.render();\n      });\n\n      it('should do something', function() {\n        expect(myInstance.render).to.have.been.calledOnce;\n      });\n    });\n  });\n```\n\n\n**Correct way**\n\n```javascript\n  describe('#MyClass', function() {\n    describe('#myMethod', function() {\n      let myInstance;\n      let renderSpy;\n\n      beforeEach(function() {\n        renderSpy = this.sinon.spy();\n\n        myInstance = new MyClass({\n          render: renderSpy\n        });\n      });\n\n      it('should do something', function() {\n        myInstance.render();\n\n        expect(renderSpy).to.have.been.calledOnce;\n      });\n    });\n  });\n```\n"
  },
  {
    "path": "test/unit/application.spec.js",
    "content": "'use strict';\n\nimport _ from 'underscore';\nimport Application from '../../src/application';\nimport View from '../../src/view';\n\ndescribe('Marionette Application', function() {\n\n  describe('#initialize', () => {\n    describe('when instantiating an app with specified options', function() {\n      let app;\n      let appOptions;\n      let initializeStub;\n\n      beforeEach(function() {\n        appOptions = {fooOption: 'foo'};\n        initializeStub = this.sinon.stub(Application.prototype, 'initialize');\n        this.sinon.spy(Application.prototype, '_initRadio');\n      });\n\n      it('should pass all arguments to the initialize method', function() {\n        app = new Application(appOptions, 'fooArg');\n\n        expect(initializeStub).to.have.been.calledOn(app).and.calledWith(appOptions, 'fooArg');\n      });\n\n      it('should have a cidPrefix', function() {\n        app = new Application(appOptions);\n\n        expect(app.cidPrefix).to.equal('mna');\n      });\n\n      it('should have a cid', function() {\n        app = new Application(appOptions);\n\n        expect(app.cid).to.exist;\n      });\n\n      it('should init the RadioMixin', function() {\n        app = new Application(appOptions);\n\n        expect(app._initRadio).to.have.been.called;\n      });\n    });\n  });\n\n  describe('#start', function() {\n    let app;\n    let fooOptions;\n\n    beforeEach(function() {\n      fooOptions = {foo: 'bar'};\n      app = new Application();\n    });\n\n    it('should return current application context', function() {\n      const result = app.start(fooOptions);\n\n      expect(result).to.have.been.equal(app);\n    });\n  });\n\n  describe('#onBeforeStart', function() {\n    let fooApp;\n    let fooOptions;\n    let beforeStartStub;\n    let onBeforeStartStub;\n\n    beforeEach(function() {\n      fooOptions = {foo: 'bar'};\n      beforeStartStub = this.sinon.stub();\n      onBeforeStartStub = this.sinon.stub();\n\n      const FooApp = Application.extend({\n        onBeforeStart: onBeforeStartStub\n      });\n\n      fooApp = new FooApp();\n      fooApp.on('before:start', beforeStartStub);\n    });\n\n    it('should run the onBeforeStart callback', function() {\n      fooApp.start(fooOptions);\n\n      expect(beforeStartStub).to.have.been.called;\n      expect(onBeforeStartStub).to.have.been.called;\n    });\n\n    it('should pass the startup option to the onBeforeStart callback', function() {\n      fooApp.start(fooOptions);\n\n      expect(beforeStartStub).to.have.been.calledOnce.and.calledWith(fooApp, fooOptions);\n      expect(onBeforeStartStub).to.have.been.calledOnce.and.calledWith(fooApp, fooOptions);\n    });\n  });\n\n  describe('#onStart', function() {\n    let fooApp;\n    let fooOptions;\n    let startStub;\n    let onStartStub;\n\n    beforeEach(function() {\n      fooOptions = {foo: 'bar'};\n      startStub = this.sinon.stub();\n      onStartStub = this.sinon.stub();\n\n      const FooApp = Application.extend({\n        onStart: onStartStub\n      });\n\n      fooApp = new FooApp();\n      fooApp.on('start', startStub);\n    });\n\n    it('should run the onStart callback', function() {\n      fooApp.start(fooOptions);\n\n      expect(startStub).to.have.been.called;\n      expect(onStartStub).to.have.been.called;\n    });\n\n    it('should pass the startup option to the callback', function() {\n      fooApp.start(fooOptions);\n\n      expect(startStub).to.have.been.calledOnce.and.calledWith(fooApp, fooOptions);\n      expect(onStartStub).to.have.been.calledOnce.and.calledWith(fooApp, fooOptions);\n    });\n  });\n\n  describe('#getRegion', function() {\n    let app;\n    let fooOptions;\n\n    beforeEach(function() {\n      fooOptions = {\n        region: '#fixtures'\n      };\n      app = new Application(fooOptions);\n    });\n\n    it('should get the region selector with getRegion', function() {\n      expect(app.getRegion().$el).to.have.length(1);\n    });\n  });\n\n  describe('#showView', function() {\n    let app;\n    let view;\n    let appRegion;\n    let fooOptions;\n    let showViewInRegionSpy;\n\n    beforeEach(function() {\n      fooOptions = {\n        region: '#fixtures'\n      };\n      view = new View({\n        template: _.template('ohai')\n      });\n      app = new Application(fooOptions);\n\n      appRegion = app.getRegion();\n\n      showViewInRegionSpy = this.sinon.spy(appRegion, 'show');\n    });\n\n    describe('when additional arguments was passed', function() {\n      let fooArgs;\n\n      beforeEach(function() {\n        fooArgs = {foo: 'bar'};\n      });\n\n      it('should call show method in region with additional arguments', function() {\n        app.showView(view, fooArgs);\n\n        expect(showViewInRegionSpy).to.have.been.calledWith(view, fooArgs);\n      });\n    });\n\n    describe('when just view as argument was passed', function() {\n      it('should call show method in region', function() {\n        app.showView(view);\n\n        expect(showViewInRegionSpy).to.have.been.called;\n      });\n    });\n  });\n\n  describe('#getView', function() {\n    let app;\n    let view;\n    let fooOptions;\n\n    beforeEach(function() {\n      fooOptions = {\n        region: '#fixtures'\n      };\n      view = new View({\n        template: _.template('ohai')\n      });\n      app = new Application(fooOptions);\n    });\n\n    it('should return View which was shown', function() {\n      app.showView(view);\n\n      expect(app.getView()).to.have.deep.equal(view);\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/backbone.marionette.spec.js",
    "content": "import _ from 'underscore';\n\nimport * as Mn from '../../src/backbone.marionette';\nimport Marionette from '../../src/backbone.marionette';\n\nimport {version} from '../../package.json';\n\nimport extend from '../../src/utils/extend';\n\nimport monitorViewEvents from '../../src/common/monitor-view-events';\n\nimport Events from '../../src/mixins/events';\n\nimport MnObject from '../../src/object';\nimport View from '../../src/view';\nimport CollectionView from '../../src/collection-view';\nimport Behavior from '../../src/behavior';\nimport Region from '../../src/region';\nimport Application from '../../src/application';\n\nimport DomApi from '../../src/config/dom';\n\nimport {\n  isEnabled,\n  setEnabled\n} from '../../src/config/features';\n\n\ndescribe('backbone.marionette', function() {\n  describe('Named Exports', function() {\n    const namedExports = {\n      View,\n      CollectionView,\n      MnObject,\n      Region,\n      Behavior,\n      Application,\n      isEnabled,\n      setEnabled,\n      monitorViewEvents,\n      Events,\n      extend,\n      DomApi,\n    };\n\n    _.each(namedExports, (val, key) => {\n      it(`should have named export ${ key }`, function() {\n        expect(Mn[key]).to.equal(val);\n      });\n    });\n  });\n\n  describe('Default Export', function() {\n    const namedExports = {\n      View,\n      CollectionView,\n      MnObject,\n      Region,\n      Behavior,\n      Application,\n      isEnabled,\n      setEnabled,\n      monitorViewEvents,\n      Events,\n      extend,\n      DomApi,\n    };\n\n    _.each(namedExports, (val, key) => {\n      it(`should have key ${ key }`, function() {\n        expect(Marionette[key]).to.equal(val);\n      });\n    });\n\n    it('should have key Object', function() {\n      expect(Marionette.Object).to.equal(MnObject);\n    });\n  });\n\n  describe('VERSION', function() {\n    it('should attach the package.json version', function() {\n      expect(Mn.VERSION).to.equal(version);\n    });\n  });\n\n  describe('Proxied Utilities', function() {\n    let context;\n\n    beforeEach(function() {\n      context = new MnObject();\n    });\n\n    it('should proxy bindEvents', function() {\n      const entity = new MnObject();\n      const eventHandler = this.sinon.stub();\n      const events = { 'foo': eventHandler };\n\n      Mn.bindEvents(context, entity, events);\n      entity.trigger('foo');\n\n      expect(eventHandler)\n        .to.have.been.calledOnce\n        .and.calledOn(context);\n    });\n\n    it('should proxy unbindEvents', function() {\n      this.sinon.spy(context, 'stopListening');\n\n      const entity = new MnObject();\n      context.listenTo(entity, 'foo', _.noop);\n\n      Mn.unbindEvents(context, entity);\n\n      expect(context.stopListening)\n        .to.have.been.calledOnce\n        .and.calledOn(context)\n        .and.calledWith(entity);\n    });\n\n    it('should proxy bindRequests', function() {\n      const replyFooStub = this.sinon.stub();\n      const channel = { reply: this.sinon.stub() };\n\n      Mn.bindRequests(context, channel, {'foo': replyFooStub});\n\n      expect(channel.reply)\n        .to.have.been.calledOnce\n        .and.calledWith({'foo': replyFooStub}, context);\n    });\n\n    it('should proxy unbindRequests', function() {\n      const channel = { stopReplying: this.sinon.stub() };\n\n      Mn.unbindRequests(context, channel);\n\n      expect(channel.stopReplying)\n        .to.have.been.calledOnce\n        .and.calledWith(null, null, context);\n    });\n\n    it('should proxy mergeOptions', function() {\n      context.foo = 'bar';\n\n      Mn.mergeOptions(context, { foo: 'baz' }, ['foo']);\n\n      expect(context.foo).to.equal('baz');\n    });\n\n    it('should proxy getOption', function() {\n      context.options.foo = 'bar';\n\n      expect(Mn.getOption(context, 'foo')).to.equal('bar');\n    });\n\n    it('should proxy normalizeMethods', function() {\n      context.onFoo = this.sinon.stub();\n\n      expect(Mn.normalizeMethods(context, { foo: 'onFoo' })).to.deep.equal({ foo: context.onFoo });\n    });\n\n    it('should proxy triggerMethod', function() {\n      context.onFoo = this.sinon.stub();\n\n      Mn.triggerMethod(context, 'foo', 'bar');\n\n      expect(context.onFoo)\n        .to.have.been.calledOnce\n        .and.calledOn(context)\n        .and.calledWith('bar');\n    });\n  });\n\n  describe('#setDomApi', function() {\n    const DomClasses = {\n      CollectionView,\n      Region,\n      View\n    };\n\n    const fakeDomApi = {\n      foo: 'bar'\n    };\n\n    _.each(DomClasses, function(Class, key) {\n      it(`should setDomApi on ${ key }`, function() {\n        this.sinon.spy(Class, 'setDomApi');\n        Mn.setDomApi(fakeDomApi);\n\n        expect(Class.setDomApi)\n          .to.be.calledOnce\n          .and.calledWith(fakeDomApi);\n      });\n    });\n  });\n\n  describe('#setRenderer', function() {\n    let renderer;\n\n    beforeEach(function() {\n      renderer = View.prototype._renderHtml;\n    });\n\n    afterEach(function() {\n      Mn.setRenderer(renderer);\n    });\n\n    const RendererClasses = {\n      CollectionView,\n      View\n    };\n\n    const fakeRenderer = function() {};\n\n    _.each(RendererClasses, function(Class, key) {\n      it(`should setRenderer on ${ key }`, function() {\n        this.sinon.spy(Class, 'setRenderer');\n\n        Mn.setRenderer(fakeRenderer);\n        expect(Class.setRenderer)\n          .to.be.calledOnce\n          .and.calledWith(fakeRenderer);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/behavior.spec.js",
    "content": "import _ from 'underscore';\nimport Behavior from '../../src/behavior';\nimport Region from '../../src/region';\nimport View from '../../src/view';\nimport CollectionView from '../../src/collection-view';\nimport { bindEvents } from '../../src/backbone.marionette';\n\ndescribe('Behavior', function() {\n  describe('when instantiating a behavior with some options', function() {\n    it('should merge the options into instance options', function() {\n      const createOptions = {foo: 'bar'};\n      const behavior = new Behavior(createOptions);\n\n      expect(behavior.options).to.eql(createOptions);\n    });\n  });\n\n  describe('behavior parsing', function() {\n    let behaviorSpies;\n    let FooView;\n\n    beforeEach(function() {\n      const Bar = Behavior.extend({});\n      const Baz = Behavior.extend({});\n\n      behaviorSpies = {\n        foo: this.sinon.spy(Behavior),\n        bar: this.sinon.spy(Bar),\n        baz: this.sinon.spy(Baz)\n      };\n    });\n\n    describe('with array notation', function() {\n      describe('when one behavior', function() {\n        beforeEach(function() {\n          FooView = View.extend({\n            behaviors: [behaviorSpies.foo]\n          });\n        });\n\n        it('should instantiate the behavior', function() {\n          /* eslint-disable no-unused-vars */\n          const fooView = new FooView();\n\n          expect(behaviorSpies.foo).to.have.been.calledOnce;\n        });\n      });\n\n      describe('when multiple behaviors', function() {\n        beforeEach(function() {\n          FooView = View.extend({\n            behaviors: [behaviorSpies.foo, behaviorSpies.bar]\n          });\n        });\n\n        it('should instantiate the behaviors', function() {\n          /* eslint-disable no-unused-vars */\n          const fooView = new FooView();\n\n          expect(behaviorSpies.foo).to.have.been.calledOnce;\n          expect(behaviorSpies.bar).to.have.been.calledOnce;\n        });\n      });\n\n      describe('when behavior class is provided', function() {\n        beforeEach(function() {\n          FooView = View.extend({\n            behaviors: [{behaviorClass: behaviorSpies.foo}]\n          });\n        });\n\n        it('should instantiate the behavior', function() {\n          /* eslint-disable no-unused-vars */\n          const fooView = new FooView();\n\n          expect(behaviorSpies.foo).to.have.been.calledOnce;\n        });\n      });\n\n      describe('when behavior class and constructor are provided', function() {\n        beforeEach(function() {\n          FooView = View.extend({\n            behaviors: [behaviorSpies.foo, behaviorSpies.bar, {\n              behaviorClass: behaviorSpies.baz\n            }]\n          });\n        });\n\n        it('should instantiate the behaviors', function() {\n          /* eslint-disable no-unused-vars */\n          const fooView = new FooView();\n\n          expect(behaviorSpies.foo).to.have.been.calledOnce;\n          expect(behaviorSpies.bar).to.have.been.calledOnce;\n          expect(behaviorSpies.baz).to.have.been.calledOnce;\n        });\n      });\n    });\n\n    describe('with object notation', function() {\n      describe('when one behavior', function() {\n        beforeEach(function() {\n          FooView = View.extend({\n            behaviors: {x: behaviorSpies.foo}\n          });\n        });\n\n        it('should instantiate the behavior', function() {\n          /* eslint-disable no-unused-vars */\n          const fooView = new FooView();\n\n          expect(behaviorSpies.foo).to.have.been.calledOnce;\n        });\n      });\n\n      describe('when multiple behaviors', function() {\n        beforeEach(function() {\n          FooView = View.extend({\n            behaviors: {x: behaviorSpies.foo, y: behaviorSpies.bar}\n          });\n        });\n\n        it('should instantiate the behaviors', function() {\n          /* eslint-disable no-unused-vars */\n          const fooView = new FooView();\n\n          expect(behaviorSpies.foo).to.have.been.calledOnce;\n          expect(behaviorSpies.bar).to.have.been.calledOnce;\n        });\n      });\n\n      describe('when behavior class is provided', function() {\n        beforeEach(function() {\n          FooView = View.extend({\n            behaviors: {x: {behaviorClass: behaviorSpies.foo}}\n          });\n        });\n\n        it('should instantiate the behavior', function() {\n          /* eslint-disable no-unused-vars */\n          const fooView = new FooView();\n\n          expect(behaviorSpies.foo).to.have.been.calledOnce;\n        });\n      });\n\n      describe('when behavior class and constructor are provided', function() {\n        beforeEach(function() {\n          FooView = View.extend({\n            behaviors: {\n              x: behaviorSpies.foo,\n              y: behaviorSpies.bar,\n              z: {\n                behaviorClass: behaviorSpies.baz\n              }\n            }\n          });\n        });\n\n        it('should instantiate the behaviors', function() {\n          /* eslint-disable no-unused-vars */\n          const fooView = new FooView();\n\n          expect(behaviorSpies.foo).to.have.been.calledOnce;\n          expect(behaviorSpies.bar).to.have.been.calledOnce;\n          expect(behaviorSpies.baz).to.have.been.calledOnce;\n        });\n      });\n    });\n\n\n  });\n\n  describe('behavior initialize', function() {\n    let behavior;\n    let view;\n\n    beforeEach(function() {\n      const TestBehavior = Behavior.extend({\n        initialize: this.sinon.stub()\n      });\n\n      view = new View();\n\n      behavior = new TestBehavior({ foo: 'bar' }, view);\n    });\n\n    it('should have a cidPrefix', function() {\n      expect(behavior.cidPrefix).to.equal('mnb');\n    });\n\n    it('should have a cid', function() {\n      expect(behavior.cid).to.exist;\n    });\n\n    it('should call initialize when a behavior is created', function() {\n      expect(behavior.initialize)\n        .to.have.been.calledOnce\n        .and.calledWith({ foo: 'bar' }, view);\n    });\n  });\n\n  describe('behavior initialize from constructor args', function() {\n    let fooStub;\n    let barStub;\n    let FooView;\n    let behaviorSpies;\n\n    beforeEach(function() {\n      fooStub = this.sinon.stub();\n      barStub = this.sinon.stub();\n\n      behaviorSpies = {\n        foo: Behavior.extend({initialize: fooStub}),\n        bar: Behavior.extend({initialize: barStub})\n      };\n\n      FooView = View.extend({\n        behaviors: [behaviorSpies.foo]\n      });\n    });\n\n    it('should call initialize when a behavior is created', function() {\n      /* eslint-disable no-unused-vars */\n      const fooView = new FooView({behaviors: [behaviorSpies.bar]});\n\n      expect(barStub).to.have.been.calledOnce;\n      expect(fooStub).not.to.have.been.called;\n    });\n  });\n\n  describe('behavior events', function() {\n    let fooClickStub;\n    let barClickStub;\n    let bazClickStub;\n    let viewClickStub;\n    let behaviorSpies;\n    let FooView;\n    let fooView;\n\n    beforeEach(function() {\n      fooClickStub = this.sinon.stub();\n      barClickStub = this.sinon.stub();\n      bazClickStub = this.sinon.stub();\n      viewClickStub = this.sinon.stub();\n\n      behaviorSpies = {\n        foo: Behavior.extend({\n          events: {\n            'click': fooClickStub\n          }\n        }),\n        bar: Behavior.extend({\n          events: {\n            'click': barClickStub\n          }\n        }),\n        baz: Behavior.extend({\n          events: {\n            'click': 'handleClick'\n          },\n          handleClick: bazClickStub\n        })\n      };\n\n      FooView = View.extend({\n        events: {\n          'click': viewClickStub\n        },\n        behaviors: {\n          x: behaviorSpies.foo,\n          y: behaviorSpies.bar,\n          z: behaviorSpies.baz\n        }\n      });\n\n      fooView = new FooView();\n    });\n\n    it('should call first behaviors event', function() {\n      fooView.$el.click();\n\n      expect(fooClickStub).to.have.been.calledOnce.and.calledOn(this.sinon.match.instanceOf(behaviorSpies.foo));\n    });\n\n    it('should call second behaviors event', function() {\n      fooView.$el.click();\n\n      expect(barClickStub).to.have.been.calledOnce.and.calledOn(this.sinon.match.instanceOf(behaviorSpies.bar));\n    });\n\n    it('should call third behaviors event', function() {\n      fooView.$el.click();\n\n      expect(bazClickStub).to.have.been.calledOnce.and.calledOn(this.sinon.match.instanceOf(behaviorSpies.baz));\n    });\n\n    it('should call the view click handler', function() {\n      fooView.$el.click();\n\n      expect(viewClickStub).to.have.been.calledOnce.and.calledOn(fooView);\n    });\n  });\n\n  describe('behavior triggers', function() {\n    let onClickFooStub;\n    let triggerMethodViewSpy;\n    let triggerMethodSpy;\n    let behaviorSpies;\n    let fooView;\n\n    beforeEach(function() {\n      onClickFooStub = this.sinon.stub();\n\n      behaviorSpies = {\n        foo: Behavior.extend({\n          triggers: {'click': 'click:foo'},\n          onClickFoo: onClickFooStub\n        })\n      };\n\n      const FooView = View.extend({\n        triggers: {\n          'click': 'click:foo:view'\n        },\n        behaviors: [behaviorSpies.foo]\n      });\n\n      const fooModel = new Backbone.Model();\n      const fooCollection = new Backbone.Collection();\n\n      fooView = new FooView({\n        model: fooModel,\n        collection: fooCollection\n      });\n\n      triggerMethodSpy = this.sinon.spy();\n      triggerMethodViewSpy = this.sinon.spy();\n\n      fooView.on('click:foo', triggerMethodSpy);\n      fooView.on('click:foo:view', triggerMethodViewSpy);\n    });\n\n    it('should call `triggerMethod` with the triggered event', function() {\n      fooView.$el.click();\n\n      expect(triggerMethodSpy)\n        .to.have.been.calledOnce\n        .and.calledOn(fooView);\n    });\n\n    it('should call the triggered method', function() {\n      fooView.$el.click();\n\n      expect(onClickFooStub)\n        .to.have.been.calledOnce\n        .and.have.been.calledOn(this.sinon.match.instanceOf(behaviorSpies.foo));\n    });\n\n    it('should not collide with view triggers with same event', function() {\n      fooView.$el.click();\n\n      expect(triggerMethodViewSpy)\n        .to.have.been.calledOnce\n        .and.calledOn(fooView);\n    });\n  });\n\n  describe('proxyViewProperties', function() {\n    let fooBehavior;\n    let fooView;\n\n    beforeEach(function() {\n      const behaviorSpies = {\n        foo: Behavior.extend({\n          initialize: function() {\n            fooBehavior = this;\n          }\n        })\n      };\n\n      const FooView = View.extend({\n        behaviors: [behaviorSpies.foo]\n      });\n\n      fooView = new FooView();\n    });\n\n    it('should proxy the views $el', function() {\n      fooView.setElement(document.createElement('bar'));\n\n      expect(fooBehavior.$el).to.equal(fooView.$el);\n    });\n\n    it('should proxy the views el', function() {\n      fooView.setElement(document.createElement('bar'));\n\n      expect(fooBehavior.el).to.equal(fooView.el);\n    });\n  });\n\n  describe('behavior UI', function() {\n    let fooBehavior;\n    let onRenderStub;\n    let onBeforeAttachStub;\n    let onAttachStub;\n    let onDestroyStub;\n    let onFooClickStub;\n    let onBarClickStub;\n    let behaviorSpies;\n    let FooView;\n\n    beforeEach(function() {\n      onRenderStub = this.sinon.stub();\n      onBeforeAttachStub = this.sinon.stub();\n      onAttachStub = this.sinon.stub();\n      onDestroyStub = this.sinon.stub();\n      onFooClickStub = this.sinon.stub();\n      onBarClickStub = this.sinon.stub();\n\n      behaviorSpies = {\n        foo: Behavior.extend({\n          ui: {foo: '.foo'},\n          initialize: function() {fooBehavior = this;},\n          events: {\n            'click @ui.foo': 'onFooClick',\n            'click @ui.bar': 'onBarClick'\n          },\n\n          testViewUI: function() { this.ui.bar.trigger('test'); },\n          testBehaviorUI: function() { this.ui.foo.trigger('test'); },\n          onRender: onRenderStub,\n          onBeforeAttach: onBeforeAttachStub,\n          onAttach: onAttachStub,\n          onDestroy: onDestroyStub,\n          onFooClick: onFooClickStub,\n          onBarClick: onBarClickStub\n        })\n      };\n\n      FooView = View.extend({\n        template: _.template('<div class=\"foo\"></div><div class=\"bar\"></div>'),\n        ui: {bar: '.bar'},\n        behaviors: [behaviorSpies.foo]\n      });\n    });\n\n    describe('should call onAttach when inside a CollectionView', function() {\n      let region;\n      let fooCollection;\n      let fooCollectionView;\n\n      beforeEach(function() {\n        const FooCollectionView = CollectionView.extend({\n          childView: FooView\n        });\n\n        fooCollection = new Backbone.Collection([{}]);\n        fooCollectionView = new FooCollectionView({collection: fooCollection});\n\n        this.setFixtures('<div id=\"region\"></div>');\n\n        region = new Region({\n          el: '#region'\n        });\n      });\n\n      it('should call onAttach when inside a CollectionView', function() {\n        region.show(fooCollectionView);\n\n        expect(onAttachStub).to.have.been.called;\n      });\n\n      it('should call onAttach when already shown and reset', function() {\n        region.show(fooCollectionView);\n        fooCollection.reset([{id: 1}, {id: 2}]);\n\n        expect(onAttachStub.callCount).to.equal(3);\n      });\n\n      it('should call onAttach when a single model is added and the collectionView is already shown', function() {\n        region.show(fooCollectionView);\n        fooCollection.add({id: 3});\n\n        expect(onAttachStub.callCount).to.equal(2);\n      });\n    });\n\n    describe('view should be able to override predefined behavior ui', function() {\n      let barView;\n\n      beforeEach(function() {\n        const BarView = View.extend({\n          template: _.template('<div class=\"zip\"></div><div class=\"bar\"></div>'),\n          ui: {\n            bar: '.bar',\n            foo: '.zip' // override foo selector behavior\n          },\n          behaviors: [behaviorSpies.foo]\n        });\n\n        barView = new BarView();\n        barView.render();\n      });\n\n      it('should handle behavior ui click event', function() {\n        barView.$el.find('.zip').click();\n\n        expect(onFooClickStub).to.have.been.calledOnce.and.calledOn(fooBehavior);\n      });\n\n      it('should handle view ui click event', function() {\n        barView.$el.find('.bar').click();\n\n        expect(onBarClickStub).to.have.been.calledOnce.and.calledOn(fooBehavior);\n      });\n    });\n\n    describe('within a view', function() {\n      let fooView;\n\n      it('should not clobber the event prototype', function() {\n        fooView = new FooView();\n\n        expect(behaviorSpies.foo.prototype.events).to.have.property('click @ui.bar', 'onBarClick');\n      });\n\n      it('should handle click events after calling delegateEvents', function() {\n        fooView = new FooView();\n        fooView.render();\n        fooView.delegateEvents();\n\n        expect(fooBehavior.ui.foo.click.bind(fooView.ui.bar)).to.not.throw();\n        expect(fooView.ui.bar.click.bind(fooView.ui.bar)).to.not.throw();\n      });\n\n      it('should set the behavior UI element', function() {\n        fooView = new FooView();\n        fooView.render();\n\n        expect(onRenderStub).to.have.been.calledOnce;\n      });\n\n      it('should make the view\\'s ui hash available to callbacks', function() {\n        fooView = new FooView();\n        fooView.render();\n\n        expect(fooBehavior.testViewUI.bind(fooBehavior)).to.not.throw();\n      });\n\n      it('should make the behavior\\'s ui hash available to callbacks', function() {\n        fooView = new FooView();\n        fooView.render();\n\n        expect(fooBehavior.testBehaviorUI.bind(fooBehavior)).to.not.throw();\n      });\n\n      describe('the $el', function() {\n        beforeEach(function() {\n          fooView = new FooView();\n          fooView.render();\n        });\n\n        it('should handle behavior ui click event', function() {\n          fooView.$el.find('.foo').click();\n\n          expect(onFooClickStub).to.have.been.calledOnce.and.calledOn(fooBehavior);\n        });\n\n        it('should handle view ui click event', function() {\n          fooView.$el.find('.bar').click();\n\n          expect(onBarClickStub).to.have.been.calledOnce.and.calledOn(fooBehavior);\n        });\n\n        it('has a getUI method which returns the selector', function() {\n          expect(fooBehavior.getUI('foo')).to.have.length(1);\n        });\n      });\n\n      describe('the el', function() {\n        beforeEach(function() {\n          fooView = new FooView();\n          fooView.render();\n        });\n\n        it('should handle behavior ui click event', function() {\n          $(fooView.el).find('.foo').click();\n\n          expect(onFooClickStub).to.have.been.calledOnce.and.calledOn(fooBehavior);\n        });\n\n        it('should handle view ui click event', function() {\n          $(fooView.el).find('.bar').click();\n\n          expect(onBarClickStub).to.have.been.calledOnce.and.calledOn(fooBehavior);\n        });\n      });\n    });\n\n    describe('within a layout', function() {\n      let barView;\n\n      beforeEach(function() {\n        this.setFixtures('<div id=\"layout\"></div>');\n\n        const BarView = View.extend({\n          el: '#layout',\n          template: _.template('<div class=\"baz\"></div>'),\n          regions: {bazRegion: '.baz'}\n        });\n\n        barView = new BarView();\n        barView.render();\n      });\n\n      it('should call onBeforeAttach', function() {\n        barView.getRegion('bazRegion').show(new FooView());\n\n        expect(onBeforeAttachStub).to.have.been.calledOnce;\n      });\n\n      it('should call onAttach', function() {\n        barView.getRegion('bazRegion').show(new FooView());\n\n        expect(onAttachStub).to.have.been.calledOnce;\n      });\n\n      it('should call onDestroy', function() {\n        barView.getRegion('bazRegion').show(new FooView());\n        barView.destroy();\n\n        expect(onDestroyStub).to.have.been.calledOnce;\n      });\n    });\n  });\n\n  describe('behavior instance events', function() {\n    let listenToChangeStub;\n    let onFooStub;\n    let fooModel;\n    let fooView;\n\n    beforeEach(function() {\n      fooModel = new Backbone.Model();\n\n      listenToChangeStub = this.sinon.stub();\n      onFooStub = this.sinon.stub();\n\n      const FooBehavior = Behavior.extend({\n        initialize: function() {\n          this.listenTo(fooModel, 'change', listenToChangeStub);\n          this.on('foo', onFooStub);\n        }\n      });\n\n      const FooView = View.extend({\n        behaviors: [FooBehavior]\n      });\n\n      fooView = new FooView();\n      fooView.destroy();\n    });\n\n    it('should unbind listenTo on destroy', function() {\n      fooModel.set('bar', 'baz');\n\n      expect(listenToChangeStub).not.to.have.been.calledOnce;\n    });\n  });\n\n  describe('behavior model events', function() {\n    let handleModelChangeStub;\n    let handleCollectionResetStub;\n    let handleModelFooChangeStub;\n    let fooBehavior;\n    let FooView;\n    let FooCollectionView;\n    let fooModel;\n    let fooCollection;\n\n    beforeEach(function() {\n      handleModelChangeStub = this.sinon.stub();\n      handleCollectionResetStub = this.sinon.stub();\n      handleModelFooChangeStub = this.sinon.stub();\n\n      const behaviorSpies = {\n        foo: Behavior.extend({\n          initialize: function() {\n            fooBehavior = this;\n          },\n          modelEvents: {\n            'change': handleModelChangeStub,\n            'change:foo': 'handleModelFooChange'\n          },\n          collectionEvents: {\n            'reset': handleCollectionResetStub\n          },\n          handleModelFooChange: handleModelFooChangeStub\n        })\n      };\n\n      FooCollectionView = CollectionView.extend({\n        behaviors: [behaviorSpies.foo]\n      });\n      FooView = View.extend({\n        behaviors: [behaviorSpies.foo]\n      });\n\n      fooModel = new Backbone.Model({foo: 'bar'});\n      fooCollection = new Backbone.Collection([]);\n    });\n\n    it('should proxy model events', function() {\n      /* eslint-disable no-unused-vars */\n      const fooView = new FooView({model: fooModel});\n      fooModel.set('foo', 'baz');\n\n      expect(handleModelChangeStub).to.have.been.calledOnce.and.calledOn(fooBehavior);\n    });\n\n    it('should proxy model events w/ string cbk', function() {\n      /* eslint-disable no-unused-vars */\n      const fooView = new FooView({model: fooModel});\n      fooModel.set('foo', 'baz');\n\n      expect(handleModelFooChangeStub).to.have.been.calledOnce.and.calledOn(fooBehavior);\n    });\n\n    it('should proxy collection events', function() {\n      /* eslint-disable no-unused-vars */\n      const fooCollectionView = new FooCollectionView({collection: fooCollection});\n      fooCollection.reset();\n\n      expect(handleCollectionResetStub).to.have.been.calledOnce.and.calledOn(fooBehavior);\n    });\n\n    it('should unbind model events on view undelegateEntityEvents', function() {\n      const fooView = new FooView({model: fooModel});\n      fooView.undelegateEntityEvents();\n      fooModel.set('foo', 'doge');\n\n      expect(handleModelFooChangeStub).not.to.have.been.called;\n    });\n\n    it('should unbind collection events on view undelegateEntityEvents', function() {\n      const fooCollectionView = new FooCollectionView({collection: fooCollection});\n      fooCollectionView.undelegateEntityEvents();\n      fooCollection.reset();\n\n      expect(handleCollectionResetStub).not.to.have.been.called;\n    });\n  });\n\n  describe('behavior trigger calls', function() {\n    let onRenderStub;\n    let fooView;\n\n    beforeEach(function() {\n      onRenderStub = this.sinon.stub();\n\n      const behaviorSpies = {\n        foo: Behavior.extend({\n          onRender: onRenderStub\n        })\n      };\n\n      const FooView = View.extend({\n        behaviors: [behaviorSpies.foo]\n      });\n\n      fooView = new FooView();\n    });\n\n    it('should call onRender when a view is rendered', function() {\n      fooView.triggerMethod('render');\n\n      expect(onRenderStub).to.have.been.calledOnce;\n    });\n  });\n\n  describe('behavior is evented', function() {\n    let listenToStub;\n    let changeStub;\n    let behavior;\n    let fooModel;\n\n    beforeEach(function() {\n      listenToStub = this.sinon.stub();\n      changeStub = this.sinon.stub();\n\n      behavior = new Behavior({}, new View());\n      fooModel = new Backbone.Model();\n\n      bindEvents(behavior, fooModel, {\n        'change': changeStub\n      });\n\n      behavior.listenTo(fooModel, 'foo', listenToStub);\n    });\n\n    it('should listenTo events', function() {\n      fooModel.trigger('foo');\n\n      expect(listenToStub).to.have.been.calledOnce;\n    });\n\n    it('should support bindEntityEvents', function() {\n      fooModel.set('foo', 'bar');\n\n      expect(changeStub).to.have.been.calledOnce;\n    });\n\n    it('should execute in the specified context', function() {\n      fooModel.trigger('foo');\n\n      expect(listenToStub).to.have.been.calledOnce.and.calledOn(behavior);\n    });\n  });\n\n  describe('#destroy', function() {\n    let behavior;\n    let view;\n\n    beforeEach(function() {\n      view = new View();\n      behavior = new Behavior({}, view);\n      this.sinon.spy(behavior, '_deleteEntityEventHandlers');\n      this.sinon.spy(behavior, 'destroy');\n      this.sinon.spy(behavior, 'stopListening');\n      this.sinon.spy(view, '_removeBehavior');\n\n      behavior.destroy();\n    });\n\n    it('should delete entity event handlers', function() {\n      expect(behavior._deleteEntityEventHandlers).to.have.been.calledOnce;\n    });\n\n    it('should stopListening', function() {\n      expect(behavior.stopListening).to.have.been.calledOnce;\n    });\n\n    it('should remove the behavior from the view', function() {\n      expect(view._removeBehavior).to.have.been.calledOnce;\n    });\n\n    it('should return the behavior', function() {\n      expect(behavior.destroy).to.have.returned(behavior);\n    });\n  });\n\n  describe('#_getEvents', function() {\n    let behavior;\n    let eventHandlers;\n\n    beforeEach(function() {\n      eventHandlers = {\n        'click .test'() {},\n        'click .no-handler': null,\n        'click .test2': 'onHandler'\n      };\n\n      const MyBehavior = Behavior.extend({\n        events() {\n          return eventHandlers;\n        },\n        onHandler: this.sinon.stub()\n      });\n\n      behavior = new MyBehavior();\n\n      this.sinon.spy(behavior, 'normalizeUIKeys');\n      this.sinon.spy(behavior, '_getEvents');\n    });\n\n    it('should pass normalizeUIKeys the results of events', function() {\n      behavior._getEvents();\n      expect(behavior.normalizeUIKeys)\n        .to.have.been.calledOnce\n        .and.calledWith(eventHandlers);\n    });\n\n    it('should convert named handlers to bound instance handlers', function() {\n      const events = behavior._getEvents();\n      const onHandler = _.last(_.values(events));\n      onHandler();\n\n      expect(behavior.onHandler).to.be.calledOn(behavior);\n    });\n\n    it('should remove events without handlers', function() {\n      const events = behavior._getEvents();\n      expect(_.values(events)).to.be.lengthOf(2);\n    });\n\n    it('should namespace the handlers', function() {\n      const events = behavior._getEvents();\n      _.each(_.keys(events), key => {\n        expect(key).to.have.string('.' + behavior.cid);\n      });\n    });\n\n    describe('when there are no events', function() {\n      beforeEach(function() {\n        behavior.events = null;\n        behavior._getEvents();\n      });\n\n      it('should not normalize the keys', function() {\n        expect(behavior.normalizeUIKeys).to.not.have.been.called;\n      });\n\n      it('should return undefined', function() {\n        expect(behavior._getEvents).to.have.returned(undefined);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/child-view-container.spec.js",
    "content": "import _ from 'underscore';\nimport Backbone from 'backbone';\nimport ChildViewContainer from '../../src/child-view-container';\n\ndescribe('#ChildViewContainer', function() {\n\n  describe('emulate collection', function() {\n    let container;\n\n    beforeEach(function() {\n      container = new ChildViewContainer();\n\n      container._set([\n        new Backbone.View({ id: 1 }),\n        new Backbone.View({ id: 2 }),\n        new Backbone.View({ id: 3 })\n      ], true);\n    });\n\n    it('should be able to map over list', function() {\n      expect(container.map('id')).to.eql([1, 2, 3]);\n    });\n  });\n\n  describe('#_init', function() {\n    let container;\n\n    beforeEach(function() {\n      container = new ChildViewContainer();\n\n      container._set([\n        new Backbone.View(),\n        new Backbone.View(),\n        new Backbone.View(),\n        new Backbone.View()\n      ], true);\n\n      container._init();\n    });\n\n    it('should empty all of the view buffers', function() {\n      expect(container._views).to.deep.equal([]);\n      expect(container._viewsByCid).to.deep.equal({});\n      expect(container._indexByModel).to.deep.equal({});\n    });\n\n    it('should update length to 0', function() {\n      expect(container).to.have.lengthOf(0);\n    });\n  });\n\n  describe('#_add', function() {\n    describe('when adding a view that does not have a model', function() {\n      let container;\n      let view;\n      let foundView;\n      let indexView;\n\n      beforeEach(function() {\n        view = new Backbone.View();\n\n        container = new ChildViewContainer();\n\n        container._add(view);\n\n        foundView = container.findByCid(view.cid);\n        indexView = container.findByIndex(0);\n      });\n\n      it('should make the view retrievable by the view\\'s cid', function() {\n        expect(foundView).to.equal(view);\n      });\n\n      it('should make the view retrievable by numeric index', function() {\n        expect(indexView).to.equal(view);\n      });\n\n      it('should update the size of the chidren', function() {\n        expect(container).to.have.lengthOf(1);\n      })\n    });\n\n    describe('when adding a view that has a model', function() {\n      let container;\n      let view;\n      let foundView;\n      let model;\n\n      beforeEach(function() {\n        model = new Backbone.Model();\n        view = new Backbone.View({\n          model: model\n        });\n\n        container = new ChildViewContainer();\n\n        container._add(view);\n\n        foundView = container.findByModel(model);\n      });\n\n      it('should make the view retrievable by the model', function() {\n        expect(foundView).to.equal(view);\n      });\n    });\n\n    describe('when adding a view with an index value', function() {\n      let container;\n      let view;\n      let foundView;\n\n      beforeEach(function() {\n        view = new Backbone.View();\n\n        container = new ChildViewContainer();\n\n        container._set([\n          new Backbone.View(),\n          new Backbone.View(),\n          new Backbone.View(),\n          new Backbone.View()\n        ], true);\n\n        container._add(view, 3);\n\n        foundView = container.findByIndex(3);\n      });\n\n      it('should make the view retrievable by the index', function() {\n        expect(foundView).to.equal(view);\n      });\n    });\n\n  });\n\n  describe('#_set', function() {\n    let container;\n    let views;\n    let originalViews;\n    let originalView;\n\n    beforeEach(function() {\n      views = [\n        new Backbone.View(),\n        new Backbone.View()\n      ];\n\n      container = new ChildViewContainer();\n\n      container._add(new Backbone.View());\n      container._add(new Backbone.View());\n      container._add(new Backbone.View());\n\n      originalViews = container._views;\n      originalView = container._views[0];\n    });\n\n    it('should replace the contents of _views', function() {\n      container._set(views);\n      expect(container._views[0]).to.equal(views[0]);\n    });\n\n    it('should keep the _views array reference', function() {\n      container._set(views);\n      expect(container._views).to.equal(originalViews);\n    });\n\n    describe('when resetting', function() {\n      beforeEach(function() {\n        container._set(views, true);\n      });\n\n      it('should not have an old view', function() {\n        expect(container.hasView(originalView)).to.be.false;\n      });\n\n      it('should have a new view', function() {\n        expect(container.hasView(views[0])).to.be.true;\n      });\n\n      it('should update the length', function() {\n        expect(container).to.have.lengthOf(2);\n      });\n    });\n  });\n\n  describe('#_remove', function() {\n    describe('when removing a view that has a model', function() {\n      let container;\n      let view;\n      let model;\n\n      beforeEach(function() {\n        model = new Backbone.Model();\n\n        view = new Backbone.View({\n          model: model\n        });\n\n        container = new ChildViewContainer();\n\n        container._set([\n          new Backbone.View(),\n          new Backbone.View(),\n          new Backbone.View(),\n          new Backbone.View()\n        ], true);\n\n        container._add(view, 1);\n\n        container._remove(view);\n      });\n\n      it('should update the size of the children', function() {\n        expect(container).to.have.lengthOf(4);\n      });\n\n      it('should remove the index by model', function() {\n        const foundView = container.findByModel(model);\n        expect(foundView).to.be.undefined;\n      });\n\n      it('should remove the index', function() {\n        const foundView = container.findByIndex(1);\n        expect(foundView).to.not.equal(view);\n      });\n\n      it('should remove the view from the container', function() {\n        const foundView = container.findByCid(view.cid);\n        expect(foundView).to.be.undefined;\n      });\n    });\n\n    describe('when removing a view that does not have a model', function() {\n      let container;\n      let view;\n\n      beforeEach(function() {\n        view = new Backbone.View();\n\n        container = new ChildViewContainer();\n\n        container._set([\n          new Backbone.View(),\n          new Backbone.View(),\n          new Backbone.View(),\n          new Backbone.View()\n        ], true);\n\n        container._add(view, 1);\n\n        container._remove(view);\n      });\n\n      it('should update the size of the children', function() {\n        expect(container).to.have.lengthOf(4);\n      });\n\n      it('should remove the index', function() {\n        const foundView = container.findByIndex(1);\n        expect(foundView).to.not.equal(view);\n      });\n\n      it('should remove the view from the container', function() {\n        const foundView = container.findByCid(view.cid);\n        expect(foundView).to.be.undefined;\n      });\n    });\n\n    describe('when removing a view not in the container', function() {\n      let container;\n      let view;\n\n      beforeEach(function() {\n        view = new Backbone.View();\n\n        container = new ChildViewContainer();\n\n        container._set([\n          new Backbone.View(),\n          new Backbone.View(),\n          new Backbone.View(),\n          new Backbone.View()\n        ], true);\n\n        container._remove(view);\n      });\n\n      it('should not remove a view from the container', function() {\n        expect(container).to.have.lengthOf(4);\n      });\n    });\n  });\n\n  describe('when using iterators and collection functions', function() {\n    let container;\n    let view;\n    let views;\n\n    beforeEach(function() {\n      views = [];\n      view = new Backbone.View();\n\n      container = new ChildViewContainer();\n      container._add(view);\n\n      container.each(function(v) {\n        views.push(v);\n      });\n    });\n\n    it('should provide a .each iterator', function() {\n      expect(_.isFunction(container.each)).to.equal(true);\n    });\n\n    it('should iterate the views with the .each function', function() {\n      expect(views[0]).to.equal(view);\n    });\n  });\n\n  describe('#_sort', function() {\n    describe('when using a string comparator', function() {\n      let container;\n      let collection;\n\n      beforeEach(function() {\n        collection = new Backbone.Collection([\n          { text: 'foo' },\n          { text: 'bar' },\n          { text: 'baz' }\n        ]);\n\n        container = new ChildViewContainer();\n\n        collection.each(model => {\n          const view = new Backbone.View({ model });\n          container._add(view);\n        });\n\n        container._sort('text');\n      });\n\n      it('should should re-sort the container', function() {\n        expect(container.findByIndex(0).model).to.equal(collection.models[1]);\n        expect(container.findByIndex(1).model).to.equal(collection.models[2]);\n        expect(container.findByIndex(2).model).to.equal(collection.models[0]);\n      });\n\n      describe('when a view does not have a model', function() {\n        beforeEach(function() {\n          container._add(new Backbone.View());\n          container._sort('text');\n        });\n\n        it('should should re-sort the container', function() {\n          expect(container.findByIndex(0).model).to.equal(collection.models[1]);\n          expect(container.findByIndex(1).model).to.equal(collection.models[2]);\n          expect(container.findByIndex(2).model).to.equal(collection.models[0]);\n        });\n\n        it('should sort the view without model at the end', function() {\n          expect(container.findByIndex(3).model).to.be.undefined;\n        });\n      });\n    });\n\n    describe('when using a sortBy iterator', function() {\n      let container;\n      let collection;\n      let comparator;\n\n      beforeEach(function() {\n        collection = new Backbone.Collection([\n          { text: 'foo' },\n          { text: 'bar' },\n          { text: 'baz' }\n        ]);\n\n        container = new ChildViewContainer();\n\n        collection.each(model => {\n          const view = new Backbone.View({ model });\n          container._add(view);\n        });\n\n        this.comparator = function(view) {\n          return view.model.get('text').substring(1);\n        };\n\n        comparator = this.sinon.spy(this, 'comparator');\n\n        container._sort(this.comparator, this);\n      });\n\n      it('should call the comparator with context', function() {\n        expect(comparator).to.have.been.calledOn(this);\n      });\n\n      it('should should re-sort the container', function() {\n        expect(container.findByIndex(0).model).to.equal(collection.models[1]);\n        expect(container.findByIndex(1).model).to.equal(collection.models[2]);\n        expect(container.findByIndex(2).model).to.equal(collection.models[0]);\n      });\n    });\n\n    describe('when using a sort iterator', function() {\n      let container;\n      let collection;\n      let comparator;\n\n      beforeEach(function() {\n        collection = new Backbone.Collection([\n          { text: 'foo' },\n          { text: 'bar' },\n          { text: 'baz' }\n        ]);\n\n        container = new ChildViewContainer();\n\n        collection.each(model => {\n          const view = new Backbone.View({ model });\n          container._add(view);\n        });\n\n        this.comparator = function(viewa, viewb) {\n          const aText = viewa.model.get('text');\n          const bText = viewb.model.get('text');\n          return bText.localeCompare(aText);\n        };\n\n        comparator = this.sinon.spy(this, 'comparator');\n\n        container._sort(this.comparator, this);\n      });\n\n      it('should call the comparator with context', function() {\n        expect(comparator).to.have.been.calledOn(this);\n      });\n\n      it('should re-sort the container', function() {\n        expect(container.findByIndex(0).model).to.equal(collection.models[0]);\n        expect(container.findByIndex(1).model).to.equal(collection.models[2]);\n        expect(container.findByIndex(2).model).to.equal(collection.models[1]);\n      });\n    });\n  });\n\n  describe('#_swap', function() {\n    let container;\n    let collection;\n\n    beforeEach(function() {\n      collection = new Backbone.Collection([\n        { id: 1 },\n        { id: 2 },\n        { id: 3 }\n      ]);\n\n      container = new ChildViewContainer();\n\n      collection.each(model => {\n        const view = new Backbone.View({ model });\n        container._add(view);\n      });\n\n    });\n\n    describe('when both views are in the container', function() {\n      it('should swap the views', function() {\n        container._swap(container.findByIndex(0), container.findByIndex(2));\n\n        expect(container.findByIndex(0).model).to.equal(collection.get(3));\n        expect(container.findByIndex(1).model).to.equal(collection.get(2));\n        expect(container.findByIndex(2).model).to.equal(collection.get(1));\n      });\n    });\n\n    describe('when the first view is not in the container', function() {\n      it('should not swap views', function() {\n        container._swap(new Backbone.View(), container.findByIndex(2));\n\n        expect(container.findByIndex(0).model).to.equal(collection.get(1));\n        expect(container.findByIndex(1).model).to.equal(collection.get(2));\n        expect(container.findByIndex(2).model).to.equal(collection.get(3));\n      });\n    });\n\n    describe('when the second view is not in the container', function() {\n      it('should not swap views', function() {\n        container._swap(container.findByIndex(0), new Backbone.View());\n\n        expect(container.findByIndex(0).model).to.equal(collection.get(1));\n        expect(container.findByIndex(1).model).to.equal(collection.get(2));\n        expect(container.findByIndex(2).model).to.equal(collection.get(3));\n      });\n    });\n  });\n\n  describe('#hasView', function() {\n    it('should return true if a view exists in the container', function() {\n      const container = new ChildViewContainer();\n      const view = new Backbone.View();\n      container._add(view);\n      expect(container.hasView(view)).to.be.true;\n    });\n\n    it('should return false if a view does not exist in the container', function() {\n      const container = new ChildViewContainer();\n      const view = new Backbone.View();\n      expect(container.hasView(view)).to.be.false;\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/collection-view/collection-view-children.spec.js",
    "content": "// Tests for the children container integration\n\nimport $ from 'jquery';\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport CollectionView from '../../../src/collection-view';\nimport ChildViewContainer from '../../../src/child-view-container';\nimport View from '../../../src/view';\nimport Region from '../../../src/region';\n\n\ndescribe('CollectionView Children', function() {\n  const collection = new Backbone.Collection([\n    { id: 1 },\n    { id: 2 },\n    { id: 3 }\n  ]);\n  let MyCollectionView;\n\n  beforeEach(function() {\n    const MyChildView = View.extend({\n      template: _.noop\n    });\n\n    MyCollectionView = CollectionView.extend({\n      childView: MyChildView\n    });\n  });\n\n  describe('when instantiating a CollectionView', function() {\n    let myCollectionView;\n\n    beforeEach(function() {\n      myCollectionView = new MyCollectionView();\n    });\n\n    it('should instantiate the children container', function() {\n      expect(myCollectionView.children).to.be.instanceOf(ChildViewContainer);\n    });\n\n    it('should instantiate the children container', function() {\n      expect(myCollectionView.children).to.be.instanceOf(ChildViewContainer);\n    });\n  });\n\n  describe('when rendering a CollectionView', function() {\n    let myCollectionView;\n\n    beforeEach(function() {\n      myCollectionView = new MyCollectionView({ collection });\n      myCollectionView.onBeforeRenderChildren = this.sinon.stub();\n      myCollectionView.onRenderChildren = this.sinon.stub();\n      myCollectionView.onBeforeAddChild = this.sinon.stub();\n      myCollectionView.onAddChild = this.sinon.stub();\n\n      this.sinon.spy(myCollectionView.children, '_add');\n      myCollectionView.render();\n    });\n\n    it('should add children to match the collection', function() {\n      collection.each((model, index) => {\n        const call = myCollectionView.children._add.getCall(index);\n        expect(call.args[0].model).to.equal(model);\n        expect(call.args[1]).to.equal(undefined);\n      });\n    });\n\n    it('should trigger \"before:render:children\"', function() {\n      expect(myCollectionView.onBeforeRenderChildren)\n        .to.be.calledOnce.and.calledWith(myCollectionView, myCollectionView.children._views);\n    });\n\n    it('should trigger \"render:children\"', function() {\n      expect(myCollectionView.onRenderChildren)\n        .to.be.calledOnce.and.calledWith(myCollectionView, myCollectionView.children._views);\n    });\n\n    it('should trigger \"before:add:child\" for each model', function() {\n      collection.each((model, index) => {\n        const call = myCollectionView.onBeforeAddChild.getCall(index);\n        expect(call.args[0]).to.equal(myCollectionView);\n        expect(call.args[1].model).to.equal(model);\n      });\n    });\n\n    it('should trigger \"add:child\" for each model', function() {\n      collection.each((model, index) => {\n        const call = myCollectionView.onAddChild.getCall(index);\n        expect(call.args[0]).to.equal(myCollectionView);\n        expect(call.args[1].model).to.equal(model);\n      });\n    });\n  });\n\n  describe('#swapChildViews', function() {\n    let collectionView;\n\n    beforeEach(function() {\n      collectionView = new MyCollectionView({ collection });\n      collectionView.render();\n    });\n\n    describe('when both children are in the collectionview', function() {\n      let view1;\n      let view2;\n\n      beforeEach(function() {\n        view1 = collectionView.children.first();\n        view2 = collectionView.children.last();\n      });\n\n      it('should swap the children', function() {\n        this.sinon.spy(collectionView.children, '_swap');\n\n        collectionView.swapChildViews(view1, view2);\n\n        expect(collectionView.children._swap).to.have.been.calledOnce\n          .and.calledWith(view1, view2);\n      });\n\n      it('should swap the filtered children', function() {\n        this.sinon.spy(collectionView.children, '_swap');\n\n        collectionView.swapChildViews(view1, view2);\n\n        expect(collectionView.children._swap).to.have.been.calledOnce\n          .and.calledWith(view1, view2);\n      });\n\n      it('should swap the els in the DOM', function() {\n        this.sinon.spy(collectionView.Dom, 'swapEl');\n\n        collectionView.swapChildViews(view1, view2);\n\n        expect(collectionView.Dom.swapEl).to.have.been.calledOnce\n          .and.calledWith(view1.el, view2.el);\n      });\n\n      it('should return the collectionView', function() {\n        expect(collectionView.swapChildViews(view1, view2)).to.equal(collectionView);\n      });\n\n      it('should not re-filter the collectionView', function() {\n        this.sinon.spy(collectionView, 'filter');\n\n        collectionView.swapChildViews(view1, view2);\n\n        expect(collectionView.filter).to.not.be.called;\n      });\n\n      describe('when one of the children is attached but the other is not', function() {\n        it('should re-filter the collectionView', function() {\n          collectionView.setFilter(view => {\n            return view.model.id !== 1;\n          });\n\n          this.sinon.spy(collectionView, 'filter');\n\n          collectionView.swapChildViews(view1, view2);\n\n          expect(collectionView.filter).to.have.been.calledOnce;\n        });\n      });\n    });\n\n    describe('when the first child is not in the collectionview', function() {\n      it('should throw an error', function() {\n        const view1 = new View();\n        const view2 = collectionView.children.first();\n\n        expect(function() {\n          collectionView.swapChildViews(view1, view2);\n        }).to.throw();\n      });\n    });\n\n    describe('when the second child is not in the collectionview', function() {\n      it('should throw an error', function() {\n        const view1 = collectionView.children.first();\n        const view2 = new View();\n\n        expect(function() {\n          collectionView.swapChildViews(view1, view2);\n        }).to.throw();\n      });\n    });\n  });\n\n  describe('#addChildView', function() {\n    let myCollectionView;\n    let addView;\n\n    beforeEach(function() {\n      myCollectionView = new MyCollectionView({ collection });\n      addView = new View({ template: _.noop });\n\n      myCollectionView.render();\n      myCollectionView.onBeforeRenderChildren = this.sinon.stub();\n      myCollectionView.onRenderChildren = this.sinon.stub();\n      myCollectionView.onBeforeAddChild = this.sinon.stub();\n      myCollectionView.onAddChild = this.sinon.stub();\n\n      this.sinon.spy(myCollectionView.children, '_add');\n      this.sinon.spy(myCollectionView, 'addChildView');\n      this.sinon.spy(myCollectionView, 'sort');\n    });\n\n    describe('when called with preventRender option', function() {\n\n      beforeEach(function() {\n        myCollectionView.addChildView(addView, { preventRender: true });\n      });\n\n      it('should return the added view', function() {\n        expect(myCollectionView.addChildView).to.have.returned(addView);\n      });\n\n      it('should add to the children container', function() {\n        expect(myCollectionView.children._add)\n          .to.have.been.calledOnce.and.calledWith(addView);\n      });\n\n      it('should not call sort', function() {\n        expect(myCollectionView.sort)\n          .to.be.not.called;\n      });\n\n      it('should not trigger \"before:render:children\"', function() {\n        expect(myCollectionView.onBeforeRenderChildren)\n          .to.be.not.called;\n      });\n\n      it('should not trigger \"render:children\"', function() {\n        expect(myCollectionView.onRenderChildren)\n          .to.be.not.called;\n      });\n\n      it('should trigger \"add:child\"', function() {\n        expect(myCollectionView.onAddChild)\n          .to.be.calledOnce.and.calledWith(myCollectionView, addView);\n      });\n\n      it('should trigger \"before:add:child\"', function() {\n        expect(myCollectionView.onBeforeAddChild)\n          .to.be.calledOnce.and.calledWith(myCollectionView, addView);\n      });\n\n    });\n\n    describe('when called with an index in options', function() {\n      const addIndex = 1;\n      beforeEach(function() {\n        myCollectionView.addChildView(addView, 0, { preventRender: true, index: addIndex });\n      });\n\n      it('should add to the children container at the index from options', function() {\n        expect(myCollectionView.children._add)\n          .to.have.been.calledOnce.and.calledWith(addView, addIndex);\n      });\n\n    });\n\n    describe('when called without preventRender after preventReder calls', function() {\n      const addIndex = 1;\n      beforeEach(function() {\n        const addView2 = new View({ template: _.noop });\n        myCollectionView.addChildView(addView, { preventRender: true, index: addIndex });\n        myCollectionView.addChildView(addView2);\n      });\n\n      it('should not use the _addedViews perf', function() {\n        expect(myCollectionView.onRenderChildren.args[0][1]).to.have.lengthOf(myCollectionView.children.length);\n      });\n\n    });\n\n    describe('when collection changed having unrendered views', function() {\n      let onRender;\n      beforeEach(function() {\n        onRender = this.sinon.stub();\n        let addView1 = new View({ template: _.noop, onRender });\n        let addView2 = new View({ template: _.noop, onRender });\n        myCollectionView.addChildView(addView1, { preventRender: true, index: 0 });\n        myCollectionView.addChildView(addView2, { preventRender: true });\n        collection.add({id: 4});\n      });\n      afterEach(function() {\n        collection.remove(collection.last());\n      });\n      it('should render all unrendered views', function() {\n        expect(onRender).to.have.been.calledTwice;\n      });\n    });\n\n    describe('when called without an index', function() {\n      beforeEach(function() {\n\n        // Needed to test _addedViews perf\n        myCollectionView.viewComparator = false;\n        myCollectionView.addChildView(addView);\n      });\n\n      it('should return the added view', function() {\n        expect(myCollectionView.addChildView).to.have.returned(addView);\n      });\n\n      it('should add to the children container', function() {\n        expect(myCollectionView.children._add)\n          .to.have.been.calledOnce.and.calledWith(addView);\n      });\n\n      it('should trigger \"before:render:children\"', function() {\n        expect(myCollectionView.onBeforeRenderChildren)\n          .to.be.calledOnce.and.calledWith(myCollectionView);\n      });\n\n      it('should trigger \"render:children\"', function() {\n        expect(myCollectionView.onRenderChildren)\n          .to.be.calledOnce.and.calledWith(myCollectionView);\n      });\n\n      it('should use the _addedViews perf', function() {\n        expect(myCollectionView.onRenderChildren.args[0][1]).to.have.lengthOf(1);\n      });\n\n      it('should trigger \"add:child\"', function() {\n        expect(myCollectionView.onAddChild)\n          .to.be.calledOnce.and.calledWith(myCollectionView, addView);\n      });\n\n      it('should trigger \"before:add:child\"', function() {\n        expect(myCollectionView.onBeforeAddChild)\n          .to.be.calledOnce.and.calledWith(myCollectionView, addView);\n      });\n\n      it('should sort the children', function() {\n        expect(myCollectionView.sort).to.have.been.calledOnce;\n      });\n    });\n\n    describe('when called with an index', function() {\n      const addIndex = 1;\n\n      beforeEach(function() {\n        myCollectionView.addChildView(addView, addIndex);\n      });\n\n      it('should add to the children container at the index', function() {\n        expect(myCollectionView.children._add)\n          .to.have.been.calledOnce.and.calledWith(addView, addIndex);\n      });\n\n      it('should trigger \"before:render:children\"', function() {\n        expect(myCollectionView.onBeforeRenderChildren)\n          .to.be.calledOnce.and.calledWith(myCollectionView);\n      });\n\n      it('should trigger \"render:children\"', function() {\n        expect(myCollectionView.onRenderChildren)\n          .to.be.calledOnce.and.calledWith(myCollectionView);\n      });\n\n      it('should not use _addedViews perf', function() {\n        expect(myCollectionView.onRenderChildren.args[0][1]).to.have.lengthOf(myCollectionView.children.length);\n      });\n\n      it('should trigger \"add:child\"', function() {\n        expect(myCollectionView.onAddChild)\n          .to.be.calledOnce.and.calledWith(myCollectionView, addView);\n      });\n\n      it('should trigger \"before:add:child\"', function() {\n        expect(myCollectionView.onBeforeAddChild)\n          .to.be.calledOnce.and.calledWith(myCollectionView, addView);\n      });\n\n      it('should not sort the children', function() {\n        expect(myCollectionView.sort).to.not.have.been.called;\n      });\n    });\n\n    describe('when the collectionView is not rendered', function() {\n      let unrenderedCollectionView;\n\n      beforeEach(function() {\n        unrenderedCollectionView = new MyCollectionView({ collection });\n        this.sinon.spy(unrenderedCollectionView, 'render');\n\n        unrenderedCollectionView.addChildView(addView);\n      });\n\n      it('should render the collectionView', function() {\n        expect(unrenderedCollectionView.render).to.have.been.calledOnce;\n      });\n    });\n\n    describe('when called without a view', function() {\n      beforeEach(function() {\n        myCollectionView.addChildView();\n      });\n\n      it('should not trigger \"add:child\"', function() {\n        expect(myCollectionView.onAddChild).to.not.be.called;\n      });\n    });\n\n    describe('when called with a destroyed view', function() {\n      let destroyedView;\n\n      beforeEach(function() {\n        destroyedView = new View();\n        destroyedView.destroy();\n\n        myCollectionView.addChildView(destroyedView);\n      });\n\n      it('should not trigger \"add:child\"', function() {\n        expect(myCollectionView.onAddChild).to.not.be.called;\n      });\n\n      it('should return the destroyed view', function() {\n        expect(myCollectionView.addChildView).to.have.returned(destroyedView);\n      });\n    });\n\n    describe('when called with showed view', function() {\n      let anotherCollectionView;\n\n      beforeEach(function() {\n        anotherCollectionView = new MyCollectionView();\n        addView = new View({ template: _.noop });\n        anotherCollectionView.addChildView(addView);\n      });\n\n      it('should throw an error', function() {\n        expect(myCollectionView.addChildView.bind(myCollectionView, addView)).to.throw();\n      });\n\n    });\n\n    describe('when adding detached view', function() {\n      let anotherCollectionView;\n      let region;\n      beforeEach(function() {\n        anotherCollectionView = new MyCollectionView();\n        this.setFixtures('<div id=\"region\"></div>');\n        region = new Region({ el: '#region' });\n        addView = new View({ template: _.noop });\n      });\n\n      it('should not throw an error if view was detached from CollectionView',function() {\n        anotherCollectionView.addChildView(addView);\n        anotherCollectionView.detachChildView(addView);\n        expect(myCollectionView.addChildView.bind(myCollectionView, addView)).to.not.throw();\n      });\n\n      it('should not throw an error if view was detached from Region',function() {\n        region.show(addView);\n        region.detachView(addView);\n        expect(myCollectionView.addChildView.bind(myCollectionView, addView)).to.not.throw();\n      });\n\n    });\n  });\n\n  describe('#detachChildView', function() {\n    let myCollectionView;\n    let detachView;\n\n    beforeEach(function() {\n      myCollectionView = new MyCollectionView({ collection });\n      this.sinon.spy(myCollectionView, 'removeChildView');\n      this.sinon.spy(myCollectionView, 'detachChildView');\n\n      myCollectionView.render();\n      detachView = myCollectionView.children.first();\n\n      myCollectionView.detachChildView(detachView);\n    });\n\n    it('should return the detached view', function() {\n      expect(myCollectionView.detachChildView).to.have.returned(detachView);\n    });\n\n    it('should call removeChildView', function() {\n      expect(myCollectionView.removeChildView)\n        .to.have.been.calledOnce.and.calledWith(detachView, { shouldDetach: true });\n    });\n\n  });\n\n  describe('#removeChildView', function() {\n    let myCollectionView;\n    let removeView;\n\n    beforeEach(function() {\n      myCollectionView = new MyCollectionView({ collection });\n      myCollectionView.onBeforeRemoveChild = this.sinon.stub();\n      myCollectionView.onRemoveChild = this.sinon.stub();\n\n      this.sinon.spy(myCollectionView.children, '_remove');\n      this.sinon.spy(myCollectionView, 'removeChildView');\n\n      myCollectionView.render();\n      removeView = myCollectionView.children.first();\n\n      myCollectionView.removeChildView(removeView);\n    });\n\n    it('should return the removed view', function() {\n      expect(myCollectionView.removeChildView).to.have.returned(removeView);\n    });\n\n    it('should destroy the removed view', function() {\n      expect(removeView.isDestroyed()).to.be.true;\n    });\n\n    it('should remove from the children container', function() {\n      expect(myCollectionView.children._remove)\n        .to.have.been.calledOnce.and.calledWith(removeView);\n    });\n\n    it('should trigger \"remove:child\"', function() {\n      expect(myCollectionView.onRemoveChild)\n        .to.be.calledOnce.and.calledWith(myCollectionView, removeView);\n    });\n\n    it('should trigger \"before:remove:child\"', function() {\n      expect(myCollectionView.onBeforeRemoveChild)\n        .to.be.calledOnce.and.calledWith(myCollectionView, removeView);\n    });\n\n    describe('when called without a view', function() {\n      beforeEach(function() {\n        myCollectionView.onRemoveChild.reset();\n        myCollectionView.removeChildView.resetHistory();\n        myCollectionView.removeChildView();\n      });\n\n      it('should not trigger \"remove:child\"', function() {\n        expect(myCollectionView.onRemoveChild).to.not.be.called;\n      });\n    });\n\n    // Used only by #detachChildView\n    describe('when called with shouldDetach', function() {\n      let detachView;\n\n      beforeEach(function() {\n        myCollectionView.onRemoveChild.reset();\n        myCollectionView.removeChildView.resetHistory();\n        this.sinon.spy(myCollectionView, 'detachHtml');\n\n        detachView = myCollectionView.children.first();\n\n        myCollectionView.removeChildView(detachView, { shouldDetach: true });\n      });\n\n      it('should not destroy the view', function() {\n        expect(detachView.isDestroyed()).to.be.false;\n      });\n\n      it('should detach the view\\'s html', function() {\n        expect(myCollectionView.detachHtml).to.be.calledOnce.and.calledWith(detachView);\n      });\n    });\n  });\n\n  describe('when destroying a childView', function() {\n    let myCollectionView;\n    let destroyedView;\n\n    beforeEach(function() {\n      myCollectionView = new MyCollectionView({ collection });\n      this.sinon.spy(myCollectionView, 'removeChildView');\n\n      myCollectionView.render();\n      destroyedView = myCollectionView.children.first();\n      destroyedView.destroy();\n    });\n\n    it('should remove the childView', function() {\n      expect(myCollectionView.removeChildView)\n        .to.have.been.calledOnce.and.calledWith(destroyedView);\n    });\n  });\n\n  // The lifecycle is tested with Backbone.View\n  describe('childView lifecycle', function() {\n    let myCollectionView;\n    let childView;\n\n    beforeEach(function() {\n      myCollectionView = new MyCollectionView();\n\n      const ChildView = Backbone.View.extend({\n        onBeforeRender: this.sinon.stub(),\n        onRender: this.sinon.stub(),\n        onBeforeAttach: this.sinon.stub(),\n        onAttach: this.sinon.stub(),\n        onBeforeDetach: this.sinon.stub(),\n        onDetach: this.sinon.stub(),\n        onBeforeDestroy: this.sinon.stub(),\n        onDestroy: this.sinon.stub()\n      });\n\n      _.extend(ChildView.prototype, Marionette.Events);\n\n      childView = new ChildView();\n    });\n\n    describe('when the collectionView is attached', function() {\n      describe('when attaching the childview', function() {\n        beforeEach(function() {\n          const myRegion = new Region({ el: '#fixtures' });\n          myRegion.show(myCollectionView);\n          myCollectionView.addChildView(childView);\n        });\n\n        it('should trigger \"before:render\" event on the childView', function() {\n          expect(childView.onBeforeRender).to.have.been.calledOnce.and.calledWith(childView);\n        });\n\n        it('should trigger \"render\" event on the childView', function() {\n          expect(childView.onRender).to.have.been.calledOnce.and.calledWith(childView);\n        });\n\n        it('should trigger \"before:attach\" event on the childView', function() {\n          expect(childView.onBeforeAttach).to.have.been.calledOnce.and.calledWith(childView);\n        });\n\n        it('should trigger \"attach\" event on the childView', function() {\n          expect(childView.onAttach).to.have.been.calledOnce.and.calledWith(childView);\n        });\n\n        // All children are possibly attached when adding any children\n        describe('when attaching another childview', function() {\n          let anotherView;\n\n          beforeEach(function() {\n            const AnotherView = View.extend({\n              template: _.noop,\n              onBeforeAttach: this.sinon.stub(),\n              onAttach: this.sinon.stub()\n            })\n            anotherView = new AnotherView();\n            childView.onBeforeAttach.reset();\n            childView.onAttach.reset();\n            myCollectionView.addChildView(anotherView, 0);\n          });\n\n          it('should not trigger \"before:attach\" event on the childView', function() {\n            expect(childView.onBeforeAttach).to.not.be.called;\n          });\n\n          it('should not trigger \"attach\" event on the childView', function() {\n            expect(childView.onAttach).to.not.be.called;\n          });\n\n          it('should trigger \"before:attach\" event on anotherView', function() {\n            expect(anotherView.onBeforeAttach).to.have.been.calledOnce.and.calledWith(anotherView);\n          });\n\n          it('should trigger \"attach\" event on anotherView', function() {\n            expect(anotherView.onAttach).to.have.been.calledOnce.and.calledWith(anotherView);\n          });\n        });\n\n        describe('when attaching another childview at the end', function() {\n          let anotherView;\n          let AnotherView;\n          beforeEach(function() {\n            AnotherView = View.extend({\n              template: _.noop,\n              onBeforeAttach: this.sinon.stub(),\n              onAttach: this.sinon.stub()\n            })\n            anotherView = new AnotherView();\n            childView.onBeforeAttach.reset();\n            childView.onAttach.reset();\n            myCollectionView.addChildView(anotherView);\n          });\n\n          it('should not trigger \"before:attach\" event on the childView', function() {\n            expect(childView.onBeforeAttach).to.not.be.called;\n          });\n\n          it('should not trigger \"attach\" event on the childView', function() {\n            expect(childView.onAttach).to.not.be.called;\n          });\n\n          it('should trigger \"before:attach\" event on anotherView', function() {\n            expect(anotherView.onBeforeAttach).to.have.been.calledOnce.and.calledWith(anotherView);\n          });\n\n          it('should trigger \"attach\" event on anotherView', function() {\n            expect(anotherView.onAttach).to.have.been.calledOnce.and.calledWith(anotherView);\n          });\n\n          it('should only append the added child', function() {\n            this.sinon.stub(myCollectionView, 'attachHtml');\n\n            // Only true if not maintaining collection sort\n            myCollectionView.sortWithCollection = false;\n            myCollectionView.addChildView(new AnotherView());\n            const callArgs = myCollectionView.attachHtml.args[0];\n            const attachHtmlEls = callArgs[0];\n            expect($(attachHtmlEls).children()).to.have.lengthOf(1);\n          });\n\n          it('should still have all children attached', function() {\n            expect(myCollectionView.$el.children()).to.have.lengthOf(2);\n          });\n        });\n\n        describe('when removing the childview', function() {\n          beforeEach(function() {\n            myCollectionView.removeChildView(childView);\n          });\n\n          it('should trigger \"before:detach\" event on the childView', function() {\n            expect(childView.onBeforeDetach).to.have.been.calledOnce.and.calledWith(childView);\n          });\n\n          it('should trigger \"detach\" event on the childView', function() {\n            expect(childView.onDetach).to.have.been.calledOnce.and.calledWith(childView);\n          });\n\n          it('should trigger \"before:destroy\" event on the childView', function() {\n            expect(childView.onBeforeDestroy).to.have.been.calledOnce.and.calledWith(childView);\n          });\n\n          it('should trigger \"destroy\" event on the childView', function() {\n            expect(childView.onDestroy).to.have.been.calledOnce.and.calledWith(childView);\n          });\n        });\n\n        describe('when detaching the childview', function() {\n          beforeEach(function() {\n            myCollectionView.detachChildView(childView);\n          });\n\n          it('should trigger \"before:detach\" event on the childView', function() {\n            expect(childView.onBeforeDetach).to.have.been.calledOnce.and.calledWith(childView);\n          });\n\n          it('should trigger \"detach\" event on the childView', function() {\n            expect(childView.onDetach).to.have.been.calledOnce.and.calledWith(childView);\n          });\n\n          it('should not trigger \"before:destroy\" event on the childView', function() {\n            expect(childView.onBeforeDestroy).to.not.be.called;\n          });\n\n          it('should not trigger \"destroy\" event on the childView', function() {\n            expect(childView.onDestroy).to.not.be.called;\n          });\n        });\n      });\n\n      describe('when the collectionView is not monitoring events', function() {\n        beforeEach(function() {\n          const myRegion = new Region({ el: '#fixtures' });\n          myRegion.show(myCollectionView);\n          myCollectionView.monitorViewEvents = false;\n          myCollectionView.addChildView(childView);\n        });\n\n        it('should not trigger \"before:attach\" event on the childView', function() {\n          expect(childView.onBeforeAttach).to.not.be.called;\n        });\n\n        it('should not trigger \"attach\" event on the childView', function() {\n          expect(childView.onAttach).to.not.be.called;\n        });\n\n        describe('when removing the childview', function() {\n          beforeEach(function() {\n            myCollectionView.removeChildView(childView);\n          });\n\n          it('should not trigger \"before:detach\" event on the childView', function() {\n            expect(childView.onBeforeDetach).to.not.be.called;\n          });\n\n          it('should not trigger \"detach\" event on the childView', function() {\n            expect(childView.onDetach).to.not.be.called;\n          });\n        });\n\n        describe('when detaching the childview', function() {\n          beforeEach(function() {\n            myCollectionView.detachChildView(childView);\n          });\n\n          it('should not trigger \"before:detach\" event on the childView', function() {\n            expect(childView.onBeforeDetach).to.not.be.called;\n          });\n\n          it('should not trigger \"detach\" event on the childView', function() {\n            expect(childView.onDetach).to.not.be.called;\n          });\n        });\n      });\n    });\n\n    describe('when the collectionView is not attached', function() {\n      beforeEach(function() {\n        myCollectionView.addChildView(childView);\n        myCollectionView.removeChildView(childView);\n      });\n\n      it('should trigger \"before:render\" event on the childView', function() {\n        expect(childView.onBeforeRender).to.have.been.calledOnce.and.calledWith(childView);\n      });\n\n      it('should trigger \"render\" event on the childView', function() {\n        expect(childView.onRender).to.have.been.calledOnce.and.calledWith(childView);\n      });\n\n      it('should not trigger \"before:attach\" event on the childView', function() {\n        expect(childView.onBeforeAttach).to.not.be.called;\n      });\n\n      it('should not trigger \"attach\" event on the childView', function() {\n        expect(childView.onAttach).to.not.be.called;\n      });\n\n      it('should not trigger \"before:detach\" event on the childView', function() {\n        expect(childView.onBeforeDetach).to.not.be.called;\n      });\n\n      it('should not trigger \"detach\" event on the childView', function() {\n        expect(childView.onDetach).to.not.be.called;\n      });\n\n      it('should trigger \"before:destroy\" event on the childView', function() {\n        expect(childView.onBeforeDestroy).to.have.been.calledOnce.and.calledWith(childView);\n      });\n\n      it('should trigger \"destroy\" event on the childView', function() {\n        expect(childView.onDestroy).to.have.been.calledOnce.and.calledWith(childView);\n      });\n    });\n  });\n\n  describe('when destroying the collectionView with children', function() {\n    let myCollectionView;\n\n    beforeEach(function() {\n      myCollectionView = new MyCollectionView({ collection });\n      myCollectionView.onBeforeDestroyChildren = this.sinon.stub();\n      myCollectionView.onDestroyChildren = this.sinon.stub();\n\n      this.sinon.spy(myCollectionView.children, '_init');\n      myCollectionView.render();\n    });\n\n    it('should destroy each view', function() {\n      myCollectionView.destroy();\n      myCollectionView.children.each(view => {\n        expect(view.isDestroyed()).to.be.true;\n      });\n    });\n\n    it('should trigger \"before:destroy:children\"', function() {\n      myCollectionView.destroy();\n      expect(myCollectionView.onBeforeDestroyChildren)\n        .to.be.calledOnce.and.calledWith(myCollectionView);\n    });\n\n    it('should reinit the children container', function() {\n      myCollectionView.destroy();\n      expect(myCollectionView.children._init).to.be.calledOnce;\n    });\n\n    it('should trigger \"destroy:children\"', function() {\n      myCollectionView.destroy();\n      expect(myCollectionView.onDestroyChildren)\n        .to.be.calledOnce.and.calledWith(myCollectionView);\n    });\n\n    describe('when view events are not monitored', function() {\n      it('should detach the contents from the dom prior to destroying', function() {\n        myCollectionView.Dom = _.clone(myCollectionView.Dom);\n        myCollectionView.Dom.detachContents = this.sinon.stub();\n        myCollectionView.monitorViewEvents = false;\n        myCollectionView.destroy();\n        expect(myCollectionView.Dom.detachContents).to.have.been.calledOnce\n          .and.calledWith(myCollectionView.el, myCollectionView.$el)\n          .and.calledAfter(myCollectionView.onBeforeDestroyChildren)\n          .and.calledBefore(myCollectionView.onDestroyChildren);\n      });\n    });\n  });\n\n  describe('when destroying the collectionView without children', function() {\n    let myCollectionView;\n\n    beforeEach(function() {\n      myCollectionView = new MyCollectionView({ collection });\n      myCollectionView.onDestroyChildren = this.sinon.stub();\n\n      myCollectionView.destroy();\n    });\n\n    it('should not trigger \"destroy:children\"', function() {\n      expect(myCollectionView.onDestroyChildren).to.not.be.called;\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/collection-view/collection-view-childviewcontainer.sepc.js",
    "content": "import _ from 'underscore';\nimport Backbone from 'backbone';\nimport CollectionView from '../../../src/collection-view';\nimport View from '../../../src/view';\n\ndescribe('CollectionView - childViewContainer', function() {\n  let MyCollectionView;\n  let ChildView;\n  let template;\n  let collection;\n\n  beforeEach(function() {\n    collection = new Backbone.Collection([{ foo: 'bar' }, { foo: 'baz' }]);\n\n    template = _.template('<ul id=\"foo\"></ul>bazinga');\n\n    ChildView = View.extend({\n      tagName: 'li',\n      template: _.template('<%=foo%>')\n    });\n\n    MyCollectionView = CollectionView.extend({\n      childView: ChildView\n    });\n  });\n\n  describe('when childViewContainer is undefined', function() {\n    it('should set the $container to the $el', function() {\n      const myCollectionView = new MyCollectionView({ collection });\n      myCollectionView.render();\n\n      expect(myCollectionView.$container).to.equal(myCollectionView.$el);\n    });\n  });\n\n  describe('when childViewContainer is defined', function() {\n    describe('when a selector within the el', function() {\n      it('should should put the children within the found $container', function() {\n        const myCollectionView = new MyCollectionView({\n          collection,\n          template,\n          childViewContainer: '#foo'\n        });\n        myCollectionView.render();\n\n        expect(myCollectionView.$container).to.have.$text('barbaz');\n      });\n    });\n\n    describe('when a selector not within the el', function() {\n      it('should should throw an error', function() {\n        const myCollectionView = new MyCollectionView({\n          collection,\n          template,\n          childViewContainer: '#bar'\n        });\n\n        expect(myCollectionView.render.bind(myCollectionView))\n          .to.throw('The specified \"childViewContainer\" was not found: #bar');\n      });\n    });\n\n    describe('when a function', function() {\n      it('should should put the children within the found $container', function() {\n        const myCollectionView = new MyCollectionView({\n          collection,\n          template,\n          childViewContainer: _.constant('#foo')\n        });\n        myCollectionView.render();\n\n        expect(myCollectionView.$container).to.have.$text('barbaz');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/collection-view/collection-view-data.spec.js",
    "content": "// Anything related to Bb.collection events\n\nimport $ from 'jquery';\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport CollectionView from '../../../src/collection-view';\nimport View from '../../../src/view';\n\ndescribe('CollectionView Data', function() {\n  let MyCollectionView;\n\n  beforeEach(function() {\n    const MyChildView = View.extend({\n      template: _.noop\n    });\n\n    MyCollectionView = CollectionView.extend({\n      childView: MyChildView\n    });\n  });\n\n  describe('when the collection sorts', function() {\n    let collection;\n\n    beforeEach(function() {\n      collection = new Backbone.Collection([{ id: 1 }, { id: 3 }, { id: 2 }], { comparator: 'id' });\n    });\n\n    describe('when sortWithCollection is false', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView({\n          collection,\n          sortWithCollection: false\n        });\n\n        myCollectionView.render();\n\n        this.sinon.spy(myCollectionView, 'sort');\n\n        myCollectionView.collection.sort();\n      });\n\n      it('should not call the sort method', function() {\n        expect(myCollectionView.sort).to.not.have.been.called;\n      });\n    });\n\n    describe('when sortWithCollection is true', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        // sortWithCollection is true by default\n        myCollectionView = new MyCollectionView({ collection });\n\n        myCollectionView.render();\n\n        this.sinon.spy(myCollectionView, 'sort');\n\n        myCollectionView.collection.sort();\n      });\n\n      it('should call the sort method', function() {\n        expect(myCollectionView.sort).to.have.been.calledOnce;\n      });\n    });\n\n    describe('when sort is triggered from the collection changing', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        // sortWithCollection is true by default\n        myCollectionView = new MyCollectionView({ collection });\n\n        myCollectionView.render();\n\n        this.sinon.spy(myCollectionView, 'sort');\n\n        myCollectionView.collection.add({ id: 5 });\n      });\n\n      it('should only sort once', function() {\n        expect(myCollectionView.sort).to.have.been.calledOnce;\n      });\n    });\n\n    describe('when the collection resets', function() {\n      let myCollectionView;\n      let renderChildrenStub;\n      let destroyChildrenStub;\n\n      beforeEach(function() {\n        renderChildrenStub = this.sinon.stub();\n        destroyChildrenStub = this.sinon.stub();\n\n        myCollectionView = new MyCollectionView({\n          collection: new Backbone.Collection([{ id: 1 }], { id: 2 })\n        });\n\n        myCollectionView.render();\n\n        this.sinon.spy(myCollectionView.children, '_init');\n\n        myCollectionView.on({\n          'render:children': renderChildrenStub,\n          'destroy:children': destroyChildrenStub\n        });\n\n        myCollectionView.collection.reset([{ id: 3 }]);\n      });\n\n      it('should destroy the children', function() {\n        expect(destroyChildrenStub).to.have.been.calledOnce;\n      });\n\n      it('should re init the children', function() {\n        expect(myCollectionView.children._init).to.have.been.calledOnce;\n      });\n\n      it('should only contain the new children', function() {\n        const myModel = myCollectionView.collection.get(3);\n        const childView = myCollectionView.children.findByModel(myModel);\n\n        expect(childView).to.not.be.undefined;\n        expect(myCollectionView.children).to.have.lengthOf(1);\n      });\n\n      it('should render the new children', function() {\n        expect(renderChildrenStub).to.have.been.calledOnce;\n      });\n    });\n  });\n\n  describe('when managing models in a collectionView.collection', function() {\n    let myCollectionView;\n    let collection;\n    let attachingModel;\n    let detachingModel;\n\n    beforeEach(function() {\n      collection = new Backbone.Collection([{ id: 1 }, { id: 2 }, { id: 3 }]);\n      attachingModel = new Backbone.Model({ id: 'attaching '});\n      detachingModel = collection.at(1);\n      myCollectionView = new MyCollectionView({ collection });\n    });\n\n    describe('when rendering a collectionView', function() {\n      it('should add each of the models as children', function() {\n        myCollectionView.render();\n        expect(myCollectionView.children.length).to.equal(collection.length);\n        myCollectionView.children.each((view, index) => {\n          expect(view.model).to.equal(collection.at(index));\n        });\n      });\n    });\n\n    describe('when a collection model changes before a render', function() {\n      it('should not trigger any events', function() {\n        const collectionViewEventStub = this.sinon.stub();\n        myCollectionView.on('all', collectionViewEventStub);\n        collection.add(attachingModel);\n        collection.remove(detachingModel);\n\n        expect(collectionViewEventStub).to.not.have.been.called;\n      });\n    });\n\n    describe('when a collection model changes after a render', function() {\n      let addChildStub;\n      let removeChildStub;\n      let renderChildrenStub;\n      let removingView;\n      let removingViewDestroyStub;\n\n      beforeEach(function() {\n        addChildStub = this.sinon.stub();\n        removeChildStub = this.sinon.stub();\n        renderChildrenStub = this.sinon.stub();\n        removingViewDestroyStub = this.sinon.stub();\n\n        myCollectionView.render();\n\n        myCollectionView.on({\n          'add:child': addChildStub,\n          'remove:child': removeChildStub,\n          'render:children': renderChildrenStub\n        });\n\n        this.sinon.spy(myCollectionView, 'detachHtml');\n\n        removingView = myCollectionView.children.findByModel(detachingModel);\n\n        removingView.on('destroy', removingViewDestroyStub);\n\n        collection.set([collection.at(0), collection.at(2), attachingModel]);\n      });\n\n      it('should remove a child before adding one', function() {\n        expect(addChildStub).to.be.calledOnce;\n        expect(removeChildStub).to.be.calledOnce;\n        expect(addChildStub).to.be.calledAfter(removeChildStub);\n      });\n\n      it('should render the children', function() {\n        expect(myCollectionView.children.length).to.equal(collection.length);\n        myCollectionView.children.each((view, index) => {\n          expect(view.model).to.equal(collection.at(index));\n        });\n      });\n\n      it('should detach the child', function() {\n        expect(myCollectionView.detachHtml).to.have.been.calledOnce.and.calledWith(removingView);\n      });\n\n      it('should destroy the child', function() {\n        expect(removingViewDestroyStub).to.have.been.calledOnce;\n      });\n    });\n  });\n\n  describe('when adding models only to the end of the collection', function() {\n    let myCollectionView;\n    let collection;\n\n    describe('when children are sorted', function() {\n      beforeEach(function() {\n        collection = new Backbone.Collection([{ id: 1 }, { id: 2 }, { id: 3 }]);\n\n        myCollectionView = new MyCollectionView({ collection });\n        myCollectionView.render();\n      });\n\n      it('should append all of the children', function() {\n        this.sinon.stub(myCollectionView, 'attachHtml');\n        collection.add([{ id: 4 }, { id: 5 }]);\n\n        const callArgs = myCollectionView.attachHtml.args[0];\n        const attachHtmlEls = callArgs[0];\n        expect($(attachHtmlEls).children()).to.have.lengthOf(5);\n      });\n\n      it('should append to the el', function() {\n        this.sinon.stub(myCollectionView, 'attachHtml');\n        collection.add([{ id: 4 }, { id: 5 }]);\n\n        const callArgs = myCollectionView.attachHtml.args[0];\n        const $el = callArgs[1];\n        expect($el).to.equal(myCollectionView.$el);\n      });\n\n      it('should still have all children attached', function() {\n        collection.add([{ id: 4 }, { id: 5 }]);\n\n        expect(myCollectionView.$el.children()).to.have.lengthOf(5);\n      });\n    });\n\n    describe('when children are not sorted', function() {\n      beforeEach(function() {\n        collection = new Backbone.Collection([{ id: 1 }, { id: 2 }, { id: 3 }]);\n\n        myCollectionView = new MyCollectionView({ collection, viewComparator: false });\n        myCollectionView.render();\n      });\n\n      it('should only append the added children', function() {\n        this.sinon.stub(myCollectionView, 'attachHtml');\n        collection.add([{ id: 4 }, { id: 5 }]);\n\n        const callArgs = myCollectionView.attachHtml.args[0];\n        const attachHtmlEls = callArgs[0];\n        expect($(attachHtmlEls).children()).to.have.lengthOf(2);\n      });\n\n      it('should still have all children attached', function() {\n        collection.add([{ id: 4 }, { id: 5 }]);\n\n        expect(myCollectionView.$el.children()).to.have.lengthOf(5);\n      });\n    });\n  });\n\n  describe('when only removing models from a collection', function() {\n    let myCollectionView;\n    let collection;\n\n    beforeEach(function() {\n      const emptyView = View.extend({ template: _.template('empty') });\n\n      collection = new Backbone.Collection([{ id: 1 }, { id: 2 }, { id: 3 }]);\n\n      myCollectionView = new MyCollectionView({ collection, emptyView });\n      myCollectionView.render();\n    });\n\n    it('should still have the originally added children in the el', function() {\n      collection.remove({ id: 1 });\n\n      expect(myCollectionView.$el.children()).to.have.lengthOf(2);\n    });\n  });\n\n  describe('when removing a model that does not match a children view model', function() {\n    let myCollectionView;\n    let collection;\n\n    beforeEach(function() {\n      collection = new Backbone.Collection([{ id: 1 }, { id: 2 }, { id: 3 }]);\n\n      const BuildCollectionView = MyCollectionView.extend({\n        buildChildView(child, ChildViewClass) {\n          return new ChildViewClass({ model: new Backbone.Model() });\n        }\n      });\n\n      myCollectionView = new BuildCollectionView({ collection });\n      myCollectionView.render();\n    });\n\n    it('should not throw an error', function() {\n      expect(collection.remove({ id: 1 })).to.not.throw;\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/collection-view/collection-view-empty.spec.js",
    "content": "// Anything related to emptyView\n\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport CollectionView from '../../../src/collection-view';\nimport View from '../../../src/view';\nimport Region from '../../../src/region';\nimport Events from '../../../src/mixins/events';\n\ndescribe('CollectionView -  Empty', function() {\n  let MyEmptyView;\n  let MyCollectionView;\n\n  beforeEach(function() {\n    const MyChildView = View.extend({\n      template: _.noop\n    });\n\n    MyEmptyView = View.extend({\n      template: _.template('Empty')\n    });\n\n    MyCollectionView = CollectionView.extend({\n      childView: MyChildView,\n      emptyView: MyEmptyView\n    });\n  });\n\n  describe('when instantiating a CollectionView', function() {\n    let myCollectionView;\n\n    beforeEach(function() {\n      this.sinon.spy(MyCollectionView.prototype, 'getEmptyRegion');\n      myCollectionView = new MyCollectionView();\n    });\n\n    it('should be replaceElement: false', function() {\n      Region.prototype.replaceElement = true;\n      expect(myCollectionView.getEmptyRegion().replaceElement).to.be.false;\n      Region.prototype.replaceElement = false;\n    });\n\n    it('should instantiate the emptyRegion', function() {\n      expect(myCollectionView.getEmptyRegion).to.have.been.calledOnce;\n    });\n\n    describe('when destroying the collectionView', function() {\n      it('should destroy the region', function() {\n        const emptyRegion = myCollectionView.getEmptyRegion();\n        myCollectionView.destroy();\n        expect(emptyRegion.isDestroyed()).to.be.true;\n      });\n    });\n  });\n\n  describe('when rendering an empty collectionview during instantiation', function() {\n    it('should show the view in the emptyRegion', function() {\n      const collection = new Backbone.Collection();\n\n      const MyInitCollectionView = MyCollectionView.extend({\n        initialize() {\n          this.render();\n        }\n      });\n\n      const myCollectionView = new MyInitCollectionView({ collection });\n\n      expect(myCollectionView.getEmptyRegion().hasView()).to.be.true;\n    });\n  });\n\n  describe('when an emptyView is rendered', function() {\n    let emptyViewRenderStub;\n    let myCollectionView;\n\n    beforeEach(function() {\n      const collection = new Backbone.Collection();\n\n      emptyViewRenderStub = this.sinon.stub();\n\n      myCollectionView = new MyCollectionView({\n        collection,\n        childViewEvents: {\n          'render': emptyViewRenderStub\n        }\n      });\n\n      myCollectionView.render();\n    });\n\n    it('should trigger child events on the collectionView', function() {\n      expect(emptyViewRenderStub).to.have.been.calledOnce;\n    });\n\n    describe('when the collection is no longer empty', function() {\n      it('should empty the emptyRegion', function() {\n        const emptyRegionEmptyStub = this.sinon.stub();\n        myCollectionView.getEmptyRegion().on('empty', emptyRegionEmptyStub);\n        myCollectionView.collection.add({ id: 1 });\n        expect(emptyRegionEmptyStub).to.have.been.calledOnce;\n      });\n    });\n  });\n\n  describe('when rendering in a template', function() {\n    it('should show the emptyView inside the childViewContainer', function() {\n      const TemplatedCollectionView = MyCollectionView.extend({\n        childViewContainer: '#region',\n        template: _.template('<div id=\"region\"></div>')\n      });\n\n      const cv = new TemplatedCollectionView({\n        collection: new Backbone.Collection()\n      });\n\n      cv.render();\n\n      expect(cv.$('#region')).to.contain.$text('Empty');\n    });\n  });\n\n  describe('#getEmptyRegion', function() {\n    let collection;\n    let myCollectionView;\n\n    beforeEach(function() {\n      collection = new Backbone.Collection();\n      myCollectionView = new MyCollectionView({ collection });\n    });\n\n    it('should return the empty region for the collectionView el', function() {\n      expect(myCollectionView.getEmptyRegion().el).to.equal(myCollectionView.el);\n    });\n\n    it('should return the same region on subsequent calls', function() {\n      const emptyRegion = myCollectionView.getEmptyRegion();\n\n      expect(myCollectionView.getEmptyRegion()).to.equal(emptyRegion);\n    });\n\n    // Internal implementation detail, but needs to be tested\n    it('should set the parentView', function() {\n      expect(myCollectionView.getEmptyRegion()._parentView).to.equal(myCollectionView);\n    });\n\n    it('should return a new emptyRegion instance if the current is destroyed', function() {\n      const emptyRegion = myCollectionView.getEmptyRegion();\n      emptyRegion.destroy();\n\n      expect(myCollectionView.getEmptyRegion()).to.not.equal(emptyRegion);\n      expect(myCollectionView.getEmptyRegion().el).to.equal(myCollectionView.el);\n    });\n  });\n\n  describe('#emptyView', function() {\n    const collection = new Backbone.Collection();\n    const BBView = Backbone.View.extend();\n    _.extend(BBView.prototype, Events);\n\n    describe('when emptyView is falsey', function() {\n      it('should not show an emptyView', function() {\n        const myCollectionView = new CollectionView({\n          collection,\n          emptyView: false\n        });\n\n        this.sinon.spy(myCollectionView.getEmptyRegion(), 'show');\n        myCollectionView.render();\n\n        expect(myCollectionView.getEmptyRegion().show).to.not.have.been.called;\n      });\n    });\n\n    describe('when emptyView is a type of Backbone.View', function() {\n      it('should show an emptyView from the defined view', function() {\n        const MyView = View.extend({ template: _.noop });\n        const myCollectionView = new CollectionView({\n          collection,\n          emptyView: MyView\n        });\n\n        this.sinon.spy(myCollectionView.getEmptyRegion(), 'show');\n        myCollectionView.render();\n\n        expect(myCollectionView.getEmptyRegion().show)\n          .to.be.calledOnce\n          .and.calledWith(sinon.match.instanceOf(MyView));\n      });\n    });\n\n    describe('when emptyView is a Backbone.View', function() {\n      it('should show an emptyView from the defined view', function() {\n        const myCollectionView = new CollectionView({\n          collection,\n          emptyView: BBView\n        });\n\n        this.sinon.spy(myCollectionView.getEmptyRegion(), 'show');\n        myCollectionView.render();\n\n        expect(myCollectionView.getEmptyRegion().show)\n          .to.be.calledOnce\n          .and.calledWith(sinon.match.instanceOf(BBView));\n      });\n    });\n\n    describe('when emptyView is a function returning a view', function() {\n      it('should show an emptyView from the returned view', function() {\n        const emptyViewStub = this.sinon.stub();\n        emptyViewStub.returns(BBView);\n\n        const myCollectionView = new CollectionView({\n          collection,\n          emptyView: emptyViewStub\n        });\n\n        this.sinon.spy(myCollectionView.getEmptyRegion(), 'show');\n        myCollectionView.render();\n\n        expect(myCollectionView.getEmptyRegion().show)\n          .to.be.calledOnce\n          .and.calledWith(sinon.match.instanceOf(BBView));\n      });\n    });\n\n    describe('when emptyView is not a valid view', function() {\n      it('should not show an emptyView', function() {\n        const myCollectionView = new CollectionView({\n          collection,\n          emptyView: 'foo'\n        });\n\n        this.sinon.spy(myCollectionView.getEmptyRegion(), 'show');\n        myCollectionView.render();\n\n        expect(myCollectionView.getEmptyRegion().show).to.not.have.been.called;\n      });\n    });\n  });\n\n  describe('#emptyViewOptions', function() {\n    describe('when emptyViewOptions is a function', function() {\n      const collection = new Backbone.Collection();\n      const MyView = View.extend({ template: _.noop });\n      const emptyViewOptions = { foo: 'bar' };\n\n      let myCollectionView;\n      let emptyViewOptionsStub;\n\n      beforeEach(function() {\n        emptyViewOptionsStub = this.sinon.stub();\n        emptyViewOptionsStub.returns(emptyViewOptions);\n\n        myCollectionView = new CollectionView({\n          collection,\n          emptyView: MyView,\n          emptyViewOptions: emptyViewOptionsStub\n        });\n\n        myCollectionView.render();\n      });\n\n      it('should show an emptyView with the emptyViewOptions', function() {\n        const emptyView = myCollectionView.getEmptyRegion().currentView;\n        expect(emptyView.options).to.deep.equal(emptyViewOptions);\n      });\n\n      it('should call childViewOptions', function() {\n        expect(emptyViewOptionsStub).to.have.been.calledOnce;\n      });\n    });\n\n    describe('when emptyViewOptions is undefined', function() {\n      const collection = new Backbone.Collection();\n      const MyView = View.extend({ template: _.noop });\n      const childViewOptions = { foo: 'bar' };\n\n      let myCollectionView;\n      let childViewOptionsStub;\n\n      beforeEach(function() {\n        childViewOptionsStub = this.sinon.stub();\n        childViewOptionsStub.returns(childViewOptions);\n\n        myCollectionView = new CollectionView({\n          collection,\n          emptyView: MyView,\n          childViewOptions: childViewOptionsStub\n        });\n\n        myCollectionView.render();\n      });\n\n      it('should show an emptyView with the emptyViewOptions', function() {\n        const emptyView = myCollectionView.getEmptyRegion().currentView;\n        expect(emptyView.options).to.deep.equal(childViewOptions);\n      });\n\n      it('should call childViewOptions', function() {\n        expect(childViewOptionsStub).to.have.been.calledOnce;\n      });\n    });\n  });\n\n  describe('#isEmpty', function() {\n    describe('when rendering a collectionView', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        const collection = new Backbone.Collection([{ id: 1 }, { id: 2 }]);\n        myCollectionView = new MyCollectionView({ collection });\n        this.sinon.spy(myCollectionView, 'isEmpty');\n        myCollectionView.render();\n      });\n\n      it('should call isEmpty', function() {\n        expect(myCollectionView.isEmpty).to.be.calledOnce;\n      });\n\n      it('should not show the emptyView', function() {\n        expect(myCollectionView.getEmptyRegion().hasView()).to.be.false;\n      });\n\n      describe('when removing one child', function() {\n        beforeEach(function() {\n          myCollectionView.isEmpty.resetHistory();\n          myCollectionView.removeChildView(myCollectionView.children.first());\n        });\n\n        it('should call isEmpty', function() {\n          expect(myCollectionView.isEmpty).to.be.calledOnce;\n        });\n\n        it('should not show the emptyView', function() {\n          expect(myCollectionView.getEmptyRegion().hasView()).to.be.false;\n        });\n      });\n\n      describe('when removing the only child', function() {\n        beforeEach(function() {\n          myCollectionView.removeChildView(myCollectionView.children.first());\n          myCollectionView.isEmpty.resetHistory();\n          myCollectionView.removeChildView(myCollectionView.children.first());\n        });\n\n        it('should call isEmpty', function() {\n          expect(myCollectionView.isEmpty).to.be.calledOnce;\n        });\n\n        it('should show the emptyView', function() {\n          expect(myCollectionView.getEmptyRegion().hasView()).to.be.true;\n        });\n      });\n    });\n\n    describe('when rendering an empty collectionView', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        const collection = new Backbone.Collection();\n        myCollectionView = new MyCollectionView({ collection });\n        this.sinon.spy(myCollectionView, 'isEmpty');\n        myCollectionView.render();\n      });\n\n      it('should call isEmpty', function() {\n        expect(myCollectionView.isEmpty).to.be.calledOnce;\n      });\n\n      it('should show the emptyView', function() {\n        expect(myCollectionView.getEmptyRegion().hasView()).to.be.true;\n      });\n    });\n\n    describe('when filtering some views from a collectionView', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        const collection = new Backbone.Collection([{ id: 1 }, { id: 2 }]);\n        myCollectionView = new MyCollectionView({ collection });\n        myCollectionView.render();\n        this.sinon.spy(myCollectionView, 'isEmpty');\n        myCollectionView.setFilter(view => {\n          return view.model.id === 1;\n        });\n      });\n\n      it('should call isEmpty', function() {\n        expect(myCollectionView.isEmpty).to.be.calledOnce;\n      });\n\n      it('should not show the emptyView', function() {\n        expect(myCollectionView.getEmptyRegion().hasView()).to.be.false;\n      });\n    });\n\n    describe('when filtering all views from a collectionView', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        const collection = new Backbone.Collection([{ id: 1 }]);\n        myCollectionView = new MyCollectionView({ collection });\n        myCollectionView.render();\n        this.sinon.spy(myCollectionView, 'isEmpty');\n        myCollectionView.setFilter(_.constant(false));\n      });\n\n      it('should call isEmpty', function() {\n        expect(myCollectionView.isEmpty).to.be.calledOnce;\n      });\n\n      it('should show the emptyView', function() {\n        expect(myCollectionView.getEmptyRegion().hasView()).to.be.true;\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/collection-view/collection-view-filtering.spec.js",
    "content": "// Anything viewFilter related\n\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport CollectionView from '../../../src/collection-view';\nimport Region from '../../../src/region';\nimport View from '../../../src/view';\n\nfunction renderModels(models) {\n  return _.map(models, model => `<li>${ model.get('num') }</li>`);\n}\n\nfunction isOdd(num) {\n  return !!(num % 2);\n}\n\ndescribe('CollectionView - Filtering', function() {\n  let collection;\n  let collectionOddModels;\n  let collectionEvenModels;\n\n  before(function() {\n    collection = new Backbone.Collection();\n\n    _.times(50, (n) => { collection.add({ num: n, isOdd: isOdd(n) }); });\n\n    const partition = collection.partition(model => { return isOdd(model.get('num')); });\n\n    collectionOddModels = partition[0];\n    collectionEvenModels = partition[1];\n  });\n\n  let MyChildView;\n  let MyEmptyView;\n  let MyCollectionView;\n\n  beforeEach(function() {\n    MyEmptyView = View.extend({\n      tagName: 'li',\n      template: _.template('Empty')\n    });\n\n    MyChildView = View.extend({\n      tagName: 'li',\n      template: _.template('<%- num %>')\n    });\n\n    MyCollectionView = CollectionView.extend({\n      tagName: 'ul',\n      childView: MyChildView,\n      emptyView: MyEmptyView,\n      onBeforeFilter: this.sinon.stub(),\n      onFilter: this.sinon.stub(),\n      onRenderChildren: this.sinon.stub()\n    });\n  });\n\n  describe('#viewFilter', function() {\n    describe('when viewFilter is falsy', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView({ collection });\n\n        myCollectionView.render();\n      });\n\n      it('should render the entire collection', function() {\n        const nums = renderModels(collection.models);\n        expect(myCollectionView.$el.html()).to.equal(nums.join(''));\n      });\n\n      it('should not call \"before:filter\" event', function() {\n        expect(myCollectionView.onBeforeFilter).to.not.have.been.called;\n      });\n\n      it('should not call \"filter\" event', function() {\n        expect(myCollectionView.onFilter).to.not.have.been.called;\n      });\n    });\n\n    describe('when viewFilter is invalid', function() {\n      let myCollectionView;\n\n      const viewFilter = 47;\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView({ collection, viewFilter });\n      });\n\n      it('should throw InvalidViewFilterError', function() {\n        expect(myCollectionView.render.bind(myCollectionView)).to.throw('\"viewFilter\" must be a function, predicate object literal, a string indicating a model attribute, or falsy');\n      });\n    });\n\n    describe('when viewFilter is a function', function() {\n      let myCollectionView;\n\n      const viewFilter = function(view) { return isOdd(view.model.get('num')); };\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView({ collection, viewFilter });\n\n        myCollectionView.render();\n      });\n\n      it('should render only the filtered collection', function() {\n        const nums = renderModels(collectionOddModels);\n        expect(myCollectionView.$el.html()).to.equal(nums.join(''));\n      });\n\n      it('should call \"before:filter\" event', function() {\n        expect(myCollectionView.onBeforeFilter)\n          .to.have.been.calledOnce\n          .and.calledWith(myCollectionView);\n      });\n\n      it('should call \"filter\" event', function() {\n        const calledWith = myCollectionView.onFilter.firstCall.args;\n        expect(myCollectionView.onFilter).to.have.been.calledOnce;\n        expect(calledWith[0]).to.equal(myCollectionView);\n        expect(_.map(calledWith[1], 'model')).to.have.same.members(collectionOddModels);\n        expect(_.map(calledWith[2], 'model')).to.have.same.members(collectionEvenModels);\n      });\n    });\n\n    describe('when viewFilter is an object', function() {\n      let myCollectionView;\n\n      const viewFilter = { isOdd: false };\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView({ collection, viewFilter });\n\n        myCollectionView.render();\n      });\n\n      it('should render only the filtered collection', function() {\n        const nums = renderModels(collectionEvenModels);\n        expect(myCollectionView.$el.html()).to.equal(nums.join(''));\n      });\n\n      describe('when children has a view without a model', function() {\n        beforeEach(function() {\n          myCollectionView.addChildView(new View({ template: _.noop }));\n        });\n\n        it('should filter without error', function() {\n          expect(myCollectionView.filter.bind(myCollectionView)).to.not.throw();\n        });\n      });\n    });\n\n    describe('when viewFilter is a string', function() {\n      let myCollectionView;\n\n      const viewFilter = 'isOdd';\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView({ collection, viewFilter });\n\n        myCollectionView.render();\n      });\n\n      it('should render only the filtered collection', function() {\n        const nums = renderModels(collectionOddModels);\n        expect(myCollectionView.$el.html()).to.equal(nums.join(''));\n      });\n\n      describe('when children has a view without a model', function() {\n        beforeEach(function() {\n          myCollectionView.addChildView(new View({ template: _.noop }));\n        });\n\n        it('should filter without error', function() {\n          expect(myCollectionView.filter.bind(myCollectionView)).to.not.throw();\n        });\n      });\n    });\n  });\n\n  describe('#getFilter', function() {\n    let myCollectionView;\n\n    beforeEach(function() {\n      MyCollectionView = MyCollectionView.extend({\n        getFilter() {\n          return { isOdd: false }\n        }\n      });\n\n      myCollectionView = new MyCollectionView({\n        collection,\n        viewFilter: 'isOdd'\n      });\n\n      myCollectionView.render();\n    });\n\n    it('should render only the filtered collection', function() {\n      const nums = renderModels(collectionEvenModels);\n      expect(myCollectionView.$el.html()).to.equal(nums.join(''));\n    });\n  });\n\n  describe('#filter', function() {\n    describe('when the view is destroyed', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView({\n          collection\n        });\n\n        this.sinon.spy(myCollectionView, 'filter');\n\n        myCollectionView.destroy();\n\n        myCollectionView.filter();\n      });\n\n      it('should not filter the children', function() {\n        expect(myCollectionView.onBeforeFilter).to.not.have.been.called;\n      });\n\n      it('should not render the children', function() {\n        expect(myCollectionView.onRenderChildren).to.not.have.been.called;\n      });\n\n      it('should return the collectionView', function() {\n        expect(myCollectionView.filter).to.have.returned(myCollectionView);\n      });\n    });\n\n    describe('when the view collection is empty', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView();\n\n        this.sinon.spy(myCollectionView, 'filter');\n\n        myCollectionView.filter();\n      });\n\n      it('should not filter the children', function() {\n        expect(myCollectionView.onBeforeFilter).to.not.have.been.called;\n      });\n\n      it('should render no children', function() {\n        expect(myCollectionView.onRenderChildren)\n          .to.have.been.calledOnce\n          .and.calledWith(myCollectionView, []);\n      });\n\n      it('should return the collectionView', function() {\n        expect(myCollectionView.filter).to.have.returned(myCollectionView);\n      });\n    });\n\n    describe('when filtering with an existing viewFilter', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView({\n          collection,\n          viewFilter: 'isOdd'\n        });\n\n        this.sinon.spy(myCollectionView, 'filter');\n      });\n\n      describe('when the collectionView has not been rendered', function() {\n        beforeEach(function() {\n          myCollectionView.filter();\n        });\n\n        it('should not filter the children', function() {\n          expect(myCollectionView.onBeforeFilter).to.not.have.been.called;\n        });\n\n        it('should render no children', function() {\n          expect(myCollectionView.onRenderChildren)\n            .to.have.been.calledOnce\n            .and.calledWith(myCollectionView, []);\n        });\n\n        it('should return the collectionView', function() {\n          expect(myCollectionView.filter).to.have.returned(myCollectionView);\n        });\n      });\n\n      describe('when the collectionView has been rendered', function() {\n        let filteredViews;\n\n        beforeEach(function() {\n          myCollectionView.render();\n\n          myCollectionView.onRenderChildren.reset();\n          myCollectionView.onBeforeFilter.reset();\n\n          filteredViews = myCollectionView.children.filter(view => {\n            return isOdd(view.model.get('num'));\n          });\n\n          this.sinon.spy(myCollectionView.children, '_set');\n\n          myCollectionView.filter();\n        });\n\n        it('should filter the children', function() {\n          expect(myCollectionView.onBeforeFilter).to.have.been.calledOnce;\n        });\n\n        it('should set the children', function() {\n          expect(myCollectionView.children._set)\n            .to.have.been.calledOnce.and.calledWith(filteredViews);\n        });\n\n        it('should render the children', function() {\n          expect(myCollectionView.onRenderChildren)\n            .to.have.been.calledOnce.and.calledWith(myCollectionView, filteredViews);\n        });\n\n        it('should return the collectionView', function() {\n          expect(myCollectionView.filter).to.have.returned(myCollectionView);\n        });\n      });\n    });\n  });\n\n  describe('#setFilter', function() {\n    let myCollectionView;\n\n    beforeEach(function() {\n      myCollectionView = new MyCollectionView({\n        collection,\n        viewFilter: 'isOdd'\n      });\n\n      this.sinon.spy(myCollectionView, 'filter');\n    });\n\n    it('should return the collectionView instance', function() {\n      this.sinon.spy(myCollectionView, 'setFilter');\n\n      myCollectionView.setFilter();\n\n      expect(myCollectionView.setFilter).to.have.returned(myCollectionView);\n    });\n\n    describe('when setting with a new viewFilter', function() {\n\n      const newViewFilter = { isOdd: false };\n\n      beforeEach(function() {\n        myCollectionView.setFilter(newViewFilter);\n      });\n\n      it('should set the viewFilter', function() {\n        expect(myCollectionView.viewFilter).to.equal(newViewFilter);\n      });\n\n      it('should re-filter the view', function() {\n        expect(myCollectionView.filter).to.have.been.calledOnce;\n      });\n\n      describe('when setting with the current viewFilter', function() {\n        beforeEach(function() {\n          myCollectionView.setFilter(newViewFilter);\n        });\n\n        // Note: This is nested inside the first setFilter\n        it('should not re-filter the view', function() {\n          expect(myCollectionView.filter).to.have.been.calledOnce;\n        });\n      });\n    });\n\n    describe('when setting with preventRender option', function() {\n      const newViewFilter = { isOdd: false };\n\n      beforeEach(function() {\n        myCollectionView.setFilter(newViewFilter, { preventRender: true });\n      });\n\n      it('should set the viewFilter', function() {\n        expect(myCollectionView.viewFilter).to.equal(newViewFilter);\n      });\n\n      it('should not re-filter the view', function() {\n        expect(myCollectionView.filter).to.not.have.been.called;\n      });\n    });\n  });\n\n  describe('#removeFilter', function() {\n    let myCollectionView;\n\n    beforeEach(function() {\n      myCollectionView = new CollectionView();\n      this.sinon.spy(myCollectionView, 'setFilter');\n      this.sinon.spy(myCollectionView, 'removeFilter');\n\n      myCollectionView.removeFilter('foo');\n    });\n\n    it('should call setFilter', function() {\n      expect(myCollectionView.setFilter)\n        .to.be.calledOnce\n        .and.to.be.calledWith(null, 'foo');\n    });\n\n    it('should return the collectionView instance', function() {\n      expect(myCollectionView.removeFilter).to.have.returned(myCollectionView);\n    });\n  });\n\n  describe('#isEmpty', function() {\n    let myCollectionView;\n\n    beforeEach(function() {\n      myCollectionView = new MyCollectionView({\n        collection\n      });\n\n      myCollectionView.render();\n\n      this.sinon.spy(myCollectionView, 'isEmpty');\n    });\n\n    describe('when all children are filtered', function() {\n      beforeEach(function() {\n        myCollectionView.setFilter(view => { return false; });\n      });\n\n      it('should call isEmpty', function() {\n        expect(myCollectionView.isEmpty).to.have.been.calledOnce;\n      });\n\n      it('should show the empty view', function() {\n        expect(myCollectionView.$el.text()).to.equal('Empty');\n      });\n    });\n\n    describe('when all children are not filtered', function() {\n      beforeEach(function() {\n        myCollectionView.setFilter(view => { return true; });\n      });\n\n      it('should pass isEmpty false in the 1st argument', function() {\n        expect(myCollectionView.isEmpty).to.have.been.calledOnce;\n      });\n\n      it('should not show the empty view', function() {\n        expect(myCollectionView.$el.text()).to.not.equal('Empty');\n      });\n    });\n  });\n\n  describe('when attaching a collectionview with filtered children', function() {\n    let myCollectionView;\n    let myRegion;\n\n    beforeEach(function() {\n      const viewFilter = 'isOdd';\n      myRegion = new Region({ el: '#fixtures' });\n\n      myCollectionView = new MyCollectionView({ collection, viewFilter });\n\n      myCollectionView.render();\n    });\n\n    it('should trigger attach on attached children', function() {\n      const attachedChild = myCollectionView._children.findByIndex(1);\n\n      attachedChild.onAttach = this.sinon.stub();\n\n      myRegion.show(myCollectionView);\n\n      expect(attachedChild.onAttach).to.have.been.calledOnce;\n    });\n\n    it('should not trigger attach on children filtered out', function() {\n      const detachedChild = myCollectionView._children.findByIndex(2);\n\n      detachedChild.onAttach = this.sinon.stub();\n\n      myRegion.show(myCollectionView);\n\n      expect(detachedChild.onAttach).to.not.have.been.called;\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/collection-view/collection-view-sorting.spec.js",
    "content": "// Anything viewComparator related\n\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport CollectionView from '../../../src/collection-view';\nimport View from '../../../src/view';\n\ndescribe('CollectionView - Sorting', function() {\n  let collection;\n  let MyChildView;\n  let MyCollectionView;\n\n  const noSortText = '0,5,2,1,1,4,2,3,5,3,2,1,4,4,3,';\n  const sortText = '1,1,4,3,2,1,2,3,5,4,4,3,0,5,2,';\n  const altSortText = '3,2,1,0,5,2,4,4,3,1,1,4,2,3,5,';\n\n  beforeEach(function() {\n    collection = new Backbone.Collection([\n      { index: 0, sort: 5, altSort: 2 },\n      { index: 1, sort: 1, altSort: 4 },\n      { index: 2, sort: 3, altSort: 5 },\n      { index: 3, sort: 2, altSort: 1 },\n      { index: 4, sort: 4, altSort: 3 }\n    ]);\n\n    MyChildView = View.extend({\n      tagName: 'li',\n      template: _.template('<%- index %>,<%- sort %>,<%- altSort %>,')\n    });\n\n    MyCollectionView = CollectionView.extend({\n      tagName: 'ul',\n      childView: MyChildView,\n      onBeforeSort: this.sinon.stub(),\n      onSort: this.sinon.stub(),\n      onRenderChildren: this.sinon.stub()\n    });\n  });\n\n  describe('#viewComparator', function() {\n    describe('when the collection is undefined', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView();\n\n        myCollectionView.addChildView(new View({template: _.noop}));\n      });\n\n      // The default viewComparator sorts by the view.model's index in the collection\n      it('should not throw an error', function() {\n        expect(myCollectionView.render.bind(myCollectionView)).to.not.throw();\n      });\n    });\n\n    describe('when viewComparator is false', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView({\n          viewComparator: false,\n          collection\n        });\n\n        myCollectionView.render();\n      });\n\n\n      it('should not sort the collection', function() {\n        expect(myCollectionView.$el.text()).to.equal(noSortText);\n      });\n\n      it('should not call \"before:sort\" event', function() {\n        expect(myCollectionView.onBeforeSort).to.not.be.called;\n      });\n\n      it('should not call \"sort\" event', function() {\n        expect(myCollectionView.onSort).to.not.be.called;\n      });\n\n      describe('when resorting the collection', function() {\n        beforeEach(function() {\n          this.sinon.spy(myCollectionView, 'sort');\n          collection.comparator = 'sort';\n          collection.sort();\n        });\n\n        it('should not call sort', function() {\n          expect(myCollectionView.sort).to.not.be.called;\n        });\n\n        it('should not resort the children on sort', function() {\n          myCollectionView.sort();\n\n          expect(myCollectionView.$el.text()).to.equal(noSortText);\n        });\n      });\n    });\n\n    describe('when viewComparator is falsy but not false', function() {\n      let myCollectionView;\n\n      describe('when sortWithCollection is true', function() {\n        beforeEach(function() {\n          myCollectionView = new MyCollectionView({ collection });\n\n          myCollectionView.render();\n        });\n\n\n        it('should sort the collection by the collection index', function() {\n          expect(myCollectionView.$el.text()).to.equal(noSortText);\n        });\n\n        it('should call \"before:sort\" event', function() {\n          expect(myCollectionView.onBeforeSort)\n            .to.have.been.calledOnce\n            .and.calledWith(myCollectionView);\n        });\n\n        it('should call \"sort\" event', function() {\n          expect(myCollectionView.onSort)\n            .to.have.been.calledOnce\n            .and.calledWith(myCollectionView);\n        });\n\n        describe('when resorting the collection', function() {\n          it('should sort the collectionView by the collection index', function() {\n            collection.comparator = 'sort';\n            collection.sort();\n\n            myCollectionView.render();\n\n            expect(myCollectionView.$el.text()).to.equal(sortText);\n          });\n        });\n      });\n\n      describe('when sortWithCollection is false', function() {\n        beforeEach(function() {\n          myCollectionView = new MyCollectionView({\n            sortWithCollection: false,\n            collection\n          });\n\n          myCollectionView.render();\n        });\n\n        it('should not call \"before:sort\" event', function() {\n          expect(myCollectionView.onBeforeSort).to.not.be.called;\n        });\n\n        it('should not call \"sort\" event', function() {\n          expect(myCollectionView.onSort).to.not.be.called;\n        });\n      });\n    });\n\n    describe('when viewComparator is defined', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView({\n          viewComparator: 'altSort',\n          collection\n        });\n\n        myCollectionView.render();\n      });\n\n      it('should sort the collectionView by the viewComparator', function() {\n        expect(myCollectionView.$el.text()).to.equal(altSortText);\n      });\n\n      it('should call \"before:sort\" event', function() {\n        expect(myCollectionView.onBeforeSort)\n          .to.have.been.calledOnce\n          .and.calledWith(myCollectionView);\n      });\n\n      it('should call \"sort\" event', function() {\n        expect(myCollectionView.onSort)\n          .to.have.been.calledOnce\n          .and.calledWith(myCollectionView);\n      });\n    });\n\n    describe('when viewComparator is a function', function() {\n      let myCollectionView;\n      let viewComparator;\n\n      beforeEach(function() {\n        viewComparator = this.sinon.stub();\n\n        viewComparator.returns('sort');\n\n        myCollectionView = new MyCollectionView({\n          viewComparator: function(val) {\n            return viewComparator.call(this, val);\n          },\n          collection\n        });\n\n        myCollectionView.render();\n      });\n\n      it('should call it with the context of the collectionView', function() {\n        expect(viewComparator).to.be.calledOn(myCollectionView);\n      });\n    });\n  });\n\n  describe('#getComparator', function() {\n    let myCollectionView;\n\n    beforeEach(function() {\n      MyCollectionView = MyCollectionView.extend({\n        getComparator() {\n          return 'altSort';\n        }\n      });\n\n      myCollectionView = new MyCollectionView({\n        collection,\n        viewComparator: 'sort'\n      });\n\n      myCollectionView.render();\n    });\n\n    it('should sort by the return of getComparator', function() {\n\n      expect(myCollectionView.$el.text()).to.equal(altSortText);\n    });\n  });\n\n  describe('#sort', function() {\n    it('should sort the collectionView', function() {\n      const myCollectionView = new MyCollectionView({\n        collection\n      });\n      myCollectionView.render();\n      myCollectionView.onSort.reset();\n      myCollectionView.sort();\n\n      expect(myCollectionView.onSort).to.have.been.calledOnce;\n    });\n\n    it('should return the collectionView instance', function() {\n      const myCollectionView = new CollectionView();\n      this.sinon.spy(myCollectionView, 'sort');\n\n      myCollectionView.sort();\n\n      expect(myCollectionView.sort).to.have.returned(myCollectionView);\n    });\n\n    describe('when the view is destroyed', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView({\n          collection\n        });\n\n        this.sinon.spy(myCollectionView, 'sort');\n\n        myCollectionView.destroy();\n\n        myCollectionView.sort();\n      });\n\n      it('should not sort the children', function() {\n        expect(myCollectionView.onBeforeSort).to.not.have.been.called;\n      });\n\n      it('should not render the children', function() {\n        expect(myCollectionView.onRenderChildren).to.not.have.been.called;\n      });\n\n      it('should return the collectionView', function() {\n        expect(myCollectionView.sort).to.have.returned(myCollectionView);\n      });\n    });\n\n    describe('when the view collection is empty', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView();\n\n        this.sinon.spy(myCollectionView, 'sort');\n\n        myCollectionView.sort();\n      });\n\n      it('should not sort the children', function() {\n        expect(myCollectionView.onBeforeSort).to.not.have.been.called;\n      });\n\n      it('should render no children', function() {\n        expect(myCollectionView.onRenderChildren)\n          .to.have.been.calledOnce\n          .and.calledWith(myCollectionView, []);\n      });\n\n      it('should return the collectionView', function() {\n        expect(myCollectionView.sort).to.have.returned(myCollectionView);\n      });\n    });\n  });\n\n  describe('#setComparator', function() {\n    it('should return the collectionView instance', function() {\n      const myCollectionView = new CollectionView();\n      this.sinon.spy(myCollectionView, 'setComparator');\n\n      myCollectionView.setComparator();\n\n      expect(myCollectionView.setComparator).to.have.returned(myCollectionView);\n    });\n\n    describe('when setting with a new viewComparator', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView({\n          viewComparator: 'sort'\n        });\n\n        this.sinon.spy(myCollectionView, 'sort');\n        myCollectionView.setComparator('altSort');\n      });\n\n      it('should set the viewComparator', function() {\n        expect(myCollectionView.viewComparator).to.equal('altSort');\n      });\n\n      it('should sort the collectionView', function() {\n        expect(myCollectionView.sort).to.be.calledOnce;\n      });\n\n      describe('when setting with the same viewComparator', function() {\n        it('should not sort the collectionView', function() {\n          myCollectionView.sort.resetHistory();\n          myCollectionView.setComparator('altSort');\n          expect(myCollectionView.sort).to.not.be.called;\n        });\n      });\n    });\n\n    describe('when setting with preventRender option', function() {\n      let myCollectionView;\n\n      beforeEach(function() {\n        myCollectionView = new MyCollectionView({\n          viewComparator: 'sort'\n        });\n\n        this.sinon.spy(myCollectionView, 'sort');\n        myCollectionView.setComparator('altSort', { preventRender: true });\n      });\n\n      it('should set the viewComparator', function() {\n        expect(myCollectionView.viewComparator).to.equal('altSort');\n      });\n\n      it('should not sort the collectionView', function() {\n\n        expect(myCollectionView.sort).to.not.be.called;\n      });\n    });\n  });\n\n  describe('#removeComparator', function() {\n    let myCollectionView;\n\n    beforeEach(function() {\n      myCollectionView = new CollectionView();\n      this.sinon.spy(myCollectionView, 'setComparator');\n      this.sinon.spy(myCollectionView, 'removeComparator');\n\n      myCollectionView.removeComparator('foo');\n    });\n\n    it('should call setComparator', function() {\n      expect(myCollectionView.setComparator)\n        .to.be.calledOnce\n        .and.to.be.calledWith(null, 'foo');\n    });\n\n    it('should return the collectionView instance', function() {\n      expect(myCollectionView.removeComparator).to.have.returned(myCollectionView);\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/collection-view/collection-view-viewmixin.spec.js",
    "content": "// Anything testing the integration of the ViewMixin, but not the ViewMixin itself.\n\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport CollectionView from '../../../src/collection-view';\nimport View from '../../../src/view';\n\ndescribe('CollectionView - ViewMixin', function() {\n\n  describe('when initializing a CollectionView', function() {\n    let collectionView;\n    let initBehaviorsSpy;\n    let initializeSpy;\n    let delegateEntityEventsSpy;\n\n    const mergeOptions = {\n      behaviors: {},\n      childViewEventPrefix: 'child',\n      childViewEvents: {},\n      childViewTriggers: {},\n      collectionEvents: {},\n      modelEvents: {},\n      triggers: {},\n      ui: {}\n    };\n\n    beforeEach(function() {\n      const MyCollectionView = CollectionView.extend();\n\n      initBehaviorsSpy = this.sinon.spy(MyCollectionView.prototype, '_initBehaviors');\n      initializeSpy = this.sinon.spy(MyCollectionView.prototype, 'initialize');\n      delegateEntityEventsSpy = this.sinon.spy(MyCollectionView.prototype, 'delegateEntityEvents');\n\n      collectionView = new MyCollectionView(mergeOptions);\n    });\n\n    _.each(mergeOptions, function(value, key) {\n      it(`should merge ViewMixin option ${ key }`, function() {\n        expect(collectionView[key]).to.equal(value);\n      });\n    });\n\n    it('should call _initBehaviors', function() {\n      expect(initBehaviorsSpy)\n        .to.have.been.calledOnce\n        .and.calledBefore(initializeSpy);\n    });\n\n    it('should call delegateEntityEvents', function() {\n      expect(delegateEntityEventsSpy)\n        .to.have.been.calledOnce\n        .and.calledAfter(initializeSpy);\n    });\n  });\n\n  // _childViewEventHandler\n  describe('when an event is triggered on a childView', function() {\n    let collectionView;\n    let handlerSpy;\n\n    const eventArg = 'foo';\n    const dataArg = 'bar';\n\n    beforeEach(function() {\n      const MyCollectionView = CollectionView.extend({\n        childView: View.extend({ template: _.noop })\n      });\n      const collection = new Backbone.Collection([{}, {}]);\n\n      collectionView = new MyCollectionView({ collection, childViewEventPrefix: 'childview' });\n\n      handlerSpy = this.sinon.spy(collectionView, '_childViewEventHandler');\n\n      collectionView.render();\n    });\n\n    it('should call _childViewEventHandler', function() {\n      const childView = collectionView.children.findByIndex(0);\n\n      handlerSpy.resetHistory();\n\n      childView.triggerMethod(eventArg, dataArg);\n\n      expect(handlerSpy)\n        .to.be.calledOnce\n        .and.calledWith(eventArg, dataArg);\n    });\n\n    describe('when the childView is removed from the collectionView', function() {\n      it('should not call _childViewEventHandler', function() {\n        const childView = collectionView.children.findByIndex(0);\n\n        collectionView.removeChildView(childView);\n\n        handlerSpy.resetHistory();\n\n        childView.triggerMethod(eventArg, dataArg);\n\n        expect(handlerSpy).to.not.be.called;\n      });\n    });\n  });\n\n  describe('#_getImmediateChildren', function() {\n    let collectionView;\n\n    describe('when empty', function() {\n      beforeEach(function() {\n        collectionView = new CollectionView();\n      });\n\n      it('should return an empty array for getImmediateChildren', function() {\n        expect(collectionView._getImmediateChildren())\n          .to.be.instanceof(Array)\n          .and.to.have.length(0);\n      });\n    });\n\n    describe('when there are children', function() {\n      let childOne;\n      let childTwo;\n\n      beforeEach(function() {\n        collectionView = new CollectionView({\n          collection: new Backbone.Collection([{}, {}]),\n          childView: View.extend({ template: _.noop })\n        });\n        collectionView.render();\n\n        const children = collectionView.children;\n\n        childOne = children.findByIndex(0);\n        childTwo = children.findByIndex(1);\n      });\n\n      it('should return an empty array for getImmediateChildren', function() {\n        expect(collectionView._getImmediateChildren())\n          .to.be.instanceof(Array)\n          .and.to.have.length(2)\n          .and.to.contain(childOne)\n          .and.to.contain(childTwo);\n      });\n    });\n  });\n\n  describe('#_removeChildren', function() {\n    let collectionView;\n    let childOne;\n    let childTwo;\n\n    beforeEach(function() {\n      collectionView = new CollectionView({\n        collection: new Backbone.Collection([{}, {}]),\n        childView: View.extend({ template: _.noop })\n      });\n      collectionView.render();\n\n      const children = collectionView.children;\n\n      childOne = children.findByIndex(0);\n      childTwo = children.findByIndex(1);\n\n      collectionView._removeChildren();\n    });\n\n    it('should empty the children', function() {\n      expect(collectionView.children).to.have.lengthOf(0);\n    });\n\n    it('should have destroyed all of the children', function() {\n      expect(childOne.isDestroyed()).to.be.true;\n      expect(childTwo.isDestroyed()).to.be.true;\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/collection-view/collection-view.spec.js",
    "content": "// Life-cycle and base functions\n\nimport $ from 'jquery';\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport CollectionView from '../../../src/collection-view';\nimport View from '../../../src/view';\nimport Events from '../../../src/mixins/events';\n\ndescribe('CollectionView', function() {\n  let MyChildView;\n  let MyBbChildView;\n\n  beforeEach(function() {\n    MyChildView = View.extend({\n      template: _.noop,\n      onBeforeRender: this.sinon.stub(),\n      onRender: this.sinon.stub(),\n      onBeforeDestroy: this.sinon.stub(),\n      onDestroy: this.sinon.stub(),\n    });\n\n    MyBbChildView = Backbone.View.extend({\n      onBeforeRender: this.sinon.stub(),\n      onRender: this.sinon.stub(),\n      onBeforeDestroy: this.sinon.stub(),\n      onDestroy: this.sinon.stub(),\n    });\n    _.extend(MyBbChildView.prototype, Events);\n  });\n\n  describe('#constructor', function() {\n    let MyCollectionView;\n\n    beforeEach(function() {\n      MyCollectionView = CollectionView.extend({\n        childView: MyChildView\n      });\n    });\n\n    describe('when passing in options', function() {\n      let collectionView;\n\n      const mergeOptions = {\n        behaviors: {},\n        childView: {},\n        childViewContainer: {},\n        childViewEventPrefix: 'child',\n        childViewEvents: {},\n        childViewOptions: {},\n        childViewTriggers: {},\n        collectionEvents: {},\n        emptyView: {},\n        emptyViewOptions: {},\n        modelEvents: {},\n        sortWithCollection: {},\n        template: {},\n        templateContext: {},\n        triggers: {},\n        ui: {},\n        viewComparator: {},\n        viewFilter: {}\n      };\n\n      beforeEach(function() {\n        collectionView = new MyCollectionView(mergeOptions);\n      });\n\n      // NOTE: `events` is purposefully left out as it is handled by\n      // backbone.js and is mutated on instantiation\n      _.each(mergeOptions, function(value, key) {\n        it(`should merge option ${ key }`, function() {\n          expect(collectionView[key]).to.equal(value);\n        });\n      });\n\n      // _setOptions\n      it('should attach options to the collectionView', function() {\n        expect(collectionView.options).to.deep.equal(mergeOptions);\n      });\n    });\n\n    it('should setup the lifecycle monitor before initialize', function() {\n      this.sinon.stub(MyCollectionView.prototype, 'initialize').callsFake(function() {\n        expect(this._areViewEventsMonitored).to.be.true;\n      });\n\n      new MyCollectionView();\n    });\n\n    it('should have a valid inheritance chain back to Backbone.View', function() {\n      const options = {foo: 'bar'};\n      const customParam = {foo: 'baz'};\n\n      const TestView = MyCollectionView.extend({\n        initialize: this.sinon.stub()\n      })\n\n      const testView = new TestView(options, customParam);\n\n      expect(testView.initialize).to.have.been.calledOnce.and.calledWith(options, customParam);\n    });\n\n    it('should call initialize prior to delegateEntityEvents', function() {\n      this.sinon.stub(MyCollectionView.prototype, 'initialize');\n      this.sinon.stub(MyCollectionView.prototype, 'delegateEntityEvents');\n\n      const myCollectionView = new MyCollectionView();\n\n      expect(myCollectionView.initialize).to.be.calledBefore(myCollectionView.delegateEntityEvents);\n    });\n\n    it('should trigger `initialize` on the behaviors', function() {\n      this.sinon.stub(MyCollectionView.prototype, '_triggerEventOnBehaviors');\n\n      const myCollectionView = new MyCollectionView({ foo: 'bar' });\n\n      // _triggerEventOnBehaviors comes from Behaviors mixin\n      expect(myCollectionView._triggerEventOnBehaviors)\n        .to.be.calledOnce.and.calledWith('initialize', myCollectionView, { foo: 'bar' });\n    });\n  });\n\n  describe('#childView', function() {\n    const collection = new Backbone.Collection([{ id: 1 }]);\n    const model = collection.get(1);\n\n    beforeEach(function() {\n      this.sinon.spy(CollectionView.prototype, 'buildChildView');\n    });\n\n    describe('when childView is falsey', function() {\n      it('should throw NoChildViewError', function() {\n        const myCollectionView = new CollectionView({ collection });\n\n        expect(myCollectionView.render.bind(myCollectionView)).to.throw('A \"childView\" must be specified');\n      });\n    });\n\n    describe('when childView is a type of Backbone.View', function() {\n      it('should build children from the defined view', function() {\n        const MyView = View.extend({ template: _.noop });\n        const myCollectionView = new CollectionView({\n          collection,\n          childView: MyView\n        });\n        myCollectionView.render();\n\n        expect(myCollectionView.buildChildView).to.be.calledWith(model, MyView);\n      });\n    });\n\n    describe('when childView is a Backbone.View', function() {\n      it('should build children from the defined view', function() {\n        let BBView = Backbone.View.extend();\n        _.extend(BBView.prototype, Events);\n        const myCollectionView = new CollectionView({\n          collection,\n          childView: BBView\n        });\n        myCollectionView.render();\n\n        expect(myCollectionView.buildChildView).to.be.calledWith(model, BBView);\n      });\n    });\n\n    describe('when childView is a function returning a view', function() {\n      let myCollectionView;\n      let childViewStub;\n      let BBView = Backbone.View.extend();\n      _.extend(BBView.prototype, Events);\n      beforeEach(function() {\n        childViewStub = this.sinon.stub();\n        childViewStub.returns(BBView);\n\n        myCollectionView = new CollectionView({\n          collection,\n          childView: childViewStub\n        });\n        myCollectionView.render();\n      });\n\n      it('should build children from the returned view', function() {\n        expect(myCollectionView.buildChildView).to.be.calledWith(model, BBView);\n      });\n\n      it('should call childView with the model', function() {\n        expect(childViewStub)\n          .to.have.been.calledOnce\n          .and.calledWith(model);\n      });\n    });\n\n    describe('when childView is not a valid view', function() {\n      it('should throw InvalidChildViewError', function() {\n        const myCollectionView = new CollectionView({\n          collection,\n          childView: 'foo'\n        });\n\n        expect(myCollectionView.render.bind(myCollectionView)).to.throw('\"childView\" must be a view class or a function that returns a view class');\n      });\n    });\n  });\n\n  describe('#childViewOptions', function() {\n    describe('when childViewOptions is a function', function() {\n      const collection = new Backbone.Collection([{ id: 1 }]);\n      const model = collection.get(1);\n      const childViewOptions = {};\n\n      let myCollectionView;\n      let childViewOptionsStub;\n      let childView;\n\n      beforeEach(function() {\n        childView = MyBbChildView;\n\n        childViewOptionsStub = this.sinon.stub();\n        childViewOptionsStub.returns(childViewOptions);\n        this.sinon.spy(CollectionView.prototype, 'buildChildView');\n\n        myCollectionView = new CollectionView({\n          collection,\n          childView,\n          childViewOptions: childViewOptionsStub\n        });\n\n        myCollectionView.render();\n      });\n\n      it('should call buildChildView with childViewOptions results', function() {\n        expect(myCollectionView.buildChildView).to.be.calledWith(model, childView, childViewOptions);\n      });\n\n      it('should call childViewOptions with child model', function() {\n        expect(childViewOptionsStub)\n          .to.have.been.calledOnce\n          .and.calledWith(model);\n      });\n    });\n  });\n\n  describe('#buildChildView', function() {\n    it('should call buildChildView with arguments', function() {\n      const collection = new Backbone.Collection([{ id: 1 }]);\n      const model = collection.get(1);\n      const childView = MyBbChildView;\n      const childViewOptions = {};\n\n      this.sinon.spy(CollectionView.prototype, 'buildChildView');\n\n      const myCollectionView = new CollectionView({\n        collection,\n        childView,\n        childViewOptions\n      });\n\n      myCollectionView.render();\n      expect(myCollectionView.buildChildView).to.be.calledWith(model, childView, childViewOptions);\n    });\n  });\n\n  describe('#setElement', function() {\n\n    it('should call Backbone.View.setElement with all arguments', function() {\n      const myCollectionView = new CollectionView();\n      const bBSetElement = this.sinon.spy(Backbone.View.prototype, 'setElement');\n\n      myCollectionView.setElement('#foo',2,3,4);\n\n      expect(bBSetElement).to.be.calledWith('#foo',2,3,4);\n    });\n\n    it('should return the collectionView instance', function() {\n      const myCollectionView = new CollectionView();\n      this.sinon.spy(myCollectionView, 'setElement');\n\n      myCollectionView.setElement();\n\n      expect(myCollectionView.setElement).to.have.returned(myCollectionView);\n    });\n\n\n    describe('when the view does not have an attach el', function() {\n      it('should not mark the view as attached', function() {\n        const myCollectionView = new CollectionView({ el: $('<div>') });\n\n        expect(myCollectionView.isAttached()).to.be.false;\n      });\n    });\n\n    describe('when the view is given an attach el', function() {\n      it('should mark the view as attached', function() {\n        this.setFixtures('<div id=\"attached\"></div>');\n        const myCollectionView = new CollectionView({ el: $('#attached') });\n\n        expect(myCollectionView.isAttached()).to.be.true;\n      });\n    });\n  });\n\n  describe('#render', function() {\n    let myCollectionView;\n\n    beforeEach(function() {\n      const MyCollectionView = CollectionView.extend({\n        onBeforeRender: this.sinon.stub(),\n        onRender: this.sinon.stub(),\n      });\n\n      myCollectionView = new MyCollectionView();\n      this.sinon.spy(myCollectionView, 'render');\n    });\n\n    describe('when the view is not destroyed', function() {\n      beforeEach(function() {\n        myCollectionView.render();\n      });\n\n      it('should set isRendered to true', function() {\n        expect(myCollectionView.isRendered()).to.be.true;\n      });\n\n      it('should call \"before:render\" event', function() {\n        expect(myCollectionView.onBeforeRender)\n          .to.have.been.calledOnce\n          .and.calledWith(myCollectionView);\n      });\n\n      it('should call \"render\" event', function() {\n        expect(myCollectionView.onRender)\n          .to.have.been.calledOnce\n          .and.calledWith(myCollectionView);\n      });\n\n      it('should return the collectionView instance', function() {\n        expect(myCollectionView.render).to.have.returned(myCollectionView);\n      });\n\n    });\n\n    describe('when the view is destroyed', function() {\n      beforeEach(function() {\n        myCollectionView.destroy();\n        myCollectionView.render();\n      });\n\n      it('should not call \"before:render\" event', function() {\n        expect(myCollectionView.onBeforeRender).to.not.have.been.called;\n      });\n\n      it('should not call \"render\" event', function() {\n        expect(myCollectionView.onRender).to.not.have.been.called;\n      });\n\n      it('should return the collectionView instance', function() {\n        expect(myCollectionView.render).to.have.returned(myCollectionView);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/common/bind-events.spec.js",
    "content": "import { bindEvents, unbindEvents } from '../../../src/common/bind-events';\n\ndescribe('bind-events', function() {\n  let entity;\n  let target;\n\n  beforeEach(function() {\n    entity = this.sinon.stub();\n\n    target = {\n      handleFoo: this.sinon.stub(),\n      listenTo: this.sinon.stub(),\n      stopListening: this.sinon.stub(),\n      bindEvents,\n      unbindEvents\n    };\n\n    this.sinon.spy(target, 'bindEvents');\n    this.sinon.spy(target, 'unbindEvents');\n  });\n\n  describe('bindEvents', function() {\n    describe('when entity isnt passed', function() {\n      beforeEach(function() {\n        target.bindEvents(false, { 'foo': 'handleFoo' });\n      });\n\n      it('shouldnt bind any events', function() {\n        expect(target.listenTo).not.to.have.been.called;\n      });\n\n      it('should return the target', function() {\n        expect(target.bindEvents).to.have.returned(target);\n      });\n    });\n\n    describe('when bindings isnt passed', function() {\n      beforeEach(function() {\n        target.bindEvents(entity, null);\n      });\n\n      it('shouldnt bind any events', function() {\n        expect(target.listenTo).not.to.have.been.called;\n      });\n\n      it('should return the target', function() {\n        expect(target.bindEvents).to.have.returned(target);\n      });\n    });\n\n    describe('when bindings is an object with an event handler hash', function() {\n      it('should return the target', function() {\n        target.bindEvents(entity, { 'foo': 'handleFoo' });\n        expect(target.bindEvents).to.have.returned(target);\n      });\n\n      describe('when handler is a function', function() {\n        it('should bind an event to targets handler', function() {\n          const handleBar = this.sinon.stub();\n          target.bindEvents(entity, { 'bar': handleBar });\n          expect(target.listenTo)\n            .to.have.been.calledOnce\n            .and.calledWith(entity, { 'bar': handleBar });\n        });\n      });\n\n      describe('when handler is a string', function() {\n        it('should bind an event to targets handler', function() {\n          target.bindEvents(entity, { 'foo': 'handleFoo' });\n          expect(target.listenTo)\n            .to.have.been.calledOnce\n            .and.calledWith(entity, { 'foo': target.handleFoo });\n        });\n      });\n    });\n\n    describe('when bindings is not an object', function() {\n      it('should error', function() {\n        expect(function() {\n          target.bindEvents(entity, 'handleFoo');\n        }).to.throw('Bindings must be an object.');\n      });\n    });\n  });\n\n  describe('unbindEvents', function() {\n    describe('when entity isnt passed', function() {\n      beforeEach(function() {\n        target.unbindEvents(false, { 'foo': 'handleFoo' });\n      });\n\n      it('shouldnt unbind any events', function() {\n        expect(target.stopListening).not.to.have.been.called;\n      });\n\n      it('should return the target', function() {\n        expect(target.unbindEvents).to.have.returned(target);\n      });\n    });\n\n    describe('when bindings isnt passed', function() {\n      beforeEach(function() {\n        target.unbindEvents(entity, null);\n      });\n\n      it('should unbind all events', function() {\n        expect(target.stopListening)\n          .to.have.been.calledOnce\n          .and.calledWith(entity);\n      });\n\n      it('should return the target', function() {\n        expect(target.unbindEvents).to.have.returned(target);\n      });\n    });\n\n    describe('when bindings is an object with an event handler hash', function() {\n      it('should return the target', function() {\n        target.unbindEvents(entity, { 'foo': 'handleFoo' })\n        expect(target.unbindEvents).to.have.returned(target);\n      });\n\n      describe('when handler is a function', function() {\n        it('should unbind an event', function() {\n          const handleBar = this.sinon.stub();\n          target.unbindEvents(entity, { 'bar': handleBar });\n          expect(target.stopListening)\n            .to.have.been.calledOnce\n            .and.calledWith(entity, { 'bar': handleBar });\n        });\n      });\n\n      describe('when handler is a string', function() {\n        describe('when one handler is passed', function() {\n          it('should unbind an event', function() {\n            target.unbindEvents(entity, { 'foo': 'handleFoo' });\n            expect(target.stopListening)\n              .to.have.been.calledOnce\n              .and.calledWith(entity, { 'foo': target.handleFoo });\n          });\n        });\n      });\n    });\n\n    describe('when bindings is not an object', function() {\n      it('should error', function() {\n        expect(function() {\n          target.unbindEvents(entity, 'handleFoo');\n        }).to.throw('Bindings must be an object.');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/common/bind-request.spec.js",
    "content": "import { bindRequests, unbindRequests } from '../../../src/common/bind-requests';\n\ndescribe('bind-requests', function() {\n  let channel;\n  let target;\n\n  beforeEach(function() {\n    channel = {\n      reply: this.sinon.stub(),\n      stopReplying: this.sinon.stub()\n    };\n\n    target = {\n      replyFoo: this.sinon.stub(),\n      bindRequests,\n      unbindRequests\n    };\n\n    this.sinon.spy(target, 'bindRequests');\n    this.sinon.spy(target, 'unbindRequests')\n  });\n\n  describe('bindRequests', function() {\n    describe('when channel isnt passed', function() {\n      beforeEach(function() {\n        target.bindRequests(false, { 'foo': 'replyFoo' });\n      });\n\n      it('shouldnt bind any requests', function() {\n        expect(channel.reply).not.to.have.been.called;\n      });\n\n      it('should return the target', function() {\n        expect(target.bindRequests).to.have.returned(target);\n      });\n    });\n\n    describe('when bindings isnt passed', function() {\n      beforeEach(function() {\n        target.bindRequests(channel, null);\n      });\n\n      it('shouldnt bind any requests', function() {\n        expect(channel.reply).not.to.have.been.called;\n      });\n\n      it('should return the target', function() {\n        expect(target.bindRequests).to.have.returned(target);\n      });\n    });\n\n    describe('when bindings is an object with an event handler hash', function() {\n      it('should return the target', function() {\n        target.bindRequests(channel, { 'foo': 'replyFoo' })\n        expect(target.bindRequests).to.have.returned(target);\n      });\n\n      describe('when handler is a function', function() {\n        it('should bind a request to targets handler', function() {\n          const replyBar = this.sinon.stub();\n          target.bindRequests(channel, { 'bar': replyBar });\n          expect(channel.reply)\n            .to.have.been.calledOnce\n            .and.calledWith({ 'bar': replyBar });\n        });\n      });\n\n      describe('when handler is a string', function() {\n        describe('when one handler is passed', function() {\n          it('should bind a request to targets handler', function() {\n            target.bindRequests(channel, { 'foo': 'replyFoo' });\n            expect(channel.reply)\n              .to.have.been.calledOnce\n              .and.calledWith({ 'foo': target.replyFoo });\n          });\n        });\n      });\n    });\n\n    describe('when bindings is not an object', function() {\n      it('should error', function() {\n        expect(function() {\n          target.bindRequests(channel, 'replyFoo');\n        }).to.throw('Bindings must be an object.');\n      });\n    });\n  });\n\n  describe('unbindRequests', function() {\n    describe('when channel isnt passed', function() {\n      beforeEach(function() {\n        target.unbindRequests(false, { 'foo': 'replyFoo' });\n      });\n\n      it('shouldnt unbind any request', function() {\n        expect(channel.stopReplying).not.to.have.been.called;\n      });\n\n      it('should return the target', function() {\n        expect(target.unbindRequests).to.have.returned(target);\n      });\n    });\n\n    describe('when bindings isnt passed', function() {\n      beforeEach(function() {\n        target.unbindRequests(channel, null);\n      });\n\n      it('should unbind all requests', function() {\n        expect(channel.stopReplying)\n          .to.have.been.calledOnce\n          .and.calledWith(null, null, target);\n      });\n\n      it('should return the target', function() {\n        expect(target.unbindRequests).to.have.returned(target);\n      });\n    });\n\n    describe('when bindings is an object with an event handler hash', function() {\n      it('should return the target', function() {\n        target.unbindRequests(channel, { 'foo': 'replyFoo' });\n        expect(target.unbindRequests).to.have.returned(target);\n      });\n\n      describe('when handler is a function', function() {\n        it('should unbind an request', function() {\n          const replyBar = this.sinon.stub();\n          target.unbindRequests(channel, { 'bar': replyBar })\n          expect(channel.stopReplying)\n            .to.have.been.calledOnce\n            .and.calledWith({ 'bar': replyBar });\n        });\n      });\n\n      describe('when handler is a string', function() {\n        describe('when one handler is passed', function() {\n          it('should unbind an request', function() {\n            target.unbindRequests(channel, { 'foo': 'replyFoo' });\n            expect(channel.stopReplying)\n              .to.have.been.calledOnce\n              .and.calledWith({ 'foo': target.replyFoo });\n          });\n        });\n      });\n    });\n\n    describe('when bindings is not an object', function() {\n      it('should error', function() {\n        expect(function() {\n          target.unbindRequests(channel, 'replyFoo');\n        }).to.throw('Bindings must be an object.');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/common/build-region.spec.js",
    "content": "import View from '../../../src/view';\nimport Region from '../../../src/region';\n\ndescribe('Region', function() {\n  describe('.buildRegion', function() {\n    let DefaultRegionClass;\n    let view;\n    let fooSelector;\n    let barSelector;\n    let BarRegion;\n    let BazRegion;\n\n    beforeEach(function() {\n\n      DefaultRegionClass = Region.extend();\n\n      view = new View({\n        template: _.noop,\n        regionClass: DefaultRegionClass\n      });\n\n      fooSelector = '#foo-region';\n\n      barSelector = '#bar-region';\n      BarRegion = Region.extend({el: barSelector});\n\n      BazRegion = Region.extend();\n    });\n\n    describe('with a selector string', function() {\n      let region;\n\n      beforeEach(function() {\n        region = view.addRegion(_.uniqueId('region_'), fooSelector);\n      });\n\n      it('uses the default region class', function() {\n        expect(region).to.be.an.instanceof(DefaultRegionClass);\n      });\n\n      it('uses the selector', function() {\n        expect(region.el).to.equal(fooSelector);\n      });\n    });\n\n    describe('with a region class', function() {\n      describe('with `el` defined', function() {\n        let region;\n\n        beforeEach(function() {\n          region = view.addRegion(_.uniqueId('region_'), BarRegion);\n        });\n\n        it('uses the passed in region class', function() {\n          expect(region).to.be.an.instanceof(BarRegion);\n        });\n\n        it('uses the defined el', function() {\n          expect(region.el).to.equal(barSelector);\n        });\n      });\n\n      describe('without `el` defined', function() {\n        let buildRegion;\n\n        beforeEach(function() {\n          buildRegion = function() {\n            view.addRegion(_.uniqueId('region_'), BazRegion);\n          };\n        });\n\n        it('throws a `NoElError`', function() {\n          expect(buildRegion).to.throw('An \"el\" must be specified for a region.');\n        });\n      });\n    });\n\n    describe('with an object literal', function() {\n      describe('with `el` defined', function() {\n        describe('when el is a selector string', function() {\n          let definition;\n          let region;\n\n          beforeEach(function() {\n            definition = {el: fooSelector};\n            region = view.addRegion(_.uniqueId('region_'),definition);\n          });\n\n          it('uses the default region class', function() {\n            expect(region).to.be.an.instanceof(DefaultRegionClass);\n          });\n\n          it('uses the el', function() {\n            expect(region.el).to.equal(fooSelector);\n          });\n\n          describe('with `parentEl` also defined', function() {\n            describe('including the selector', function() {\n              beforeEach(function() {\n                this.setFixtures('<div id=\"parent\"><div id=\"child\">text</div></div>');\n                const parentEl = $('#parent');\n                definition = _.defaults({parentEl: parentEl, el: '#child' }, definition);\n                region = view.addRegion(_.uniqueId('region_'), definition);\n              });\n\n              it('returns the jQuery(el)', function() {\n                expect(region.getEl(region.el).text()).to.equal($(region.el).text());\n              });\n            });\n\n            describe('excluding the selector', function() {\n              beforeEach(function() {\n                this.setFixtures('<div id=\"parent\"></div><div id=\"not-child\">text</div>');\n                const parentEl = $('#parent');\n                definition = _.defaults({parentEl: parentEl, el: '#not-child' }, definition);\n                region = view.addRegion(_.uniqueId('region_'), definition);\n              });\n\n              it('returns the jQuery(el)', function() {\n                expect(region.getEl(region.el).text()).to.not.equal($(region.el).text());\n              });\n            });\n\n            describe('including multiple instances of the selector', function() {\n              beforeEach(function() {\n                this.setFixtures('<div id=\"parent\"><div class=\"child\">text</div><div class=\"child\">text</div></div>');\n                const parentEl = $('#parent');\n                definition = _.defaults({parentEl: parentEl, el: '.child' }, definition);\n                region = view.addRegion(_.uniqueId('region_'), definition);\n              });\n\n              it('should ensure a jQuery(el) of length 1', function() {\n                // calls _ensureElement\n                region.empty();\n                expect(region.$el.length).to.equal(1);\n              });\n            });\n          });\n        });\n\n        describe('when el is an HTML node', function() {\n          let el;\n          let definition;\n          let region;\n\n          beforeEach(function() {\n            el = $('<div id=\"baz-region\">')[0];\n            new DefaultRegionClass({el: el});\n            definition = {el: el};\n            region = view.addRegion(_.uniqueId('region_'), definition);\n          });\n\n          it('uses the default region class', function() {\n            expect(region).to.be.an.instanceof(DefaultRegionClass);\n          });\n\n          it('uses the el', function() {\n            expect(region.el).to.equal(el);\n          });\n\n          describe('with `parentEl` also defined', function() {\n            beforeEach(function() {\n              const parentEl = $('<div id=\"not-actual-parent\"></div>');\n              definition = _.defaults({parentEl: parentEl}, definition);\n              region = view.addRegion(_.uniqueId('region_'), definition);\n            });\n\n            it('returns the jQuery(el)', function() {\n              expect(region.getEl(el)).to.deep.equal($(el));\n            });\n\n          });\n        });\n\n        describe('when el is a jQuery object', function() {\n          let el;\n          let region;\n\n          beforeEach(function() {\n            el = $('<div id=\"baz-region\">');\n            new DefaultRegionClass({el: el});\n            const definition = {el: el};\n            region = view.addRegion(_.uniqueId('region_'), definition);\n          });\n\n          it('uses the default region class', function() {\n            expect(region).to.be.an.instanceof(DefaultRegionClass);\n          });\n\n          it('uses the el', function() {\n            expect(region.el).to.equal(el[0]);\n          });\n        });\n      });\n\n      describe('when el is an empty jQuery object', function() {\n        let buildRegion;\n\n        beforeEach(function() {\n          const el = $('i-am-not-real');\n          const definition = {el: el};\n\n          buildRegion = function() {\n            view.addRegion(_.uniqueId('region_'), definition);\n          };\n        });\n\n        it('throws a `NoElError`', function() {\n          expect(buildRegion).to.throw('An \"el\" must be specified for a region.');\n        });\n      });\n\n      describe('with `regionClass` defined', function() {\n        describe('with `el` also defined', function() {\n          let el;\n          let region1;\n          let region2;\n          let region3;\n\n          beforeEach(function() {\n            const $el = $('<div id=\"baz-region\">');\n            el = $el[0];\n\n            const baseDefinition = {regionClass: BazRegion};\n            const region1Definition = _.defaults({el: fooSelector}, baseDefinition);\n            const region2Definition = _.defaults({el: el}, baseDefinition);\n            const region3Definition = _.defaults({el: $el}, baseDefinition);\n\n            region1 = view.addRegion(_.uniqueId('region_'), region1Definition);\n            region2 = view.addRegion(_.uniqueId('region_'), region2Definition);\n            region3 = view.addRegion(_.uniqueId('region_'), region3Definition);\n          });\n\n          it('uses the region class', function() {\n            expect(region1).to.be.an.instanceof(BazRegion);\n            expect(region2).to.be.an.instanceof(BazRegion);\n            expect(region3).to.be.an.instanceof(BazRegion);\n          });\n\n          it('uses the el', function() {\n            expect(region1.el).to.equal(fooSelector);\n            expect(region2.el).to.equal(el);\n            expect(region3.el).to.equal(el);\n          });\n        });\n\n        describe('without `selector` or `el` defined on `regionConfig`', function() {\n          describe('with `el` defined on `regionClass`', function() {\n            let region;\n\n            beforeEach(function() {\n              const definition = {regionClass: BarRegion};\n              region = view.addRegion(_.uniqueId('region_'), definition);\n            });\n\n            it('uses the region class', function() {\n              expect(region).to.be.an.instanceof(BarRegion);\n            });\n          });\n\n          describe('without `el` defined on `regionClass`', function() {\n            let buildRegion;\n\n            beforeEach(function() {\n              const definition = {regionClass: BazRegion};\n\n              buildRegion = function() {\n                view.addRegion(_.uniqueId('region_'), definition);\n              };\n            });\n\n            it('throws a `NoElError`', function() {\n              expect(buildRegion).to.throw('An \"el\" must be specified for a region.');\n            });\n          });\n        });\n      });\n\n      describe('with additional region options', function() {\n        let region;\n\n        beforeEach(function() {\n          const definition = {\n            el: fooSelector,\n            regionClass: BazRegion,\n            myRegionOption: 42,\n            myOtherRegionOption: 'foobar'\n          };\n\n          region = view.addRegion(_.uniqueId('region_'), definition);\n        });\n\n        it('it sets the region options', function() {\n          expect(region.getOption('myRegionOption')).to.equal(42);\n          expect(region.getOption('myOtherRegionOption')).to.equal('foobar');\n        });\n      });\n    });\n\n    describe('with a instantiated region', function() {\n      let region;\n\n      beforeEach(function() {\n        region = view.addRegion(_.uniqueId('region_'), new BarRegion());\n      });\n\n      it('uses the region class', function() {\n        expect(region).to.be.an.instanceof(BarRegion);\n      });\n    });\n\n    describe('with a missing regionConfig', function() {\n      let buildRegion;\n\n      beforeEach(function() {\n        buildRegion = function() {\n          view.addRegion(_.uniqueId('region_'));\n        };\n      });\n\n      it('throws an error', function() {\n        expect(buildRegion).to.throw('Improper region configuration type.');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/common/get-option.spec.js",
    "content": "import getOption from '../../../src/common/get-option';\n\ndescribe('get option', function() {\n  describe('when calling without arguments', function() {\n    it('should return undefined', function() {\n      expect(getOption()).to.be.undefined;\n    });\n  });\n\n  describe('when an object only has the option set on the definition', function() {\n    it('should return that definitions option', function() {\n      const target = {\n        foo: 'bar',\n        getOption\n      };\n\n      expect(target.getOption('foo')).to.equal(target.foo);\n    });\n  });\n\n  describe('when an object only has the option set on the options', function() {\n    it('should return value from the options', function() {\n      const target = {\n        options: {foo: 'bar'},\n        getOption\n      };\n\n      expect(target.getOption('foo')).to.equal(target.options.foo);\n    });\n  });\n\n  describe('when an object has the option set on the options, and it is a \"falsey\" value', function() {\n    it('should return value from the options', function() {\n      const target = {\n        options: {foo: false},\n        getOption\n      };\n\n      expect(target.getOption('foo')).to.equal(target.options.foo);\n    });\n  });\n\n  describe('when an object has the option set on the options, and it is a \"undefined\" value', function() {\n    it('should return the objects value', function() {\n      const target = {\n        foo: 'bar',\n        options: {foo: undefined},\n        getOption\n      };\n\n      expect(target.getOption('foo')).to.equal(target.foo);\n    });\n  });\n\n  describe('when an object has the option set on both the definition and options', function() {\n    it('should return that value from the options', function() {\n      const target = {\n        foo: 'bar',\n        options: {foo: 'baz'},\n        getOption\n      };\n\n      expect(target.getOption('foo')).to.equal(target.options.foo);\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/common/merge-options.spec.js",
    "content": "import mergeOptions from '../../../src/common/merge-options';\n\ndescribe('mergeOptions', function() {\n  let target;\n\n  beforeEach(function() {\n    target = {\n      myOptions: ['color', 'size'],\n      mergeOptions,\n      initialize(options) {\n        this.mergeOptions(options, this.myOptions);\n      }\n    };\n  });\n\n  describe('when calling with undefined options', function() {\n    it('should return instantly without merging anything', function() {\n      expect(mergeOptions()).to.be.undefined;\n    });\n  });\n\n  describe('when no matching the keys', function() {\n    it('should not merge any of those options', function() {\n      target.initialize({\n        hungry: true,\n        country: 'USA'\n      });\n\n      expect(target).to.not.contain.keys('hungry', 'country');\n    });\n  });\n\n  describe('when some matching the keys', function() {\n    beforeEach(function() {\n      target.initialize({\n        hungry: true,\n        country: 'USA',\n        color: 'blue'\n      });\n    });\n\n    it('should not merge the ones that do not match', function() {\n      expect(target).to.not.contain.keys('hungry', 'country');\n    });\n\n    it('should merge the ones that match', function() {\n      expect(target).to.contain.keys('color');\n    });\n  });\n\n  describe('when all matching the keys', function() {\n    it('should merge all of the options', function() {\n      target.initialize({\n        size: 'large',\n        color: 'blue'\n      });\n\n      expect(target).to.contain.keys('color', 'size');\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/common/monitor-view-events.js",
    "content": "import View from '../../../src/view';\nimport monitorViewEvents from '../../../src/common/monitor-view-events';\n\ndescribe('monitorViewEvents', function() {\n  describe('when the monitor is disabled', function() {\n    let view;\n\n    beforeEach(function() {\n      const NonMonitoredView = View.extend({\n        monitorViewEvents: false\n      });\n\n      view = new NonMonitoredView();\n\n      this.sinon.spy(view, 'on');\n    });\n\n    it('should not attach events', function() {\n      monitorViewEvents(view);\n      expect(view.on).to.not.have.been.called;\n    });\n  });\n\n  describe('when the view is already monitored', function() {\n    let view;\n\n    beforeEach(function() {\n      view = new View();\n\n      monitorViewEvents(view);\n\n      this.sinon.spy(view, 'on');\n    });\n\n    it('should not attach events', function() {\n      monitorViewEvents(view);\n      expect(view.on).to.not.have.been.called;\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/common/normalize-methods.spec.js",
    "content": "import View from '../../../src/view';\n\ndescribe('normalizeMethods', function() {\n  'use strict';\n\n  let view;\n\n  beforeEach(function() {\n    const MyView = View.extend({\n      foo: this.sinon.stub()\n    });\n    view = new MyView();\n  });\n\n  describe('when called with no value', function() {\n    it('should return nothing', function() {\n      expect(view.normalizeMethods()).to.be.undefined;\n    });\n  });\n\n  describe('when called with a hash of functions and strings', function() {\n    let normalizedHash;\n    let hash;\n\n    beforeEach(function() {\n      hash = {\n        'foo': 'foo',\n        'bar': 'bar'\n      };\n      normalizedHash = view.normalizeMethods(hash);\n    });\n\n    it('should convert the strings that exist as functions to functions', function() {\n      expect(normalizedHash).to.have.property('foo');\n    });\n\n    it('should ignore strings that dont exist as functions on the context', function() {\n      expect(normalizedHash).not.to.have.property('bar');\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/common/trigger-method.spec.js",
    "content": "import triggerMethod from '../../../src/common/trigger-method';\n\ndescribe('triggerMethod', function() {\n  let target;\n\n  beforeEach(function() {\n    target = {\n      trigger: this.sinon.stub(),\n      triggerMethod\n    };\n\n    this.sinon.spy(target, 'triggerMethod');\n  });\n\n  describe('when no onEventName method matcheds the event', function() {\n    beforeEach(function() {\n      target.triggerMethod('event:name', 'foo', 'bar');\n    });\n\n    it('should trigger all arguments', function() {\n      expect(target.trigger)\n        .to.have.been.calledOnce\n        .and.calledOn(target)\n        .and.calledWith('event:name', 'foo', 'bar');\n    });\n\n    it('should return undefined', function() {\n      expect(target.triggerMethod).to.have.returned(undefined);\n    });\n  });\n\n  describe('when an onEventName method on the target matches the event', function() {\n    beforeEach(function() {\n      target.onEventName = this.sinon.stub().returns('baz');\n      target.triggerMethod('event:name', 'foo', 'bar');\n    });\n\n    it('should trigger all arguments', function() {\n      expect(target.trigger)\n        .to.have.been.calledOnce\n        .and.calledOn(target)\n        .and.calledWith('event:name', 'foo', 'bar');\n    });\n\n    it('should call onEventName methods on the target', function() {\n      expect(target.onEventName)\n        .to.have.been.calledOnce\n        .and.calledWith('foo', 'bar');\n    });\n\n    it('should return baz', function() {\n      expect(target.triggerMethod).to.have.returned('baz');\n    });\n  });\n\n  describe('when an onEventName method on the target options matches the event', function() {\n    beforeEach(function() {\n      target.options = {\n        onEventName: this.sinon.stub().returns('baz')\n      };\n      target.triggerMethod('event:name', 'foo', 'bar');\n    });\n\n    it('should trigger all arguments', function() {\n      expect(target.trigger)\n        .to.have.been.calledOnce\n        .and.calledWith('event:name', 'foo', 'bar');\n    });\n\n    it('should call onEventName methods on the target', function() {\n      expect(target.options.onEventName)\n        .to.have.been.calledOnce\n        .and.calledWith('foo', 'bar')\n        .and.calledOn(target);\n    });\n\n    it('should return baz', function() {\n      expect(target.triggerMethod).to.have.returned('baz');\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/common/view.spec.js",
    "content": "import Backbone from 'backbone';\n\nimport { renderView, destroyView } from '../../../src/common/view';\n\ndescribe('common view methods', function() {\n  let view;\n\n  beforeEach(function() {\n    view = new Backbone.View();\n    view.triggerMethod = this.sinon.stub();\n  });\n\n  describe('#renderView', function() {\n    beforeEach(function() {\n      view.render = this.sinon.stub();\n    });\n\n    describe('when render lifecycle is supported', function() {\n      beforeEach(function() {\n        view.supportsRenderLifecycle = true;\n        renderView(view);\n      });\n\n      it('should call render', function() {\n        expect(view.render).to.be.calledOnce;\n      });\n\n      it('should not trigger events', function() {\n        expect(view.triggerMethod).to.not.be.called;\n      });\n\n      describe('when view is rendered twice', function() {\n        it('should call not call render again', function() {\n          renderView(view);\n\n          expect(view.render)\n            .to.have.been.calledOnce\n            .to.not.have.been.calledTwice;\n        });\n      });\n    });\n\n    describe('when render lifecycle is not supported', function() {\n      beforeEach(function() {\n        view.supportsRenderLifecycle = false;\n        renderView(view);\n      });\n\n      it('should trigger before:render', function() {\n        expect(view.triggerMethod).to.be.calledWith('before:render', view);\n      });\n\n      it('should call render', function() {\n        expect(view.render).to.be.calledOnce;\n      });\n\n      it('should trigger render', function() {\n        expect(view.triggerMethod)\n          .to.be.calledWith('render', view);\n      });\n\n      describe('when view is rendered twice', function() {\n        it('should call not call render again', function() {\n          renderView(view);\n\n          expect(view.render)\n            .to.have.been.calledOnce\n            .to.not.have.been.calledTwice;\n        });\n      });\n    });\n  });\n\n  describe('#destroyView', function() {\n    beforeEach(function() {\n      this.sinon.spy(view, 'remove');\n    });\n\n    describe('when view has a native destroy method', function() {\n      beforeEach(function() {\n        view.destroy = this.sinon.stub();\n        destroyView(view, 'foo');\n      });\n\n      it('should call the view destroy', function() {\n        expect(view.destroy).to.be.calledOnce;\n      });\n\n      it('should not call view remove', function() {\n        expect(view.remove).to.not.be.called;\n      });\n\n      it('should not trigger events', function() {\n        expect(view.triggerMethod).to.not.be.called;\n      });\n\n      // Internal only test\n      it('should attach shouldDisableEvents flag to the view', function() {\n        expect(view._disableDetachEvents).to.equal('foo');\n      });\n    });\n\n    describe('when destroy lifecycle is supported', function() {\n      beforeEach(function() {\n        view.supportsDestroyLifecycle = true;\n        destroyView(view);\n      });\n\n      it('should remove the view', function() {\n        expect(view.remove).to.be.calledOnce;\n      });\n\n      it('should not trigger destroy events', function() {\n        expect(view.triggerMethod)\n          .to.not.be.calledWith('before:destroy', view)\n          .and.not.calledWith('destroy', view);\n      });\n\n      // Internal test\n      it('should mark the view destroyed', function() {\n        expect(view._isDestroyed).to.be.true;\n      });\n    });\n\n    describe('when destroy lifecycle is not supported', function() {\n      beforeEach(function() {\n        view.supportsDestroyLifecycle = false;\n        destroyView(view);\n      });\n\n      it('should trigger before:destroy event', function() {\n        expect(view.triggerMethod).to.be.calledWith('before:destroy', view)\n      });\n\n      it('should remove the view', function() {\n        expect(view.remove).to.be.calledOnce;\n      });\n\n      it('should trigger destroy event', function() {\n        expect(view.triggerMethod).to.be.calledWith('destroy', view)\n      });\n\n      // Internal test\n      it('should mark the view destroyed', function() {\n        expect(view._isDestroyed).to.be.true;\n      });\n    });\n\n    // _isAttached is internal Mn flag added by Region or CollectionView\n    describe('when view is attached', function() {\n      beforeEach(function() {\n        view._isAttached = true;\n      });\n\n      describe('when disabling events', function() {\n        beforeEach(function() {\n          destroyView(view, true);\n        });\n\n        it('should not trigger detach events', function() {\n          expect(view.triggerMethod)\n            .to.not.be.calledWith('before:detach', view)\n            .and.not.calledWith('detach', view);\n        });\n      });\n\n      describe('when not disabling events', function() {\n        beforeEach(function() {\n          destroyView(view, false);\n        });\n\n        it('should trigger before:detach event', function() {\n          expect(view.triggerMethod).to.be.calledWith('before:detach', view);\n        });\n\n        it('should trigger detach event', function() {\n          expect(view.triggerMethod).to.be.calledWith('detach', view);\n        });\n      });\n    });\n\n    describe('when view is not attached', function() {\n      beforeEach(function() {\n        view._isAttached = false;\n      });\n\n      describe('when disabling events', function() {\n        beforeEach(function() {\n          destroyView(view, true);\n        });\n\n        it('should not trigger detach events', function() {\n          expect(view.triggerMethod)\n            .to.not.be.calledWith('before:detach', view)\n            .and.not.calledWith('detach', view);\n        });\n      });\n\n      describe('when not disabling events', function() {\n        beforeEach(function() {\n          destroyView(view, false);\n        });\n\n        it('should not trigger detach events', function() {\n          expect(view.triggerMethod)\n            .to.not.be.calledWith('before:detach', view)\n            .and.not.calledWith('detach', view);\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/config/dom.js",
    "content": "import $ from 'jquery';\nimport _ from 'underscore';\nimport DomApi, { setDomApi } from '../../../src/config/dom';\n\n// Copied from https://github.com/jashkenas/underscore/blob/1.8.3/underscore.js#L137\nconst MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;\nconst getLength = _.property('length');\nfunction isArrayLike(collection) {\n  let length = getLength(collection);\n  return typeof length === 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;\n}\n\nchai.use(function(_chai, utils) {\n  _chai.Assertion.addProperty('arrayLike', function() {\n    this.assert(\n      isArrayLike(utils.flag(this, 'object')),\n      'expected #{this} to be a Array-like',\n      'expected #{this} to not be a Array-like'\n    );\n  });\n});\n\n\ndescribe('DomApi', function() {\n  describe('#setDomApi', function() {\n    it('should return the current class', function() {\n      const MyObject = function() {};\n      MyObject.setDomApi = setDomApi;\n      expect(MyObject.setDomApi()).to.be.eq(MyObject);\n    });\n  });\n\n  describe('#createBuffer', function() {\n    it('should return an appendable node', function() {\n      expect(DomApi.createBuffer().appendChild).to.be.a('function');\n    })\n  });\n\n  describe('#getEl', function() {\n    let $domEl;\n    let domEl;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"foo\"></div>');\n      $domEl = $('#foo');\n      domEl = $domEl[0];\n    });\n\n    describe('when passing a selector', function() {\n      it('should return an array-like object', function() {\n        expect(DomApi.getEl('#foo')).to.be.arrayLike;\n      });\n\n      it('should return the DOM element', function() {\n        expect(DomApi.getEl('#foo')[0]).to.eql(domEl)\n      });\n    });\n\n    describe('when passing a DOM element', function() {\n      it('should return an array-like object', function() {\n        expect(DomApi.getEl(domEl)).to.be.arrayLike;\n      });\n\n      it('should return the DOM element', function() {\n        expect(DomApi.getEl(domEl)[0]).to.eql(domEl)\n      });\n    });\n\n    describe('when passing a jQuery element', function() {\n      it('should return an array-like object', function() {\n        expect(DomApi.getEl($domEl)).to.be.arrayLike;\n      });\n\n      it('should return the DOM element', function() {\n        expect(DomApi.getEl($domEl)[0]).to.eql(domEl)\n      });\n    });\n  });\n\n  describe('#findEl', function() {\n    let domEl;\n    let findEl;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"foo\"><div id=\"bar\"></div></div>');\n      domEl = $('#foo')[0];\n      findEl = $('#bar')[0];\n    });\n\n    it('should return an array-like object', function() {\n      expect(DomApi.findEl(domEl, '#bar')).to.be.arrayLike;\n    });\n\n    it('should return the DOM element', function() {\n      expect(DomApi.findEl(domEl, '#bar')[0]).to.eql(findEl)\n    });\n  });\n\n  describe('#hasEl', function() {\n    let domEl;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"foo\"><div id=\"bar\"></div></div>');\n      domEl = $('#foo')[0];\n    });\n\n    describe('when the node is within the el', function() {\n      it('should return true', function() {\n        expect(DomApi.hasEl(domEl, $('#bar')[0])).to.be.true;\n      });\n    });\n\n    describe('when the node is not within the el', function() {\n      it('should return false', function() {\n        expect(DomApi.hasEl(domEl, $('<div>')[0])).to.be.false;\n      });\n    });\n  });\n\n  describe('#detachEl', function() {\n    let $domEl;\n    let domEl;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"foo\"></div>');\n      $domEl = $('#foo');\n      domEl = $domEl[0];\n    });\n\n    it('should detach the el from the DOM', function() {\n      DomApi.detachEl(domEl);\n      expect($(document).has(domEl)).to.have.lengthOf(0);\n    });\n\n    it('should not remove listeners', function() {\n      const onClickStub = this.sinon.stub();\n      $domEl.on('click', onClickStub);\n      DomApi.detachEl(domEl);\n      $domEl.trigger('click');\n\n      expect(onClickStub).to.be.calledOnce;\n    });\n  });\n\n  describe('#replaceEl', function() {\n    let newEl;\n    let oldEl;\n    let parentEl;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"foo\"><div id=\"bar\">old</div></div>');\n      parentEl = $('#foo')[0];\n    });\n\n    describe('when newEl and oldEl are the same', function() {\n      it('should not change anything', function() {\n        newEl = oldEl = $('#bar')[0];\n        DomApi.replaceEl(newEl, oldEl);\n        expect(parentEl.innerHTML).to.have.string('old');\n      });\n    });\n\n    describe('when oldEl is not attached', function() {\n      it('should not error', function() {\n        const $oldEl = $('#bar');\n        oldEl = $oldEl[0];\n        $oldEl.detach();\n        newEl = $('<div>new</div>')[0];\n        expect(_.partial(DomApi.replaceEl, newEl, oldEl)).to.not.throw();\n      });\n    });\n\n    describe('when oldEl is attached', function() {\n      it('should replace the contents', function() {\n        oldEl = $('#bar')[0];\n        newEl = $('<div>new</div>')[0];\n        DomApi.replaceEl(newEl, oldEl);\n        expect(parentEl.innerHTML).to.have.string('new');\n      });\n    });\n  });\n\n  describe('#swapEl', function() {\n    let el1;\n    let el2;\n    let parentEl;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"foo\"><div id=\"bar\">1</div><div id=\"baz\">2</div></div>');\n      parentEl = $('#foo')[0];\n    });\n\n    describe('when el1 and el2 are the same', function() {\n      it('should not change anything', function() {\n        el1 = el2 = $('#bar')[0];\n        DomApi.swapEl(el1, el2);\n        expect(parentEl.textContent).to.have.string('12');\n      });\n    });\n\n    describe('when el1 is not attached', function() {\n      it('should not error', function() {\n        const $el1 = $('#bar');\n        el1 = $el1[0];\n        $el1.detach();\n        el2 = $('#baz')[0];\n        expect(_.partial(DomApi.swapEl, el1, el2)).to.not.throw();\n      });\n    });\n\n    describe('when el2 is not attached', function() {\n      it('should not error', function() {\n        const $el2 = $('#baz');\n        el2 = $el2[0];\n        $el2.detach();\n        el1 = $('#bar')[0];\n        expect(_.partial(DomApi.swapEl, el1, el2)).to.not.throw();\n      });\n    });\n\n    describe('when both els are attached', function() {\n      it('should swap the contents', function() {\n        el1 = $('#bar')[0];\n        el2 = $('#baz')[0];\n        DomApi.swapEl(el1, el2);\n        expect(parentEl.textContent).to.have.string('21');\n      });\n    });\n  });\n\n  describe('#setContents', function() {\n    let domEl;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"foo\">Existing Html</div>');\n      domEl = $('#foo')[0];\n      DomApi.setContents(domEl, 'New Html');\n    });\n\n    it('should add the contents', function() {\n      expect(domEl.innerHTML).to.have.string('New Html');\n    });\n\n    it('should remove existing contents', function() {\n      expect(domEl.innerHTML).to.not.have.string('Existing Html');\n    });\n  });\n\n  describe('#appendContents', function() {\n    let domEl;\n    let appending;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"foo\">Existing Html</div>');\n      domEl = $('#foo')[0];\n      appending = $('<div>Appended</div>')[0];\n    });\n\n    it('should append the contents to the end of the contents of the el', function() {\n      DomApi.appendContents(domEl, appending);\n      expect(domEl.innerHTML).to.have.string('Existing Html<div>Appended</div>');\n    });\n  });\n\n  describe('#hasContents', function() {\n    it('should return true when el has contents', function() {\n      this.setFixtures('<div id=\"foo\">Existing Html</div>');\n      const domEl = $('#foo')[0];\n      expect(DomApi.hasContents(domEl)).to.be.true;\n    });\n\n    it('should return false when el has no contents', function() {\n      this.setFixtures('<div id=\"foo\"></div>');\n      const domEl = $('#foo')[0];\n      expect(DomApi.hasContents(domEl)).to.be.false;\n    });\n\n    it('should return false when el is undefined or null', function() {\n      expect(DomApi.hasContents(undefined)).to.be.false;\n      expect(DomApi.hasContents(null)).to.be.false;\n    });\n  });\n\n  describe('#detachContents', function() {\n    let domEl;\n    let $detachEl;\n    let detachEl;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"foo\"><div id=\"bar\"></div></div>');\n      domEl = $('#foo')[0];\n      $detachEl = $('#bar');\n      detachEl = $detachEl[0];\n    });\n\n    it('should detach the contents of the el from the DOM', function() {\n      DomApi.detachContents(domEl);\n      expect($(document).has(detachEl)).to.have.lengthOf(0);\n    });\n\n    it('should not detach the el from the DOM', function() {\n      DomApi.detachContents(domEl);\n      expect($(document).has(domEl)).to.have.lengthOf(1);\n    });\n\n    it('should not remove listeners', function() {\n      const onClickStub = this.sinon.stub();\n      $detachEl.on('click', onClickStub);\n      DomApi.detachContents(domEl);\n      $detachEl.trigger('click');\n\n      expect(onClickStub).to.be.calledOnce;\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/config/features.spec.js",
    "content": "import { setEnabled, isEnabled } from '../../../src/config/features';\n\ndescribe('features', function() {\n  it('enabled when its present and true', function() {\n    setEnabled('foo', true);\n    expect(isEnabled('foo')).to.be.true;\n  });\n\n  it('disabled when its present and false', function() {\n    setEnabled('foo', false);\n    expect(isEnabled('foo')).to.be.false;\n  });\n\n  it('disabled when not present', function() {\n    expect(isEnabled('foo')).to.be.false;\n  });\n});\n"
  },
  {
    "path": "test/unit/config/renderer.spec.js",
    "content": "import { setRenderer } from '../../../src/config/renderer';\n\ndescribe('#setRenderer', function() {\n  let MyObject;\n\n  beforeEach(function() {\n    MyObject = function() {};\n    MyObject.setRenderer = setRenderer;\n  });\n\n  it('should return the current class', function() {\n    expect(MyObject.setRenderer()).to.be.eq(MyObject);\n  });\n\n  it('should set _renderHtml on the class', function() {\n    const renderer = function() {};\n    MyObject.setRenderer(renderer);\n    expect(MyObject.prototype._renderHtml).to.equal(renderer);\n  });\n});\n"
  },
  {
    "path": "test/unit/destroying-views.spec.js",
    "content": "import View from '../../src/view';\n\n\ndescribe('destroying views', function() {\n  'use strict';\n\n  describe('when destroying a Marionette.View multiple times', function() {\n    let onDestroyStub;\n    let view;\n\n    beforeEach(function() {\n      onDestroyStub = this.sinon.spy(function() {\n        return this.isRendered();\n      });\n\n      view = new View();\n      view.onDestroy = onDestroyStub;\n\n      view.destroy();\n      view.destroy();\n    });\n\n    it('should only run the destroying code once', function() {\n      expect(onDestroyStub).to.have.been.calledOnce;\n    });\n\n    it('should mark the view as destroyed', function() {\n      expect(view).to.have.property('_isDestroyed', true);\n    });\n  });\n\n  describe('when destroying a Marionette.View multiple times', function() {\n    let onBeforeDestroyStub;\n    let itemView;\n\n    beforeEach(function() {\n      onBeforeDestroyStub = this.sinon.stub();\n\n      itemView = new View();\n      itemView.onBeforeDestroy = onBeforeDestroyStub;\n\n      itemView.destroy();\n      itemView.destroy();\n    });\n\n    it('should only run the destroying code once', function() {\n      expect(onBeforeDestroyStub).to.have.been.calledOnce;\n    });\n\n    it('should mark the view as destroyed', function() {\n      expect(itemView).to.have.property('_isDestroyed', true);\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/get-immediate-children.spec.js",
    "content": "import View from '../../src/view';\n\ndescribe('_getImmediateChildren', function() {\n  let BaseView;\n\n  beforeEach(function() {\n    // A suitable view to use as a child\n    BaseView = View.extend({\n      template: _.noop\n    });\n  });\n\n  describe('Marionette.View', function() {\n    let view;\n\n    beforeEach(function() {\n      view = new View();\n    });\n    it('should return an empty array for getImmediateChildren', function() {\n      expect(view._getImmediateChildren())\n        .to.be.instanceof(Array)\n        .and.to.have.length(0);\n    });\n\n    describe('without regions', function() {\n      let layoutView;\n\n      beforeEach(function() {\n        layoutView = new View({\n          template: _.noop\n        });\n      });\n      it('should return an empty array for getImmediateChildren', function() {\n        expect(layoutView._getImmediateChildren())\n          .to.be.instanceof(Array)\n          .and.to.have.length(0);\n      });\n    });\n\n    describe('when there are empty regions', function() {\n      let layoutView;\n\n      beforeEach(function() {\n        layoutView = new View({\n          template: _.template('<main></main><footer></footer>'),\n          regions: {\n            main: '.main',\n            footer: '.footer'\n          }\n        });\n        layoutView.render();\n      });\n      it('should return an empty array for getImmediateChildren', function() {\n        expect(layoutView._getImmediateChildren())\n          .to.be.instanceof(Array)\n          .and.to.have.length(0);\n      });\n    });\n\n    describe('when there are non-empty regions', function() {\n      let layoutView;\n      let childOne;\n      let childTwo;\n\n      beforeEach(function() {\n        layoutView = new View({\n          template: _.template('<main></main><footer></footer>'),\n          regions: {\n            main: 'main',\n            footer: 'footer'\n          }\n        });\n        layoutView.render();\n        childOne = new BaseView();\n        childTwo = new BaseView();\n        layoutView.getRegion('main').show(childOne);\n        layoutView.getRegion('footer').show(childTwo);\n      });\n      it('should return an empty array for getImmediateChildren', function() {\n        expect(layoutView._getImmediateChildren())\n          .to.be.instanceof(Array)\n          .and.to.have.length(2)\n          .and.to.contain(childOne)\n          .and.to.contain(childTwo);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/mixins/behaviors.spec.js",
    "content": "'use strict';\n\nimport _ from 'underscore';\nimport Backbone from 'backbone';\nimport BehaviorsMixin from '../../../src/mixins/behaviors';\nimport Behavior from '../../../src/behavior';\n\ndescribe('Behaviors Mixin', function() {\n  let Behaviors;\n\n  beforeEach(function() {\n    Behaviors = Backbone.View.extend();\n    _.extend(Behaviors.prototype, BehaviorsMixin);\n  });\n\n  describe('#_initBehaviors', function() {\n    let behaviorsInstance;\n    let fooInitializeStub;\n    let FooBehavior;\n\n    beforeEach(function() {\n      fooInitializeStub = this.sinon.stub();\n      behaviorsInstance = new Behaviors();\n      FooBehavior = Behavior.extend({initialize: fooInitializeStub});\n    });\n\n    describe('with no behaviors', function() {\n      it('should not have behaviors', function() {\n        behaviorsInstance._initBehaviors();\n\n        expect(behaviorsInstance._behaviors).to.be.deep.equal([]);\n      });\n    });\n\n    describe('with behaviorClass option', function() {\n      beforeEach(function() {\n        behaviorsInstance.behaviors = [\n          {\n            behaviorClass: FooBehavior\n          }\n        ];\n        behaviorsInstance._initBehaviors();\n      });\n\n      it('should call initialize when a behavior is created', function() {\n        expect(fooInitializeStub).to.be.calledOnce;\n      });\n\n      it('should have behaviors', function() {\n        expect(behaviorsInstance._behaviors).to.have.lengthOf(1);\n      });\n    });\n\n    describe('without behaviorClass option', function() {\n      beforeEach(function() {\n        behaviorsInstance.behaviors = [FooBehavior];\n        behaviorsInstance._initBehaviors();\n      });\n\n      it('should call initialize when a behavior is created', function() {\n        expect(fooInitializeStub).to.be.calledOnce;\n      });\n\n      it('should have behaviors', function() {\n        expect(behaviorsInstance._behaviors).to.have.lengthOf(1);\n      });\n    });\n\n    describe('with nested behaviors', function() {\n      let barInitializeStub;\n      let bazInitializeStub;\n\n      beforeEach(function() {\n        barInitializeStub = this.sinon.stub();\n        bazInitializeStub = this.sinon.stub();\n\n        let BarBehavior = Behavior.extend({\n          initialize: barInitializeStub,\n        });\n\n        FooBehavior = Behavior.extend({\n          initialize: fooInitializeStub,\n          behaviors: [BarBehavior]\n        });\n\n        behaviorsInstance.behaviors = [FooBehavior];\n\n        behaviorsInstance._initBehaviors();\n      });\n\n      it('should call initialize when a behavior is created', function() {\n        expect(fooInitializeStub).to.be.calledOnce;\n        expect(bazInitializeStub).not.to.have.been.called;\n      });\n\n      it('should call initialize when a nested behavior is created', function() {\n        expect(barInitializeStub).to.be.calledOnce;\n      });\n\n      it('should have behaviors', function() {\n        expect(behaviorsInstance._behaviors).to.have.lengthOf(2);\n      });\n    });\n\n    describe('with nested behaviors and without behaviorsLookup', function() {\n      let barInitializeStub;\n\n      beforeEach(function() {\n        barInitializeStub = this.sinon.stub();\n\n        let BarBehavior = Behavior.extend({\n          initialize: barInitializeStub,\n        });\n\n        FooBehavior = Behavior.extend({\n          initialize: fooInitializeStub,\n          behaviors: [BarBehavior]\n        });\n\n        behaviorsInstance.behaviors = {foo: FooBehavior};\n        behaviorsInstance._initBehaviors();\n      });\n\n      it('should call initialize when a behavior is created', function() {\n        expect(fooInitializeStub).to.be.calledOnce;\n      });\n\n      it('should call initialize when a nested behavior is created', function() {\n        expect(barInitializeStub).to.be.calledOnce;\n      });\n\n      it('should have behaviors', function() {\n        expect(behaviorsInstance._behaviors).to.have.lengthOf(2);\n      });\n    });\n\n    describe('with invalid option', function() {\n      beforeEach(function() {\n        behaviorsInstance.behaviors = [{foo: 'bar'}];\n      });\n\n      it('should throw an error', function() {\n        expect(function() {\n          behaviorsInstance._initBehaviors()\n        }).to.throw('Unable to get behavior class. A Behavior constructor should be passed directly or as behaviorClass property of options');\n      });\n    })\n  });\n\n  describe('#_getBehaviorTriggers', function() {\n    let behaviorsInstance;\n    let FooBehavior;\n    let BarBehavior;\n    let triggers;\n\n    beforeEach(function() {\n      behaviorsInstance = new Behaviors();\n      triggers = {\n        'click @ui.foo': 'bar'\n      };\n      FooBehavior = Behavior.extend({});\n\n      this.sinon.stub(FooBehavior.prototype, '_getTriggers').callsFake(function() {\n        if (this.triggers) {\n          return this.triggers;\n        } else {\n          return;\n        }\n      });\n\n      BarBehavior = FooBehavior.extend({\n        triggers: triggers\n      });\n    });\n\n    describe('when triggers are set', function() {\n\n      beforeEach(function() {\n        behaviorsInstance.behaviors = {bar: BarBehavior};\n        behaviorsInstance._initBehaviors();\n      });\n\n      it('should return behavior triggers', function() {\n        const result = behaviorsInstance._getBehaviorTriggers();\n\n        expect(result).to.have.been.deep.equal(triggers);\n      });\n    });\n\n    describe('when triggers are not set', function() {\n\n      beforeEach(function() {\n        behaviorsInstance.behaviors = {foo: FooBehavior};\n        behaviorsInstance._initBehaviors();\n      });\n\n      it('should return empty object', function() {\n        const result = behaviorsInstance._getBehaviorTriggers();\n\n        expect(result).to.have.been.deep.equal({});\n      });\n    });\n  });\n\n  describe('#_getBehaviorEvents', function() {\n    let behaviorsInstance;\n    let FooBehavior;\n    let BarBehavior;\n    let events;\n\n    beforeEach(function() {\n      behaviorsInstance = new Behaviors();\n      events = {\n        'click @ui.foo': 'bar'\n      };\n      FooBehavior = Behavior.extend({});\n\n      this.sinon.stub(FooBehavior.prototype, '_getEvents').callsFake(function() {\n        if (this.events) {\n          return this.events;\n        } else {\n          return;\n        }\n      });\n\n      BarBehavior = FooBehavior.extend({\n        events: events\n      });\n    });\n\n    describe('when events are set', function() {\n\n      beforeEach(function() {\n        behaviorsInstance.behaviors = {bar: BarBehavior};\n        behaviorsInstance._initBehaviors();\n      });\n\n      it('should return behavior events', function() {\n        const result = behaviorsInstance._getBehaviorEvents();\n\n        expect(result).to.have.been.deep.equal(events);\n      });\n    });\n\n    describe('when events are not set', function() {\n\n      beforeEach(function() {\n        behaviorsInstance.behaviors = {foo: FooBehavior};\n        behaviorsInstance._initBehaviors();\n      });\n\n      it('should return empty object', function() {\n        const result = behaviorsInstance._getBehaviorEvents();\n\n        expect(result).to.have.been.deep.equal({});\n      });\n    });\n  });\n\n  describe('#_proxyBehaviorViewProperties', function() {\n    let behaviorsInstance;\n    let FooBehavior;\n    let BarBehavior;\n\n    beforeEach(function() {\n      behaviorsInstance = new Behaviors();\n      FooBehavior = Behavior.extend({});\n      BarBehavior = Behavior.extend({});\n\n      this.sinon.spy(FooBehavior.prototype, 'proxyViewProperties');\n      this.sinon.spy(BarBehavior.prototype, 'proxyViewProperties');\n\n      behaviorsInstance.behaviors = {foo: FooBehavior, bar: BarBehavior};\n      behaviorsInstance._initBehaviors();\n    });\n\n    it('should invoke proxyViewProperties', function() {\n      behaviorsInstance._proxyBehaviorViewProperties();\n\n      expect(FooBehavior.prototype.proxyViewProperties).to.have.been.calledOnce;\n      expect(BarBehavior.prototype.proxyViewProperties).to.have.been.calledOnce;\n    });\n  });\n\n  describe('#_delegateBehaviorEntityEvents', function() {\n    let behaviorsInstance;\n    let FooBehavior;\n    let BarBehavior;\n\n    beforeEach(function() {\n      behaviorsInstance = new Behaviors();\n      FooBehavior = Behavior.extend({});\n      BarBehavior = Behavior.extend({});\n\n      this.sinon.spy(FooBehavior.prototype, 'delegateEntityEvents');\n      this.sinon.spy(BarBehavior.prototype, 'delegateEntityEvents');\n\n      behaviorsInstance.behaviors = {foo: FooBehavior, bar: BarBehavior};\n      behaviorsInstance._initBehaviors();\n    });\n\n    it('should invoke delegateEntityEvents', function() {\n      behaviorsInstance._delegateBehaviorEntityEvents();\n\n      expect(FooBehavior.prototype.delegateEntityEvents).to.have.been.calledOnce;\n      expect(BarBehavior.prototype.delegateEntityEvents).to.have.been.calledOnce;\n    });\n  });\n\n  describe('#_undelegateBehaviorEntityEvents', function() {\n    let behaviorsInstance;\n    let FooBehavior;\n    let BarBehavior;\n\n    beforeEach(function() {\n      behaviorsInstance = new Behaviors();\n      FooBehavior = Behavior.extend({});\n      BarBehavior = Behavior.extend({});\n\n      this.sinon.spy(FooBehavior.prototype, 'undelegateEntityEvents');\n      this.sinon.spy(BarBehavior.prototype, 'undelegateEntityEvents');\n\n      behaviorsInstance.behaviors = {foo: FooBehavior, bar: BarBehavior};\n      behaviorsInstance._initBehaviors();\n    });\n\n    it('should invoke undelegateEntityEvents', function() {\n      behaviorsInstance._undelegateBehaviorEntityEvents();\n\n      expect(FooBehavior.prototype.undelegateEntityEvents).to.have.been.calledOnce;\n      expect(BarBehavior.prototype.undelegateEntityEvents).to.have.been.calledOnce;\n    });\n  });\n\n  describe('#_destroyBehaviors', function() {\n    let behaviorsInstance;\n    let FooBehavior;\n    let BarBehavior;\n\n    beforeEach(function() {\n      behaviorsInstance = new Behaviors();\n      FooBehavior = Behavior.extend({});\n      BarBehavior = Behavior.extend({});\n\n      this.sinon.stub(FooBehavior.prototype, 'destroy');\n      this.sinon.stub(BarBehavior.prototype, 'destroy');\n\n      behaviorsInstance.behaviors = {foo: FooBehavior, bar: BarBehavior};\n      behaviorsInstance._initBehaviors();\n    });\n\n    it('should invoke destroy with options argument', function() {\n      behaviorsInstance._destroyBehaviors({foo: 'bar'});\n\n      expect(FooBehavior.prototype.destroy)\n        .to.have.been.calledOnce.and.calledWith({foo: 'bar'});\n      expect(BarBehavior.prototype.destroy)\n        .to.have.been.calledOnce.and.calledWith({foo: 'bar'});\n    });\n\n    it('should invoke destroy without arguments', function() {\n      behaviorsInstance._destroyBehaviors();\n\n      expect(FooBehavior.prototype.destroy).to.have.been.calledOnce;\n      expect(BarBehavior.prototype.destroy).to.have.been.calledOnce;\n    });\n  });\n\n  describe('#_removeBehavior', function() {\n    let behaviorsInstance;\n    let FooBehavior;\n    let BarBehavior;\n\n    beforeEach(function() {\n      behaviorsInstance = new Behaviors();\n      FooBehavior = Behavior.extend({});\n      BarBehavior = Behavior.extend({});\n\n      behaviorsInstance.behaviors = {foo: FooBehavior, bar: BarBehavior};\n      behaviorsInstance._initBehaviors();\n    });\n\n    it('should remove the behavior from the view\\'s behaviors', function() {\n      const behaviorInstance = behaviorsInstance._behaviors[0];\n\n      behaviorsInstance._removeBehavior(behaviorInstance);\n\n      expect(behaviorsInstance._behaviors).to.have.lengthOf(1).and.not.to.include(behaviorInstance);\n    });\n\n    describe('when the view is destroyed', function() {\n      it('should not remove the behavior', function() {\n        // behaviorsInstance is not an actual view so simulate destroy\n        behaviorsInstance._isDestroyed = true;\n\n        const behaviorInstance = behaviorsInstance._behaviors[0];\n\n        behaviorsInstance._removeBehavior(behaviorInstance);\n\n        expect(behaviorsInstance._behaviors).to.have.lengthOf(2).to.include(behaviorInstance);\n      });\n    });\n  });\n\n  describe('#_bindBehaviorUIElements', function() {\n    let behaviorsInstance;\n    let FooBehavior;\n    let BarBehavior;\n\n    beforeEach(function() {\n      behaviorsInstance = new Behaviors();\n      FooBehavior = Behavior.extend({});\n      BarBehavior = Behavior.extend({});\n\n      this.sinon.spy(FooBehavior.prototype, 'bindUIElements');\n      this.sinon.spy(BarBehavior.prototype, 'bindUIElements');\n\n      behaviorsInstance.behaviors = {foo: FooBehavior, bar: BarBehavior};\n      behaviorsInstance._initBehaviors();\n    });\n\n    it('should invoke bindUIElements', function() {\n      behaviorsInstance._bindBehaviorUIElements();\n\n      expect(FooBehavior.prototype.bindUIElements).to.have.been.calledOnce;\n      expect(BarBehavior.prototype.bindUIElements).to.have.been.calledOnce;\n    });\n  });\n\n  describe('#_unbindBehaviorUIElements', function() {\n    let behaviorsInstance;\n    let FooBehavior;\n    let BarBehavior;\n\n    beforeEach(function() {\n      behaviorsInstance = new Behaviors();\n      FooBehavior = Behavior.extend({});\n      BarBehavior = Behavior.extend({});\n\n      this.sinon.spy(FooBehavior.prototype, 'unbindUIElements');\n      this.sinon.spy(BarBehavior.prototype, 'unbindUIElements');\n\n      behaviorsInstance.behaviors = {foo: FooBehavior, bar: BarBehavior};\n      behaviorsInstance._initBehaviors();\n    });\n\n    it('should invoke unbindUIElements', function() {\n      behaviorsInstance._unbindBehaviorUIElements();\n\n      expect(FooBehavior.prototype.unbindUIElements).to.have.been.calledOnce;\n      expect(BarBehavior.prototype.unbindUIElements).to.have.been.calledOnce;\n    });\n  });\n\n  describe('#_triggerEventOnBehaviors', function() {\n    let behaviorsInstance;\n    let FooBehavior;\n    let BarBehavior;\n\n    beforeEach(function() {\n      behaviorsInstance = new Behaviors();\n      FooBehavior = Behavior.extend({\n        onFoo: this.sinon.stub()\n      });\n      BarBehavior = Behavior.extend({\n        onFoo: this.sinon.stub()\n      });\n\n      behaviorsInstance.behaviors = {foo: FooBehavior, bar: BarBehavior};\n      behaviorsInstance._initBehaviors();\n    });\n\n    it('should invoke events', function() {\n      behaviorsInstance._triggerEventOnBehaviors('foo', 'view', 'options');\n\n      expect(FooBehavior.prototype.onFoo)\n        .to.have.been.calledOnce\n        .and.calledWith('view', 'options');\n      expect(BarBehavior.prototype.onFoo)\n        .to.have.been.calledOnce\n        .and.calledWith('view', 'options');\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/mixins/common.spec.js",
    "content": "import _ from 'underscore';\nimport CommonMixin from '../../../src/mixins/common';\n\ndescribe('Common Mixin', function() {\n  describe('#setOptions', function() {\n    let object;\n    const classOptions = [];\n    const options = {\n      foo: 'baz',\n      baz: 'baz'\n    };\n\n    beforeEach(function() {\n      object = _.extend({\n        options() {\n          return {\n            foo: 'bar',\n            bar: 'baz'\n          };\n        }\n      }, CommonMixin);\n\n      this.sinon.spy(object, 'mergeOptions');\n\n      object._setOptions(options, classOptions);\n    });\n\n    it('should not mutate the options argument', function() {\n      expect(options).to.eql({\n        foo: 'baz',\n        baz: 'baz'\n      })\n    });\n\n    // This test covers merge order and options as a function\n    it('should set options on the context', function() {\n      expect(object.options).to.eql({\n        foo: 'baz',\n        bar: 'baz',\n        baz: 'baz'\n      });\n    });\n\n    it('should call mergeOptions', function() {\n      expect(object.mergeOptions)\n        .to.have.been.calledOnce\n        .and.calledWith(options, classOptions);\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/mixins/delegate-entity-events.spec.js",
    "content": "import _ from 'underscore';\nimport Backbone from 'backbone';\nimport DelegateEntityEventsMixin from '../../../src/mixins/delegate-entity-events';\n\ndescribe('delegate entity events mixin', function() {\n  let obj;\n  let model;\n  let collection;\n\n  beforeEach(function() {\n    obj = _.extend({\n      bindEvents: this.sinon.stub(),\n      unbindEvents: this.sinon.stub(),\n    }, DelegateEntityEventsMixin);\n\n    model = new Backbone.Model();\n    collection = new Backbone.Collection();\n  });\n\n  describe('#_delegateEntityEvents', function() {\n    describe('when passed a model', function() {\n      describe('when modelEvents is an object', function() {\n        beforeEach(function() {\n          obj.modelEvents = { foo: 'onFoo' };\n          obj._delegateEntityEvents(model);\n        });\n\n        it('should cache modelEvents', function() {\n          expect(obj._modelEvents).to.equal(obj.modelEvents);\n        });\n\n        it('should call bindEvents', function() {\n          expect(obj.bindEvents)\n            .to.have.been.calledOnce\n            .to.have.been.calledWith(model, obj.modelEvents);\n        });\n      });\n\n      describe('when modelEvents is a method', function() {\n        const modelEvents = { foo: 'onFoo' };\n\n        beforeEach(function() {\n          obj.modelEvents = this.sinon.stub().returns(modelEvents);\n          obj._delegateEntityEvents(model);\n        });\n\n        it('should cache modelEvents', function() {\n          expect(obj._modelEvents).to.equal(modelEvents);\n        });\n\n        it('should call bindEvents', function() {\n          expect(obj.bindEvents)\n            .to.have.been.calledOnce\n            .to.have.been.calledWith(model, modelEvents);\n        });\n      });\n    });\n\n    describe('when passed a collection', function() {\n      describe('when collectionEvents is an object', function() {\n        beforeEach(function() {\n          obj.collectionEvents = { foo: 'onFoo' };\n          obj._delegateEntityEvents(null, collection);\n        });\n\n        it('should cache collectionEvents', function() {\n          expect(obj._collectionEvents).to.equal(obj.collectionEvents);\n        });\n\n        it('should call bindEvents', function() {\n          expect(obj.bindEvents)\n            .to.have.been.calledOnce\n            .to.have.been.calledWith(collection, obj.collectionEvents);\n        });\n      });\n\n      describe('when collectionEvents is a method', function() {\n        const collectionEvents = { foo: 'onFoo' };\n\n        beforeEach(function() {\n          obj.collectionEvents = this.sinon.stub().returns(collectionEvents);\n          obj._delegateEntityEvents(null, collection);\n        });\n\n        it('should cache modelEvents', function() {\n          expect(obj._collectionEvents).to.equal(collectionEvents);\n        });\n\n        it('should call bindEvents', function() {\n          expect(obj.bindEvents)\n            .to.have.been.calledOnce\n            .to.have.been.calledWith(collection, collectionEvents);\n        });\n      });\n    });\n\n    describe('when entities are not passed', function() {\n      beforeEach(function() {\n        obj._delegateEntityEvents();\n      });\n\n      it('should not call bindEvents', function() {\n        expect(obj.bindEvents).to.not.have.been.called;\n      });\n\n      it('should not cache event handlers', function() {\n        expect(obj).to.not.have.property('_modelEvents');\n        expect(obj).to.not.have.property('_collectionEvents');\n      });\n    });\n  });\n\n  describe('#_undelegateEntityEvents', function() {\n    describe('when modelEvents have been cached', function() {\n      beforeEach(function() {\n        obj._modelEvents = 'foo';\n        obj._undelegateEntityEvents(model, collection);\n      });\n\n      it('should call unbindEvents', function() {\n        expect(obj.unbindEvents)\n          .to.have.been.calledOnce\n          .to.have.been.calledWith(model, 'foo');\n      });\n\n      it('should remove the cache', function() {\n        expect(obj).to.not.have.property('_modelEvents');\n      });\n    });\n\n    describe('when collectionEvents have been cached', function() {\n      beforeEach(function() {\n        obj._collectionEvents = 'foo';\n        obj._undelegateEntityEvents(model, collection);\n      });\n\n      it('should call unbindEvents', function() {\n        expect(obj.unbindEvents)\n          .to.have.been.calledOnce\n          .to.have.been.calledWith(collection, 'foo');\n      });\n\n      it('should remove the cache', function() {\n        expect(obj).to.not.have.property('_collectionEvents');\n      });\n    });\n\n    describe('when no events are cached', function() {\n      it('should not call unbindEvents', function() {\n        obj._undelegateEntityEvents(model, collection);\n        expect(obj.unbindEvents).to.not.have.been.called;\n      });\n    });\n  });\n\n  describe('_deleteEntityEventHandlers', function() {\n    it('should remove cached handlers', function() {\n      obj._modelEvents = 'foo';\n      obj._collectionEvents = 'bar';\n      obj._deleteEntityEventHandlers();\n\n      expect(obj).to.not.have.property('_modelEvents');\n      expect(obj).to.not.have.property('_collectionEvents');\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/mixins/destroy.spec.js",
    "content": "import _ from 'underscore';\nimport DestroyMixin from '../../../src/mixins/destroy';\n\ndescribe('Destroy Mixin', function() {\n  let obj;\n\n  beforeEach(function() {\n    obj = _.extend({\n      triggerMethod: this.sinon.stub(),\n      stopListening: this.sinon.stub()\n    }, DestroyMixin);\n\n    this.sinon.spy(obj, 'destroy');\n  });\n\n  it('should not be destroyed by default', function() {\n    expect(obj.isDestroyed()).to.be.false;\n  });\n\n  describe('when destroying', function() {\n    beforeEach(function() {\n      obj.destroy({ foo: 'bar' });\n    });\n\n    it('should be destroyed', function() {\n      expect(obj.isDestroyed()).to.be.true;\n    });\n\n    it('should trigger destroy events', function() {\n      expect(obj.triggerMethod)\n        .to.have.been.calledTwice\n        .and.calledWith('before:destroy', obj, { foo: 'bar' })\n        .and.calledWith('destroy', obj, { foo: 'bar' });\n    });\n\n    it('should stopListening', function() {\n      expect(obj.stopListening)\n        .to.have.been.calledOnce\n        .and.not.calledBefore(obj.triggerMethod);\n    });\n\n    it('should return the instance', function() {\n      expect(obj.destroy).to.have.returned(obj);\n    });\n  });\n\n  describe('when destroying a destroyed object', function() {\n    beforeEach(function() {\n      obj.destroy();\n      obj.triggerMethod.reset();\n      obj.destroy();\n    });\n\n    it('should not trigger any events', function() {\n      expect(obj.triggerMethod).to.not.have.been.called;\n    });\n\n    it('should return the instance', function() {\n      expect(obj.destroy).to.have.returned(obj);\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/mixins/radio.spec.js",
    "content": "import _ from 'underscore';\nimport Backbone from 'backbone';\nimport Radio from 'backbone.radio';\nimport RadioMixin from '../../../src/mixins/radio';\n\ndescribe('Radio Mixin on Marionette.Object', function() {\n  let radioObject;\n  let channelFoo;\n\n  beforeEach(function() {\n    radioObject = _.extend({\n      // Simulate implementation\n      initialize() {\n        this._initRadio();\n      },\n      bindEvents: this.sinon.stub(),\n      bindRequests: this.sinon.stub(),\n    }, Backbone.Events, RadioMixin);\n\n    channelFoo = Radio.channel('foo');\n  });\n\n  describe('when a channelName is not defined', function() {\n    beforeEach(function() {\n      radioObject.initialize();\n    });\n\n    it('should not have a Radio channel', function() {\n      expect(radioObject.getChannel()).to.be.undefined;\n    });\n\n    it('should not bind radioEvents', function() {\n      expect(radioObject.bindEvents).to.not.have.been.called;\n    });\n\n    it('should not bind radioRequests', function() {\n      expect(radioObject.bindRequests).to.not.have.been.called;\n    });\n  });\n\n  describe('when a channelName is defined', function() {\n    describe('on the object', function() {\n      it('should have the named Radio channel', function() {\n        radioObject.channelName = 'foo';\n        radioObject.initialize();\n\n        expect(radioObject.getChannel()).to.eql(channelFoo);\n      });\n    });\n\n    describe('as a function', function() {\n      it('should have the named Radio channel', function() {\n        radioObject.channelName = this.sinon.stub().returns('foo');\n        radioObject.initialize();\n\n        expect(radioObject.getChannel()).to.eql(channelFoo);\n      });\n    });\n  });\n\n  describe('when a radioEvents is defined', function() {\n    beforeEach(function() {\n      radioObject.channelName = 'foo';\n    });\n\n    describe('on the object', function() {\n      it('should bind events to the channel', function() {\n        radioObject.radioEvents = {'bar': 'onBar'};\n        radioObject.initialize();\n\n        expect(radioObject.bindEvents).to.have.been.calledOnce\n          .and.to.have.been.calledWith(channelFoo, {'bar': 'onBar'});\n      });\n    });\n\n    describe('as a function', function() {\n      it('should bind events to the channel', function() {\n        radioObject.radioEvents = this.sinon.stub().returns({'bar': 'onBar'});\n        radioObject.initialize();\n\n        expect(radioObject.bindEvents).to.have.been.calledOnce\n          .and.to.have.been.calledWith(channelFoo, {'bar': 'onBar'});\n      });\n    });\n  });\n\n  describe('when a radioRequests is defined', function() {\n    beforeEach(function() {\n      radioObject.channelName = 'foo';\n    });\n\n    describe('on the object', function() {\n      it('should bind requests to the channel', function() {\n        radioObject.radioRequests = {'baz': 'getBaz'};\n        radioObject.initialize();\n\n        expect(radioObject.bindRequests).to.have.been.calledOnce\n          .and.to.have.been.calledWith(channelFoo, {'baz': 'getBaz'});\n      });\n    });\n\n    describe('as a function', function() {\n      it('should bind requests to the channel', function() {\n        radioObject.radioRequests = this.sinon.stub().returns({'baz': 'getBaz'});\n        radioObject.initialize();\n\n        expect(radioObject.bindRequests).to.have.been.calledOnce\n          .and.to.have.been.calledWith(channelFoo, {'baz': 'getBaz'});\n      });\n    });\n  });\n\n  describe('when an Object is destroyed', function() {\n    let fooChannel;\n\n    beforeEach(function() {\n      radioObject.channelName = 'foo'\n      radioObject.initialize();\n\n      fooChannel = radioObject.getChannel();\n\n      this.sinon.spy(fooChannel, 'stopReplying');\n\n      radioObject.trigger('destroy');\n    });\n\n    it('should stopReplying to the object', function() {\n      expect(fooChannel.stopReplying).to.have.been.calledOnce\n        .and.to.have.been.calledWith(null, null, radioObject);\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/mixins/template-render.spec.js",
    "content": "import _ from 'underscore';\nimport Backbone from 'backbone';\n\nimport TemplateRenderMixin from '../../../src/mixins/template-render';\n\ndescribe('template-render', function() {\n  let renderer;\n\n  beforeEach(function() {\n    renderer = _.extend({\n      render() {\n        // Simple mixin implementation\n        this._renderTemplate(this.getTemplate());\n      },\n      Dom: {\n        setContents: this.sinon.stub()\n      }\n    }, TemplateRenderMixin);\n  });\n\n  describe('when rendering (#_renderTemplate)', function() {\n    const testData = { data: 'foo' };\n\n    beforeEach(function() {\n      renderer.template = this.sinon.stub();\n      renderer.serializeData = this.sinon.stub().returns(testData);\n      this.sinon.spy(renderer, 'mixinTemplateContext');\n      this.sinon.spy(renderer, 'attachElContent');\n    });\n\n    it('should serialize data', function() {\n      renderer.render();\n      expect(renderer.serializeData).to.have.been.calledOnce;\n    });\n\n    it('should mixin template context', function() {\n      renderer.render();\n      expect(renderer.mixinTemplateContext)\n        .to.have.been.calledOnce\n        .and.calledWith(testData);\n    });\n\n    // Tests default renderer #_renderHtml\n    it('should render data in a template', function() {\n      renderer.render();\n      expect(renderer.template)\n        .to.have.been.calledOnce\n        .and.calledWith(testData);\n    });\n\n    describe('when renderer returns html', function() {\n      it('should attach content', function() {\n        renderer._renderHtml = _.constant('html');\n        renderer.render();\n        expect(renderer.attachElContent)\n          .to.have.been.calledOnce\n          .and.calledWith('html');\n      });\n    });\n\n    // An empty template should still render\n    describe('when rendering returns an empty string', function() {\n      it('should attach content', function() {\n        renderer._renderHtml = _.constant('');\n        renderer.render();\n        expect(renderer.attachElContent)\n          .to.have.been.calledOnce\n          .and.calledWith('');\n      });\n    });\n\n    describe('when renderer does not return html', function() {\n      it('should attach content', function() {\n        renderer._renderHtml = _.noop;\n        renderer.render();\n        expect(renderer.attachElContent).to.not.have.been.called;\n      });\n    });\n  });\n\n  describe('default #getTemplate', function() {\n    it('should return this.template', function() {\n      renderer.template = 'foo';\n      expect(renderer.getTemplate()).to.equal('foo');\n    });\n  });\n\n  describe('when mixing template context', function() {\n\n    beforeEach(function() {\n      renderer.template = _.noop;\n      renderer._renderHtml = this.sinon.stub();\n      renderer.serializeData = this.sinon.stub().returns({ foo: 'data', bar: 'data' });\n    });\n\n    describe('when templateContext is a method', function() {\n      it('should mix the templateCotext results and data', function() {\n        renderer.templateContext = this.sinon.stub().returns({ baz: 'tc' });\n        renderer.render();\n        expect(renderer._renderHtml)\n          .to.be.calledOnce\n          .and.calledWith(renderer.template, { foo: 'data', bar: 'data', baz: 'tc' });\n      });\n    });\n\n    describe('when templateContext is not defined', function() {\n      it('should return the data', function() {\n        renderer.render();\n        expect(renderer._renderHtml)\n          .to.be.calledOnce\n          .and.calledWith(renderer.template, { foo: 'data', bar: 'data' });\n      });\n    });\n\n    describe('when no data is serialized', function() {\n      it('should return the templateContext', function() {\n        renderer.serializeData = this.sinon.stub();\n        renderer.templateContext = this.sinon.stub().returns({ baz: 'tc' });\n        renderer.render();\n        expect(renderer._renderHtml)\n          .to.be.calledOnce\n          .and.calledWith(renderer.template, { baz: 'tc' });\n      });\n    });\n\n    describe('when template context and data is defined', function() {\n      it('should mix the context with data giving context priority', function() {\n        renderer.templateContext = { bar: 'tc', baz: 'tc' };\n        renderer.render();\n        expect(renderer._renderHtml)\n          .to.be.calledOnce\n          .and.calledWith(renderer.template, { foo: 'data', bar: 'tc', baz: 'tc' });\n      });\n    });\n  });\n\n  describe('when serializing data', function() {\n    let model;\n    let collection;\n\n    beforeEach(function() {\n      model = new Backbone.Model({ foo: 'data' });\n      collection = new Backbone.Collection([{ id: 1 }, { id: 2 }]);\n      renderer.template = _.noop;\n      this.sinon.spy(renderer, 'serializeModel');\n      this.sinon.spy(renderer, 'serializeCollection');\n      this.sinon.spy(renderer, '_renderHtml');\n    });\n\n\n    describe('when object has no model or collection', function() {\n      beforeEach(function() {\n        renderer.render();\n      });\n\n      it('should not serialize the model', function() {\n        expect(renderer.serializeModel).to.not.be.called;\n      });\n\n      it('should not serialize the collection', function() {\n        expect(renderer.serializeCollection).to.not.be.called;\n      });\n\n      it('should send an empty object to the renderer', function() {\n        expect(renderer._renderHtml)\n          .to.be.calledOnce\n          .and.calledWith(renderer.template, {});\n      });\n    });\n\n    describe('when object has a model', function() {\n      beforeEach(function() {\n        renderer.model = model;\n        renderer.render();\n      });\n\n      it('should serialize the model', function() {\n        expect(renderer.serializeModel).to.be.calledOnce;\n      });\n\n      it('should not serialize the collection', function() {\n        expect(renderer.serializeCollection).to.not.be.called;\n      });\n\n      it('should send the model attributes to the renderer', function() {\n        expect(renderer._renderHtml)\n          .to.be.calledOnce\n          .and.calledWith(renderer.template, { foo: 'data' });\n      });\n    });\n\n    describe('when object has only a collection', function() {\n      beforeEach(function() {\n        renderer.collection = collection;\n        renderer.render();\n      });\n\n      it('should not serialize the model', function() {\n        expect(renderer.serializeModel).to.not.be.called;\n      });\n\n      it('should serialize the collection', function() {\n        expect(renderer.serializeCollection).to.be.calledOnce;\n      });\n\n      it('should send the collection data on items to the renderer', function() {\n        expect(renderer._renderHtml)\n          .to.be.calledOnce\n          .and.calledWith(renderer.template, { items: [{ id: 1 },{ id: 2 }] });\n      });\n    });\n\n    describe('when object has both model and collection', function() {\n      beforeEach(function() {\n        renderer.model = model;\n        renderer.collection = collection;\n        renderer.render();\n      });\n\n      it('should serialize the model', function() {\n        expect(renderer.serializeModel).to.be.calledOnce;\n      });\n\n      it('should not serialize the collection', function() {\n        expect(renderer.serializeCollection).to.not.be.called;\n      });\n    });\n  });\n\n  describe('when attaching content', function() {\n    it('should call the DOM Mixin', function() {\n      renderer.el = 'fooEl';\n      renderer.$el = '$fooEl';\n      renderer._renderHtml = _.constant('html');\n      renderer.render();\n\n      // 3rd argument is for internal use only\n      expect(renderer.Dom.setContents)\n        .to.have.been.calledOnce\n        .and.calledWith('fooEl', 'html', '$fooEl');\n    });\n  })\n});\n"
  },
  {
    "path": "test/unit/mixins/ui.spec.js",
    "content": "import View from '../../../src/view';\n\ndescribe('normalizeUIKeys', function() {\n  'use strict';\n\n  describe('When creating a generic View class without a ui hash, and creating two generic view sublcasses with a ui hash', function() {\n    let GenericView;\n    let genericViewSubclass1Instance;\n    let genericViewSubclass2Instance;\n\n    beforeEach(function() {\n      GenericView = View.extend({\n        events: {'change @ui.someUi': 'onSomeUiChange'},\n        onSomeUiChange: sinon.stub()\n      });\n      const GenericViewSubclass1 = GenericView.extend({\n        template: _.template('<div class=\"subclass-1-el\"><div class=\"subclass-1-ui\"></div></div>'),\n        ui: {someUi: '.subclass-1-ui'}\n      });\n      const GenericViewSubclass2 = GenericView.extend({\n        template: _.template('<div class=\"subclass-2-el\"><div class=\"subclass-2-ui\"></div></div>'),\n        ui: {someUi: '.subclass-2-ui'}\n      });\n      genericViewSubclass1Instance = new GenericViewSubclass1();\n      genericViewSubclass2Instance = new GenericViewSubclass2();\n      genericViewSubclass1Instance.render();\n      genericViewSubclass2Instance.render();\n    });\n\n    describe('the 1st generic view subclass instance', function() {\n      it('should have its registered event handler called when the ui DOM event is triggered', function() {\n        genericViewSubclass1Instance.ui.someUi.trigger('change');\n        expect(genericViewSubclass1Instance.onSomeUiChange).to.be.calledOnce;\n      });\n    });\n\n    describe('the 2nd generic view subclass instance', function() {\n      it('should have its registered event handler called when the ui DOM event is triggered', function() {\n        genericViewSubclass2Instance.ui.someUi.trigger('change');\n        expect(genericViewSubclass2Instance.onSomeUiChange).to.be.calledOnce;\n      });\n    });\n\n    it('the generic view class should have its prototype events hash untouched and in its original form', function() {\n      expect(GenericView.prototype.events).to.eql({'change @ui.someUi': 'onSomeUiChange'});\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/mixins/view.spec.js",
    "content": "import { setEnabled } from '../../../src/backbone.marionette';\nimport CollectionView from '../../../src/collection-view';\nimport View from '../../../src/view';\n\ndescribe('view mixin', function() {\n  'use strict';\n\n  describe('when creating a view', function() {\n    let initializeStub;\n    let view;\n\n    beforeEach(function() {\n      initializeStub = sinon.stub();\n\n      const MyView = View.extend({\n        initialize: initializeStub\n      });\n\n      view = new MyView();\n    });\n\n    it('should call initialize', function() {\n      expect(initializeStub).to.have.been.calledOnce;\n    });\n\n    it('should set _behaviors', function() {\n      expect(view._behaviors).to.be.eql([]);\n    });\n  });\n\n  describe('when using listenTo for the \"destroy\" event on itself, and destroying the view', function() {\n    let destroyStub;\n\n    beforeEach(function() {\n      destroyStub = sinon.stub();\n      const view = new View();\n      view.listenTo(view, 'destroy', destroyStub);\n      view.destroy();\n    });\n\n    it('should trigger the \"destroy\" event', function() {\n      expect(destroyStub).to.have.been.called;\n    });\n  });\n\n  describe('when destroying a view', function() {\n    let view;\n    let onDestroyStub;\n    let destroyStub;\n\n    beforeEach(function() {\n      view = new View();\n\n      sinon.spy(view, '_removeElement');\n      sinon.spy(view, '_deleteEntityEventHandlers');\n      sinon.spy(view, 'destroy');\n\n      onDestroyStub = sinon.stub();\n      view.onDestroy = onDestroyStub;\n\n      destroyStub = sinon.stub();\n      view.on('destroy', destroyStub);\n\n      view.destroy({foo: 'bar'});\n    });\n\n    it('should trigger the destroy event', function() {\n      expect(destroyStub).to.have.been.calledOnce;\n    });\n\n    it('should call an onDestroy method with options argument passed to destroy', function() {\n      expect(onDestroyStub)\n        .to.have.been.calledOnce\n        .and.calledWith(view, {foo: 'bar'});\n    });\n\n    it('should remove the view', function() {\n      expect(view._removeElement).to.have.been.calledOnce;\n    });\n\n    it('should delete entity event handlers', function() {\n      expect(view._deleteEntityEventHandlers).to.have.been.calledOnce;\n    });\n\n    it('should set the view _isDestroyed to true', function() {\n      expect(view).to.be.have.property('_isDestroyed', true);\n    });\n\n    it('should return the View', function() {\n      expect(view.destroy).to.have.returned(view);\n    });\n\n    describe('and it has already been destroyed', function() {\n      beforeEach(function() {\n        view.destroy();\n      });\n\n      it('should return the View', function() {\n        expect(view.destroy).to.have.returned(view);\n      });\n    });\n\n    describe('_isDestroyed property', function() {\n      beforeEach(function() {\n        view = new View();\n      });\n\n      it('should be set to false before destroy', function() {\n        expect(view).to.be.have.property('_isDestroyed', false);\n      });\n\n      it('should be set to true after destroying', function() {\n        view.destroy();\n        expect(view).to.be.have.property('_isDestroyed', true);\n      });\n    });\n  });\n\n  describe('when destroying a view with listeners for destroy', function() {\n    let view;\n    let destroyStub;\n    let beforeDestroyStub;\n    let onDestroyStub;\n    let onBeforeDestroyStub;\n\n    beforeEach(function() {\n\n      view = new View({\n        template: () => '<div data-foo-region></div>',\n        regions: {child: '[data-foo-region]'},\n        onRender() {\n          const childView = new View({ template: false });\n          this.listenTo(childView, 'destroy', this.destroy);\n          this.showChildView('child', childView);\n        }\n      });\n\n      destroyStub = sinon.stub();\n      view.on('destroy', destroyStub);\n\n      beforeDestroyStub = sinon.stub();\n      view.on('before:destroy', beforeDestroyStub);\n\n      onDestroyStub = sinon.stub();\n      view.onDestroy = onDestroyStub;\n\n      onBeforeDestroyStub = sinon.stub();\n      view.onBeforeDestroy = onBeforeDestroyStub;\n\n      view.render();\n      view.destroy();\n\n    });\n    it('should trigger the destroy event once', function() {\n      expect(destroyStub).to.have.been.calledOnce;\n      expect(onDestroyStub).to.have.been.calledOnce;\n    });\n    it('should trigger the before:destroy event once', function() {\n      expect(beforeDestroyStub).to.have.been.calledOnce;\n      expect(onBeforeDestroyStub).to.have.been.calledOnce;\n    });\n  });\n\n  describe('constructing a view with default options', function() {\n    let presets;\n    let options;\n    let MyView;\n    let ViewPresets;\n    let ViewPresetsFn;\n\n    beforeEach(function() {\n      presets = {foo: 'foo'};\n      options = {foo: 'bar'};\n\n      const presetsStub = sinon.stub().returns(presets);\n\n      MyView = View.extend();\n      ViewPresets = View.extend({options: presets});\n      ViewPresetsFn = View.extend({options: presetsStub});\n    });\n\n    it('should take and store view options', function() {\n      const view = new MyView(options);\n      expect(view.options).to.deep.equal(options);\n    });\n\n    it('should have an empty hash of options by default', function() {\n      const view = new MyView();\n      expect(view.options).to.deep.equal({});\n    });\n\n    it('should retain options set on view class', function() {\n      const view = new ViewPresets();\n      expect(view.options).to.deep.equal(presets);\n    });\n\n    it('should retain options set on view class as a function', function() {\n      const view = new ViewPresetsFn();\n      expect(view.options).to.deep.equal(presets);\n    });\n  });\n\n  // http://backbonejs.org/#View-constructor\n  describe('should expose its options in the constructor', function() {\n    let options;\n    let view;\n\n    beforeEach(function() {\n      options = {foo: 'bar'};\n      view = new View(options);\n    });\n\n    it('should be able to access instance options', function() {\n      expect(view.options).to.deep.equal(options);\n    });\n  });\n\n  describe('when destroying a view that is already destroyed', function() {\n    let view;\n    let removeSpy;\n    let destroyStub;\n\n    beforeEach(function() {\n      view = new View();\n\n      removeSpy = sinon.spy(view, '_removeElement');\n      destroyStub = sinon.stub();\n      view.on('destroy', destroyStub);\n\n      view.destroy();\n      view.destroy();\n    });\n\n    it('should not trigger the destroy event', function() {\n      expect(destroyStub).to.have.been.calledOnce;\n    });\n\n    it('should not remove the view', function() {\n      expect(removeSpy).to.have.been.calledOnce;\n    });\n\n    it('should leave _isDestroyed as true', function() {\n      expect(view).to.be.have.property('_isDestroyed', true);\n    });\n  });\n\n  describe('#delegateEvents', function() {\n    describe('when passing events', function() {\n      let events;\n      let view;\n\n      beforeEach(function() {\n        const FooView = View.extend({\n          events: {\n            'click': 'onClick'\n          },\n          onClick: this.sinon.stub()\n        });\n\n        view = new FooView();\n\n        events = {\n          'click': this.sinon.stub()\n        };\n\n        view.delegateEvents(events);\n\n        view.$el.trigger('click');\n      });\n\n      it('should delegate the passed events', function() {\n        expect(events.click).to.have.been.calledOnce;\n      });\n\n      it('should not delegate instance events', function() {\n        expect(view.onClick).to.not.have.been.called;\n      });\n    });\n  });\n\n  describe('when serializing a model', function() {\n    const modelData = {foo: 'bar'};\n    let view;\n\n    beforeEach(function() {\n      const model = new Backbone.Model(modelData);\n      view = new View({\n        model: model\n      });\n    });\n\n    it('should return all attributes', function() {\n      expect(view.serializeModel()).to.be.eql(modelData);\n    });\n  });\n\n  describe('triggering events through a child view', function() {\n    let onChildviewFooClickStub;\n    let MyView;\n    let MyCollectionView;\n    let collection;\n    let collectionView;\n    let childView;\n\n    beforeEach(function() {\n      onChildviewFooClickStub = this.sinon.stub();\n\n      MyView = View.extend({\n        template: _.template('foo'),\n        triggers: {'click': 'foo:click'}\n      });\n\n      MyCollectionView = CollectionView.extend({\n        childView: MyView,\n        childViewEventPrefix: 'childview',\n        onChildviewFooClick: onChildviewFooClickStub\n      });\n\n      collection = new Backbone.Collection([{foo: 'bar'}]);\n      collectionView = new MyCollectionView({\n        collection: collection\n      });\n\n      collectionView.render();\n      childView = collectionView.children.findByModel(collection.at(0));\n      childView.$el.click();\n    });\n\n    it('should fire the event method once', function() {\n      expect(onChildviewFooClickStub).to.have.been.calledOnce;\n    });\n  });\n\n  describe('when proxying events to a parent layout', function() {\n    let superView;\n    let layoutView;\n    let childView;\n    let layoutEventHandler;\n    let layoutEventOnHandler;\n    let layoutViewOnBoomHandler;\n    let superViewOnRattleHandler;\n    let childEventsFunction;\n\n    beforeEach(function() {\n      const LayoutView = View.extend({\n        template: _.template('<div class=\"child\"></div>'),\n\n        regions: {\n          'child': '.child',\n        },\n\n        childViewEventPrefix: 'childview',\n\n        childViewEvents: {\n          'boom': 'onBoom'\n        },\n\n        onBoom: this.sinon.stub(),\n\n        childViewTriggers: {\n          'whack': 'rattle'\n        }\n      });\n\n      const ChildView = View.extend({\n        template: _.noop\n      });\n\n      const SuperView = View.extend({\n        template: _.template('<div class=\"layout\"></div>'),\n\n        regions: {\n          'layout': '.layout',\n        },\n\n        childViewEvents: {\n          rattle: 'onRattle'\n        },\n\n        onRattle: this.sinon.stub()\n      });\n\n      superView = new SuperView();\n      layoutView = new LayoutView();\n      childView = new ChildView();\n      layoutView.render();\n      superView.render();\n\n      layoutEventHandler = sinon.spy();\n      layoutView.on('childview:boom', layoutEventHandler);\n\n      layoutEventOnHandler = sinon.spy();\n      layoutView.onChildviewBoom = layoutEventOnHandler;\n\n      layoutViewOnBoomHandler = layoutView.onBoom;\n\n      superViewOnRattleHandler = superView.onRattle;\n\n      childEventsFunction = (function() {\n        return {\n          'boom': layoutViewOnBoomHandler\n        };\n      }).bind(this);\n    });\n\n    describe('when there is not a containing layout', function() {\n      beforeEach(function() {\n        childView.triggerMethod('boom', 'foo', 'bar');\n      });\n\n      it('does not emit the event on the layout', function() {\n        expect(layoutEventHandler).not.to.have.been.called;\n      });\n    });\n\n    describe('when there is a containing layout', function() {\n      beforeEach(function() {\n        layoutView.showChildView('child', childView);\n        childView.triggerMethod('boom', 'foo', 'bar');\n      });\n\n      it('emits the event on the layout', function() {\n        expect(layoutEventHandler)\n          .to.have.been.calledWith('foo', 'bar')\n          .and.to.have.been.calledOn(layoutView)\n          .and.calledOnce;\n      });\n\n      it('invokes the layout on handler', function() {\n        expect(layoutEventOnHandler)\n          .to.have.been.calledWith('foo', 'bar')\n          .and.to.have.been.calledOn(layoutView)\n          .and.calledOnce;\n      });\n\n      it('invokes the layout childViewEvents handler', function() {\n        expect(layoutViewOnBoomHandler)\n          .to.have.been.calledWith('foo', 'bar')\n          .and.to.have.been.calledOn(layoutView)\n          .and.calledOnce;\n      });\n    });\n\n    describe('when childViewEvents was passed as a function', function() {\n      beforeEach(function() {\n        // use the function definition of childViewEvents instead of the hash\n        layoutView.childViewEvents = childEventsFunction;\n        layoutView.delegateEvents();\n        layoutView.showChildView('child', childView);\n        childView.triggerMethod('boom', 'foo', 'bar');\n      });\n\n      it('invokes the layout childViewEvents handler', function() {\n        expect(layoutViewOnBoomHandler)\n          .to.have.been.calledWith('foo', 'bar')\n          .and.to.have.been.calledOn(layoutView)\n          .and.calledOnce;\n      });\n    });\n\n    describe('using childViewTriggers', function() {\n      beforeEach(function() {\n        superView.showChildView('layout', layoutView);\n        layoutView.showChildView('child', childView);\n        childView.triggerMethod('whack', 'foo', 'bar');\n      });\n\n      it('invokes the super trigger handler', function() {\n        expect(superViewOnRattleHandler)\n          .to.have.been.calledWith('foo', 'bar')\n          .to.have.been.calledOn(superView)\n          .and.calledOnce;\n      });\n    });\n\n    describe('when childViewEventPrefix is false', function() {\n      beforeEach(function() {\n        layoutView.showChildView('child', childView);\n        layoutView.childViewEventPrefix = false;\n        layoutView.delegateEvents();\n        childView.triggerMethod('boom', 'foo', 'bar');\n      });\n\n      it('should not emit the event on the layout', function() {\n        expect(layoutEventHandler).not.to.have.been.called;\n      });\n    });\n\n    describe('when childViewEventPrefix flag is false', function() {\n      let myView;\n\n      beforeEach(function() {\n        setEnabled('childViewEventPrefix', false);\n        myView = new View();\n      });\n\n      afterEach(function() {\n        setEnabled('childViewEventPrefix', true);\n      });\n\n      it('should set childViewEventPrefix to false', function() {\n        expect(myView._eventPrefix).to.be.false;\n      });\n    });\n\n    describe('when childViewEventPrefix flag is true', function() {\n      let myView;\n\n      beforeEach(function() {\n        setEnabled('childViewEventPrefix', true);\n        myView = new View();\n      });\n\n      afterEach(function() {\n        setEnabled('childViewEventPrefix', false);\n      });\n\n      it('should set childViewEventPrefix to \"childview\"', function() {\n        expect(myView._eventPrefix).to.equal('childview:');\n      });\n    });\n\n    describe('return values of wrapped methods', function() {\n      let fooView;\n\n      beforeEach(function() {\n        fooView = new Marionette.View();\n      });\n\n      it('destroy should return the view', function() {\n        this.sinon.spy(fooView, 'destroy');\n        fooView.destroy();\n\n        expect(fooView.destroy).to.have.returned(fooView);\n      });\n\n      it('setElement should return the view', function() {\n        this.sinon.spy(fooView, 'setElement');\n        fooView.setElement(fooView.$el);\n\n        expect(fooView.setElement).to.have.returned(fooView);\n      });\n\n      it('delegateEvents should return the view', function() {\n        this.sinon.spy(fooView, 'delegateEvents');\n        fooView.delegateEvents();\n\n        expect(fooView.delegateEvents).to.have.returned(fooView);\n      });\n\n      it('undelegateEvents should return the view', function() {\n        this.sinon.spy(fooView, 'undelegateEvents');\n        fooView.undelegateEvents({});\n\n        expect(fooView.undelegateEvents).to.have.returned(fooView);\n      });\n\n      it('delegateEntityEvents should return the view', function() {\n        this.sinon.spy(fooView, 'delegateEntityEvents');\n        fooView.delegateEntityEvents();\n\n        expect(fooView.delegateEntityEvents).to.have.returned(fooView);\n      });\n\n      it('undelegateEntityEvents should return the view', function() {\n        this.sinon.spy(fooView, 'undelegateEntityEvents');\n        fooView.undelegateEntityEvents({});\n\n        expect(fooView.undelegateEntityEvents).to.have.returned(fooView);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/object.spec.js",
    "content": "import MnObject from '../../src/object';\n\ndescribe('marionette object', function() {\n\n  describe('when creating an object', function() {\n    let object;\n    let options;\n\n    beforeEach(function() {\n      const Obj = MnObject.extend({\n        initialize(opts) {\n          this.bindEvents(opts.model, this.modelEvents);\n        },\n\n        modelEvents: {\n          'bar': 'onBar'\n        },\n\n        onBar: this.sinon.stub()\n      });\n\n      this.sinon.spy(Obj.prototype, '_initRadio');\n\n      const model = new Backbone.Model();\n\n      options = {\n        model,\n        channelName: 'foo',\n        radioEvents: {},\n        radioRequests: {}\n      };\n\n      object = new Obj(options);\n    });\n\n    it('should merge the class options to the object', function() {\n      expect(object.channelName).to.equal(options.channelName);\n      expect(object.radioEvents).to.equal(options.radioEvents);\n      expect(object.radioRequests).to.equal(options.radioRequests);\n    });\n\n    it('should maintain a reference to the options', function() {\n      expect(object.options).to.deep.equal(options);\n    });\n\n    it('should have a cidPrefix', function() {\n      expect(object.cidPrefix).to.equal('mno');\n    });\n\n    it('should have a cid', function() {\n      expect(object.cid).to.contain('mno');\n    });\n\n    it('should init the RadioMixin', function() {\n      expect(object._initRadio).to.have.been.called;\n    });\n\n    it('should support triggering events on itself', function() {\n      const fooHandler = this.sinon.spy();\n      object.on('foo', fooHandler);\n\n      object.trigger('foo', options);\n\n      expect(fooHandler).to.have.been.calledOnce.and.calledWith(options);\n    });\n\n    it('should support binding to evented objects', function() {\n      options.model.trigger('bar', options);\n\n      expect(object.onBar).to.have.been.calledOnce.and.calledWith(options);\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/on-attach.spec.js",
    "content": "import _ from 'underscore';\nimport View from '../../src/view';\nimport Region from '../../src/region';\n\ndescribe('onAttach', function() {\n  const expectTriggerMethod = (method, target, retval, before = null) => {\n    expect(method)\n      .to.have.been.calledOnce\n      .and.to.have.been.calledOn(target)\n      .and.to.have.been.calledWithExactly(target)\n      .and.to.have.returned(retval);\n    if (before) {\n      expect(method).to.have.been.calledBefore(before);\n    }\n  };\n\n  const extendAttachMethods = superConstructor => target => _.assign(target, {\n    constructor(options) {\n      superConstructor.call(this, options);\n      sinon.spy(this, 'onAttach');\n      sinon.spy(this, 'onBeforeAttach');\n      sinon.spy(this, 'onDetach');\n      sinon.spy(this, 'onBeforeDetach');\n      sinon.spy(this, 'onDestroy');\n    },\n    onAttach() {\n      return !!this._isAttached;\n    },\n    onBeforeAttach() {\n      return !!this._isAttached;\n    },\n    onDetach() {\n      return !!this._isAttached;\n    },\n    onBeforeDetach() {\n      return !!this._isAttached;\n    },\n    onDestroy() {\n      return !!this._isAttached;\n    }\n  });\n\n  let sinon;\n  let TestView;\n  let region; // A Region to show our View within\n\n  beforeEach(function() {\n    sinon = this.sinon;\n    TestView = View.extend(extendAttachMethods(View)({\n      template: _.template('<header></header><main></main><footer></footer>'),\n      regions: {\n        header: 'header',\n        main: 'main',\n        footer: 'footer'\n      }\n    }));\n    // A Region to show our View within\n    this.setFixtures('<div id=\"region\"></div>');\n    const regionEl = document.getElementById('region');\n    region = new Region({el: regionEl});\n  });\n\n  describe('when showing a view into a region of a view without events monitored', function() {\n    let layoutView;\n    let view;\n\n    beforeEach(function() {\n      const LayoutView = View.extend({\n        monitorViewEvents: false,\n        el: '#region',\n        template: _.template('<div id=\"child\"></div>'),\n        regions: {\n          child: '#child'\n        }\n      });\n\n      layoutView = new LayoutView();\n      layoutView.render();\n\n      view = new TestView();\n      layoutView.showChildView('child', view);\n    });\n\n    it('should not trigger onBeforeAttach on the view', function() {\n      expect(view.onBeforeAttach).to.not.be.called;\n    });\n\n    it('should not trigger onAttach on the view', function() {\n      expect(view.onAttach).to.not.be.called;\n    });\n\n    describe('when destroying the view', function() {\n      beforeEach(function() {\n        layoutView.getRegion('child').destroyView(view);\n      });\n\n      it('should not trigger onBeforeDetach on the view', function() {\n        expect(view.onBeforeDetach).to.not.be.called;\n      });\n\n      it('should not trigger onDetach on the view', function() {\n        expect(view.onDetach).to.not.be.called;\n      });\n    });\n\n    describe('when detaching the view', function() {\n      beforeEach(function() {\n        layoutView.getRegion('child').detachView();\n      });\n\n      it('should not trigger onBeforeDetach on the view', function() {\n        expect(view.onBeforeDetach).to.not.be.called;\n      });\n\n      it('should not trigger onDetach on the view', function() {\n        expect(view.onDetach).to.not.be.called;\n      });\n    });\n  });\n\n  describe('when showing a view into a region not attached to the document', function() {\n    let detachedRegion;\n    let view;\n\n    beforeEach(function() {\n      view = new TestView();\n      detachedRegion = new Region({el: document.createElement('div')});\n      detachedRegion.show(view);\n    });\n\n    it('should not call onAttach/onBeforeAttach methods on the view', function() {\n      expect(view.onAttach).to.not.have.been.called;\n      expect(view.onBeforeAttach).to.not.have.been.called;\n    });\n\n    describe('when removing a view from a region not attached to the document', function() {\n      beforeEach(function() {\n        detachedRegion.empty();\n      });\n\n      it('should not call onDetach/onBeforeDetach methods on the view', function() {\n        expect(view.onDetach).to.not.have.been.called;\n        expect(view.onBeforeDetach).to.not.have.been.called;\n      });\n    });\n  });\n\n  describe('when showing a view into a region attached to the document', function() {\n    let view;\n\n    beforeEach(function() {\n      view = new TestView();\n      region.show(view);\n    });\n\n    it('should call onBeforeAttach on the view', function() {\n      expectTriggerMethod(view.onBeforeAttach, view, false, view.onAttach);\n    });\n\n    it('should call onAttach on the view', function() {\n      expectTriggerMethod(view.onAttach, view, true);\n    });\n\n    describe('when destroying a view from a region attached to the document', function() {\n      beforeEach(function() {\n        region.empty();\n      });\n\n      it('should call onBeforeDetach on the view', function() {\n        expectTriggerMethod(view.onBeforeDetach, view, true, view.onDetach);\n      });\n\n      it('should call onDetach on the view', function() {\n        expectTriggerMethod(view.onDetach, view, false);\n      });\n\n      it('should call onDetach before destroying view', function() {\n        expect(view.onDestroy).to.have.been.calledAfter(view.onDetach);\n      });\n    });\n\n    describe('when detaching a view from a region attached to the document', function() {\n      beforeEach(function() {\n        region.empty({preventDestroy: true});\n      });\n\n      it('should call onBeforeDetach on the view', function() {\n        expectTriggerMethod(view.onBeforeDetach, view, true, view.onDetach);\n      });\n\n      it('should call onDetach on the view', function() {\n        expectTriggerMethod(view.onDetach, view, false);\n      });\n    });\n  });\n\n  describe('when the parent view is initially detached', function() {\n    describe('When showing a View with a single level of nested views', function() {\n      let mainView;\n      let footerView;\n\n      beforeEach(function() {\n        const ParentView = TestView.extend({\n          onRender: function() {\n            mainView = new TestView();\n            footerView = new TestView();\n            this.showChildView('main', mainView);\n            this.showChildView('footer', footerView);\n          }\n        });\n\n        const parentView = new ParentView();\n        region.show(parentView);\n      });\n\n      it('should trigger onBeforeAttach & onAttach on the mainView', function() {\n        expectTriggerMethod(mainView.onBeforeAttach, mainView, false, mainView.onAttach);\n        expectTriggerMethod(mainView.onAttach, mainView, true);\n      });\n\n      it('should trigger onBeforeAttach & onAttach on the footerView', function() {\n        expectTriggerMethod(footerView.onBeforeAttach, footerView, false, footerView.onAttach);\n        expectTriggerMethod(footerView.onAttach, footerView, true);\n      });\n\n      describe('When destroying a View with a single level of nested view', function() {\n        beforeEach(function() {\n          region.empty();\n        });\n\n        it('should call onBeforeDetach & onDetach on the mainView', function() {\n          expectTriggerMethod(mainView.onBeforeDetach, mainView, true, mainView.onDetach);\n          expectTriggerMethod(mainView.onDetach, mainView, false);\n        });\n\n        it('should call onBeforeDetach & onDetach on the footerView', function() {\n          expectTriggerMethod(footerView.onBeforeDetach, footerView, true, footerView.onDetach);\n          expectTriggerMethod(footerView.onDetach, footerView, false);\n        });\n      });\n    });\n\n    describe('When showing a View with a single level of nested views in onAttach', function() {\n      let mainView;\n      let footerView;\n\n      beforeEach(function() {\n        const ParentView = TestView.extend({\n          onAttach: function() {\n            mainView = new TestView();\n            footerView = new TestView();\n            this.showChildView('main', mainView);\n            this.showChildView('footer', footerView);\n          }\n        });\n\n        const parentView = new ParentView();\n        region.show(parentView);\n      });\n\n      it('should trigger onBeforeAttach & onAttach on the mainView', function() {\n        expectTriggerMethod(mainView.onBeforeAttach, mainView, false, mainView.onAttach);\n        expectTriggerMethod(mainView.onAttach, mainView, true);\n      });\n\n      it('should trigger onBeforeAttach & onAttach on the footerView', function() {\n        expectTriggerMethod(footerView.onBeforeAttach, footerView, false, footerView.onAttach);\n        expectTriggerMethod(footerView.onAttach, footerView, true);\n      });\n    });\n\n    describe('When showing a View with two levels of nested views', function() {\n      let grandparentView;\n      let parentView;\n      let childView;\n\n      beforeEach(function() {\n        const GrandparentView = TestView.extend({\n          onRender: function() {\n            parentView = new ParentView();\n            this.showChildView('main', parentView);\n          }\n        });\n\n        const ParentView = TestView.extend({\n          onRender: function() {\n            childView = new TestView();\n            this.showChildView('main', childView);\n          }\n        });\n\n        grandparentView = new GrandparentView();\n        region.show(grandparentView);\n      });\n\n      it('should trigger onBeforeAttach & onAttach on the grandparent view', function() {\n        expect(grandparentView.onAttach).to.have.been.calledOnce;\n        expect(grandparentView.onBeforeAttach).to.have.been.calledOnce;\n      });\n\n      it('should trigger onBeforeAttach & onAttach on the parent view', function() {\n        expect(parentView.onBeforeAttach).to.have.been.calledOnce;\n        expect(parentView.onAttach).to.have.been.calledOnce;\n      });\n\n      it('should trigger onBeforeAttach & onAttach on the child view', function() {\n        expectTriggerMethod(childView.onBeforeAttach, childView, false, childView.onAttach);\n        expectTriggerMethod(childView.onAttach, childView, true);\n      });\n\n      describe('When destroying a View with two levels of nested views', function() {\n        beforeEach(function() {\n          region.empty();\n        });\n\n        it('should trigger onBeforeDetach & onDetach on the grandparent view', function() {\n          expect(grandparentView.onDetach).to.have.been.calledOnce;\n          expect(grandparentView.onBeforeDetach).to.have.been.calledOnce;\n        });\n\n        it('should trigger onBeforeDetach & onDetach on the parent view', function() {\n          expect(parentView.onBeforeDetach).to.have.been.calledOnce;\n          expect(parentView.onDetach).to.have.been.calledOnce;\n        });\n\n        it('should trigger onBeforeDetach & onDetach on the child view', function() {\n          expectTriggerMethod(childView.onBeforeDetach, childView, true, childView.onDetach);\n          expectTriggerMethod(childView.onDetach, childView, false);\n        });\n      });\n    });\n  });\n\n  describe('when the parent view is initially attached', function() {\n    describe('When showing a View with a single level of nested views', function() {\n      let mainView;\n      let footerView;\n\n      beforeEach(function() {\n        const parentView = new TestView();\n        region.show(parentView);\n\n        mainView = new TestView();\n        footerView = new TestView();\n        parentView.showChildView('main', mainView);\n        parentView.showChildView('footer', footerView);\n      });\n\n      it('should trigger onBeforeAttach & onAttach on the mainView', function() {\n        expectTriggerMethod(mainView.onBeforeAttach, mainView, false, mainView.onAttach);\n        expectTriggerMethod(mainView.onAttach, mainView, true);\n      });\n\n      it('should trigger onBeforeAttach & onAttach on the footerView', function() {\n        expectTriggerMethod(footerView.onBeforeAttach, footerView, false, footerView.onAttach);\n        expect(footerView.onAttach, footerView, true);\n      });\n    });\n\n    describe('When showing a View with two levels of nested views', function() {\n      let grandparentView;\n      let parentView;\n      let childView;\n\n      beforeEach(function() {\n        const ParentView = TestView.extend({\n          onRender: function() {\n            childView = new TestView();\n            this.showChildView('main', childView);\n          }\n        });\n\n        grandparentView = new TestView();\n        region.show(grandparentView);\n\n        parentView = new ParentView();\n        grandparentView.showChildView('main', parentView);\n      });\n\n      it('should trigger onBeforeAttach & onAttach on the grandparent view', function() {\n        expect(grandparentView.onAttach).to.have.been.calledOnce;\n        expect(grandparentView.onBeforeAttach).to.have.been.calledOnce;\n      });\n\n      it('should trigger onBeforeAttach & onAttach on the parent view', function() {\n        expect(parentView.onBeforeAttach).to.have.been.calledOnce;\n        expect(parentView.onAttach).to.have.been.calledOnce;\n      });\n\n      it('should trigger onBeforeAttach & onAttach on the child view', function() {\n        expectTriggerMethod(childView.onBeforeAttach, childView, false, childView.onAttach);\n        expect(childView.onAttach, childView, true);\n      });\n    });\n  });\n\n});\n"
  },
  {
    "path": "test/unit/on-dom-refresh.spec.js",
    "content": "import _ from 'underscore';\nimport Backbone from 'backbone';\nimport Events from '../../src/mixins/events';\nimport View from '../../src/view';\nimport Region from '../../src/region';\n\ndescribe('onDomRefresh', function() {\n  'use strict';\n\n  let attachedRegion;\n  let detachedRegion;\n  let BbView;\n  let MnView;\n\n  beforeEach(function() {\n    this.setFixtures($('<div id=\"region\"></div>'));\n    attachedRegion = new Region({el: '#region'});\n    detachedRegion = new Region({el: $('<div></div>')});\n    BbView = Backbone.View.extend({\n      onDomRefresh: this.sinon.stub()\n    });\n    _.extend(BbView.prototype, Events);\n    MnView = View.extend({\n      template: _.noop,\n      onDomRefresh: this.sinon.stub()\n    });\n  });\n\n  describe('when a Backbone view is shown detached from the DOM', function() {\n    let bbView;\n\n    beforeEach(function() {\n      bbView = new BbView();\n      detachedRegion.show(bbView);\n    });\n\n    it('should never trigger onDomRefresh', function() {\n      expect(bbView.onDomRefresh).not.to.have.been.calledOnce;\n    });\n  });\n\n  describe('when a Marionette view is shown detached from the DOM', function() {\n    let mnView;\n\n    beforeEach(function() {\n      mnView = new MnView();\n      detachedRegion.show(mnView);\n    });\n\n    it('should never trigger onDomRefresh', function() {\n      expect(mnView.onDomRefresh).not.to.have.been.calledOnce;\n    });\n  });\n\n  describe('when a Backbone view is shown attached to the DOM', function() {\n    let bbView;\n\n    beforeEach(function() {\n      bbView = new BbView();\n      attachedRegion.show(bbView);\n    });\n\n    it('should trigger onDomRefresh on the view', function() {\n      expect(bbView.onDomRefresh).to.have.been.calledOnce;\n    });\n  });\n\n  describe('when a Marionette view is shown attached to the DOM', function() {\n    let mnView;\n\n    beforeEach(function() {\n      mnView = new MnView();\n      attachedRegion.show(mnView);\n    });\n\n    it('should trigger onDomRefresh on the view', function() {\n      expect(mnView.onDomRefresh).to.have.been.calledOnce;\n    });\n  });\n\n});\n"
  },
  {
    "path": "test/unit/on-dom-remove.spec.js",
    "content": "import _ from 'underscore';\nimport Backbone from 'backbone';\nimport Events from '../../src/mixins/events';\nimport View from '../../src/view';\nimport Region from '../../src/region';\n\ndescribe('onDomRemove', function() {\n  'use strict';\n\n  let attachedRegion;\n  let detachedRegion;\n  let BbView;\n  let MnView;\n\n  beforeEach(function() {\n    this.setFixtures($('<div id=\"region\"></div>'));\n    attachedRegion = new Region({el: '#region'});\n    detachedRegion = new Region({el: $('<div></div>')});\n    BbView = Backbone.View.extend({\n      onDomRemove: this.sinon.stub()\n    });\n    _.extend(BbView.prototype, Events);\n    MnView = View.extend({\n      template: _.noop,\n      onDomRemove: this.sinon.stub()\n    });\n  });\n\n  describe('when a Backbone view is shown detached from the DOM', function() {\n    let bbView;\n\n    beforeEach(function() {\n      bbView = new BbView();\n      detachedRegion.show(bbView);\n      detachedRegion.empty();\n    });\n\n    it('should never trigger onDomRemove', function() {\n      expect(bbView.onDomRemove).not.to.have.been.called;\n    });\n  });\n\n  describe('when a Marionette view is shown detached from the DOM', function() {\n    let mnView;\n\n    beforeEach(function() {\n      mnView = new MnView();\n      detachedRegion.show(mnView);\n      mnView.render();\n      detachedRegion.empty();\n    });\n\n    it('should never trigger onDomRemove', function() {\n      expect(mnView.onDomRemove).not.to.have.been.called;\n    });\n  });\n\n  describe('when a Backbone view is shown attached to the DOM', function() {\n    let bbView;\n\n    beforeEach(function() {\n      bbView = new BbView();\n      attachedRegion.show(bbView);\n    });\n\n    describe('when the region is emptied', function() {\n      it('should trigger onDomRemove on the view', function() {\n        attachedRegion.empty();\n        expect(bbView.onDomRemove).to.have.been.calledOnce.and.calledWith(bbView);\n      });\n    });\n  });\n\n  describe('when a Marionette view is shown attached to the DOM', function() {\n    let mnView;\n\n    beforeEach(function() {\n      mnView = new MnView();\n      attachedRegion.show(mnView);\n    });\n\n    describe('when the region is emptied', function() {\n      it('should trigger onDomRemove on the view', function() {\n        attachedRegion.empty();\n        expect(mnView.onDomRemove).to.have.been.calledOnce.and.calledWith(mnView);\n      });\n    });\n\n    describe('when the view is re-rendered', function() {\n      it('should trigger onDomRemove on the view', function() {\n        mnView.render();\n        expect(mnView.onDomRemove).to.have.been.calledOnce.and.calledWith(mnView);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/region.spec.js",
    "content": "import _ from 'underscore';\nimport Backbone from 'backbone';\nimport Events from '../../src/mixins/events';\nimport Region from '../../src/region';\nimport View from '../../src/view';\nimport CollectionView from '../../src/collection-view';\n\ndescribe('region', function() {\n  'use strict';\n\n  describe('when creating a new region and no configuration has been provided', function() {\n    it('should throw an exception saying an \"el\" is required', function() {\n      expect(function() {\n        return new Region();\n      }).to.throw('An \"el\" must be specified for a region.');\n    });\n  });\n\n  describe('when passing an el DOM reference in directly', function() {\n    let el;\n    let customRegion;\n    let optionRegion;\n    let optionRegionJquery;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"region\"></div>');\n      el = $('#region')[0];\n\n      customRegion = new (Region.extend({\n        el: el\n      }))();\n\n      optionRegion = new Region({el: el});\n\n      optionRegionJquery = new Region({el: $(el)});\n    });\n\n    it('should not have been replaced', function() {\n      expect(customRegion.isReplaced()).to.be.false;\n    });\n\n    it('should work when el is passed in as an option', function() {\n      expect(optionRegionJquery.$el[0]).to.equal(el);\n      expect(optionRegionJquery.el).to.equal(el);\n    });\n\n    it('should handle when the el option is passed in as a jquery selector', function() {\n      expect(optionRegion.$el[0]).to.equal(el);\n    });\n\n    it('should work when el is set in the region extend', function() {\n      expect(customRegion.$el[0]).to.equal(el);\n    });\n\n    it('should not have a view', function() {\n      expect(customRegion.hasView()).to.equal(false);\n      expect(optionRegion.hasView()).to.equal(false);\n    });\n\n    it('should complain if the el passed in as an option is invalid', function() {\n      expect(function() {\n        Region({el: $('the-ghost-of-lechuck')[0]});\n      }).to.throw;\n    });\n\n    it('should complain if the el passed in via an extended region is invalid', function() {\n      expect(function() {\n        (Region.extend({el: $('the-ghost-of-lechuck')[0]}))();\n      }).to.throw;\n    });\n\n    it('should not be swapping view', function() {\n      expect(customRegion.isSwappingView()).to.be.false;\n    });\n  });\n\n  describe('when creating a new region and the \"el\" does not exist in DOM', function() {\n    let MyRegion;\n    let MyView;\n    let myView;\n\n    beforeEach(function() {\n      MyRegion = Region.extend({\n        el: '#not-existed-region'\n      });\n\n      MyView = Backbone.View.extend({\n        render: function() {\n          $(this.el).html('some content');\n        }\n      });\n      myView = new MyView();\n\n      this.setFixtures('<div id=\"region\"></div>');\n    });\n\n    describe('when showing a view', function() {\n      describe('when allowMissingEl is not set', function() {\n        let region;\n\n        beforeEach(function() {\n          region = new MyRegion();\n        });\n\n        it('should throw an exception saying an \"el\" doesnt exist in DOM', function() {\n          expect(function() {\n            region.show(new MyView());\n          }.bind(this)).to.throw('An \"el\" must exist in DOM for this region ' + region.cid);\n        });\n\n        it('should not have a view', function() {\n          expect(region.hasView()).to.be.false;\n        });\n      });\n\n      describe('when allowMissingEl is set', function() {\n        let region;\n\n        beforeEach(function() {\n          region = new MyRegion({allowMissingEl: true});\n        });\n\n        it('should not throw an exception', function() {\n          expect(function() {\n            region.show(new MyView());\n          }.bind(this)).not.to.throw();\n        });\n\n        it('should not have a view', function() {\n          expect(region.hasView()).to.be.false;\n        });\n\n        it('should not render the view', function() {\n          this.sinon.spy(myView, 'render');\n          region.show(myView);\n          expect(myView.render).not.to.have.been.called;\n        });\n      });\n    });\n  });\n\n  // NOTE: Currently an internal API with potential for public release\n  describe('when setting the region element', function() {\n    let TestView;\n    let region;\n    let oneEl;\n    let twoEl;\n\n    beforeEach(function() {\n      TestView = View.extend({ id: 'view', template: _.template('foo') });\n      this.setFixtures('<div id=\"region1\"></div><div id=\"region2\"></div>');\n      oneEl = $('#region1')[0];\n      twoEl = $('#region2')[0];\n\n      region = new Region({ el: oneEl });\n    });\n\n    it('should return the region', function() {\n      expect(region._setElement(twoEl)).to.equal(region);\n    });\n\n    it('should set the el', function() {\n      region.show(new TestView());\n      region._setElement(twoEl);\n      expect(region.el).to.equal(twoEl);\n    });\n\n    it('should set the $el', function() {\n      region.show(new TestView());\n      region._setElement(twoEl);\n      expect(region.$el[0]).to.equal($(twoEl)[0]);\n    });\n\n    it('should throw an error if the `el` is not specified', function() {\n      expect(region._setElement.bind(region)).to.throw();\n    });\n\n    describe('when setting the `el` to the same element', function() {\n      it('should not requery the el', function() {\n        this.sinon.spy(region, 'getEl');\n        expect(region._setElement(oneEl)).to.equal(region);\n        expect(region.getEl).to.not.be.called;\n      });\n    });\n\n    describe('when there is a replaceElement:true view', function() {\n      it('should replace the el of the region with the view el', function() {\n        const view = new TestView();\n        region.show(view, { replaceElement: true });\n        region._setElement(twoEl);\n        expect($('#region1')).to.be.lengthOf(1);\n        expect($('#view')).to.be.lengthOf(1);\n        expect($('#region2')).to.be.lengthOf(0);\n      });\n    });\n\n    describe('when there is a replaceElement:false view', function() {\n      it('should attach the view html to the region', function() {\n        const view = new TestView();\n        region.show(view, { replaceElement: false });\n        region._setElement(twoEl);\n        expect($('#region1')).to.be.lengthOf(1);\n        expect($('#region1 #view')).to.be.lengthOf(0);\n        expect($('#region2 #view')).to.be.lengthOf(1);\n      });\n    });\n  });\n\n  describe('when showing a template', function() {\n    let myRegion;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"region\"></div>');\n      myRegion = new Region({\n        el: '#region'\n      });\n\n      myRegion.show(_.template('<b>Hello World!</b>'));\n    });\n\n    it('should render the template in the region', function() {\n      expect(myRegion.$el).to.contain.$html('<b>Hello World!</b>');\n    });\n  });\n\n  describe('when showing a template with viewOptions', function() {\n    let myRegion;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"region\"></div>');\n      myRegion = new Region({\n        el: '#region'\n      });\n\n      myRegion.show({\n        template: _.template('<b>Hello <%- who %>!</b>'),\n        model: new Backbone.Model({ who: 'World' })\n      });\n    });\n\n    it('should render the template in the region', function() {\n      expect(myRegion.$el).to.contain.$html('<b>Hello World!</b>');\n    });\n  });\n\n  describe('when showing an html string', function() {\n    let myRegion;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"region\"></div>');\n      myRegion = new Region({\n        el: '#region'\n      });\n\n      myRegion.show('<b>Hello World!</b>');\n    });\n\n    it('should render the string in the region', function() {\n      expect(myRegion.$el).to.contain.$html('<b>Hello World!</b>');\n    });\n  });\n\n  describe('when showing an initial view', function() {\n    let MyView;\n    let showOptions;\n    let isSwappingOnShow;\n    let view;\n    let region;\n\n    beforeEach(function() {\n      const sinon = this.sinon;\n\n      const MyRegion = Region.extend({\n        el: '#region',\n        onBeforeShow: sinon.stub(),\n        onShow: sinon.spy(function() {\n          isSwappingOnShow = this.isSwappingView();\n        }),\n        onBeforeEmpty: sinon.stub(),\n        onEmpty: sinon.stub(),\n      });\n\n      MyView = Backbone.View.extend({\n        events: {\n          'click': 'onClick'\n        },\n        render: function() {\n          $(this.el).html('some content');\n        },\n        destroy: function() {},\n        onBeforeRender: function() {},\n        onRender: sinon.stub(),\n        onBeforeAttach: sinon.stub(),\n        onAttach: sinon.stub(),\n        onDomRefresh: sinon.stub(),\n        onClick: sinon.stub()\n      });\n\n      _.extend(MyView.prototype, Events);\n\n      sinon.stub(MyView.prototype, 'onBeforeRender').callsFake(() => { return region.currentView; });\n\n      this.setFixtures('<div id=\"region\"></div>');\n      view = new MyView();\n      region = new MyRegion();\n\n      sinon.spy(region, 'show');\n\n      showOptions = {foo: 'bar'};\n      region.show(view, showOptions);\n    });\n\n    it('should have a cidPrefix', function() {\n      expect(region.cidPrefix).to.equal('mnr');\n    });\n\n    it('should have a cid', function() {\n      expect(region.cid).to.exist;\n    });\n\n    it('should render the view', function() {\n      expect(view.onRender).to.have.been.called;\n    });\n\n    it('should have a view', function() {\n      expect(region.hasView()).to.equal(true);\n    });\n\n    it('should set $el and el', function() {\n      expect(region.$el[0]).to.equal(region.el);\n    });\n\n    it('should append the rendered HTML to the managers \"el\"', function() {\n      expect(region.$el).to.contain.$html(view.$el.html());\n    });\n\n    it('should pass the proper arguments to the region \"onShow\"', function() {\n      expect(region.onShow).to.have.been.calledWith(region, view, showOptions);\n    });\n\n    it('should pass the proper arguments to the region \"onBeforeShow\"', function() {\n      expect(region.onBeforeShow).to.have.been.calledWith(region, view, showOptions);\n    });\n\n    it('should not be swapping view', function() {\n      expect(isSwappingOnShow).to.be.false;\n    });\n\n    it('should have the currentView set before rendering', function() {\n      expect(view.onBeforeRender).to.have.returned(view);\n    });\n\n    describe('region and view event ordering', function() {\n      it('triggers before:show before before:render', function() {\n        expect(region.onBeforeShow).to.have.been.calledBefore(view.onBeforeRender);\n        expect(view.onBeforeRender).to.have.been.calledBefore(view.onRender);\n        expect(view.onRender).to.have.been.calledBefore(view.onBeforeAttach);\n        expect(view.onBeforeAttach).to.have.been.calledBefore(view.onAttach);\n        expect(view.onAttach).to.have.been.calledBefore(view.onDomRefresh);\n        expect(view.onDomRefresh).to.have.been.calledBefore(region.onShow);\n        expect(region.onShow).to.have.been.called;\n      });\n    });\n\n    it('should return the region', function() {\n      expect(region.show).to.have.returned(region);\n    });\n\n    describe('and then showing a different view', function() {\n      let view2;\n      let otherOptions;\n\n      beforeEach(function() {\n        view = region.currentView;\n\n        region.onEmpty.reset();\n        region.onBeforeEmpty.reset();\n\n        view2 = new MyView();\n        otherOptions = {\n          bar: 'foo'\n        };\n        region.show(view2, otherOptions);\n      });\n\n      it('should trigger empty once', function() {\n        expect(region.onEmpty).to.have.been.calledOnce;\n        expect(region.onBeforeEmpty).to.have.been.calledOnce;\n      });\n\n      it('should still have a view', function() {\n        expect(region.hasView()).to.equal(true);\n      });\n\n      it('should be swapping view', function() {\n        expect(isSwappingOnShow).to.be.true;\n      });\n    });\n\n    describe('when setting the \"replaceElement\" class option', function() {\n      let regionHtml;\n      let $parentEl;\n\n      beforeEach(function() {\n        this.sinon.spy(region, '_restoreEl');\n        // empty region to clean existing view\n        region.empty();\n        $parentEl = region.$el.parent();\n        regionHtml = $parentEl.html();\n        region.replaceElement = true;\n        region.show(view);\n      });\n\n      it('should append the view HTML to the parent \"el\"', function() {\n        expect($parentEl).to.contain.$html(view.$el.html());\n      });\n\n      it('should remove the region\\'s \"el\" from the DOM', function() {\n        expect($parentEl).to.not.contain.$html(regionHtml);\n      });\n\n      it('should call _restoreEl', function() {\n        expect(region._restoreEl).to.have.been.called;\n      });\n\n      it('should not restore if the \"currentView\" has been deleted from the region', function() {\n        delete region.currentView;\n        region._restoreEl();\n        expect(region.currentView).to.be.undefined;\n      });\n\n      it('should not restore if the \"currentView.el\" has been remove from the DOM', function() {\n        view.remove();\n        region._restoreEl();\n        expect(region.currentView.el.parentNode).is.null;\n      });\n\n      describe('and then emptying the region', function() {\n        beforeEach(function() {\n          region.empty();\n        });\n\n        it('should remove the view from the parent', function() {\n          expect($parentEl).to.not.contain.$html(view.$el.html());\n        });\n\n        it('should restore the region\\'s \"el\" to the DOM', function() {\n          expect($parentEl).to.contain.$html('<div id=\"region\"></div>');\n        });\n      });\n\n      describe('and the view is detaching from region', function() {\n        beforeEach(function() {\n          region.detachView();\n        });\n\n        it('should remove the view from the parent', function() {\n          expect($parentEl).to.not.contain.$html(view.$el.html());\n        });\n\n        it('should restore the region\\'s \"el\" to the DOM', function() {\n          expect($parentEl).to.contain.$html('<div id=\"region\"></div>');\n        });\n\n        it('should call _restoreEl', function() {\n          expect(region._restoreEl).to.have.been.called;\n        });\n      });\n\n      describe('and showing another view', function() {\n        let MyView2;\n        let view2;\n\n        beforeEach(function() {\n          MyView2 = View.extend({\n            template: _.template('some different content'),\n            onAttach: this.sinon.stub()\n          });\n\n          view2 = new MyView2();\n          region.show(view2, { replaceElement: true });\n        });\n\n        it('should append the view HTML to the parent \"el\"', function() {\n          expect($parentEl).to.contain.$html(view2.$el.html());\n        });\n\n        it('should trigger attach events', function() {\n          expect(view2.onAttach).to.be.calledOnce;\n        });\n      });\n    });\n\n    describe('and the view is detached', function() {\n      let viewDestroyStub;\n      let viewDetachStub;\n      let regionEmptyStub;\n      let detachedView;\n      let noDetachedView;\n\n      beforeEach(function() {\n        viewDestroyStub = this.sinon.stub();\n        view.on('destroy', viewDestroyStub);\n\n        viewDetachStub = this.sinon.stub();\n        view.on('detach', viewDetachStub);\n\n        regionEmptyStub = this.sinon.stub();\n        region.on('empty', regionEmptyStub);\n\n        this.sinon.spy(region, 'removeView');\n\n        detachedView = region.detachView();\n        noDetachedView = region.detachView();\n      });\n\n      it('should return the childView it was given', function() {\n        expect(detachedView).to.equal(view);\n      });\n\n      it('should not return a childView if it was already detached', function() {\n        expect(noDetachedView).to.be.undefined;\n      });\n\n      it('should have _isDestroyed set to falsy', function() {\n        expect(detachedView._isDestroyed).to.not.be.ok;\n      });\n\n      it('should not have triggered destroy on the view', function() {\n        expect(viewDestroyStub).to.not.been.called;\n      });\n\n      it('should have triggered detach on the view', function() {\n        expect(viewDetachStub).to.been.called;\n      });\n\n      it('should have triggered empty on the region', function() {\n        expect(regionEmptyStub).to.been.called;\n      });\n\n      it('should not have a parent', function() {\n        expect(detachedView).to.not.have.property('_parent');\n      });\n\n      it('should not call removeView', function() {\n        expect(region.removeView).not.to.have.been.called;\n      });\n\n    });\n  });\n\n  describe('when showing an attached view', function() {\n    let testView;\n    let region;\n    let anotherRegion;\n    let collectionView;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"reg1\"></div><div id=\"reg2\"></div><div id=\"cv\"></div><div id=\"view\">content</div>')\n      region = new Region({ el: '#reg1' });\n      anotherRegion = new Region({ el: '#reg2' });\n      collectionView = new CollectionView({ el: '#cv' });\n      testView = new View({ el: '#view' });\n    });\n\n    it('should throw an error if view is attached in another region', function() {\n      anotherRegion.show(testView);\n      expect(region.show.bind(region, testView)).to.throw();\n    });\n\n    it('should throw an error if view is attached in a collection view', function() {\n      collectionView\n        .render()\n        .addChildView(testView);\n      expect(region.show.bind(region, testView)).to.throw();\n    });\n\n  });\n\n  describe('when showing detached view', function() {\n    let collectionView;\n    let anotherRegion;\n    let region;\n    let view;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"region\"></div><div id=\"another-region\"></div>');\n      collectionView = new CollectionView();\n      region = new Region({ el: '#region' });\n      anotherRegion = new Region({ el: '#another-region' });\n      view = new View({ template: _.noop });\n    });\n\n    it('should not throw an error if a view was detached from CollectionView',function() {\n      collectionView.addChildView(view);\n      collectionView.detachChildView(view);\n      expect(region.show.bind(region, view)).to.not.throw();\n    });\n\n    it('should not throw an error if a view was detached from Region',function() {\n      anotherRegion.show(view);\n      anotherRegion.detachView(view);\n      expect(region.show.bind(region, view)).to.not.throw();\n    });\n  });\n\n  describe('when showing nested views', function() {\n    let MyRegion;\n    let MyView;\n    let SubView;\n    let innerRegionRenderSpy;\n    let region;\n    let attachHtmlSpy;\n\n    beforeEach(function() {\n      const sinon = this.sinon;\n\n      MyRegion = Region.extend({\n        el: '#region'\n      });\n\n      MyView = View.extend({\n        regions: {\n          subRegion: '.sub-region'\n        },\n\n        template: function() {\n          return '<div class=\"sub-region\"></div><div>some content</div>';\n        },\n\n        onRender: function() {\n          this.getRegion('subRegion').show(new SubView());\n        }\n      });\n\n      SubView = Backbone.View.extend({\n        render: function() {\n          $(this.el).html('some content');\n        },\n\n        initialize: function() {\n          innerRegionRenderSpy = sinon.stub();\n          this.on('render', innerRegionRenderSpy);\n        }\n      });\n\n      _.extend(SubView.prototype, Events);\n\n      this.setFixtures('<div id=\"region\"></div>');\n      region = new MyRegion();\n      attachHtmlSpy = sinon.spy(region, 'attachHtml');\n      region.show(new MyView());\n    });\n\n    it('should call inner region render before attaching to DOM', function() {\n      expect(innerRegionRenderSpy).to.have.been.calledBefore(attachHtmlSpy);\n    });\n  });\n\n  describe('when a view is already attached and shown in a region', function() {\n    let myRegion;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"region\"><div id=\"view\">Foo</div></div>');\n      myRegion = new Region({\n        el: '#region'\n      });\n      this.sinon.spy(myRegion, 'empty');\n\n      myRegion.show(new View({ el: '#view' }));\n    });\n\n    it('should not empty the region', function() {\n      expect(myRegion.empty).to.not.have.been.called;\n    });\n  });\n\n  describe('when a view is already shown and showing another', function() {\n    let MyRegion;\n    let MyView;\n    let view1;\n    let view2;\n    let region;\n\n    beforeEach(function() {\n      MyRegion = Region.extend({\n        el: '#region'\n      });\n\n      MyView = Backbone.View.extend({\n        render: function() {\n          $(this.el).html('some content');\n        },\n\n        destroy: function() {}\n      });\n\n      _.extend(MyView.prototype, Events);\n\n      this.setFixtures('<div id=\"region\"></div><div id=\"pre-rendered\">content</div>');\n\n      view1 = new MyView();\n      view2 = new MyView();\n      region = new MyRegion();\n\n      this.sinon.spy(view1, 'destroy');\n\n      region.show(view1);\n      region.show(view2);\n    });\n\n    it('should call \"destroy\" on the already open view', function() {\n      expect(view1.destroy).to.have.been.called;\n    });\n\n    it('should call \"empty\" even if a new view is attached to the DOM', function() {\n\n      this.sinon.spy(region, 'empty');\n      const preRenderedView = new View({ el: '#pre-rendered' });\n\n      region.show(preRenderedView);\n      expect(region.empty).to.have.been.called;\n    });\n\n    it('should reference the new view as the current view', function() {\n      expect(region.currentView).to.equal(view2);\n    });\n\n  });\n\n  describe('when a view is already shown and showing the same one', function() {\n    let MyRegion;\n    let MyView;\n    let view;\n    let region;\n\n    beforeEach(function() {\n      MyRegion = Region.extend({\n        el: '#region'\n      });\n\n      MyView = Backbone.View.extend({\n        render: function() {\n          $(this.el).html('some content');\n        },\n        destroy: function() {},\n        attachHtml: function() {}\n      });\n\n      _.extend(MyView.prototype, Events);\n\n      this.setFixtures('<div id=\"region\"></div>');\n\n      view = new MyView();\n      region = new MyRegion();\n      region.show(view);\n\n      this.sinon.spy(view, 'destroy');\n      this.sinon.spy(region, 'attachHtml');\n      this.sinon.spy(view, 'render');\n      region.show(view);\n    });\n\n    it('should not call \"destroy\" on the view', function() {\n      expect(view.destroy).not.to.have.been.called;\n    });\n\n    it('should not call \"attachHtml\" on the view', function() {\n      expect(region.attachHtml).not.to.have.been.calledWith(view);\n    });\n\n    it('should not call \"render\" on the view', function() {\n      expect(view.render).not.to.have.been.called;\n    });\n\n  });\n\n  describe('when a Mn view is already shown but destroyed externally', function() {\n    let MyRegion;\n    let MyView;\n    let view;\n    let region;\n\n\n    beforeEach(function() {\n      MyRegion = Region.extend({\n        el: '#region'\n      });\n\n      MyView = View.extend({\n        template: _.template('<div></div>'),\n        open: function() {}\n      });\n\n      this.setFixtures('<div id=\"region\"></div>');\n\n      view = new MyView();\n      region = new MyRegion();\n      region.show(view);\n      view.destroy();\n\n      this.sinon.spy(view, 'destroy');\n      this.sinon.spy(region, 'attachHtml');\n      this.sinon.spy(view, 'render');\n    });\n\n    it('should not throw an error saying the views been destroyed if a destroyed view is passed in', function() {\n      expect(function() {\n        region.show(view);\n      }).not.to.throw(new RegExp('View (cid: \"' + view.cid +\n          '\") has already been destroyed and cannot be used.'));\n    });\n\n    describe('and destroyView is called', function() {\n      beforeEach(function() {\n        region.destroyView(view);\n      });\n\n      it('should not call view.destroy', function() {\n        expect(view.destroy).to.have.not.been.called;\n      })\n    })\n\n  });\n\n  describe('when a view is already destroyed and showing another', function() {\n    let MyRegion;\n    let MyView;\n    let view1;\n    let view2;\n    let region;\n\n    beforeEach(function() {\n      MyRegion = Region.extend({\n        el: '#region'\n      });\n\n      MyView = View.extend({\n        render: function() {\n          $(this.el).html('some content');\n        }\n      });\n\n      this.setFixtures('<div id=\"region\"></div>');\n\n      view1 = new MyView();\n      view2 = new MyView();\n      region = new MyRegion();\n\n      this.sinon.spy(view1, 'destroy');\n    });\n\n    it('shouldnt call \"destroy\" on an already destroyed view', function() {\n      region.show(view1);\n      view1.destroy();\n      region.show(view2);\n\n      expect(view1.destroy.callCount).to.equal(1);\n    });\n  });\n\n  describe('when calling empty', function() {\n    let MyRegion;\n    let MyView;\n    let view;\n    let region;\n\n    beforeEach(function() {\n      MyRegion = Region.extend({\n        el: '#region'\n      });\n\n      this.setFixtures('<div id=\"region\"></div>');\n      MyView = Backbone.View.extend({\n        render: function() {\n          $(this.el).html('some content');\n        },\n\n        destroy: function() {}\n      });\n\n      _.extend(MyView.prototype, Events);\n\n      region = new MyRegion();\n      view = new MyView();\n      this.sinon.spy(view, 'destroy');\n      region.show(view);\n    });\n\n    describe('without arguments', function() {\n      beforeEach(function() {\n        region.empty();\n      });\n      it('should destroy view', function() {\n        expect(view.destroy).to.have.been.called;\n      });\n    });\n  });\n\n  describe('when destroying the current view', function() {\n    let MyRegion;\n    let MyView;\n    let view;\n    let region;\n    let isSwappingOnEmpty;\n\n    beforeEach(function() {\n      const sinon = this.sinon;\n\n      MyRegion = Region.extend({\n        el: '#region',\n        onBeforeEmpty: sinon.stub(),\n        onEmpty: sinon.spy(function() {\n          isSwappingOnEmpty = this.isSwappingView();\n        })\n      });\n\n      MyView = Backbone.View.extend({\n        render: function() {\n          $(this.el).html('some content');\n        },\n\n        destroy: function() {}\n      });\n\n      _.extend(MyView.prototype, Events);\n\n      this.setFixtures('<div id=\"region\"></div>');\n\n      view = new MyView();\n      sinon.spy(view, 'destroy');\n      sinon.spy(view, '_removeElement');\n\n      region = new MyRegion();\n      sinon.spy(region, 'empty');\n      region.show(view);\n      region.empty();\n    });\n\n    it('should trigger a \"before:empty\" event with the view thats being destroyed', function() {\n      expect(region.onBeforeEmpty)\n        .to.have.been.calledOnce\n        .and.to.have.been.calledWith(region, view)\n        .and.to.have.been.calledOn(region);\n    });\n\n    it('should trigger a empty event', function() {\n      expect(region.onEmpty)\n        .to.have.been.calledOnce\n        .and.to.have.been.calledWith(region, view)\n        .and.to.have.been.calledOn(region);\n    });\n\n    it('should call \"destroy\" on the already show view', function() {\n      expect(view.destroy).to.have.been.called;\n    });\n\n    it('should not call \"_removeElement\" directly, on the view', function() {\n      expect(view._removeElement).not.to.have.been.called;\n    });\n\n    it('should delete the current view reference', function() {\n      expect(region.currentView).to.be.undefined;\n    });\n\n    it('should return the region', function() {\n      expect(region.empty).to.have.returned(region);\n    });\n\n    it('should return the region even when there was not a view to destroy', function() {\n      // The first empty() should have removed the view, this empty() call would be when there isn't a view\n      region.empty();\n      expect(region.empty.thirdCall).to.have.returned(region);\n    });\n\n    it('should not have a view', function() {\n      expect(region.hasView()).to.equal(false);\n    });\n\n    it('should not be swapping view', function() {\n      expect(isSwappingOnEmpty).to.be.false;\n    });\n  });\n\n  describe('when destroying the current view and it does not have a \"destroy\" method', function() {\n    let MyRegion;\n    let MyView;\n    let view;\n    let region;\n\n    beforeEach(function() {\n      MyRegion = Region.extend({\n        el: '<div></div>'\n      });\n\n      MyView = Backbone.View.extend({\n        render: function() {\n          $(this.el).html('some content');\n        }\n      });\n      _.extend(MyView.prototype, Events);\n\n      view = new MyView();\n      this.sinon.spy(view, '_removeElement');\n      region = new MyRegion();\n      region.show(view);\n      region.empty();\n    });\n\n    it('should call \"_removeElement\" on the view', function() {\n      expect(view._removeElement).to.have.been.called;\n    });\n\n    it('should set \"_isDestroyed\" on the view', function() {\n      expect(view._isDestroyed).to.be.true;\n    });\n\n    describe('and then attempting to show the view again in the Region', function() {\n      let showFunction;\n\n      beforeEach(function() {\n        showFunction = function() {\n          region.show(view);\n        };\n      });\n\n      it('should throw an error.', function() {\n        const errorMessage = 'View (cid: \"' + view.cid + '\") has already been destroyed and cannot be used.';\n        expect(showFunction).to.throw(errorMessage);\n      });\n    });\n  });\n\n  describe('when initializing a region and passing an \"el\" option', function() {\n    let el;\n    let region;\n\n    beforeEach(function() {\n      el = '#foo';\n      region = new Region({\n        el: el\n      });\n    });\n\n    it('should manage the specified el', function() {\n      expect(region.el).to.equal(el);\n    });\n  });\n\n  describe('when creating a region instance with an initialize method', function() {\n    let expectedOptions;\n    let MyRegion;\n\n    beforeEach(function() {\n      expectedOptions = {foo: 'bar'};\n      MyRegion = Region.extend({\n        el: '#foo',\n        initialize: function() {}\n      });\n\n      this.sinon.spy(MyRegion.prototype, 'initialize');\n\n      new MyRegion(expectedOptions);\n    });\n\n    it('should call the initialize method with the options from the constructor', function() {\n      expect(MyRegion.prototype.initialize).to.have.been.calledWith(expectedOptions);\n    });\n  });\n\n  describe('when removing a region', function() {\n    let itemView;\n    let region;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"region\"></div><div id=\"region2\"></div>');\n\n      itemView = new View();\n      itemView.template = function() {\n        return 'content';\n      };\n      itemView.addRegions({\n        MyRegion: '#region',\n        anotherRegion: '#region2'\n      });\n\n      region = itemView.getRegion('MyRegion');\n      this.sinon.spy(region, 'empty');\n\n      itemView.removeRegion('MyRegion');\n    });\n\n    it('should be removed from the view', function() {\n      expect(itemView.getRegion('MyRegion')).to.be.undefined;\n    });\n\n    it('should call \"empty\" of the region', function() {\n      expect(region.empty).to.have.been.called;\n    });\n  });\n\n  describe('when getting a region', function() {\n    let itemView;\n    let region;\n\n    beforeEach(function() {\n      itemView = new View();\n      itemView.render = this.sinon.stub();\n      itemView.addRegions({\n        MyRegion: '#region',\n        anotherRegion: '#region2'\n      });\n\n      region = itemView._regions.MyRegion;\n    });\n\n    it('should return the region', function() {\n      expect(itemView.getRegion('MyRegion')).to.equal(region);\n    });\n\n    it('should call render if getRegion is called without being rendered', function() {\n      itemView.getRegion('whoCares');\n      expect(itemView.render).to.be.calledOnce;\n    });\n  });\n\n  describe('when resetting a region', function() {\n    let region;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"region\"></div>');\n\n      region = new Region({\n        el: '#region'\n      });\n\n      this.sinon.spy(region, 'empty');\n\n      region.show(new View({ template: false }));\n\n      this.sinon.spy(region, 'reset');\n      region.reset();\n    });\n\n    it('should not hold on to the regions previous \"el\"', function() {\n      expect(region.$el).not.to.exist;\n    });\n\n    it('should empty any existing view', function() {\n      expect(region.empty).to.have.been.called;\n    });\n\n    it('should return the region', function() {\n      expect(region.reset).to.have.returned(region);\n    });\n  });\n\n  describe('when destroying a region', function() {\n    let region;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"region\"></div>');\n\n      region = new Region({\n        el: '#region'\n      });\n\n      this.sinon.spy(region, 'reset');\n\n      this.sinon.spy(region, 'destroy');\n      region.destroy();\n    });\n\n    it('should reset the region', function() {\n      expect(region.reset).to.have.been.called;\n    });\n\n    it('should return the region', function() {\n      expect(region.destroy).to.have.returned(region);\n    });\n\n    describe('when the region is already destroyed', function() {\n      it('should not reset the region', function() {\n        region.reset.resetHistory();\n        region.destroy();\n        expect(region.reset).to.not.have.been.called;\n      });\n\n      it('should return the region', function() {\n        region.destroy.resetHistory();\n        region.destroy();\n        expect(region.destroy).to.have.returned(region);\n      });\n    });\n  });\n\n  describe('when destroying a Mn view in a region', function() {\n    let beforeEmptySpy;\n    let emptySpy;\n    let onBeforeDestroy;\n    let onDestroy;\n    let MyView;\n    let region;\n    let view;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"region\"></div>');\n      beforeEmptySpy = new sinon.spy();\n      emptySpy = new sinon.spy();\n      onBeforeDestroy = this.sinon.stub();\n      onDestroy = this.sinon.stub();\n\n      region = new Region({\n        el: '#region'\n      });\n\n      region.on('before:empty', beforeEmptySpy);\n      region.on('empty', emptySpy);\n\n      MyView = View.extend({\n        template: _.template('')\n      });\n\n      view = new MyView();\n\n      view.on('before:destroy', onBeforeDestroy);\n      view.on('destroy', onDestroy);\n\n      region.show(view);\n      region.currentView.destroy();\n    });\n\n    it('should remove the view from the region after being destroyed', function() {\n      expect(beforeEmptySpy).to.have.been.calledOnce.and.calledWith(region, view);\n      expect(emptySpy).to.have.been.calledOnce.calledWith(region, view);\n      expect(region.currentView).to.be.undefined;\n    });\n\n    it('view \"before:destroy\" event is triggered once', function() {\n      expect(onBeforeDestroy).to.have.been.calledOnce;\n    });\n\n    it('view \"destroy\" event is triggered once', function() {\n      expect(onDestroy).to.have.been.calledOnce;\n    });\n  });\n\n  describe('when showing undefined in a region', function() {\n    let insertUndefined;\n    let region;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"region\"></div>');\n\n      region = new Region({\n        el: '#region'\n      });\n\n      insertUndefined = function() {\n        region.show(undefined);\n      }.bind(this);\n    });\n\n    it('should throw an error', function() {\n      const errorMessage = 'The view passed is undefined and therefore invalid. You must pass a view instance to show.';\n      expect(insertUndefined).to.throw(errorMessage);\n    });\n  });\n\n  describe('when showing a Backbone.View child view', function() {\n    let BbView;\n    let region;\n    let view;\n\n    beforeEach(function() {\n      BbView = Backbone.View.extend({\n        onBeforeRender: this.sinon.stub(),\n        onRender: this.sinon.stub(),\n        onBeforeDestroy: this.sinon.stub(),\n        onDestroy: this.sinon.stub()\n      });\n      _.extend(BbView.prototype, Events);\n\n      region = new Region({\n        el: $('<div></div>')\n      });\n      view = new BbView();\n      region.show(view);\n    });\n\n    it('should fire before:render and render on the child view on show', function() {\n      expect(view.onBeforeRender)\n        .to.have.been.calledOnce\n        .and.to.have.been.calledOn(view)\n        .and.to.have.been.calledWith(view);\n      expect(view.onRender)\n        .to.have.been.calledOnce\n        .and.to.have.been.calledOn(view)\n        .and.to.have.been.calledWith(view);\n    });\n\n    describe('when emptying while containing the Backbone.View', function() {\n      beforeEach(function() {\n        region.empty();\n      });\n\n      it('should fire before:destroy and destroy on the child view on show', function() {\n        expect(view.onBeforeDestroy)\n          .to.have.been.calledOnce\n          .and.to.have.been.calledOn(view)\n          .and.to.have.been.calledWith(view);\n        expect(view.onDestroy)\n          .to.have.been.calledOnce\n          .and.to.have.been.calledOn(view)\n          .and.to.have.been.calledWith(view);\n      });\n    });\n  });\n\n  describe('when calling \"_ensureElement\"', function() {\n    let region;\n\n    beforeEach(function() {\n      region = new Region({\n        el: '#region'\n      });\n    });\n\n    it('should prefer passed options over initial options', function() {\n      region.allowMissingEl = false;\n\n      expect(region._ensureElement({allowMissingEl: true})).to.be.false;\n    });\n\n    it('should fallback to initial options when not passed options', function() {\n      region.allowMissingEl = false;\n\n      expect(function() {\n        region._ensureElement();\n      }.bind(this)).to.throw;\n    });\n  });\n\n  // This is a terrible example of an edge-case where something related to the view's destroy\n  // may also want to empty the same region.\n  describe('when emptying a region destroys a view that empties the same region', function() {\n    let MyRegion;\n    let region;\n    let MyView;\n\n    it('should only empty once', function() {\n      this.setFixtures('<div id=\"region\"></div>');\n\n      MyRegion = Region.extend({\n        el: '#region',\n        onEmpty: this.sinon.stub(),\n      });\n\n      region = new MyRegion();\n      MyView = View.extend({\n        template: _.noop,\n        onDestroy: function() {\n          region.empty();\n        }\n      });\n      region.show(new MyView());\n      region.empty();\n\n      expect(region.onEmpty).to.have.been.calledOnce;\n    });\n  });\n\n  describe('when emptying a region with no view and preexisting html', function() {\n    let MyRegion;\n    let region;\n\n    beforeEach(function() {\n      MyRegion = Region.extend({\n        el: '#region',\n      });\n    });\n\n    it('should clear the region contents', function() {\n      this.setFixtures('<div id=\"region\">Preexisting HTML</div>');\n      region = new MyRegion();\n      region.empty();\n      expect(region.$el.html()).to.eql('');\n    });\n\n    // In the future, hopefully allowMissingEl can default to true\n    describe('when no el exists while passing allowMissingEl: false', function() {\n      it('should throw an error', function() {\n        region = new MyRegion();\n        expect(function() {\n          region.empty({ allowMissingEl: false });\n        }).to.throw('An \"el\" must exist in DOM for this region ' + region.cid);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/utils/deprecate.spec.js",
    "content": "import deprecate from '../../../src/utils/deprecate';\n\nimport {setEnabled} from '../../../src/config/features';\n\ndescribe('deprecate', function() {\n  beforeEach(function() {\n    setEnabled('DEV_MODE', true);\n    this.sinon.spy(deprecate, '_warn');\n    this.sinon.stub(deprecate._console, 'warn');\n    this.sinon.stub(deprecate._console, 'log');\n\n    deprecate._cache = {};\n  });\n\n  afterEach(function() {\n    setEnabled('DEV_MODE', false);\n  });\n\n  describe('#_warn', function() {\n    it('should `console.warn` the message', function() {\n      deprecate._warn('foo');\n      expect(deprecate._console.warn)\n        .to.have.been.calledOnce\n        .and.calledOn(deprecate._console)\n        .and.calledWith('foo');\n    });\n\n    describe('when `console.warn` does not exist', function() {\n      beforeEach(function() {\n        deprecate._console.warn = null;\n      });\n\n      it('should `console.log` the message', function() {\n        deprecate._warn('foo');\n        expect(deprecate._console.log)\n          .to.have.been.calledOnce\n          .and.calledOn(deprecate._console)\n          .and.calledWith('foo');\n      });\n\n      describe('when `console.log` does not exist', function() {\n        it('should call `_.noop`', function() {\n          deprecate._console.log = null;\n          this.sinon.spy(_, 'noop');\n          deprecate._warn('foo');\n\n          expect(_.noop).to.have.been.calledOnce;\n        });\n      });\n    });\n  });\n\n  describe('when calling with a message', function() {\n    beforeEach(function() {\n      deprecate('foo');\n    });\n\n    it('should `console.warn` the message', function() {\n      expect(deprecate._warn)\n        .to.have.been.calledOnce\n        .and.calledWith('Deprecation warning: foo');\n    });\n  });\n\n  describe('when calling with an object', function() {\n    beforeEach(function() {\n      deprecate({\n        prev: 'foo',\n        next: 'bar'\n      });\n    });\n\n    it('should `console.warn` the message', function() {\n      expect(deprecate._warn)\n        .to.have.been.calledOnce\n        .and.calledWith('Deprecation warning: foo is going to be removed in the future. Please use bar instead.');\n    });\n  });\n\n  describe('when calling with an object with a url', function() {\n    beforeEach(function() {\n      deprecate({\n        prev: 'foo',\n        next: 'bar',\n        url: 'baz'\n      });\n    });\n\n    it('should `console.warn` the message', function() {\n      expect(deprecate._warn)\n        .to.have.been.calledOnce\n        .and.calledWith('Deprecation warning: foo is going to be removed in the future. Please use bar instead. See: baz');\n    });\n  });\n\n  describe('when calling with a message and a falsy test', function() {\n    beforeEach(function() {\n      deprecate('bar', false);\n    });\n\n    it('should `console.warn` the message', function() {\n      expect(deprecate._warn)\n        .to.have.been.calledOnce\n        .and.calledWith('Deprecation warning: bar');\n    });\n  });\n\n  describe('when calling with a message and a truthy test', function() {\n    beforeEach(function() {\n      deprecate('Foo', true);\n    });\n\n    it('should not `console.warn` the message', function() {\n      expect(deprecate._warn).not.to.have.been.called;\n    });\n  });\n\n  describe('when calling with the same message twice', function() {\n    beforeEach(function() {\n      deprecate('baz');\n      deprecate('baz');\n    });\n\n    it('should `console.warn` the message', function() {\n      expect(deprecate._warn)\n        .to.have.been.calledOnce\n        .and.calledWith('Deprecation warning: baz');\n    });\n  });\n\n  describe('when calling in production mode', function() {\n    beforeEach(function() {\n      setEnabled('DEV_MODE', false);\n      deprecate('baz');\n    });\n\n    it('should `console.warn` the message', function() {\n      expect(deprecate._warn).to.not.have.been.called;\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/utils/error.spec.js",
    "content": "import { VERSION } from '../../../src/backbone.marionette';\nimport MarionetteError from '../../../src/utils/error';\n\ndescribe('MarionetteError', function() {\n  it('should be subclass of native Error', function() {\n    expect(new MarionetteError({ message: 'foo' })).to.be.instanceOf(Error);\n  });\n\n  describe('when passed options', function() {\n    let error;\n\n    beforeEach(function() {\n      error = new MarionetteError({\n        name: 'Foo',\n        message: 'Bar'\n      });\n    });\n\n    it('should contain the correct properties', function() {\n      expect(error).to.contain({\n        name: 'Foo',\n        message: 'Bar'\n      });\n    });\n\n    it('should output the correct string', function() {\n      expect(error.toString()).to.equal('Foo: Bar See: http://marionettejs.com/docs/v' + VERSION + '/');\n    });\n  });\n\n  describe('when passed options with a url', function() {\n    let error;\n\n    beforeEach(function() {\n      error = new MarionetteError({\n        name: 'Foo',\n        message: 'Bar',\n        url: 'Baz'\n      });\n    });\n\n    it('should contain the correct properties', function() {\n      expect(error).to.contain({\n        name: 'Foo',\n        message: 'Bar',\n        url: 'http://marionettejs.com/docs/v' + VERSION + '/Baz'\n      });\n    });\n\n    it('should output the correct string', function() {\n      expect(error.toString()).to.equal('Foo: Bar See: http://marionettejs.com/docs/v' + VERSION + '/Baz');\n    });\n  });\n\n  describe('when passed valid error properties', function() {\n    let props;\n    let error;\n\n    beforeEach(function() {\n      props = {\n        description: 'myDescription',\n        fileName: 'myFileName',\n        lineNumber: 'myLineNumber',\n        name: 'myName',\n        message: 'myMessage',\n        number: 'myNumber'\n      };\n      error = new MarionetteError(props);\n    });\n\n    it('should contain all the valid error properties', function() {\n      expect(error).to.contain(props);\n    });\n  });\n\n  describe('when passed invalid error properties', function() {\n    let props;\n    let error;\n\n    beforeEach(function() {\n      props = {\n        foo: 'myFoo',\n        bar: 'myBar',\n        baz: 'myBaz'\n      };\n      error = new MarionetteError(props);\n    });\n\n    it('should not contain invalid properties', function() {\n      expect(error).not.to.contain(props);\n    });\n  });\n\n  describe('when Error.captureStackTrace is unavailable', function() {\n    let captureStackTrace = Error.captureStackTrace;\n\n    beforeEach(function() {\n      this.sinon.spy(MarionetteError.prototype, 'captureStackTrace');\n      Error.captureStackTrace = undefined;\n    });\n\n    afterEach(function() {\n      Error.captureStackTrace = captureStackTrace;\n    });\n\n    it('should not captureStackTrace', function() {\n      new MarionetteError({ message: 'foo' });\n      expect(MarionetteError.prototype.captureStackTrace).to.not.be.called;\n    });\n  })\n});\n"
  },
  {
    "path": "test/unit/utils/get-namespaced-event-name.spec.js",
    "content": "import getNamespacedEventName from '../../../src/utils/get-namespaced-event-name';\n\ndescribe('getNamespacedEventName', function() {\n  it('should postfix a namespace to the event', function() {\n    expect(getNamespacedEventName('click a.name', 'test')).to.equal('click.test a.name');\n  });\n});\n"
  },
  {
    "path": "test/unit/utils/proxy.spec.js",
    "content": "import proxy from '../../../src/utils/proxy';\n\ndescribe('proxy', function() {\n  let method;\n\n  beforeEach(function() {\n    method = this.sinon.stub();\n  });\n\n  it('should return a function', function() {\n    expect(proxy(method)).to.be.a('function');\n  });\n\n  describe('when calling the returned function', function() {\n    it('should call the method on context with all arguments', function() {\n      const context = {};\n      const proxiedMethod = proxy(method);\n\n      proxiedMethod(context, 1, 2, 3);\n\n      expect(method).to.be.calledOn(context).and.calledWith(1,2,3);\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/view.child-views.spec.js",
    "content": "describe('layoutView', function() {\n  'use strict';\n\n  beforeEach(function() {\n    this.layoutViewManagerTemplateFn = _.template('<div id=\"regionOne\"></div><div id=\"regionTwo\"></div>');\n    this.template = function() {\n      return '<span class=\".craft\"></span><h1 id=\"#a-fun-game\"></h1>';\n    };\n\n    this.View = Backbone.Marionette.View.extend({\n      template: this.layoutViewManagerTemplateFn,\n      regions: {\n        regionOne: '#regionOne',\n        regionTwo: '#regionTwo'\n      },\n      initialize: function() {\n        if (this.model) {\n          this.listenTo(this.model, 'change', this.render);\n        }\n      },\n      onBeforeRender: function() {\n        return this.isRendered();\n      },\n      onRender: function() {\n        return this.isRendered();\n      }\n    });\n\n    this.CustomRegion1 = function() {};\n\n    this.CustomRegion2 = Backbone.Marionette.Region.extend();\n\n    this.ViewNoDefaultRegion = this.View.extend({\n      regions: {\n        regionOne: {\n          selector: '#regionOne',\n          regionClass: this.CustomRegion1\n        },\n        regionTwo: '#regionTwo'\n      }\n    });\n  });\n\n  describe('on instantiation', function() {\n    beforeEach(function() {\n      let suite = this;\n      this.ViewInitialize = this.View.extend({\n        initialize: function() {\n          suite.regionOne = this.getRegion('regionOne');\n        }\n      });\n\n      this.layoutViewManager = new this.ViewInitialize();\n    });\n\n    it('should instantiate the specified region before initialize', function() {\n      expect(this.regionOne).to.equal(this.layoutViewManager.getRegion('regionOne'));\n    });\n\n    it('should create backlink with region manager', function() {\n      it('should instantiate the specified region managers', function() {\n        expect(this.layoutViewManager._parent).to.deep.equal(this.layoutViewManager);\n      });\n    });\n  });\n\n  describe('on instantiation with no regions defined', function() {\n    beforeEach(function() {\n      let suite = this;\n      this.NoRegions = Marionette.View.extend({});\n      this.init = function() {\n        suite.layoutViewManager = new suite.NoRegions();\n      };\n    });\n\n    it('should instantiate the specified region managers', function() {\n      expect(this.init).not.to.throw;\n    });\n  });\n\n  describe('on instantiation with custom region managers', function() {\n    beforeEach(function() {\n      this.ViewCustomRegion = this.View.extend({\n        regionClass: this.CustomRegion1,\n        regions: {\n          regionOne: {\n            el: '#regionOne',\n            regionClass: this.CustomRegion1\n          },\n          regionTwo: {\n            el: '#regionTwo',\n            regionClass: this.CustomRegion2,\n            specialOption: true\n          },\n          regionThree: {\n            el: '#regionThree'\n          },\n          regionFour: '#regionFour'\n        }\n      });\n\n      this.layoutViewManager = new this.ViewCustomRegion();\n    });\n\n    it('should instantiate specific regions with custom regions if specified', function() {\n      expect(this.layoutViewManager.getRegion('regionOne')).to.be.instanceof(this.CustomRegion1);\n      expect(this.layoutViewManager.getRegion('regionTwo')).to.be.instanceof(this.CustomRegion2);\n    });\n\n    it('should instantiate the default regionManager if specified', function() {\n      expect(this.layoutViewManager.getRegion('regionThree')).to.be.instanceof(this.CustomRegion1);\n      expect(this.layoutViewManager.getRegion('regionThree')).to.be.instanceof(this.CustomRegion1);\n    });\n\n    it('should instantiate marionette regions is no regionClass is specified', function() {\n      let layoutViewManagerNoDefault = new this.ViewNoDefaultRegion();\n      expect(layoutViewManagerNoDefault.getRegion('regionTwo')).to.be.instanceof(Backbone.Marionette.Region);\n    });\n\n    it('should pass extra options to the custom regionClass', function() {\n      expect(this.layoutViewManager.getRegion('regionTwo')).to.have.property('options');\n      expect(this.layoutViewManager.getRegion('regionTwo').options).to.have.property('specialOption');\n      expect(this.layoutViewManager.getRegion('regionTwo').options.specialOption).to.be.ok;\n    });\n  });\n\n  describe('when regions are defined as a function', function() {\n    beforeEach(function() {\n      const View = this.View.extend({\n        regions: function() {\n          return {\n            regionOne: '#regionOne',\n            regionTwo: '#regionTwo'\n          };\n        }\n      });\n\n      this.layoutView = new View();\n      this.layoutView.render();\n    });\n\n    it('should build the regions from the returns object literal', function() {\n      expect(this.layoutView.getRegion('regionOne')).to.be.instanceof(Backbone.Marionette.Region);\n    });\n  });\n\n  describe('on rendering', function() {\n    beforeEach(function() {\n      this.layoutViewManager = new this.View();\n      sinon.spy(this.layoutViewManager, 'onRender');\n      sinon.spy(this.layoutViewManager, 'onBeforeRender');\n      sinon.spy(this.layoutViewManager, 'trigger');\n      this.layoutViewManager.render();\n    });\n\n    it('should find the region scoped within the rendered template', function() {\n      this.layoutViewManager.getRegion('regionOne')._ensureElement();\n      let el = this.layoutViewManager.$('#regionOne');\n      expect(this.layoutViewManager.getRegion('regionOne').$el[0]).to.equal(el[0]);\n    });\n\n    it('should call \"onBeforeRender\" before rendering', function() {\n      expect(this.layoutViewManager.onBeforeRender).to.have.been.calledOnce;\n    });\n\n    it('should call \"onRender\" after rendering', function() {\n      expect(this.layoutViewManager.onRender).to.have.been.calledOnce;\n    });\n\n    it('should call \"onBeforeRender\" before \"onRender\"', function() {\n      expect(this.layoutViewManager.onBeforeRender).to.have.been.calledBefore(this.layoutViewManager.onRender);\n    });\n\n    it('should not be rendered when \"onBeforeRender\" is called', function() {\n      expect(this.layoutViewManager.onBeforeRender.lastCall.returnValue).not.to.be.ok;\n    });\n\n    it('should be rendered when \"onRender\" is called', function() {\n      expect(this.layoutViewManager.onRender.lastCall.returnValue).to.be.true;\n    });\n\n    it('should trigger a \"before:render\" event', function() {\n      expect(this.layoutViewManager.trigger).to.have.been.calledWith('before:render', this.layoutViewManager);\n    });\n\n    it('should trigger a \"render\" event', function() {\n      expect(this.layoutViewManager.trigger).to.have.been.calledWith('render', this.layoutViewManager);\n    });\n\n    it('should be marked rendered', function() {\n      expect(this.layoutViewManager).to.have.property('_isRendered', true);\n    });\n  });\n\n  describe('when destroying', function() {\n\n    beforeEach(function() {\n      this.layoutViewManager = new this.View();\n      $('<span id=\"parent\">').append(this.layoutViewManager.el);\n      this.layoutViewManager.render();\n\n      this.regionOne = this.layoutViewManager.getRegion('regionOne');\n      this.regionTwo = this.layoutViewManager.getRegion('regionTwo');\n\n      const View = Marionette.View.extend({\n        template: _.noop,\n        destroy: function() {\n          this.hadParent = this.$el.closest('#parent').length > 0;\n          return View.__super__.destroy.call(this);\n        }\n      });\n\n      this.regionOneView = new View();\n      this.sinon.spy(this.regionOne, 'empty');\n      this.sinon.spy(this.regionTwo, 'empty');\n\n      this.regionOne.show(this.regionOneView);\n\n      this.sinon.spy(this.layoutViewManager, 'destroy');\n      this.layoutViewManager.destroy();\n      this.layoutViewManager.destroy();\n    });\n\n    it('should empty the region managers', function() {\n      expect(this.regionOne.empty).to.have.been.calledTwice;\n      expect(this.regionTwo.empty).to.have.been.calledOnce;\n    });\n\n    it('should delete the region managers', function() {\n      expect(this.layoutViewManager.getRegion('regionOne')).to.be.undefined;\n      expect(this.layoutViewManager.getRegion('regionTwo')).to.be.undefined;\n    });\n\n    it('should return the view', function() {\n      expect(this.layoutViewManager.destroy).to.have.always.returned(this.layoutViewManager);\n    });\n\n    it('should remove itself from the DOM before destroying child regions by default', function() {\n      expect(this.regionOneView.hadParent).to.be.false;\n    });\n\n    it('should be marked destroyed', function() {\n      expect(this.layoutViewManager).to.have.property('_isDestroyed', true);\n    });\n\n    it('should be marked not rendered', function() {\n      expect(this.layoutViewManager).to.have.property('_isRendered', false);\n    });\n  });\n\n  describe('when showing a childView as a basic Backbone.View', function() {\n    beforeEach(function() {\n      const BBView = Backbone.View.extend();\n      _.extend(BBView.prototype, Marionette.Events);\n\n      this.layoutView = new this.View();\n      this.layoutView.render();\n\n      // create a basic Backbone child view\n      this.childView = new BBView();\n      this.layoutView.showChildView('regionOne', this.childView);\n    });\n\n    it('shows the childview in the region', function() {\n      expect(this.layoutView.getChildView('regionOne')).to.equal(this.childView);\n    });\n  });\n\n  describe('when using showChildView with options', function() {\n    let options = {myOption: 'some value'};\n\n    beforeEach(function() {\n      const BBView = Backbone.View.extend();\n      _.extend(BBView.prototype, Marionette.Events);\n\n      this.layoutView = new this.View().render();\n      this.regionOne = this.layoutView.getRegion('regionOne');\n      this.childView = new BBView();\n      this.sinon.spy(this.regionOne, 'show');\n      this.layoutView.showChildView('regionOne', this.childView, options);\n    });\n\n    it('passes the options hash to the region', function() {\n      expect(this.regionOne.show)\n        .to.have.been.calledOnce\n        .and.calledWith(this.childView, options);\n    });\n  });\n\n  describe('when showing a childView as a View', function() {\n    beforeEach(function() {\n      this.layoutView = new this.View();\n      this.childEventsHandlerTrigger = this.sinon.spy();\n      this.childEventsHandlerTriggerMethod = this.sinon.spy();\n\n      // add child events to listen for\n      this.layoutView.childViewEvents = {\n        'before:content:rendered': this.childEventsHandlerTrigger,\n        'content:rendered': this.childEventsHandlerTriggerMethod\n      };\n      this.layoutView.delegateEvents();\n      this.layoutView.render();\n\n      // create a child view which triggers an event on render\n      let ChildView = Marionette.View.extend({\n        template: _.noop,\n        onBeforeRender: function() {\n          this.trigger('before:content:rendered');\n        },\n        onRender: function() {\n          this.triggerMethod('content:rendered');\n        }\n      });\n      this.childView = new ChildView();\n\n      this.layoutView.showChildView('regionOne', this.childView);\n    });\n\n    it('shows the childview in the region', function() {\n      expect(this.layoutView.getChildView('regionOne')).to.equal(this.childView);\n    });\n\n    it('childViewEvents are triggered', function() {\n      expect(this.childEventsHandlerTrigger).to.have.been.calledOnce;\n    });\n\n    it('childViewEvents are triggered', function() {\n      expect(this.childEventsHandlerTriggerMethod).to.have.been.calledOnce;\n    });\n\n    describe('and the view is detached', function() {\n      beforeEach(function() {\n        this.detachedView = this.layoutView.detachChildView('regionOne');\n        this.noDetachedView = this.layoutView.detachChildView('regionOne');\n      });\n\n      it('should return the childView it was given', function() {\n        expect(this.detachedView).to.equal(this.childView);\n      });\n\n      it('should not return a childView if it was already detached', function() {\n        expect(this.noDetachedView).to.be.undefined;\n      });\n    });\n  });\n\n  describe('when showing a layoutView via a region', function() {\n    beforeEach(function() {\n      let suite = this;\n\n      this.setFixtures('<div id=\"mgr\"></div>');\n\n      this.layoutView = new this.View();\n      this.layoutView.onRender = function() {\n        suite.regionOne = suite.layoutView.getRegion('regionOne');\n        suite.regionOne._ensureElement();\n      };\n\n      this.region = new Backbone.Marionette.Region({\n        el: '#mgr'\n      });\n\n      this.showReturn = this.region.show(this.layoutView);\n    });\n\n    it('should make the regions available in `onRender`', function() {\n      expect(this.regionOne).to.exist;\n    });\n\n    it('the regions should find their elements in `onRender`', function() {\n      expect(this.regionOne.$el.length).to.equal(1);\n    });\n\n    it('should return the region after showing a view in a region', function() {\n      expect(this.showReturn).to.equal(this.region);\n    });\n  });\n\n  describe('when destroying a childView as a View', function() {\n    beforeEach(function() {\n      this.childEventsHandler = this.sinon.spy();\n      this.layoutView = new this.View({\n        childViewEvents: {\n          'destroy': this.childEventsHandler\n        }\n      });\n\n      this.layoutView.render();\n\n      // create a child view which triggers an event on render\n      let ChildView = Marionette.View.extend({\n        template: _.noop\n      });\n      this.childView = new ChildView();\n\n      this.layoutView.showChildView('regionOne', this.childView);\n      this.childView.destroy();\n    });\n\n    it('childViewEvents \"destroy\" method is triggered', function() {\n      expect(this.childEventsHandler).to.have.been.calledOnce;\n    });\n  });\n\n  describe('when destroying the childView destroys the parent', function() {\n    let layoutView;\n\n    beforeEach(function() {\n      const LayoutView = Marionette.View.extend({\n        childViewEvents: {\n          'destroy': 'destroy'\n        },\n        template: _.template('<div id=\"regionOne\"></div>'),\n        regions: {\n          regionOne: '#regionOne'\n        }\n      });\n\n      layoutView = new LayoutView();\n\n      const childView = new Marionette.View({\n        template: _.noop\n      });\n\n      layoutView.showChildView('regionOne', childView);\n    });\n\n    it('should not throw any errors', function() {\n      expect(function() { layoutView.destroy(); }).to.not.throw();\n    });\n  });\n\n  describe('when re-rendering an already rendered layoutView', function() {\n    beforeEach(function() {\n      const BBView = Backbone.View.extend();\n      _.extend(BBView.prototype, Marionette.Events);\n\n      this.ViewBoundRender = this.View.extend({\n        initialize: function() {\n          if (this.model) {\n            this.listenTo(this.model, 'change', this.render);\n          }\n        }\n      });\n\n      this.layoutView = new this.ViewBoundRender({\n        model: new Backbone.Model()\n      });\n      this.layoutView.render();\n\n      this.sinon.spy(this.layoutView.getRegion('regionOne'), 'empty');\n      this.view = new BBView();\n      this.view.destroy = function() {};\n      this.layoutView.getRegion('regionOne').show(this.view);\n\n      this.layoutView.render();\n      this.layoutView.getRegion('regionOne').show(this.view);\n      this.region = this.layoutView.getRegion('regionOne');\n    });\n\n    it('should re-bind the regions to the newly rendered elements', function() {\n      expect(this.region.$el.parent()[0]).to.equal(this.layoutView.el);\n    });\n\n    it('triggers \"before:render\" before emptying the regions', function() {\n      let cb = function() {\n        expect(this.region.$el).to.exist;\n      };\n      this.layoutView.listenTo(this.layoutView, 'before:render', cb.bind(this));\n      this.layoutView.render();\n    });\n\n    it('should call empty twice', function() {\n      expect(this.region.empty).to.have.been.calledThrice;\n    });\n\n    describe('and the views \"render\" function is bound to an event in the \"initialize\" function', function() {\n      beforeEach(function() {\n        let suite = this;\n        this.layoutView.onRender = function() {\n          this.getRegion('regionOne').show(suite.view);\n        };\n\n        this.layoutView.model.trigger('change');\n      });\n\n      it('should re-bind the regions correctly', function() {\n        expect(this.layoutView.$('#regionOne')).not.to.equal();\n      });\n    });\n  });\n\n  describe('when getting a region', function() {\n    beforeEach(function() {\n      this.layoutView = new this.View();\n      this.region = this.layoutView.getRegion('regionOne');\n    });\n\n    it('should return the region', function() {\n      expect(this.layoutView.getRegion('regionOne')).to.equal(this.region);\n    });\n  });\n\n  describe('when checking for a region', function() {\n    beforeEach(function() {\n      this.layoutView = new this.View();\n      this.region = this.layoutView.getRegion('regionOne');\n    });\n\n    it('should return if has the region', function() {\n      expect(this.layoutView.hasRegion('regionOne')).to.equal(true);\n      expect(this.layoutView.hasRegion('regionNone')).to.equal(false);\n    });\n  });\n\n  describe('when adding regions in a layoutViews options', function() {\n    beforeEach(function() {\n      let suite = this;\n\n      this.CustomRegion = this.sinon.spy();\n      this.regionOptions = {\n        war: '.craft',\n        is: {\n          regionClass: this.CustomRegion,\n          selector: '#a-fun-game'\n        }\n      };\n\n      this.layoutView = new Backbone.Marionette.View({\n        template: this.template,\n        regions: this.regionOptions\n      });\n\n      this.layoutView2 = new Backbone.Marionette.View({\n        template: this.template,\n        regions: function() {\n          return suite.regionOptions;\n        }\n      });\n    });\n\n    it('should lookup and set the regions', function() {\n      expect(this.layoutView.getRegion('is')).to.exist;\n      expect(this.layoutView.getRegion('war')).to.exist;\n    });\n\n    it('should lookup and set the regions when passed a function', function() {\n      expect(this.layoutView2.getRegion('is')).to.exist;\n      expect(this.layoutView2.getRegion('war')).to.exist;\n    });\n\n    it('should set custom region classes', function() {\n      expect(this.CustomRegion).to.have.been.called;\n    });\n  });\n\n  describe('when defining region selectors using @ui. syntax', function() {\n    beforeEach(function() {\n      let UIView = Backbone.Marionette.View.extend({\n        template: this.template,\n        regions: {\n          war: '@ui.war',\n          mario: {\n            el: '@ui.mario'\n          },\n          princess: {\n            el: '@ui.princess'\n          }\n        },\n        ui: {\n          war: '.craft',\n          mario: '.bros',\n          princess: '.toadstool'\n        }\n      });\n      this.layoutView = new UIView();\n    });\n\n    it('should apply the relevant @ui. syntax selector to a simple string value', function() {\n      expect(this.layoutView.getRegion('war')).to.exist;\n    });\n    it('should apply the relevant @ui. syntax selector to selector in a region definition object', function() {\n      expect(this.layoutView.getRegion('mario')).to.exist;\n    });\n    it('should apply the relevant @ui. syntax selector to el in a region definition object', function() {\n      expect(this.layoutView.getRegion('princess')).to.exist;\n    });\n  });\n\n  describe('when a layout has regions', function() {\n    beforeEach(function() {\n      this.layout = new this.View();\n    });\n\n    it('should be able to retrieve all regions', function() {\n      this.layout.render();\n      this.regions = this.layout.getRegions();\n      expect(this.regions.regionOne).to.equal(this.layout.getRegion('regionOne'));\n      expect(this.regions.regionTwo).to.equal(this.layout.getRegion('regionTwo'));\n    });\n\n    it('should render the view if it hasn\\'t been yet', function() {\n      this.sinon.spy(this.layout, 'render');\n      this.layout.getRegions();\n      expect(this.layout.render).to.be.calledOnce;\n    });\n\n    describe('when the regions are specified via regions hash and the view has no template', function() {\n      beforeEach(function() {\n        let fixture =\n          '<div class=\"region-hash-no-template-spec\">' +\n            '<div class=\"region-one\">Out-of-scope region</div>' +\n            '<div class=\"some-layout-view\">' +\n              '<div class=\"region-one\">In-scope region</div>' +\n            '</div>' +\n          '</div>';\n        this.setFixtures(fixture);\n        this.layout.render();\n        this.regions = this.layout.getRegions();\n        this.View = Backbone.Marionette.View.extend({\n          el: '.region-hash-no-template-spec .some-layout-view',\n          template: _.noop,\n          regions: {\n            regionOne: '.region-one'\n          }\n        });\n        this.layoutViewInstance = new this.View();\n        let $specNode = $('.region-hash-no-template-spec');\n        this.$inScopeRegion = $specNode.find('.some-layout-view .region-one');\n        this.$outOfScopeRegion = $specNode.children('.region-one');\n      });\n\n      it('after initialization, the view\\'s regions should be scoped to its parent view', function() {\n        expect(this.layoutViewInstance.getRegion('regionOne').$el).to.have.length(1);\n        expect(this.layoutViewInstance.getRegion('regionOne').$el.is(this.$inScopeRegion)).to.equal(true);\n        expect(this.layoutViewInstance.getRegion('regionOne').$el.is(this.$outOfScopeRegion)).to.equal(false);\n      });\n    });\n  });\n\n  describe('manipulating regions', function() {\n    beforeEach(function() {\n      this.beforeAddRegionSpy = this.sinon.spy();\n      this.addRegionSpy = this.sinon.spy();\n      this.beforeRegionRemoveSpy = this.sinon.spy();\n      this.removeRegionSpy = this.sinon.spy();\n\n      this.Layout = Marionette.View.extend({\n        template: _.noop,\n        onBeforeAddRegion: this.beforeAddRegionSpy,\n        onAddRegion: this.addRegionSpy,\n        onBeforeRemoveRegion: this.beforeRegionRemoveSpy,\n        onRemoveRegion: this.removeRegionSpy\n      });\n\n      this.layout = new this.Layout();\n\n      this.regionName = 'myRegion';\n      this.layout.addRegion(this.regionName, '.region-selector');\n    });\n\n    it('should trigger correct region add events', function() {\n      expect(this.beforeAddRegionSpy)\n        .to.have.been.calledOnce\n        .and.calledOn(this.layout)\n        .and.calledWith(this.layout, this.regionName);\n\n      expect(this.addRegionSpy)\n        .to.have.been.calledOnce\n        .and.calledOn(this.layout)\n        .and.calledWith(this.layout, this.regionName);\n    });\n\n    it('should trigger correct region remove events', function() {\n      this.layout.removeRegion(this.regionName);\n\n      expect(this.beforeRegionRemoveSpy)\n        .to.have.been.calledOnce\n        .and.calledOn(this.layout)\n        .and.calledWith(this.layout, this.regionName);\n\n      expect(this.removeRegionSpy)\n        .to.have.been.calledOnce\n        .and.calledOn(this.layout)\n        .and.calledWith(this.layout, this.regionName);\n    });\n  });\n\n});\n"
  },
  {
    "path": "test/unit/view.dynamic-regions.spec.js",
    "content": "describe('itemView - dynamic regions', function() {\n  'use strict';\n\n  let BBView;\n\n  beforeEach(function() {\n    BBView = Backbone.View.extend();\n    _.extend(BBView.prototype, Marionette.Events);\n\n    this.template = function() {\n      return '<div id=\"foo\"></div><div id=\"bar\"></div>';\n    };\n  });\n\n  describe('when adding a region to a layoutView, after it has been rendered', function() {\n    beforeEach(function() {\n      this.MyView = Marionette.View.extend({\n        onAddRegion: function() {},\n        onBeforeAddRegion: function() {}\n      });\n\n      this.layoutView = new this.MyView({\n        template: this.template\n      });\n\n      this.beforeAddHandler = this.sinon.spy();\n      this.addHandler = this.sinon.spy();\n      this.onBeforeAddSpy = this.sinon.spy(this.layoutView, 'onBeforeAddRegion');\n      this.onAddSpy = this.sinon.spy(this.layoutView, 'onAddRegion');\n      this.layoutView.on('before:add:region', this.beforeAddHandler);\n      this.layoutView.on('add:region', this.addHandler);\n\n      this.layoutView.render();\n\n      this.region = this.layoutView.addRegion('foo', '#foo');\n\n      this.view = new BBView();\n      this.layoutView.getRegion('foo').show(this.view);\n    });\n\n    it('should add the region to the layoutView', function() {\n      expect(this.layoutView.getRegion('foo')).to.equal(this.region);\n    });\n\n    it('should add the region definition to the regions property', function() {\n      expect(this.layoutView.regions.foo).to.equal('#foo');\n    });\n\n    it('should set the parent of the region to the layoutView', function() {\n      expect(this.region.$el.parent()[0]).to.equal(this.layoutView.el);\n    });\n\n    it('should be able to show a view in the region', function() {\n      expect(this.layoutView.getRegion('foo').$el.children().length).to.equal(1);\n    });\n\n    it('should trigger a before:add:region event', function() {\n      expect(this.beforeAddHandler).to.have.been.calledWith(this.layoutView, 'foo');\n      expect(this.onBeforeAddSpy).to.have.been.calledWith(this.layoutView, 'foo');\n    });\n\n    it('should trigger a add:region event', function() {\n      expect(this.addHandler).to.have.been.calledWith(this.layoutView, 'foo', this.region);\n      expect(this.onAddSpy).to.have.been.calledWith(this.layoutView, 'foo', this.region);\n    });\n  });\n\n  describe('when adding a region to a layoutView, before it has been rendered', function() {\n    beforeEach(function() {\n      this.layoutView = new Marionette.View({\n        template: this.template\n      });\n\n      this.region = this.layoutView.addRegion('foo', '#foo');\n\n      this.layoutView.render();\n\n      this.view = new BBView();\n      this.layoutView.getRegion('foo').show(this.view);\n    });\n\n    it('should add the region to the layoutView after it is rendered', function() {\n      expect(this.layoutView.getRegion('foo')).to.equal(this.region);\n    });\n\n    it('should set the parent of the region to the layoutView', function() {\n      expect(this.region.$el.parent()[0]).to.equal(this.layoutView.el);\n    });\n\n    it('should be able to show a view in the region', function() {\n      expect(this.layoutView.getRegion('foo').$el.children().length).to.equal(1);\n    });\n  });\n\n  describe('when adding a region to a layoutView that does not have any regions defined, and re-rendering the layoutView', function() {\n    beforeEach(function() {\n      this.layoutView = new Marionette.View({\n        template: this.template\n      });\n\n      this.region = this.layoutView.addRegion('foo', '#foo');\n\n      this.layoutView.render();\n      this.layoutView.render();\n\n      this.view = new BBView();\n      this.layoutView.getRegion('foo').show(this.view);\n    });\n\n    it('should re-add the region to the layoutView after it is re-rendered', function() {\n      expect(this.layoutView.getRegion('foo')).to.equal(this.region);\n    });\n\n    it('should set the parent of the region to the layoutView', function() {\n      expect(this.region.$el.parent()[0]).to.equal(this.layoutView.el);\n    });\n\n    it('should be able to show a view in the region', function() {\n      expect(this.layoutView.getRegion('foo').$el.children().length).to.equal(1);\n    });\n  });\n\n  describe('when adding a region to a layoutView that already has regions defined, and re-rendering the layoutView', function() {\n    beforeEach(function() {\n      this.layoutView = new Marionette.View({\n        regions: {\n          bar: '#bar'\n        },\n        template: this.template\n      });\n\n      this.barRegion = this.layoutView.getRegion('bar');\n\n      this.region = this.layoutView.addRegion('foo', '#foo');\n\n      this.layoutView.render();\n      this.layoutView.render();\n\n      this.view = new BBView();\n      this.layoutView.getRegion('foo').show(this.view);\n    });\n\n    it('should keep the original regions', function() {\n      expect(this.layoutView.getRegion('bar')).to.equal(this.barRegion);\n    });\n\n    it('should re-add the region to the layoutView after it is re-rendered', function() {\n      expect(this.layoutView.getRegion('foo')).to.equal(this.region);\n    });\n\n    it('should set the parent of the region to the layoutView', function() {\n      this.region.show(new BBView());\n      expect(this.region.$el.parent()[0]).to.equal(this.layoutView.el);\n    });\n\n    it('should be able to show a view in the region', function() {\n      expect(this.layoutView.getRegion('foo').$el.children().length).to.equal(1);\n    });\n  });\n\n  describe('when removing a region from a layoutView', function() {\n    beforeEach(function() {\n      this.View = Marionette.View.extend({\n        template: this.template,\n        regions: {\n          foo: '#foo'\n        },\n        onBeforeRemoveRegion: function() {},\n        onRemoveRegion: function() {}\n      });\n\n      this.emptyHandler = this.sinon.spy();\n      this.beforeRemoveHandler = this.sinon.spy();\n      this.removeHandler = this.sinon.spy();\n      this.beforeDestroyHandler = this.sinon.spy();\n      this.destroyHandler = this.sinon.spy();\n\n      this.layoutView = new this.View();\n\n      this.onBeforeRemoveSpy = this.sinon.spy(this.layoutView, 'onBeforeRemoveRegion');\n      this.onRemoveSpy = this.sinon.spy(this.layoutView, 'onRemoveRegion');\n\n      this.layoutView.render();\n      this.layoutView.getRegion('foo').show(new BBView());\n      this.region = this.layoutView.getRegion('foo');\n\n      this.region.on('empty', this.emptyHandler);\n      this.layoutView.on('before:remove:region', this.beforeRemoveHandler);\n      this.layoutView.on('remove:region', this.removeHandler);\n      this.region.on('before:destroy', this.beforeDestroyHandler);\n      this.region.on('destroy', this.destroyHandler);\n      this.layoutView.removeRegion('foo');\n    });\n\n    it('should empty the region', function() {\n      expect(this.emptyHandler).to.have.been.called;\n    });\n\n    it('should trigger a before:destroy event on the region', function() {\n      expect(this.beforeDestroyHandler).to.have.been.calledWith(this.region);\n    });\n\n    it('should trigger a destroy event on the region', function() {\n      expect(this.destroyHandler).to.have.been.calledWith(this.region);\n    });\n\n    it('should trigger a before:remove:region event', function() {\n      expect(this.onBeforeRemoveSpy).to.have.been.calledWith(this.layoutView, 'foo');\n      expect(this.beforeRemoveHandler).to.have.been.calledWith(this.layoutView, 'foo');\n    });\n\n    it('should trigger a remove:region event', function() {\n      expect(this.onRemoveSpy).to.have.been.calledWith(this.layoutView, 'foo', this.region);\n      expect(this.removeHandler).to.have.been.calledWith(this.layoutView, 'foo', this.region);\n    });\n\n    it('should remove the region', function() {\n      expect(this.layoutView.getRegion('foo')).to.be.undefined;\n      expect(this.layoutView.regions.foo).to.be.undefined;\n    });\n  });\n\n  describe('when removing a region and then re-rendering the layoutView', function() {\n    beforeEach(function() {\n      this.View = Marionette.View.extend({\n        template: this.template,\n        regions: {\n          foo: '#foo'\n        }\n      });\n\n      this.layoutView = new this.View();\n\n      this.layoutView.render();\n      this.layoutView.getRegion('foo').show(new BBView());\n\n      this.layoutView.removeRegion('foo');\n      this.layoutView.render();\n\n      this.region = this.layoutView.getRegion('foo');\n    });\n\n    it('should not re-attach the region to the layoutView', function() {\n      expect(this.region).to.be.undefined;\n    });\n  });\n\n  describe('when adding a region to a layoutView then destroying the layoutView', function() {\n    beforeEach(function() {\n      this.emptyHandler = this.sinon.stub();\n      this.layoutView = new Marionette.View({\n        template: this.template\n      });\n\n      this.layoutView.render();\n\n      this.region = this.layoutView.addRegion('foo', '#foo');\n      this.region.on('empty', this.emptyHandler);\n\n      this.view = new BBView();\n      this.layoutView.getRegion('foo').show(this.view);\n\n      this.layoutView.destroy();\n    });\n\n    it('should empty the region', function() {\n      expect(this.emptyHandler).to.have.been.called;\n    });\n  });\n\n  describe('when calling emptyRegions', function() {\n    beforeEach(function() {\n\n      this.view = new Marionette.View({\n        template: this.template\n      });\n      this.view.render();\n      this.region = this.view.addRegion('foo', '#foo');\n      this.regions = this.view.getRegions();\n      this.region.show(new BBView());\n\n      this.emptyHandler = this.sinon.stub();\n      this.region.on('empty', this.emptyHandler);\n\n      this.sinon.spy(this.view, 'emptyRegions');\n      this.view.emptyRegions();\n    });\n\n    it('should empty all regions', function() {\n      expect(this.emptyHandler).to.have.been.called;\n    });\n\n    it('should not remove all regions', function() {\n      expect(this.view.getRegion('foo')).to.equal(this.region);\n    });\n\n    it('should return the regions', function() {\n      expect(this.view.emptyRegions).to.have.returned(this.regions);\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/view.renderer.js",
    "content": "import _ from 'underscore';\nimport Backbone from 'backbone';\nimport View from '../../src/view';\n\ndescribe('View.setRenderer', function() {\n  let ViewClass;\n  let ViewSubClass;\n  let model;\n\n  const template = 'fooTemplate';\n  const data = { foo: 'bar' };\n\n  beforeEach(function() {\n    ViewClass = View.extend();\n    ViewSubClass = ViewClass.extend();\n    model = new Backbone.Model(data);\n  });\n\n  describe('when setting a renderer on a View class', function() {\n    it('should return the View class', function() {\n      expect(ViewClass.setRenderer()).to.be.eq(ViewClass);\n    });\n  });\n\n  describe('when changing a renderer on a View class', function() {\n    let rendererStub;\n\n    beforeEach(function() {\n      rendererStub = this.sinon.stub();\n\n      ViewClass.setRenderer(rendererStub);\n\n      const view = new ViewClass({ template, model });\n\n      view.render();\n    });\n\n    it('should use the custom renderer to render', function() {\n      expect(rendererStub).to.have.been.calledOnce.and.calledWith(template, data);\n    });\n\n    it('should not affect the renderer of the extended View', function() {\n      rendererStub.reset();\n\n      const baseView = new View({ template: _.template('bar'), model });\n      baseView.render();\n\n      expect(rendererStub).to.not.have.been.called;\n    });\n\n    describe('when inheriting from the view class', function() {\n      it('should use the custom renderer', function() {\n        rendererStub.reset();\n\n        const subView = new ViewSubClass({ template, model });\n        subView.render();\n\n        expect(rendererStub).to.have.been.calledOnce.and.calledWith(template, data);\n      });\n    });\n\n    describe('when changing a renderer on an inherited class', function() {\n      let subRendererStub;\n\n      beforeEach(function() {\n        subRendererStub = this.sinon.stub();\n\n        ViewSubClass.setRenderer(subRendererStub);\n\n        rendererStub.reset();\n\n        const view = new ViewSubClass({ template, model });\n\n        view.render();\n      });\n\n      it('should use the custom renderer to render', function() {\n        expect(subRendererStub).to.have.been.calledOnce.and.calledWith(template, data);\n      });\n\n      it('should not use the custom renderer of the inherited class', function() {\n        expect(rendererStub).to.not.have.been.called;\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/view.spec.js",
    "content": "import Backbone from 'backbone';\nimport Region from '../../src/region';\nimport View from '../../src/view';\n\ndescribe('item view', function() {\n  'use strict';\n\n  let modelData;\n  let model;\n  let template;\n  let templateStub;\n\n  beforeEach(function() {\n    modelData = {foo: 'bar'};\n    model = new Backbone.Model(modelData);\n\n    template = 'foobar';\n    templateStub = this.sinon.stub().returns(template);\n  });\n\n  // Fixes https://github.com/marionettejs/backbone.marionette/issues/3527\n  describe('when entity events are added in initialize', function() {\n    it('should not undelegate them', function() {\n      const TestView = Marionette.View.extend({\n        template: false,\n        initialize() {\n          this.listenTo(model, 'foo', this.onFoo);\n        },\n        onFoo: this.sinon.stub()\n      });\n\n      const view = new TestView({ model });\n\n      model.trigger('foo');\n\n      expect(view.onFoo).to.have.been.calledOnce;\n    });\n  });\n\n  describe('when instantiating a view with a DOM element', function() {\n    let view;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"foo\"><span class=\"element\">bar</span></div>');\n      view = new View({\n        el: '#foo',\n        ui: {\n          element: '.element'\n        }\n      });\n    });\n\n    it('should be rendered', function() {\n      expect(view.isRendered()).to.be.true;\n    });\n\n    it('should be attached', function() {\n      expect(view.isAttached()).to.be.true;\n    });\n\n    it('should contain the DOM content', function() {\n      expect(view.el.innerHTML).to.contain('<span class=\"element\">bar</span>');\n    });\n\n    it('should bind ui elements', function() {\n      expect(view.ui.element.text()).to.contain('bar');\n    });\n  });\n\n  describe('when instantiating a view with a non existing DOM element', function() {\n    let view;\n\n    beforeEach(function() {\n      this.setFixtures('<div id=\"foo\"><span class=\"element\">bar</span></div>');\n      view = new View({\n        el: '#nonexistent'\n      });\n    });\n\n    it('should not be rendered', function() {\n      expect(view.isRendered()).to.be.false;\n    });\n\n    it('should not be attached', function() {\n      expect(view.isAttached()).to.be.false;\n    });\n  });\n\n  describe('when rendering without a valid template', function() {\n    let view;\n\n    beforeEach(function() {\n      view = new View();\n    });\n\n    it('should throw an exception because there was no valid template', function() {\n      expect(function() {view.render()}).to.throw();\n    });\n  });\n\n  describe('when rendering with a false template', function() {\n    let onBeforeRenderStub;\n    let onRenderStub;\n    let TestView;\n    let marionetteRendererSpy;\n    let serializeDataSpy;\n    let mixinTemplateContextSpy;\n    let attachElContentSpy;\n    let bindUIElementsSpy;\n    let view;\n\n    beforeEach(function() {\n      onBeforeRenderStub = this.sinon.stub();\n      onRenderStub = this.sinon.stub();\n\n      TestView = View.extend({\n        template: false,\n        onBeforeRender: onBeforeRenderStub,\n        onRender: onRenderStub,\n\n        ui: {\n          testElement: '.test-element'\n        }\n      });\n\n      view = new TestView();\n\n      marionetteRendererSpy = this.sinon.spy(view, '_renderHtml');\n      serializeDataSpy = this.sinon.spy(view, 'serializeData');\n      mixinTemplateContextSpy = this.sinon.spy(view, 'mixinTemplateContext');\n      attachElContentSpy = this.sinon.spy(view, 'attachElContent');\n      bindUIElementsSpy = this.sinon.spy(view, 'bindUIElements');\n\n      view.render();\n    });\n\n    it('should not throw an exception for a false template', function() {\n      expect(view.render.bind(view)).to.not.throw();\n    });\n\n    it('should not call an \"onBeforeRender\" method on the view', function() {\n      expect(onBeforeRenderStub).to.not.have.been.called;\n    });\n\n    it('should not call an \"onRender\" method on the view', function() {\n      expect(onRenderStub).to.not.have.been.called;\n    });\n\n    it('should not call bindUIElements', function() {\n      expect(bindUIElementsSpy).to.not.have.been.called;\n    });\n\n    it('should not add in data or template context', function() {\n      expect(serializeDataSpy).to.not.have.been.called;\n      expect(mixinTemplateContextSpy).to.not.have.been.called;\n    });\n\n    it('should not render a template', function() {\n      expect(marionetteRendererSpy).to.not.have.been.called;\n    });\n\n    it('should not attach any html content', function() {\n      expect(attachElContentSpy).to.not.have.been.called;\n    });\n\n    it('should not claim isRendered', function() {\n      expect(view.isRendered()).to.be.false;\n    });\n\n    describe('and there is prerendered content', function() {\n      let elView;\n\n      beforeEach(function() {\n        this.setFixtures('<div id=\"foo\">bar</div>');\n        elView = new TestView({ el: '#foo' });\n      });\n\n      it('should stay rendered', function() {\n        expect(elView.isRendered()).to.be.true;\n      });\n    });\n  });\n\n\n  describe('when destroying an item view', function() {\n    let onBeforeDestroyStub;\n    let onDestroyStub;\n    let TestView;\n    let view;\n    let removeSpy;\n    let stopListeningSpy;\n    let triggerSpy;\n\n    beforeEach(function() {\n      onBeforeDestroyStub = this.sinon.spy(function() {\n        return {\n          isRendered: this.isRendered(),\n          isDestroyed: this.isDestroyed()\n        };\n      });\n      onDestroyStub = this.sinon.spy(function() {\n        return {\n          isRendered: this.isRendered(),\n          isDestroyed: this.isDestroyed()\n        };\n      });\n\n      TestView = View.extend({\n        template: templateStub,\n        onBeforeDestroy: onBeforeDestroyStub,\n        onDestroy: onDestroyStub\n      });\n\n      view = new TestView();\n      view.render();\n\n      removeSpy = this.sinon.spy(view, '_removeElement');\n      stopListeningSpy = this.sinon.spy(view, 'stopListening');\n      triggerSpy = this.sinon.spy(view, 'trigger');\n\n      this.sinon.spy(view, 'destroy');\n      view.destroy();\n    });\n\n    it('should remove the views EL from the DOM', function() {\n      expect(removeSpy).to.have.been.calledOnce;\n    });\n\n    it('should unbind any listener to custom view events', function() {\n      expect(stopListeningSpy).to.have.been.calledOnce;\n    });\n\n    it('should trigger \"before:destroy\"', function() {\n      expect(triggerSpy).to.have.been.calledWith('before:destroy');\n    });\n\n    it('should trigger \"destroy\"', function() {\n      expect(triggerSpy).to.have.been.calledWith('destroy');\n    });\n\n    it('should call \"onBeforeDestroy\" if provided', function() {\n      expect(onBeforeDestroyStub).to.have.been.called;\n    });\n\n    it('should call \"onDestroy\" if provided', function() {\n      expect(onDestroyStub).to.have.been.called;\n    });\n\n    it('should return the view', function() {\n      expect(view.destroy).to.have.returned(view);\n    });\n\n    it('should not be destroyed when \"onBeforeDestroy\" is called', function() {\n      expect(onBeforeDestroyStub.lastCall.returnValue.isDestroyed).not.to.be.ok;\n    });\n\n    it('should be rendered when \"onBeforeDestroy\" is called', function() {\n      expect(onBeforeDestroyStub.lastCall.returnValue.isRendered).to.be.true;\n    });\n\n    it('should be destroyed when \"onDestroy\" is called', function() {\n      expect(onDestroyStub.lastCall.returnValue.isDestroyed).to.be.true;\n    });\n\n    it('should not be rendered when \"onDestroy\" is called', function() {\n      expect(onDestroyStub.lastCall.returnValue.isRendered).to.be.false;\n    });\n\n    it('should be marked destroyed', function() {\n      expect(view).to.have.property('_isDestroyed', true);\n    });\n\n    it('should be marked not rendered', function() {\n      expect(view).to.have.property('_isRendered', false);\n    });\n  });\n\n  describe('when re-rendering an View that is already shown', function() {\n    let onDomRefreshStub;\n    let TestView;\n    let view;\n    let region;\n    let TestRegion;\n\n    beforeEach(function() {\n      onDomRefreshStub = this.sinon.stub();\n\n      TestView = View.extend({\n        template: templateStub,\n        onDomRefresh: onDomRefreshStub\n      });\n\n      this.setFixtures('<div id=\"region\"></div>');\n      TestRegion = Region.extend({\n        el: '#region'\n      });\n\n      view = new TestView();\n      region = new TestRegion();\n      region.show(view);\n      view.render();\n    });\n\n    it('should trigger a dom:refresh event', function() {\n      expect(onDomRefreshStub).to.have.been.calledTwice;\n    });\n  });\n\n  describe('has a valid inheritance chain back to Backbone.View', function() {\n    let constructor;\n\n    beforeEach(function() {\n      constructor = this.sinon.spy(Backbone.View.prototype, 'constructor');\n    });\n\n    it('calls the parent Backbone.Views constructor function on instantiation with the proper parameters', function() {\n      const options = {foo: 'bar'};\n      const customParam = {foo: 'baz'};\n\n      new View(options, customParam);\n      expect(constructor).to.have.been.calledWith(options, customParam);\n    });\n  });\n\n  describe('when instantiating a View', function() {\n    it('should trigger `initialize` on the behaviors', function() {\n      this.sinon.stub(View.prototype, '_triggerEventOnBehaviors');\n\n      const myView = new View({ foo: 'bar' });\n\n      // _triggerEventOnBehaviors comes from Behaviors mixin\n      expect(myView._triggerEventOnBehaviors)\n        .to.be.calledOnce.and.calledWith('initialize', myView, { foo: 'bar' });\n    });\n  });\n\n\n});\n"
  },
  {
    "path": "test/unit/view.triggers.spec.js",
    "content": "import Backbone from 'backbone';\nimport { setEnabled } from '../../src/config/features';\nimport View from '../../src/view';\n\ndescribe('view triggers', function() {\n  'use strict';\n\n  let triggersHash;\n  let eventsHash;\n  let fooHandlerStub;\n  let barHandlerStub;\n  let fooEvent;\n  let barEvent;\n\n  beforeEach(function() {\n    triggersHash = {'foo': 'fooHandler'};\n    eventsHash = {'bar': 'barHandler'};\n\n    fooHandlerStub = this.sinon.stub();\n    barHandlerStub = this.sinon.stub();\n\n    fooEvent = $.Event('foo');\n    barEvent = $.Event('bar');\n  });\n\n  describe('when DOM events are configured to trigger a view event, and the DOM events are fired', function() {\n    let model;\n    let collection;\n    let TestView;\n    let view;\n\n    beforeEach(function() {\n      model = new Backbone.Model();\n      collection = new Backbone.Collection();\n\n      TestView = View.extend({triggers: triggersHash});\n      view = new TestView({\n        model: model,\n        collection: collection\n      });\n\n      view.on('fooHandler', fooHandlerStub);\n      view.$el.trigger(fooEvent, ['foo', 'bar']);\n    });\n\n    it('should trigger the first view event', function() {\n      expect(fooHandlerStub).to.have.been.calledOnce;\n    });\n\n    it('should include the view in the event', function() {\n      expect(fooHandlerStub.lastCall.args[0]).to.contain(view);\n    });\n\n    it('should include the event object in the event', function() {\n      expect(fooHandlerStub.lastCall.args[1]).to.be.an.instanceOf($.Event);\n    });\n\n    it('should include additional triggered event arguments', function() {\n      expect(fooHandlerStub.lastCall.args[2]).to.equal('foo');\n      expect(fooHandlerStub.lastCall.args[3]).to.equal('bar');\n    });\n  });\n\n  describe('when triggers and standard events are both configured', function() {\n    let TestView;\n    let view;\n\n    beforeEach(function() {\n      TestView = View.extend({\n        triggers: triggersHash,\n        events: eventsHash,\n        barHandler: barHandlerStub\n      });\n\n      view = new TestView();\n      view.on('fooHandler', fooHandlerStub);\n\n      view.$el.trigger(fooEvent);\n      view.$el.trigger(barEvent);\n    });\n\n    it('should fire the trigger', function() {\n      expect(fooHandlerStub).to.have.been.calledOnce;\n    });\n\n    it('should fire the standard event', function() {\n      expect(barHandlerStub).to.have.been.calledOnce;\n    });\n  });\n\n  describe('when triggers are configured with a function', function() {\n    let triggersStub;\n    let TestView;\n    let view;\n\n    beforeEach(function() {\n      triggersStub = this.sinon.stub().returns(triggersHash);\n      TestView = View.extend({triggers: triggersStub});\n      view = new TestView();\n      view.on('fooHandler', fooHandlerStub);\n\n      view.$el.trigger(fooEvent);\n    });\n\n    it('should call the function', function() {\n      expect(triggersStub).to.have.been.calledOnce.and.calledOn(view);\n    });\n\n    it('should trigger the first view event', function() {\n      expect(fooHandlerStub).to.have.been.calledOnce;\n    });\n  });\n\n  describe('triggers should stop propagation and events by default', function() {\n    let TestView;\n    let view;\n\n    beforeEach(function() {\n      TestView = View.extend({triggers: triggersHash});\n      view = new TestView();\n      view.on('fooHandler', fooHandlerStub);\n\n      view.$el.trigger(fooEvent);\n    });\n\n    it('should stop propagation by default', function() {\n      expect(fooEvent.isPropagationStopped()).to.be.true;\n    });\n\n    it('should prevent default by default', function() {\n      expect(fooEvent.isDefaultPrevented()).to.be.true;\n    });\n  });\n\n  describe('when triggers items are manually configured', function() {\n    let TestView;\n    let view;\n\n    beforeEach(function() {\n      TestView = View.extend({\n        triggers: {\n          'foo': {\n            event: 'fooHandler',\n            preventDefault: true,\n            stopPropagation: false\n          }\n        }\n      });\n      view = new TestView();\n      view.on('fooHandler', fooHandlerStub);\n\n      view.$el.trigger(fooEvent);\n    });\n\n    it('should prevent and dont stop the first view event', function() {\n      expect(fooEvent.isDefaultPrevented()).to.be.true;\n      expect(fooEvent.isPropagationStopped()).to.be.false;\n    });\n  });\n\n  describe('when triggersPreventDefault flag is set to false', function() {\n    beforeEach(function() {\n      setEnabled('triggersPreventDefault', false);\n    });\n\n    afterEach(function() {\n      setEnabled('triggersPreventDefault', true);\n    });\n\n    describe('triggers should not prevent events by default', function() {\n      let TestView;\n      let view;\n\n      beforeEach(function() {\n        TestView = View.extend({triggers: triggersHash});\n        view = new TestView();\n        view.on('fooHandler', fooHandlerStub);\n\n        view.$el.trigger(fooEvent);\n      });\n\n      it('should stop propagation by default', function() {\n        expect(fooEvent.isPropagationStopped()).to.be.true;\n      });\n\n      it('should not prevent default by default', function() {\n        expect(fooEvent.isDefaultPrevented()).to.be.false;\n      });\n    });\n\n    describe('when triggers items are manually configured', function() {\n      let TestView;\n      let view;\n\n      beforeEach(function() {\n        TestView = View.extend({\n          triggers: {\n            'foo': {\n              event: 'fooHandler',\n              preventDefault: true,\n              stopPropagation: true\n            }\n          }\n        });\n        view = new TestView();\n        view.on('fooHandler', fooHandlerStub);\n\n        view.$el.trigger(fooEvent);\n      });\n\n      it('should prevent and stop the first view event', function() {\n        expect(fooEvent.isDefaultPrevented()).to.be.true;\n        expect(fooEvent.isPropagationStopped()).to.be.true;\n      });\n    });\n  });\n\n  describe('when triggersStopPropagation flag is set to false', function() {\n    beforeEach(function() {\n      setEnabled('triggersStopPropagation', false);\n    });\n\n    afterEach(function() {\n      setEnabled('triggersStopPropagation', true);\n    });\n\n    describe('triggers should not stop propagation by default', function() {\n      let TestView;\n      let view;\n\n      beforeEach(function() {\n        TestView = View.extend({triggers: triggersHash});\n        view = new TestView();\n        view.on('fooHandler', fooHandlerStub);\n\n        view.$el.trigger(fooEvent);\n      });\n\n      it('should stop propagation by default', function() {\n        expect(fooEvent.isPropagationStopped()).to.be.false;\n      });\n\n      it('should prevent default by default', function() {\n        expect(fooEvent.isDefaultPrevented()).to.be.true;\n      });\n    });\n\n    describe('when triggers items are manually configured', function() {\n      let TestView;\n      let view;\n\n      beforeEach(function() {\n        TestView = View.extend({\n          triggers: {\n            'foo': {\n              event: 'fooHandler',\n              preventDefault: true,\n              stopPropagation: true\n            }\n          }\n        });\n        view = new TestView();\n        view.on('fooHandler', fooHandlerStub);\n\n        view.$el.trigger(fooEvent);\n      });\n\n      it('should prevent and stop the first view event', function() {\n        expect(fooEvent.isDefaultPrevented()).to.be.true;\n        expect(fooEvent.isPropagationStopped()).to.be.true;\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/view.ui-bindings.spec.js",
    "content": "describe('view ui elements', function() {\n  'use strict';\n\n  beforeEach(function() {\n    this.templateFn = _.template('<div id=\"<%= name %>\"></div>');\n    this.uiHash = {foo: '#foo', bar: '#bar'};\n    this.model = this.model = new Backbone.Model({name: 'foo'});\n    this.View = Marionette.View.extend({\n      template: this.templateFn,\n      ui: this.uiHash\n    });\n  });\n\n  describe('when normalizing a ui string', function() {\n    beforeEach(function() {\n      this.view = new this.View({model: this.model});\n      this.view.render();\n    });\n\n    it('should return the string unmodified if it does not begin with @ui.', function() {\n      expect(this.view.normalizeUIString('baz')).to.equal('baz');\n    })\n\n    it('should translate it if it can be found', function() {\n      expect(this.view.normalizeUIString('@ui.foo')).to.equal('#foo');\n    });\n\n    it('should return undefined if it begins with @ui. but can not be found', function() {\n      expect(this.view.normalizeUIString('@ui.baz')).to.equal('undefined');\n    });\n  });\n\n  describe('when accessing a ui element from the hash', function() {\n    beforeEach(function() {\n      this.view = new this.View({model: this.model});\n      this.view.render();\n    });\n\n    it('should return its jQuery selector if it can be found', function() {\n      expect(this.view.ui.foo).to.be.instanceOf(jQuery).and.to.have.lengthOf(1);\n    });\n\n    it('should return an empty jQuery object if it cannot be found', function() {\n      expect(this.view.ui.bar).to.be.instanceOf(jQuery).and.to.have.lengthOf(0);\n    });\n\n    it('should return its jQuery selector through getUI', function() {\n      expect(this.view.getUI('foo')).to.be.instanceOf(jQuery).and.to.have.lengthOf(1);\n      expect(this.view.getUI('bar')).to.be.instanceOf(jQuery).and.to.have.lengthOf(0);\n    });\n  });\n\n  describe('when re-rendering a view with a UI element configuration', function() {\n    beforeEach(function() {\n      this.view = new this.View({model: this.model});\n      this.view.render();\n      this.view.model.set('name', 'bar');\n      this.view.render();\n    });\n\n    it('should return an up-to-date selector on subsequent renders', function() {\n      expect(this.view.ui.foo).to.be.instanceOf(jQuery).and.to.have.lengthOf(0);\n      expect(this.view.ui.bar).to.be.instanceOf(jQuery).and.to.have.lengthOf(1);\n    });\n\n    it('should return an up-to-date selector through getUI', function() {\n      expect(this.view.getUI('foo')).to.be.instanceOf(jQuery).and.to.have.lengthOf(0);\n      expect(this.view.getUI('bar')).to.be.instanceOf(jQuery).and.to.have.lengthOf(1);\n    });\n  });\n\n  describe('when the ui element is a function that returns a hash', function() {\n    beforeEach(function() {\n      this.View = this.View.extend({\n        ui: this.sinon.stub().returns(this.uiHash)\n      });\n\n      this.view = new this.View({model: this.model});\n      this.view.render();\n    });\n\n    it('should return its jQuery selector if it can be found', function() {\n      expect(this.view.ui.foo).to.be.instanceOf(jQuery).and.to.have.lengthOf(1);\n    });\n\n    it('should return an empty jQuery object if it cannot be found', function() {\n      expect(this.view.ui.bar).to.be.instanceOf(jQuery).and.to.have.lengthOf(0);\n    });\n\n    it('should return an up-to-date selector on subsequent renders', function() {\n      expect(this.view.ui.foo).to.be.instanceOf(jQuery).and.to.have.lengthOf(1);\n      expect(this.view.ui.bar).to.be.instanceOf(jQuery).to.have.lengthOf(0);\n\n      this.view.model.set('name', 'bar');\n      this.view.render();\n\n      expect(this.view.ui.foo).to.have.lengthOf(0);\n      expect(this.view.ui.bar).to.have.lengthOf(1);\n    });\n\n    it('should return its jQuery selector through getUI', function() {\n      expect(this.view.getUI('foo')).to.be.instanceOf(jQuery).and.to.have.lengthOf(1);\n    });\n  });\n\n  describe('when destroying a view that has not been rendered', function() {\n    beforeEach(function() {\n      this.viewOne = new this.View({model: this.model});\n      this.viewTwo = new this.View({model: this.model});\n    });\n\n    it('should not affect future ui bindings', function() {\n      expect(this.viewTwo.ui).to.deep.equal(this.uiHash);\n    });\n  });\n\n  describe('when destroying a view', function() {\n    beforeEach(function() {\n      this.view = new this.View({model: this.model});\n      this.view.render();\n      this.view.destroy();\n    });\n\n    it('should unbind UI elements and reset them to the selector', function() {\n      expect(this.view.ui).to.deep.equal(this.uiHash);\n    });\n  });\n});\n"
  },
  {
    "path": "test/unit/view.ui-event-and-triggers.spec.js",
    "content": "describe('view ui event trigger configuration', function() {\n  'use strict';\n\n  describe('@ui syntax within events and triggers', function() {\n    beforeEach(function() {\n      this.fooHandlerStub = this.sinon.stub();\n      this.barHandlerStub = this.sinon.stub();\n      this.notBarHandlerStub = this.sinon.stub();\n      this.fooBarBazHandlerStub = this.sinon.stub();\n\n      this.templateFn = _.template('<div id=\"foo\"></div><div id=\"bar\"></div><div id=\"baz\"></div>');\n\n      this.uiHash = {\n        foo: '#foo',\n        bar: '#bar',\n        'some-baz': '#baz'\n      };\n\n      this.triggersHash = {\n        'click @ui.foo': 'fooHandler',\n        'click @ui.some-baz': 'bazHandler'\n      };\n\n      this.eventsHash = {\n        'click @ui.bar': this.barHandlerStub,\n        'click div:not(@ui.bar)': this.notBarHandlerStub,\n        'click @ui.foo, @ui.bar, @ui.some-baz': this.fooBarBazHandlerStub\n      };\n    });\n\n    describe('as objects', function() {\n      beforeEach(function() {\n        this.View = Marionette.View.extend({\n          template: this.templateFn,\n          ui: this.uiHash,\n          triggers: this.triggersHash,\n          events: this.eventsHash\n        });\n        this.view = new this.View();\n        this.view.render();\n\n        this.view.on('fooHandler', this.fooHandlerStub);\n      });\n\n      it('should correctly trigger an event', function() {\n        this.view.ui.foo.trigger('click');\n        expect(this.fooHandlerStub).to.have.been.calledOnce;\n        expect(this.fooBarBazHandlerStub).to.have.been.calledOnce;\n      });\n\n      it('should correctly trigger a complex event', function() {\n        this.view.ui.bar.trigger('click');\n        expect(this.barHandlerStub).to.have.been.calledOnce;\n        expect(this.fooBarBazHandlerStub).to.have.been.calledOnce;\n      });\n\n      it('should correctly call an event', function() {\n        this.view.ui['some-baz'].trigger('click');\n        expect(this.notBarHandlerStub).to.have.been.calledOnce;\n        expect(this.fooBarBazHandlerStub).to.have.been.calledOnce;\n      });\n    });\n\n    describe('as functions', function() {\n      beforeEach(function() {\n        this.View = Marionette.View.extend({\n          template: this.templateFn,\n          ui: this.sinon.stub().returns(this.uiHash),\n          triggers: this.sinon.stub().returns(this.triggersHash),\n          events: this.sinon.stub().returns(this.eventsHash)\n        });\n        this.view = new this.View();\n        this.view.render();\n\n        this.view.on('fooHandler', this.fooHandlerStub);\n      });\n\n      it('should initialize events with context of the view', function() {\n        expect(this.View.prototype.events).to.have.been.calledOn(this.view);\n      });\n\n      it('should initialize triggers with context of the view', function() {\n        expect(this.View.prototype.triggers).to.have.been.calledOn(this.view);\n      });\n\n      it('should correctly trigger an event', function() {\n        this.view.ui.foo.trigger('click');\n        expect(this.fooHandlerStub).to.have.been.calledOnce;\n        expect(this.fooBarBazHandlerStub).to.have.been.calledOnce;\n      });\n\n      it('should correctly trigger a complex event', function() {\n        this.view.ui.bar.trigger('click');\n        expect(this.barHandlerStub).to.have.been.calledOnce;\n        expect(this.fooBarBazHandlerStub).to.have.been.calledOnce;\n      });\n\n      it('should correctly call an event', function() {\n        this.view.ui['some-baz'].trigger('click');\n        expect(this.notBarHandlerStub).to.have.been.calledOnce;\n        expect(this.fooBarBazHandlerStub).to.have.been.calledOnce;\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "trigger-deploy-mn-com.js",
    "content": "var Travis = require('travis-ci');\nvar repo = 'marionettejs/marionettejs.com';\nvar travis = new Travis({\n  version: '2.0.0',\n  headers: {\n    'User-Agent': 'Travis/1.0'\n  }\n});\n\nvar getLastMainBuildId = function(builds) {\n  var id;\n\n  for (var i = 0; i < builds.length; i++) {\n    if (!builds[i].pull_request) {\n      id = builds[i].id;\n      break;\n    }\n  }\n\n  if (!id) {\n    throw new Error('Build id was not found');\n  }\n\n  return id;\n};\n\ntravis.authenticate({\n  github_token: process.env.GH_TOKEN\n}, function (err, res) {\n  if (err) {\n    return console.error(err);\n  }\n\n  //get repo builds\n  travis.repos(repo.split('/')[0], repo.split('/')[1]).builds.get(function (err, res) {\n    if (err) {\n      return console.error(err);\n    }\n    \n    //rebuild latest build\n    travis.requests.post({\n      build_id: getLastMainBuildId(res.builds)\n    }, function (err, res) {\n      if (err) {\n        return console.error(err);\n      }\n      console.log(res.flash[0].notice);\n    });\n  });\n});\n"
  },
  {
    "path": "upgradeGuide.md",
    "content": "## Newer versions\n\nUpgrade information for newer versions are available in the changelog or upgrade guides\nfound on [marionettejs.com](http://marionettejs.com/docs/current).\n\n## v2.x - v3.0.0\nA lot of changes were made between v2 and v3. Please see the\n[upgrade guide on the website](http://marionettejs.com/docs/v3.0.0/upgrade-v2-v3.html)\nfor the full list of changes and how to migrate to Marionette 3.\n\n## v2.0.0 - v2.x\nNo breaking changes have been introduced between these versions\n\n## v1.x.x - v2.0.0\nLarge amounts of things have changed between these releases.\nPlease refer to https://github.com/marionettejs/Marionette.Upgrade to ease the transition from any 1.x app.\n\n## v.1.7.x - v1.8.x\nNo breaking changes have been introduced between these versions\n\n## Upgrade to v.1.5.0 ~ v.1.7.x\nIf you are overriding `appendHTML` in your `collectionView` or `compositeView` make sure to update your method to match the [buffering implementation](https://github.com/marionettejs/backbone.marionette/blob/v1.8.8/src/marionette.collectionview.js#L303). If you do not you may observe the `show` event not being called per `itemViews`\n\n## Upgrade to v.1.1.0 ~ v.1.4.x\nNo breaking changes have been introduced between these versions\n\n## Upgrade to v1.1.0\n\nv1.1.0 adds a few new features, but should not break any existing API or\nbehavior. It should, therefore, be a drop-in replacement for v1.0.x.\n\nPlease see the [changelog](https://github.com/marionettejs/backbone.marionette/blob/master/changelog.md)\nfor the complete list of what was added and fixed in this release.\n\n## Upgrade to v1.0.0\n\nIn addition to the following notes, please see previous upgrade guide entries and the\n[changelog](https://github.com/marionettejs/backbone.marionette/blob/master/changelog.md).\n\n### Backbone 1.0 and Underscore 1.4.4\n\nMarionette v1.0 is built and tested with Backbone v1.0 and Underscore v1.4.4. You should be\nable to use Backbone v0.9.9 or v0.9.10 with Marionette 1.0, but there is no\nguarantee that everything will work as expected. Older versions of\nBackbone are not supported at all.\n\nAs of Backbone v1.0, calling `fetch()` on a collection will not trigger the **reset** event\nby default. This will cause Marionette's [CollectionView](https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.collectionview.md) and [CompositeView](https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.compositeview.md) to not function\nas expected. Be sure to pass the `reset: true` option when calling `fetch()`.\n\n### Wreqr v0.2.0\n\nThis update renames the `addHandler` methods to `setHandler` to help\nset the expectation that there is a single handler for any given\ncommand or request/response handler. When updating to Wreqr v0.2.0,\nyou will need to change all calls to `addHandler` to `setHandler`. For\nmore information on other changes in Wreqr, see the\n[Wreqr changelog](https://github.com/marionettejs/backbone.wreqr/blob/master/CHANGELOG.md).\n\n### Grunt v0.4\n\nGrunt v0.4 has a significantly different architecture than previous versions. If\nyou are building Marionette and/or running the specs from your local computer, you\nwill need to update to the latest version of Grunt v0.4 to do so.\n\nSee the\n[getting started guide for Grunt](http://gruntjs.com/getting-started).\n\nOnce you have done that, you should be able to run Grunt to get things rolling.\n\n### Marionette.createObject\n\nThis method has been removed. It was never used by Marionette directly,\nand you should replace its use with a proper polyfill such as Modernizr.\n\n## Upgrade to v1.0.0-rc4\n\nRC4 is mostly bug fixes and zombie killing. There are a few\nthings that you need to pay attention to, though. Check the\n[changelog](https://github.com/marionettejs/backbone.marionette/blob/master/changelog.md)\nfor a more complete list.\n\n### Marionette.addEventBinder Function Has Been Removed\n\nThe method `Marionette.addEventBinder` has been removed\nentirely. If you were using this method call in your code,\nyou will need to delete that line of code.\n\nThe replacement for this is simply Backbone.Events, which\nhas the necessary `.listenTo` and `.stopListening` methods,\nas noted in previous upgrade guide entries.\n\nThe `addEventBinder` had provided a 4th `context` parameter\nto the `.listenTo` and `.stopListening` methods, in anticipation\nof Backbone adding these in a future release. After further\ndiscussion and research, though, I realized that this parameter\nis not needed. Further, Backbone is not going to be adding this\nparameter any time soon. There has not been a clear need for\nit.\n\n### Marionette.EventAggregator Object Has Been Removed\n\nThe `Marionette.EventAggregator` object did nothing more than\nimport `Backbone.Wreqr.EventAggregator` in to the Marionette\nnamespace. This has been removed as it added no value. Replace\nall uses of `Marionette.EventAggregator` with\n`Backbone.Wreqr.EventAggregator`.\n\n## Upgrade v1.0.0-rc3 to Backbone v0.9.10 and jQuery v1.9.0\n\nThis is a simple update:\n\n* Update Backbone to v0.9.10\n* Update jQuery to v1.9.0\n\nNote that there are no changes in Marionette for this minor.\nYou should not have to change any Marionette specific code\nto update your app. You may have to change code that core\nBackbone runs, or that jQuery runs, though. This includes\nany core Backbone features that are included in Marionette,\nsuch as the use of the `view.make` function which is no\nlonger included in Backbone.View.\n\nFor more information on what you may need to change, see\nthe change logs for\n[Backbone v0.9.10](http://backbonejs.org/#changelog)\nand the upgrade guide for [jQuery v1.9.0](http://jquery.com/upgrade-guide/1.9/)\n\n## Upgrade from v1.0.0-rc2 to v1.0.0-rc3\n\nThere are several breaking changes that occurred between v1.0.0-rc2 and\nv1.0.0-rc3 that need special attention. Please use this upgrade guide\nas a list of things that you need to account for when updating.\n\nIn general, you need to grab the latest version of Backbone, Underscore,\nand Backbone.Wreqr.\n\n### Backbone v0.9.2 no longer supported\n\nFirst and foremost, with the release of Backbone v0.9.9, we are no\nlonger supporting Backbone v0.9.2. There are several additions to\nv0.9.9 that have made code previously found in Marionette's pre-requisites\nobsolete. This has caused a ripple effect of API changes for\nnaming consistency in Marionette.\n\nIn order to use Marionette v1.0.0-rc3, you must upgrade to Backbone\nv0.9.9 and Underscore v1.4.3 or higher (as necessary, with Backbone\nversions).\n\n### Backbone.EventBinder is now obsolete\n\nWith Backbone v0.9.9, the Backbone.EventBinder pre-requisite is now\nobsolete. It will be kept around for backward compatibility with\nolder versions of Marionette and Backbone, but it is no longer used\nby Marionette directly. Unless you have a significant investment in\nits use, you should discontinue its use when ugprading to Marionette\nv1.0.0-rc3.\n\nTo replace the use of Backbone.EventBinder in your Marionette applications,\nyou have two choices:\n\n1. Mix Backbone.Events in to your objects directly\n2. Use Backbone.Wreqr.EventAggregator\n\nWith the introduction of `.listenTo` and `.stopListening` to Backbone.Events,\nthe need for Backbone.EventBinder is no longer there. You can either\nuse `_.extend(myObject, Backbone.Events)` to mix in Backbone.Events\ndirectly, or you can use an instance of `Backbone.Wreqr.EventAggregator`\nto replace your Backbone.EventBinder instances, directly.\n\nAlong with this dependency being obsolete now, you should make the\nfollowing changes:\n\n* Replace `bindTo` with `listenTo`\n* Replace `unbindAll` with `stopListening`\n* Remove calls to `unbindFrom` as this has no equivalent\n\n### Marionette.Async is no longer supported\n\nThe Marionette.Async library was a mistake from the start. It advocated\nbad practices by making the View layer responsible for the knowledge\nof application workflow. I'm happy to say that it has been removed\nfrom Marionette and is no longer supported.\n\nIf your app currently relies on Marionette.Async, I suggest re-thinking\nthe architecture before upgrading to Marionette v1.0.0-rc3 or later. Specifically,\nmove any logic that deals with asynchronous calls, and workflow / process\nlogic out of your views and in to a Marionette.Controller or other object\nthat can properly coordinate the efforts.\n\nFor example, loading a model before displaying it:\n\n```js\nMarionette.Controller.extend({\n  showById: function(id){\n    var model = new MyModel({\n      id: id\n    });\n\n    var promise = model.fetch();\n\n    $.when(promise).then(_.bind(this.showIt, this));\n  },\n\n  showIt: function(model){\n    var view = new MyView({\n      model: model\n    });\n\n    MyApp.myRegion.show(view);\n  }\n});\n```\n"
  }
]