populate-me 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE +20 -0
  5. data/README.md +655 -0
  6. data/Rakefile +14 -0
  7. data/example/config.ru +100 -0
  8. data/lib/populate_me.rb +2 -0
  9. data/lib/populate_me/admin.rb +157 -0
  10. data/lib/populate_me/admin/__assets__/css/asmselect.css +63 -0
  11. data/lib/populate_me/admin/__assets__/css/jquery-ui.min.css +6 -0
  12. data/lib/populate_me/admin/__assets__/css/main.css +244 -0
  13. data/lib/populate_me/admin/__assets__/img/help/children.png +0 -0
  14. data/lib/populate_me/admin/__assets__/img/help/create.png +0 -0
  15. data/lib/populate_me/admin/__assets__/img/help/delete.png +0 -0
  16. data/lib/populate_me/admin/__assets__/img/help/edit.png +0 -0
  17. data/lib/populate_me/admin/__assets__/img/help/form.png +0 -0
  18. data/lib/populate_me/admin/__assets__/img/help/list.png +0 -0
  19. data/lib/populate_me/admin/__assets__/img/help/login.png +0 -0
  20. data/lib/populate_me/admin/__assets__/img/help/logout.png +0 -0
  21. data/lib/populate_me/admin/__assets__/img/help/menu.png +0 -0
  22. data/lib/populate_me/admin/__assets__/img/help/overview.png +0 -0
  23. data/lib/populate_me/admin/__assets__/img/help/save.png +0 -0
  24. data/lib/populate_me/admin/__assets__/img/help/sort.png +0 -0
  25. data/lib/populate_me/admin/__assets__/img/help/sublist.png +0 -0
  26. data/lib/populate_me/admin/__assets__/js/asmselect.js +412 -0
  27. data/lib/populate_me/admin/__assets__/js/columnav.js +87 -0
  28. data/lib/populate_me/admin/__assets__/js/jquery-ui.min.js +7 -0
  29. data/lib/populate_me/admin/__assets__/js/main.js +388 -0
  30. data/lib/populate_me/admin/__assets__/js/mustache.js +578 -0
  31. data/lib/populate_me/admin/__assets__/js/sortable.js +2 -0
  32. data/lib/populate_me/admin/views/help.erb +94 -0
  33. data/lib/populate_me/admin/views/page.erb +189 -0
  34. data/lib/populate_me/api.rb +124 -0
  35. data/lib/populate_me/attachment.rb +186 -0
  36. data/lib/populate_me/document.rb +192 -0
  37. data/lib/populate_me/document_mixins/admin_adapter.rb +149 -0
  38. data/lib/populate_me/document_mixins/callbacks.rb +125 -0
  39. data/lib/populate_me/document_mixins/outcasting.rb +83 -0
  40. data/lib/populate_me/document_mixins/persistence.rb +95 -0
  41. data/lib/populate_me/document_mixins/schema.rb +198 -0
  42. data/lib/populate_me/document_mixins/typecasting.rb +70 -0
  43. data/lib/populate_me/document_mixins/validation.rb +44 -0
  44. data/lib/populate_me/file_system_attachment.rb +40 -0
  45. data/lib/populate_me/grid_fs_attachment.rb +103 -0
  46. data/lib/populate_me/mongo.rb +160 -0
  47. data/lib/populate_me/s3_attachment.rb +120 -0
  48. data/lib/populate_me/variation.rb +38 -0
  49. data/lib/populate_me/version.rb +4 -0
  50. data/populate-me.gemspec +34 -0
  51. data/test/helper.rb +37 -0
  52. data/test/test_admin.rb +183 -0
  53. data/test/test_api.rb +246 -0
  54. data/test/test_attachment.rb +167 -0
  55. data/test/test_document.rb +128 -0
  56. data/test/test_document_admin_adapter.rb +221 -0
  57. data/test/test_document_callbacks.rb +151 -0
  58. data/test/test_document_outcasting.rb +247 -0
  59. data/test/test_document_persistence.rb +83 -0
  60. data/test/test_document_schema.rb +280 -0
  61. data/test/test_document_typecasting.rb +128 -0
  62. data/test/test_grid_fs_attachment.rb +239 -0
  63. data/test/test_mongo.rb +324 -0
  64. data/test/test_s3_attachment.rb +281 -0
  65. data/test/test_variation.rb +91 -0
  66. data/test/test_version.rb +11 -0
  67. metadata +294 -0
