livelist-rails 0.0.11 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -3,3 +3,4 @@
3
3
  .bundle
4
4
  Gemfile.lock
5
5
  pkg/*
6
+ coverage
data/.rspec CHANGED
@@ -1,2 +1,2 @@
1
1
  --color
2
- --format progress
2
+ --format documentation
@@ -1,3 +1,3 @@
1
- //= require mustache
1
+ //= require mustache.min
2
2
  //= require underscore-min
3
3
  //= require livelist
@@ -1,5 +1,5 @@
1
1
  class window.Utilities
2
- setOptions: (options, context=@) =>
2
+ setOptions: (options, context = @) =>
3
3
  _.each( options, (value, option) => context[option] = value )
4
4
 
5
5
  class window.LiveList extends Utilities
@@ -7,8 +7,9 @@ class window.LiveList extends Utilities
7
7
  @listSelector = options.list.renderTo
8
8
  @resourceName = options.global.resourceName
9
9
  @resourceNameSingular = options.global.resourceNameSingular
10
+ @urlPrefix = options.global.urlPrefix || "/#{@resourceName}"
11
+ @httpMethod = options.global.httpMethod || 'get'
10
12
  @eventName = "livelist:#{@resourceName}"
11
- @urlPrefix = "/#{@resourceName}"
12
13
  @search = new Search(options.search, @)
13
14
  @filters = new Filters(options.filters, @)
14
15
  @pagination = new Pagination(options.pagination, @)
@@ -65,7 +66,7 @@ class window.List extends Utilities
65
66
  $(@renderTo).html( listHTML )
66
67
  @removeFetchingIndication()
67
68
 
68
- window.LiveList.version = '0.0.5'
69
+ window.LiveList.version = '0.0.7'
69
70
 
70
71
  class window.Filters extends Utilities
71
72
  constructor: (options, livelist) ->
@@ -29,8 +29,9 @@
29
29
  this.listSelector = options.list.renderTo;
30
30
  this.resourceName = options.global.resourceName;
31
31
  this.resourceNameSingular = options.global.resourceNameSingular;
32
+ this.urlPrefix = options.global.urlPrefix || ("/" + this.resourceName);
33
+ this.httpMethod = options.global.httpMethod || 'get';
32
34
  this.eventName = "livelist:" + this.resourceName;
33
- this.urlPrefix = "/" + this.resourceName;
34
35
  this.search = new Search(options.search, this);
35
36
  this.filters = new Filters(options.filters, this);
36
37
  this.pagination = new Pagination(options.pagination, this);
@@ -114,7 +115,7 @@
114
115
 
115
116
  })(Utilities);
116
117
 
117
- window.LiveList.version = '0.0.5';
118
+ window.LiveList.version = '0.0.7';
118
119
 
119
120
  window.Filters = (function(_super) {
120
121
 
@@ -1 +1 @@
1
- ((function(){var a=function(a,b){return function(){return a.apply(b,arguments)}},b=Object.prototype.hasOwnProperty,c=function(a,c){function e(){this.constructor=a}for(var d in c)b.call(c,d)&&(a[d]=c[d]);return e.prototype=c.prototype,a.prototype=new e,a.__super__=c.prototype,a};window.Utilities=function(){function b(){this.setOptions=a(this.setOptions,this)}return b.prototype.setOptions=function(a,b){var c=this;return b==null&&(b=this),_.each(a,function(a,c){return b[c]=a})},b}(),window.LiveList=function(a){function b(a){this.listSelector=a.list.renderTo,this.resourceName=a.global.resourceName,this.resourceNameSingular=a.global.resourceNameSingular,this.eventName="livelist:"+this.resourceName,this.urlPrefix="/"+this.resourceName,this.search=new Search(a.search,this),this.filters=new Filters(a.filters,this),this.pagination=new Pagination(a.pagination,this),this.list=new List(a.list,this)}return c(b,a),b}(Utilities),window.List=function(b){function d(b,c){this.renderIndex=a(this.renderIndex,this),this.removeFetchingIndication=a(this.removeFetchingIndication,this),this.displayFetchingIndication=a(this.displayFetchingIndication,this);var d=this;this.fetchRequest=null,this.livelist=c,this.listTemplate="{{#"+this.livelist.resourceName+"}}{{>"+this.livelist.resourceNameSingular+"}}{{/"+this.livelist.resourceName+"}}",this.listItemTemplate="<li>{{id}}</li>",this.fetchingIndicationClass="updating",this.renderTo="ul#"+this.livelist.resourceName,this.setOptions(b),$(this.renderTo).bind(this.livelist.eventName,function(a,b){return d.fetch({presets:null,page:b!=null?b.page:void 0})}),this.fetch({presets:this.livelist.filters.getPresets()})}return c(d,b),d.prototype.displayFetchingIndication=function(){return $(this.renderTo).addClass(this.fetchingIndicationClass)},d.prototype.removeFetchingIndication=function(){return $(this.renderTo).removeClass(this.fetchingIndicationClass)},d.prototype.renderIndex=function(a,b,c){return this.livelist.data=a,this.render(),this.livelist.pagination.render(this.livelist.data),this.livelist.filters.render(this.livelist.data)},d.prototype.fetch=function(a){var b,c;return this.fetchRequest&&this.fetchRequest.abort(),c=this.livelist.search.searchTerm(),b={},b.filters=this.livelist.filters.setPresets(a.presets),c&&(b.q=c),a.page&&(b.page=a.page),this.fetchRequest=$.ajax({url:this.livelist.urlPrefix,type:this.livelist.httpMethod,dataType:"json",data:b,beforeSend:this.displayFetchingIndication,success:this.renderIndex})},d.prototype.render=function(){var a,b;return b={},b[this.livelist.resourceNameSingular]=this.listItemTemplate,a=Mustache.to_html(this.listTemplate,this.livelist.data,b),$(this.renderTo).html(a),this.removeFetchingIndication()},d}(Utilities),window.LiveList.version="0.0.5",window.Filters=function(b){function d(b,c){this.handleAdvancedOptionsClick=a(this.handleAdvancedOptionsClick,this);var d=this;this.livelist=c,this.filters=b.presets?_.keys(b.presets):[],this.initializeCookies(),this.setOptions(b),$("input.filter_option",this.renderTo).live("change",function(){return $(d.livelist.listSelector).trigger(d.livelist.eventName)}),$(this.advancedOptionsToggleSelector).click(this.handleAdvancedOptionsClick)}return c(d,b),d.prototype.initializeCookies=function(){if(jQuery.cookie&&this.useCookies&&this.cookieName)return this.cookieName="livelist_filter_presets"},d.prototype.getPresets=function(){var a;return jQuery.cookie&&this.useCookies&&(a=jQuery.cookie(this.cookieName)),this.useCookies&&a?JSON.parse(a):this.presets},d.prototype.setPresets=function(a){var b;return b={},jQuery.isEmptyObject(a)?(b=this.selections(),jQuery.cookie&&this.setCookie(b)):b=a,b},d.prototype.setCookie=function(a){if(!jQuery.isEmptyObject(a))return jQuery.cookie(this.cookieName,JSON.stringify(a))},d.prototype.template="{{#filters}}\n<div class='filter'>\n <h3>\n {{name}}\n </h3>\n <ul id='{{filter_slug}}_filter_options'>\n {{#options}}\n <label>\n <li>\n <input {{#selected}}checked='checked'{{/selected}}\n class='left filter_option'\n id='filter_{{slug}}'\n name='filters[]'\n type='checkbox'\n value='{{value}}' />\n <div class='left filter_name'>{{name}}</div>\n <div class='right filter_count'>{{count}}</div>\n <div class='clear'></div>\n </li>\n </label>\n {{/options}}\n </ul>\n</div>\n{{/filters}}",d.prototype.selections=function(){var a,b=this;return a={},_.each(this.filters,function(b){return a[b]=_.pluck($("#"+b+"_filter_options input.filter_option:checked"),"value")}),a},d.prototype.noFiltersSelected=function(a){return _.all(a.filters,function(a){return _.all(a.options,function(a){return!a.selected})})},d.prototype.sortOptions=function(a){return _.map(a,function(a){return a.options=_.sortBy(a.options,function(a){return a.name}),a})},d.prototype.sort=function(a){return _.sortBy(a,function(a){return a.name})},d.prototype.render=function(a){var b;this.filters=_.pluck(a.filters,"filter_slug"),this.sort(a.filters),this.sortOptions(a.filters),b=Mustache.to_html(this.template,a),$(this.renderTo).html(b);if(this.noFiltersSelected(a)&&a[this.livelist.resourceName].length>0)return $('input[type="checkbox"]',this.renderTo).attr("checked","checked")},d.prototype.handleAdvancedOptionsClick=function(a){return a.preventDefault(),$(this.renderTo).slideToggle()},d}(Utilities),window.Pagination=function(b){function d(b,c){this.handlePaginationLinkClick=a(this.handlePaginationLinkClick,this),this.livelist=c,this.pagination=null,this.maxPages=30,this.emptyListMessage="<p>No "+this.livelist.resourceName+" matched your filter criteria</p>",this.setOptions(b),$(""+this.renderTo+" a").live("click",function(a){return a.preventDefault()}),$(""+this.renderTo+" li:not(.disabled) a").live("click",this.handlePaginationLinkClick)}return c(d,b),d.prototype.template="{{#isEmpty}}\n {{{emptyListMessage}}}\n{{/isEmpty}}\n{{^isEmpty}}\n<div class=\"pagination\">\n <ul>\n <li class=\"{{^previousPage}}disabled{{/previousPage}}\">\n <a href='{{urlPrefix}}?page={{previousPage}}' data-page='{{previousPage}}'>← Previous</a>\n </li>\n\n {{#pages}}\n <li class=\"{{#currentPage}}active disabled{{/currentPage}}\">\n <a href='{{urlPrefix}}?page={{page}}' data-page='{{page}}'>{{page}}</a>\n </li>\n {{/pages}}\n\n <li class=\"{{^nextPage}}disabled{{/nextPage}}\">\n <a href='{{urlPrefix}}?page={{nextPage}}' data-page='{{nextPage}}'>Next →</a>\n </li>\n </ul>\n</div>\n{{/isEmpty}}",d.prototype.pagesJSON=function(a,b){var c,d,e,f,g,h;return d=Math.floor(this.maxPages/2),c=a<=d?1:a-d,f=c+d*2-1,e=f>=b?b:f,_.map(function(){h=[];for(var a=c;c<=e?a<=e:a>=e;c<=e?a++:a--)h.push(a);return h}.apply(this),function(b){return{page:b,currentPage:a===b}})},d.prototype.paginationJSON=function(a){return{isEmpty:a.total_pages===0,emptyListMessage:this.emptyListMessage,currentPage:a.current_page,nextPage:a.next_page,previousPage:a.previous_page,urlPrefix:this.livelist.urlPrefix,pages:this.pagesJSON(a.current_page,a.total_pages)}},d.prototype.render=function(a){var b;return this.pagination=this.paginationJSON(a.pagination),b=Mustache.to_html(this.template,this.pagination),$(this.renderTo).html(b)},d.prototype.handlePaginationLinkClick=function(a){return a.preventDefault(),$(this.livelist.listSelector).trigger(this.livelist.eventName,{page:$(a.target).data("page")})},d}(Utilities),window.Search=function(b){function d(b,c){this.handleSearchFormSubmit=a(this.handleSearchFormSubmit,this);var d=this;this.livelist=c,this.setOptions(b),$(this.formSelector).submit(function(a){return d.handleSearchFormSubmit(a)})}return c(d,b),d.prototype.searchTerm=function(){var a;return a=$(this.searchTextInputSelector).val(),!a||a===""?null:a},d.prototype.handleSearchFormSubmit=function(a){return a.preventDefault(),$(this.livelist.listSelector).trigger(this.livelist.eventName)},d}(Utilities)})).call(this);
1
+ ((function(){var a=function(a,b){return function(){return a.apply(b,arguments)}},b=Object.prototype.hasOwnProperty,c=function(a,c){function e(){this.constructor=a}for(var d in c)b.call(c,d)&&(a[d]=c[d]);return e.prototype=c.prototype,a.prototype=new e,a.__super__=c.prototype,a};window.Utilities=function(){function b(){this.setOptions=a(this.setOptions,this)}return b.prototype.setOptions=function(a,b){var c=this;return b==null&&(b=this),_.each(a,function(a,c){return b[c]=a})},b}(),window.LiveList=function(a){function b(a){this.listSelector=a.list.renderTo,this.resourceName=a.global.resourceName,this.resourceNameSingular=a.global.resourceNameSingular,this.urlPrefix=a.global.urlPrefix||"/"+this.resourceName,this.httpMethod=a.global.httpMethod||"get",this.eventName="livelist:"+this.resourceName,this.search=new Search(a.search,this),this.filters=new Filters(a.filters,this),this.pagination=new Pagination(a.pagination,this),this.list=new List(a.list,this)}return c(b,a),b}(Utilities),window.List=function(b){function d(b,c){this.renderIndex=a(this.renderIndex,this),this.removeFetchingIndication=a(this.removeFetchingIndication,this),this.displayFetchingIndication=a(this.displayFetchingIndication,this);var d=this;this.fetchRequest=null,this.livelist=c,this.listTemplate="{{#"+this.livelist.resourceName+"}}{{>"+this.livelist.resourceNameSingular+"}}{{/"+this.livelist.resourceName+"}}",this.listItemTemplate="<li>{{id}}</li>",this.fetchingIndicationClass="updating",this.renderTo="ul#"+this.livelist.resourceName,this.setOptions(b),$(this.renderTo).bind(this.livelist.eventName,function(a,b){return d.fetch({presets:null,page:b!=null?b.page:void 0})}),this.fetch({presets:this.livelist.filters.getPresets()})}return c(d,b),d.prototype.displayFetchingIndication=function(){return $(this.renderTo).addClass(this.fetchingIndicationClass)},d.prototype.removeFetchingIndication=function(){return $(this.renderTo).removeClass(this.fetchingIndicationClass)},d.prototype.renderIndex=function(a,b,c){return this.livelist.data=a,this.render(),this.livelist.pagination.render(this.livelist.data),this.livelist.filters.render(this.livelist.data)},d.prototype.fetch=function(a){var b,c;return this.fetchRequest&&this.fetchRequest.abort(),c=this.livelist.search.searchTerm(),b={},b.filters=this.livelist.filters.setPresets(a.presets),c&&(b.q=c),a.page&&(b.page=a.page),this.fetchRequest=$.ajax({url:this.livelist.urlPrefix,type:this.livelist.httpMethod,dataType:"json",data:b,beforeSend:this.displayFetchingIndication,success:this.renderIndex})},d.prototype.render=function(){var a,b;return b={},b[this.livelist.resourceNameSingular]=this.listItemTemplate,a=Mustache.to_html(this.listTemplate,this.livelist.data,b),$(this.renderTo).html(a),this.removeFetchingIndication()},d}(Utilities),window.LiveList.version="0.0.7",window.Filters=function(b){function d(b,c){this.handleAdvancedOptionsClick=a(this.handleAdvancedOptionsClick,this);var d=this;this.livelist=c,this.filters=b.presets?_.keys(b.presets):[],this.initializeCookies(),this.setOptions(b),$("input.filter_option",this.renderTo).live("change",function(){return $(d.livelist.listSelector).trigger(d.livelist.eventName)}),$(this.advancedOptionsToggleSelector).click(this.handleAdvancedOptionsClick)}return c(d,b),d.prototype.initializeCookies=function(){if(jQuery.cookie&&this.useCookies&&this.cookieName)return this.cookieName="livelist_filter_presets"},d.prototype.getPresets=function(){var a;return jQuery.cookie&&this.useCookies&&(a=jQuery.cookie(this.cookieName)),this.useCookies&&a?JSON.parse(a):this.presets},d.prototype.setPresets=function(a){var b;return b={},jQuery.isEmptyObject(a)?(b=this.selections(),jQuery.cookie&&this.setCookie(b)):b=a,b},d.prototype.setCookie=function(a){if(!jQuery.isEmptyObject(a))return jQuery.cookie(this.cookieName,JSON.stringify(a))},d.prototype.template="{{#filters}}\n<div class='filter'>\n <h3>\n {{name}}\n </h3>\n <ul id='{{filter_slug}}_filter_options'>\n {{#options}}\n <label>\n <li>\n <input {{#selected}}checked='checked'{{/selected}}\n class='left filter_option'\n id='filter_{{slug}}'\n name='filters[]'\n type='checkbox'\n value='{{value}}' />\n <div class='left filter_name'>{{name}}</div>\n <div class='right filter_count'>{{count}}</div>\n <div class='clear'></div>\n </li>\n </label>\n {{/options}}\n </ul>\n</div>\n{{/filters}}",d.prototype.selections=function(){var a,b=this;return a={},_.each(this.filters,function(b){return a[b]=_.pluck($("#"+b+"_filter_options input.filter_option:checked"),"value")}),a},d.prototype.noFiltersSelected=function(a){return _.all(a.filters,function(a){return _.all(a.options,function(a){return!a.selected})})},d.prototype.sortOptions=function(a){return _.map(a,function(a){return a.options=_.sortBy(a.options,function(a){return a.name}),a})},d.prototype.sort=function(a){return _.sortBy(a,function(a){return a.name})},d.prototype.render=function(a){var b;this.filters=_.pluck(a.filters,"filter_slug"),this.sort(a.filters),this.sortOptions(a.filters),b=Mustache.to_html(this.template,a),$(this.renderTo).html(b);if(this.noFiltersSelected(a)&&a[this.livelist.resourceName].length>0)return $('input[type="checkbox"]',this.renderTo).attr("checked","checked")},d.prototype.handleAdvancedOptionsClick=function(a){return a.preventDefault(),$(this.renderTo).slideToggle()},d}(Utilities),window.Pagination=function(b){function d(b,c){this.handlePaginationLinkClick=a(this.handlePaginationLinkClick,this),this.livelist=c,this.pagination=null,this.maxPages=30,this.emptyListMessage="<p>No "+this.livelist.resourceName+" matched your filter criteria</p>",this.setOptions(b),$(""+this.renderTo+" a").live("click",function(a){return a.preventDefault()}),$(""+this.renderTo+" li:not(.disabled) a").live("click",this.handlePaginationLinkClick)}return c(d,b),d.prototype.template="{{#isEmpty}}\n {{{emptyListMessage}}}\n{{/isEmpty}}\n{{^isEmpty}}\n<div class=\"pagination\">\n <ul>\n <li class=\"{{^previousPage}}disabled{{/previousPage}}\">\n <a href='{{urlPrefix}}?page={{previousPage}}' data-page='{{previousPage}}'>← Previous</a>\n </li>\n\n {{#pages}}\n <li class=\"{{#currentPage}}active disabled{{/currentPage}}\">\n <a href='{{urlPrefix}}?page={{page}}' data-page='{{page}}'>{{page}}</a>\n </li>\n {{/pages}}\n\n <li class=\"{{^nextPage}}disabled{{/nextPage}}\">\n <a href='{{urlPrefix}}?page={{nextPage}}' data-page='{{nextPage}}'>Next →</a>\n </li>\n </ul>\n</div>\n{{/isEmpty}}",d.prototype.pagesJSON=function(a,b){var c,d,e,f,g,h;return d=Math.floor(this.maxPages/2),c=a<=d?1:a-d,f=c+d*2-1,e=f>=b?b:f,_.map(function(){h=[];for(var a=c;c<=e?a<=e:a>=e;c<=e?a++:a--)h.push(a);return h}.apply(this),function(b){return{page:b,currentPage:a===b}})},d.prototype.paginationJSON=function(a){return{isEmpty:a.total_pages===0,emptyListMessage:this.emptyListMessage,currentPage:a.current_page,nextPage:a.next_page,previousPage:a.previous_page,urlPrefix:this.livelist.urlPrefix,pages:this.pagesJSON(a.current_page,a.total_pages)}},d.prototype.render=function(a){var b;return this.pagination=this.paginationJSON(a.pagination),b=Mustache.to_html(this.template,this.pagination),$(this.renderTo).html(b)},d.prototype.handlePaginationLinkClick=function(a){return a.preventDefault(),$(this.livelist.listSelector).trigger(this.livelist.eventName,{page:$(a.target).data("page")})},d}(Utilities),window.Search=function(b){function d(b,c){this.handleSearchFormSubmit=a(this.handleSearchFormSubmit,this);var d=this;this.livelist=c,this.setOptions(b),$(this.formSelector).submit(function(a){return d.handleSearchFormSubmit(a)})}return c(d,b),d.prototype.searchTerm=function(){var a;return a=$(this.searchTextInputSelector).val(),!a||a===""?null:a},d.prototype.handleSearchFormSubmit=function(a){return a.preventDefault(),$(this.livelist.listSelector).trigger(this.livelist.eventName)},d}(Utilities)})).call(this);
@@ -0,0 +1,6 @@
1
+ /*! Version: 0.4.2 */
2
+ /*
3
+ mustache.js — Logic-less templates in JavaScript
4
+
5
+ See http://mustache.github.com/ for more info.
6
+ */var Mustache=function(){function g(a){return String(a).replace(/&(?!#?\w+;)|[<>"']/g,function(a){return f[a]||a})}var a=Object.prototype.toString;Array.isArray=Array.isArray||function(b){return a.call(b)=="[object Array]"};var b=String.prototype.trim,c;if(b)c=function(a){return a==null?"":b.call(a)};else{var d,e;/\S/.test(" ")?(d=/^[\s\xA0]+/,e=/[\s\xA0]+$/):(d=/^\s+/,e=/\s+$/),c=function(a){return a==null?"":a.toString().replace(d,"").replace(e,"")}}var f={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},h={},i=function(){};return i.prototype={otag:"{{",ctag:"}}",pragmas:{},buffer:[],pragmas_implemented:{"IMPLICIT-ITERATOR":!0},context:{},render:function(a,b,c,d){d||(this.context=b,this.buffer=[]);if(!this.includes("",a)){if(d)return a;this.send(a);return}a=this.render_pragmas(a);var e=this.render_section(a,b,c);e===!1&&(e=this.render_tags(a,b,c,d));if(d)return e;this.sendLines(e)},send:function(a){a!==""&&this.buffer.push(a)},sendLines:function(a){if(a){var b=a.split("\n");for(var c=0;c<b.length;c++)this.send(b[c])}},render_pragmas:function(a){if(!this.includes("%",a))return a;var b=this,c=this.getCachedRegex("render_pragmas",function(a,b){return new RegExp(a+"%([\\w-]+) ?([\\w]+=[\\w]+)?"+b,"g")});return a.replace(c,function(a,c,d){if(!b.pragmas_implemented[c])throw{message:"This implementation of mustache doesn't understand the '"+c+"' pragma"};b.pragmas[c]={};if(d){var e=d.split("=");b.pragmas[c][e[0]]=e[1]}return""})},render_partial:function(a,b,d){a=c(a);if(!d||d[a]===undefined)throw{message:"unknown_partial '"+a+"'"};return!b||typeof b[a]!="object"?this.render(d[a],b,d,!0):this.render(d[a],b[a],d,!0)},render_section:function(a,b,c){if(!this.includes("#",a)&&!this.includes("^",a))return!1;var d=this,e=this.getCachedRegex("render_section",function(a,b){return new RegExp("^([\\s\\S]*?)"+a+"(\\^|\\#)\\s*(.+?)\\s*"+b+"\n*([\\s\\S]*?)"+a+"\\/\\s*\\3\\s*"+b+"\\s*([\\s\\S]*)$","g")});return a.replace(e,function(a,e,f,g,h,i){var j=e?d.render_tags(e,b,c,!0):"",k=i?d.render(i,b,c,!0):"",l,m=d.find(g,b);return f==="^"?!m||Array.isArray(m)&&m.length===0?l=d.render(h,b,c,!0):l="":f==="#"&&(Array.isArray(m)?l=d.map(m,function(a){return d.render(h,d.create_context(a),c,!0)}).join(""):d.is_object(m)?l=d.render(h,d.create_context(m),c,!0):typeof m=="function"?l=m.call(b,h,function(a){return d.render(a,b,c,!0)}):m?l=d.render(h,b,c,!0):l=""),j+l+k})},render_tags:function(a,b,c,d){var e=this,f=function(){return e.getCachedRegex("render_tags",function(a,b){return new RegExp(a+"(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?"+b+"+","g")})},h=f(),i=function(a,d,i){switch(d){case"!":return"";case"=":return e.set_delimiters(i),h=f(),"";case">":return e.render_partial(i,b,c);case"{":case"&":return e.find(i,b);default:return g(e.find(i,b))}},j=a.split("\n");for(var k=0;k<j.length;k++)j[k]=j[k].replace(h,i,this),d||this.send(j[k]);if(d)return j.join("\n")},set_delimiters:function(a){var b=a.split(" ");this.otag=this.escape_regex(b[0]),this.ctag=this.escape_regex(b[1])},escape_regex:function(a){if(!arguments.callee.sRE){var b=["/",".","*","+","?","|","(",")","[","]","{","}","\\"];arguments.callee.sRE=new RegExp("(\\"+b.join("|\\")+")","g")}return a.replace(arguments.callee.sRE,"\\$1")},find:function(a,b){function d(a){return a===!1||a===0||a}a=c(a);var e;if(a.match(/([a-z_]+)\./ig)){var f=this.walk_context(a,b);d(f)&&(e=f)}else d(b[a])?e=b[a]:d(this.context[a])&&(e=this.context[a]);return typeof e=="function"?e.apply(b):e!==undefined?e:""},walk_context:function(a,b){var c=a.split("."),d=b[c[0]]!=undefined?b:this.context,e=d[c.shift()];while(e!=undefined&&c.length>0)d=e,e=e[c.shift()];return typeof e=="function"?e.apply(d):e},includes:function(a,b){return b.indexOf(this.otag+a)!=-1},create_context:function(a){if(this.is_object(a))return a;var b=".";this.pragmas["IMPLICIT-ITERATOR"]&&(b=this.pragmas["IMPLICIT-ITERATOR"].iterator);var c={};return c[b]=a,c},is_object:function(a){return a&&typeof a=="object"},map:function(a,b){if(typeof a.map=="function")return a.map(b);var c=[],d=a.length;for(var e=0;e<d;e++)c.push(b(a[e]));return c},getCachedRegex:function(a,b){var c=h[this.otag];c||(c=h[this.otag]={});var d=c[this.ctag];d||(d=c[this.ctag]={});var e=d[a];return e||(e=d[a]=b(this.otag,this.ctag)),e}},{name:"mustache.js",version:"0.4.2",to_html:function(a,b,c,d){var e=new i;d&&(e.send=d),e.render(a,b||{},c);if(!d)return e.buffer.join("\n")}}}();
@@ -1,30 +1,31 @@
1
- // Underscore.js 1.2.3
2
- // (c) 2009-2011 Jeremy Ashkenas, DocumentCloud Inc.
1
+ // Underscore.js 1.3.1
2
+ // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
3
3
  // Underscore is freely distributable under the MIT license.
4
4
  // Portions of Underscore are inspired or borrowed from Prototype,
5
5
  // Oliver Steele's Functional, and John Resig's Micro-Templating.
6
6
  // For all details and documentation:
7
7
  // http://documentcloud.github.com/underscore
8
- (function(){function r(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
9
- c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&r(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(m.call(a,h)&&(f++,!(g=m.call(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(m.call(c,
10
- h)&&!f--)break;g=!f}}d.pop();return g}var s=this,F=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,G=k.concat,H=k.unshift,l=p.toString,m=p.hasOwnProperty,v=k.forEach,w=k.map,x=k.reduce,y=k.reduceRight,z=k.filter,A=k.every,B=k.some,q=k.indexOf,C=k.lastIndexOf,p=Array.isArray,I=Object.keys,t=Function.prototype.bind,b=function(a){return new n(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else typeof define==="function"&&
11
- define.amd?define("underscore",function(){return b}):s._=b;b.VERSION="1.2.3";var j=b.each=b.forEach=function(a,c,b){if(a!=null)if(v&&a.forEach===v)a.forEach(c,b);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(b,a[e],e,a)===o)break}else for(e in a)if(m.call(a,e)&&c.call(b,a[e],e,a)===o)break};b.map=function(a,c,b){var e=[];if(a==null)return e;if(w&&a.map===w)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});return e};b.reduce=b.foldl=b.inject=function(a,
12
- c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(x&&a.reduce===x)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(y&&a.reduceRight===y)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,
13
- c,d,e):b.reduce(g,c)};b.find=b.detect=function(a,c,b){var e;D(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(z&&a.filter===z)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(A&&a.every===A)return a.every(c,
14
- b);j(a,function(a,g,h){if(!(e=e&&c.call(b,a,g,h)))return o});return e};var D=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(B&&a.some===B)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return q&&a.indexOf===q?a.indexOf(c)!=-1:b=D(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(c.call?c||a:a[c]).apply(a,
15
- d)})};b.pluck=function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,
16
- computed:b})});return e.value};b.shuffle=function(a){var c=[],b;j(a,function(a,f){f==0?c[0]=a:(b=Math.floor(Math.random()*(f+1)),c[f]=c[b],c[b]=a)});return c};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,c){var b=a.criteria,d=c.criteria;return b<d?-1:b>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=
17
- function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-
18
- 1]};b.rest=b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},
19
- []);return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,
20
- c,d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(q&&a.indexOf===q)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(C&&a.lastIndexOf===C)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};
21
- var E=function(){};b.bind=function(a,c){var d,e;if(a.bind===t&&t)return t.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));E.prototype=a.prototype;var b=new E,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,
22
- c){var d={};c||(c=b.identity);return function(){var b=c.apply(this,arguments);return m.call(d,b)?d[b]:d[b]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true:
23
- a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=G.apply([a],arguments);return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=
24
- function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=I||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)m.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){j(i.call(arguments,
25
- 1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(m.call(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===
26
- Object(a)};b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!m.call(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)==
27
- "[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.noConflict=function(){s._=F;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};b.mixin=function(a){j(b.functions(a),function(c){J(c,
28
- b[c]=a[c])})};var K=0;b.uniqueId=function(a){var b=K++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape,function(a,b){return"',_.escape("+b.replace(/\\'/g,"'")+"),'"}).replace(d.interpolate,function(a,b){return"',"+b.replace(/\\'/g,
29
- "'")+",'"}).replace(d.evaluate||null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};var n=function(a){this._wrapped=a};b.prototype=n.prototype;var u=function(a,c){return c?b(a).chain():a},J=function(a,c){n.prototype[a]=function(){var a=i.call(arguments);H.call(a,this._wrapped);return u(c.apply(b,
30
- a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];n.prototype[a]=function(){b.apply(this._wrapped,arguments);return u(this._wrapped,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];n.prototype[a]=function(){return u(b.apply(this._wrapped,arguments),this._chain)}});n.prototype.chain=function(){this._chain=true;return this};n.prototype.value=function(){return this._wrapped}}).call(this);
8
+ (function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
9
+ c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,
10
+ h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each=
11
+ b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===n)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===n)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(x&&a.map===x)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==
12
+ null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=
13
+ function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e=
14
+ e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
15
+ function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})});
16
+ return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){f==0?b[0]=a:(d=Math.floor(Math.random()*(f+1)),b[f]=b[d],b[d]=a)});return b};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,
17
+ c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=
18
+ b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},[]);
19
+ return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,
20
+ d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(p&&a.indexOf===p)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(D&&a.lastIndexOf===D)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};
21
+ var F=function(){};b.bind=function(a,c){var d,e;if(a.bind===s&&s)return s.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));F.prototype=a.prototype;var b=new F,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,
22
+ c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true:
23
+ a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};
24
+ b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments,
25
+ 1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};
26
+ b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};
27
+ b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};b.mixin=function(a){j(b.functions(a),
28
+ function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+
29
+ u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]=
30
+ function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=
31
+ true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);
@@ -5,23 +5,26 @@ module Livelist
5
5
  module Rails
