diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..5073443 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: node_js +node_js: + - "6.1" + +before_script: + - npm install phantomjs + +script: + - phantomjs runner_test.js diff --git a/README.md b/README.md index daa0242..3a8769b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # YPet +[![Build Status](https://travis-ci.org/AnoXDD/YPet.svg?branch=master)](https://travis-ci.org/AnoXDD/YPet) + [YPet](https://github.com/SuLab/YPet) is a Javascript library built in [Marionette.js](http://marionettejs.com/) to rapidly annotate paragraphs of text on websites. The project aims to rethink HTML text annotation, primarily focused on biocuration and adheres to the following rules: * Limit the possibility for damaged annotations, individual letters are not desired. @@ -17,8 +19,49 @@ Example of behavior: ## How to Use +The latest version of YPet (`ypet-new.js`) is built based on Marionette V3, but a older version of YPet (`ypet.js`) supports V2. + +The build badge at the beginning of this file indicates the status of the **latest** version. + +We recommend working with Marionette V3, because the older version of YPet does not process special characters like &, <, > properly. You will get `&`, `<`, `>` instead of the characters. + ### Setup +For Marionette V3: + +```javascript +/* Setup the paragraphs with a string to tokenize */ +var p1 = new Paragraph({'text': $('p#some-paragraph').html()}); +var p2 = new Paragraph({'text': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam tincidunt tempus lorem, quis sollicitudin lectus pretium nec. Ut non enim.'}); + +/* Configure the # and colors of Annotation types (minimum 1 required) */ +YPet.AnnotationTypes = new AnnotationTypeList([ +{name: 'Person', color: '#A4DEAB'}, +{name: 'Place', color: 'PowderBlue'}, +{name: 'Thing', color: 'rgb(0, 180, 200)'} +]); + +YPet = new Backbone.Marionette.Application({ + region: "#doc" // where p1 and p2 are placed +}); + +/* Assign views to Region */ +YPet.showView(new (Mn.View.extend({ + el: ".container-to-hold-p1p2", + regions: { + 'p1': '#container-to-place-p1', + 'p2': '#container-to-place-p2' + } +}))()); + +/* Put the new Annotation views on the page */ +YPet.getView().getRegion(1).show( new WordCollectionView({collection: p1.get('words')}) ); +YPet.getView().getRegion(2).show( new WordCollectionView({collection: p2.get('words')}) ); + +YPet.start(); +``` +For Marionette V2: + ```javascript YPet.addInitializer(function(options) { /* Setup the paragraphs with a string to tokenize */ @@ -47,12 +90,29 @@ YPet.start(); ``` -### Events +#### Events If you want to live track annotations as they're put on the paragraph (to save, send to a server, or do something else with) the following callbacks and serialization methods are available. Each annotation is returned as an object with a `start` and `text` attribute, as well as an array of children words. +For Marionette V3: + +```javascript +YPet.getView().getRegion(1).currentView.collection.parentDocument.get('annotations').on('add', function(model, collection) { + console.log('Add:', model.toJSON(), collection.toJSON()); +}); + +YPet.getView().getRegion(1).currentView.collection.parentDocument.get('annotations').on('remove', function(model, collection) { + console.log('Remove:', model.toJSON(), collection.toJSON()); +}); + +YPet.getView().getRegion(1).currentView.collection.parentDocument.get('annotations').on('change', function(model) { + console.log('Change:', model.toJSON()); +}); +``` + +For Marionette V2: ```javascript YPet['p1'].currentView.collection.parentDocument.get('annotations').on('add', function(model, collection) { @@ -70,7 +130,7 @@ YPet['p1'].currentView.collection.parentDocument.get('annotations').on('change', ## About -[YPet](https://github.com/SuLab/YPet) was developed to rapidly annotate bio-medical literature for [Mark2Cure](http://mark2cure.org) at [The Su Lab](http://sulab.org/) by [Max Nanis](http://twitter.com/x0xMaximus). +[YPet](https://github.com/SuLab/YPet) was developed to rapidly annotate bio-medical literature for [Mark2Cure](http://mark2cure.org) at [The Su Lab](http://sulab.org/) by [Max Nanis](http://twitter.com/x0xMaximus). The testing script is written by [Runjie Guan](http://anoxic.me). ![The Scripps Research Institute](http://www.scripps.edu/files/images/logo120.png "The Scripps Research Institute") diff --git a/runner_test.js b/runner_test.js new file mode 100644 index 0000000..21c286b --- /dev/null +++ b/runner_test.js @@ -0,0 +1,96 @@ +/* phantomjs page setup */ + +var page = require('webpage').create(); + +page.onConsoleMessage = function(msg) { + console.log(msg); +}; + +page.viewportSize = { + width: 800, + height: 800 +}; + +var test_suites = { + "./test/test_page.html": [ + "_testClickOnValidWords", + "_testClickOnInvalidWords", + + "_testDragSameLine", + "_testDragDifferentLine", + "_testDragOverSelectedWord", + "_testDragFromSelectedWord", + "_testDragToSelectedWord", + + "_testDragInvalidWord", + "_testSubmitResults" + ], + "./test/test_page_special_char.html": [ + "_testClickOnInvalidWords", + + "_testSelectAll", + "_testClickOnEachValidWord", + ], + "./test/test_page_fixed.html": [ + "_testClickOnValidWordsFixed", + + "_testDragFixed", + "_testDragSelectedFixed", + + "_testDragInvalidWordFixed" + ] +}; + +/* test runner */ +var htmls = Object.keys(test_suites); +var running_html = ""; +for (var i = 0; i < htmls.length; ++i) { + (function(i) { + var interval = setInterval(function() { + if (running_html === htmls[i]) { + clearInterval(interval); + page.open(running_html, function(status) { + if (status !== "success") { + console.log("Error loading page"); + phantom.exit(1); + } else { + console.log("\n===========Page loaded: " + running_html + "==========="); + } + + page.evaluate(function() { + return document.testInit(); + }); + + test_suites[running_html].forEach(function(test_function) { + var msg = page.evaluate("document." + test_function); + if (msg && msg != "") { + throw new Error("Error: " + msg); + } + }); + + console.log(test_suites[running_html].length + " tests PASSED"); + // Pass to the next test suite + if (!(running_html = htmls[++i])) { + phantom.exit(0); + } + }); + + } + }, 1000); + })(i); +} +running_html = htmls[0]; + + +page.onError = function(msg, trace) { + console.error("An error occured"); + console.error(JSON.stringify(trace)); + /* inject a line number into the error message raised by assert() */ + if (trace.length > 1) { + console.log(msg.replace(/: in /, + " in line " + (parseInt(trace[1].line) - 1) + " of ")); + } else { + console.log("line " + (parseInt(trace[0].line) - 1) + ": " + msg); + } + phantom.exit(1); +}; diff --git a/src/backbone.marionette_v3.min.js b/src/backbone.marionette_v3.min.js new file mode 100644 index 0000000..7186b31 --- /dev/null +++ b/src/backbone.marionette_v3.min.js @@ -0,0 +1,11 @@ +// MarionetteJS (Backbone.Marionette) +// ---------------------------------- +// v3.1.0 +// +// Copyright (c)2016 Derick Bailey, Muted Solutions, LLC. +// Distributed under MIT license +// +// http://marionettejs.com +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("backbone"),require("underscore"),require("backbone.radio")):"function"==typeof define&&define.amd?define(["backbone","underscore","backbone.radio"],t):e.Marionette=e.Mn=t(e.Backbone,e._,e.Backbone.Radio)}(this,function(e,t,i){"use strict";function n(e,t,i){return i.toUpperCase()}function r(e){for(var i=arguments.length,n=Array(i>1?i-1:0),r=1;r1?i-1:0),s=1;s1?i-1:0),r=1;r0)for(e=0;e1?n-1:0),s=1;s1&&void 0!==arguments[1]?arguments[1]:{},n=!e._isAttached&&P(this.el),r="undefined"==typeof i.replaceElement?!!t.result(this,"replaceElement"):!!i.replaceElement;n&&s(e,"before:attach",e),r?this._replaceEl(e):this.attachHtml(e),n&&(e._isAttached=!0,s(e,"attach",e)),this.currentView=e},_ensureElement:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(t.isObject(this.el)||(this.$el=this.getEl(this.el),this.el=this.$el[0]),!this.$el||0===this.$el.length){var i="undefined"==typeof e.allowMissingEl?!!t.result(this,"allowMissingEl"):!!e.allowMissingEl;if(i)return!1;throw new Y('An "el" must exist in DOM for this region '+this.cid)}return!0},_ensureView:function(e){if(!e)throw new Y({name:"ViewNotValid",message:"The view passed is undefined and therefore invalid. You must pass a view instance to show."});if(e._isDestroyed)throw new Y({name:"ViewDestroyedError",message:'View (cid: "'+e.cid+'") has already been destroyed and cannot be used.'})},getEl:function(i){return e.$(i,t.result(this,"parentEl"))},_replaceEl:function(e){this._restoreEl();var t=this.el.parentNode;t.replaceChild(e.el,this.el),this._isReplaced=!0},_restoreEl:function(){if(this._isReplaced){var e=this.currentView;if(e){var t=e.el.parentNode;t&&(t.replaceChild(this.el,e.el),this._isReplaced=!1)}}},isReplaced:function(){return!!this._isReplaced},attachHtml:function(e){this.el.appendChild(e.el)},empty:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{allowMissingEl:!0},t=this.currentView;if(!t)return this._ensureElement(e)&&this.detachHtml(),this;var i=!e.preventDestroy;return i||F("The preventDestroy option is deprecated. Use Region#detachView"),this._empty(t,i),this},_empty:function(e,t){e.off("destroy",this._empty,this),this.triggerMethod("before:empty",this,e),this._restoreEl(),delete this.currentView,e._isDestroyed||(this._removeView(e,t),delete e._parent),this.triggerMethod("empty",this,e)},_removeView:function(e,t){return t?void(e.destroy?e.destroy():A(e)):void this._detachView(e)},detachView:function(){var e=this.currentView;if(e)return this._empty(e),e},_detachView:function(e){var t=!!e._isAttached;t&&s(e,"before:detach",e),this.detachHtml(),t&&(e._isAttached=!1,s(e,"detach",e))},detachHtml:function(){this.$el.contents().detach()},hasView:function(){return!!this.currentView},reset:function(e){return this.empty(e),this.$el&&(this.el=this._initEl),delete this.$el,this},destroy:function(e){return this.reset(e),X.prototype.destroy.apply(this,arguments)}}),pe={regionClass:fe,_initRegions:function(){this.regions=this.regions||{},this._regions={},this.addRegions(t.result(this,"regions"))},_reInitRegions:function(){te(this._regions,"reset")},addRegion:function(e,t){var i={};return i[e]=t,this.addRegions(i)[e]},addRegions:function(e){if(!t.isEmpty(e))return e=this.normalizeUIValues(e,["selector","el"]),this.regions=t.extend({},this.regions,e),this._addRegions(e)},_addRegions:function(e){var i=this,n={regionClass:this.regionClass,parentEl:t.partial(t.result,this,"el")};return t.reduce(e,function(e,t,r){return e[r]=O(t,n),i._addRegion(e[r],r),e},{})},_addRegion:function(e,t){this.triggerMethod("before:add:region",this,t,e),e._parent=this,this._regions[t]=e,this.triggerMethod("add:region",this,t,e)},removeRegion:function(e){var t=this._regions[e];return this._removeRegion(t,e),t},removeRegions:function(){var e=this.getRegions();return t.each(this._regions,t.bind(this._removeRegion,this)),e},_removeRegion:function(e,t){this.triggerMethod("before:remove:region",this,t,e),e.destroy(),delete this.regions[t],delete this._regions[t],this.triggerMethod("remove:region",this,t,e)},emptyRegions:function(){var e=this.getRegions();return te(e,"empty"),e},hasRegion:function(e){return!!this.getRegion(e)},getRegion:function(e){return this._regions[e]},getRegions:function(){return t.clone(this._regions)},showChildView:function(e,t){for(var i=this.getRegion(e),n=arguments.length,r=Array(n>2?n-2:0),s=2;s0&&void 0!==arguments[0]?arguments[0]:{},i=t.result(this,"templateContext");return t.extend(e,i)},attachElContent:function(e){return this.$el.html(e),this},_removeChildren:function(){this.removeRegions()},_getImmediateChildren:function(){return t.chain(this.getRegions()).map("currentView").compact().value()}});t.extend(ve.prototype,ce,pe);var me=["forEach","each","map","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","toArray","first","initial","rest","last","without","isEmpty","pluck","reduce"],we=function(e,i){t.each(me,function(n){e[n]=function(){var e=t.values(t.result(this,i)),r=[e].concat(t.toArray(arguments));return t[n].apply(t,r)}})},ye=function(e){this._views={},this._indexByModel={},this._indexByCustom={},this._updateLength(),t.each(e,t.bind(this.add,this))};we(ye.prototype,"_views"),t.extend(ye.prototype,{add:function(e,t){return this._add(e,t)._updateLength()},_add:function(e,t){var i=e.cid;return this._views[i]=e,e.model&&(this._indexByModel[e.model.cid]=i),t&&(this._indexByCustom[t]=i),this},findByModel:function(e){return this.findByModelCid(e.cid)},findByModelCid:function(e){var t=this._indexByModel[e];return this.findByCid(t)},findByCustom:function(e){var t=this._indexByCustom[e];return this.findByCid(t)},findByIndex:function(e){return t.values(this._views)[e]},findByCid:function(e){return this._views[e]},remove:function(e){return this._remove(e)._updateLength()},_remove:function(e){var i=e.cid;return e.model&&delete this._indexByModel[e.model.cid],t.some(this._indexByCustom,t.bind(function(e,t){if(e===i)return delete this._indexByCustom[t],!0},this)),delete this._views[i],this},_updateLength:function(){return this.length=t.size(this._views),this}});var Ee=["behaviors","childView","childViewEventPrefix","childViewEvents","childViewOptions","childViewTriggers","collectionEvents","events","filter","emptyView","emptyViewOptions","modelEvents","reorderOnSort","sort","triggers","ui","viewComparator"],Ve=e.View.extend({sort:!0,constructor:function(i){this.render=t.bind(this.render,this),this._setOptions(i),this.mergeOptions(i,Ee),v(this),this._initBehaviors(),this.once("render",this._initialEvents),this._initChildViewStorage(),this._bufferedChildren=[];var n=Array.prototype.slice.call(arguments);n[0]=this.options,e.View.prototype.constructor.apply(this,n),this.delegateEntityEvents()},_startBuffering:function(){this._isBuffering=!0},_endBuffering:function(){var e=!!this._isAttached,i=e?this._getImmediateChildren():[];this._isBuffering=!1,t.each(i,function(e){s(e,"before:attach",e)}),this.attachBuffer(this,this._createBuffer()),t.each(i,function(e){e._isAttached=!0,s(e,"attach",e)}),this._bufferedChildren=[]},_getImmediateChildren:function(){return t.values(this.children._views)},_initialEvents:function(){this.collection&&(this.listenTo(this.collection,"add",this._onCollectionAdd),this.listenTo(this.collection,"update",this._onCollectionUpdate),this.listenTo(this.collection,"reset",this.render),this.sort&&this.listenTo(this.collection,"sort",this._sortViews))},_onCollectionAdd:function(e,i,n){var r=void 0!==n.at&&(n.index||i.indexOf(e));(this.filter||r===!1)&&(r=t.indexOf(this._filteredSortedModels(r),e)),this._shouldAddChild(e,r)&&(this._destroyEmptyView(),this._addChild(e,r))},_onCollectionUpdate:function(e,t){var i=t.changes;this._removeChildModels(i.removed)},_removeChildModels:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=t.checkEmpty,n=i!==!1,r=this._getRemovedViews(e);r.length&&(this.children._updateLength(),this._updateIndices(r,!1),n&&this._checkEmpty())},_getRemovedViews:function(e){var i=this;return t.reduce(e,function(e,t){var n=i.children.findByModel(t);return!n||n._isDestroyed?e:(i._removeChildView(n),e.push(n),e)},[])},_findGreatestIndexedView:function(e){return t.reduce(e,function(e,t){return!e||e._index1&&void 0!==arguments[1]?arguments[1]:{},i=t.preventRender,n=this._isRendered&&!this._isDestroyed,r=this.filter!==e,s=n&&r&&!i;if(s){var o=this._filteredSortedModels();this.filter=e;var h=this._filteredSortedModels();this._applyModelDeltas(h,o)}else this.filter=e;return this},removeFilter:function(e){return this.setFilter(null,e)},_applyModelDeltas:function(e,i){var n=this,r={};t.each(e,function(e,t){var i=!n.children.findByModel(e);i&&n._onCollectionAdd(e,n.collection,{at:t}),r[e.cid]=!0});var s=t.filter(i,function(e){return!r[e.cid]&&n.children.findByModel(e)});this._removeChildModels(s)},reorder:function(){var e=this,i=this.children,n=this._filteredSortedModels();if(!n.length&&this._showingEmptyView)return this;var r=t.some(n,function(e){return!i.findByModel(e)});return r?this.render():!function(){var r=[],s=i.reduce(function(e,i){var s=t.indexOf(n,i.model);return s===-1?(r.push(i.model),e):(i._index=s,e[s]=i.el,e)},new Array(n.length));e.triggerMethod("before:reorder",e),e._appendReorderedChildren(s),e._removeChildModels(r),e.triggerMethod("reorder",e)}(),this},resortView:function(){return this.reorderOnSort?this.reorder():this._renderChildren(),this},_sortViews:function(){var e=this,i=this._filteredSortedModels(),n=t.find(i,function(t,i){var n=e.children.findByModel(t);return!n||n._index!==i});n&&this.resortView()},_emptyViewIndex:-1,_appendReorderedChildren:function(e){this.$el.append(e)},_renderChildren:function(){this._isRendered&&(this._destroyEmptyView(),this._destroyChildren({checkEmpty:!1}));var e=this._filteredSortedModels();this.isEmpty({processedModels:e})?this._showEmptyView():(this.triggerMethod("before:render:children",this),this._startBuffering(),this._showCollection(e),this._endBuffering(),this.triggerMethod("render:children",this))},_createView:function(e,t){var i=this._getChildView(e),n=this._getChildViewOptions(e,t),r=this.buildChildView(e,i,n);return r},_setupChildView:function(e,t){e._parent=this,v(e),this._proxyChildEvents(e),this.sort&&(e._index=t)},_showCollection:function(e){t.each(e,t.bind(this._addChild,this)),this.children._updateLength()},_filteredSortedModels:function(e){if(!this.collection||!this.collection.length)return[];var t=this.getViewComparator(),i=this.collection.models;if(e=Math.min(Math.max(e,0),i.length-1),t){var n=void 0;e&&(n=i[e],i=i.slice(0,e).concat(i.slice(e+1))),i=this._sortModelsBy(i,t),n&&i.splice(e,0,n)}return i=this._filterModels(i)},getViewComparator:function(){return this.viewComparator},_filterModels:function(e){var i=this;return this.filter&&(e=t.filter(e,function(e,t){return i._shouldAddChild(e,t)})),e},_sortModelsBy:function(e,i){return"string"==typeof i?t.sortBy(e,function(e){return e.get(i)}):1===i.length?t.sortBy(e,t.bind(i,this)):e.sort(t.bind(i,this))},_showEmptyView:function(){var i=this._getEmptyView();if(i&&!this._showingEmptyView){this._showingEmptyView=!0;var n=new e.Model,r=this.emptyViewOptions||this.childViewOptions;t.isFunction(r)&&(r=r.call(this,n,this._emptyViewIndex));var s=this.buildChildView(n,i,r);this.triggerMethod("before:render:empty",this,s),this.addChildView(s,0),this.triggerMethod("render:empty",this,s)}},_destroyEmptyView:function(){this._showingEmptyView&&(this.triggerMethod("before:remove:empty",this),this._destroyChildren(),delete this._showingEmptyView,this.triggerMethod("remove:empty",this))},_getEmptyView:function(){var e=this.emptyView;if(e)return this._getView(e)},_getChildView:function(e){var t=this.childView;if(!t)throw new Y({name:"NoChildViewError",message:'A "childView" must be specified'});if(t=this._getView(t,e),!t)throw new Y({name:"InvalidChildViewError",message:'"childView" must be a view class or a function that returns a view class'});return t},_getView:function(i,n){return i.prototype instanceof e.View||i===e.View?i:t.isFunction(i)?i.call(this,n):void 0},_addChild:function(e,t){var i=this._createView(e,t);return this.addChildView(i,t),i},_getChildViewOptions:function(e,i){return t.isFunction(this.childViewOptions)?this.childViewOptions(e,i):this.childViewOptions},addChildView:function(e,t){return this.triggerMethod("before:add:child",this,e),this._setupChildView(e,t),this._isBuffering?this.children._add(e):(this._updateIndices(e,!0),this.children.add(e)),this._renderView(e),this._attachView(e,t),this.triggerMethod("add:child",this,e),e},_updateIndices:function(e,i){if(this.sort){var n=t.isArray(e)?this._findGreatestIndexedView(e):e;this.children.each(function(e){e._index>=n._index&&(e._index+=i?1:-1)})}},_renderView:function(e){e._isRendered||(e.supportsRenderLifecycle||s(e,"before:render",e),e.render(),e.supportsRenderLifecycle||(e._isRendered=!0,s(e,"render",e)))},_attachView:function(e,t){var i=!e._isAttached&&!this._isBuffering&&this._isAttached;i&&s(e,"before:attach",e),this.attachHtml(this,e,t),i&&(e._isAttached=!0,s(e,"attach",e))},buildChildView:function(e,i,n){var r=t.extend({model:e},n);return new i(r)},removeChildView:function(e){return!e||e._isDestroyed?e:(this._removeChildView(e),this.children._updateLength(),this._updateIndices(e,!1),e)},isEmpty:function(e){var i=void 0;return t.result(e,"processedModels")?i=e.processedModels:(i=this.collection?this.collection.models:[],i=this._filterModels(i)),0===i.length},_checkEmpty:function(){this.isEmpty()&&this._showEmptyView()},attachBuffer:function(e,t){e.$el.append(t)},_createBuffer:function(){var e=document.createDocumentFragment();return t.each(this._bufferedChildren,function(t){e.appendChild(t.el)}),e},attachHtml:function(e,t,i){e._isBuffering?e._bufferedChildren.splice(i,0,t):e._insertBefore(t,i)||e._insertAfter(t)},_insertBefore:function(e,t){var i=void 0,n=this.sort&&t1?i-1:0),r=1;rthis.length)n=this.length;if(n<0)n+=this.length+1;var s=[];var a=[];var h=[];var o=[];var l={};var u=e.add;var c=e.merge;var f=e.remove;var d=false;var v=this.comparator&&n==null&&e.sort!==false;var g=i.isString(this.comparator)?this.comparator:null;var p,m;for(m=0;m7);this._useHashChange=this._wantsHashChange&&this._hasHashChange;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.history&&this.history.pushState);this._usePushState=this._wantsPushState&&this._hasPushState;this.fragment=this.getFragment();this.root=("/"+this.root+"/").replace(O,"/");if(this._wantsHashChange&&this._wantsPushState){if(!this._hasPushState&&!this.atRoot()){var e=this.root.slice(0,-1)||"/";this.location.replace(e+"#"+this.getPath());return true}else if(this._hasPushState&&this.atRoot()){this.navigate(this.getHash(),{replace:true})}}if(!this._hasHashChange&&this._wantsHashChange&&!this._usePushState){this.iframe=document.createElement("iframe");this.iframe.src="javascript:0";this.iframe.style.display="none";this.iframe.tabIndex=-1;var r=document.body;var n=r.insertBefore(this.iframe,r.firstChild).contentWindow;n.document.open();n.document.close();n.location.hash="#"+this.fragment}var s=window.addEventListener||function(t,e){return attachEvent("on"+t,e)};if(this._usePushState){s("popstate",this.checkUrl,false)}else if(this._useHashChange&&!this.iframe){s("hashchange",this.checkUrl,false)}else if(this._wantsHashChange){this._checkUrlInterval=setInterval(this.checkUrl,this.interval)}if(!this.options.silent)return this.loadUrl()},stop:function(){var t=window.removeEventListener||function(t,e){return detachEvent("on"+t,e)};if(this._usePushState){t("popstate",this.checkUrl,false)}else if(this._useHashChange&&!this.iframe){t("hashchange",this.checkUrl,false)}if(this.iframe){document.body.removeChild(this.iframe);this.iframe=null}if(this._checkUrlInterval)clearInterval(this._checkUrlInterval);N.started=false},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe){e=this.getHash(this.iframe.contentWindow)}if(e===this.fragment)return false;if(this.iframe)this.navigate(e);this.loadUrl()},loadUrl:function(t){if(!this.matchRoot())return false;t=this.fragment=this.getFragment(t);return i.some(this.handlers,function(e){if(e.route.test(t)){e.callback(t);return true}})},navigate:function(t,e){if(!N.started)return false;if(!e||e===true)e={trigger:!!e};t=this.getFragment(t||"");var i=this.root;if(t===""||t.charAt(0)==="?"){i=i.slice(0,-1)||"/"}var r=i+t;t=this.decodeFragment(t.replace(U,""));if(this.fragment===t)return;this.fragment=t;if(this._usePushState){this.history[e.replace?"replaceState":"pushState"]({},document.title,r)}else if(this._wantsHashChange){this._updateHash(this.location,t,e.replace);if(this.iframe&&t!==this.getHash(this.iframe.contentWindow)){var n=this.iframe.contentWindow;if(!e.replace){n.document.open();n.document.close()}this._updateHash(n.location,t,e.replace)}}else{return this.location.assign(r)}if(e.trigger)return this.loadUrl(t)},_updateHash:function(t,e,i){if(i){var r=t.href.replace(/(javascript:|#).*$/,"");t.replace(r+"#"+e)}else{t.hash="#"+e}}});e.history=new N;var q=function(t,e){var r=this;var n;if(t&&i.has(t,"constructor")){n=t.constructor}else{n=function(){return r.apply(this,arguments)}}i.extend(n,r,e);n.prototype=i.create(r.prototype,t);n.prototype.constructor=n;n.__super__=r.prototype;return n};y.extend=x.extend=$.extend=k.extend=N.extend=q;var F=function(){throw new Error('A "url" property or function must be specified')};var B=function(t,e){var i=e.error;e.error=function(r){if(i)i.call(e.context,t,r,e);t.trigger("error",t,r,e)}};return e}); +//# sourceMappingURL=backbone-min.map \ No newline at end of file diff --git a/src/lib/backbone.radio.min.js b/src/lib/backbone.radio.min.js new file mode 100644 index 0000000..7fa28b0 --- /dev/null +++ b/src/lib/backbone.radio.min.js @@ -0,0 +1,3 @@ +// Backbone.Radio v2.0.0 +!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n(require("underscore"),require("backbone")):"function"==typeof define&&define.amd?define(["underscore","backbone"],n):(e.Backbone=e.Backbone||{},e.Backbone.Radio=n(e._,e.Backbone))}(this,function(e,n){"use strict";function t(e,n,t,r){var o=e[n];if(!(t&&t!==o.callback&&t!==o.callback._callback||r&&r!==o.context))return delete e[n],!0}function r(n,r,o,i){n||(n={});for(var s=r?[r]:e.keys(n),u=!1,c=0,a=s.length;cthis.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}if(e.hasClass("active"))return this.sliding=!1;var j=e[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:g});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,f&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(e)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:g});return a.support.transition&&this.$element.hasClass("slide")?(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one("bsTransitionEnd",function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(1e3*d.css("transition-duration").slice(0,-1))):(d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger(m)),f&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(b=!b),e||d.data("bs.collapse",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};c.VERSION="3.2.0",c.DEFAULTS={toggle:!0},c.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},c.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var c=a.Event("show.bs.collapse");if(this.$element.trigger(c),!c.isDefaultPrevented()){var d=this.$parent&&this.$parent.find("> .panel > .in");if(d&&d.length){var e=d.data("bs.collapse");if(e&&e.transitioning)return;b.call(d,"hide"),e||d.data("bs.collapse",null)}var f=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[f](0),this.transitioning=1;var g=function(){this.$element.removeClass("collapsing").addClass("collapse in")[f](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return g.call(this);var h=a.camelCase(["scroll",f].join("-"));this.$element.one("bsTransitionEnd",a.proxy(g,this)).emulateTransitionEnd(350)[f](this.$element[0][h])}}},c.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(d,this)).emulateTransitionEnd(350):d.call(this)}}},c.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var d=a.fn.collapse;a.fn.collapse=b,a.fn.collapse.Constructor=c,a.fn.collapse.noConflict=function(){return a.fn.collapse=d,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(c){var d,e=a(this),f=e.attr("data-target")||c.preventDefault()||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),g=a(f),h=g.data("bs.collapse"),i=h?"toggle":e.data(),j=e.attr("data-parent"),k=j&&a(j);h&&h.transitioning||(k&&k.find('[data-toggle="collapse"][data-parent="'+j+'"]').not(e).addClass("collapsed"),e[g.hasClass("in")?"addClass":"removeClass"]("collapsed")),b.call(g,i)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=c(a(this)),e={relatedTarget:this};d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown",e)),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown",e))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.2.0",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('