-
Notifications
You must be signed in to change notification settings - Fork 2
/
backbone-dom-view.min.js
1 lines (1 loc) · 17 KB
/
backbone-dom-view.min.js
1
!function(factory){"function"==typeof define&&define.amd?define(["backbone","underscore"],factory):Backbone.DOMView=factory(Backbone,_)}(function(BB,_){"use strict";function DOMView(ops){ops=ops||{},has(ops,"parent")&&(this.parent=ops.parent),this.attributes={},this.callbacks={};for(var name in ops)has(ops,name)&&"function"==typeof ops[name]&&(this.callbacks[name]=ops[name]);this.defaults&&this.set(mergeExtendedField(this,"defaults")),View.apply(this,arguments),helpers.template.call(this,"",this.template),this.trigger(DOMView.readyEvent)}function ensureUI(view,name){var selector=view.ui[name];return"string"==typeof selector&&(view.ui[name]=view.find(selector)),view.ui[name]}function listenElement(method){return function(node,events){this._listenElement||(this._listenElement=[]);var ns=".listenBy"+this.cid;-1===this._listenElement.indexOf(node)&&this._listenElement.push(node),node=node instanceof $?node:$(node),events&&(events=events.split(/\s+/).map(function(event){return event+ns}).join(" "));var view=this,args=_.rest(arguments).map(function(arg){if("function"==typeof arg){var key="_bindWith"+view.cid;return arg[key]||(arg[key]=_.bind(arg,view)),arg[key]}return arg});return args[0]=events,node[method].apply(node,args),this}}function templateHelper(rootSelector,template){var selector,selectors=this.selectorsSorter(template);rootSelector&&has(this.ui,rootSelector)&&(rootSelector="{"+rootSelector+"}");for(var i=0,len=selectors.length;i<len;i++){selector=selectors[i];var helpersList=template[selector];rootSelector&&(selector="&"===selector.charAt(0)?selector.slice(1):" "+selector);for(var helper in helpersList)if(has(helpersList,helper))if("&"!==helper.charAt(0))helpers[helper].call(this,rootSelector+selector,helpersList[helper]);else{var ops={};ops[helper]=helpersList[helper],templateHelper.call(this,rootSelector+selector,ops)}}}function classHelper(selector,options){callJquerySetterMethod({view:this,node:this.find(selector),method:"toggleClass",options:options,wrapper:function(v){return _.isFunction(v)?function(){return!!v.apply(this,arguments)}:!!v}})}function attrHelper(selector,options){callJquerySetterMethod({view:this,node:this.find(selector),method:"attr",options:options})}function propHelper(selector,options){callJquerySetterMethod({view:this,node:this.find(selector),method:"prop",options:options})}function styleHelper(selector,options){callJquerySetterMethod({view:this,node:this.find(selector),method:"css",options:options})}function htmlHelper(selector,options){callJqueryMethod({view:this,node:this.find(selector),method:"html",options:options})}function safeHtmlHelper(selector,options){var dangerTagStart=/<(?:script|style|link|meta|iframe|frame)\b/gi,dangerTagEnd=/<\/(?:script|style|link|meta|iframe|frame)\b/gi,isWord=/\w/;callJqueryMethod({view:this,node:this.find(selector),method:"html",options:options,wrapper:function(html){html=html.replace(dangerTagStart,'<div style="display: none;"').replace(dangerTagEnd,"</div");for(var attr,char,context=0,i=0,len=html.length;i<len;i++)char=html[i],0===context&&"<"===char&&isWord.test(html[i+1])?context=1:">"!==char||5===context&&" "!==attr?" "===char&&1===context?context=2:" "!==char&&2===context?(context=3,"o"===char&&"n"===html[i+1]&&(html=html.slice(0,i)+"x-"+html.slice(i+2))):"="===char&&3===context?context=4:'"'!==char&&"'"!==char||4!==context?" "!==char&&4===context?(attr=" ",context=5):char===attr&&5===context&&(attr=!1,context=2):(attr=char,context=5):context=0;return html}})}function textHelper(selector,options){callJqueryMethod({view:this,node:this.find(selector),method:"text",options:options,wrapper:function(value){return _.isNull(value)||_.isUndefined(value)?"":value}})}function onHelper(listenMethod){return function(selector,options){var ops,view=this,node=this.find(selector);for(var event in options)if(has(options,event))switch(typeof(ops=options[event])){case"function":this[listenMethod](node,event,ops);break;case"object":for(var target in ops)has(ops,target)&&this[listenMethod](node,event,target,ops[target]);break;case"string":!function(method){var prevent="!"===method.charAt(0);prevent&&(method=method.slice(1)),view[listenMethod](node,event,function(e){prevent&&e.preventDefault(),method&&this[method]()})}(ops)}}}function clickHelper(selector,options){helpers.on.call(this,selector,{click:options})}function connectHelper(selector,options){function connectHelperBind(prop,field){var event="change",propEvent=prop.split("|");2===propEvent.length&&(prop=propEvent[0],event=propEvent[1]);var target=view.has(field)?view:view.model;view.listenElement(node,event,function(e){target.set(field,e.currentTarget[prop])}),view.listenTo(target,"change:"+field,function(model,value){node.prop(prop,value)}),node.prop(prop,target.get(field))}var view=this,node=view.find(selector);for(var prop in options)has(options,prop)&&connectHelperBind(prop,options[prop])}function visibleHelper(selector,options){callJquerySetterMethod({view:this,node:this.find(selector),method:"css",options:{display:options},wrapper:function(v){return v?"":"none"}})}function hiddenHelper(selector,options){callJquerySetterMethod({view:this,node:this.find(selector),method:"css",options:{display:options},wrapper:function(v){return v?"none":""}})}function callJqueryMethod(ops){function bindEvents(events,func){view.bind(events,function(){ops.value=func?func.apply(view,arguments):arguments[0],applyJqueryMethod(ops)})}var view=ops.view,model=view.model,options=ops.options;switch(ops=_.extend({model:model},ops),typeof options){case"string":bindEvents(options);break;case"object":if(null===options)break;for(var events in options)has(options,events)&&null!==options[events]&&bindEvents(events,options[events]);break;case"function":ops.value=options.apply(view,arguments),applyJqueryMethod(ops);break;default:throw new Error("Unknown options type")}}function applyJqueryMethod(ops){var view=ops.view,node=ops.node,method=ops.method,fieldName=ops.fieldName,value=ops.value,wrapper=ops.wrapper;view.ignoreEmptyNodeWarning;_.isFunction(value)?node.each(function(i,item){var val=value.call(view,i,item);wrapper&&(val=wrapper(val)),fieldName?$(item)[method](fieldName,val):$(item)[method](val)}):(wrapper&&(value=wrapper(value)),fieldName?node[method](fieldName,value):node[method](value))}function callJquerySetterMethod(ops){var options=ops.options;for(var name in options)has(options,name)&&(ops.fieldName=name,ops.options=options[name],callJqueryMethod(ops))}function eachHelper(selector,options){function eachAddListener(model,collection,ops){var View=isClass(options.view)?options.view:options.view.call(view,model),childView=View;if(isClass(View)){var el,viewOps={model:model,parent:view};viewElMap&&_.find(viewElMap,function(item){var field=_.isFunction(item.field)?item.field(model):model.get(item.field);return!!(el=item.nodes[field])}),el||(el=viewEl),el&&(viewOps.el=el.clone()),childView=new View(viewOps)}childView.parent=childView.parent||view,viewList[model.cid]=childView,addHandler.call(view,holder,childView,ops),childView.trigger(options.addedEvent)}function eachResetListener(model,ops){ops.previousModels.forEach(eachRemoveListener),list.each(eachAddListener)}function eachRemoveListener(model){var subView=viewList[model.cid];delHandler.call(view,holder,subView),subView.trigger(options.removeEvent,view),subView.parent===view&&(subView.parent=null),options.offOnRemove&&subView.off().stopListening().stopListeningElement(),delete viewList[model.cid]}function eachTriggerChangeEvent(){view.trigger("change:"+options.field,view,list)}function eachSortHandler(){sort.field?list.toArray().sort(sortByField).reduce(sortViews):list.reduce(sortViews)}function sortViews(prev,model,i){if(1===i){var first=viewList[prev.cid].$el;holder.prepend(first),prev=first}return viewList[model.cid].$el.insertAfter(prev)}function sortByField(a,b){a=a.get(sort.field),b=b.get(sort.field);var order=sort.order&&"asc"!==sort.order?1:-1;return a<b?order:a===b?0:-order}function eachSortListByViewsHandler(){sortByViews.field?list.forEach(function(model){model.set(sortByViews.field,modelViewIndex(model))}):list.models=list.sortBy(modelViewIndex)}function modelViewIndex(model){return viewList[model.cid].$el.index()}_.defaults(options,{addHandler:"append",delHandler:"remove",addEvent:"add",resetEvent:"reset",removeEvent:"remove",addedEvent:"added",sort:!1,sortByViews:!1,offOnRemove:!0}),options.eachAddListener=eachAddListener,options.eachResetListener=eachResetListener,options.eachRemoveListener=eachRemoveListener;var viewEl,viewElMap,fieldName,fieldClass,view=this,holder=view.find(selector),list=view.model;switch("function"==typeof options.el&&(options.el=options.el.call(view,holder)),typeof options.el){case"string":viewEl=holder.find(options.el).detach();break;case"object":options.el instanceof $?viewEl=options.el.detach():viewElMap=_.map(options.el,function(field,attr){var nodes={};return holder.find("> ["+attr+"]").detach().each(function(i,node){nodes[node.getAttribute(attr)]=$(node)}),{field:field,nodes:nodes}})}if(options.removeClass&&(viewEl?viewEl.removeClass(options.removeClass):viewElMap&&viewElMap.forEach(function(item){_.invoke(item.nodes,"removeClass",options.removeClass)})),options.field){var field=options.field;fieldName=field,"object"==typeof field&&(fieldName=field.name,fieldClass=field.wrapper),list=view.get(fieldName)||view.model.get(fieldName)}var viewList=options.viewList=new EachViewList,addHandler=options.addHandler,delHandler=options.delHandler;"string"==typeof addHandler&&(addHandler=eachHelper.addHandlers[addHandler]),"string"==typeof delHandler&&(delHandler=eachHelper.delHandlers[delHandler]);var sort=options.sort;sort&&view.listenTo(list,sort.event||"sort",eachSortHandler);var sortByViews=options.sortByViews;if(sortByViews){var sortEvent="string"==typeof sortByViews?sortByViews:sortByViews.event;view.on(sortEvent,eachSortListByViewsHandler)}fieldClass?isClass(fieldClass)?(list=new fieldClass,view.listenTo(list,options.addEvent,eachAddListener).listenTo(list,options.resetEvent,eachResetListener).listenTo(list,options.removeEvent,eachRemoveListener),view.bind("@"+fieldName,function(data){list.set(data)})):(list=null,view.bind("@"+fieldName,function(data){list&&(list.each(eachRemoveListener),list.reset([])),list=fieldClass.call(view,data),list.each(eachAddListener)})):(view.listenTo(list,options.addEvent,eachAddListener).listenTo(list,options.resetEvent,eachResetListener).listenTo(list,options.removeEvent,eachRemoveListener),options.field&&view.listenTo(list,[options.addEvent,options.removeEvent,options.resetEvent].join(" "),eachTriggerChangeEvent),list.each(eachAddListener)),options.viewProp&&(this[options.viewProp]=viewList)}function EachViewList(){}function isClass(func){return has(func,"prototype")&&_.isFunction(func.prototype.initialize)}function getViewExtendedFieldList(viewClass,field,context){var value=viewClass.prototype[field]||{};_.isFunction(value)&&(value=value.call(context,cloneDeep));var result=[value];return viewClass.__super__?result.concat(getViewExtendedFieldList(viewClass.__super__.constructor,field,context)):result}function mergeExtendedField(context,field,deep){var viewClass=context.constructor;return(deep?cloneDeep:clone).apply(null,getViewExtendedFieldList(viewClass,field,context).reverse())}function clone(){for(var target={},i=0,len=arguments.length;i<len;i++)$.extend(target,arguments[i]);return target}function cloneDeep(){for(var target={},i=0,len=arguments.length;i<len;i++)$.extend(!0,target,arguments[i]);return target}DOMView.v="1.67.1";var View=BB.View,$=BB.$;BB.DOMView=View.extend({constructor:DOMView,ui:{root:""},selectorsSorter:_.keys,setElement:function(){View.prototype.setElement.apply(this,arguments);var ui=this.ui=mergeExtendedField(this,"ui");for(var name in ui)has(ui,name)&&"string"==typeof ui[name]&&ensureUI(this,name);return this.template=mergeExtendedField(this,"template",!0),this.trigger(DOMView.elementEvent),this},find:function(selector){if(!selector)return this.$el;if(this.ui[selector])return ensureUI(this,selector);if(selector.indexOf("{")>-1){var view=this,rootSelectorLength=this.$el.selector&&this.$el.selector.length;selector=selector.replace(uiSelectors,function(x,name){var selector=ensureUI(view,name).selector||"";return rootSelectorLength?selector.slice(rootSelectorLength):selector})}var node=this.$el.find(selector);return node.selector||(node.selector=selector),node},bind:function(events,callback){function parseEvent(event){function bindApplyCallback(){var args=null===argNum?arguments:[arguments[argNum]];return argNot&&(args[0]=!args[0]),callback.apply(view,args)}var target=model,argNum=null,argNot="!"===event.charAt(0);switch(argNot&&(event=event.slice(1)),event.charAt(0)){case"=":return event=event.slice(1),target=has(view.attributes,event)?view:model,void bindApplyCallback(target.get(event));case"@":event=event.slice(1),target=has(view.attributes,event)?view:model,argNum=1,bindApplyCallback(target,target.get(event)),event="change:"+event;break;case"/":event=event.slice(1),target=has(view.attributes,event)?view:model,argNum=1,event="change:"+event;break;case"#":event=event.slice(1),target=view}event||console.warn("Empty event name"),target===model?view.listenTo(model,event,bindApplyCallback):view.on(event,bindApplyCallback)}var view=this,model=view.model;if(1===arguments.length&&"object"==typeof events){var ops=events;events=ops.events,callback=ops.callback,has(ops,"model")&&(model=ops.model)}if(events=events.trim().split(/\s+/),events.every(function(e){return">"===e||"/"===e.charAt(0)})){var origin=callback,fields=(">"===events[0]?events.slice(1):events).map(function(field){return field.slice(1)});callback=function(){return origin.apply(this,fields.map(function(field){return has(view.attributes,field)?view.get(field):view.model.get(field)}))}}for(var i=0,len=events.length;i<len;i++)">"!==events[i]?parseEvent(events[i]):callback.call(this);return this},bindTo:function(model,events,callback){return this.bind({model:model,events:events,callback:callback})},matches:function(attrs){for(var key in attrs)if(has(attrs,key)&&attrs[key]!==this.get(key)){if(!(attrs[key]instanceof RegExp))return!1;if(!attrs[key].test(this.get(key)))return!1}return!0},get:BB.Model.prototype.get,set:BB.Model.prototype.set,has:BB.Model.prototype.has,pick:BB.Model.prototype.pick,omit:BB.Model.prototype.omit,_validate:BB.Model.prototype._validate,getViewList:function(selector){return this.template[selector].each.viewList},listenElement:listenElement("on"),listenElementOnce:listenElement("one"),stopListeningElement:function(node,events){if(!this._listenElement)return this;var ns=".listenBy"+this.cid;node&&(node=node instanceof $?node:$(node)),events&&(events=events.split(/\s+/).map(function(event){return event+ns}).join(" "));var i,len;switch(arguments.length){case 0:for(i=0,len=this._listenElement.length;i<len;i++)$(this._listenElement[i]).off(ns);this._listenElement=null;break;case 1:node.off(ns);break;case 2:node.off(events);break;default:var view=this,args=_.rest(arguments).map(function(arg){return"function"==typeof arg&&arg["_bindWith"+view.cid]?arg["_bindWith"+view.cid]:arg});args[0]=events,node.off.apply(node,args)}return this}}),DOMView.readyEvent="template-ready",DOMView.elementEvent="element-ready";var helpers=DOMView.helpers={template:templateHelper,class:classHelper,toggleClass:classHelper,attr:attrHelper,prop:propHelper,style:styleHelper,html:htmlHelper,safeHtml:safeHtmlHelper,text:textHelper,on:onHelper("listenElement"),once:onHelper("listenElementOnce"),click:clickHelper,connect:connectHelper,visible:visibleHelper,hidden:hiddenHelper,each:eachHelper},uiSelectors=/\{([^}]+)}/g;eachHelper.addHandlers={append:function(ul,view){ul.append(view.$el)},appendAt:function(ul,view,ops){has(ops,"at")?0===ops.at?ul.prepend(view.$el):view.$el.insertAfter(ul.children().get(ops.at-1)):ul.append(view.$el)},prepend:function(ul,view){ul.prepend(view.$el)},fadeIn:function(ul,view){view.$el.hide().appendTo(ul).fadeIn()},slideDown:function(ul,view){view.$el.hide().appendTo(ul).slideDown()}},eachHelper.delHandlers={remove:function(ul,view){view.$el.remove()},fadeOut:function(ul,view){view.$el.fadeOut(function(){return view.$el.remove()})},slideUp:function(ul,view){view.$el.slideUp(function(){return view.$el.remove()})}},eachHelper.EachViewList=EachViewList,_.extend(EachViewList.prototype,{where:function(attrs,first){return this[first?"find":"filter"](function(view){return view.matches(attrs)})},findWhere:function(attrs){return this.where(attrs,!0)},count:function(attrs){var count=0;return this.forEach(function(view){view.matches(attrs)&&count++}),count},getModels:function(){return this.map(function(view){return view.model})},getByEl:function(el){return el instanceof $&&(el=el.get(0)),this.find(function(view){return view.el===el})},get:function(id){return this[id]||this[id.cid]||this.find(function(item){return item.cid===id||item.model===id||item.model.id===id||item.model.id===id.id})}}),_.forEach(["forEach","map","reduce","reduceRight","find","filter","reject","every","some","max","min"],function(name){EachViewList.prototype[name]=function(cb){return _[name](this,cb,this)}}),_.forEach(["contains","invoke","toArray","size","without","difference","isEmpty","chain"],function(name){EachViewList.prototype[name]=function(){var args=_.toArray(arguments);return args.unshift(this),_[name].apply(_,args)}});var has=_.has;return DOMView});