@@ -0,0 +1,7 @@
1
+ /*! jQuery UI - v1.12.1 - 2018-02-23
2
+ * http://jqueryui.com
3
+ * Includes: widget.js, data.js, scroll-parent.js, widgets/sortable.js, widgets/mouse.js
4
+ * Copyright jQuery Foundation and other contributors; Licensed MIT */
5
+
6
+ (function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)})(function(t){t.ui=t.ui||{},t.ui.version="1.12.1";var e=0,i=Array.prototype.slice;t.cleanData=function(e){return function(i){var s,n,o;for(o=0;null!=(n=i[o]);o++)try{s=t._data(n,"events"),s&&s.remove&&t(n).triggerHandler("remove")}catch(a){}e(i)}}(t.cleanData),t.widget=function(e,i,s){var n,o,a,r={},l=e.split(".")[0];e=e.split(".")[1];var h=l+"-"+e;return s||(s=i,i=t.Widget),t.isArray(s)&&(s=t.extend.apply(null,[{}].concat(s))),t.expr[":"][h.toLowerCase()]=function(e){return!!t.data(e,h)},t[l]=t[l]||{},n=t[l][e],o=t[l][e]=function(t,e){return this._createWidget?(arguments.length&&this._createWidget(t,e),void 0):new o(t,e)},t.extend(o,n,{version:s.version,_proto:t.extend({},s),_childConstructors:[]}),a=new i,a.options=t.widget.extend({},a.options),t.each(s,function(e,s){return t.isFunction(s)?(r[e]=function(){function t(){return i.prototype[e].apply(this,arguments)}function n(t){return i.prototype[e].apply(this,t)}return function(){var e,i=this._super,o=this._superApply;return this._super=t,this._superApply=n,e=s.apply(this,arguments),this._super=i,this._superApply=o,e}}(),void 0):(r[e]=s,void 0)}),o.prototype=t.widget.extend(a,{widgetEventPrefix:n?a.widgetEventPrefix||e:e},r,{constructor:o,namespace:l,widgetName:e,widgetFullName:h}),n?(t.each(n._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete n._childConstructors):i._childConstructors.push(o),t.widget.bridge(e,o),o},t.widget.extend=function(e){for(var s,n,o=i.call(arguments,1),a=0,r=o.length;r>a;a++)for(s in o[a])n=o[a][s],o[a].hasOwnProperty(s)&&void 0!==n&&(e[s]=t.isPlainObject(n)?t.isPlainObject(e[s])?t.widget.extend({},e[s],n):t.widget.extend({},n):n);return e},t.widget.bridge=function(e,s){var n=s.prototype.widgetFullName||e;t.fn[e]=function(o){var a="string"==typeof o,r=i.call(arguments,1),l=this;return a?this.length||"instance"!==o?this.each(function(){var i,s=t.data(this,n);return"instance"===o?(l=s,!1):s?t.isFunction(s[o])&&"_"!==o.charAt(0)?(i=s[o].apply(s,r),i!==s&&void 0!==i?(l=i&&i.jquery?l.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+o+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+o+"'")}):l=void 0:(r.length&&(o=t.widget.extend.apply(null,[o].concat(r))),this.each(function(){var e=t.data(this,n);e?(e.option(o||{}),e._init&&e._init()):t.data(this,n,new s(o,this))})),l}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{classes:{},disabled:!1,create:null},_createWidget:function(i,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=e++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),this.classesElementLookup={},s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),i),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){var e=this;this._destroy(),t.each(this.classesElementLookup,function(t,i){e._removeClass(i,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,o,a=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(a={},s=e.split("."),e=s.shift(),s.length){for(n=a[e]=t.widget.extend({},this.options[e]),o=0;s.length-1>o;o++)n[s[o]]=n[s[o]]||{},n=n[s[o]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];a[e]=i}return this._setOptions(a),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(e){var i,s,n;for(i in e)n=this.classesElementLookup[i],e[i]!==this.options.classes[i]&&n&&n.length&&(s=t(n.get()),this._removeClass(n,i),s.addClass(this._classes({element:s,keys:i,classes:e,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(e){function i(i,o){var a,r;for(r=0;i.length>r;r++)a=n.classesElementLookup[i[r]]||t(),a=e.add?t(t.unique(a.get().concat(e.element.get()))):t(a.not(e.element).get()),n.classesElementLookup[i[r]]=a,s.push(i[r]),o&&e.classes[i[r]]&&s.push(e.classes[i[r]])}var s=[],n=this;return e=t.extend({element:this.element,classes:this.options.classes||{}},e),this._on(e.element,{remove:"_untrackClassesElement"}),e.keys&&i(e.keys.match(/\S+/g)||[],!0),e.extra&&i(e.extra.match(/\S+/g)||[]),s.join(" ")},_untrackClassesElement:function(e){var i=this;t.each(i.classesElementLookup,function(s,n){-1!==t.inArray(e.target,n)&&(i.classesElementLookup[s]=t(n.not(e.target).get()))})},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,s){s="boolean"==typeof s?s:i;var n="string"==typeof t||null===t,o={extra:n?e:i,keys:n?t:e,element:n?this.element:t,add:s};return o.element.toggleClass(this._classes(o),s),this},_on:function(e,i,s){var n,o=this;"boolean"!=typeof e&&(s=i,i=e,e=!1),s?(i=n=t(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),t.each(s,function(s,a){function r(){return e||o.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof a?o[a]:a).apply(o,arguments):void 0}"string"!=typeof a&&(r.guid=a.guid=a.guid||r.guid||t.guid++);var l=s.match(/^([\w:-]*)\s*(.*)$/),h=l[1]+o.eventNamespace,c=l[2];c?n.on(h,c,r):i.on(h,r)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.off(i).off(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){this._addClass(t(e.currentTarget),null,"ui-state-hover")},mouseleave:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){this._addClass(t(e.currentTarget),null,"ui-state-focus")},focusout:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}}),t.widget,t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])}}),t.fn.scrollParent=function(e){var i=this.css("position"),s="absolute"===i,n=e?/(auto|scroll|hidden)/:/(auto|scroll)/,o=this.parents().filter(function(){var e=t(this);return s&&"static"===e.css("position")?!1:n.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==i&&o.length?o:t(this[0].ownerDocument||document)},t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());var s=!1;t(document).on("mouseup",function(){s=!1}),t.widget("ui.mouse",{version:"1.12.1",options:{cancel:"input, textarea, button, select, option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.on("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).on("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.off("."+this.widgetName),this._mouseMoveDelegate&&this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!s){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,n=1===e.which,o="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return n&&!o&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.on("mousemove."+this.widgetName,this._mouseMoveDelegate).on("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),s=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)if(e.originalEvent.altKey||e.originalEvent.ctrlKey||e.originalEvent.metaKey||e.originalEvent.shiftKey)this.ignoreMissingWhich=!0;else if(!this.ignoreMissingWhich)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),this._mouseDelayTimer&&(clearTimeout(this._mouseDelayTimer),delete this._mouseDelayTimer),this.ignoreMissingWhich=!1,s=!1,e.preventDefault()},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),t.widget("ui.sortable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_isOverAxis:function(t,e,i){return t>=e&&e+i>t},_isFloating:function(t){return/left|right/.test(t.css("float"))||/inline|table-cell/.test(t.css("display"))},_create:function(){this.containerCache={},this._addClass("ui-sortable"),this.refresh(),this.offset=this.element.offset(),this._mouseInit(),this._setHandleClassName(),this.ready=!0},_setOption:function(t,e){this._super(t,e),"handle"===t&&this._setHandleClassName()},_setHandleClassName:function(){var e=this;this._removeClass(this.element.find(".ui-sortable-handle"),"ui-sortable-handle"),t.each(this.items,function(){e._addClass(this.instance.options.handle?this.item.find(this.instance.options.handle):this.item,"ui-sortable-handle")})},_destroy:function(){this._mouseDestroy();for(var t=this.items.length-1;t>=0;t--)this.items[t].item.removeData(this.widgetName+"-item");return this},_mouseCapture:function(e,i){var s=null,n=!1,o=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(e),t(e.target).parents().each(function(){return t.data(this,o.widgetName+"-item")===o?(s=t(this),!1):void 0}),t.data(e.target,o.widgetName+"-item")===o&&(s=t(e.target)),s?!this.options.handle||i||(t(this.options.handle,s).find("*").addBack().each(function(){this===e.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(e,i,s){var n,o,a=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(e),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,a.cursorAt&&this._adjustOffsetFromHelper(a.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),a.containment&&this._setContainment(),a.cursor&&"auto"!==a.cursor&&(o=this.document.find("body"),this.storedCursor=o.css("cursor"),o.css("cursor",a.cursor),this.storedStylesheet=t("<style>*{ cursor: "+a.cursor+" !important; }</style>").appendTo(o)),a.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",a.opacity)),a.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",a.zIndex)),this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this._addClass(this.helper,"ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,o,a=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY<a.scrollSensitivity?this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop+a.scrollSpeed:e.pageY-this.overflowOffset.top<a.scrollSensitivity&&(this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop-a.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-e.pageX<a.scrollSensitivity?this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft+a.scrollSpeed:e.pageX-this.overflowOffset.left<a.scrollSensitivity&&(this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft-a.scrollSpeed)):(e.pageY-this.document.scrollTop()<a.scrollSensitivity?r=this.document.scrollTop(this.document.scrollTop()-a.scrollSpeed):this.window.height()-(e.pageY-this.document.scrollTop())<a.scrollSensitivity&&(r=this.document.scrollTop(this.document.scrollTop()+a.scrollSpeed)),e.pageX-this.document.scrollLeft()<a.scrollSensitivity?r=this.document.scrollLeft(this.document.scrollLeft()-a.scrollSpeed):this.window.width()-(e.pageX-this.document.scrollLeft())<a.scrollSensitivity&&(r=this.document.scrollLeft(this.document.scrollLeft()+a.scrollSpeed))),r!==!1&&t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e)),this.positionAbs=this._convertPositionTo("absolute"),this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),i=this.items.length-1;i>=0;i--)if(s=this.items[i],n=s.item[0],o=this._intersectsWithPointer(s),o&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===o?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===o?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),o=this.options.axis,a={};o&&"x"!==o||(a.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollLeft)),o&&"y"!==o||(a.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(a,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp(new t.Event("mouseup",{target:null})),"original"===this.options.helper?(this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,o=t.left,a=o+t.width,r=t.top,l=r+t.height,h=this.offset.click.top,c=this.offset.click.left,u="x"===this.options.axis||s+h>r&&l>s+h,d="y"===this.options.axis||e+c>o&&a>e+c,p=u&&d;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?p:e+this.helperProportions.width/2>o&&a>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&l>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var e,i,s="x"===this.options.axis||this._isOverAxis(this.positionAbs.top+this.offset.click.top,t.top,t.height),n="y"===this.options.axis||this._isOverAxis(this.positionAbs.left+this.offset.click.left,t.left,t.width),o=s&&n;return o?(e=this._getDragVerticalDirection(),i=this._getDragHorizontalDirection(),this.floating?"right"===i||"down"===e?2:1:e&&("down"===e?2:1)):!1},_intersectsWithSides:function(t){var e=this._isOverAxis(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),i=this._isOverAxis(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),s=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return this.floating&&n?"right"===n&&i||"left"===n&&!i:s&&("down"===s&&e||"up"===s&&!e)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this._setHandleClassName(),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){function i(){r.push(this)}var s,n,o,a,r=[],l=[],h=this._connectWith();if(h&&e)for(s=h.length-1;s>=0;s--)for(o=t(h[s],this.document[0]),n=o.length-1;n>=0;n--)a=t.data(o[n],this.widgetFullName),a&&a!==this&&!a.options.disabled&&l.push([t.isFunction(a.options.items)?a.options.items.call(a.element):t(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a]);for(l.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=l.length-1;s>=0;s--)l[s][0].each(i);return t(r)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,o,a,r,l,h,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i],this.document[0]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&(u.push([t.isFunction(o.options.items)?o.options.items.call(o.element[0],e,{item:this.currentItem}):t(o.options.items,o.element),o]),this.containers.push(o));for(i=u.length-1;i>=0;i--)for(a=u[i][1],r=u[i][0],s=0,h=r.length;h>s;s++)l=t(r[s]),l.data(this.widgetName+"-item",a),c.push({item:l,instance:a,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.floating=this.items.length?"x"===this.options.axis||this._isFloating(this.items[0].item):!1,this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,o;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),o=n.offset(),s.left=o.left,s.top=o.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)o=this.containers[i].element.offset(),this.containers[i].containerCache.left=o.left,this.containers[i].containerCache.top=o.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t("<"+s+">",e.document[0]);return e._addClass(n,"ui-sortable-placeholder",i||e.currentItem[0].className)._removeClass(n,"ui-sortable-helper"),"tbody"===s?e._createTrPlaceholder(e.currentItem.find("tr").eq(0),t("<tr>",e.document[0]).appendTo(n)):"tr"===s?e._createTrPlaceholder(e.currentItem,n):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_createTrPlaceholder:function(e,i){var s=this;e.children().each(function(){t("<td>&#160;</td>",s.document[0]).attr("colspan",t(this).attr("colspan")||1).appendTo(i)})},_contactContainers:function(e){var i,s,n,o,a,r,l,h,c,u,d=null,p=null;for(i=this.containers.length-1;i>=0;i--)if(!t.contains(this.currentItem[0],this.containers[i].element[0]))if(this._intersectsWith(this.containers[i].containerCache)){if(d&&t.contains(this.containers[i].element[0],d.element[0]))continue;d=this.containers[i],p=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",e,this._uiHash(this)),this.containers[i].containerCache.over=0);if(d)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",e,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(n=1e4,o=null,c=d.floating||this._isFloating(this.currentItem),a=c?"left":"top",r=c?"width":"height",u=c?"pageX":"pageY",s=this.items.length-1;s>=0;s--)t.contains(this.containers[p].element[0],this.items[s].item[0])&&this.items[s].item[0]!==this.currentItem[0]&&(l=this.items[s].item.offset()[a],h=!1,e[u]-l>this.items[s][r]/2&&(h=!0),n>Math.abs(e[u]-l)&&(n=Math.abs(e[u]-l),o=this.items[s],this.direction=h?"up":"down"));if(!o&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[p])return this.currentContainer.containerCache.over||(this.containers[p]._trigger("over",e,this._uiHash()),this.currentContainer.containerCache.over=1),void 0;o?this._rearrange(e,o,null,!0):this._rearrange(e,null,this.containers[p].element,!0),this._trigger("change",e,this._uiHash()),this.containers[p]._trigger("change",e,this._uiHash(this)),this.currentContainer=this.containers[p],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[p]._trigger("over",e,this._uiHash(this)),this.containers[p].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===this.document[0].body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,"document"===n.containment?this.document.width():this.window.width()-this.helperProportions.width-this.margins.left,("document"===n.containment?this.document.height()||document.body.parentNode.scrollHeight:this.window.height()||this.document[0].body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s}
7
+ },_generatePosition:function(e){var i,s,n=this.options,o=e.pageX,a=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,l=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.left<this.containment[0]&&(o=this.containment[0]+this.offset.click.left),e.pageY-this.offset.click.top<this.containment[1]&&(a=this.containment[1]+this.offset.click.top),e.pageX-this.offset.click.left>this.containment[2]&&(o=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(a=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((a-this.originalPageY)/n.grid[1])*n.grid[1],a=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((o-this.originalPageX)/n.grid[0])*n.grid[0],o=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:a-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():l?0:r.scrollTop()),left:o-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():l?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){function i(t,e,i){return function(s){i._trigger(t,s,e._uiHash(e))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&n.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||n.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(n.push(function(t){this._trigger("remove",t,this._uiHash())}),n.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)e||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!e){for(s=0;n.length>s;s++)n[s].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!this.cancelHelperRemoval},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}})});
@@ -0,0 +1,388 @@
1
+ // Namespace
2
+ var PopulateMe = {};
3
+
4
+ // Returns a Mustache template from either
5
+ // the dom element itself, or the id of the dom element.
6
+ PopulateMe.init_template = function(obj_or_id) {
7
+ var obj = (typeof obj_or_id == 'object') ? obj_or_id : $(obj_or_id);
8
+ var template = obj.html();
9
+ Mustache.parse(template);
10
+ return template;
11
+ };
12
+
13
+ // Output a legible version of the size in bytes.
14
+ // 1024 => "1KB"
15
+ // 2097152 => "2MB"
16
+ PopulateMe.display_file_size = function(size) {
17
+ var unit = 'B';
18
+ if (size>1024) {
19
+ size = size / 1024;
20
+ unit = 'KB';
21
+ }
22
+ if (size>1024) {
23
+ size = size / 1024;
24
+ unit = 'MB';
25
+ }
26
+ if (size>1024) {
27
+ size = size / 1024;
28
+ unit = 'GB';
29
+ }
30
+ return size+unit;
31
+ };
32
+
33
+ // Add or update query string parameter on a URI
34
+ PopulateMe.update_query_parameter = function(uri, key, value) {
35
+ var sane_key = key.replace(/[\[\]]/g, "\\$&");
36
+ var re = new RegExp("([?&])" + sane_key + "=.*?(&|$)", "i");
37
+ var separator = uri.indexOf('?') !== -1 ? "&" : "?";
38
+ if (uri.match(re)) {
39
+ return uri.replace(re, '$1' + key + "=" + encodeURIComponent(value) + '$2');
40
+ }
41
+ else {
42
+ return uri + separator + key + "=" + encodeURIComponent(value);
43
+ }
44
+ };
45
+
46
+ // Template helpers
47
+ PopulateMe.template_helpers = {
48
+ custom_partial_or_default: function() {
49
+ return function(text,render) {
50
+ return render('{{>'+(this.custom_template||text)+'}}');
51
+ }
52
+ },
53
+ adapted_field: function() {
54
+ return function(text,render) {
55
+ var tmpl;
56
+ if (this.custom_template) {
57
+ tmpl = this.custom_template;
58
+ } else {
59
+ tmpl = 'template_'+this.type+'_field';
60
+ if (!(tmpl in PopulateMe.templates)) tmpl = 'template_string_field';
61
+ }
62
+ return render('{{>'+tmpl+'}}');
63
+ }
64
+ },
65
+ build_input_attributes: function() {
66
+ var out = "";
67
+ $.each(this.input_attributes, function(k,v) {
68
+ if (v!==false) {
69
+ out = out+' '+k;
70
+ if (v!==true) out = out+'=\''+Mustache.escape(v)+'\'';
71
+ }
72
+ });
73
+ return out;
74
+ },
75
+ cache_buster: function() {
76
+ // Simple version which assumes the url has no query yet or hash
77
+ var buster = Math.random()*10000000000000000;
78
+ return '?cache_buster='+buster;
79
+ }
80
+ };
81
+
82
+ // Template render with helpers
83
+ PopulateMe.mustache_render = function(data) {
84
+ var data_and_helpers = $.extend(data,PopulateMe.template_helpers);
85
+ return Mustache.render(PopulateMe.templates[data.template],data_and_helpers,PopulateMe.templates);
86
+ };
87
+
88
+ // Make Sortable from element or css selector
89
+ PopulateMe.make_sortable = function(selector,context) {
90
+ var obj = (typeof selector == 'string') ? $(selector,context) : selector;
91
+ return obj.sortable({
92
+ forcePlaceholderSize: true,
93
+ handle: '.handle'
94
+ });
95
+ };
96
+
97
+ // Scroll to an element, possibly in a specific column.
98
+ PopulateMe.scroll_to = function(el, column) {
99
+ if (!column) {
100
+ column = el.closest('.column');
101
+ }
102
+ column.animate({scrollTop: el.position().top});
103
+ };
104
+
105
+ // Mark errors for report after form validation.
106
+ // It adds the .invalid class to invalid fields,
107
+ // and adds the report after the label of the field.
108
+ PopulateMe.mark_errors = function(context,report) {
109
+ $.each(report,function(k,v) {
110
+ var field = context.find('> [data-field-name='+k+']:first');
111
+ if (field.is('fieldset')) {
112
+ $.each(v, function(index,subreport) {
113
+ var subcontext = field.find('> .nested-documents > li:nth('+index+')');
114
+ PopulateMe.mark_errors(subcontext, subreport);
115
+ });
116
+ } else {
117
+ field.addClass('invalid');
118
+ var errors = "<span class='errors'>, "+v.join(', ')+"</span>";
119
+ field.find('> label').append(errors);
120
+ }
121
+ });
122
+ };
123
+
124
+ // JS Validations
125
+ // This adds validations that could happen before sending
126
+ // anything to the server and that cannot be done with
127
+ // browser form validations like "required".
128
+ // For example we can check the file size so that files are not sent
129
+ // to the server at all if they are too big.
130
+ // Returns a boolean.
131
+ PopulateMe.jsValidationsPassed = function(context) {
132
+ if (window.File && window.FileReader && window.FileList && window.Blob) {
133
+ try {
134
+ var max_size_fields = $('input[type=file][data-max-size]', context);
135
+ max_size_fields.each(function() {
136
+ var field = $(this);
137
+ var max_size = parseInt(field.data('max-size'));
138
+ if (field[0].files[0]) {
139
+ var fsize = field[0].files[0].size;
140
+ var fname = field[0].files[0].name;
141
+ if (fsize>max_size) {
142
+ alert('File too big: '+fname+' should be less than '+PopulateMe.display_file_size(max_size)+'.');
143
+ throw "Validation error";
144
+ }
145
+ }
146
+ });
147
+ } catch(e) {
148
+ if (e==='Validation error') {
149
+ return false;
150
+ } else {
151
+ throw(e);
152
+ }
153
+ }
154
+ }
155
+ return true;
156
+ };
157
+
158
+ // Init column
159
+ // Bind events and init things that need to happen when
160
+ // a new column is added to the finder.
161
+ // The callback `custom_init_column` is also called at the end
162
+ // in case you have things to put in your custom javascript.
163
+ PopulateMe.init_column = function(c) {
164
+
165
+ // Sort list item
166
+ PopulateMe.make_sortable('.documents',c).bind('sortupdate', function(e, ui) {
167
+ var list = $(ui.item).closest('.documents');
168
+ var ids = list.children().map(function() {
169
+ return $(this).data().id;
170
+ }).get();
171
+ $.ajax({
172
+ url: list.data().sortUrl,
173
+ type: 'put',
174
+ data: {
175
+ action: 'sort',
176
+ field: list.data().sortField,
177
+ ids: ids
178
+ }
179
+ });
180
+ /*
181
+ ui.item contains the current dragged element.
182
+ ui.item.index() contains the new index of the dragged element
183
+ ui.oldindex contains the old index of the dragged element
184
+ ui.startparent contains the element that the dragged item comes from
185
+ ui.endparent contains the element that the dragged item was added to
186
+ */
187
+ });
188
+
189
+ // Sort nested documents
190
+ PopulateMe.make_sortable('.nested-documents',c);
191
+
192
+ // Init textareas
193
+ $('textarea',c).trigger('input');
194
+
195
+ // Init multiple select with asmSelect
196
+ $('select[multiple]', c).asmSelect({ sortable: true, removeLabel: '&times;' });
197
+
198
+ // Select with preview
199
+ $('select:not([multiple])', c).change(function() {
200
+ var $this = $(this);
201
+ var container;
202
+ if ($this.data('preview-container')) {
203
+ container = $($this.data('preview-container'), c);
204
+ } else {
205
+ container = $this.next('.preview-container');
206
+ }
207
+ if (container.size() == 0) return;
208
+ var path = $this.find(':selected:first').data('preview');
209
+ if (path) {
210
+ var img = container.find('img:first');
211
+ if (img.size() < 1) {
212
+ img = $("<img src='' alt='Preview' title='Preview' width='250' />");
213
+ container.html(img);
214
+ }
215
+ img.attr('src', path);
216
+ } else {
217
+ container.html('');
218
+ }
219
+ });
220
+ $('option:selected[data-preview]').parent().change();
221
+
222
+ // Polymorphic selector
223
+ $('select.polymorphic_type_values').change(function() {
224
+ var $this = $(this);
225
+ var link = $this.next();
226
+ link.attr('href', PopulateMe.update_query_parameter(link.attr('href'), 'data[polymorphic_type]', $this.val()));
227
+ }).change();
228
+
229
+ // Warning when date input not supported
230
+ var dateFields = $('[type="date"]', c);
231
+ if ( dateFields.size()>0 && dateFields.prop('type') != 'date' ) {
232
+ alert('Your browser does not support date fields. You will have to enter dates manually. If you want a better experience and have a date picker, use a modern browser like Chrome.');
233
+ }
234
+
235
+ // Possible callback from custom javascript file.
236
+ // If you need to do something on init_column,
237
+ // create this callback.
238
+ if (PopulateMe.custom_init_column) {
239
+ PopulateMe.custom_init_column(c);
240
+ }
241
+
242
+ }; // End - Init column
243
+
244
+
245
+
246
+ // Dom ready
247
+ $(function() {
248
+
249
+ // Dom elements.
250
+ PopulateMe.finder = $('#finder');
251
+
252
+ // Init templates
253
+ PopulateMe.templates = {};
254
+ $('[type=x-tmpl-mustache]').each(function() {
255
+ var $this = $(this);
256
+ PopulateMe.templates[$this.attr('id').replace(/-/g,'_')] = PopulateMe.init_template($this);
257
+ });
258
+
259
+ // Reactive text area
260
+ // It switches between online or longer depending on the amount
261
+ // of text.
262
+ // Long term, for this reason, it might be used for both
263
+ // :string and :text fields.
264
+ $('body').on('input propertychange', 'textarea', function() {
265
+ if (this.value.length>50 || this.value.match(/\n/)) {
266
+ $(this).removeClass('oneline');
267
+ } else {
268
+ $(this).addClass('oneline');
269
+ }
270
+ });
271
+
272
+ // Ajax form
273
+ $('body').on('submit','form.admin-post, form.admin-put', function(e) {
274
+ e.preventDefault();
275
+ var self = $(this);
276
+ if (PopulateMe.jsValidationsPassed(self)) {
277
+
278
+ var submit_button = $('input[type=submit]',self);
279
+ submit_button.hide();
280
+ $.ajax({
281
+ url: self.attr('action'),
282
+ type: (self.is('.admin-put') ? 'put' : 'post'),
283
+ data: new FormData(this),
284
+ processData: false,
285
+ contentType: false,
286
+ success: function(res) {
287
+ if (res.success==true) {
288
+ var reloader = PopulateMe.finder.find('> li:nth-last-child(3) .selected')
289
+ if (reloader.size()>0) {
290
+ reloader.trigger('click.columnav',[function(cb_object) {
291
+ var target = $('[data-id='+res.data.id+']', cb_object.column);
292
+ if (target.size()>0) {
293
+ PopulateMe.scroll_to(target, cb_object.column);
294
+ }
295
+ }]);
296
+ } else {
297
+ PopulateMe.finder.trigger('pop.columnav');
298
+ }
299
+ }
300
+ },
301
+ error: function(xhr) {
302
+ res = xhr.responseJSON;
303
+ if (res.success==false) {
304
+ $('.invalid',self).removeClass('invalid');
305
+ $('.errors',self).remove();
306
+ PopulateMe.mark_errors(self,res.data);
307
+ PopulateMe.scroll_to(self.find('.invalid:first'));
308
+ submit_button.show();
309
+ }
310
+ }
311
+ });
312
+
313
+ }
314
+ });
315
+
316
+ // Create nested document
317
+ $('body').on('click','.new-nested-document-btn', function(e) {
318
+ e.preventDefault();
319
+ var self = $(this);
320
+ $.get(this.href, function(data) {
321
+ var content = $(PopulateMe.mustache_render(data));
322
+ PopulateMe.make_sortable(self.closest('fieldset').find('> ol').append(content).sortable('destroy'));
323
+ PopulateMe.scroll_to(content);
324
+ });
325
+ });
326
+
327
+ // Ajax delete document
328
+ $('body').on('click', 'button.admin-delete', function(e) {
329
+ e.preventDefault();
330
+ var self = $(this);
331
+ if (confirm('Are you sure you want to delete this item? This operation is not reversible.')) {
332
+ $.ajax({
333
+ url: self.val(),
334
+ type: 'DELETE',
335
+ success: function() {
336
+ var li = self.parents('li.admin-list-item');
337
+ li.fadeOut(function() {
338
+ li.remove();
339
+ });
340
+ }
341
+ });
342
+ }
343
+ });
344
+
345
+ // Ajax delete nested document
346
+ $('body').on('click', 'button.admin-delete-nested', function(e) {
347
+ e.preventDefault();
348
+ var self = $(this);
349
+ if (confirm('Are you sure you want to delete this item? This operation is not reversible.')) {
350
+ var li = self.closest('li');
351
+ li.fadeOut(function() {
352
+ li.remove();
353
+ });
354
+ }
355
+ });
356
+
357
+ // Attachment deleter
358
+ $('body').on('click', 'button.attachment-deleter', function(e) {
359
+ e.preventDefault();
360
+ var self = $(this);
361
+ var input = self.parent().find('input');
362
+ if (input.attr('type')=='file') {
363
+ alert('The attachment will be deleted when you save the document.');
364
+ input.attr('type','hidden').val('');
365
+ self.text('Cancel attachment deletion');
366
+ } else {
367
+ input.attr('type','file');
368
+ self.text('x');
369
+ }
370
+ });
371
+
372
+ // Init finder
373
+ PopulateMe.finder.columnav({
374
+ on_push: function(data) {
375
+ PopulateMe.init_column(data.column);
376
+ },
377
+ process_data: function(data) {
378
+ if (typeof data == 'object') {
379
+ return PopulateMe.mustache_render(data);
380
+ } else {
381
+ return data;
382
+ }
383
+ }
384
+ });
385
+ PopulateMe.finder.trigger('getandpush.columnav',[window.admin_path+window.index_path]);
386
+
387
+ }); // End - DomReady
388
+
@@ -0,0 +1,578 @@
1
+ /*!
2
+ * mustache.js - Logic-less {{mustache}} templates with JavaScript
3
+ * http://github.com/janl/mustache.js
4
+ */
5
+
6
+ /*global define: false*/
7
+
8
+ (function (global, factory) {
9
+ if (typeof exports === "object" && exports) {
10
+ factory(exports); // CommonJS
11
+ } else if (typeof define === "function" && define.amd) {
12
+ define(['exports'], factory); // AMD
13
+ } else {
14
+ factory(global.Mustache = {}); // <script>
15
+ }
16
+ }(this, function (mustache) {
17
+
18
+ var Object_toString = Object.prototype.toString;
19
+ var isArray = Array.isArray || function (object) {
20
+ return Object_toString.call(object) === '[object Array]';
21
+ };
22
+
23
+ function isFunction(object) {
24
+ return typeof object === 'function';
25
+ }
26
+
27
+ function escapeRegExp(string) {
28
+ return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
29
+ }
30
+
31
+ // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
32
+ // See https://github.com/janl/mustache.js/issues/189
33
+ var RegExp_test = RegExp.prototype.test;
34
+ function testRegExp(re, string) {
35
+ return RegExp_test.call(re, string);
36
+ }
37
+
38
+ var nonSpaceRe = /\S/;
39
+ function isWhitespace(string) {
40
+ return !testRegExp(nonSpaceRe, string);
41
+ }
42
+
43
+ var entityMap = {
44
+ "&": "&amp;",
45
+ "<": "&lt;",
46
+ ">": "&gt;",
47
+ '"': '&quot;',
48
+ "'": '&#39;',
49
+ "/": '&#x2F;'
50
+ };
51
+
52
+ function escapeHtml(string) {
53
+ return String(string).replace(/[&<>"'\/]/g, function (s) {
54
+ return entityMap[s];
55
+ });
56
+ }
57
+
58
+ var whiteRe = /\s*/;
59
+ var spaceRe = /\s+/;
60
+ var equalsRe = /\s*=/;
61
+ var curlyRe = /\s*\}/;
62
+ var tagRe = /#|\^|\/|>|\{|&|=|!/;
63
+
64
+ /**
65
+ * Breaks up the given `template` string into a tree of tokens. If the `tags`
66
+ * argument is given here it must be an array with two string values: the
67
+ * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of
68
+ * course, the default is to use mustaches (i.e. mustache.tags).
69
+ *
70
+ * A token is an array with at least 4 elements. The first element is the
71
+ * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag
72
+ * did not contain a symbol (i.e. {{myValue}}) this element is "name". For
73
+ * all text that appears outside a symbol this element is "text".
74
+ *
75
+ * The second element of a token is its "value". For mustache tags this is
76
+ * whatever else was inside the tag besides the opening symbol. For text tokens
77
+ * this is the text itself.
78
+ *
79
+ * The third and fourth elements of the token are the start and end indices,
80
+ * respectively, of the token in the original template.
81
+ *
82
+ * Tokens that are the root node of a subtree contain two more elements: 1) an
83
+ * array of tokens in the subtree and 2) the index in the original template at
84
+ * which the closing tag for that section begins.
85
+ */
86
+ function parseTemplate(template, tags) {
87
+ if (!template)
88
+ return [];
89
+
90
+ var sections = []; // Stack to hold section tokens
91
+ var tokens = []; // Buffer to hold the tokens
92
+ var spaces = []; // Indices of whitespace tokens on the current line
93
+ var hasTag = false; // Is there a {{tag}} on the current line?
94
+ var nonSpace = false; // Is there a non-space char on the current line?
95
+
96
+ // Strips all whitespace tokens array for the current line
97
+ // if there was a {{#tag}} on it and otherwise only space.
98
+ function stripSpace() {
99
+ if (hasTag && !nonSpace) {
100
+ while (spaces.length)
101
+ delete tokens[spaces.pop()];
102
+ } else {
103
+ spaces = [];
104
+ }
105
+
106
+ hasTag = false;
107
+ nonSpace = false;
108
+ }
109
+
110
+ var openingTagRe, closingTagRe, closingCurlyRe;
111
+ function compileTags(tags) {
112
+ if (typeof tags === 'string')
113
+ tags = tags.split(spaceRe, 2);
114
+
115
+ if (!isArray(tags) || tags.length !== 2)
116
+ throw new Error('Invalid tags: ' + tags);
117
+
118
+ openingTagRe = new RegExp(escapeRegExp(tags[0]) + '\\s*');
119
+ closingTagRe = new RegExp('\\s*' + escapeRegExp(tags[1]));
120
+ closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tags[1]));
121
+ }
122
+
123
+ compileTags(tags || mustache.tags);
124
+
125
+ var scanner = new Scanner(template);
126
+
127
+ var start, type, value, chr, token, openSection;
128
+ while (!scanner.eos()) {
129
+ start = scanner.pos;
130
+
131
+ // Match any text between tags.
132
+ value = scanner.scanUntil(openingTagRe);
133
+
134
+ if (value) {
135
+ for (var i = 0, valueLength = value.length; i < valueLength; ++i) {
136
+ chr = value.charAt(i);
137
+
138
+ if (isWhitespace(chr)) {
139
+ spaces.push(tokens.length);
140
+ } else {
141
+ nonSpace = true;
142
+ }
143
+
144
+ tokens.push([ 'text', chr, start, start + 1 ]);
145
+ start += 1;
146
+
147
+ // Check for whitespace on the current line.
148
+ if (chr === '\n')
149
+ stripSpace();
150
+ }
151
+ }
152
+
153
+ // Match the opening tag.
154
+ if (!scanner.scan(openingTagRe))
155
+ break;
156
+
157
+ hasTag = true;
158
+
159
+ // Get the tag type.
160
+ type = scanner.scan(tagRe) || 'name';
161
+ scanner.scan(whiteRe);
162
+
163
+ // Get the tag value.
164
+ if (type === '=') {
165
+ value = scanner.scanUntil(equalsRe);
166
+ scanner.scan(equalsRe);
167
+ scanner.scanUntil(closingTagRe);
168
+ } else if (type === '{') {
169
+ value = scanner.scanUntil(closingCurlyRe);
170
+ scanner.scan(curlyRe);
171
+ scanner.scanUntil(closingTagRe);
172
+ type = '&';
173
+ } else {
174
+ value = scanner.scanUntil(closingTagRe);
175
+ }
176
+
177
+ // Match the closing tag.
178
+ if (!scanner.scan(closingTagRe))
179
+ throw new Error('Unclosed tag at ' + scanner.pos);
180
+
181
+ token = [ type, value, start, scanner.pos ];
182
+ tokens.push(token);
183
+
184
+ if (type === '#' || type === '^') {
185
+ sections.push(token);
186
+ } else if (type === '/') {
187
+ // Check section nesting.
188
+ openSection = sections.pop();
189
+
190
+ if (!openSection)
191
+ throw new Error('Unopened section "' + value + '" at ' + start);
192
+
193
+ if (openSection[1] !== value)
194
+ throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
195
+ } else if (type === 'name' || type === '{' || type === '&') {
196
+ nonSpace = true;
197
+ } else if (type === '=') {
198
+ // Set the tags for the next time around.
199
+ compileTags(value);
200
+ }
201
+ }
202
+
203
+ // Make sure there are no open sections when we're done.
204
+ openSection = sections.pop();
205
+
206
+ if (openSection)
207
+ throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
208
+
209
+ return nestTokens(squashTokens(tokens));
210
+ }
211
+
212
+ /**
213
+ * Combines the values of consecutive text tokens in the given `tokens` array
214
+ * to a single token.
215
+ */
216
+ function squashTokens(tokens) {
217
+ var squashedTokens = [];
218
+
219
+ var token, lastToken;
220
+ for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
221
+ token = tokens[i];
222
+
223
+ if (token) {
224
+ if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {
225
+ lastToken[1] += token[1];
226
+ lastToken[3] = token[3];
227
+ } else {
228
+ squashedTokens.push(token);
229
+ lastToken = token;
230
+ }
231
+ }
232
+ }
233
+
234
+ return squashedTokens;
235
+ }
236
+
237
+ /**
238
+ * Forms the given array of `tokens` into a nested tree structure where
239
+ * tokens that represent a section have two additional items: 1) an array of
240
+ * all tokens that appear in that section and 2) the index in the original
241
+ * template that represents the end of that section.
242
+ */
243
+ function nestTokens(tokens) {
244
+ var nestedTokens = [];
245
+ var collector = nestedTokens;
246
+ var sections = [];
247
+
248
+ var token, section;
249
+ for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
250
+ token = tokens[i];
251
+
252
+ switch (token[0]) {
253
+ case '#':
254
+ case '^':
255
+ collector.push(token);
256
+ sections.push(token);
257
+ collector = token[4] = [];
258
+ break;
259
+ case '/':
260
+ section = sections.pop();
261
+ section[5] = token[2];
262
+ collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
263
+ break;
264
+ default:
265
+ collector.push(token);
266
+ }
267
+ }
268
+
269
+ return nestedTokens;
270
+ }
271
+
272
+ /**
273
+ * A simple string scanner that is used by the template parser to find
274
+ * tokens in template strings.
275
+ */
276
+ function Scanner(string) {
277
+ this.string = string;
278
+ this.tail = string;
279
+ this.pos = 0;
280
+ }
281
+
282
+ /**
283
+ * Returns `true` if the tail is empty (end of string).
284
+ */
285
+ Scanner.prototype.eos = function () {
286
+ return this.tail === "";
287
+ };
288
+
289
+ /**
290
+ * Tries to match the given regular expression at the current position.
291
+ * Returns the matched text if it can match, the empty string otherwise.
292
+ */
293
+ Scanner.prototype.scan = function (re) {
294
+ var match = this.tail.match(re);
295
+
296
+ if (!match || match.index !== 0)
297
+ return '';
298
+
299
+ var string = match[0];
300
+
301
+ this.tail = this.tail.substring(string.length);
302
+ this.pos += string.length;
303
+
304
+ return string;
305
+ };
306
+
307
+ /**
308
+ * Skips all text until the given regular expression can be matched. Returns
309
+ * the skipped string, which is the entire tail if no match can be made.
310
+ */
311
+ Scanner.prototype.scanUntil = function (re) {
312
+ var index = this.tail.search(re), match;
313
+
314
+ switch (index) {
315
+ case -1:
316
+ match = this.tail;
317
+ this.tail = "";
318
+ break;
319
+ case 0:
320
+ match = "";
321
+ break;
322
+ default:
323
+ match = this.tail.substring(0, index);
324
+ this.tail = this.tail.substring(index);
325
+ }
326
+
327
+ this.pos += match.length;
328
+
329
+ return match;
330
+ };
331
+
332
+ /**
333
+ * Represents a rendering context by wrapping a view object and
334
+ * maintaining a reference to the parent context.
335
+ */
336
+ function Context(view, parentContext) {
337
+ this.view = view == null ? {} : view;
338
+ this.cache = { '.': this.view };
339
+ this.parent = parentContext;
340
+ }
341
+
342
+ /**
343
+ * Creates a new context using the given view with this context
344
+ * as the parent.
345
+ */
346
+ Context.prototype.push = function (view) {
347
+ return new Context(view, this);
348
+ };
349
+
350
+ /**
351
+ * Returns the value of the given name in this context, traversing
352
+ * up the context hierarchy if the value is absent in this context's view.
353
+ */
354
+ Context.prototype.lookup = function (name) {
355
+ var cache = this.cache;
356
+
357
+ var value;
358
+ if (name in cache) {
359
+ value = cache[name];
360
+ } else {
361
+ var context = this, names, index;
362
+
363
+ while (context) {
364
+ if (name.indexOf('.') > 0) {
365
+ value = context.view;
366
+ names = name.split('.');
367
+ index = 0;
368
+
369
+ while (value != null && index < names.length)
370
+ value = value[names[index++]];
371
+ } else {
372
+ value = context.view[name];
373
+ }
374
+
375
+ if (value != null)
376
+ break;
377
+
378
+ context = context.parent;
379
+ }
380
+
381
+ cache[name] = value;
382
+ }
383
+
384
+ if (isFunction(value))
385
+ value = value.call(this.view);
386
+
387
+ return value;
388
+ };
389
+
390
+ /**
391
+ * A Writer knows how to take a stream of tokens and render them to a
392
+ * string, given a context. It also maintains a cache of templates to
393
+ * avoid the need to parse the same template twice.
394
+ */
395
+ function Writer() {
396
+ this.cache = {};
397
+ }
398
+
399
+ /**
400
+ * Clears all cached templates in this writer.
401
+ */
402
+ Writer.prototype.clearCache = function () {
403
+ this.cache = {};
404
+ };
405
+
406
+ /**
407
+ * Parses and caches the given `template` and returns the array of tokens
408
+ * that is generated from the parse.
409
+ */
410
+ Writer.prototype.parse = function (template, tags) {
411
+ var cache = this.cache;
412
+ var tokens = cache[template];
413
+
414
+ if (tokens == null)
415
+ tokens = cache[template] = parseTemplate(template, tags);
416
+
417
+ return tokens;
418
+ };
419
+
420
+ /**
421
+ * High-level method that is used to render the given `template` with
422
+ * the given `view`.
423
+ *
424
+ * The optional `partials` argument may be an object that contains the
425
+ * names and templates of partials that are used in the template. It may
426
+ * also be a function that is used to load partial templates on the fly
427
+ * that takes a single argument: the name of the partial.
428
+ */
429
+ Writer.prototype.render = function (template, view, partials) {
430
+ var tokens = this.parse(template);
431
+ var context = (view instanceof Context) ? view : new Context(view);
432
+ return this.renderTokens(tokens, context, partials, template);
433
+ };
434
+
435
+ /**
436
+ * Low-level method that renders the given array of `tokens` using
437
+ * the given `context` and `partials`.
438
+ *
439
+ * Note: The `originalTemplate` is only ever used to extract the portion
440
+ * of the original template that was contained in a higher-order section.
441
+ * If the template doesn't use higher-order sections, this argument may
442
+ * be omitted.
443
+ */
444
+ Writer.prototype.renderTokens = function (tokens, context, partials, originalTemplate) {
445
+ var buffer = '';
446
+
447
+ // This function is used to render an arbitrary template
448
+ // in the current context by higher-order sections.
449
+ var self = this;
450
+ function subRender(template) {
451
+ return self.render(template, context, partials);
452
+ }
453
+
454
+ var token, value;
455
+ for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
456
+ token = tokens[i];
457
+
458
+ switch (token[0]) {
459
+ case '#':
460
+ value = context.lookup(token[1]);
461
+
462
+ if (!value)
463
+ continue;
464
+
465
+ if (isArray(value)) {
466
+ for (var j = 0, valueLength = value.length; j < valueLength; ++j) {
467
+ buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate);
468
+ }
469
+ } else if (typeof value === 'object' || typeof value === 'string') {
470
+ buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate);
471
+ } else if (isFunction(value)) {
472
+ if (typeof originalTemplate !== 'string')
473
+ throw new Error('Cannot use higher-order sections without the original template');
474
+
475
+ // Extract the portion of the original template that the section contains.
476
+ value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
477
+
478
+ if (value != null)
479
+ buffer += value;
480
+ } else {
481
+ buffer += this.renderTokens(token[4], context, partials, originalTemplate);
482
+ }
483
+
484
+ break;
485
+ case '^':
486
+ value = context.lookup(token[1]);
487
+
488
+ // Use JavaScript's definition of falsy. Include empty arrays.
489
+ // See https://github.com/janl/mustache.js/issues/186
490
+ if (!value || (isArray(value) && value.length === 0))
491
+ buffer += this.renderTokens(token[4], context, partials, originalTemplate);
492
+
493
+ break;
494
+ case '>':
495
+ if (!partials)
496
+ continue;
497
+
498
+ value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
499
+
500
+ if (value != null)
501
+ buffer += this.renderTokens(this.parse(value), context, partials, value);
502
+
503
+ break;
504
+ case '&':
505
+ value = context.lookup(token[1]);
506
+
507
+ if (value != null)
508
+ buffer += value;
509
+
510
+ break;
511
+ case 'name':
512
+ value = context.lookup(token[1]);
513
+
514
+ if (value != null)
515
+ buffer += mustache.escape(value);
516
+
517
+ break;
518
+ case 'text':
519
+ buffer += token[1];
520
+ break;
521
+ }
522
+ }
523
+
524
+ return buffer;
525
+ };
526
+
527
+ mustache.name = "mustache.js";
528
+ mustache.version = "0.8.1";
529
+ mustache.tags = [ "{{", "}}" ];
530
+
531
+ // All high-level mustache.* functions use this writer.
532
+ var defaultWriter = new Writer();
533
+
534
+ /**
535
+ * Clears all cached templates in the default writer.
536
+ */
537
+ mustache.clearCache = function () {
538
+ return defaultWriter.clearCache();
539
+ };
540
+
541
+ /**
542
+ * Parses and caches the given template in the default writer and returns the
543
+ * array of tokens it contains. Doing this ahead of time avoids the need to
544
+ * parse templates on the fly as they are rendered.
545
+ */
546
+ mustache.parse = function (template, tags) {
547
+ return defaultWriter.parse(template, tags);
548
+ };
549
+
550
+ /**
551
+ * Renders the `template` with the given `view` and `partials` using the
552
+ * default writer.
553
+ */
554
+ mustache.render = function (template, view, partials) {
555
+ return defaultWriter.render(template, view, partials);
556
+ };
557
+
558
+ // This is here for backwards compatibility with 0.4.x.
559
+ mustache.to_html = function (template, view, partials, send) {
560
+ var result = mustache.render(template, view, partials);
561
+
562
+ if (isFunction(send)) {
563
+ send(result);
564
+ } else {
565
+ return result;
566
+ }
567
+ };
568
+
569
+ // Export the escaping function so that the user may override it.
570
+ // See https://github.com/janl/mustache.js/issues/244
571
+ mustache.escape = escapeHtml;
572
+
573
+ // Export these mainly for testing, but also for advanced usage.
574
+ mustache.Scanner = Scanner;
575
+ mustache.Context = Context;
576
+ mustache.Writer = Writer;
577
+
578
+ }));