6
6
  module ActiveRecord
7
7
 
8
- def filter_for(slug, options = {})
8
+ def filters
9
9
  @filters ||= FilterCollection.new
10
- @filters.create_filter(
10
+ end
11
+
12
+ def filter_for(slug, options = {})
13
+ filters.create_filter(
11
14
  :reference_criteria => options[:reference_criteria],
15
+ :name => options[:name],
12
16
  :model_name => model_name,
13
17
  :slug => slug
14
18
  )
19
+ end
15
20
 
16
- def filters_as_json(params)
17
- @filters.as_json(scoped, params)
18
- end
19
-
20
- def filter(params)
21
- @filters.relation(scoped, params)
22
- end
21
+ def filters_as_json(params, options = {})
22
+ filters.as_json(scoped, params, options)
23
23
  end
24
24
 
25
+ def filter(params, options = {})
26
+ filters.relation(scoped, params, options)
27
+ end
25
28
  end
26
29
  end
27
30
  end
@@ -5,6 +5,10 @@ module Livelist
5
5
  module Rails
6
6
 
7
7
  class Filter
8
+ DEFAULT_FILTER_OPTIONS = {
9
+ :reference_criteria => nil
10
+ }
11
+
8
12
  attr_accessor :slug,
9
13
  :name,
10
14
  :key_name,
@@ -29,6 +33,12 @@ module Livelist
29
33
  )
