Form Builder | Create Responsive Contact Forms - Version 1.8

Version Description

  • Added drag and drop in contact form editing panel.
  • Bug Fixes.
Download this release

Release Info

Developer umarbajwa
Plugin Icon 128x128 Form Builder | Create Responsive Contact Forms
Version 1.8
Comparing to
See all releases

Code changes from version 1.7 to 1.8

admin/assets/js/backbone.min.js CHANGED
@@ -5,6 +5,1766 @@
5
  * Copyright (c)2013 Rotunda Software, LLC.
6
  * Distributed under MIT license
7
  * http://github.com/rotundasoftware/backbone-collection-view
 
 
 
 
 
 
 
 
 
8
  */
9
 
10
- !function(a,b){"function"==typeof define&&define.amd?define(["underscore","backbone","jquery"],b):"undefined"!=typeof exports?module.exports=b(require("underscore"),require("backbone"),require("backbone").$):b(a._,a.Backbone,a.jQuery||a.Zepto||a.$)}(this,function(a,b,c){function d(b){var c=[];if(!a.isArray(b))throw new Error("Option declarations must be an array.");return a.each(b,function(b){var d,e,f;if(e=!1,f=void 0,a.isString(b))d=b;else{if(!a.isObject(b))throw new Error("Each element in the option declarations array must be either a string or an object.");d=a.first(a.keys(b)),f=a.clone(b[d])}"!"===d[d.length-1]&&(e=!0,d=d.slice(0,d.length-1)),c.push({name:d,required:e,defaultValue:f})}),c}var e=b.View,f="model",g=["collection","modelView","modelViewOptions","itemTemplate","itemTemplateFunction","detachedRendering"],h={background:"transparent",border:"none","box-shadow":"none"};return b.CollectionView=b.View.extend({tagName:"ul",events:{"mousedown > li, tbody > tr > td":"_listItem_onMousedown","dblclick > li, tbody > tr > td":"_listItem_onDoubleClick",click:"_listBackground_onClick","click ul.collection-view, table.collection-view":"_listBackground_onClick",keydown:"_onKeydown"},spawnMessages:{focus:"focus"},passMessages:{"*":"."},initializationOptions:[{collection:null},{modelView:null},{modelViewOptions:{}},{itemTemplate:null},{itemTemplateFunction:null},{selectable:!0},{clickToSelect:!0},{selectableModelsFilter:null},{visibleModelsFilter:null},{sortableModelsFilter:null},{selectMultiple:!1},{clickToToggle:!1},{processKeyEvents:!0},{sortable:!1},{sortableOptions:null},{reuseModelViews:!0},{detachedRendering:!1},{emptyListCaption:null}],initialize:function(a){b.ViewOptions.add(this,"initializationOptions"),this.setOptions(a),this.collection||(this.collection=new b.Collection),this._hasBeenRendered=!1,this._isBackboneCourierAvailable()&&b.Courier.add(this),this.$el.data("view",this),this.$el.addClass("collection-view collection-list"),this.selectable&&this.$el.addClass("selectable"),this.processKeyEvents&&this.$el.attr("tabindex",0),this.selectedItems=[],this._updateItemTemplate(),this.collection&&this._registerCollectionEvents(),this.viewManager=new ChildViewContainer},onOptionsChanged:function(b,c){var d=this,e=!1;a.each(a.keys(b),function(f){var h=b[f],i=c[f];switch(f){case"collection":h!==i&&(d.stopListening(i),d._registerCollectionEvents());break;case"selectMultiple":!h&&d.selectedItems.length>1&&d.setSelectedModel(a.first(d.selectedItems),{by:"cid"});break;case"selectable":!h&&d.selectedItems.length>0&&d.setSelectedModels([]);break;case"sortable":b.sortable?d._setupSortable():d.$el.sortable("destroy");break;case"selectableModelsFilter":d.reapplyFilter("selectableModels");break;case"sortableOptions":d.$el.sortable("destroy"),d._setupSortable();break;case"sortableModelsFilter":d.reapplyFilter("sortableModels");break;case"visibleModelsFilter":d.reapplyFilter("visibleModels");break;case"itemTemplate":d._updateItemTemplate();break;case"processKeyEvents":h&&d.$el.attr("tabindex",0);break;case"modelView":d.viewManager.each(function(a){d.viewManager.remove(a),a.remove()})}a.contains(g,f)&&(e=!0)}),this._hasBeenRendered&&e&&this.render()},setOption:function(a,b){var c={};c[a]=b,this.setOptions(c)},getSelectedModel:function(b){return this.selectedItems.length?a.first(this.getSelectedModels(b)):null},getSelectedModels:function(b){var d=this;b=a.extend({},{by:f},b);var e=b.by,g=[];switch(e){case"id":a.each(this.selectedItems,function(a){g.push(d.collection.get(a).id)});break;case"cid":g=g.concat(this.selectedItems);break;case"offset":var h=0,i=this._getVisibleItemEls();i.each(function(){var a=c(this);a.is(".selected")&&g.push(h),h++});break;case"model":a.each(this.selectedItems,function(a){g.push(d.collection.get(a))});break;case"view":a.each(this.selectedItems,function(a){g.push(d.viewManager.findByModel(d.collection.get(a)))});break;default:throw new Error("Invalid referenceBy option: "+e)}return g},setSelectedModels:function(b,d){if(!a.isArray(b))throw"Invalid parameter value";if(this.selectable||!(b.length>0)){d=a.extend({},{silent:!1,by:f},d);var e=d.by,g=[];switch(e){case"cid":g=b;break;case"id":this.collection.each(function(c){a.contains(b,c.id)&&g.push(c.cid)});break;case"model":g=a.pluck(b,"cid");break;case"view":a.each(b,function(a){g.push(a.model.cid)});break;case"offset":var h=0,i=this._getVisibleItemEls();i.each(function(){var d=c(this);a.contains(b,h)&&g.push(d.attr("data-model-cid")),h++});break;default:throw new Error("Invalid referenceBy option: "+e)}var j=this.getSelectedModels(),k=a.clone(this.selectedItems);this.selectedItems=this._convertStringsToInts(g),this._validateSelection();var l=this.getSelectedModels();this._containSameElements(k,this.selectedItems)||(this._addSelectedClassToSelectedItems(k),d.silent||(this._isBackboneCourierAvailable()?this.spawn("selectionChanged",{selectedModels:l,oldSelectedModels:j}):this.trigger("selectionChanged",l,j)),this.updateDependentControls())}},setSelectedModel:function(a,b){a||0===a?this.setSelectedModels([a],b):this.setSelectedModels([],b)},render:function(){this._hasBeenRendered=!0,this.selectable&&this._saveSelection();var b;b=this._getContainerEl();var c=this.viewManager;this.viewManager=new ChildViewContainer,c.each(function(a){this.reuseModelViews&&this.collection.get(a.model.cid)?a.$el.detach():a.remove()},this),b.empty();var d;this.detachedRendering&&(d=document.createDocumentFragment()),this.collection.each(function(e){var f=c.findByModelCid(e.cid);(!this.reuseModelViews||a.isUndefined(f))&&(f=this._createNewModelView(e,this._getModelViewOptions(e))),this._insertAndRenderModelView(f,d||b)},this),this.detachedRendering&&b.append(d),this.sortable&&this._setupSortable(),this._showEmptyListCaptionIfAppropriate(),this._isBackboneCourierAvailable()?this.spawn("render"):this.trigger("render"),this.selectable&&(this._restoreSelection(),this.updateDependentControls()),this.forceRerenderOnNextSortEvent=!1},_showEmptyListCaptionIfAppropriate:function(){if(this._removeEmptyListCaption(),this.emptyListCaption){var b=this._getVisibleItemEls();if(0===b.length){var d;d=a.isFunction(this.emptyListCaption)?this.emptyListCaption():this.emptyListCaption;var e,f=c("<var class='empty-list-caption'>"+d+"</var>");e=this._isRenderedAsList()?f.wrapAll("<li class='not-sortable'></li>").parent().css(h):f.wrapAll("<tr class='not-sortable'><td colspan='1000'></td></tr>").parent().parent().css(h),this._getContainerEl().append(e)}}},_removeEmptyListCaption:function(){this._isRenderedAsList()?this._getContainerEl().find("> li > var.empty-list-caption").parent().remove():this._getContainerEl().find("> tr > td > var.empty-list-caption").parent().parent().remove()},_insertAndRenderModelView:function(b,c,d){var e=this._wrapModelView(b);if(11===c.nodeType)c.appendChild(e.get(0));else{var f=c.children().length;!a.isUndefined(d)&&d>=0&&f>d?c.children().eq(d).before(e):(!a.isUndefined(d)&&d>f&&(this.forceRerenderOnNextSortEvent=!0),c.append(e))}var g=b.render();g===!1&&(e.hide(),e.addClass("not-visible"));var h=!1;a.isFunction(this.visibleModelsFilter)&&(h=!this.visibleModelsFilter(b.model)),1===e.children().length?e.toggle(!h):b.$el.toggle(!h),e.toggleClass("not-visible",h),!h&&this.emptyListCaption&&this._removeEmptyListCaption(),this.viewManager.add(b)},updateDependentControls:function(){this._isBackboneCourierAvailable()?this.spawn("updateDependentControls",{selectedModels:this.getSelectedModels()}):this.trigger("updateDependentControls",this.getSelectedModels())},remove:function(){this.viewManager.each(function(a){a.remove()}),b.View.prototype.remove.apply(this,arguments)},reapplyFilter:function(b){var c=this;if(!a.contains(["selectableModels","sortableModels","visibleModels"],b))throw new Error("Invalid filter identifier supplied to reapplyFilter: "+b);switch(b){case"visibleModels":c.viewManager.each(function(a){var b=c.visibleModelsFilter&&!c.visibleModelsFilter.call(c,a.model);a.$el.toggleClass("not-visible",b),c._modelViewHasWrapperLI(a)?a.$el.closest("li").toggleClass("not-visible",b).toggle(!b):a.$el.toggle(!b)}),this._showEmptyListCaptionIfAppropriate();break;case"sortableModels":c.$el.sortable("destroy"),c.viewManager.each(function(a){var b=c.sortableModelsFilter&&!c.sortableModelsFilter.call(c,a.model);a.$el.toggleClass("not-sortable",b),c._modelViewHasWrapperLI(a)&&a.$el.closest("li").toggleClass("not-sortable",b)}),c._setupSortable();break;case"selectableModels":c.viewManager.each(function(a){var b=c.selectableModelsFilter&&!c.selectableModelsFilter.call(c,a.model);a.$el.toggleClass("not-selectable",b),c._modelViewHasWrapperLI(a)&&a.$el.closest("li").toggleClass("not-selectable",b)}),c._validateSelection()}},_removeModelView:function(a){this.selectable&&this._saveSelection(),this.viewManager.remove(a),this._modelViewHasWrapperLI(a)&&a.$el.parent().remove(),a.remove(),this.selectable&&this._restoreSelection(),this._showEmptyListCaptionIfAppropriate()},_validateSelectionAndRender:function(){this._validateSelection(),this.render()},_registerCollectionEvents:function(){this.listenTo(this.collection,"add",function(a){var b;this._hasBeenRendered&&(b=this._createNewModelView(a,this._getModelViewOptions(a)),this._insertAndRenderModelView(b,this._getContainerEl(),this.collection.indexOf(a))),this._isBackboneCourierAvailable()?this.spawn("add",b):this.trigger("add",b)}),this.listenTo(this.collection,"remove",function(a){var b;this._hasBeenRendered&&(b=this.viewManager.findByModelCid(a.cid),this._removeModelView(b)),this._isBackboneCourierAvailable()?this.spawn("remove"):this.trigger("remove")}),this.listenTo(this.collection,"reset",function(){this._hasBeenRendered&&this.render(),this._isBackboneCourierAvailable()?this.spawn("reset"):this.trigger("reset")}),this.listenTo(this.collection,"sort",function(a,b){this._hasBeenRendered&&(b.add!==!0||this.forceRerenderOnNextSortEvent)&&this.render(),this._isBackboneCourierAvailable()?this.spawn("sort"):this.trigger("sort")})},_getContainerEl:function(){if(this._isRenderedAsTable()){var a=this.$el.find("> tbody");if(a.length>0)return a}return this.$el},_getClickedItemId:function(a){var b=null,d=c(a.currentTarget);if(d.closest(".collection-view").get(0)===this.$el.get(0)){var e=d.closest("[data-model-cid]");return e.length>0&&(b=e.attr("data-model-cid"),c.isNumeric(b)&&(b=parseInt(b,10))),b}},_updateItemTemplate:function(){var b;if(this.itemTemplate){if(0===c(this.itemTemplate).length)throw"Could not find item template from selector: "+this.itemTemplate;b=c(this.itemTemplate).html()}else b=this.$(".item-template").html();b&&(this.itemTemplateFunction=a.template(b))},_validateSelection:function(){var b=a.pluck(this.collection.models,"cid");this.selectedItems=a.intersection(b,this.selectedItems),a.isFunction(this.selectableModelsFilter)&&(this.selectedItems=a.filter(this.selectedItems,function(a){return this.selectableModelsFilter.call(this,this.collection.get(a))},this))},_saveSelection:function(){if(!this.selectable)throw"Attempt to save selection on non-selectable list";this.savedSelection={items:a.clone(this.selectedItems),offset:this.getSelectedModel({by:"offset"})}},_restoreSelection:function(){if(!this.savedSelection)throw"Attempt to restore selection but no selection has been saved!";this.setSelectedModels([],{silent:!0}),this.savedSelection.items.length>0&&(this.setSelectedModels(this.savedSelection.items,{by:"cid",silent:!0}),0===this.selectedItems.length&&this.setSelectedModel(this.savedSelection.offset,{by:"offset"}),this.selectedItems.length!==this.savedSelection.items.length&&(this._isBackboneCourierAvailable()?this.spawn("selectionChanged",{selectedModels:this.getSelectedModels(),oldSelectedModels:[]}):this.trigger("selectionChanged",this.getSelectedModels(),[]))),delete this.savedSelection},_addSelectedClassToSelectedItems:function(b){a.isUndefined(b)&&(b=[]);var c=b;c=a.without(c,this.selectedItems),a.each(c,function(a){this._getContainerEl().find("[data-model-cid="+a+"]").removeClass("selected"),this._isRenderedAsList()&&this._getContainerEl().find("li[data-model-cid="+a+"] > *").removeClass("selected")},this);var d=this.selectedItems;d=a.without(d,b),a.each(d,function(a){this._getContainerEl().find("[data-model-cid="+a+"]").addClass("selected"),this._isRenderedAsList()&&this._getContainerEl().find("li[data-model-cid="+a+"] > *").addClass("selected")},this)},_reorderCollectionBasedOnHTML:function(){var a=this;this._getContainerEl().children().each(function(){var b=c(this).attr("data-model-cid");if(b){var d=a.collection.get(b);d&&(a.collection.remove(d,{silent:!0}),a.collection.add(d,{silent:!0,sort:!a.collection.comparator}))}}),this._isBackboneCourierAvailable()?this.spawn("reorder"):this.collection.trigger("reorder"),this.collection.comparator&&this.collection.sort()},_getModelViewConstructor:function(a){return this.modelView||e},_getModelViewOptions:function(b){var c=this.modelViewOptions;return a.isFunction(c)&&(c=c(b)),a.extend({model:b},c)},_createNewModelView:function(b,c){var d=this._getModelViewConstructor(b);if(a.isUndefined(d))throw"Could not find modelView constructor for model";var e=new d(c);return e.collectionListView=e.collectionView=this,e},_wrapModelView:function(b){var c,d=this;return this._isRenderedAsTable()?(c=b.$el,b.$el.attr("data-model-cid",b.model.cid)):this._isRenderedAsList()&&(b.$el.is("li")?(c=b.$el,b.$el.attr("data-model-cid",b.model.cid)):c=b.$el.wrapAll("<li data-model-cid='"+b.model.cid+"'></li>").parent()),a.isFunction(this.sortableModelsFilter)&&(this.sortableModelsFilter.call(d,b.model)||(c.addClass("not-sortable"),b.$el.addClass("not-selectable"))),a.isFunction(this.selectableModelsFilter)&&(this.selectableModelsFilter.call(d,b.model)||(c.addClass("not-selectable"),b.$el.addClass("not-selectable"))),c},_convertStringsToInts:function(b){return a.map(b,function(b){if(!a.isString(b))return b;var c=parseInt(b,10);return c==b?c:b})},_containSameElements:function(b,c){if(b.length!=c.length)return!1;var d=a.intersection(b,c).length;return d==b.length},_isRenderedAsTable:function(){return"table"===this.$el.prop("tagName").toLowerCase()},_isRenderedAsList:function(){return!this._isRenderedAsTable()},_modelViewHasWrapperLI:function(a){return this._isRenderedAsList()&&!a.$el.is("li")},_getVisibleItemEls:function(){var a=[];return a=this._getContainerEl().find("> [data-model-cid]:not(.not-visible)")},_charCodes:{upArrow:38,downArrow:40},_isBackboneCourierAvailable:function(){return!a.isUndefined(b.Courier)},_setupSortable:function(){var b=a.extend({axis:"y",distance:10,forcePlaceholderSize:!0,items:this._isRenderedAsTable()?"> tbody > tr:not(.not-sortable)":"> li:not(.not-sortable)",start:a.bind(this._sortStart,this),change:a.bind(this._sortChange,this),stop:a.bind(this._sortStop,this),receive:a.bind(this._receive,this),over:a.bind(this._over,this)},a.result(this,"sortableOptions"));this.$el=this.$el.sortable(b)},_sortStart:function(a,b){var c=this.collection.get(b.item.attr("data-model-cid"));this._isBackboneCourierAvailable()?this.spawn("sortStart",{modelBeingSorted:c}):this.trigger("sortStart",c)},_sortChange:function(a,b){var c=this.collection.get(b.item.attr("data-model-cid"));this._isBackboneCourierAvailable()?this.spawn("sortChange",{modelBeingSorted:c}):this.trigger("sortChange",c)},_sortStop:function(a,b){var c=this.collection.get(b.item.attr("data-model-cid")),d=this._getContainerEl(),e=d.children().index(b.item);-1==e&&c&&this.collection.remove(c),c&&(this._reorderCollectionBasedOnHTML(),this.updateDependentControls(),this._isBackboneCourierAvailable()?this.spawn("sortStop",{modelBeingSorted:c,newIndex:e}):this.trigger("sortStop",c,e))},_receive:function(a,b){var c=b.sender,d=c.data("view");if(d&&d.collection){var e=this._getContainerEl().children().index(b.item),f=d.collection.get(b.item.attr("data-model-cid"));d.collection.remove(f),this.collection.add(f,{at:e}),f.collection=this.collection,this.setSelectedModel(f)}},_over:function(a,b){this._getContainerEl().find("> var.empty-list-caption").hide()},_onKeydown:function(a){if(!this.processKeyEvents)return!0;var b=!1;if(1==this.getSelectedModels({by:"offset"}).length){var c=this.getSelectedModel({by:"offset"});a.which===this._charCodes.upArrow&&0!==c?(this.setSelectedModel(c-1,{by:"offset"}),b=!0):a.which===this._charCodes.downArrow&&c!==this.collection.length-1&&(this.setSelectedModel(c+1,{by:"offset"}),b=!0)}return!b},_listItem_onMousedown:function(b){if(this.selectable&&this.clickToSelect){var c=this._getClickedItemId(b);if(c){if(a.isFunction(this.selectableModelsFilter)&&!this.selectableModelsFilter.call(this,this.collection.get(c)))return;if(this.selectMultiple&&b.shiftKey){var d=-1;this.selectedItems.length>0&&this.collection.find(function(b){return d++,a.contains(this.selectedItems,b.cid)},this);var e=-1;this.collection.find(function(a){return e++,a.cid==c},this);for(var f=-1==d?e:d,g=Math.min(e,f),h=Math.max(e,f),i=[],j=g;h>=j;j++)i.push(this.collection.at(j).cid);if(this.setSelectedModels(i,{by:"cid"}),document.selection&&document.selection.empty)document.selection.empty();else if(window.getSelection){var k=window.getSelection();k&&k.removeAllRanges&&k.removeAllRanges()}}else(this.selectMultiple||a.contains(this.selectedItems,c))&&(this.clickToToggle||b.metaKey||b.ctrlKey)?a.contains(this.selectedItems,c)?this.setSelectedModels(a.without(this.selectedItems,c),{by:"cid"}):this.setSelectedModels(a.union(this.selectedItems,[c]),{by:"cid"}):this.setSelectedModels([c],{by:"cid"})}else this.setSelectedModels([])}},_listItem_onDoubleClick:function(a){var b=this._getClickedItemId(a);if(b){var c=this.collection.get(b);this._isBackboneCourierAvailable()?this.spawn("doubleClick",{clickedModel:c}):this.trigger("doubleClick",c)}},_listBackground_onClick:function(a){this.selectable&&c(a.target).is(".collection-view")&&this.setSelectedModels([])}},{setDefaultModelViewConstructor:function(a){e=a}}),b.ViewOptions={},b.ViewOptions.add=function(b,c){a.isUndefined(c)&&(c="options"),b.setOptions=function(b){var e=this,f={},g={},h=a.result(this,c);if(!a.isUndefined(h)){var i=d(h);a.each(i,function(c){if(thisOptionName=c.name,thisOptionRequired=c.required,thisOptionDefaultValue=c.defaultValue,thisOptionRequired&&(!b||!a.contains(a.keys(b),thisOptionName)&&a.isUndefined(e[thisOptionName])||a.isUndefined(b[thisOptionName])))throw new Error('Required option "'+thisOptionName+'" was not supplied.');b&&thisOptionName in b?(a.isUndefined(e[thisOptionName])||(g[thisOptionName]=e[thisOptionName],f[thisOptionName]=b[thisOptionName]),e[thisOptionName]=b[thisOptionName]):!a.isUndefined(thisOptionDefaultValue)&&a.isUndefined(e[thisOptionName])&&(e[thisOptionName]=thisOptionDefaultValue)})}a.keys(f).length>0&&(a.isFunction(e.onOptionsChanged)?e.onOptionsChanged(f,g):a.isFunction(e._onOptionsChanged)&&e._onOptionsChanged(f,g))},b.getOptions=function(){var b=a.result(this,c);if(a.isUndefined(b))return[];var e=d(b),f=a.pluck(e,"name");return a.pick(this,f)}},ChildViewContainer=function(a,b){var c=function(a){this._views={},this._indexByModel={},this._indexByCustom={},this._updateLength(),b.each(a,this.add,this)};b.extend(c.prototype,{add:function(a,b){var c=a.cid;this._views[c]=a,a.model&&(this._indexByModel[a.model.cid]=c),b&&(this._indexByCustom[b]=c),this._updateLength()},findByModel:function(a){return this.findByModelCid(a.cid)},findByModelCid:function(a){var b=this._indexByModel[a];return this.findByCid(b)},findByCustom:function(a){var b=this._indexByCustom[a];return this.findByCid(b)},findByIndex:function(a){return b.values(this._views)[a]},findByCid:function(a){return this._views[a]},findIndexByCid:function(a){var c=-1,d=b.find(this._views,function(b){return c++,b.model.cid==a?b:void 0});return d?c:-1},remove:function(a){var c=a.cid;a.model&&delete this._indexByModel[a.model.cid],b.any(this._indexByCustom,function(a,b){return a===c?(delete this._indexByCustom[b],!0):void 0},this),delete this._views[c],this._updateLength()},call:function(a){this.apply(a,b.tail(arguments))},apply:function(a,c){b.each(this._views,function(d){b.isFunction(d[a])&&d[a].apply(d,c||[])})},_updateLength:function(){this.length=b.size(this._views)}});var d=["forEach","each","map","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","toArray","first","initial","rest","last","without","isEmpty","pluck"];return b.each(d,function(a){c.prototype[a]=function(){var c=b.values(this._views),d=[c].concat(b.toArray(arguments));return b[a].apply(b,d)}}),c}(b,a),b.CollectionView});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  * Copyright (c)2013 Rotunda Software, LLC.
6
  * Distributed under MIT license
