populate-me 0.0.33 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/LICENSE +1 -1
- data/README.md +399 -4
- data/Rakefile +14 -0
- data/example/config.ru +67 -0
- data/lib/populate_me.rb +2 -0
- data/lib/populate_me/admin.rb +143 -0
- data/lib/populate_me/admin/__assets__/css/main.css +174 -0
- data/lib/populate_me/admin/__assets__/js/columnav.js +82 -0
- data/lib/populate_me/admin/__assets__/js/main.js +251 -0
- data/lib/populate_me/admin/__assets__/js/mustache.js +578 -0
- data/lib/populate_me/admin/__assets__/js/sortable.js +2 -0
- data/lib/populate_me/admin/views/page.erb +163 -0
- data/lib/populate_me/api.rb +124 -0
- data/lib/populate_me/attachment.rb +182 -0
- data/lib/populate_me/document.rb +178 -0
- data/lib/populate_me/document_mixins/admin_adapter.rb +131 -0
- data/lib/populate_me/document_mixins/callbacks.rb +104 -0
- data/lib/populate_me/document_mixins/outcasting.rb +49 -0
- data/lib/populate_me/document_mixins/persistence.rb +92 -0
- data/lib/populate_me/document_mixins/schema.rb +99 -0
- data/lib/populate_me/document_mixins/typecasting.rb +60 -0
- data/lib/populate_me/document_mixins/validation.rb +44 -0
- data/lib/populate_me/file_system_attachment.rb +40 -0
- data/lib/populate_me/grid_fs_attachment.rb +127 -0
- data/lib/populate_me/mongo.rb +98 -3
- data/lib/populate_me/variation.rb +34 -0
- data/lib/populate_me/version.rb +4 -0
- data/populate-me.gemspec +20 -12
- data/test/helper.rb +37 -0
- data/test/test_admin.rb +161 -0
- data/test/test_api.rb +246 -0
- data/test/test_attachment.rb +155 -0
- data/test/test_document.rb +120 -0
- data/test/test_document_admin_adapter.rb +43 -0
- data/test/test_document_callbacks.rb +107 -0
- data/test/test_document_persistence.rb +56 -0
- data/test/test_document_typecasting.rb +121 -0
- data/test/test_mongo.rb +217 -0
- data/test/test_variation.rb +91 -0
- data/test/test_version.rb +11 -0
- metadata +115 -66
- data/lib/populate_me/control.rb +0 -196
- data/lib/populate_me/control/_public/css/main.css +0 -207
- data/lib/populate_me/control/_public/css/plugin.asmselect.css +0 -63
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_flat_30_cccccc_40x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_flat_50_5c5c5c_40x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_glass_20_555555_1x400.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_glass_40_0078a3_1x400.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_glass_40_ffc73d_1x400.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_gloss-wave_25_333333_500x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_highlight-soft_80_eeeeee_1x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_inset-soft_25_000000_1x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_inset-soft_30_f58400_1x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_222222_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_4b8e0b_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_a83300_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_cccccc_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_ffffff_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/jquery-ui-1.8.17.custom.css +0 -430
- data/lib/populate_me/control/_public/img/grip.png +0 -0
- data/lib/populate_me/control/_public/img/icons-cms-solarized.png +0 -0
- data/lib/populate_me/control/_public/img/icons-cms.png +0 -0
- data/lib/populate_me/control/_public/img/placeholder.png +0 -0
- data/lib/populate_me/control/_public/img/placeholder.stash_thumb.gif +0 -0
- data/lib/populate_me/control/_public/img/placeholder.stash_thumb.png +0 -0
- data/lib/populate_me/control/_public/img/small-loader.gif +0 -0
- data/lib/populate_me/control/_public/js/addon.timepicker.js +0 -20
- data/lib/populate_me/control/_public/js/jquery-ui.js +0 -114
- data/lib/populate_me/control/_public/js/jquery.js +0 -167
- data/lib/populate_me/control/_public/js/jquery.mustache.js +0 -559
- data/lib/populate_me/control/_public/js/main.js +0 -144
- data/lib/populate_me/control/_public/js/plugin.asmselect.js +0 -407
- data/lib/populate_me/control/_public/js/plugin.form.js +0 -11
- data/lib/populate_me/control/_public/js/plugin.quicksearch.js +0 -1
- data/lib/populate_me/control/_public/js/plugin.underwood.js +0 -4
- data/lib/populate_me/control/views/populate_me_layout.erb +0 -75
- data/lib/populate_me/ext.rb +0 -16
- data/lib/populate_me/mongo/backend_api_plug.rb +0 -78
- data/lib/populate_me/mongo/crushyform.rb +0 -243
- data/lib/populate_me/mongo/mutation.rb +0 -324
- data/lib/populate_me/mongo/plug.rb +0 -134
- data/lib/populate_me/mongo/stash.rb +0 -171
- data/test/spec_ext.rb +0 -29
- data/test/spec_mongo_mutation.rb +0 -279
@@ -1,11 +0,0 @@
|
|
1
|
-
/*!
|
2
|
-
* jQuery Form Plugin
|
3
|
-
* version: 2.83 (11-JUL-2011)
|
4
|
-
* @requires jQuery v1.3.2 or later
|
5
|
-
*
|
6
|
-
* Examples and documentation at: http://malsup.com/jquery/form/
|
7
|
-
* Dual licensed under the MIT and GPL licenses:
|
8
|
-
* http://www.opensource.org/licenses/mit-license.php
|
9
|
-
* http://www.gnu.org/licenses/gpl.html
|
10
|
-
*/
|
11
|
-
;(function($){$.fn.ajaxSubmit=function(w){if(!this.length){log('ajaxSubmit: skipping submit process - no element selected');return this}var x,action,url,$form=this;if(typeof w=='function'){w={success:w}}x=this.attr('method');action=this.attr('action');url=(typeof action==='string')?$.trim(action):'';url=url||window.location.href||'';if(url){url=(url.match(/^([^#]+)/)||[])[1]}w=$.extend(true,{url:url,success:$.ajaxSettings.success,type:x||'GET',iframeSrc:/^https/i.test(window.location.href||'')?'javascript:false':'about:blank'},w);var y={};this.trigger('form-pre-serialize',[this,w,y]);if(y.veto){log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');return this}if(w.beforeSerialize&&w.beforeSerialize(this,w)===false){log('ajaxSubmit: submit aborted via beforeSerialize callback');return this}var n,v,a=this.formToArray(w.semantic);if(w.data){w.extraData=w.data;for(n in w.data){if(w.data[n]instanceof Array){for(var k in w.data[n]){a.push({name:n,value:w.data[n][k]})}}else{v=w.data[n];v=$.isFunction(v)?v():v;a.push({name:n,value:v})}}}if(w.beforeSubmit&&w.beforeSubmit(a,this,w)===false){log('ajaxSubmit: submit aborted via beforeSubmit callback');return this}this.trigger('form-submit-validate',[a,this,w,y]);if(y.veto){log('ajaxSubmit: submit vetoed via form-submit-validate trigger');return this}var q=$.param(a);if(w.type.toUpperCase()=='GET'){w.url+=(w.url.indexOf('?')>=0?'&':'?')+q;w.data=null}else{w.data=q}var z=[];if(w.resetForm){z.push(function(){$form.resetForm()})}if(w.clearForm){z.push(function(){$form.clearForm()})}if(!w.dataType&&w.target){var A=w.success||function(){};z.push(function(a){var b=w.replaceTarget?'replaceWith':'html';$(w.target)[b](a).each(A,arguments)})}else if(w.success){z.push(w.success)}w.success=function(a,b,c){var d=w.context||w;for(var i=0,max=z.length;i<max;i++){z[i].apply(d,[a,b,c||$form,$form])}};var B=$('input:file',this).length>0;var C='multipart/form-data';var D=($form.attr('enctype')==C||$form.attr('encoding')==C);if(w.iframe!==false&&(B||w.iframe||D)){if(w.closeKeepAlive){$.get(w.closeKeepAlive,function(){fileUpload(a)})}else{fileUpload(a)}}else{if($.browser.msie&&x=='get'){var E=$form[0].getAttribute('method');if(typeof E==='string')w.type=E}$.ajax(w)}this.trigger('form-submit-notify',[this,w]);return this;function fileUpload(a){var l=$form[0],el,i,s,g,id,$io,io,xhr,sub,n,timedOut,timeoutHandle;var m=!!$.fn.prop;if(a){for(i=0;i<a.length;i++){el=$(l[a[i].name]);el[m?'prop':'attr']('disabled',false)}}if($(':input[name=submit],:input[id=submit]',l).length){alert('Error: Form elements must not have name or id of "submit".');return}s=$.extend(true,{},$.ajaxSettings,w);s.context=s.context||s;id='jqFormIO'+(new Date().getTime());if(s.iframeTarget){$io=$(s.iframeTarget);n=$io.attr('name');if(n==null)$io.attr('name',id);else id=n}else{$io=$('<iframe name="'+id+'" src="'+s.iframeSrc+'" />');$io.css({position:'absolute',top:'-1000px',left:'-1000px'})}io=$io[0];xhr={aborted:0,responseText:null,responseXML:null,status:0,statusText:'n/a',getAllResponseHeaders:function(){},getResponseHeader:function(){},setRequestHeader:function(){},abort:function(a){var e=(a==='timeout'?'timeout':'aborted');log('aborting upload... '+e);this.aborted=1;$io.attr('src',s.iframeSrc);xhr.error=e;s.error&&s.error.call(s.context,xhr,e,a);g&&$.event.trigger("ajaxError",[xhr,s,e]);s.complete&&s.complete.call(s.context,xhr,e)}};g=s.global;if(g&&!$.active++){$.event.trigger("ajaxStart")}if(g){$.event.trigger("ajaxSend",[xhr,s])}if(s.beforeSend&&s.beforeSend.call(s.context,xhr,s)===false){if(s.global){$.active--}return}if(xhr.aborted){return}sub=l.clk;if(sub){n=sub.name;if(n&&!sub.disabled){s.extraData=s.extraData||{};s.extraData[n]=sub.value;if(sub.type=="image"){s.extraData[n+'.x']=l.clk_x;s.extraData[n+'.y']=l.clk_y}}}var o=1;var p=2;function getDoc(a){var b=a.contentWindow?a.contentWindow.document:a.contentDocument?a.contentDocument:a.document;return b}function doSubmit(){var t=$form.attr('target'),a=$form.attr('action');l.setAttribute('target',id);if(!x){l.setAttribute('method','POST')}if(a!=s.url){l.setAttribute('action',s.url)}if(!s.skipEncodingOverride&&(!x||/post/i.test(x))){$form.attr({encoding:'multipart/form-data',enctype:'multipart/form-data'})}if(s.timeout){timeoutHandle=setTimeout(function(){timedOut=true;cb(o)},s.timeout)}function checkState(){try{var a=getDoc(io).readyState;log('state = '+a);if(a.toLowerCase()=='uninitialized')setTimeout(checkState,50)}catch(e){log('Server abort: ',e,' (',e.name,')');cb(p);timeoutHandle&&clearTimeout(timeoutHandle);timeoutHandle=undefined}}var b=[];try{if(s.extraData){for(var n in s.extraData){b.push($('<input type="hidden" name="'+n+'" />').attr('value',s.extraData[n]).appendTo(l)[0])}}if(!s.iframeTarget){$io.appendTo('body');io.attachEvent?io.attachEvent('onload',cb):io.addEventListener('load',cb,false)}setTimeout(checkState,15);l.submit()}finally{l.setAttribute('action',a);if(t){l.setAttribute('target',t)}else{$form.removeAttr('target')}$(b).remove()}}if(s.forceSync){doSubmit()}else{setTimeout(doSubmit,10)}var q,doc,domCheckCount=50,callbackProcessed;function cb(e){if(xhr.aborted||callbackProcessed){return}try{doc=getDoc(io)}catch(ex){log('cannot access response document: ',ex);e=p}if(e===o&&xhr){xhr.abort('timeout');return}else if(e==p&&xhr){xhr.abort('server abort');return}if(!doc||doc.location.href==s.iframeSrc){if(!timedOut)return}io.detachEvent?io.detachEvent('onload',cb):io.removeEventListener('load',cb,false);var c='success',errMsg;try{if(timedOut){throw'timeout';}var d=s.dataType=='xml'||doc.XMLDocument||$.isXMLDoc(doc);log('isXml='+d);if(!d&&window.opera&&(doc.body==null||doc.body.innerHTML=='')){if(--domCheckCount){log('requeing onLoad callback, DOM not available');setTimeout(cb,250);return}}var f=doc.body?doc.body:doc.documentElement;xhr.responseText=f?f.innerHTML:null;xhr.responseXML=doc.XMLDocument?doc.XMLDocument:doc;if(d)s.dataType='xml';xhr.getResponseHeader=function(a){var b={'content-type':s.dataType};return b[a]};if(f){xhr.status=Number(f.getAttribute('status'))||xhr.status;xhr.statusText=f.getAttribute('statusText')||xhr.statusText}var h=s.dataType||'';var i=/(json|script|text)/.test(h.toLowerCase());if(i||s.textarea){var j=doc.getElementsByTagName('textarea')[0];if(j){xhr.responseText=j.value;xhr.status=Number(j.getAttribute('status'))||xhr.status;xhr.statusText=j.getAttribute('statusText')||xhr.statusText}else if(i){var k=doc.getElementsByTagName('pre')[0];var b=doc.getElementsByTagName('body')[0];if(k){xhr.responseText=k.textContent?k.textContent:k.innerHTML}else if(b){xhr.responseText=b.innerHTML}}}else if(s.dataType=='xml'&&!xhr.responseXML&&xhr.responseText!=null){xhr.responseXML=r(xhr.responseText)}try{q=v(xhr,s.dataType,s)}catch(e){c='parsererror';xhr.error=errMsg=(e||c)}}catch(e){log('error caught: ',e);c='error';xhr.error=errMsg=(e||c)}if(xhr.aborted){log('upload aborted');c=null}if(xhr.status){c=(xhr.status>=200&&xhr.status<300||xhr.status===304)?'success':'error'}if(c==='success'){s.success&&s.success.call(s.context,q,'success',xhr);g&&$.event.trigger("ajaxSuccess",[xhr,s])}else if(c){if(errMsg==undefined)errMsg=xhr.statusText;s.error&&s.error.call(s.context,xhr,c,errMsg);g&&$.event.trigger("ajaxError",[xhr,s,errMsg])}g&&$.event.trigger("ajaxComplete",[xhr,s]);if(g&&!--$.active){$.event.trigger("ajaxStop")}s.complete&&s.complete.call(s.context,xhr,c);callbackProcessed=true;if(s.timeout)clearTimeout(timeoutHandle);setTimeout(function(){if(!s.iframeTarget)$io.remove();xhr.responseXML=null},100)}var r=$.parseXML||function(s,a){if(window.ActiveXObject){a=new ActiveXObject('Microsoft.XMLDOM');a.async='false';a.loadXML(s)}else{a=(new DOMParser()).parseFromString(s,'text/xml')}return(a&&a.documentElement&&a.documentElement.nodeName!='parsererror')?a:null};var u=$.parseJSON||function(s){return window['eval']('('+s+')')};var v=function(a,b,s){var c=a.getResponseHeader('content-type')||'',xml=b==='xml'||!b&&c.indexOf('xml')>=0,q=xml?a.responseXML:a.responseText;if(xml&&q.documentElement.nodeName==='parsererror'){$.error&&$.error('parsererror')}if(s&&s.dataFilter){q=s.dataFilter(q,b)}if(typeof q==='string'){if(b==='json'||!b&&c.indexOf('json')>=0){q=u(q)}else if(b==="script"||!b&&c.indexOf("javascript")>=0){$.globalEval(q)}}return q}}};$.fn.ajaxForm=function(f){if(this.length===0){var o={s:this.selector,c:this.context};if(!$.isReady&&o.s){log('DOM not ready, queuing ajaxForm');$(function(){$(o.s,o.c).ajaxForm(f)});return this}log('terminating; zero elements found by selector'+($.isReady?'':' (DOM not ready)'));return this}return this.ajaxFormUnbind().bind('submit.form-plugin',function(e){if(!e.isDefaultPrevented()){e.preventDefault();$(this).ajaxSubmit(f)}}).bind('click.form-plugin',function(e){var a=e.target;var b=$(a);if(!(b.is(":submit,input:image"))){var t=b.closest(':submit');if(t.length==0){return}a=t[0]}var c=this;c.clk=a;if(a.type=='image'){if(e.offsetX!=undefined){c.clk_x=e.offsetX;c.clk_y=e.offsetY}else if(typeof $.fn.offset=='function'){var d=b.offset();c.clk_x=e.pageX-d.left;c.clk_y=e.pageY-d.top}else{c.clk_x=e.pageX-a.offsetLeft;c.clk_y=e.pageY-a.offsetTop}}setTimeout(function(){c.clk=c.clk_x=c.clk_y=null},100)})};$.fn.ajaxFormUnbind=function(){return this.unbind('submit.form-plugin click.form-plugin')};$.fn.formToArray=function(b){var a=[];if(this.length===0){return a}var c=this[0];var d=b?c.getElementsByTagName('*'):c.elements;if(!d){return a}var i,j,n,v,el,max,jmax;for(i=0,max=d.length;i<max;i++){el=d[i];n=el.name;if(!n){continue}if(b&&c.clk&&el.type=="image"){if(!el.disabled&&c.clk==el){a.push({name:n,value:$(el).val()});a.push({name:n+'.x',value:c.clk_x},{name:n+'.y',value:c.clk_y})}continue}v=$.fieldValue(el,true);if(v&&v.constructor==Array){for(j=0,jmax=v.length;j<jmax;j++){a.push({name:n,value:v[j]})}}else if(v!==null&&typeof v!='undefined'){a.push({name:n,value:v})}}if(!b&&c.clk){var e=$(c.clk),input=e[0];n=input.name;if(n&&!input.disabled&&input.type=='image'){a.push({name:n,value:e.val()});a.push({name:n+'.x',value:c.clk_x},{name:n+'.y',value:c.clk_y})}}return a};$.fn.formSerialize=function(a){return $.param(this.formToArray(a))};$.fn.fieldSerialize=function(b){var a=[];this.each(function(){var n=this.name;if(!n){return}var v=$.fieldValue(this,b);if(v&&v.constructor==Array){for(var i=0,max=v.length;i<max;i++){a.push({name:n,value:v[i]})}}else if(v!==null&&typeof v!='undefined'){a.push({name:this.name,value:v})}});return $.param(a)};$.fn.fieldValue=function(a){for(var b=[],i=0,max=this.length;i<max;i++){var c=this[i];var v=$.fieldValue(c,a);if(v===null||typeof v=='undefined'||(v.constructor==Array&&!v.length)){continue}v.constructor==Array?$.merge(b,v):b.push(v)}return b};$.fieldValue=function(b,c){var n=b.name,t=b.type,tag=b.tagName.toLowerCase();if(c===undefined){c=true}if(c&&(!n||b.disabled||t=='reset'||t=='button'||(t=='checkbox'||t=='radio')&&!b.checked||(t=='submit'||t=='image')&&b.form&&b.form.clk!=b||tag=='select'&&b.selectedIndex==-1)){return null}if(tag=='select'){var d=b.selectedIndex;if(d<0){return null}var a=[],ops=b.options;var e=(t=='select-one');var f=(e?d+1:ops.length);for(var i=(e?d:0);i<f;i++){var g=ops[i];if(g.selected){var v=g.value;if(!v){v=(g.attributes&&g.attributes['value']&&!(g.attributes['value'].specified))?g.text:g.value}if(e){return v}a.push(v)}}return a}return $(b).val()};$.fn.clearForm=function(){return this.each(function(){$('input,select,textarea',this).clearFields()})};$.fn.clearFields=$.fn.clearInputs=function(){var a=/^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i;return this.each(function(){var t=this.type,tag=this.tagName.toLowerCase();if(a.test(t)||tag=='textarea'){this.value=''}else if(t=='checkbox'||t=='radio'){this.checked=false}else if(tag=='select'){this.selectedIndex=-1}})};$.fn.resetForm=function(){return this.each(function(){if(typeof this.reset=='function'||(typeof this.reset=='object'&&!this.reset.nodeType)){this.reset()}})};$.fn.enable=function(b){if(b===undefined){b=true}return this.each(function(){this.disabled=!b})};$.fn.selected=function(b){if(b===undefined){b=true}return this.each(function(){var t=this.type;if(t=='checkbox'||t=='radio'){this.checked=b}else if(this.tagName.toLowerCase()=='option'){var a=$(this).parent('select');if(b&&a[0]&&a[0].type=='select-one'){a.find('option').selected(false)}this.selected=b}})};function log(){var a='[jquery.form] '+Array.prototype.join.call(arguments,'');if(window.console&&window.console.log){window.console.log(a)}else if(window.opera&&window.opera.postError){window.opera.postError(a)}}})(jQuery);
|
@@ -1 +0,0 @@
|
|
1
|
-
(function($,h,j,k){$.fn.quicksearch=function(d,f){var g,cache,rowcache,jq_results,val='',e=this,options=$.extend({delay:100,selector:null,stripeRows:null,loader:null,noResults:'',bind:'keyup',onBefore:function(){return},onAfter:function(){return},show:function(){this.style.display=""},hide:function(){this.style.display="none"},prepareQuery:function(a){return a.toLowerCase().split(' ')},testQuery:function(a,b,c){for(var i=0;i<a.length;i+=1){if(b.indexOf(a[i])===-1){return false}}return true}},f);this.go=function(){var i=0,noresults=true,query=options.prepareQuery(val),val_empty=(val.replace(' ','').length===0);for(var i=0,len=rowcache.length;i<len;i++){if(val_empty||options.testQuery(query,cache[i],rowcache[i])){options.show.apply(rowcache[i]);noresults=false}else{options.hide.apply(rowcache[i])}}if(noresults){this.results(false)}else{this.results(true);this.stripe()}this.loader(false);options.onAfter();return this};this.stripe=function(){if(typeof options.stripeRows==="object"&&options.stripeRows!==null){var a=options.stripeRows.join(' ');var b=options.stripeRows.length;jq_results.not(':hidden').each(function(i){$(this).removeClass(a).addClass(options.stripeRows[i%b])})}return this};this.strip_html=function(a){var b=a.replace(new RegExp('<[^<]+\>','g'),"");b=$.trim(b.toLowerCase());return b};this.results=function(a){if(typeof options.noResults==="string"&&options.noResults!==""){if(a){$(options.noResults).hide()}else{$(options.noResults).show()}}return this};this.loader=function(a){if(typeof options.loader==="string"&&options.loader!==""){(a)?$(options.loader).show():$(options.loader).hide()}return this};this.cache=function(){jq_results=$(d);if(typeof options.noResults==="string"&&options.noResults!==""){jq_results=jq_results.not(options.noResults)}var t=(typeof options.selector==="string")?jq_results.find(options.selector):$(d).not(options.noResults);cache=t.map(function(){return e.strip_html(this.innerHTML)});rowcache=jq_results.map(function(){return this});return this.go()};this.trigger=function(){this.loader(true);options.onBefore();h.clearTimeout(g);g=h.setTimeout(function(){e.go()},options.delay);return this};this.cache();this.results(true);this.stripe();this.loader(false);return this.each(function(){$(this).bind(options.bind,function(){val=$(this).val();e.trigger()})})}}(jQuery,this,document));
|
@@ -1,4 +0,0 @@
|
|
1
|
-
// Copyright (c) 2010-11 Mickael Riga - See MIT_LICENCE for details
|
2
|
-
// Version 0.2.2
|
3
|
-
;(function($){$.fn.underwood=function(l){var m={toolbar:"title paragraph bold italic link mailto unlink source",title_block:'<h3>',paragraph_block:'<p>',sanitize:true,css_href:null};var n=$.extend({},m,l);if(document.designMode||document.contentEditable){return this.each(function(){$(this).parents('form').unbind('submit.underwood').bind('submit.underwood',function(){$(this).find('iframe.underwood_iframe').each(function(){disable_design_mode(this,true)})});enable_design_mode($(this))})}function enable_design_mode(a){var b=document.createElement("iframe");b.frameBorder=0;b.frameMargin=0;b.framePadding=0;b.height=200;b.className="underwood_iframe";if(a.attr('name'))b.rel=a.attr('name');a.after(b);var c;if(n.css_href){c="<link rel='stylesheet' href='"+n.css_href+"' type='text/css' media='screen' charset='utf-8' />"}else{c=" <style type='text/css'> .underwood_frame_body {font-family:sans-serif;font-size:12px;margin:0;padding:10px;} .underwood_frame_body p {border:1px #DDD solid;padding:2px;} </style>"}var d=a.val();if($.trim(d)=='')d='<br>';var e="<html><head>"+c+"</head><body class='underwood_frame_body'>"+d+"</body></html>";try_enable_design_mode(b,e,function(){$(b).prevAll('.underwood_toolbar').remove().end().before(toolbar(b));a.remove()})}function try_enable_design_mode(a,b,c){try{a.contentWindow.document.open();a.contentWindow.document.write(b);a.contentWindow.document.close()}catch(error){console.log(error)}if(document.contentEditable){a.contentWindow.document.designMode="On";c();return true}else if(document.designMode!=null){try{a.contentWindow.document.designMode="on";c();return true}catch(error){console.log(error)}}setTimeout(function(){try_enable_design_mode(a,b,c)},250);return false}function toolbar(e){var f=$("<div class='underwood_toolbar'></div>");var g=n.toolbar.split(' ');for(var i in g){var h=g[i];var j=h.charAt(0).toUpperCase()+h.substr(1).toLowerCase();var k="<a href='#' class='underwood_btn underwood_btn_"+h+"' title='"+j+"'>"+j+"</a>";f.append($(k))}$('.underwood_btn_title',f).click(function(){exec_command(e,"formatblock",n.title_block);return false});$('.underwood_btn_paragraph',f).click(function(){exec_command(e,"formatblock",n.paragraph_block);return false});$('.underwood_btn_bold',f).click(function(){exec_command(e,'bold');return false});$('.underwood_btn_italic',f).click(function(){exec_command(e,'italic');return false});$('.underwood_btn_link',f).click(function(){var a=prompt("URL:","http://");var b=confirm('Open in a new window? (press cancel to open in the same window)')?'_blank':'_self';if(a){exec_command(e,'CreateLink',a);var c=e.contentWindow;var d=c.getSelection();d.focusNode.parentNode.target=b}return false});$('.underwood_btn_mailto',f).click(function(){var a='mailto:'+prompt("Email address:");if(a)exec_command(e,'CreateLink',a);return false});$('.underwood_btn_unlink',f).click(function(){exec_command(e,'unlink');return false});$('.underwood_btn_image',f).click(function(){var a=prompt("Image URL:");if(a)exec_command(e,'InsertImage',a);return false});$('.underwood_btn_source',f).click(function(){var a=disable_design_mode(e);var b=$("<a href='#' class='underwood_btn underwood_btn_back'>Back to Rich Text Editor</a>");f.empty().append(b);b.click(function(){enable_design_mode(a);return false}).hover(function(){$(this).css('opacity',0.6)},function(){$(this).css('opacity',1)});return false});$('.underwood_btn',f).hover(function(){$(this).css('opacity',0.6)},function(){$(this).css('opacity',1)});return f}function exec_command(a,b,c){a.contentWindow.focus();try{a.contentWindow.document.execCommand(b,false,c)}catch(e){console.log(e)}a.contentWindow.focus()}function sanitize_this(s){s=n.sanitize?s.replace(/(<\/?font[^>]*>|style=.[^'"]*['"])/g,''):s;return(s.match(/(>|^)[^<]+(<|$)/)||s.match(/<(object|iframe|img)/))?s:''};function disable_design_mode(a,b){var c=a.contentWindow.document.getElementsByTagName("body")[0].innerHTML;if(b==true)var d=$('<input type="hidden" />');else var d=$('<textarea cols="40" rows="10"></textarea>');d.val(sanitize_this(c));t=d.get(0);t.className="underwood_textarea_copy";if(a.rel)t.name=a.rel;$(a).before(d);if(b!=true)$(a).remove();return d}function create_targeted_link(a,b,c){selected=a.contentWindow.document.getSelection().getRangeAt(0);var d=a.contentWindow.document.createElement('a');d.href=b;d.target=c;if(selected.toString()==''){d.innerHTML=b;selected.insertNode(d)}else{selected.surroundContents(d)}}}})(jQuery);
|
4
|
-
|
@@ -1,75 +0,0 @@
|
|
1
|
-
<%# coding: UTF-8 %>
|
2
|
-
<!DOCTYPE html>
|
3
|
-
<html lang="en">
|
4
|
-
<head>
|
5
|
-
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
6
|
-
<link rel="stylesheet" href="<%= config[:path] %>/_public/css/plugin.asmselect.css" type="text/css" media="screen" charset="utf-8" />
|
7
|
-
<link rel="stylesheet" href="<%= config[:path] %>/_public/css/ui-darkness/jquery-ui-1.8.17.custom.css" type="text/css" media="screen" charset="utf-8" />
|
8
|
-
<link rel="stylesheet" href="<%= config[:path] %>/_public/css/main.css" type="text/css" media="screen" charset="utf-8" />
|
9
|
-
<title><%= config[:client_name] %> - Admin</title>
|
10
|
-
<script id='template-menu' type='text/html'>
|
11
|
-
<ul class='menu-list'>
|
12
|
-
{{#items}}
|
13
|
-
<li><a href='{{href}}' class='pushstack'>{{title}}</a></li>
|
14
|
-
{{/items}}
|
15
|
-
</ul>
|
16
|
-
</script>
|
17
|
-
<script id='template-nut-tree' type='text/html'>
|
18
|
-
{{#command_plus}}
|
19
|
-
<a href='<%= config[:path] %>/form/{{class_name}}{{query_string}}' class='btn plus-btn extra-plus pushstack' title='Create'></a>
|
20
|
-
{{/command_plus}}
|
21
|
-
<ul class='nut-tree {{#sortable}}sortable{{/sortable}}'>
|
22
|
-
{{#items}}{{>nutshell}}{{/items}}
|
23
|
-
</ul>
|
24
|
-
</script>
|
25
|
-
<script id='template-nutshell' type='text/html'>
|
26
|
-
<li class='nutshell nutshell-{{class_name}}' id='{{class_name}}-{{id}}'>
|
27
|
-
<div class='nutshell-core'>
|
28
|
-
<div class='nutshell-bar {{#sortable}}sortable-handle{{/sortable}}'>
|
29
|
-
|
30
|
-
<a href='<%= config[:path] %>/{{class_name}}/{{id}}' class='btn cross-btn nutshell-delete float-right' title='Delete'></a>
|
31
|
-
</div>
|
32
|
-
<a href='<%= config[:path] %>/form/{{class_name}}/{{id}}' class='nutshell-edit pushstack' title='Edit'>
|
33
|
-
{{#thumb}}<img src='{{thumb}}' onerror="this.style.display='none'" alt='Thumb' />{{/thumb}}
|
34
|
-
<span class='nutshell-title'>{{title}}</span>
|
35
|
-
</a>
|
36
|
-
</div>
|
37
|
-
<ul class='nutshell-children'>
|
38
|
-
{{#children}}
|
39
|
-
<li><a href='<%= config[:path] %>/list/{{children_class_name}}?filter[{{foreign_key_name}}]={{id}}' class='btn further-btn further-bar pushstack'>{{title}} {{count}}</a></li>
|
40
|
-
{{/children}}
|
41
|
-
</ul>
|
42
|
-
</li>
|
43
|
-
</script>
|
44
|
-
</head>
|
45
|
-
<body>
|
46
|
-
<div id='trunk'>
|
47
|
-
<h1 id='page-title' class='shadowed'><%= config[:page_title] %></h1>
|
48
|
-
<div id='header' class='shadowed'>
|
49
|
-
<a href='#' class='btn back-btn float-left popstack' title='Back'></a>
|
50
|
-
<a href='<%= config[:path] %>' class='btn home-btn float-right' title='Home'></a>
|
51
|
-
<div id='search-wrap'><input type='text' id='search' placeholder='Search' /></div>
|
52
|
-
</div>
|
53
|
-
<noscript><div>In order to have this content management system working, you need to have javascript enabled.</div></noscript>
|
54
|
-
<div id='content'></div>
|
55
|
-
<div id='footer'>
|
56
|
-
© Mickaël Riga<br>
|
57
|
-
<a href='https://github.com/mig-hub/populate-me' target='_blank'>Populate Me</a> is an open source project
|
58
|
-
</div>
|
59
|
-
</div>
|
60
|
-
<script type="text/javascript" charset="utf-8">
|
61
|
-
var admin_path = "<%= config[:path] %>";
|
62
|
-
</script>
|
63
|
-
<!-- // <script src='http://code.jquery.com/jquery-1.6.2.min.js' type='text/javascript'></script> -->
|
64
|
-
<script src='<%= config[:path] %>/_public/js/jquery.js' type='text/javascript'></script>
|
65
|
-
<script src='<%= config[:path] %>/_public/js/jquery.mustache.js' type='text/javascript'></script>
|
66
|
-
<script src='<%= config[:path] %>/_public/js/jquery-ui.js' type='text/javascript'></script>
|
67
|
-
<script src='<%= config[:path] %>/_public/js/addon.timepicker.js' type='text/javascript'></script>
|
68
|
-
<script src='<%= config[:path] %>/_public/js/plugin.form.js' type='text/javascript'></script>
|
69
|
-
<script src='<%= config[:path] %>/_public/js/plugin.underwood.js' type='text/javascript'></script>
|
70
|
-
<script src='<%= config[:path] %>/_public/js/plugin.asmselect.js' type='text/javascript'></script>
|
71
|
-
<script src='<%= config[:path] %>/_public/js/plugin.quicksearch.js' type='text/javascript'></script>
|
72
|
-
<script src='<%= config[:path] %>/_public/js/main.js' type='text/javascript'></script>
|
73
|
-
</body>
|
74
|
-
</html>
|
75
|
-
|
data/lib/populate_me/ext.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
# Extends standard classes
|
4
|
-
|
5
|
-
Integer.class_eval do
|
6
|
-
def to_price_string
|
7
|
-
("%.2f" % (self/100.0)).sub(/\.00/, '').reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
String.class_eval do
|
12
|
-
def to_price_integer
|
13
|
-
("%.2f" % self.gsub(/[^\d\.\-]/, '')).gsub(/\./,'').to_i
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
@@ -1,78 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
module PopulateMe
|
3
|
-
module Mongo
|
4
|
-
module BackendApiPlug
|
5
|
-
|
6
|
-
# This module adds a layer between the backend API and the models.
|
7
|
-
# It is legacy code and could probably be removed,
|
8
|
-
# but in a way it makes it easier to plug something else than MongoDB.
|
9
|
-
# I'll keep it and see.
|
10
|
-
|
11
|
-
def self.included(base)
|
12
|
-
base.extend(ClassMethods)
|
13
|
-
end
|
14
|
-
|
15
|
-
module ClassMethods
|
16
|
-
def backend_get(id); id=='unique' ? find_one : get(id); end
|
17
|
-
def backend_post(doc=nil); inst = new(doc); inst.is_new = true; inst; end
|
18
|
-
end
|
19
|
-
|
20
|
-
# Instance Methods
|
21
|
-
|
22
|
-
def backend_delete; delete; end
|
23
|
-
def backend_put(fields); update_doc(fields); end
|
24
|
-
def backend_values; @doc; end
|
25
|
-
def backend_save?; !save.nil?; end
|
26
|
-
def backend_form(url, cols=nil, opts={})
|
27
|
-
cols ||= default_backend_columns
|
28
|
-
if block_given?
|
29
|
-
fields_list = ''
|
30
|
-
yield(fields_list)
|
31
|
-
else
|
32
|
-
fields_list = respond_to?(:crushyform) ? crushyform(cols) : backend_fields(cols)
|
33
|
-
end
|
34
|
-
o = "<form action='#{url}' method='POST' #{"enctype='multipart/form-data'" if fields_list.match(/type='file'/)} class='backend-form'>\n"
|
35
|
-
#o << backend_form_title unless block_given?
|
36
|
-
o << fields_list
|
37
|
-
opts[:method] = 'PUT' if (opts[:method].nil? && !self.new?)
|
38
|
-
o << "<input type='hidden' name='_method' value='#{opts[:method]}' />\n" unless opts[:method].nil?
|
39
|
-
o << "<input type='hidden' name='_destination' value='#{opts[:destination]}' />\n" unless opts[:destination].nil?
|
40
|
-
o << "<input type='hidden' name='_submit_text' value='#{opts[:submit_text]}' />\n" unless opts[:submit_text].nil?
|
41
|
-
o << "<input type='hidden' name='_no_wrap' value='#{opts[:no_wrap]}' />\n" unless opts[:no_wrap].nil?
|
42
|
-
cols.each do |c|
|
43
|
-
o << "<input type='hidden' name='fields[]' value='#{c}' />\n"
|
44
|
-
end
|
45
|
-
o << "<input type='submit' name='save' value='#{opts[:submit_text] || 'SAVE'}' />\n"
|
46
|
-
o << "</form>\n"
|
47
|
-
o
|
48
|
-
end
|
49
|
-
def backend_delete_form(url, opts={}); backend_form(url, [], {:submit_text=>'X', :method=>'DELETE'}.update(opts)){}; end
|
50
|
-
def backend_clone_form(url, opts={})
|
51
|
-
backend_form(url, [], {:submit_text=>'CLONE', :method=>'POST'}.update(opts)) do |out|
|
52
|
-
out << "<input type='hidden' name='clone_id' value='#{self.id}' />\n"
|
53
|
-
end
|
54
|
-
end
|
55
|
-
# Silly but usable form prototype
|
56
|
-
# Not really meant to be used in a real case
|
57
|
-
# It uses a textarea for everything
|
58
|
-
# Override it
|
59
|
-
# Or even better, use Sequel-Crushyform plugin instead
|
60
|
-
def backend_fields(cols)
|
61
|
-
o = ''
|
62
|
-
cols.each do |c|
|
63
|
-
identifier = "#{id}-#{self.class}-#{c}"
|
64
|
-
o << "<label for='#{identifier}'>#{c.to_s.capitalize}</label><br />\n"
|
65
|
-
o << "<textarea id='#{identifier}' name='model[#{c}]'>#{self[c]}</textarea><br />\n"
|
66
|
-
end
|
67
|
-
o
|
68
|
-
end
|
69
|
-
def backend_form_title; self.new? ? "New #{model.human_name}" : "Edit #{self.to_label}"; end
|
70
|
-
def backend_show; 'OK'; end
|
71
|
-
|
72
|
-
def default_backend_columns; model.schema.keys; end
|
73
|
-
def cloning_backend_columns; default_backend_columns.reject{|c| model.schema[c][:type]==:attachment}; end
|
74
|
-
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
@@ -1,243 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
module PopulateMe
|
3
|
-
module Mongo
|
4
|
-
module Crushyform
|
5
|
-
|
6
|
-
# This module adds to mutated models the ability
|
7
|
-
# to build forms using the settings of the schema
|
8
|
-
|
9
|
-
def self.included(base)
|
10
|
-
base.extend(ClassMethods)
|
11
|
-
end
|
12
|
-
|
13
|
-
module ClassMethods
|
14
|
-
|
15
|
-
def crushyform_types
|
16
|
-
@crushyform_types ||= {
|
17
|
-
:none => proc{''},
|
18
|
-
:string => proc do |m,c,o|
|
19
|
-
if o[:autocompleted]
|
20
|
-
values = o[:autocomplete_options] || m.class.collection.distinct(c)
|
21
|
-
js = <<-EOJS
|
22
|
-
<script type="text/javascript" charset="utf-8">
|
23
|
-
$(function(){
|
24
|
-
$( "##{m.field_id_for(c)}" ).autocomplete({source: ["#{values.map{|v|v.to_s.gsub(/"/,'')}.join('","')}"]});
|
25
|
-
});
|
26
|
-
</script>
|
27
|
-
EOJS
|
28
|
-
end
|
29
|
-
tag = "<input type='%s' name='%s' value=\"%s\" id='%s' class='%s' %s />%s\n" % [o[:input_type]||'text', o[:input_name], o[:input_value], m.field_id_for(c), o[:input_class], o[:required]&&'required', o[:required]]
|
30
|
-
"#{tag}#{js}"
|
31
|
-
end,
|
32
|
-
:slug => proc do |m,c,o|
|
33
|
-
crushyform_types[:string].call(m,c,o)
|
34
|
-
end,
|
35
|
-
:price => proc do |m,c,o|
|
36
|
-
value = o[:input_value].to_price_string if o[:input_value].respond_to?(:to_price_string)
|
37
|
-
"<input type='%s' name='%s' value=\"%s\" id='%s' class='%s' %s />%s\n" % [o[:input_type]||'text', o[:input_name], value, m.field_id_for(c), o[:input_class], o[:required]&&'required', o[:required]]
|
38
|
-
end,
|
39
|
-
:boolean => proc do |m,c,o|
|
40
|
-
crushid = m.field_id_for(c)
|
41
|
-
checked = 'checked' if o[:input_value]
|
42
|
-
out = "<input type='hidden' name='%s' value='false' id='%s-off' />\n"
|
43
|
-
out += "<input type='checkbox' name='%s' value='true' id='%s' class='%s' %s />\n"
|
44
|
-
out % [o[:input_name], crushid, o[:input_name], crushid, o[:input_class], checked]
|
45
|
-
end,
|
46
|
-
:text => proc do |m,c,o|
|
47
|
-
"<textarea name='%s' id='%s' class='%s' %s>%s</textarea>%s\n" % [o[:input_name], m.field_id_for(c), o[:input_class], o[:required]&&'required', o[:input_value], o[:required]]
|
48
|
-
end,
|
49
|
-
:date => proc do |m,c,o|
|
50
|
-
o[:input_value] = o[:input_value].strftime("%Y-%m-%d") if o[:input_value].respond_to?(:strftime)
|
51
|
-
o[:required] = "%s Format: yyyy-mm-dd" % [o[:required]]
|
52
|
-
crushyform_types[:string].call(m,c,o)
|
53
|
-
end,
|
54
|
-
:time => proc do |m,c,o|
|
55
|
-
o[:input_value] = o[:input_value].strftime("%T") if o[:input_value].respond_to?(:strftime)
|
56
|
-
o[:required] = "%s Format: hh:mm:ss" % [o[:required]]
|
57
|
-
crushyform_types[:string].call(m,c,o)
|
58
|
-
end,
|
59
|
-
:datetime => proc do |m,c,o|
|
60
|
-
o[:input_value] = o[:input_value].strftime("%Y-%m-%d %T") if o[:input_value].respond_to?(:strftime)
|
61
|
-
o[:required] = "%s Format: yyyy-mm-dd hh:mm:ss" % [o[:required]]
|
62
|
-
crushyform_types[:string].call(m,c,o)
|
63
|
-
end,
|
64
|
-
:parent => proc do |m,c,o|
|
65
|
-
parent_class = o[:parent_class].nil? ? Kernel.const_get(c.sub(/^id_/, '')) : m.resolve_class(o[:parent_class])
|
66
|
-
option_list = parent_class.to_dropdown(o[:input_value])
|
67
|
-
"<select name='%s' id='%s' class='%s'>%s</select>\n" % [o[:input_name], m.field_id_for(c), o[:input_class], option_list]
|
68
|
-
end,
|
69
|
-
:children => proc do |m,c,o|
|
70
|
-
children_class = o[:children_class].nil? ? Kernel.const_get(c.sub(/^ids_/, '')) : m.resolve_class(o[:children_class])
|
71
|
-
opts = o.update({
|
72
|
-
:multiple=>true,
|
73
|
-
:select_options=>children_class.dropdown_cache
|
74
|
-
})
|
75
|
-
@crushyform_types[:select].call(m,c,opts)
|
76
|
-
end,
|
77
|
-
:attachment => proc do |m,c,o|
|
78
|
-
deleter = "<input type='checkbox' name='#{o[:input_name]}' class='deleter' value='nil' /> Delete this file<br />" unless m.doc[c].nil?
|
79
|
-
"%s<input type='file' name='%s' id='%s' class='%s' />%s %s\n" % [m.to_thumb(c), o[:input_name], m.field_id_for(c), o[:input_class], o[:required], deleter]
|
80
|
-
end,
|
81
|
-
:select => proc do |m,c,o|
|
82
|
-
# starter ensures it sends something when multiple is empty
|
83
|
-
# Otherwise it is not sent and therefore not updated
|
84
|
-
starter = if o[:multiple]
|
85
|
-
"<input type='hidden' name='%s[]' value='nil' class='multiple-select-starter' />\n" % [o[:input_name]]
|
86
|
-
else
|
87
|
-
''
|
88
|
-
end
|
89
|
-
out = "%s<select name='%s%s' id='%s' class='%s' %s title='-- Select --'>\n" % [starter, o[:input_name], ('[]' if o[:multiple]), m.field_id_for(c), o[:input_class], ('multiple' if o[:multiple])]
|
90
|
-
o[:select_options] = m.__send__(o[:select_options]) unless o[:select_options].kind_of?(Array)
|
91
|
-
select_options = o[:select_options].dup
|
92
|
-
if (o[:multiple] && !o[:input_value].nil? && o[:input_value].size>1)
|
93
|
-
# This if is for having the selected options ordered (they can be ordered with asm select)
|
94
|
-
o[:input_value].reverse.each do |v|
|
95
|
-
elem = select_options.find{|x| x==v||(x||[])[1]==v }
|
96
|
-
select_options.unshift(select_options.delete(elem)) unless elem.nil?
|
97
|
-
end
|
98
|
-
end
|
99
|
-
if select_options.kind_of?(Array)
|
100
|
-
select_options.each do |op|
|
101
|
-
key,val = op.kind_of?(Array) ? [op[0],op[1]] : [op,op]
|
102
|
-
if key==:optgroup
|
103
|
-
out << "<optgroup label=\"%s\">\n" % [val]
|
104
|
-
elsif key==:closegroup
|
105
|
-
out << "</optgroup>\n"
|
106
|
-
else
|
107
|
-
# Array case is for multiple select
|
108
|
-
selected = 'selected' if (val==o[:input_value] || (o[:input_value].kind_of?(Array)&&o[:input_value].include?(val)))
|
109
|
-
out << "<option value=\"%s\" %s>%s</option>\n" % [val,selected,key]
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
out << "</select>%s\n" % [o[:required]]
|
114
|
-
end,
|
115
|
-
:string_list => proc do |m,c,o|
|
116
|
-
if o[:autocompleted]
|
117
|
-
values = o[:autocomplete_options] || m.class.collection.distinct(c)
|
118
|
-
js = <<-EOJS
|
119
|
-
<script type="text/javascript" charset="utf-8">
|
120
|
-
$(function(){
|
121
|
-
$( "##{m.field_id_for(c)}" )
|
122
|
-
.bind( "keydown", function( event ) {
|
123
|
-
if ( event.keyCode === $.ui.keyCode.TAB &&
|
124
|
-
$( this ).data( "autocomplete" ).menu.active ) {
|
125
|
-
event.preventDefault();
|
126
|
-
}
|
127
|
-
})
|
128
|
-
.autocomplete({
|
129
|
-
minLength: 0,
|
130
|
-
source: function( request, response ) {
|
131
|
-
response($.ui.autocomplete.filter(["#{values.map{|v|v.to_s.gsub(/"/,'')}.join('","')}"], request.term.split(/,\s*/).pop()));
|
132
|
-
},
|
133
|
-
focus: function() { return false; },
|
134
|
-
select: function( event, ui ) {
|
135
|
-
var terms = this.value.split(/,\s*/);
|
136
|
-
terms.pop();
|
137
|
-
terms.push(ui.item.value);
|
138
|
-
terms.push("");
|
139
|
-
this.value = terms.join( ", " );
|
140
|
-
return false;
|
141
|
-
}
|
142
|
-
});
|
143
|
-
});
|
144
|
-
</script>
|
145
|
-
EOJS
|
146
|
-
o[:autocompleted] = false # reset so that it does not autocomplete for :string type below
|
147
|
-
end
|
148
|
-
tag = @crushyform_types[:string].call(m,c,o.update({:input_value=>(o[:input_value]||[]).join(',')}))
|
149
|
-
"#{tag}#{js}"
|
150
|
-
end,
|
151
|
-
:permalink => proc do |instance, column_name, options|
|
152
|
-
values = "<option value=''>Or Browse the list</option>\n"
|
153
|
-
tag = @crushyform_types[:string].call(instance, column_name, options)
|
154
|
-
return tag if options[:permalink_classes].nil?
|
155
|
-
options[:permalink_classes].each do |sym|
|
156
|
-
c = Kernel.const_get sym
|
157
|
-
entries = c.find
|
158
|
-
unless entries.count==0
|
159
|
-
values << "<optgroup label='#{c.human_name}'>\n"
|
160
|
-
entries.each do |e|
|
161
|
-
values << "<option value='#{e.permalink}' #{'selected' if e.permalink==options[:input_value]}>#{e.to_label}</option>\n"
|
162
|
-
end
|
163
|
-
values << "</optgroup>\n"
|
164
|
-
end
|
165
|
-
end
|
166
|
-
"#{tag}<br />\n<select name='__permalink' class='permalink-dropdown'>\n#{values}</select>\n"
|
167
|
-
end
|
168
|
-
}
|
169
|
-
end
|
170
|
-
|
171
|
-
# What represents a required field
|
172
|
-
# Can be overriden
|
173
|
-
def crushyfield_required; "<span class='crushyfield-required'> *</span>"; end
|
174
|
-
# Stolen from ERB
|
175
|
-
def html_escape(s)
|
176
|
-
s.to_s.gsub(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/</, "<")
|
177
|
-
end
|
178
|
-
# Cache dropdown options for children classes to use
|
179
|
-
# Meant to be reseted each time an entry is created, updated or destroyed
|
180
|
-
# So it is only rebuild once required after the list has changed
|
181
|
-
# Maintaining an array and not rebuilding it all might be faster
|
182
|
-
# But it will not happen much so that it is fairly acceptable
|
183
|
-
def to_dropdown(selection=nil, nil_name='** UNDEFINED **')
|
184
|
-
dropdown_cache.inject("<option value=''>#{nil_name}</option>\n") do |out, row|
|
185
|
-
selected = 'selected' if row[1]==selection
|
186
|
-
"%s%s%s%s" % [out, row[2], selected, row[3]]
|
187
|
-
end
|
188
|
-
end
|
189
|
-
def dropdown_cache
|
190
|
-
@dropdown_cache ||= self.find({},:fields=>['_id',label_column]).inject([]) do |out,row|
|
191
|
-
out.push([row.to_label, row.id.to_s, "<option value=\"#{row.id}\" ", ">#{row.to_label}</option>\n"])
|
192
|
-
end
|
193
|
-
end
|
194
|
-
def reset_dropdown_cache; @dropdown_cache = nil; end
|
195
|
-
|
196
|
-
end
|
197
|
-
|
198
|
-
# Instance Methods
|
199
|
-
|
200
|
-
def crushyform(columns=model.schema.keys, action=nil, meth='POST')
|
201
|
-
columns.delete('_id')
|
202
|
-
fields = columns.inject(""){|out,c|out.force_encoding('utf-8')+crushyfield(c).force_encoding('utf-8')}
|
203
|
-
enctype = fields.match(/type='file'/) ? "enctype='multipart/form-data'" : ''
|
204
|
-
action.nil? ? fields : "<form action='%s' method='%s' %s>%s</form>\n" % [action, meth, enctype, fields]
|
205
|
-
end
|
206
|
-
# crushyfield is crushyinput but with label+error
|
207
|
-
def crushyfield(col, o={})
|
208
|
-
return '' if (o[:type]==:none || model.schema[col][:type]==:none)
|
209
|
-
return crushyinput(col,o) if (o[:input_type]=='hidden' || model.schema[col][:input_type]=='hidden')
|
210
|
-
default_field_name = col[/^id_/] ? Kernel.const_get(col.sub(/^id_/, '')).human_name : col.tr('_', ' ').capitalize
|
211
|
-
field_name = o[:name] || model.schema[col][:name] || default_field_name
|
212
|
-
if field_name.is_a?(Proc)
|
213
|
-
field_name = field_name.(self)
|
214
|
-
end
|
215
|
-
error_list = errors_on(col).map{|e|" - #{e}"} if !errors_on(col).nil?
|
216
|
-
"<p class='crushyfield %s'><label for='%s'>%s</label><span class='crushyfield-error-list'>%s</span><br />\n%s</p>\n" % [error_list&&'crushyfield-error', field_id_for(col), field_name, error_list, crushyinput(col, o)]
|
217
|
-
end
|
218
|
-
def crushyinput(col, o={})
|
219
|
-
o = model.schema[col].dup.update(o)
|
220
|
-
o[:input_name] ||= "model[#{col}]"
|
221
|
-
o[:input_value] = o[:input_value].nil? ? self[col] : o[:input_value]
|
222
|
-
o[:input_value] = model.html_escape(o[:input_value]) if (o[:input_value].is_a?(String) && o[:html_escape]!=false)
|
223
|
-
o[:required] = o[:required]==true ? model.crushyfield_required : o[:required]
|
224
|
-
crushyform_type = model.crushyform_types[o[:type]] || model.crushyform_types[:string]
|
225
|
-
crushyform_type.call(self,col,o)
|
226
|
-
end
|
227
|
-
# Provide a thumbnail for the column
|
228
|
-
def to_thumb(c)
|
229
|
-
current = @doc[c]
|
230
|
-
if current.respond_to?(:[])
|
231
|
-
"<img src='/gridfs/#{@doc[c]['stash_thumb_gif']}' width='100' onerror=\"this.style.display='none'\" alt='Thumb' />\n"
|
232
|
-
end
|
233
|
-
end
|
234
|
-
# Reset dropdowns on hooks
|
235
|
-
def after_save; model.reset_dropdown_cache; super; end
|
236
|
-
def after_delete; model.reset_dropdown_cache; super; end
|
237
|
-
# Fix types
|
238
|
-
def fix_type_string_list(k,v); @doc[k] = v.to_s.strip.split(/\s*,\s*/).compact if v.is_a?(String); end
|
239
|
-
|
240
|
-
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|
@@ -1,324 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
module PopulateMe
|
3
|
-
module Mongo
|
4
|
-
module Mutation
|
5
|
-
|
6
|
-
# Most important MongoDB module
|
7
|
-
# It defines the ODM
|
8
|
-
|
9
|
-
def self.included(weak)
|
10
|
-
weak.extend(MutateClass)
|
11
|
-
weak.db = DB if defined?(DB)
|
12
|
-
weak.schema = {}
|
13
|
-
weak.relationships = {}
|
14
|
-
end
|
15
|
-
|
16
|
-
module MutateClass
|
17
|
-
attr_accessor :db, :schema, :relationships
|
18
|
-
attr_writer :label_column, :slug_column, :sorting_order
|
19
|
-
|
20
|
-
LABEL_COLUMNS = ['title', 'label', 'fullname', 'full_name', 'surname', 'lastname', 'last_name', 'name', 'firstname', 'first_name', 'login', 'caption', 'reference', 'file_name', 'body', '_id']
|
21
|
-
def label_column; @label_column ||= LABEL_COLUMNS.find{|c| @schema.keys.include?(c)||c=='_id'}; end
|
22
|
-
def slug_column; @slug_column ||= (@schema.find{|k,v| v[:type]==:slug}||[])[0]; end
|
23
|
-
def foreign_key_name(plural=false); "id#{'s' if plural}_"+self.name; end
|
24
|
-
def human_name; self.name.gsub(/([A-Z])/, ' \1')[1..-1]; end
|
25
|
-
def human_plural_name; human_name+'s'; end
|
26
|
-
def collection; db[self.name]; end
|
27
|
-
def correct_id_class(id)
|
28
|
-
if id.is_a?(String)&&BSON::ObjectId.legal?(id)
|
29
|
-
return BSON::ObjectId.from_string(id)
|
30
|
-
elsif !id.is_a?(BSON::ObjectId)
|
31
|
-
return ''
|
32
|
-
end
|
33
|
-
id
|
34
|
-
end
|
35
|
-
def ref(id)
|
36
|
-
{'_id' => (id.kind_of?(Array) ? {'$in'=> id.map{|i|correct_id_class(i)} } : correct_id_class(id)) }
|
37
|
-
end
|
38
|
-
def find(selector={},opts={})
|
39
|
-
selector.update(opts.delete(:selector)||{})
|
40
|
-
opts = {:sort=>self.sorting_order}.update(opts)
|
41
|
-
if opts.key?(:fields)
|
42
|
-
opts[:projection] = opts[:fields].inject({}) do |h, f|
|
43
|
-
h[f.to_sym] = 1
|
44
|
-
h
|
45
|
-
end
|
46
|
-
opts.delete(:fields)
|
47
|
-
end
|
48
|
-
cur = collection.find(selector,opts)
|
49
|
-
cur.instance_variable_set('@mutant_class', self)
|
50
|
-
cur.extend(CursorMutation)
|
51
|
-
end
|
52
|
-
def find_one(spec_or_object_id=nil,opts={})
|
53
|
-
spec_or_object_id.nil? ? spec_or_object_id = opts.delete(:selector) : spec_or_object_id.update(opts.delete(:selector)||{})
|
54
|
-
opts = {:sort=>self.sorting_order}.update(opts)
|
55
|
-
item = collection.find(spec_or_object_id,opts).first
|
56
|
-
item.nil? ? nil : self.new(item)
|
57
|
-
end
|
58
|
-
def count(opts={}); collection.count(opts); end
|
59
|
-
|
60
|
-
def sorting_order
|
61
|
-
@sorting_order ||= if @schema.key?('position')&&!@schema['position'][:scope].nil?
|
62
|
-
{@schema['position'][:scope] => 1, 'position' => 1}
|
63
|
-
elsif @schema.key?('position')
|
64
|
-
{'position' => 1, '_id' => 1}
|
65
|
-
else
|
66
|
-
{'_id' => 1}
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def sort(ids)
|
71
|
-
requests = ids.each_with_index.inject([]) do |list, (id, i)|
|
72
|
-
list << {update_one:
|
73
|
-
{
|
74
|
-
filter: ref(id),
|
75
|
-
update: {'$set'=>{'position'=>i}}
|
76
|
-
}
|
77
|
-
}
|
78
|
-
end
|
79
|
-
collection.bulk_write requests
|
80
|
-
end
|
81
|
-
|
82
|
-
# CRUD
|
83
|
-
def get(id, opts={}); doc = collection.find(ref(id), opts).first; doc.nil? ? nil : self.new(doc); end
|
84
|
-
def delete(id); collection.delete_one(ref(id)); end
|
85
|
-
|
86
|
-
def get_multiple(ids, opts={})
|
87
|
-
corrected_ids = ids.map{|id| correct_id_class(id) }
|
88
|
-
sort_proc = proc{ |a,b| corrected_ids.index(a['_id'])<=>corrected_ids.index(b['_id']) }
|
89
|
-
self.find(ref(corrected_ids), opts).to_a.sort(&sort_proc)
|
90
|
-
end
|
91
|
-
|
92
|
-
def is_unique(doc={})
|
93
|
-
return unless collection.count==0
|
94
|
-
self.new(doc).save
|
95
|
-
end
|
96
|
-
|
97
|
-
private
|
98
|
-
def slot(name,opts={})
|
99
|
-
@schema[name] = {:type=>:string}.update(opts)
|
100
|
-
define_method(name) { @doc[name] }
|
101
|
-
define_method("#{name}=") { |x| @doc[name] = x }
|
102
|
-
end
|
103
|
-
def image_slot(name='image',opts={})
|
104
|
-
slot name, {:type=>:attachment}.update(opts)
|
105
|
-
slot "#{name}_tooltip"
|
106
|
-
slot "#{name}_alternative_text"
|
107
|
-
end
|
108
|
-
def has_many(k,opts={}); @relationships[k] = opts; end
|
109
|
-
end
|
110
|
-
|
111
|
-
# Instance Methods
|
112
|
-
|
113
|
-
attr_accessor :doc, :old_doc, :errors, :is_new
|
114
|
-
def initialize(document=nil); @errors={}; @doc = document || default_doc; end
|
115
|
-
def default_doc
|
116
|
-
@is_new = true
|
117
|
-
out = {}
|
118
|
-
model.schema.each { |k,v| out.store(k,v[:default].is_a?(Proc) ? v[:default].call : v[:default]) }
|
119
|
-
out
|
120
|
-
end
|
121
|
-
def model; self.class; end
|
122
|
-
def id; @doc['_id']; end
|
123
|
-
def [](field); @doc[field]; end
|
124
|
-
def []=(field,val); @doc[field] = val; end
|
125
|
-
def to_label; @doc[model.label_column].to_s.tr("\n\r", ' '); end
|
126
|
-
ACCENTS_FROM =
|
127
|
-
"ÀÁÂÃÄÅàáâãäåĀāĂ㥹ÇçĆćĈĉĊċČčÐðĎďĐđÈÉÊËèéêëĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħÌÍÎÏìíîïĨĩĪīĬĭĮįİıĴĵĶķĸĹĺĻļĽľĿŀŁłÑñŃńŅņŇňʼnŊŋÒÓÔÕÖØòóôõöøŌōŎŏŐőŔŕŖŗŘřŚśŜŝŞ"
|
128
|
-
ACCENTS_TO =
|
129
|
-
"AAAAAAaaaaaaAaAaAaCcCcCcCcCcDdDdDdEEEEeeeeEeEeEeEeEeGgGgGgGgHhHhIIIIiiiiIiIiIiIiIiJjKkkLlLlLlLlLlNnNnNnNnnNnOOOOOOooooooOoOoOoRrRrRrSsSsSsSssT"
|
130
|
-
def auto_slug
|
131
|
-
s = self.to_label.tr(ACCENTS_FROM,ACCENTS_TO).tr(' .,;:?!/\'"()[]{}<>','-').gsub(/&/, 'and').gsub(/-+/,'-').gsub(/(^-|-$)/,'')
|
132
|
-
defined?(::Rack::Utils) ? ::Rack::Utils.escape(s) : s
|
133
|
-
end
|
134
|
-
def to_slug; @doc[model.slug_column]||self.auto_slug; end
|
135
|
-
# To param will be deprecated
|
136
|
-
# Use a URL like .../<id>/<slug> instead
|
137
|
-
def to_param; "#{@doc['_id']}-#{to_label.scan(/\w+/).join('-')}"; end
|
138
|
-
def field_id_for(col); "%s-%s-%s" % [id||'new',model.name,col]; end
|
139
|
-
|
140
|
-
# relationships
|
141
|
-
def resolve_class(k); k.kind_of?(Class) ? k : Kernel.const_get(k); end
|
142
|
-
def parent(k, opts={})
|
143
|
-
if k.kind_of?(String)
|
144
|
-
key = k
|
145
|
-
klass = resolve_class(model.schema[k][:parent_class])
|
146
|
-
else
|
147
|
-
klass = resolve_class(k)
|
148
|
-
key = klass.foreign_key_name
|
149
|
-
end
|
150
|
-
klass.get(@doc[key], opts)
|
151
|
-
end
|
152
|
-
def slot_children(k, opts={})
|
153
|
-
if k.kind_of?(String)
|
154
|
-
key = k
|
155
|
-
klass = resolve_class(model.schema[k][:children_class])
|
156
|
-
else
|
157
|
-
klass = resolve_class(k)
|
158
|
-
key = klass.foreign_key_name(true)
|
159
|
-
end
|
160
|
-
klass.get_multiple((@doc[key]||[]), opts)
|
161
|
-
end
|
162
|
-
def first_slot_child(k, opts={})
|
163
|
-
if k.kind_of?(String)
|
164
|
-
key = k
|
165
|
-
klass = resolve_class(model.schema[k][:children_class])
|
166
|
-
else
|
167
|
-
klass = resolve_class(k)
|
168
|
-
key = klass.foreign_key_name(true)
|
169
|
-
end
|
170
|
-
klass.get((@doc[key]||[])[0], opts)
|
171
|
-
end
|
172
|
-
def children(k,opts={})
|
173
|
-
k = resolve_class(k)
|
174
|
-
slot_name = opts.delete(:slot_name) || model.foreign_key_name
|
175
|
-
k.find({slot_name=>@doc['_id'].to_s}, opts)
|
176
|
-
end
|
177
|
-
def first_child(k,opts={})
|
178
|
-
k = resolve_class(k)
|
179
|
-
slot_name = opts.delete(:slot_name) || model.foreign_key_name
|
180
|
-
d = k.find_one({slot_name=>@doc['_id'].to_s}, opts)
|
181
|
-
end
|
182
|
-
def children_count(k,sel={})
|
183
|
-
k = resolve_class(k)
|
184
|
-
slot_name = sel.delete(:slot_name) || model.foreign_key_name
|
185
|
-
k.collection.count({slot_name=>@doc['_id'].to_s}.update(sel))
|
186
|
-
end
|
187
|
-
|
188
|
-
# CRUD
|
189
|
-
def delete
|
190
|
-
before_delete
|
191
|
-
model.delete(@doc['_id'])
|
192
|
-
after_delete
|
193
|
-
end
|
194
|
-
|
195
|
-
# saving and hooks
|
196
|
-
def new?; @is_new ||= !@doc.key?('_id'); end
|
197
|
-
def update_doc(fields)
|
198
|
-
@old_doc = @doc.dup
|
199
|
-
@doc.update(fields)
|
200
|
-
@is_new = false
|
201
|
-
self
|
202
|
-
end
|
203
|
-
# Getter and setter in one
|
204
|
-
def errors_on(col,message=nil)
|
205
|
-
message.nil? ? @errors[col] : @errors[col] = (@errors[col]||[]) << message
|
206
|
-
end
|
207
|
-
def before_delete; @old_doc = @doc.dup; end
|
208
|
-
alias before_destroy before_delete
|
209
|
-
def after_delete
|
210
|
-
model.relationships.each do |k,v|
|
211
|
-
Kernel.const_get(k).find({model.foreign_key_name=>@old_doc['_id'].to_s}).each{|m| m.delete} unless v[:independent]
|
212
|
-
end
|
213
|
-
end
|
214
|
-
alias after_destroy after_delete
|
215
|
-
def valid?
|
216
|
-
before_validation
|
217
|
-
validate
|
218
|
-
after_validation
|
219
|
-
@errors.empty?
|
220
|
-
end
|
221
|
-
def before_validation
|
222
|
-
@errors = {}
|
223
|
-
@doc.each do |k,v|
|
224
|
-
next unless model.schema.key?(k)
|
225
|
-
type = k=='_id' ? :primary_key : model.schema[k][:type]
|
226
|
-
fix_method = "fix_type_#{type}"
|
227
|
-
if v=='' and type!=:attachment
|
228
|
-
default = model.schema[k][:default]
|
229
|
-
@doc[k] = default.is_a?(Proc) ? default.call : default
|
230
|
-
else
|
231
|
-
self.__send__(fix_method, k, v) if self.respond_to?(fix_method)
|
232
|
-
end
|
233
|
-
end
|
234
|
-
end
|
235
|
-
def validate; end
|
236
|
-
def after_validation; end
|
237
|
-
def fix_type_integer(k,v); @doc[k] = v.to_i; end
|
238
|
-
def fix_type_price(k,v)
|
239
|
-
@doc[k] = v.respond_to?(:to_price_integer) ? v.to_price_integer : v
|
240
|
-
end
|
241
|
-
def fix_type_boolean(k,v); @doc[k] = (v=='true'||v==true) ? true : false; end
|
242
|
-
def fix_type_slug(k,v); @doc[k] = self.auto_slug if v.to_s==''; end
|
243
|
-
def fix_type_date(k,v)
|
244
|
-
if v.is_a?(String)
|
245
|
-
if v[/\d\d\d\d-\d\d-\d\d/]
|
246
|
-
@doc[k] = ::Time.utc(*v.split('-'))
|
247
|
-
else
|
248
|
-
default = model.schema[k][:default]
|
249
|
-
@doc[k] = default.is_a?(Proc) ? default.call : default
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
def fix_type_datetime(k,v)
|
254
|
-
if v.is_a?(String)
|
255
|
-
if v[/\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/]
|
256
|
-
@doc[k] = ::Time.utc(*v.split(/[-:\s]/))
|
257
|
-
else
|
258
|
-
default = model.schema[k][:default]
|
259
|
-
@doc[k] = default.is_a?(Proc) ? default.call : default
|
260
|
-
end
|
261
|
-
end
|
262
|
-
end
|
263
|
-
def fix_type_select(k,v)
|
264
|
-
if v.is_a?(Array)
|
265
|
-
@doc[k] = v - ['nil']
|
266
|
-
end
|
267
|
-
end
|
268
|
-
def fix_type_children(k,v)
|
269
|
-
self.fix_type_select(k,v)
|
270
|
-
end
|
271
|
-
|
272
|
-
def save
|
273
|
-
return nil unless valid?
|
274
|
-
before_save
|
275
|
-
if new?
|
276
|
-
before_create
|
277
|
-
result = model.collection.insert_one(@doc)
|
278
|
-
if result.ok? and @doc['_id'].nil?
|
279
|
-
@doc['_id'] = result.inserted_id
|
280
|
-
end
|
281
|
-
after_create
|
282
|
-
else
|
283
|
-
before_update
|
284
|
-
result = model.collection.update_one({'_id'=>@doc['_id']}, @doc)
|
285
|
-
after_update
|
286
|
-
end
|
287
|
-
after_save
|
288
|
-
result.ok? ? self : nil
|
289
|
-
end
|
290
|
-
def before_save; end
|
291
|
-
def before_create; end
|
292
|
-
def before_update; end
|
293
|
-
def after_save; end
|
294
|
-
def after_create; @is_new = false; end
|
295
|
-
def after_update; end
|
296
|
-
|
297
|
-
# ==========
|
298
|
-
# = Cursor =
|
299
|
-
# ==========
|
300
|
-
module CursorMutation
|
301
|
-
# Extend the cursor provided by the Ruby MongoDB driver
|
302
|
-
# We must keep the regular cursor
|
303
|
-
# so we should extend on demand.
|
304
|
-
# Meaning the cursor object should be extended, not the cursor class.
|
305
|
-
# @mutant_class should be defined before extending
|
306
|
-
#
|
307
|
-
# def next
|
308
|
-
# n = super
|
309
|
-
# n.nil? ? nil : @mutant_class.new(n)
|
310
|
-
# end
|
311
|
-
#
|
312
|
-
def each
|
313
|
-
super do |doc|
|
314
|
-
yield @mutant_class.new(doc)
|
315
|
-
end if block_given?
|
316
|
-
end
|
317
|
-
# legacy
|
318
|
-
def each_mutant(&b); each(&b); end
|
319
|
-
def each_mutant_with_index(&b); each_with_index(&b); end
|
320
|
-
end
|
321
|
-
|
322
|
-
end
|
323
|
-
end
|
324
|
-
end
|