30
34
  end
31
35
 
36
+ def prepare_options(options)
37
+ options ||= {}
38
+ options.reverse_merge!(DEFAULT_FILTER_OPTIONS)
39
+ @criteria.set_criteria(options[:reference_criteria]) if options[:reference_criteria]
40
+ end
41
+
32
42
  def group_by
33
43
  case @type
34
44
  when :attribute then "#{model_name.tableize}.#{@slug}"
@@ -8,22 +8,28 @@ module Livelist
8
8
  alias :filters :values
9
9
  alias :find_filter :[]
10
10
 
11
+ def slugs
12
+ keys.map(&:to_sym)
13
+ end
14
+
11
15
  def create_filter(options)
12
16
  options.merge!(:filter_collection => self)
13
17
  self[options[:slug]] = Filter.new(options)
14
18
  end
15
19
 
16
- def relation(query, params)
20
+ def relation(query, params, options = {})
17
21
  params ||= {}
18
22
  filters.each do |filter|
23
+ filter.prepare_options(options[filter.slug])
19
24
  query = filter.relation(query, params[filter.slug.to_s], params.empty?)
20
25
  end
21
26
  query
22
27
  end
23
28
 
24
- def as_json(query, params)
29
+ def as_json(query, params, options = {})
25
30
  params ||= {}