7
  * http://github.com/rotundasoftware/backbone-collection-view
8
+
9
+
10
+ !function(a,b){"function"==typeof define&&define.amd?define(["underscore","backbone","jquery"],b):"undefined"!=typeof exports?module.exports=b(require("underscore"),require("backbone"),require("backbone").$):b(a._,a.Backbone,a.jQuery||a.Zepto||a.$)}(this,function(a,b,c){function d(b){var c=[];if(!a.isArray(b))throw new Error("Option declarations must be an array.");return a.each(b,function(b){var d,e,f;if(e=!1,f=void 0,a.isString(b))d=b;else{if(!a.isObject(b))throw new Error("Each element in the option declarations array must be either a string or an object.");d=a.first(a.keys(b)),f=a.clone(b[d])}"!"===d[d.length-1]&&(e=!0,d=d.slice(0,d.length-1)),c.push({name:d,required:e,defaultValue:f})}),c}var e=b.View,f="model",g=["collection","modelView","modelViewOptions","itemTemplate","itemTemplateFunction","detachedRendering"],h={background:"transparent",border:"none","box-shadow":"none"};return b.CollectionView=b.View.extend({tagName:"ul",events:{"mousedown > li, tbody > tr > td":"_listItem_onMousedown","dblclick > li, tbody > tr > td":"_listItem_onDoubleClick",click:"_listBackground_onClick","click ul.collection-view, table.collection-view":"_listBackground_onClick",keydown:"_onKeydown"},spawnMessages:{focus:"focus"},passMessages:{"*":"."},initializationOptions:[{collection:null},{modelView:null},{modelViewOptions:{}},{itemTemplate:null},{itemTemplateFunction:null},{selectable:!0},{clickToSelect:!0},{selectableModelsFilter:null},{visibleModelsFilter:null},{sortableModelsFilter:null},{selectMultiple:!1},{clickToToggle:!1},{processKeyEvents:!0},{sortable:!1},{sortableOptions:null},{reuseModelViews:!0},{detachedRendering:!1},{emptyListCaption:null}],initialize:function(a){b.ViewOptions.add(this,"initializationOptions"),this.setOptions(a),this.collection||(this.collection=new b.Collection),this._hasBeenRendered=!1,this._isBackboneCourierAvailable()&&b.Courier.add(this),this.$el.data("view",this),this.$el.addClass("collection-view collection-list"),this.selectable&&this.$el.addClass("selectable"),this.processKeyEvents&&this.$el.attr("tabindex",0),this.selectedItems=[],this._updateItemTemplate(),this.collection&&this._registerCollectionEvents(),this.viewManager=new ChildViewContainer},onOptionsChanged:function(b,c){var d=this,e=!1;a.each(a.keys(b),function(f){var h=b[f],i=c[f];switch(f){case"collection":h!==i&&(d.stopListening(i),d._registerCollectionEvents());break;case"selectMultiple":!h&&d.selectedItems.length>1&&d.setSelectedModel(a.first(d.selectedItems),{by:"cid"});break;case"selectable":!h&&d.selectedItems.length>0&&d.setSelectedModels([]);break;case"sortable":b.sortable?d._setupSortable():d.$el.sortable("destroy");break;case"selectableModelsFilter":d.reapplyFilter("selectableModels");break;case"sortableOptions":d.$el.sortable("destroy"),d._setupSortable();break;case"sortableModelsFilter":d.reapplyFilter("sortableModels");break;case"visibleModelsFilter":d.reapplyFilter("visibleModels");break;case"itemTemplate":d._updateItemTemplate();break;case"processKeyEvents":h&&d.$el.attr("tabindex",0);break;case"modelView":d.viewManager.each(function(a){d.viewManager.remove(a),a.remove()})}a.contains(g,f)&&(e=!0)}),this._hasBeenRendered&&e&&this.render()},setOption:function(a,b){var c={};c[a]=b,this.setOptions(c)},getSelectedModel:function(b){return this.selectedItems.length?a.first(this.getSelectedModels(b)):null},getSelectedModels:function(b){var d=this;b=a.extend({},{by:f},b);var e=b.by,g=[];switch(e){case"id":a.each(this.selectedItems,function(a){g.push(d.collection.get(a).id)});break;case"cid":g=g.concat(this.selectedItems);break;case"offset":var h=0,i=this._getVisibleItemEls();i.each(function(){var a=c(this);a.is(".selected")&&g.push(h),h++});break;case"model":a.each(this.selectedItems,function(a){g.push(d.collection.get(a))});break;case"view":a.each(this.selectedItems,function(a){g.push(d.viewManager.findByModel(d.collection.get(a)))});break;default:throw new Error("Invalid referenceBy option: "+e)}return g},setSelectedModels:function(b,d){if(!a.isArray(b))throw"Invalid parameter value";if(this.selectable||!(b.length>0)){d=a.extend({},{silent:!1,by:f},d);var e=d.by,g=[];switch(e){case"cid":g=b;break;case"id":this.collection.each(function(c){a.contains(b,c.id)&&g.push(c.cid)});break;case"model":g=a.pluck(b,"cid");break;case"view":a.each(b,function(a){g.push(a.model.cid)});break;case"offset":var h=0,i=this._getVisibleItemEls();i.each(function(){var d=c(this);a.contains(b,h)&&g.push(d.attr("data-model-cid")),h++});break;default:throw new Error("Invalid referenceBy option: "+e)}var j=this.getSelectedModels(),k=a.clone(this.selectedItems);this.selectedItems=this._convertStringsToInts(g),this._validateSelection();var l=this.getSelectedModels();this._containSameElements(k,this.selectedItems)||(this._addSelectedClassToSelectedItems(k),d.silent||(this._isBackboneCourierAvailable()?this.spawn("selectionChanged",{selectedModels:l,oldSelectedModels:j}):this.trigger("selectionChanged",l,j)),this.updateDependentControls())}},setSelectedModel:function(a,b){a||0===a?this.setSelectedModels([a],b):this.setSelectedModels([],b)},render:function(){this._hasBeenRendered=!0,this.selectable&&this._saveSelection();var b;b=this._getContainerEl();var c=this.viewManager;this.viewManager=new ChildViewContainer,c.each(function(a){this.reuseModelViews&&this.collection.get(a.model.cid)?a.$el.detach():a.remove()},this),b.empty();var d;this.detachedRendering&&(d=document.createDocumentFragment()),this.collection.each(function(e){var f=c.findByModelCid(e.cid);(!this.reuseModelViews||a.isUndefined(f))&&(f=this._createNewModelView(e,this._getModelViewOptions(e))),this._insertAndRenderModelView(f,d||b)},this),this.detachedRendering&&b.append(d),this.sortable&&this._setupSortable(),this._showEmptyListCaptionIfAppropriate(),this._isBackboneCourierAvailable()?this.spawn("render"):this.trigger("render"),this.selectable&&(this._restoreSelection(),this.updateDependentControls()),this.forceRerenderOnNextSortEvent=!1},_showEmptyListCaptionIfAppropriate:function(){if(this._removeEmptyListCaption(),this.emptyListCaption){var b=this._getVisibleItemEls();if(0===b.length){var d;d=a.isFunction(this.emptyListCaption)?this.emptyListCaption():this.emptyListCaption;var e,f=c("<var class='empty-list-caption'>"+d+"</var>");e=this._isRenderedAsList()?f.wrapAll("<li class='not-sortable'></li>").parent().css(h):f.wrapAll("<tr class='not-sortable'><td colspan='1000'></td></tr>").parent().parent().css(h),this._getContainerEl().append(e)}}},_removeEmptyListCaption:function(){this._isRenderedAsList()?this._getContainerEl().find("> li > var.empty-list-caption").parent().remove():this._getContainerEl().find("> tr > td > var.empty-list-caption").parent().parent().remove()},_insertAndRenderModelView:function(b,c,d){var e=this._wrapModelView(b);if(11===c.nodeType)c.appendChild(e.get(0));else{var f=c.children().length;!a.isUndefined(d)&&d>=0&&f>d?c.children().eq(d).before(e):(!a.isUndefined(d)&&d>f&&(this.forceRerenderOnNextSortEvent=!0),c.append(e))}var g=b.render();g===!1&&(e.hide(),e.addClass("not-visible"));var h=!1;a.isFunction(this.visibleModelsFilter)&&(h=!this.visibleModelsFilter(b.model)),1===e.children().length?e.toggle(!h):b.$el.toggle(!h),e.toggleClass("not-visible",h),!h&&this.emptyListCaption&&this._removeEmptyListCaption(),this.viewManager.add(b)},updateDependentControls:function(){this._isBackboneCourierAvailable()?this.spawn("updateDependentControls",{selectedModels:this.getSelectedModels()}):this.trigger("updateDependentControls",this.getSelectedModels())},remove:function(){this.viewManager.each(function(a){a.remove()}),b.View.prototype.remove.apply(this,arguments)},reapplyFilter:function(b){var c=this;if(!a.contains(["selectableModels","sortableModels","visibleModels"],b))throw new Error("Invalid filter identifier supplied to reapplyFilter: "+b);switch(b){case"visibleModels":c.viewManager.each(function(a){var b=c.visibleModelsFilter&&!c.visibleModelsFilter.call(c,a.model);a.$el.toggleClass("not-visible",b),c._modelViewHasWrapperLI(a)?a.$el.closest("li").toggleClass("not-visible",b).toggle(!b):a.$el.toggle(!b)}),this._showEmptyListCaptionIfAppropriate();break;case"sortableModels":c.$el.sortable("destroy"),c.viewManager.each(function(a){var b=c.sortableModelsFilter&&!c.sortableModelsFilter.call(c,a.model);a.$el.toggleClass("not-sortable",b),c._modelViewHasWrapperLI(a)&&a.$el.closest("li").toggleClass("not-sortable",b)}),c._setupSortable();break;case"selectableModels":c.viewManager.each(function(a){var b=c.selectableModelsFilter&&!c.selectableModelsFilter.call(c,a.model);a.$el.toggleClass("not-selectable",b),c._modelViewHasWrapperLI(a)&&a.$el.closest("li").toggleClass("not-selectable",b)}),c._validateSelection()}},_removeModelView:function(a){this.selectable&&this._saveSelection(),this.viewManager.remove(a),this._modelViewHasWrapperLI(a)&&a.$el.parent().remove(),a.remove(),this.selectable&&this._restoreSelection(),this._showEmptyListCaptionIfAppropriate()},_validateSelectionAndRender:function(){this._validateSelection(),this.render()},_registerCollectionEvents:function(){this.listenTo(this.collection,"add",function(a){var b;this._hasBeenRendered&&(b=this._createNewModelView(a,this._getModelViewOptions(a)),this._insertAndRenderModelView(b,this._getContainerEl(),this.collection.indexOf(a))),this._isBackboneCourierAvailable()?this.spawn("add",b):this.trigger("add",b)}),this.listenTo(this.collection,"remove",function(a){var b;this._hasBeenRendered&&(b=this.viewManager.findByModelCid(a.cid),this._removeModelView(b)),this._isBackboneCourierAvailable()?this.spawn("remove"):this.trigger("remove")}),this.listenTo(this.collection,"reset",function(){this._hasBeenRendered&&this.render(),this._isBackboneCourierAvailable()?this.spawn("reset"):this.trigger("reset")}),this.listenTo(this.collection,"sort",function(a,b){this._hasBeenRendered&&(b.add!==!0||this.forceRerenderOnNextSortEvent)&&this.render(),this._isBackboneCourierAvailable()?this.spawn("sort"):this.trigger("sort")})},_getContainerEl:function(){if(this._isRenderedAsTable()){var a=this.$el.find("> tbody");if(a.length>0)return a}return this.$el},_getClickedItemId:function(a){var b=null,d=c(a.currentTarget);if(d.closest(".collection-view").get(0)===this.$el.get(0)){var e=d.closest("[data-model-cid]");return e.length>0&&(b=e.attr("data-model-cid"),c.isNumeric(b)&&(b=parseInt(b,10))),b}},_updateItemTemplate:function(){var b;if(this.itemTemplate){if(0===c(this.itemTemplate).length)throw"Could not find item template from selector: "+this.itemTemplate;b=c(this.itemTemplate).html()}else b=this.$(".item-template").html();b&&(this.itemTemplateFunction=a.template(b))},_validateSelection:function(){var b=a.pluck(this.collection.models,"cid");this.selectedItems=a.intersection(b,this.selectedItems),a.isFunction(this.selectableModelsFilter)&&(this.selectedItems=a.filter(this.selectedItems,function(a){return this.selectableModelsFilter.call(this,this.collection.get(a))},this))},_saveSelection:function(){if(!this.selectable)throw"Attempt to save selection on non-selectable list";this.savedSelection={items:a.clone(this.selectedItems),offset:this.getSelectedModel({by:"offset"})}},_restoreSelection:function(){if(!this.savedSelection)throw"Attempt to restore selection but no selection has been saved!";this.setSelectedModels([],{silent:!0}),this.savedSelection.items.length>0&&(this.setSelectedModels(this.savedSelection.items,{by:"cid",silent:!0}),0===this.selectedItems.length&&this.setSelectedModel(this.savedSelection.offset,{by:"offset"}),this.selectedItems.length!==this.savedSelection.items.length&&(this._isBackboneCourierAvailable()?this.spawn("selectionChanged",{selectedModels:this.getSelectedModels(),oldSelectedModels:[]}):this.trigger("selectionChanged",this.getSelectedModels(),[]))),delete this.savedSelection},_addSelectedClassToSelectedItems:function(b){a.isUndefined(b)&&(b=[]);var c=b;c=a.without(c,this.selectedItems),a.each(c,function(a){this._getContainerEl().find("[data-model-cid="+a+"]").removeClass("selected"),this._isRenderedAsList()&&this._getContainerEl().find("li[data-model-cid="+a+"] > *").removeClass("selected")},this);var d=this.selectedItems;d=a.without(d,b),a.each(d,function(a){this._getContainerEl().find("[data-model-cid="+a+"]").addClass("selected"),this._isRenderedAsList()&&this._getContainerEl().find("li[data-model-cid="+a+"] > *").addClass("selected")},this)},_reorderCollectionBasedOnHTML:function(){var a=this;this._getContainerEl().children().each(function(){var b=c(this).attr("data-model-cid");if(b){var d=a.collection.get(b);d&&(a.collection.remove(d,{silent:!0}),a.collection.add(d,{silent:!0,sort:!a.collection.comparator}))}}),this._isBackboneCourierAvailable()?this.spawn("reorder"):this.collection.trigger("reorder"),this.collection.comparator&&this.collection.sort()},_getModelViewConstructor:function(a){return this.modelView||e},_getModelViewOptions:function(b){var c=this.modelViewOptions;return a.isFunction(c)&&(c=c(b)),a.extend({model:b},c)},_createNewModelView:function(b,c){var d=this._getModelViewConstructor(b);if(a.isUndefined(d))throw"Could not find modelView constructor for model";var e=new d(c);return e.collectionListView=e.collectionView=this,e},_wrapModelView:function(b){var c,d=this;return this._isRenderedAsTable()?(c=b.$el,b.$el.attr("data-model-cid",b.model.cid)):this._isRenderedAsList()&&(b.$el.is("li")?(c=b.$el,b.$el.attr("data-model-cid",b.model.cid)):c=b.$el.wrapAll("<li data-model-cid='"+b.model.cid+"'></li>").parent()),a.isFunction(this.sortableModelsFilter)&&(this.sortableModelsFilter.call(d,b.model)||(c.addClass("not-sortable"),b.$el.addClass("not-selectable"))),a.isFunction(this.selectableModelsFilter)&&(this.selectableModelsFilter.call(d,b.model)||(c.addClass("not-selectable"),b.$el.addClass("not-selectable"))),c},_convertStringsToInts:function(b){return a.map(b,function(b){if(!a.isString(b))return b;var c=parseInt(b,10);return c==b?c:b})},_containSameElements:function(b,c){if(b.length!=c.length)return!1;var d=a.intersection(b,c).length;return d==b.length},_isRenderedAsTable:function(){return"table"===this.$el.prop("tagName").toLowerCase()},_isRenderedAsList:function(){return!this._isRenderedAsTable()},_modelViewHasWrapperLI:function(a){return this._isRenderedAsList()&&!a.$el.is("li")},_getVisibleItemEls:function(){var a=[];return a=this._getContainerEl().find("> [data-model-cid]:not(.not-visible)")},_charCodes:{upArrow:38,downArrow:40},_isBackboneCourierAvailable:function(){return!a.isUndefined(b.Courier)},_setupSortable:function(){var b=a.extend({axis:"y",distance:10,forcePlaceholderSize:!0,items:this._isRenderedAsTable()?"> tbody > tr:not(.not-sortable)":"> li:not(.not-sortable)",start:a.bind(this._sortStart,this),change:a.bind(this._sortChange,this),stop:a.bind(this._sortStop,this),receive:a.bind(this._receive,this),over:a.bind(this._over,this)},a.result(this,"sortableOptions"));this.$el=this.$el.sortable(b)},_sortStart:function(a,b){var c=this.collection.get(b.item.attr("data-model-cid"));this._isBackboneCourierAvailable()?this.spawn("sortStart",{modelBeingSorted:c}):this.trigger("sortStart",c)},_sortChange:function(a,b){var c=this.collection.get(b.item.attr("data-model-cid"));this._isBackboneCourierAvailable()?this.spawn("sortChange",{modelBeingSorted:c}):this.trigger("sortChange",c)},_sortStop:function(a,b){var c=this.collection.get(b.item.attr("data-model-cid")),d=this._getContainerEl(),e=d.children().index(b.item);-1==e&&c&&this.collection.remove(c),c&&(this._reorderCollectionBasedOnHTML(),this.updateDependentControls(),this._isBackboneCourierAvailable()?this.spawn("sortStop",{modelBeingSorted:c,newIndex:e}):this.trigger("sortStop",c,e))},_receive:function(a,b){var c=b.sender,d=c.data("view");if(d&&d.collection){var e=this._getContainerEl().children().index(b.item),f=d.collection.get(b.item.attr("data-model-cid"));d.collection.remove(f),this.collection.add(f,{at:e}),f.collection=this.collection,this.setSelectedModel(f)}},_over:function(a,b){this._getContainerEl().find("> var.empty-list-caption").hide()},_onKeydown:function(a){if(!this.processKeyEvents)return!0;var b=!1;if(1==this.getSelectedModels({by:"offset"}).length){var c=this.getSelectedModel({by:"offset"});a.which===this._charCodes.upArrow&&0!==c?(this.setSelectedModel(c-1,{by:"offset"}),b=!0):a.which===this._charCodes.downArrow&&c!==this.collection.length-1&&(this.setSelectedModel(c+1,{by:"offset"}),b=!0)}return!b},_listItem_onMousedown:function(b){if(this.selectable&&this.clickToSelect){var c=this._getClickedItemId(b);if(c){if(a.isFunction(this.selectableModelsFilter)&&!this.selectableModelsFilter.call(this,this.collection.get(c)))return;if(this.selectMultiple&&b.shiftKey){var d=-1;this.selectedItems.length>0&&this.collection.find(function(b){return d++,a.contains(this.selectedItems,b.cid)},this);var e=-1;this.collection.find(function(a){return e++,a.cid==c},this);for(var f=-1==d?e:d,g=Math.min(e,f),h=Math.max(e,f),i=[],j=g;h>=j;j++)i.push(this.collection.at(j).cid);if(this.setSelectedModels(i,{by:"cid"}),document.selection&&document.selection.empty)document.selection.empty();else if(window.getSelection){var k=window.getSelection();k&&k.removeAllRanges&&k.removeAllRanges()}}else(this.selectMultiple||a.contains(this.selectedItems,c))&&(this.clickToToggle||b.metaKey||b.ctrlKey)?a.contains(this.selectedItems,c)?this.setSelectedModels(a.without(this.selectedItems,c),{by:"cid"}):this.setSelectedModels(a.union(this.selectedItems,[c]),{by:"cid"}):this.setSelectedModels([c],{by:"cid"})}else this.setSelectedModels([])}},_listItem_onDoubleClick:function(a){var b=this._getClickedItemId(a);if(b){var c=this.collection.get(b);this._isBackboneCourierAvailable()?this.spawn("doubleClick",{clickedModel:c}):this.trigger("doubleClick",c)}},_listBackground_onClick:function(a){this.selectable&&c(a.target).is(".collection-view")&&this.setSelectedModels([])}},{setDefaultModelViewConstructor:function(a){e=a}}),b.ViewOptions={},b.ViewOptions.add=function(b,c){a.isUndefined(c)&&(c="options"),b.setOptions=function(b){var e=this,f={},g={},h=a.result(this,c);if(!a.isUndefined(h)){var i=d(h);a.each(i,function(c){if(thisOptionName=c.name,thisOptionRequired=c.required,thisOptionDefaultValue=c.defaultValue,thisOptionRequired&&(!b||!a.contains(a.keys(b),thisOptionName)&&a.isUndefined(e[thisOptionName])||a.isUndefined(b[thisOptionName])))throw new Error('Required option "'+thisOptionName+'" was not supplied.');b&&thisOptionName in b?(a.isUndefined(e[thisOptionName])||(g[thisOptionName]=e[thisOptionName],f[thisOptionName]=b[thisOptionName]),e[thisOptionName]=b[thisOptionName]):!a.isUndefined(thisOptionDefaultValue)&&a.isUndefined(e[thisOptionName])&&(e[thisOptionName]=thisOptionDefaultValue)})}a.keys(f).length>0&&(a.isFunction(e.onOptionsChanged)?e.onOptionsChanged(f,g):a.isFunction(e._onOptionsChanged)&&e._onOptionsChanged(f,g))},b.getOptions=function(){var b=a.result(this,c);if(a.isUndefined(b))return[];var e=d(b),f=a.pluck(e,"name");return a.pick(this,f)}},ChildViewContainer=function(a,b){var c=function(a){this._views={},this._indexByModel={},this._indexByCustom={},this._updateLength(),b.each(a,this.add,this)};b.extend(c.prototype,{add:function(a,b){var c=a.cid;this._views[c]=a,a.model&&(this._indexByModel[a.model.cid]=c),b&&(this._indexByCustom[b]=c),this._updateLength()},findByModel:function(a){return this.findByModelCid(a.cid)},findByModelCid:function(a){var b=this._indexByModel[a];return this.findByCid(b)},findByCustom:function(a){var b=this._indexByCustom[a];return this.findByCid(b)},findByIndex:function(a){return b.values(this._views)[a]},findByCid:function(a){return this._views[a]},findIndexByCid:function(a){var c=-1,d=b.find(this._views,function(b){return c++,b.model.cid==a?b:void 0});return d?c:-1},remove:function(a){var c=a.cid;a.model&&delete this._indexByModel[a.model.cid],b.any(this._indexByCustom,function(a,b){return a===c?(delete this._indexByCustom[b],!0):void 0},this),delete this._views[c],this._updateLength()},call:function(a){this.apply(a,b.tail(arguments))},apply:function(a,c){b.each(this._views,function(d){b.isFunction(d[a])&&d[a].apply(d,c||[])})},_updateLength:function(){this.length=b.size(this._views)}});var d=["forEach","each","map","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","toArray","first","initial","rest","last","without","isEmpty","pluck"];return b.each(d,function(a){c.prototype[a]=function(){var c=b.values(this._views),d=[c].concat(b.toArray(arguments));return b[a].apply(b,d)}}),c}(b,a),b.CollectionView});
11
+ **/
12
+ /*!
13
+ * Backbone.CollectionView, v1.1.4
14
+ * Copyright (c)2013 Rotunda Software, LLC.
15
+ * Distributed under MIT license
16
+ * http://github.com/rotundasoftware/backbone-collection-view
17
  */