26
31
  filters.map do |filter|
32
+ filter.prepare_options(options[filter.slug])
27
33
  filter.set_criteria_counts(query, params)
28
34
  filter.as_json(params[filter.slug])
29
35
  end
@@ -10,18 +10,28 @@ module Livelist
10
10
  attr_reader :slug
11
11
 
12
12
  def initialize(options)
13
- @filter = options[:filter]
14
- @reference_criteria = options[:reference_criteria] || default_reference_criteria
15
- @reference_criteria = @reference_criteria.call if @reference_criteria.respond_to?(:call)
16
- @slug = options[:slug]
13
+ @filter = options[:filter]
14
+ @slug = options[:slug]
17
15
 
18
- @reference_criteria.each do |reference|
19
- create_criterion(reference)
20
- end
16
+ initialize_criteria(options[:reference_criteria])
17
+ end
18
+
19
+ def initialize_criteria(reference_criteria)
20
+ reference_criteria ||= default_reference_criteria
21
+ reference_criteria = reference_criteria.call if reference_criteria.respond_to?(:call)
22
+ reference_criteria.each { |reference| create_criterion(reference) }
23
+ end
24
+
25
+ def set_criteria(reference_criteria)
26
+ clear
27
+ reference_criteria.each { |reference| create_criterion(reference) }
21
28
  end
22
29
 
23
30
  def default_reference_criteria
24
- @filter.model_class.select("distinct #{@filter.slug}")
31
+ case @filter.type
32
+ when :attribute then @filter.model_class.select("distinct #{@filter.slug}")
33
+ when :association then @filter.slug.to_s.classify.constantize.scoped
34
+ end
25
35
  end
26
36
 
27
37
  def create_criterion(reference)
@@ -18,7 +18,7 @@ module Livelist
18
18
  livelist_filename = 'livelist'
19
19
  end
20
20
 
21
- config.action_view.javascript_expansions[:livelist_dependencies] = %W(mustache underscore.min)
21
+ config.action_view.javascript_expansions[:livelist_dependencies] = %W(mustache.min underscore-min)
22
22
  config.action_view.javascript_expansions[:livelist] = [livelist_filename]
23
23
  end
24
24
  end
@@ -1,8 +1,8 @@
1
1
  module Livelist
2
2
  module Rails
3
- VERSION = '0.0.11'
4
- LIVELIST_VERSION = '73a5124e4aee536963e90935f02566d67030d2ea'
5
- MUSTACHE_VERSION = 'db5f5ece0b6c87bbb2d0584010b97f8723dde69d'
6
- UNDERSCORE_VERSION = '1.2.3'
3
+ VERSION = '0.0.12'
4
+ LIVELIST_VERSION = '0.0.7'
5
+ MUSTACHE_VERSION = '0.4.2'
6
+ UNDERSCORE_VERSION = '1.3.1'
7
7
  end