18
 
19
+ ( function( root, factory ) {
20
+ // UMD wrapper
21
+ if ( typeof define === 'function' && define.amd ) {
22
+ // AMD
23
+ define( [ 'underscore', 'backbone', 'jquery' ], factory );
24
+ } else if ( typeof exports !== 'undefined' ) {
25
+ // Node/CommonJS
26
+ module.exports = factory( require('underscore' ), require( 'backbone' ), require( 'backbone' ).$ );
27
+ } else {
28
+ // Browser globals
29
+ factory( root._, root.Backbone, ( root.jQuery || root.Zepto || root.$ ) );
30
+ }
31
+ }( this, function( _, Backbone, $ ) {
32
+ var mDefaultModelViewConstructor = Backbone.View;
33
+
34
+ var kDefaultReferenceBy = "model";
35
+
36
+ var kOptionsRequiringRerendering = [ "collection", "modelView", "modelViewOptions", "itemTemplate", "itemTemplateFunction", "detachedRendering" ];
37
+
38
+ var kStylesForEmptyListCaption = {
39
+ "background" : "transparent",
40
+ "border" : "none",
41
+ "box-shadow" : "none"
42
+ };
43
+
44
+ Backbone.CollectionView = Backbone.View.extend( {
45
+
46
+ tagName : "ul",
47
+
48
+ events : {
49
+ "mousedown > li, tbody > tr > td" : "_listItem_onMousedown",
50
+ "dblclick > li, tbody > tr > td" : "_listItem_onDoubleClick",
51
+ "click" : "_listBackground_onClick",
52
+ "click ul.collection-view, table.collection-view" : "_listBackground_onClick",
53
+ "keydown" : "_onKeydown"
54
+ },
55
+
56
+ // only used if Backbone.Courier is available
57
+ spawnMessages : {
58
+ "focus" : "focus"
59
+ },
60
+
61
+ //only used if Backbone.Courier is available
62
+ passMessages : { "*" : "." },
63
+
64
+ // viewOption definitions with default values.
65
+ initializationOptions : [
66
+ { "collection" : null },
67
+ { "modelView" : null },
68
+ { "modelViewOptions" : {} },
69
+ { "itemTemplate" : null },
70
+ { "itemTemplateFunction" : null },
71
+ { "selectable" : true },
72
+ { "clickToSelect" : true },
73
+ { "selectableModelsFilter" : null },
74
+ { "visibleModelsFilter" : null },
75
+ { "sortableModelsFilter" : null },
76
+ { "selectMultiple" : false },
77
+ { "clickToToggle" : false },
78
+ { "processKeyEvents" : true },
79
+ { "sortable" : false },
80
+ { "sortableOptions" : null },
81
+ { "reuseModelViews" : true },
82
+ { "detachedRendering" : false },
83
+ { "emptyListCaption" : null }
84
+ ],
85
+
86
+ initialize : function( options ) {
87
+ Backbone.ViewOptions.add( this, "initializationOptions" ); // setup the ViewOptions functionality.
88
+ this.setOptions( options ); // and make use of any provided options
89
+
90
+ if( ! this.collection ) this.collection = new Backbone.Collection();
91
+
92
+ this._hasBeenRendered = false;
93
+
94
+ if( this._isBackboneCourierAvailable() ) {
95
+ Backbone.Courier.add( this );
96
+ }
97
+
98
+ this.$el.data( "view", this ); // needed for connected sortable lists
99
+ this.$el.addClass( "collection-view collection-list" ); // collection-list is in there for legacy purposes
100
+ if( this.selectable ) this.$el.addClass( "selectable" );
101
+
102
+ if( this.processKeyEvents )
103
+ this.$el.attr( "tabindex", 0 ); // so we get keyboard events
104
+
105
+ this.selectedItems = [];
106
+
107
+ this._updateItemTemplate();
108
+
109
+ if( this.collection )
110
+ this._registerCollectionEvents();
111
+
112
+ this.viewManager = new ChildViewContainer();
113
+ },
114
+
115
+ _onOptionsChanged : function( changedOptions, originalOptions ) {
116
+ var _this = this;
117
+ var rerender = false;
118
+
119
+ _.each( _.keys( changedOptions ), function( changedOptionKey ) {
120
+ var newVal = changedOptions[ changedOptionKey ];
121
+ var oldVal = originalOptions[ changedOptionKey ];
122
+ switch( changedOptionKey ) {
123
+ case "collection" :
124
+ if ( newVal !== oldVal ) {
125
+ _this.stopListening( oldVal );
126
+ _this._registerCollectionEvents();
127
+ }
128
+ break;
129
+ case "selectMultiple" :
130
+ if( ! newVal && _this.selectedItems.length > 1 )
131
+ _this.setSelectedModel( _.first( _this.selectedItems ), { by : "cid" } );
132
+ break;
133
+ case "selectable" :
134
+ if( ! newVal && _this.selectedItems.length > 0 )
135
+ _this.setSelectedModels( [] );
136
+ break;
137
+ case "sortable" :
138
+ changedOptions.sortable ? _this._setupSortable() : _this.$el.sortable( "destroy" );
139
+ break;
140
+ case "selectableModelsFilter" :
141
+ _this.reapplyFilter( 'selectableModels' );
142
+ break;
143
+ case "sortableOptions" :
144
+ _this.$el.sortable( "destroy" );
145
+ _this._setupSortable();
146
+ break;
147
+ case "sortableModelsFilter" :
148
+ _this.reapplyFilter( 'sortableModels' );
149
+ break;
150
+ case "visibleModelsFilter" :
151
+ _this.reapplyFilter( 'visibleModels' );
152
+ break;
153
+ case "itemTemplate" :
154
+ _this._updateItemTemplate();
155
+ break;
156
+ case "processKeyEvents" :
157
+ if( newVal ) _this.$el.attr( "tabindex", 0 ); // so we get keyboard events
158
+ break;
159
+ case "modelView" :
160
+ //need to remove all old view instances
161
+ _this.viewManager.each( function( view ) {
162
+ _this.viewManager.remove( view );
163
+ // destroy the View itself
164
+ view.remove();
165
+ } );
166
+ break;
167
+ }
168
+ if( _.contains( kOptionsRequiringRerendering, changedOptionKey ) ) rerender = true;
169
+ } );
170
+
171
+ if( this._hasBeenRendered && rerender ) {
172
+ this.render();
173
+ }
174
+ },
175
+
176
+ setOption : function( optionName, optionValue ) { // now is mearly a wrapper around backbone.viewOptions' setOptions()
177
+ var optionHash = {};
178
+ optionHash[ optionName ] = optionValue;
179
+ this.setOptions( optionHash );
180
+ },
181
+
182
+ getSelectedModel : function( options ) {
183
+ return this.selectedItems.length ? _.first( this.getSelectedModels( options ) ) : null;
184
+ },
185
+
186
+ getSelectedModels : function ( options ) {
187
+ var _this = this;
188
+
189
+ options = _.extend( {}, {
190
+ by : kDefaultReferenceBy
191
+ }, options );
192
+
193
+ var referenceBy = options.by;
194
+ var items = [];
195
+
196
+ switch( referenceBy ) {
197
+ case "id" :
198
+ _.each( this.selectedItems, function ( item ) {
199
+ items.push( _this.collection.get( item ).id );
200
+ } );
201
+ break;
202
+ case "cid" :
203
+ items = items.concat( this.selectedItems );
204
+ break;
205
+ case "offset" :
206
+ var curLineNumber = 0;
207
+
208
+ var itemElements = this._getVisibleItemEls();
209
+
210
+ itemElements.each( function() {
211
+ var thisItemEl = $( this );
212
+ if( thisItemEl.is( ".selected" ) )
213
+ items.push( curLineNumber );
214
+ curLineNumber++;
215
+ } );
216
+ break;
217
+ case "model" :
218
+ _.each( this.selectedItems, function ( item ) {
219
+ items.push( _this.collection.get( item ) );
220
+ } );
221
+ break;
222
+ case "view" :
223
+ _.each( this.selectedItems, function ( item ) {
224
+ items.push( _this.viewManager.findByModel( _this.collection.get( item ) ) );
225
+ } );
226
+ break;
227
+ default :
228
+ throw new Error( "Invalid referenceBy option: " + referenceBy );
229
+ break;
230
+ }
231
+
232
+ return items;
233
+
234
+ },
235
+
236
+ setSelectedModels : function( newSelectedItems, options ) {
237
+ if( ! _.isArray( newSelectedItems ) ) throw "Invalid parameter value";
238
+ if( ! this.selectable && newSelectedItems.length > 0 ) return; // used to throw error, but there are some circumstances in which a list can be selectable at times and not at others, don't want to have to worry about catching errors
239
+
240
+ options = _.extend( {}, {
241
+ silent : false,
242
+ by : kDefaultReferenceBy
243
+ }, options );
244
+
245
+ var referenceBy = options.by;
246
+ var newSelectedCids = [];
247
+
248
+ switch( referenceBy ) {
249
+ case "cid" :
250
+ newSelectedCids = newSelectedItems;
251
+ break;
252
+ case "id" :
253
+ this.collection.each( function( thisModel ) {
254
+ if( _.contains( newSelectedItems, thisModel.id ) ) newSelectedCids.push( thisModel.cid );
255
+ } );
256
+ break;
257
+ case "model" :
258
+ newSelectedCids = _.pluck( newSelectedItems, "cid" );
259
+ break;
260
+ case "view" :
261
+ _.each( newSelectedItems, function( item ) {
262
+ newSelectedCids.push( item.model.cid );
263
+ } );
264
+ break;
265
+ case "offset" :
266
+ var curLineNumber = 0;
267
+ var selectedItems = [];
268
+
269
+ var itemElements = this._getVisibleItemEls();
270
+ itemElements.each( function() {
271
+ var thisItemEl = $( this );
272
+ if( _.contains( newSelectedItems, curLineNumber ) )
273
+ newSelectedCids.push( thisItemEl.attr( "data-model-cid" ) );
274
+ curLineNumber++;
275
+ } );
276
+ break;
277
+ default :
278
+ throw new Error( "Invalid referenceBy option: " + referenceBy );
279
+ break;
280
+ }
281
+
282
+ var oldSelectedModels = this.getSelectedModels();
283
+ var oldSelectedCids = _.clone( this.selectedItems );
284
+
285
+ this.selectedItems = this._convertStringsToInts( newSelectedCids );
286
+ this._validateSelection();
287
+
288
+ var newSelectedModels = this.getSelectedModels();
289
+
290
+ if( ! this._containSameElements( oldSelectedCids, this.selectedItems ) )
291
+ {
292
+ this._addSelectedClassToSelectedItems( oldSelectedCids );
293
+
294
+ if( ! options.silent )
295
+ {
296
+ if( this._isBackboneCourierAvailable() ) {
297
+ this.spawn( "selectionChanged", {
298
+ selectedModels : newSelectedModels,
299
+ oldSelectedModels : oldSelectedModels
300
+ } );
301
+ } else this.trigger( "selectionChanged", newSelectedModels, oldSelectedModels );
302
+ }
303
+
304
+ this.updateDependentControls();
305
+ }
306
+ },
307
+
308
+ setSelectedModel : function( newSelectedItem, options ) {
309
+ if( ! newSelectedItem && newSelectedItem !== 0 )
310
+ this.setSelectedModels( [], options );
311
+ else
312
+ this.setSelectedModels( [ newSelectedItem ], options );
313
+ },
314
+
315
+ render : function() {
316
+ var _this = this;
317
+
318
+ this._hasBeenRendered = true;
319
+
320
+ if( this.selectable ) this._saveSelection();
321
+
322
+ var modelViewContainerEl;
323
+
324
+ // If collection view element is a table and it has a tbody
325
+ // within it, render the model views inside of the tbody
326
+ modelViewContainerEl = this._getContainerEl();
327
+
328
+ var oldViewManager = this.viewManager;
329
+ this.viewManager = new ChildViewContainer();
330
+
331
+ // detach each of our subviews that we have already created to represent models
332
+ // in the collection. We are going to re-use the ones that represent models that
333
+ // are still here, instead of creating new ones, so that we don't loose state
334
+ // information in the views.
335
+ oldViewManager.each( function( thisModelView ) {
336
+ // to boost performance, only detach those views that will be sticking around.
337
+ // we won't need the other ones later, so no need to detach them individually.
338
+ if( this.reuseModelViews && this.collection.get( thisModelView.model.cid ) ) {
339
+ thisModelView.$el.detach();
340
+ } else thisModelView.remove();
341
+ }, this );
342
+
343
+ modelViewContainerEl.empty();
344
+ var fragmentContainer;
345
+
346
+ if( this.detachedRendering )
347
+ fragmentContainer = document.createDocumentFragment();
348
+
349
+ this.collection.each( function( thisModel ) {
350
+ var thisModelView = oldViewManager.findByModelCid( thisModel.cid );
351
+ if( ! this.reuseModelViews || _.isUndefined( thisModelView ) ) {
352
+ // if the model view has not already been created on a
353
+ // previous render then create and initialize it now.
354
+ thisModelView = this._createNewModelView( thisModel, this._getModelViewOptions( thisModel ) );
355
+ }
356
+
357
+ this._insertAndRenderModelView( thisModelView, fragmentContainer || modelViewContainerEl );
358
+ }, this );
359
+
360
+ if( this.detachedRendering )
361
+ modelViewContainerEl.append( fragmentContainer );
362
+
363
+ if( this.sortable ) this._setupSortable();
364
+
365
+ this._showEmptyListCaptionIfAppropriate();
366
+
367
+ if( this._isBackboneCourierAvailable() )
368
+ this.spawn( "render" );
369
+ else this.trigger( "render" );
370
+
371
+ if( this.selectable ) {
372
+ this._restoreSelection();
373
+ this.updateDependentControls();
374
+ }
375
+
376
+ this.forceRerenderOnNextSortEvent = false;
377
+ },
378
+
379
+ _showEmptyListCaptionIfAppropriate : function ( ) {
380
+ this._removeEmptyListCaption();
381
+
382
+ if( this.emptyListCaption ) {
383
+ var visibleEls = this._getVisibleItemEls();
384
+
385
+ if( visibleEls.length === 0 ) {
386
+ var emptyListString;
387
+
388
+ if( _.isFunction( this.emptyListCaption ) )
389
+ emptyListString = this.emptyListCaption();
390
+ else
391
+ emptyListString = this.emptyListCaption;
392
+
393
+ var $emptyListCaptionEl;
394
+ var $varEl = $( "<var class='empty-list-caption'>" + emptyListString + "</var>" );
395
+
396
+ // need to wrap the empty caption to make it fit the rendered list structure (either with an li or a tr td)
397
+ if( this._isRenderedAsList() )
398
+ $emptyListCaptionEl = $varEl.wrapAll( "<li class='not-sortable'></li>" ).parent().css( kStylesForEmptyListCaption );
399
+ else
400
+ $emptyListCaptionEl = $varEl.wrapAll( "<tr class='not-sortable'><td colspan='1000'></td></tr>" ).parent().parent().css( kStylesForEmptyListCaption );
401
+
402
+ this._getContainerEl().append( $emptyListCaptionEl );
403
+ }
404
+ }
405
+ },
406
+
407
+ _removeEmptyListCaption : function( ) {
408
+ if( this._isRenderedAsList() )
409
+ this._getContainerEl().find( "> li > var.empty-list-caption" ).parent().remove();
410
+ else
411
+ this._getContainerEl().find( "> tr > td > var.empty-list-caption" ).parent().parent().remove();
412
+ },
413
+
414
+ // Render a single model view in container object "parentElOrDocumentFragment", which is either
415
+ // a documentFragment or a jquery object. optional arg atIndex is not support for document fragments.
416
+ _insertAndRenderModelView : function( modelView, parentElOrDocumentFragment, atIndex ) {
417
+ var thisModelViewWrapped = this._wrapModelView( modelView );
418
+
419
+ if( parentElOrDocumentFragment.nodeType === 11 ) // if we are inserting into a document fragment, we need to use the DOM appendChild method
420
+ parentElOrDocumentFragment.appendChild( thisModelViewWrapped.get( 0 ) );
421
+ else {
422
+ var numberOfModelViewsCurrentlyInDOM = parentElOrDocumentFragment.children().length;
423
+ if( ! _.isUndefined( atIndex ) && atIndex >= 0 && atIndex < numberOfModelViewsCurrentlyInDOM )
424
+ // note this.collection.length might be greater than parentElOrDocumentFragment.children().length here
425
+ parentElOrDocumentFragment.children().eq( atIndex ).before( thisModelViewWrapped );
426
+ else {
427
+ // if we are attempting to insert a modelView in an position that is beyond what is currently in the
428
+ // DOM, then make a note that we need to re-render the collection view on the next sort event. If we dont
429
+ // force this re-render, we can end up with modelViews in the wrong order when the collection defines
430
+ // a comparator and multiple models are added at once. See https://github.com/rotundasoftware/backbone.collectionView/issues/69
431
+ if( ! _.isUndefined( atIndex ) && atIndex > numberOfModelViewsCurrentlyInDOM ) this.forceRerenderOnNextSortEvent = true;
432
+
433
+ parentElOrDocumentFragment.append( thisModelViewWrapped );
434
+ }
435
+ }
436
+
437
+ this.viewManager.add( modelView );
438
+
439
+ // we have to render the modelView after it has been put in context, as opposed to in the
440
+ // initialize function of the modelView, because some rendering might be dependent on
441
+ // the modelView's context in the DOM tree. For example, if the modelView stretch()'s itself,
442
+ // it must be in full context in the DOM tree or else the stretch will not behave as intended.
443
+ var renderResult = modelView.render();
444
+
445
+ // return false from the view's render function to hide this item
446
+ if( renderResult === false ) {
447
+ thisModelViewWrapped.hide();
448
+ thisModelViewWrapped.addClass( "not-visible" );
449
+ }
450
+
451
+ var hideThisModelView = false;
452
+ if( _.isFunction( this.visibleModelsFilter ) )
453
+ hideThisModelView = ! this.visibleModelsFilter( modelView.model );
454
+
455
+ if( thisModelViewWrapped.children().length === 1 )
456
+ thisModelViewWrapped.toggle( ! hideThisModelView );
457
+ else modelView.$el.toggle( ! hideThisModelView );
458
+
459
+ thisModelViewWrapped.toggleClass( "not-visible", hideThisModelView );
460
+
461
+ if( ! hideThisModelView && this.emptyListCaption ) this._removeEmptyListCaption();
462
+ },
463
+
464
+ updateDependentControls : function() {
465
+ if( this._isBackboneCourierAvailable() ) {
466
+ this.spawn( "updateDependentControls", {
467
+ selectedModels : this.getSelectedModels()
468
+ } );
469
+ } else this.trigger( "updateDependentControls", this.getSelectedModels() );
470
+ },
471
+
472
+ // Override `Backbone.View.remove` to also destroy all Views in `viewManager`
473
+ remove : function() {
474
+ this.viewManager.each( function( view ) {
475
+ view.remove();
476
+ } );
477
+
478
+ Backbone.View.prototype.remove.apply( this, arguments );
479
+ },
480
+
481
+ reapplyFilter : function( whichFilter ) {
482
+ var _this = this;
483
+
484
+ if( ! _.contains( [ "selectableModels", "sortableModels", "visibleModels" ], whichFilter ) ) {
485
+ throw new Error( "Invalid filter identifier supplied to reapplyFilter: " + whichFilter );
486
+ }
487
+
488
+ switch( whichFilter ) {
489
+ case "visibleModels":
490
+ _this.viewManager.each( function( thisModelView ) {
491
+ var notVisible = _this.visibleModelsFilter && ! _this.visibleModelsFilter.call( _this, thisModelView.model );
492
+
493
+ thisModelView.$el.toggleClass( "not-visible", notVisible );
494
+ if( _this._modelViewHasWrapperLI( thisModelView ) ) {
495
+ thisModelView.$el.closest( "li" ).toggleClass( "not-visible", notVisible ).toggle( ! notVisible );
496
+ } else thisModelView.$el.toggle( ! notVisible );
497
+ } );
498
+
499
+ this._showEmptyListCaptionIfAppropriate();
500
+ break;
501
+ case "sortableModels":
502
+ _this.$el.sortable( "destroy" );
503
+
504
+ _this.viewManager.each( function( thisModelView ) {
505
+ var notSortable = _this.sortableModelsFilter && ! _this.sortableModelsFilter.call( _this, thisModelView.model );
506
+
507
+ thisModelView.$el.toggleClass( "not-sortable", notSortable );
508
+ if( _this._modelViewHasWrapperLI( thisModelView ) ) {
509
+ thisModelView.$el.closest( "li" ).toggleClass( "not-sortable", notSortable );
510
+ }
511
+ } );
512
+
513
+ _this._setupSortable();
514
+ break;
515
+ case "selectableModels":
516
+ _this.viewManager.each( function( thisModelView ) {
517
+ var notSelectable = _this.selectableModelsFilter && ! _this.selectableModelsFilter.call( _this, thisModelView.model );
518
+
519
+ thisModelView.$el.toggleClass( "not-selectable", notSelectable );
520
+ if( _this._modelViewHasWrapperLI( thisModelView ) ) {
521
+ thisModelView.$el.closest( "li" ).toggleClass( "not-selectable", notSelectable );
522
+ }
523
+ } );
524
+
525
+ _this._validateSelection();
526
+ break;
527
+ }
528
+ },
529
+
530
+ // A method to remove the view relating to model.
531
+ _removeModelView : function( modelView ) {
532
+ if( this.selectable ) this._saveSelection();
533
+
534
+ this.viewManager.remove( modelView ); // Remove the view from the viewManager
535
+ if( this._modelViewHasWrapperLI( modelView ) ) modelView.$el.parent().remove(); // Remove the li wrapper from the DOM
536
+ modelView.remove(); // Remove the view from the DOM and stop listening to events
537
+
538
+ if( this.selectable ) this._restoreSelection();
539
+
540
+ this._showEmptyListCaptionIfAppropriate();
541
+ },
542
+
543
+ _validateSelectionAndRender : function() {
544
+ this._validateSelection();
545
+ this.render();
546
+ },
547
+
548
+ _registerCollectionEvents : function() {
549
+ this.listenTo( this.collection, "add", function( model ) {
550
+ var modelView;
551
+
552
+ if( this._hasBeenRendered ) {
553
+ modelView = this._createNewModelView( model, this._getModelViewOptions( model ) );
554
+ this._insertAndRenderModelView( modelView, this._getContainerEl(), this.collection.indexOf( model ) );
555
+ }
556
+
557
+ if( this._isBackboneCourierAvailable() )
558
+ this.spawn( "add", modelView );
559
+ else this.trigger( "add", modelView );
560
+ } );
561
+
562
+ this.listenTo( this.collection, "remove", function( model ) {
563
+ var modelView;
564
+
565
+ if( this._hasBeenRendered ) {
566
+ modelView = this.viewManager.findByModelCid( model.cid );
567
+ this._removeModelView( modelView );
568
+ }
569
+
570
+ if( this._isBackboneCourierAvailable() )
571
+ this.spawn( "remove" );
572
+ else this.trigger( "remove" );
573
+ } );
574
+
575
+ this.listenTo( this.collection, "reset", function() {
576
+ if( this._hasBeenRendered ) this.render();
577
+ if( this._isBackboneCourierAvailable() )
578
+ this.spawn( "reset" );
579
+ else this.trigger( "reset" );
580
+ } );
581
+
582
+ // we should not be listening to change events on the model as a default behavior. the models
583
+ // should be responsible for re-rendering themselves if necessary, and if the collection does
584
+ // also need to re-render as a result of a model change, this should be handled by overriding
585
+ // this method. by default the collection view should not re-render in response to model changes
586
+ // this.listenTo( this.collection, "change", function( model ) {
587
+ // if( this._hasBeenRendered ) this.viewManager.findByModel( model ).render();
588
+ // if( this._isBackboneCourierAvailable() )
589
+ // this.spawn( "change", { model : model } );
590
+ // } );
591
+
592
+ this.listenTo( this.collection, "sort", function( collection, options ) {
593
+ if( this._hasBeenRendered && ( options.add !== true || this.forceRerenderOnNextSortEvent ) ) this.render();
594
+ if( this._isBackboneCourierAvailable() )
595
+ this.spawn( "sort" );
596
+ else this.trigger( "sort" );
597
+ } );
598
+ },
599
+
600
+ _getContainerEl : function() {
601
+ if ( this._isRenderedAsTable() ) {
602
+ // not all tables have a tbody, so we test
603
+ var tbody = this.$el.find( "> tbody" );
604
+ if ( tbody.length > 0 )
605
+ return tbody;
606
+ }
607
+ return this.$el;
608
+ },
609
+
610
+ _getClickedItemId : function( theEvent ) {
611
+ var clickedItemId = null;
612
+
613
+ // important to use currentTarget as opposed to target, since we could be bubbling
614
+ // an event that took place within another collectionList
615
+ var clickedItemEl = $( theEvent.currentTarget );
616
+ if( clickedItemEl.closest( ".collection-view" ).get(0) !== this.$el.get(0) ) return;
617
+
618
+ // determine which list item was clicked. If we clicked in the blank area
619
+ // underneath all the elements, we want to know that too, since in this
620
+ // case we will want to deselect all elements. so check to see if the clicked
621
+ // DOM element is the list itself to find that out.
622
+ var clickedItem = clickedItemEl.closest( "[data-model-cid]" );
623
+ if( clickedItem.length > 0 )
624
+ {
625
+ clickedItemId = clickedItem.attr( "data-model-cid" );
626
+ if( $.isNumeric( clickedItemId ) ) clickedItemId = parseInt( clickedItemId, 10 );
627
+ }
628
+
629
+ return clickedItemId;
630
+ },
631
+
632
+ _updateItemTemplate : function() {
633
+ var itemTemplateHtml;
634
+ if( this.itemTemplate )
635
+ {
636
+ if( $( this.itemTemplate ).length === 0 )
637
+ throw "Could not find item template from selector: " + this.itemTemplate;
638
+
639
+ itemTemplateHtml = $( this.itemTemplate ).html();
640
+ }
641
+ else
642
+ itemTemplateHtml = this.$( ".item-template" ).html();
643
+
644
+ if( itemTemplateHtml ) this.itemTemplateFunction = _.template( itemTemplateHtml );
645
+
646
+ },
647
+
648
+ _validateSelection : function() {
649
+ // note can't use the collection's proxy to underscore because "cid" is not an attribute,
650
+ // but an element of the model object itself.
651
+ var modelReferenceIds = _.pluck( this.collection.models, "cid" );
652
+ this.selectedItems = _.intersection( modelReferenceIds, this.selectedItems );
653
+
654
+ if( _.isFunction( this.selectableModelsFilter ) )
655
+ {
656
+ this.selectedItems = _.filter( this.selectedItems, function( thisItemId ) {
657
+ return this.selectableModelsFilter.call( this, this.collection.get( thisItemId ) );
658
+ }, this );
659
+ }
660
+ },
661
+
662
+ _saveSelection : function() {
663
+ // save the current selection. use restoreSelection() to restore the selection to the state it was in the last time saveSelection() was called.
664
+ if( ! this.selectable ) throw "Attempt to save selection on non-selectable list";
665
+ this.savedSelection = {
666
+ items : _.clone( this.selectedItems ),
667
+ offset : this.getSelectedModel( { by : "offset" } )
668
+ };
669
+ },
670
+
671
+ _restoreSelection : function() {
672
+ if( ! this.savedSelection ) throw "Attempt to restore selection but no selection has been saved!";
673
+
674
+ // reset selectedItems to empty so that we "redraw" all "selected" classes
675
+ // when we set our new selection. We do this because it is likely that our
676
+ // contents have been refreshed, and we have thus lost all old "selected" classes.
677
+ this.setSelectedModels( [], { silent : true } );
678
+
679
+ if( this.savedSelection.items.length > 0 )
680
+ {
681
+ // first try to restore the old selected items using their reference ids.
682
+ this.setSelectedModels( this.savedSelection.items, { by : "cid", silent : true } );
683
+
684
+ // all the items with the saved reference ids have been removed from the list.
685
+ // ok. try to restore the selection based on the offset that used to be selected.
686
+ // this is the expected behavior after a item is deleted from a list (i.e. select
687
+ // the line that immediately follows the deleted line).
688
+ if( this.selectedItems.length === 0 )
689
+ this.setSelectedModel( this.savedSelection.offset, { by : "offset" } );
690
+
691
+ // Trigger a selection changed if the previously selected items were not all found
692
+ if (this.selectedItems.length !== this.savedSelection.items.length)
693
+ {
694
+ if( this._isBackboneCourierAvailable() ) {
695
+ this.spawn( "selectionChanged", {
696
+ selectedModels : this.getSelectedModels(),
697
+ oldSelectedModels : []
698
+ } );
699
+ } else this.trigger( "selectionChanged", this.getSelectedModels(), [] );
700
+ }
701
+ }
702
+
703
+ delete this.savedSelection;
704
+ },
705
+
706
+ _addSelectedClassToSelectedItems : function( oldItemsIdsWithSelectedClass ) {
707
+ if( _.isUndefined( oldItemsIdsWithSelectedClass ) ) oldItemsIdsWithSelectedClass = [];
708
+
709
+ // oldItemsIdsWithSelectedClass is used for optimization purposes only. If this info is supplied then we
710
+ // only have to add / remove the "selected" class from those items that "selected" state has changed.
711
+
712
+ var itemsIdsFromWhichSelectedClassNeedsToBeRemoved = oldItemsIdsWithSelectedClass;
713
+ itemsIdsFromWhichSelectedClassNeedsToBeRemoved = _.without( itemsIdsFromWhichSelectedClassNeedsToBeRemoved, this.selectedItems );
714
+
715
+ _.each( itemsIdsFromWhichSelectedClassNeedsToBeRemoved, function( thisItemId ) {
716
+ this._getContainerEl().find( "[data-model-cid=" + thisItemId + "]" ).removeClass( "selected" );
717
+
718
+ if( this._isRenderedAsList() ) {
719
+ this._getContainerEl().find( "li[data-model-cid=" + thisItemId + "] > *" ).removeClass( "selected" );
720
+ }
721
+ }, this );
722
+
723
+ var itemsIdsFromWhichSelectedClassNeedsToBeAdded = this.selectedItems;
724
+ itemsIdsFromWhichSelectedClassNeedsToBeAdded = _.without( itemsIdsFromWhichSelectedClassNeedsToBeAdded, oldItemsIdsWithSelectedClass );
725
+
726
+ _.each( itemsIdsFromWhichSelectedClassNeedsToBeAdded, function( thisItemId ) {
727
+ this._getContainerEl().find( "[data-model-cid=" + thisItemId + "]" ).addClass( "selected" );
728
+
729
+ if( this._isRenderedAsList() ) {
730
+ this._getContainerEl().find( "li[data-model-cid=" + thisItemId + "] > *" ).addClass( "selected" );
731
+ }
732
+ }, this );
733
+ },
734
+
735
+ _reorderCollectionBasedOnHTML : function() {
736
+ var _this = this;
737
+
738
+ this._getContainerEl().children().each( function() {
739
+ var thisModelCid = $( this ).attr( "data-model-cid" );
740
+
741
+ if( thisModelCid )
742
+ {
743
+ // remove the current model and then add it back (at the end of the collection).
744
+ // When we are done looping through all models, they will be in the correct order.
745
+ var thisModel = _this.collection.get( thisModelCid );
746
+ if( thisModel )
747
+ {
748
+ _this.collection.remove( thisModel, { silent : true } );
749
+ _this.collection.add( thisModel, { silent : true, sort : ! _this.collection.comparator } );
750
+ }
751
+ }
752
+ } );
753
+
754
+ if( this._isBackboneCourierAvailable() ) this.spawn( "reorder" );
755
+ else this.collection.trigger( "reorder" );
756
+
757
+ if( this.collection.comparator ) this.collection.sort();
758
+
759
+ },
760
+
761
+ _getModelViewConstructor : function( thisModel ) {
762
+ return this.modelView || mDefaultModelViewConstructor;
763
+ },
764
+
765
+ _getModelViewOptions : function( thisModel ) {
766
+ var modelViewOptions = this.modelViewOptions;
767
+ if( _.isFunction( modelViewOptions ) ) modelViewOptions = modelViewOptions( thisModel );
768
+
769
+ return _.extend( { model : thisModel }, modelViewOptions );
770
+ },
771
+
772
+ _createNewModelView : function( model, modelViewOptions ) {
773
+ var modelViewConstructor = this._getModelViewConstructor( model );
774
+ if( _.isUndefined( modelViewConstructor ) ) throw "Could not find modelView constructor for model";
775
+
776
+ var newModelView = new( modelViewConstructor )( modelViewOptions );
777
+ newModelView.collectionListView = newModelView.collectionView = this; // collectionListView for legacy
778
+
779
+ return newModelView;
780
+ },
781
+
782
+ _wrapModelView : function( modelView ) {
783
+ var _this = this;
784
+
785
+ // we use items client ids as opposed to real ids, since we may not have a representation
786
+ // of these models on the server
787
+ var modelViewWrapperEl;
788
+
789
+ if( this._isRenderedAsTable() ) {
790
+ // if we are rendering the collection in a table, the template $el is a tr so we just need to set the data-model-cid
791
+ modelViewWrapperEl = modelView.$el;
792
+ modelView.$el.attr( "data-model-cid", modelView.model.cid );
793
+ }
794
+ else if( this._isRenderedAsList() ) {
795
+ // if we are rendering the collection in a list, we need wrap each item in an <li></li> (if its not already an <li>)
796
+ // and set the data-model-cid
797
+ if( modelView.$el.is( "li" ) ) {
798
+ modelViewWrapperEl = modelView.$el;
799
+ modelView.$el.attr( "data-model-cid", modelView.model.cid );
800
+ } else {
801
+ modelViewWrapperEl = modelView.$el.wrapAll( "<li data-model-cid='" + modelView.model.cid + "'></li>" ).parent();
802
+ }
803
+ }
804
+
805
+ if( _.isFunction( this.sortableModelsFilter ) )
806
+ if( ! this.sortableModelsFilter.call( _this, modelView.model ) ) {
807
+ modelViewWrapperEl.addClass( "not-sortable" );
808
+ modelView.$el.addClass( "not-selectable" );
809
+ }
810
+
811
+ if( _.isFunction( this.selectableModelsFilter ) )
812
+ if( ! this.selectableModelsFilter.call( _this, modelView.model ) ) {
813
+ modelViewWrapperEl.addClass( "not-selectable" );
814
+ modelView.$el.addClass( "not-selectable" );
815
+ }
816
+
817
+ return modelViewWrapperEl;
818
+ },
819
+
820
+ _convertStringsToInts : function( theArray ) {
821
+ return _.map( theArray, function( thisEl ) {
822
+ if( ! _.isString( thisEl ) ) return thisEl;
823
+ var thisElAsNumber = parseInt( thisEl, 10 );
824
+ return( thisElAsNumber == thisEl ? thisElAsNumber : thisEl );
825
+ } );
826
+ },
827
+
828
+ _containSameElements : function( arrayA, arrayB ) {
829
+ if( arrayA.length != arrayB.length ) return false;
830
+ var intersectionSize = _.intersection( arrayA, arrayB ).length;
831
+ return intersectionSize == arrayA.length; // and must also equal arrayB.length, since arrayA.length == arrayB.length
832
+ },
833
+
834
+ _isRenderedAsTable : function() {
835
+ return this.$el.prop( "tagName" ).toLowerCase() === "table";
836
+ },
837
+
838
+ _isRenderedAsList : function() {
839
+ return ! this._isRenderedAsTable();
840
+ },
841
+
842
+ _modelViewHasWrapperLI : function( modelView ) {
843
+ return this._isRenderedAsList() && ! modelView.$el.is( "li" );
844
+ },
845
+
846
+ // Returns the wrapper HTML element for each visible modelView.
847
+ // When rendering in a table context, the returned elements are the $el of each modelView.
848
+ // When rendering in a list context,
849
+ // If the $el of the modelView is an <li>, the returned elements are the $el of each modelView.
850
+ // Otherwise, the returned elements are the <li>'s the collectionView wrapped around each modelView $el.
851
+ _getVisibleItemEls : function() {
852
+ var itemElements = [];
853
+ itemElements = this._getContainerEl().find( "> [data-model-cid]:not(.not-visible)" );
854
+
855
+ return itemElements;
856
+ },
857
+
858
+ _charCodes : {
859
+ upArrow : 38,
860
+ downArrow : 40
861
+ },
862
+
863
+ _isBackboneCourierAvailable : function() {
864
+ return !_.isUndefined( Backbone.Courier );
865
+ },
866
+
867
+ _setupSortable : function() {
868
+ var sortableOptions = _.extend( {
869
+ axis : "y",
870
+ distance : 10,
871
+ forcePlaceholderSize : true,
872
+ items : this._isRenderedAsTable() ? "> tbody > tr:not(.not-sortable)" : "> li:not(.not-sortable)",
873
+ start : _.bind( this._sortStart, this ),
874
+ change : _.bind( this._sortChange, this ),
875
+ stop : _.bind( this._sortStop, this ),
876
+ receive : _.bind( this._receive, this ),
877
+ over : _.bind( this._over, this ),
878
+ revert: true
879
+ }, _.result( this, "sortableOptions" ) );
880
+
881
+ this.$el = this.$el.sortable( sortableOptions );
882
+ //this.$el.sortable( "enable" ); // in case it was disabled previously
883
+ },
884
+
885
+ _sortStart : function( event, ui ) {
886
+
887
+ var modelBeingSorted = this.collection.get( ui.item.attr( "data-model-cid" ) );
888
+ if( this._isBackboneCourierAvailable() )
889
+ this.spawn( "sortStart", { modelBeingSorted : modelBeingSorted } );
890
+ else this.trigger( "sortStart", modelBeingSorted );
891
+ },
892
+
893
+ _sortChange : function( event, ui ) {
894
+ var modelBeingSorted = this.collection.get( ui.item.attr( "data-model-cid" ) );
895
+
896
+ if( this._isBackboneCourierAvailable() )
897
+ this.spawn( "sortChange", { modelBeingSorted : modelBeingSorted } );
898
+ else this.trigger( "sortChange", modelBeingSorted );
899
+ },
900
+
901
+ _sortStop : function( event, ui ) {
902
+
903
+
904
+ var modelBeingSorted = this.collection.get( ui.item.attr( "data-model-cid" ) );
905
+ var modelViewContainerEl = this._getContainerEl();
906
+ var newIndex = modelViewContainerEl.children().index( ui.item );
907
+
908
+
909
+
910
+ if ( ui.item.find( '[data-specialbtn]' )[0] ) {
911
+
912
+ if ( ui.item.find( '[data-btntype]' ).data(
913
+ 'btntype') == 'singleText' ) {
914
+
915
+ var TextFieldModel = new smuzform.App.Models.Field({
916
+
917
+ type: 'singletext',
918
+ label: 'Untitled',
919
+
920
+
921
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100)
922
+
923
+ });
924
+
925
+ smuzform.App.Collections.FieldsCol.add( TextFieldModel, {at: newIndex} );
926
+ }
927
+
928
+ if ( ui.item.find( '[data-btntype]' ).data(
929
+ 'btntype') == 'singleNumber' ) {
930
+
931
+ var NumberFieldModel = new smuzform.App.Models.Field({
932
+
933
+ type: 'number',
934
+ label: 'Number',
935
+
936
+
937
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100)
938
+
939
+ });
940
+
941
+ smuzform.App.Collections.FieldsCol.add( NumberFieldModel, { at: newIndex } );
942
+
943
+ }
944
+
945
+ if ( ui.item.find( '[data-btntype]' ).data(
946
+ 'btntype') == 'textarea' ) {
947
+
948
+ var TextAreaFieldModel = new smuzform.App.Models.Field({
949
+
950
+ type: 'textarea',
951
+ label: 'Comments',
952
+ size: 'large',
953
+
954
+
955
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100)
956
+
957
+ });
958
+
959
+ smuzform.App.Collections.FieldsCol.add( TextAreaFieldModel, { at: newIndex } );
960
+
961
+ }
962
+
963
+ if ( ui.item.find( '[data-btntype]' ).data(
964
+ 'btntype') == 'dropdown' ) {
965
+
966
+ var SelectFieldModel = new smuzform.App.Models.Field({
967
+
968
+ type: 'dropdown',
969
+ label: 'Untitled',
970
+
971
+
972
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100)
973
+
974
+ });
975
+
976
+ smuzform.App.Collections.FieldsCol.add( SelectFieldModel, { at: newIndex } );
977
+
978
+ }
979
+
980
+ if ( ui.item.find( '[data-btntype]' ).data(
981
+ 'btntype') == 'radioButtons' ) {
982
+
983
+ var RadioFieldModel = new smuzform.App.Models.Field({
984
+
985
+ type: 'radio',
986
+ label: 'Untitled',
987
+
988
+
989
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100)
990
+
991
+ });
992
+
993
+ smuzform.App.Collections.FieldsCol.add( RadioFieldModel, { at: newIndex } );
994
+
995
+ }
996
+
997
+ if ( ui.item.find( '[data-btntype]' ).data(
998
+ 'btntype') == 'checkboxes' ) {
999
+
1000
+ var CheckboxFieldModel = new smuzform.App.Models.Field({
1001
+
1002
+ type: 'checkbox',
1003
+ label: 'Untitled',
1004
+
1005
+
1006
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100)
1007
+
1008
+ });
1009
+
1010
+ smuzform.App.Collections.FieldsCol.add( CheckboxFieldModel, { at: newIndex } );
1011
+
1012
+ }
1013
+
1014
+ if ( ui.item.find( '[data-btntype]' ).data(
1015
+ 'btntype') == 'lineBreak' ) {
1016
+
1017
+ var LinebreakFieldModel = new smuzform.App.Models.Field({
1018
+
1019
+ type: 'linebreak',
1020
+
1021
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100)
1022
+
1023
+ });
1024
+
1025
+ smuzform.App.Collections.FieldsCol.add( LinebreakFieldModel, { at: newIndex } );
1026
+
1027
+ }
1028
+
1029
+ if ( ui.item.find( '[data-btntype]' ).data(
1030
+ 'btntype') == 'sectionBreak' ) {
1031
+
1032
+ var SectionbreakFieldModel = new smuzform.App.Models.Field({
1033
+
1034
+ type: 'sectionbreak',
1035
+
1036
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100)
1037
+
1038
+ });
1039
+
1040
+ smuzform.App.Collections.FieldsCol.add( SectionbreakFieldModel, { at: newIndex } );
1041
+
1042
+ }
1043
+
1044
+ if ( ui.item.find( '[data-btntype]' ).data(
1045
+ 'btntype') == 'fileUpload' ) {
1046
+
1047
+ var FileUploadFieldModel = new smuzform.App.Models.Field({
1048
+
1049
+ type: 'fileupload',
1050
+ label: 'Upload File',
1051
+
1052
+
1053
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100)
1054
+
1055
+ });
1056
+
1057
+ smuzform.App.Collections.FieldsCol.add( FileUploadFieldModel, { at: newIndex } );
1058
+
1059
+ }
1060
+
1061
+ if ( ui.item.find( '[data-btntype]' ).data(
1062
+ 'btntype') == 'name' ) {
1063
+
1064
+ var NameFieldModel = new smuzform.App.Models.Field({
1065
+
1066
+ type: 'name',
1067
+ label: 'Name',
1068
+ extraData: { firstName: '', LastName: '' },
1069
+ size: 'large',
1070
+
1071
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100)
1072
+
1073
+ });
1074
+
1075
+ smuzform.App.Collections.FieldsCol.add( NameFieldModel, { at: newIndex } );
1076
+
1077
+ }
1078
+
1079
+ if ( ui.item.find( '[data-btntype]' ).data(
1080
+ 'btntype') == 'email' ) {
1081
+
1082
+ var EmailFieldModel = new smuzform.App.Models.Field({
1083
+
1084
+ type: 'email',
1085
+ label: 'Email',
1086
+
1087
+
1088
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100)
1089
+
1090
+ });
1091
+
1092
+ smuzform.App.Collections.FieldsCol.add( EmailFieldModel, { at: newIndex } );
1093
+
1094
+ }
1095
+
1096
+ if ( ui.item.find( '[data-btntype]' ).data(
1097
+ 'btntype') == 'website' ) {
1098
+
1099
+ var WebsiteFieldModel = new smuzform.App.Models.Field({
1100
+
1101
+ type: 'website',
1102
+ label: 'Link',
1103
+
1104
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100)
1105
+
1106
+ });
1107
+
1108
+ smuzform.App.Collections.FieldsCol.add( WebsiteFieldModel );
1109
+
1110
+ }
1111
+
1112
+ if ( ui.item.find( '[data-btntype]' ).data(
1113
+ 'btntype') == 'date' ) {
1114
+
1115
+ var DateFieldModel = new smuzform.App.Models.Field({
1116
+
1117
+ type: 'date',
1118
+ label: 'Date',
1119
+ extraData: { day: 16, month: 05, year: 2016 },
1120
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100),
1121
+ size: 'large',
1122
+ preValue: '16/05/2016'
1123
+
1124
+ });
1125
+
1126
+ smuzform.App.Collections.FieldsCol.add( DateFieldModel, { at: newIndex } );
1127
+
1128
+ }
1129
+
1130
+ if ( ui.item.find( '[data-btntype]' ).data(
1131
+ 'btntype') == 'address' ) {
1132
+
1133
+ var addressData = {
1134
+
1135
+ firstAddress: '',
1136
+
1137
+ secondAddress: '',
1138
+
1139
+ city: '',
1140
+
1141
+ state: '',
1142
+
1143
+ code: '',
1144
+
1145
+ country: ''
1146
+
1147
+ };
1148
+
1149
+ var AddressFieldModel = new smuzform.App.Models.Field({
1150
+
1151
+ type: 'address',
1152
+ label: 'Address',
1153
+ extraData: addressData,
1154
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100),
1155
+ size: 'large'
1156
+
1157
+ });
1158
+
1159
+ smuzform.App.Collections.FieldsCol.add( AddressFieldModel, { at: newIndex } );
1160
+
1161
+ }
1162
+
1163
+ if ( ui.item.find( '[data-btntype]' ).data(
1164
+ 'btntype') == 'phone' ) {
1165
+
1166
+ var PhoneFieldModel = new smuzform.App.Models.Field({
1167
+
1168
+ type: 'phone',
1169
+ label: 'Phone Number',
1170
+ extraData: { },
1171
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100),
1172
+ size: 'medium'
1173
+
1174
+ });
1175
+
1176
+ smuzform.App.Collections.FieldsCol.add( PhoneFieldModel, { at: newIndex } );
1177
+
1178
+ }
1179
+
1180
+
1181
+ if ( ui.item.find( '[data-btntype]' ).data(
1182
+ 'btntype') == 'likertScale' ) {
1183
+
1184
+ var likertData = {};
1185
+
1186
+ var LikertFieldModel = new smuzform.App.Models.Field({
1187
+
1188
+ type: 'likert',
1189
+ extraData: likertData,
1190
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100),
1191
+
1192
+ });
1193
+
1194
+ alert( 'The field is in development. Will be available in next version.' );
1195
+
1196
+ }
1197
+
1198
+ if ( ui.item.find( '[data-btntype]' ).data(
1199
+ 'btntype') == 'customText' ) {
1200
+
1201
+
1202
+ var textData = {
1203
+ html: 'Change me',
1204
+ readyHtml: '<p style="font-size: 14px;color: #000;font-weight: normal">Change Me</p>',
1205
+ tag: 'p',
1206
+ size: 14,
1207
+ color: '#000000',
1208
+ bold: false
1209
+ };
1210
+
1211
+ var TextModel = new smuzform.App.Models.Field( {
1212
+
1213
+ type: 'customText',
1214
+ label: 'Custom Text',
1215
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100),
1216
+ extraData: textData
1217
+ });
1218
+
1219
+
1220
+ smuzform.App.Collections.FieldsCol.add( TextModel, { at: newIndex } );
1221
+
1222
+ }
1223
+
1224
+ if ( ui.item.find( '[data-btntype]' ).data(
1225
+ 'btntype') == 'customImage' ) {
1226
+
1227
+ var imageData = {
1228
+ imgUrl: '',
1229
+ readyHtml: '<img src="" width="300" height="150" />',
1230
+ width: 300,
1231
+ height: 150
1232
+ };
1233
+
1234
+ var ImageModel = new smuzform.App.Models.Field( {
1235
+
1236
+ type: 'customImage',
1237
+ label: 'Custom Image',
1238
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100),
1239
+ extraData: imageData
1240
+ });
1241
+
1242
+ smuzform.App.Collections.FieldsCol.add( ImageModel, { at: newIndex } );
1243
+
1244
+ }
1245
+
1246
+ if ( ui.item.find( '[data-btntype]' ).data(
1247
+ 'btntype') == 'customHtml' ) {
1248
+
1249
+ var htmlData = {
1250
+ readyHtml: 'Edit Me'
1251
+ };
1252
+
1253
+ var HtmlModel = new smuzform.App.Models.Field( {
1254
+
1255
+ type: 'customHtml',
1256
+ label: 'Custom Html',
1257
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100),
1258
+ extraData: htmlData
1259
+ });
1260
+
1261
+ smuzform.App.Collections.FieldsCol.add( HtmlModel, { at: newIndex } );
1262
+
1263
+ }
1264
+
1265
+ if ( ui.item.find( '[data-btntype]' ).data(
1266
+ 'btntype') == 'pageBreak' ) {
1267
+
1268
+ var pageBreakData = {
1269
+ navText: ''
1270
+ };
1271
+
1272
+ var PageBreakModel = new smuzform.App.Models.Field( {
1273
+ label: 'Page Break',
1274
+ type: 'pagebreak',
1275
+ label: 'Page Break',
1276
+ cssID: 'wpformfield'+Math.floor((Math.random() * 200000) + 100),
1277
+ extraData: pageBreakData
1278
+ });
1279
+
1280
+ smuzform.App.Collections.FieldsCol.add( PageBreakModel, { at: newIndex } );
1281
+
1282
+ }
1283
+
1284
+ if ( ui.item.find( '[data-btntype]' ).data(
1285
+ 'btntype') == 'link' ) {
1286
+
1287
+ alert( 'The field is in development. Will be available in next version.' );
1288
+
1289
+ }
1290
+
1291
+ if ( ui.item.find( '[data-btntype]' ).data(
1292
+ 'btntype') == 'rating' ) {
1293
+
1294
+ alert( 'The field is in development. Will be available in next version.' );
1295
+
1296
+ }
1297
+
1298
+
1299
+
1300
+
1301
+ ui.item.remove();
1302
+
1303
+ }
1304
+
1305
+
1306
+
1307
+ if( newIndex == -1 && modelBeingSorted ) {
1308
+ // the element was removed from this list. can happen if this sortable is connected
1309
+ // to another sortable, and the item was dropped into the other sortable.
1310
+ this.collection.remove( modelBeingSorted );
1311
+ }
1312
+
1313
+ if( ! modelBeingSorted ) return; // something is wacky. we don't mess with this case, preferring to guarantee that we can always provide a reference to the model
1314
+
1315
+ this._reorderCollectionBasedOnHTML();
1316
+ this.updateDependentControls();
1317
+
1318
+ if( this._isBackboneCourierAvailable() )
1319
+ this.spawn( "sortStop", { modelBeingSorted : modelBeingSorted, newIndex : newIndex } );
1320
+ else this.trigger( "sortStop", modelBeingSorted, newIndex );
1321
+ },
1322
+
1323
+ _receive : function( event, ui ) {
1324
+
1325
+ //alert(this._getContainerEl().children().index( ui.item ));
1326
+
1327
+ var senderListEl = ui.sender;
1328
+ var senderCollectionListView = senderListEl.data( "view" );
1329
+ if( ! senderCollectionListView || ! senderCollectionListView.collection ) return;
1330
+
1331
+ var newIndex = this._getContainerEl().children().index( ui.item );
1332
+ var modelReceived = senderCollectionListView.collection.get( ui.item.attr( "data-model-cid" ) );
1333
+ senderCollectionListView.collection.remove( modelReceived );
1334
+ this.collection.add( modelReceived, { at : newIndex } );
1335
+ modelReceived.collection = this.collection; // otherwise will not get properly set, since modelReceived.collection might already have a value.
1336
+ this.setSelectedModel( modelReceived );
1337
+ },
1338
+
1339
+ _over : function( event, ui ) {
1340
+ //console.log( ui.item.html('hello world') );
1341
+ //alert(this._getContainerEl().children().index( ui.item ));
1342
+
1343
+
1344
+
1345
+
1346
+ // when an item is being dragged into the sortable,
1347
+ // hide the empty list caption if it exists
1348
+ this._getContainerEl().find( "> var.empty-list-caption" ).hide();
1349
+ },
1350
+
1351
+ _onKeydown : function( event ) {
1352
+ if( ! this.processKeyEvents ) return true;
1353
+
1354
+ var trap = false;
1355
+
1356
+ if( this.getSelectedModels( { by : "offset" } ).length == 1 )
1357
+ {
1358
+ // need to trap down and up arrows or else the browser
1359
+ // will end up scrolling a autoscroll div.
1360
+
1361
+ var currentOffset = this.getSelectedModel( { by : "offset" } );
1362
+ if( event.which === this._charCodes.upArrow && currentOffset !== 0 )
1363
+ {
1364
+ this.setSelectedModel( currentOffset - 1, { by : "offset" } );
1365
+ trap = true;
1366
+ }
1367
+ else if( event.which === this._charCodes.downArrow && currentOffset !== this.collection.length - 1 )
1368
+ {
1369
+ this.setSelectedModel( currentOffset + 1, { by : "offset" } );
1370
+ trap = true;
1371
+ }
1372
+ }
1373
+
1374
+ return ! trap;
1375
+ },
1376
+
1377
+ _listItem_onMousedown : function( theEvent ) {
1378
+ var clickedItemId = this._getClickedItemId( theEvent );
1379
+
1380
+ if( clickedItemId ) {
1381
+ var clickedModel = this.collection.get( clickedItemId );
1382
+ if( this._isBackboneCourierAvailable() )
1383
+ this.spawn( "click", { clickedModel : clickedModel } );
1384
+ else this.trigger( "click", clickedModel );
1385
+ }
1386
+
1387
+ if( ! this.selectable || ! this.clickToSelect ) return;
1388
+
1389
+ if( clickedItemId )
1390
+ {
1391
+ // Exit if an unselectable item was clicked
1392
+ if( _.isFunction( this.selectableModelsFilter ) &&
1393
+ ! this.selectableModelsFilter.call( this, this.collection.get( clickedItemId ) ) )
1394
+ {
1395
+ return;
1396
+ }
1397
+
1398
+ // a selectable list item was clicked
1399
+ if( this.selectMultiple && theEvent.shiftKey )
1400
+ {
1401
+ var firstSelectedItemIndex = -1;
1402
+
1403
+ if( this.selectedItems.length > 0 )
1404
+ {
1405
+ this.collection.find( function( thisItemModel ) {
1406
+ firstSelectedItemIndex++;
1407
+
1408
+ // exit when we find our first selected element
1409
+ return _.contains( this.selectedItems, thisItemModel.cid );
1410
+ }, this );
1411
+ }
1412
+
1413
+ var clickedItemIndex = -1;
1414
+ this.collection.find( function( thisItemModel ) {
1415
+ clickedItemIndex++;
1416
+
1417
+ // exit when we find the clicked element
1418
+ return thisItemModel.cid == clickedItemId;
1419
+ }, this );
1420
+
1421
+ var shiftKeyRootSelectedItemIndex = firstSelectedItemIndex == -1 ? clickedItemIndex : firstSelectedItemIndex;
1422
+ var minSelectedItemIndex = Math.min( clickedItemIndex, shiftKeyRootSelectedItemIndex );
1423
+ var maxSelectedItemIndex = Math.max( clickedItemIndex, shiftKeyRootSelectedItemIndex );
1424
+
1425
+ var newSelectedItems = [];
1426
+ for( var thisIndex = minSelectedItemIndex; thisIndex <= maxSelectedItemIndex; thisIndex ++ )
1427
+ newSelectedItems.push( this.collection.at( thisIndex ).cid );
1428
+ this.setSelectedModels( newSelectedItems, { by : "cid" } );
1429
+
1430
+ // shift clicking will usually highlight selectable text, which we do not want.
1431
+ // this is a cross browser (hopefully) snippet that deselects all text selection.
1432
+ if( document.selection && document.selection.empty )
1433
+ document.selection.empty();
1434
+ else if(window.getSelection) {
1435
+ var sel = window.getSelection();
1436
+ if( sel && sel.removeAllRanges )
1437
+ sel.removeAllRanges();
1438
+ }
1439
+ }
1440
+ else if( ( this.selectMultiple || _.contains( this.selectedItems, clickedItemId ) ) && ( this.clickToToggle || theEvent.metaKey || theEvent.ctrlKey ) )
1441
+ {
1442
+ if( _.contains( this.selectedItems, clickedItemId ) )
1443
+ this.setSelectedModels( _.without( this.selectedItems, clickedItemId ), { by : "cid" } );
1444
+ else this.setSelectedModels( _.union( this.selectedItems, [clickedItemId] ), { by : "cid" } );
1445
+ }
1446
+ else
1447
+ this.setSelectedModels( [ clickedItemId ], { by : "cid" } );
1448
+ }
1449
+ else
1450
+ // the blank area of the list was clicked
1451
+ this.setSelectedModels( [] );
1452
+
1453
+ },
1454
+
1455
+ _listItem_onDoubleClick : function( theEvent ) {
1456
+ var clickedItemId = this._getClickedItemId( theEvent );
1457
+
1458
+ if( clickedItemId )
1459
+ {
1460
+ var clickedModel = this.collection.get( clickedItemId );
1461
+
1462
+ if( this._isBackboneCourierAvailable() )
1463
+ this.spawn( "doubleClick", { clickedModel : clickedModel } );
1464
+ else this.trigger( "doubleClick", clickedModel );
1465
+ }
1466
+ },
1467
+
1468
+ _listBackground_onClick : function( theEvent ) {
1469
+ if( ! this.selectable || ! this.clickToSelect ) return;
1470
+ if( ! $( theEvent.target ).is( ".collection-view" ) ) return;
1471
+
1472
+ this.setSelectedModels( [] );
1473
+ }
1474
+
1475
+ }, {
1476
+ setDefaultModelViewConstructor : function( theConstructor ) {
1477
+ mDefaultModelViewConstructor = theConstructor;
1478
+ }
1479
+ });
1480
+
1481
+ /*
1482
+ * Backbone.ViewOptions, v0.2.4
1483
+ * Copyright (c)2014 Rotunda Software, LLC.
1484
+ * Distributed under MIT license
1485
+ * http://github.com/rotundasoftware/backbone.viewOptions
1486
+ */
1487
+
1488
+ Backbone.ViewOptions = {};
1489
+
1490
+ Backbone.ViewOptions.add = function( view, optionsDeclarationsProperty ) {
1491
+ if( _.isUndefined( optionsDeclarationsProperty ) ) optionsDeclarationsProperty = "options";
1492
+
1493
+ // ****************** Public methods added to view ******************
1494
+
1495
+ view.setOptions = function( options ) {
1496
+ var _this = this;
1497
+ var optionsThatWereChanged = {};
1498
+ var optionsThatWereChangedPreviousValues = {};
1499
+
1500
+ var optionDeclarations = _.result( this, optionsDeclarationsProperty );
1501
+
1502
+ if( ! _.isUndefined( optionDeclarations ) ) {
1503
+ var normalizedOptionDeclarations = _normalizeOptionDeclarations( optionDeclarations );
1504
+
1505
+ _.each( normalizedOptionDeclarations, function( thisOptionProperties, thisOptionName ) {
1506
+ var thisOptionRequired = thisOptionProperties.required;
1507
+ var thisOptionDefaultValue = thisOptionProperties.defaultValue;
1508
+
1509
+ if( thisOptionRequired ) {
1510
+ // note we do not throw an error if a required option is not supplied, but it is
1511
+ // found on the object itself (due to a prior call of view.setOptions, most likely)
1512
+
1513
+ if( ( ! options || ! _.contains( _.keys( options ), thisOptionName ) ) && _.isUndefined( _this[ thisOptionName ] ) )
1514
+ throw new Error( "Required option \"" + thisOptionName + "\" was not supplied." );
1515
+
1516
+ if( options && _.contains( _.keys( options ), thisOptionName ) && _.isUndefined( options[ thisOptionName ] ) )
1517
+ throw new Error( "Required option \"" + thisOptionName + "\" can not be set to undefined." );
1518
+ }
1519
+
1520
+ // attach the supplied value of this option, or the appropriate default value, to the view object
1521
+ if( options && thisOptionName in options && ! _.isUndefined( options[ thisOptionName ] ) ) {
1522
+ var oldValue = _this[ thisOptionName ];
1523
+ var newValue = options[ thisOptionName ];
1524
+ // if this option already exists on the view, and the new value is different,
1525
+ // make a note that we will be changing it
1526
+ if( ! _.isUndefined( oldValue ) && oldValue !== newValue ) {
1527
+ optionsThatWereChangedPreviousValues[ thisOptionName ] = oldValue;
1528
+ optionsThatWereChanged[ thisOptionName ] = newValue;
1529
+ }
1530
+ _this[ thisOptionName ] = newValue;
1531
+ // note we do NOT delete the option off the options object here so that
1532
+ // multiple views can be passed the same options object without issue.
1533
+ }
1534
+ else if( _.isUndefined( _this[ thisOptionName ] ) ) {
1535
+ // note defaults do not write over any existing properties on the view itself.
1536
+ _this[ thisOptionName ] = thisOptionDefaultValue;
1537
+ }
1538
+ } );
1539
+ }
1540
+
1541
+ if( _.keys( optionsThatWereChanged ).length > 0 ) {
1542
+ if( _.isFunction( _this.onOptionsChanged ) )
1543
+ _this.onOptionsChanged( optionsThatWereChanged, optionsThatWereChangedPreviousValues );
1544
+ else if( _.isFunction( _this._onOptionsChanged ) )
1545
+ _this._onOptionsChanged( optionsThatWereChanged, optionsThatWereChangedPreviousValues );
1546
+ }
1547
+ };
1548
+
1549
+ view.getOptions = function() {
1550
+ var optionDeclarations = _.result( this, optionsDeclarationsProperty );
1551
+ if( _.isUndefined( optionDeclarations ) ) return {};
1552
+
1553
+ var normalizedOptionDeclarations = _normalizeOptionDeclarations( optionDeclarations );
1554
+ var optionsNames = _.keys( normalizedOptionDeclarations );
1555
+
1556
+ return _.pick( this, optionsNames );
1557
+ };
1558
+ };
1559
+
1560
+ // ****************** Private Utility Functions ******************
1561
+
1562
+ function _normalizeOptionDeclarations( optionDeclarations ) {
1563
+ // convert our short-hand option syntax (with exclamation marks, etc.)
1564
+ // to a simple array of standard option declaration objects.
1565
+
1566
+ var normalizedOptionDeclarations = {};
1567
+
1568
+ if( ! _.isArray( optionDeclarations ) ) throw new Error( "Option declarations must be an array." );
1569
+
1570
+ _.each( optionDeclarations, function( thisOptionDeclaration ) {
1571
+ var thisOptionName, thisOptionRequired, thisOptionDefaultValue;
1572
+
1573
+ thisOptionRequired = false;
1574
+ thisOptionDefaultValue = undefined;
1575
+
1576
+ if( _.isString( thisOptionDeclaration ) )
1577
+ thisOptionName = thisOptionDeclaration;
1578
+ else if( _.isObject( thisOptionDeclaration ) ) {
1579
+ thisOptionName = _.first( _.keys( thisOptionDeclaration ) );
1580
+ if( _.isFunction( thisOptionDeclaration[ thisOptionName ] ) )
1581
+ thisOptionDefaultValue = thisOptionDeclaration[ thisOptionName ];
1582
+ else
1583
+ thisOptionDefaultValue = _.clone( thisOptionDeclaration[ thisOptionName ] );
1584
+ }
1585
+ else throw new Error( "Each element in the option declarations array must be either a string or an object." );
1586
+
1587
+ if( thisOptionName[ thisOptionName.length - 1 ] === "!" ) {
1588
+ thisOptionRequired = true;
1589
+ thisOptionName = thisOptionName.slice( 0, thisOptionName.length - 1 );
1590
+ }
1591
+
1592
+ normalizedOptionDeclarations[ thisOptionName ] = normalizedOptionDeclarations[ thisOptionName ] || {};
1593
+ normalizedOptionDeclarations[ thisOptionName ].required = thisOptionRequired;
1594
+ if( ! _.isUndefined( thisOptionDefaultValue ) ) normalizedOptionDeclarations[ thisOptionName ].defaultValue = thisOptionDefaultValue;
1595
+ } );
1596
+
1597
+ return normalizedOptionDeclarations;
1598
+ }
1599
+
1600
+
1601
+ // Backbone.BabySitter
1602
+ // -------------------
1603
+ // v0.0.6
1604
+ //
1605
+ // Copyright (c)2013 Derick Bailey, Muted Solutions, LLC.
1606
+ // Distributed under MIT license
1607
+ //
1608
+ // http://github.com/babysitterjs/backbone.babysitter
1609
+
1610
+ // Backbone.ChildViewContainer
1611
+ // ---------------------------
1612
+ //
1613
+ // Provide a container to store, retrieve and
1614
+ // shut down child views.
1615
+
1616
+ ChildViewContainer = (function(Backbone, _){
1617
+
1618
+ // Container Constructor
1619
+ // ---------------------
1620
+
1621
+ var Container = function(views){
1622
+ this._views = {};
1623
+ this._indexByModel = {};
1624
+ this._indexByCustom = {};
1625
+ this._updateLength();
1626
+
1627
+ _.each(views, this.add, this);
1628
+ };
1629
+
1630
+ // Container Methods
1631
+ // -----------------
1632
+
1633
+ _.extend(Container.prototype, {
1634
+
1635
+ // Add a view to this container. Stores the view
1636
+ // by `cid` and makes it searchable by the model
1637
+ // cid (and model itself). Optionally specify
1638
+ // a custom key to store an retrieve the view.
1639
+ add: function(view, customIndex){
1640
+ var viewCid = view.cid;
1641
+
1642
+ // store the view
1643
+ this._views[viewCid] = view;
1644
+
1645
+ // index it by model
1646
+ if (view.model){
1647
+ this._indexByModel[view.model.cid] = viewCid;
1648
+ }
1649
+
1650
+ // index by custom
1651
+ if (customIndex){
1652
+ this._indexByCustom[customIndex] = viewCid;
1653
+ }
1654
+
1655
+ this._updateLength();
1656
+ },
1657
+
1658
+ // Find a view by the model that was attached to
1659
+ // it. Uses the model's `cid` to find it.
1660
+ findByModel: function(model){
1661
+ return this.findByModelCid(model.cid);
1662
+ },
1663
+
1664
+ // Find a view by the `cid` of the model that was attached to
1665
+ // it. Uses the model's `cid` to find the view `cid` and
1666
+ // retrieve the view using it.
1667
+ findByModelCid: function(modelCid){
1668
+ var viewCid = this._indexByModel[modelCid];
1669
+ return this.findByCid(viewCid);
1670
+ },
1671
+
1672
+ // Find a view by a custom indexer.
1673
+ findByCustom: function(index){
1674
+ var viewCid = this._indexByCustom[index];
1675
+ return this.findByCid(viewCid);
1676
+ },
1677
+
1678
+ // Find by index. This is not guaranteed to be a
1679
+ // stable index.
1680
+ findByIndex: function(index){
1681
+ return _.values(this._views)[index];
1682
+ },
1683
+
1684
+ // retrieve a view by it's `cid` directly
1685
+ findByCid: function(cid){
1686
+ return this._views[cid];
1687
+ },
1688
+
1689
+ findIndexByCid : function( cid ) {
1690
+ var index = -1;
1691
+ var view = _.find( this._views, function ( view ) {
1692
+ index++;
1693
+ if( view.model.cid == cid )
1694
+ return view;
1695
+ } );
1696
+ return ( view ) ? index : -1;
1697
+ },
1698
+
1699
+ // Remove a view
1700
+ remove: function(view){
1701
+ var viewCid = view.cid;
1702
+
1703
+ // delete model index
1704
+ if (view.model){
1705
+ delete this._indexByModel[view.model.cid];
1706
+ }
1707
+
1708
+ // delete custom index
1709
+ _.any(this._indexByCustom, function(cid, key) {
1710
+ if (cid === viewCid) {
1711
+ delete this._indexByCustom[key];
1712
+ return true;
1713
+ }
1714
+ }, this);
1715
+
1716
+ // remove the view from the container
1717
+ delete this._views[viewCid];
1718
+
1719
+ // update the length
1720
+ this._updateLength();
1721
+ },
1722
+
1723
+ // Call a method on every view in the container,
1724
+ // passing parameters to the call method one at a
1725
+ // time, like `function.call`.
1726
+ call: function(method){
1727
+ this.apply(method, _.tail(arguments));
1728
+ },
1729
+
1730
+ // Apply a method on every view in the container,
1731
+ // passing parameters to the call method one at a
1732
+ // time, like `function.apply`.
1733
+ apply: function(method, args){
1734
+ _.each(this._views, function(view){
1735
+ if (_.isFunction(view[method])){
1736
+ view[method].apply(view, args || []);
1737
+ }
1738
+ });
1739
+ },
1740
+
1741
+ // Update the `.length` attribute on this container
1742
+ _updateLength: function(){
1743
+ this.length = _.size(this._views);
1744
+ }
1745
+ });
1746
+
1747
+ // Borrowing this code from Backbone.Collection:
1748
+ // http://backbonejs.org/docs/backbone.html#section-106
1749
+ //
1750
+ // Mix in methods from Underscore, for iteration, and other
1751
+ // collection related features.
1752
+ var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter',
1753
+ 'select', 'reject', 'every', 'all', 'some', 'any', 'include',
1754
+ 'contains', 'invoke', 'toArray', 'first', 'initial', 'rest',
1755
+ 'last', 'without', 'isEmpty', 'pluck'];
1756
+
1757
+ _.each(methods, function(method) {
1758
+ Container.prototype[method] = function() {
1759
+ var views = _.values(this._views);
1760
+ var args = [views].concat(_.toArray(arguments));
1761
+ return _[method].apply(_, args);
1762
+ };
1763
+ });
1764
+
1765
+ // return the public API
1766
+ return Container;
1767
+ })(Backbone, _);
1768
+
1769
+ return Backbone.CollectionView;
1770
+ } ) );
admin/assets/js/script.js CHANGED
@@ -69,7 +69,7 @@ smuzform.App.Models.FormSettings = Backbone.Model.extend({
69
 
70
 
71
 
72
- var Field = Backbone.Model.extend({
73
 
74
  validate: function( attr ) {
75
 
@@ -173,7 +173,7 @@ var Field = Backbone.Model.extend({
173
 
174
  var FieldsCollection = Backbone.Collection.extend({
175
 
176
- model: Field,
177
 
178
  initialize: function() {
179
 
@@ -1016,7 +1016,7 @@ $(document).ready(function() {
1016
 
1017
  $('.singleText button').click(function() {
1018
 
1019
- var TextFieldModel = new Field({
1020
 
1021
  type: 'singletext',
1022
  label: 'Untitled',
@@ -1035,7 +1035,7 @@ $(document).ready(function() {
1035
 
1036
  $('.textArea button').click(function() {
1037
 
1038
- var TextAreaFieldModel = new Field({
1039
 
1040
  type: 'textarea',
1041
  label: 'Untitled',
@@ -1053,7 +1053,7 @@ $(document).ready(function() {
1053
 
1054
  $('.radioButtons button').click(function() {
1055
 
1056
- var RadioFieldModel = new Field({
1057
 
1058
  type: 'radio',
1059
  label: 'Untitled',
@@ -1070,7 +1070,7 @@ $(document).ready(function() {
1070
 
1071
  $('.checkboxes button').click(function() {
1072
 
1073
- var CheckboxFieldModel = new Field({
1074
 
1075
  type: 'checkbox',
1076
  label: 'Untitled',
@@ -1087,7 +1087,7 @@ $(document).ready(function() {
1087
 
1088
  $('.dropdown button').click(function() {
1089
 
1090
- var SelectFieldModel = new Field({
1091
 
1092
  type: 'dropdown',
1093
  label: 'Untitled',
@@ -1104,7 +1104,7 @@ $(document).ready(function() {
1104
 
1105
  $('.lineBreak button').click(function() {
1106
 
1107
- var LinebreakFieldModel = new Field({
1108
 
1109
  type: 'linebreak',
1110
 
@@ -1119,7 +1119,7 @@ $(document).ready(function() {
1119
 
1120
  $('.sectionBreak button').click(function() {
1121
 
1122
- var SectionbreakFieldModel = new Field({
1123
 
1124
  type: 'sectionbreak',
1125
 
@@ -1134,7 +1134,7 @@ $(document).ready(function() {
1134
 
1135
  $('.singleNumber button').click(function() {
1136
 
1137
- var NumberFieldModel = new Field({
1138
 
1139
  type: 'number',
1140
  label: 'Number',
@@ -1151,7 +1151,7 @@ $(document).ready(function() {
1151
 
1152
  $('.fileUpload button').click(function() {
1153
 
1154
- var FileUploadFieldModel = new Field({
1155
 
1156
  type: 'fileupload',
1157
  label: 'Upload File',
@@ -1168,7 +1168,7 @@ $(document).ready(function() {
1168
 
1169
  $('.name button').click(function() {
1170
 
1171
- var NameFieldModel = new Field({
1172
 
1173
  type: 'name',
1174
  label: 'Name',
@@ -1186,7 +1186,7 @@ $(document).ready(function() {
1186
 
1187
  $('.email button').click(function() {
1188
 
1189
- var EmailFieldModel = new Field({
1190
 
1191
  type: 'email',
1192
  label: 'Email',
@@ -1203,7 +1203,7 @@ $(document).ready(function() {
1203
 
1204
  $('.website button').click(function() {
1205
 
1206
- var WebsiteFieldModel = new Field({
1207
 
1208
  type: 'website',
1209
  label: 'Link',
@@ -1219,7 +1219,7 @@ $(document).ready(function() {
1219
 
1220
  $('.date button').click(function() {
1221
 
1222
- var DateFieldModel = new Field({
1223
 
1224
  type: 'date',
1225
  label: 'Date',
@@ -1239,7 +1239,7 @@ $(document).ready(function() {
1239
 
1240
  $('.phone button').click(function() {
1241
 
1242
- var PhoneFieldModel = new Field({
1243
 
1244
  type: 'phone',
1245
  label: 'Phone Number',
@@ -1274,7 +1274,7 @@ $(document).ready(function() {
1274
 
1275
  };
1276
 
1277
- var AddressFieldModel = new Field({
1278
 
1279
  type: 'address',
1280
  label: 'Address',
@@ -1292,7 +1292,7 @@ $(document).ready(function() {
1292
 
1293
  var likertData = {};
1294
 
1295
- var LikertFieldModel = new Field({
1296
 
1297
  type: 'likert',
1298
  extraData: likertData,
@@ -1317,7 +1317,7 @@ $(document).ready(function() {
1317
  bold: false
1318
  };
1319
 
1320
- var TextModel = new Field( {
1321
 
1322
  type: 'customText',
1323
  label: 'Custom Text',
@@ -1338,7 +1338,7 @@ $(document).ready(function() {
1338
  height: 150
1339
  };
1340
 
1341
- var ImageModel = new Field( {
1342
 
1343
  type: 'customImage',
1344
  label: 'Custom Image',
@@ -1356,7 +1356,7 @@ $(document).ready(function() {
1356
  readyHtml: 'Edit Me'
1357
  };
1358
 
1359
- var HtmlModel = new Field( {
1360
 
1361
  type: 'customHtml',
1362
  label: 'Custom Html',
@@ -1374,7 +1374,7 @@ $(document).ready(function() {
1374
  navText: ''
1375
  };
1376
 
1377
- var PageBreakModel = new Field( {
1378
  label: 'Page Break',
1379
  type: 'pagebreak',
1380
  label: 'Page Break',
@@ -1483,11 +1483,12 @@ $(document).ready(function() {
1483
  smuzform.App.Collections.FieldsCol.add(field);
1484
  });
1485
 
1486
- smuzform.App.Collections.FieldsCol.on( 'add', function( model ) {
1487
  $('html, body').animate({
1488
  scrollTop: $('#saveForm').offset().top - 200
1489
  }, 200);
1490
- } );
 
1491
 
1492
  }).always(function() {
1493
 
@@ -1522,4 +1523,16 @@ $(document).on( 'submit', '#formSettingsForm', function() {
1522
 
1523
  $(document).ready(function(){$('.toplevel_page_smuz-forms-main').addClass('current');})
1524
 
 
 
 
 
 
 
 
 
 
 
 
 
1525
  })(jQuery);
69
 
70
 
71
 
72
+ smuzform.App.Models.Field = Backbone.Model.extend({
73
 
74
  validate: function( attr ) {
75
 
173
 
174
  var FieldsCollection = Backbone.Collection.extend({
175
 
176
+ model: smuzform.App.Models.Field,
177
 
178
  initialize: function() {
179
 
1016
 
1017
  $('.singleText button').click(function() {
1018
 
1019
+ var TextFieldModel = new smuzform.App.Models.Field({
1020
 
1021
  type: 'singletext',
1022
  label: 'Untitled',
1035
 
1036
  $('.textArea button').click(function() {
1037
 
1038
+ var TextAreaFieldModel = new smuzform.App.Models.Field({
1039
 
1040
  type: 'textarea',
1041
  label: 'Untitled',
1053
 
1054
  $('.radioButtons button').click(function() {
1055
 
1056
+ var RadioFieldModel = new smuzform.App.Models.Field({
1057
 
1058
  type: 'radio',
1059
  label: 'Untitled',
1070
 
1071
  $('.checkboxes button').click(function() {
1072
 
1073
+ var CheckboxFieldModel = new smuzform.App.Models.Field({
1074
 
1075
  type: 'checkbox',
1076
  label: 'Untitled',
1087
 
1088
  $('.dropdown button').click(function() {
1089
 
1090
+ var SelectFieldModel = new smuzform.App.Models.Field({
1091
 
1092
  type: 'dropdown',
1093
  label: 'Untitled',
1104
 
1105
  $('.lineBreak button').click(function() {
1106
 
1107
+ var LinebreakFieldModel = new smuzform.App.Models.Field({
1108
 
1109
  type: 'linebreak',
1110
 
1119
 
1120
  $('.sectionBreak button').click(function() {
1121
 
1122
+ var SectionbreakFieldModel = new smuzform.App.Models.Field({
1123
 
1124
  type: 'sectionbreak',
1125
 
1134
 
1135
  $('.singleNumber button').click(function() {
1136
 
1137
+ var NumberFieldModel = new smuzform.App.Models.Field({
1138
 
1139
  type: 'number',
1140
  label: 'Number',
1151
 
1152
  $('.fileUpload button').click(function() {
1153
 
1154
+ var FileUploadFieldModel = new smuzform.App.Models.Field({
1155
 
1156
  type: 'fileupload',
1157
  label: 'Upload File',
1168
 
1169
  $('.name button').click(function() {
1170
 
1171
+ var NameFieldModel = new smuzform.App.Models.Field({
1172
 
1173
  type: 'name',
1174
  label: 'Name',
1186
 
1187
  $('.email button').click(function() {
1188
 
1189
+ var EmailFieldModel = new smuzform.App.Models.Field({
1190
 
1191
  type: 'email',
1192
  label: 'Email',
1203
 
1204
  $('.website button').click(function() {
1205
 
1206
+ var WebsiteFieldModel = new smuzform.App.Models.Field({
1207
 
1208
  type: 'website',
1209
  label: 'Link',
1219
 
1220
  $('.date button').click(function() {
1221
 
1222
+ var DateFieldModel = new smuzform.App.Models.Field({
1223
 
1224
  type: 'date',
1225
  label: 'Date',
1239
 
1240
  $('.phone button').click(function() {
1241
 
1242
+ var PhoneFieldModel = new smuzform.App.Models.Field({
1243
 
1244
  type: 'phone',
1245
  label: 'Phone Number',
1274
 
1275
  };
1276
 
1277
+ var AddressFieldModel = new smuzform.App.Models.Field({
1278
 
1279
  type: 'address',
1280
  label: 'Address',
1292
 
1293
  var likertData = {};
1294
 
1295
+ var LikertFieldModel = new smuzform.App.Models.Field({
1296
 
1297
  type: 'likert',
1298
  extraData: likertData,
1317
  bold: false
1318
  };
1319
 
1320
+ var TextModel = new smuzform.App.Models.Field( {
1321
 
1322
  type: 'customText',
1323
  label: 'Custom Text',
1338
  height: 150
1339
  };
1340
 
1341
+ var ImageModel = new smuzform.App.Models.Field( {
1342
 
1343
  type: 'customImage',
1344
  label: 'Custom Image',
1356
  readyHtml: 'Edit Me'
1357
  };
1358
 
1359
+ var HtmlModel = new smuzform.App.Models.Field( {
1360
 
1361
  type: 'customHtml',
1362
  label: 'Custom Html',
1374
  navText: ''
1375
  };
1376
 
1377
+ var PageBreakModel = new smuzform.App.Models.Field( {
1378
  label: 'Page Break',
1379
  type: 'pagebreak',
1380
  label: 'Page Break',
1483
  smuzform.App.Collections.FieldsCol.add(field);
1484
  });
1485
 
1486
+ /*smuzform.App.Collections.FieldsCol.on( 'add', function( model ) {
1487
  $('html, body').animate({
1488
  scrollTop: $('#saveForm').offset().top - 200
1489
  }, 200);
1490
+ } );*/
1491
+
1492
 
1493
  }).always(function() {
1494
 
1523
 
1524
  $(document).ready(function(){$('.toplevel_page_smuz-forms-main').addClass('current');})
1525
 
1526
+
1527
+ $('#fields .field').not('.smuzlocked').draggable({
1528
+ cancel: false,
1529
+ revert: 'invalid',
1530
+ connectToSortable: '#formFieldsCont',
1531
+ helper: 'clone'
1532
+ });
1533
+
1534
+ $( '.likert' ).click( function(e) {
1535
+ //alert( 'The feature is in development.' );
1536
+ } );
1537
+
1538
  })(jQuery);
admin/views/tab-fields.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  <div class="fieldWrap">
6
 
7
- <button>Single Line Text</button>
8
 
9
  </div>
10
 
@@ -14,7 +14,7 @@
14
 
15
  <div class="fieldWrap">
16
 
17
- <button>Number</button>
18
 
19
  </div>
20
 
@@ -24,7 +24,7 @@
24
 
25
  <div class="fieldWrap">
26
 
27
- <button>Textarea</button>
28
 
29
  </div>
30
 
@@ -34,7 +34,7 @@
34
 
35
  <div class="fieldWrap">
36
 
37
- <button>Dropdown</button>
38
 
39
  </div>
40
 
@@ -44,7 +44,7 @@
44
 
45
  <div class="fieldWrap">
46
 
47
- <button>Radio Buttons</button>
48
 
49
  </div>
50
 
@@ -56,7 +56,7 @@
56
 
57
  <div class="fieldWrap">
58
 
59
- <button>Checkboxes</button>
60
 
61
  </div>
62
 
@@ -67,7 +67,7 @@
67
 
68
  <div class="fieldWrap">
69
 
70
- <button>Section Break</button>
71
 
72
  </div>
73
 
@@ -77,7 +77,7 @@
77
 
78
  <div class="fieldWrap">
79
 
80
- <button>Line Break</button>
81
 
82
  </div>
83
 
@@ -90,7 +90,7 @@
90
 
91
  <div class="fieldWrap">
92
 
93
- <button>File Upload</button>
94
 
95
  </div>
96
 
@@ -100,7 +100,7 @@
100
 
101
  <div class="fieldWrap">
102
 
103
- <button>Name</button>
104
 
105
  </div>
106
 
@@ -110,7 +110,7 @@
110
 
111
  <div class="fieldWrap">
112
 
113
- <button>Email</button>
114
 
115
  </div>
116
 
@@ -120,7 +120,7 @@
120
 
121
  <div class="fieldWrap">
122
 
123
- <button>Date</button>
124
 
125
  </div>
126
 
@@ -130,7 +130,7 @@
130
 
131
  <div class="fieldWrap">
132
 
133
- <button>Address</button>
134
 
135
  </div>
136
 
@@ -140,7 +140,7 @@
140
 
141
  <div class="fieldWrap">
142
 
143
- <button>Phone</button>
144
 
145
  </div>
146
 
@@ -150,17 +150,17 @@
150
 
151
  <div class="fieldWrap">
152
 
153
- <button>Website</button>
154
 
155
  </div>
156
 
157
  </li>
158
 
159
- <li class="field likert">
160
 
161
  <div class="fieldWrap">
162
 
163
- <button>Likert</button>
164
 
165
  </div>
166
 
@@ -170,17 +170,17 @@
170
 
171
  <div class="fieldWrap">
172
 
173
- <button>Page Break</button>
174
 
175
  </div>
176
 
177
  </li>
178
 
179
- <li class="field rating likert">
180
 
181
  <div class="fieldWrap">
182
 
183
- <button>Rating</button>
184
 
185
  </div>
186
 
@@ -192,7 +192,7 @@
192
 
193
  <div class="fieldWrap">
194
 
195
- <button>Text</button>
196
 
197
  </div>
198
 
@@ -202,13 +202,13 @@
202
 
203
  <div class="fieldWrap">
204
 
205
- <button>Image</button>
206
 
207
  </div>
208
 
209
  </li>
210
 
211
- <li class="field likert">
212
 
213
  <div class="fieldWrap">
214
 
@@ -222,7 +222,7 @@
222
 
223
  <div class="fieldWrap">
224
 
225
- <button>Custom HTML</button>
226
 
227
  </div>
228
 
4
 
5
  <div class="fieldWrap">
6
 
7
+ <button data-btntype="singleText" data-specialbtn="true">Single Line Text</button>
8
 
9
  </div>
10
 
14
 
15
  <div class="fieldWrap">
16
 
17
+ <button data-btntype="singleNumber" data-specialbtn="true">Number</button>
18
 
19
  </div>
20
 
24
 
25
  <div class="fieldWrap">
26
 
27
+ <button data-btntype="textarea" data-specialbtn="true">Textarea</button>
28
 
29
  </div>
30
 
34
 
35
  <div class="fieldWrap">
36
 
37
+ <button data-btntype="dropdown" data-specialbtn="true">Dropdown</button>
38
 
39
  </div>
40
 
44
 
45
  <div class="fieldWrap">
46
 
47
+ <button data-btntype="radioButtons" data-specialbtn="true">Radio Buttons</button>
48
 
49
  </div>
50
 
56
 
57
  <div class="fieldWrap">
58
 
59
+ <button data-btntype="checkboxes" data-specialbtn="true">Checkboxes</button>
60
 
61
  </div>
62
 
67
 
68
  <div class="fieldWrap">
69
 
70
+ <button data-btntype="sectionBreak" data-specialbtn="true">Section Break</button>
71
 
72
  </div>
73
 
77
 
78
  <div class="fieldWrap">
79
 
80
+ <button data-btntype="lineBreak" data-specialbtn="true">Line Break</button>
81
 
82
  </div>
83
 
90
 
91
  <div class="fieldWrap">
92
 
93
+ <button data-btntype="fileUpload" data-specialbtn="true">File Upload</button>
94
 
95
  </div>
96
 
100
 
101
  <div class="fieldWrap">
102
 
103
+ <button data-btntype="name" data-specialbtn="true">Name</button>
104
 
105
  </div>
106
 
110
 
111
  <div class="fieldWrap">
112
 
113
+ <button data-btntype="email" data-specialbtn="true">Email</button>
114
 
115
  </div>
116
 
120
 
121
  <div class="fieldWrap">
122
 
123
+ <button data-btntype="date" data-specialbtn="true">Date</button>
124
 
125
  </div>
126
 
130
 
131
  <div class="fieldWrap">
132
 
133
+ <button data-btntype="address" data-specialbtn="true">Address</button>
134
 
135
  </div>
136
 
140
 
141
  <div class="fieldWrap">
142
 
143
+ <button data-btntype="phone" data-specialbtn="true">Phone</button>
144
 
145
  </div>
146
 
150
 
151
  <div class="fieldWrap">
152
 
153
+ <button data-btntype="Website" data-specialbtn="true">Website</button>
154
 
155
  </div>
156
 
157
  </li>
158
 
159
+ <li class="field likert smuzlocked">
160
 
161
  <div class="fieldWrap">
162
 
163
+ <button data-btntype="likertScale" data-specialbtn="true">Likert</button>
164
 
165
  </div>
166
 
170
 
171
  <div class="fieldWrap">
172
 
173
+ <button data-btntype="pageBreak" data-specialbtn="true">Page Break</button>
174
 
175
  </div>
176
 
177
  </li>
178
 
179
+ <li class="field rating likert smuzlocked">
180
 
181
  <div class="fieldWrap">
182
 
183
+ <button data-btntype="rating" data-specialbtn="true">Rating</button>
184
 
185
  </div>
186
 
192
 
193
  <div class="fieldWrap">
194
 
195
+ <button data-btntype="customText" data-specialbtn="true">Text</button>
196
 
197
  </div>
198
 
202
 
203
  <div class="fieldWrap">
204
 
205
+ <button data-btntype="customImage" data-specialbtn="true">Image</button>
206
 
207
  </div>
208
 
209
  </li>
210
 
211
+ <li class="field likert smuzlocked">
212
 
213
  <div class="fieldWrap">
214
 
222
 
223
  <div class="fieldWrap">
224
 
225
+ <button data-btntype="customHtml" data-specialbtn="true">Custom HTML</button>
226
 
227
  </div>
228
 
forms.php CHANGED
@@ -5,7 +5,7 @@ Description: Most beautiful WordPress form builder plugin. A plugin you'll love
5
  Author: Web-Settler
6
  Author URI: http://web-settler.com/form-builder/
7
  Plugin URI: http://web-settler.com/form-builder/
8
- Version: 1.7
9
  License: GPL V2+
10
  **/
11
 
5
  Author: Web-Settler
6
  Author URI: http://web-settler.com/form-builder/
7
  Plugin URI: http://web-settler.com/form-builder/
8
+ Version: 1.8
9
  License: GPL V2+
10
  **/
11
 
readme.txt CHANGED
@@ -1,17 +1,19 @@
1
- === Contact Form ===
2
  Contributors: umarbajwa
3
  Requires at least: 3.7
4
- Tested up to: 4.7
5
- Tags: advanced form, best contact form plugin, contact bank, contact form, contact form builder, contact manager, contact us, contact us form, custom form, feedback form, forms, web form
6
- Stable tag: 1.7
7
  Donate Link: http://web-settler.com/form-builder/
8
  License: GPL V2 or latest
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
11
- Contact form saves your hours of precious time by making form creation process super simple and efficient.
12
 
13
  == Description ==
14
 
 
 
15
  Contact form plugin is easiest way to build any responsive form for your website. No fuss or messing with code create the form you want easily with simple drag & drop form builder.
16
 
17
  > <strong> Upgrade to Contact Form Premium </strong>
@@ -73,7 +75,7 @@ You can create any type of forms with contact form plugin it was built for multi
73
  * Ajax based contact forms.
74
  * Design your contact forms easily.
75
  * Customizable design.
76
-
77
 
78
  = <a href='http://web-settler.com/form-builder/' > Available AddOns </a> =
79
 
@@ -133,7 +135,9 @@ Contact form plugin give you the ability to add HTML elements like Images, Links
133
 
134
  We have designed the contact form UI easy and efficient so you can create your forms in minutes without wasting any time.
135
 
136
- = More Extensions (Coming Soon) =
 
 
137
 
138
  We are working hard to create more extensions for your contact form. If you have any suggestion feel free to send us.
139
 
@@ -221,6 +225,11 @@ A: Yes, You can edit your Contact Form entries from entry manager.
221
 
222
  == Changelog ==
223
 
 
 
 
 
 
224
  = 1.5 =
225
 
226
  * Notification email fixed
@@ -252,14 +261,19 @@ Contact form plugin give you the ability to apply conditional logic for your not
252
 
253
  == Upgrade Notice ==
254
 
 
 
 
 
 
255
  = 1.6 =
256
 
257
- * Notification email bug fixed
258
 
259
 
260
 
261
  = 1.2 =
262
- * Form Styler loaded with new features.
263
  * Plugin core changes.
264
  * AddOn added.
265
 
1
+ === Contact Form by WebS – responsive drag & drop contact form builder tool ===
2
  Contributors: umarbajwa
3
  Requires at least: 3.7
4
+ Tested up to: 4.7
5
+ Tags: contact form, contact me, custom form, form builder, forms, contact form builder, contact manager, contact us, contact us form, custom form, feedback form, forms, web form
6
+ Stable tag: 1.8
7
  Donate Link: http://web-settler.com/form-builder/
8
  License: GPL V2 or latest
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
11
+ Contact form saves your hours of precious time by making contact form creation process super simple and efficient.
12
 
13
  == Description ==
14
 
15
+ Create beautiful, responsive forms with a simple drag and drop form editor.
16
+
17
  Contact form plugin is easiest way to build any responsive form for your website. No fuss or messing with code create the form you want easily with simple drag & drop form builder.
18
 
19
  > <strong> Upgrade to Contact Form Premium </strong>
75
  * Ajax based contact forms.
76
  * Design your contact forms easily.
77
  * Customizable design.
78
+ * Contact form 7 like features
79
 
80
  = <a href='http://web-settler.com/form-builder/' > Available AddOns </a> =
81
 
135
 
136
  We have designed the contact form UI easy and efficient so you can create your forms in minutes without wasting any time.
137
 
138
+ Responsive and Customizable Contact Form. Add a beautiful background image and impress your customers with your contact form.
139
+
140
+ Contact form support all field types including the upload file. Redirect after the form submission or simply display a customizable message.
141
 
142
  We are working hard to create more extensions for your contact form. If you have any suggestion feel free to send us.
143
 
225
 
226
  == Changelog ==
227
 
228
+ = 1.8 =
229
+
230
+ * Added drag and drop in contact form editing panel.
231
+ * Bug Fixes.
232
+
233
  = 1.5 =
234
 
235
  * Notification email fixed
261
 
262
  == Upgrade Notice ==
263
 
264
+ = 1.8 =
265
+
266
+ * Added drag and drop in contact form editing panel.
267
+ * Bug Fixes.
268
+
269
  = 1.6 =
270
 
271
+ * Contact form Notification email bug fixed
272
 
273
 
274
 
275
  = 1.2 =
276
+ * Contact Form Styler loaded with new features.
277
  * Plugin core changes.
278
  * AddOn added.
279