8
8
  end
@@ -18,6 +18,8 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
+ s.add_runtime_dependency 'activesupport'
22
+ s.add_runtime_dependency 'activerecord'
21
23
  s.add_development_dependency 'rspec'
22
- s.add_development_dependency 'activerecord'
24
+ s.add_development_dependency 'simplecov'
23
25
  end
@@ -1,23 +1,82 @@
1
1
  require 'spec_helper.rb'
2
+ require 'active_support/core_ext/string/inflections'
2
3
  require File.expand_path('./lib/livelist/rails/active_record.rb')
3
4
 
4
5
  describe Livelist::Rails::ActiveRecord do
6
+ module ActiveRecord::ClassMethods
7
+ def model_name
8
+ 'User'
9
+ end
10
+
11
+ def column_names
12
+ ['state', 'status']
13
+ end
14
+
15
+ def reflect_on_all_associations
16
+ []
17
+ end
18
+
19
+ def select(*args)
20
+ []
21
+ end
22
+
23
+ def scoped
24
+ ActiveRecord::Relation.new(nil, nil)
25
+ end
26
+ end
27
+
5
28
  class User
29
+ extend ActiveRecord::ClassMethods
6
30
  extend Livelist::Rails::ActiveRecord
7
- filters :status, :state
8
31
  end
9
32
 
10
33
  subject { User }
11
34
 
12
- context :filter_for do
13
-
35
+ context :filters do
36
+ it 'filters should be a FilterCollection object' do
37
+ subject.filters.should be_kind_of(Livelist::Rails::FilterCollection)
38
+ end
14
39
  end
15
40
 
16
- context :filters_as_json do
41
+ context :filter_for do
42
+ let(:name) { 'State' }
43
+ let(:reference_criteria) { ['South Carolina', 'Virginia'] }
44
+ let(:options) do
45
+ {
46
+ :reference_criteria => reference_criteria,
47
+ :name => name,
48
+ :model_name => 'User',
49
+ :slug => :state
50
+ }
51
+ end
17
52
 
18
- end
53
+ it 'should call create a filter with the proper options' do
54
+ subject.filters.should_receive(:create_filter).with(options)
55
+ subject.filter_for(:state, :reference_criteria => reference_criteria, :name => name)
56
+ end
57
+ end
19
58
 
20
- context :filter do
59
+ context 'Runtime Methods' do
60
+ let(:options) do
61
+ {}
62
+ end
21
63
 
22
- end
64
+ let(:params) do
65
+ {}
66
+ end
67
+
68
+ context :filters_as_json do
69
+ it do
70
+ subject.filters.should_receive(:as_json).with(nil, params, options)
71
+ subject.filters_as_json(params, options)
72
+ end
73
+ end
74
+
75
+ context :filter do
76
+ it do
77
+ subject.filters.should_receive(:filter).with(nil, params, options)
78
+ subject.filter(params, options)
79
+ end
80
+ end
81
+ end
23
82
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper.rb'
2
2
  require File.expand_path('./lib/livelist/rails/filter_criterion.rb')
3
3
 
4
- describe Livelist::Rails::FilterCritereon do
4
+ describe Livelist::Rails::FilterCriterion do
5
5
  subject { FilterCritereon.new }
6
6
 
7
7
  context :initialize do
data/spec/spec_helper.rb CHANGED
@@ -2,10 +2,13 @@
2
2
  # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
3
  # Require this file using `require "spec_helper.rb"` to ensure that it is only
4
4
  # loaded once.
5
- #
5
+
6
+ require 'simplecov'
7
+ SimpleCov.start
8
+
6
9
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
10
  RSpec.configure do |config|
8
- config.treat_symbols_as_metadata_keys_with_true_values = true
9
- config.run_all_when_everything_filtered = true
10
- config.filter_run :focus
11
+ #config.treat_symbols_as_metadata_keys_with_true_values = true
12
+ #config.run_all_when_everything_filtered = true
13
+ #config.filter_run :focus
11
14
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: livelist-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
4
+ version: 0.0.12
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,33 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-20 00:00:00.000000000Z
12
+ date: 2012-03-28 00:00:00.000000000Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: &8072460 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *8072460
25
+ - !ruby/object:Gem::Dependency
26
+ name: activerecord
27
+ requirement: &8072040 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *8072040
14
36
  - !ruby/object:Gem::Dependency
15
37
  name: rspec
16
- requirement: &8002740 !ruby/object:Gem::Requirement
38
+ requirement: &8071620 !ruby/object:Gem::Requirement
17
39
  none: false
18
40
  requirements:
19
41
  - - ! '>='
@@ -21,10 +43,10 @@ dependencies:
21
43
  version: '0'
22
44
  type: :development
23
45
  prerelease: false
24
- version_requirements: *8002740
46
+ version_requirements: *8071620
25
47
  - !ruby/object:Gem::Dependency
26
- name: activerecord
27
- requirement: &8002320 !ruby/object:Gem::Requirement
48
+ name: simplecov
49
+ requirement: &8071200 !ruby/object:Gem::Requirement
28
50
  none: false
29
51
  requirements:
30
52
  - - ! '>='
@@ -32,7 +54,7 @@ dependencies:
32
54
  version: '0'
33
55
  type: :development
34
56
  prerelease: false
35
- version_requirements: *8002320
57
+ version_requirements: *8071200
36
58
  description: ! 'livelist-rails is a Rails 3.1 Engine/Extension incorporating the following
37
59
  javascript libraries: Mustache.js, underscore.js, jQuery and livelist.js, and providing
38
60
  ActiveRecord filtering extenstions.'
@@ -52,7 +74,7 @@ files:
52
74
  - app/assets/javascripts/livelist.coffee
53
75
  - app/assets/javascripts/livelist.js
54
76
  - app/assets/javascripts/livelist.min.js
55
- - app/assets/javascripts/mustache.js
77
+ - app/assets/javascripts/mustache.min.js
56
78
  - app/assets/javascripts/underscore-min.js
57
79
  - lib/livelist-rails.rb
58
80
  - lib/livelist/rails.rb
@@ -1,435 +0,0 @@
1
- /*
2
- mustache.js — Logic-less templates in JavaScript
3
-
4
- See http://mustache.github.com/ for more info.
5
- */
6
-
7
- var Mustache = function () {
8
- var _toString = Object.prototype.toString;
9
-
10
- Array.isArray = Array.isArray || function (obj) {
11
- return _toString.call(obj) == "[object Array]";
12
- }
13
-
14
- var _trim = String.prototype.trim, trim;
15
-
16
- if (_trim) {
17
- trim = function (text) {
18
- return text == null ? "" : _trim.call(text);
19
- }
20
- } else {
21
- var trimLeft, trimRight;
22
-
23
- // IE doesn't match non-breaking spaces with \s.
24
- if ((/\S/).test("\xA0")) {
25
- trimLeft = /^[\s\xA0]+/;
26
- trimRight = /[\s\xA0]+$/;
27
- } else {
28
- trimLeft = /^\s+/;
29
- trimRight = /\s+$/;
30
- }
31
-
32
- trim = function (text) {
33
- return text == null ? "" :
34
- text.toString().replace(trimLeft, "").replace(trimRight, "");
35
- }
36
- }
37
-
38
- var escapeMap = {
39
- "&": "&amp;",
40
- "<": "&lt;",
41
- ">": "&gt;",
42
- '"': '&quot;',
43
- "'": '&#39;'
44
- };
45
-
46
- function escapeHTML(string) {
47
- return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) {
48
- return escapeMap[s] || s;
49
- });
50
- }
51
-
52
- var regexCache = {};
53
- var Renderer = function () {};
54
-
55
- Renderer.prototype = {
56
- otag: "{{",
57
- ctag: "}}",
58
- pragmas: {},
59
- buffer: [],
60
- pragmas_implemented: {
61
- "IMPLICIT-ITERATOR": true
62
- },
63
- context: {},
64
-
65
- render: function (template, context, partials, in_recursion) {
66
- // reset buffer & set context
67
- if (!in_recursion) {
68
- this.context = context;
69
- this.buffer = []; // TODO: make this non-lazy
70
- }
71
-
72
- // fail fast
73
- if (!this.includes("", template)) {
74
- if (in_recursion) {
75
- return template;
76
- } else {
77
- this.send(template);
78
- return;
79
- }
80
- }
81
-
82
- // get the pragmas together
83
- template = this.render_pragmas(template);
84
-
85
- // render the template
86
- var html = this.render_section(template, context, partials);
87
-
88
- // render_section did not find any sections, we still need to render the tags
89
- if (html === false) {
90
- html = this.render_tags(template, context, partials, in_recursion);
91
- }
92
-
93
- if (in_recursion) {
94
- return html;
95
- } else {
96
- this.sendLines(html);
97
- }
98
- },
99
-
100
- /*
101
- Sends parsed lines
102
- */
103
- send: function (line) {
104
- if (line !== "") {
105
- this.buffer.push(line);
106
- }
107
- },
108
-
109
- sendLines: function (text) {
110
- if (text) {
111
- var lines = text.split("\n");
112
- for (var i = 0; i < lines.length; i++) {
113
- this.send(lines[i]);
114
- }
115
- }
116
- },
117
-
118
- /*
119
- Looks for %PRAGMAS
120
- */
121
- render_pragmas: function (template) {
122
- // no pragmas
123
- if (!this.includes("%", template)) {
124
- return template;
125
- }
126
-
127
- var that = this;
128
- var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) {
129
- return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g");
130
- });
131
-
132
- return template.replace(regex, function (match, pragma, options) {
133
- if (!that.pragmas_implemented[pragma]) {
134
- throw({message:
135
- "This implementation of mustache doesn't understand the '" +
136
- pragma + "' pragma"});
137
- }
138
- that.pragmas[pragma] = {};
139
- if (options) {
140
- var opts = options.split("=");
141
- that.pragmas[pragma][opts[0]] = opts[1];
142
- }
143
- return "";
144
- // ignore unknown pragmas silently
145
- });
146
- },
147
-
148
- /*
149
- Tries to find a partial in the curent scope and render it
150
- */
151
- render_partial: function (name, context, partials) {
152
- name = trim(name);
153
- if (!partials || partials[name] === undefined) {
154
- throw({message: "unknown_partial '" + name + "'"});
155
- }
156
- if (!context || typeof context[name] != "object") {
157
- return this.render(partials[name], context, partials, true);
158
- }
159
- return this.render(partials[name], context[name], partials, true);
160
- },
161
-
162
- /*
163
- Renders inverted (^) and normal (#) sections
164
- */
165
- render_section: function (template, context, partials) {
166
- if (!this.includes("#", template) && !this.includes("^", template)) {
167
- // did not render anything, there were no sections
168
- return false;
169
- }
170
-
171
- var that = this;
172
-
173
- var regex = this.getCachedRegex("render_section", function (otag, ctag) {
174
- // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder
175
- return new RegExp(
176
- "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1)
177
-
178
- otag + // {{
179
- "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3)
180
- ctag + // }}
181
-
182
- "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped
183
-
184
- otag + // {{
185
- "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag).
186
- ctag + // }}
187
-
188
- "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped.
189
-
190
- "g");
191
- });
192
-
193
-
194
- // for each {{#foo}}{{/foo}} section do...
195
- return template.replace(regex, function (match, before, type, name, content, after) {
196
- // before contains only tags, no sections
197
- var renderedBefore = before ? that.render_tags(before, context, partials, true) : "",
198
-
199
- // after may contain both sections and tags, so use full rendering function
200
- renderedAfter = after ? that.render(after, context, partials, true) : "",
201
-
202
- // will be computed below
203
- renderedContent,
204
-
205
- value = that.find(name, context);
206
-
207
- if (type === "^") { // inverted section
208
- if (!value || Array.isArray(value) && value.length === 0) {
209
- // false or empty list, render it
210
- renderedContent = that.render(content, context, partials, true);
211
- } else {
212
- renderedContent = "";
213
- }
214
- } else if (type === "#") { // normal section
215
- if (Array.isArray(value)) { // Enumerable, Let's loop!
216
- renderedContent = that.map(value, function (row) {
217
- return that.render(content, that.create_context(row), partials, true);
218
- }).join("");
219
- } else if (that.is_object(value)) { // Object, Use it as subcontext!
220
- renderedContent = that.render(content, that.create_context(value),
221
- partials, true);
222
- } else if (typeof value == "function") {
223
- // higher order section
224
- renderedContent = value.call(context, content, function (text) {
225
- return that.render(text, context, partials, true);
226
- });
227
- } else if (value) { // boolean section
228
- renderedContent = that.render(content, context, partials, true);
229
- } else {
230
- renderedContent = "";
231
- }
232
- }
233
-
234
- return renderedBefore + renderedContent + renderedAfter;
235
- });
236
- },
237
-
238
- /*
239
- Replace {{foo}} and friends with values from our view
240
- */
241
- render_tags: function (template, context, partials, in_recursion) {
242
- // tit for tat
243
- var that = this;
244
-
245
- var new_regex = function () {
246
- return that.getCachedRegex("render_tags", function (otag, ctag) {
247
- return new RegExp(otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" + ctag + "+", "g");
248
- });
249
- };
250
-
251
- var regex = new_regex();
252
- var tag_replace_callback = function (match, operator, name) {
253
- switch(operator) {
254
- case "!": // ignore comments
255
- return "";
256
- case "=": // set new delimiters, rebuild the replace regexp
257
- that.set_delimiters(name);
258
- regex = new_regex();
259
- return "";
260
- case ">": // render partial
261
- return that.render_partial(name, context, partials);
262
- case "{": // the triple mustache is unescaped
263
- return that.find(name, context);
264
- default: // escape the value
265
- return escapeHTML(that.find(name, context));
266
- }
267
- };
268
- var lines = template.split("\n");
269
- for(var i = 0; i < lines.length; i++) {
270
- lines[i] = lines[i].replace(regex, tag_replace_callback, this);
271
- if (!in_recursion) {
272
- this.send(lines[i]);
273
- }
274
- }
275
-
276
- if (in_recursion) {
277
- return lines.join("\n");
278
- }
279
- },
280
-
281
- set_delimiters: function (delimiters) {
282
- var dels = delimiters.split(" ");
283
- this.otag = this.escape_regex(dels[0]);
284
- this.ctag = this.escape_regex(dels[1]);
285
- },
286
-
287
- escape_regex: function (text) {
288
- // thank you Simon Willison
289
- if (!arguments.callee.sRE) {
290
- var specials = [
291
- '/', '.', '*', '+', '?', '|',
292
- '(', ')', '[', ']', '{', '}', '\\'
293
- ];
294
- arguments.callee.sRE = new RegExp(
295
- '(\\' + specials.join('|\\') + ')', 'g'
296
- );
297
- }
298
- return text.replace(arguments.callee.sRE, '\\$1');
299
- },
300
-
301
- /*
302
- find `name` in current `context`. That is find me a value
303
- from the view object
304
- */
305
- find: function (name, context) {
306
- name = trim(name);
307
-
308
- // Checks whether a value is thruthy or false or 0
309
- function is_kinda_truthy(bool) {
310
- return bool === false || bool === 0 || bool;
311
- }
312
-
313
- var value;
314
-
315
- // check for dot notation eg. foo.bar
316
- if (name.match(/([a-z_]+)\./ig)) {
317
- var childValue = this.walk_context(name, context);
318
- if (is_kinda_truthy(childValue)) {
319
- value = childValue;
320
- }
321
- } else {
322
- if (is_kinda_truthy(context[name])) {
323
- value = context[name];
324
- } else if (is_kinda_truthy(this.context[name])) {
325
- value = this.context[name];
326
- }
327
- }
328
-
329
- if (typeof value == "function") {
330
- return value.apply(context);
331
- }
332
- if (value !== undefined) {
333
- return value;
334
- }
335
- // silently ignore unkown variables
336
- return "";
337
- },
338
-
339
- walk_context: function (name, context) {
340
- var path = name.split('.');
341
- // if the var doesn't exist in current context, check the top level context
342
- var value_context = (context[path[0]] != undefined) ? context : this.context;
343
- var value = value_context[path.shift()];
344
- while (value != undefined && path.length > 0) {
345
- value_context = value;
346
- value = value[path.shift()];
347
- }
348
- // if the value is a function, call it, binding the correct context
349
- if (typeof value == "function") {
350
- return value.apply(value_context);
351
- }
352
- return value;
353
- },
354
-
355
- // Utility methods
356
-
357
- /* includes tag */
358
- includes: function (needle, haystack) {
359
- return haystack.indexOf(this.otag + needle) != -1;
360
- },
361
-
362
- // by @langalex, support for arrays of strings
363
- create_context: function (_context) {
364
- if (this.is_object(_context)) {
365
- return _context;
366
- } else {
367
- var iterator = ".";
368
- if (this.pragmas["IMPLICIT-ITERATOR"]) {
369
- iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
370
- }
371
- var ctx = {};
372
- ctx[iterator] = _context;
373
- return ctx;
374
- }
375
- },
376
-
377
- is_object: function (a) {
378
- return a && typeof a == "object";
379
- },
380
-
381
- /*
382
- Why, why, why? Because IE. Cry, cry cry.
383
- */
384
- map: function (array, fn) {
385
- if (typeof array.map == "function") {
386
- return array.map(fn);
387
- } else {
388
- var r = [];
389
- var l = array.length;
390
- for(var i = 0; i < l; i++) {
391
- r.push(fn(array[i]));
392
- }
393
- return r;
394
- }
395
- },
396
-
397
- getCachedRegex: function (name, generator) {
398
- var byOtag = regexCache[this.otag];
399
- if (!byOtag) {
400
- byOtag = regexCache[this.otag] = {};
401
- }
402
-
403
- var byCtag = byOtag[this.ctag];
404
- if (!byCtag) {
405
- byCtag = byOtag[this.ctag] = {};
406
- }
407
-
408
- var regex = byCtag[name];
409
- if (!regex) {
410
- regex = byCtag[name] = generator(this.otag, this.ctag);
411
- }
412
-
413
- return regex;
414
- }
415
- };
416
-
417
- return({
418
- name: "mustache.js",
419
- version: "0.4.0-dev",
420
-
421
- /*
422
- Turns a template and view into HTML
423
- */
424
- to_html: function (template, view, partials, send_fun) {
425
- var renderer = new Renderer();
426
- if (send_fun) {
427
- renderer.send = send_fun;
428
- }
429
- renderer.render(template, view || {}, partials);
430
- if (!send_fun) {
431
- return renderer.buffer.join("\n");
432
- }
433
- }
434
- });
435
- }();