livelist-rails 0.0.4 → 0.0.5
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/.rspec +2 -0
- data/Rakefile +2 -0
- data/app/assets/javascripts/livelist.coffee +35 -6
- data/app/assets/javascripts/livelist.js +46 -11
- data/app/assets/javascripts/livelist.min.js +1 -1
- data/lib/livelist/rails/active_record.rb +46 -10
- data/lib/livelist/rails/railtie.rb +2 -3
- data/lib/livelist/rails/version.rb +2 -2
- data/livelist-rails.gemspec +3 -2
- data/spec/livelist/rails/active_record_spec.rb +211 -0
- data/spec/livelist/spec_helper.rb +6 -0
- data/spec/spec_helper.rb +11 -0
- metadata +34 -5
data/.rspec
ADDED
data/Rakefile
CHANGED
@@ -34,8 +34,14 @@ class window.List extends Utilities
|
|
34
34
|
@fetchingIndicationClass = 'updating'
|
35
35
|
@setOptions(options)
|
36
36
|
|
37
|
-
$(@renderTo).bind(@eventName, (event, params) => @fetch(
|
38
|
-
|
37
|
+
$(@renderTo).bind(@eventName, (event, params) => @fetch(presets: null, page: params?.page))
|
38
|
+
|
39
|
+
cookie = jQuery.cookie(@filters.cookieName) if jQuery.cookie && @filters.useCookies
|
40
|
+
if @filters.useCookies && cookie
|
41
|
+
presets = JSON.parse(cookie)
|
42
|
+
else
|
43
|
+
presets = @filters.presets
|
44
|
+
@fetch(presets: presets)
|
39
45
|
|
40
46
|
displayFetchingIndication: => $(@renderTo).addClass(@fetchingIndicationClass)
|
41
47
|
removeFetchingIndication: => $(@renderTo).removeClass(@fetchingIndicationClass)
|
@@ -47,14 +53,23 @@ class window.List extends Utilities
|
|
47
53
|
@filters.filters = _.pluck( @data.filters, 'filter_slug' )
|
48
54
|
@filters.render(@data)
|
49
55
|
|
56
|
+
selections: ->
|
57
|
+
filters = {}
|
58
|
+
_.each( @filters.filters, (filter) => filters[filter] = @filters.filterSelections( filter ) )
|
59
|
+
filters
|
60
|
+
|
50
61
|
fetch: (options) ->
|
51
62
|
@fetchRequest.abort() if @fetchRequest
|
52
63
|
searchTerm = @search.searchTerm()
|
53
64
|
params = { filters: {} }
|
54
|
-
|
55
|
-
|
65
|
+
|
66
|
+
if jQuery.isEmptyObject(options.presets)
|
67
|
+
params.filters = @selections()
|
68
|
+
if jQuery.cookie && not jQuery.isEmptyObject(params.filters)
|
69
|
+
jQuery.cookie(@filters.cookieName, JSON.stringify(params.filters))
|
56
70
|
else
|
57
|
-
|
71
|
+
params.filters = options.presets
|
72
|
+
|
58
73
|
if searchTerm then params.q = searchTerm
|
59
74
|
if options.page then params.page = options.page
|
60
75
|
@fetchRequest = $.ajax(
|
@@ -72,10 +87,13 @@ class window.List extends Utilities
|
|
72
87
|
$(@renderTo).html( Mustache.to_html(@listTemplate, @data, partials) )
|
73
88
|
@removeFetchingIndication()
|
74
89
|
|
90
|
+
window.LiveList.version = '0.0.3'
|
91
|
+
|
75
92
|
class window.Filters extends Utilities
|
76
93
|
constructor: (globalOptions, options = {}) ->
|
77
94
|
@setOptions(globalOptions)
|
78
95
|
@filters = if options.presets then _.keys(options.presets) else []
|
96
|
+
unless @filters.cookieName then @filters.cookieName = 'livelist_filter_presets'
|
79
97
|
@setOptions(options)
|
80
98
|
$('input.filter_option', @renderTo).live( 'change', => $(@listSelector).trigger(@eventName) )
|
81
99
|
$(@advancedOptionsToggleSelector).click(@handleAdvancedOptionsClick)
|
@@ -110,7 +128,18 @@ class window.Filters extends Utilities
|
|
110
128
|
filterValues: (filter) -> _.pluck( $(".#{filter}_filter_input"), 'value' )
|
111
129
|
filterSelections: (filter) -> _.pluck( $("##{filter}_filter_options input.filter_option:checked"), 'value' )
|
112
130
|
|
113
|
-
|
131
|
+
noFiltersSelected: (data) ->
|
132
|
+
_.all( data.filters, (filter) ->
|
133
|
+
_.all( filter.options, (option) ->
|
134
|
+
not option.selected
|
135
|
+
)
|
136
|
+
)
|
137
|
+
|
138
|
+
render: (data) ->
|
139
|
+
$(@renderTo).html( Mustache.to_html(@filtersTemplate, data) )
|
140
|
+
if @noFiltersSelected(data) && data[@resourceName].length > 0
|
141
|
+
$('input[type="checkbox"]', @renderTo).attr('checked', 'checked')
|
142
|
+
|
114
143
|
|
115
144
|
handleAdvancedOptionsClick: (event) =>
|
116
145
|
event.preventDefault()
|
@@ -51,7 +51,8 @@
|
|
51
51
|
__extends(List, _super);
|
52
52
|
|
53
53
|
function List(search, filters, pagination, globalOptions, options) {
|
54
|
-
var
|
54
|
+
var cookie, presets,
|
55
|
+
_this = this;
|
55
56
|
if (options == null) options = {};
|
56
57
|
this.renderIndex = __bind(this.renderIndex, this);
|
57
58
|
this.removeFetchingIndication = __bind(this.removeFetchingIndication, this);
|
@@ -68,12 +69,20 @@
|
|
68
69
|
this.setOptions(options);
|
69
70
|
$(this.renderTo).bind(this.eventName, function(event, params) {
|
70
71
|
return _this.fetch({
|
71
|
-
|
72
|
+
presets: null,
|
72
73
|
page: params != null ? params.page : void 0
|
73
74
|
});
|
74
75
|
});
|
76
|
+
if (jQuery.cookie && this.filters.useCookies) {
|
77
|
+
cookie = jQuery.cookie(this.filters.cookieName);
|
78
|
+
}
|
79
|
+
if (this.filters.useCookies && cookie) {
|
80
|
+
presets = JSON.parse(cookie);
|
81
|
+
} else {
|
82
|
+
presets = this.filters.presets;
|
83
|
+
}
|
75
84
|
this.fetch({
|
76
|
-
|
85
|
+
presets: presets
|
77
86
|
});
|
78
87
|
}
|
79
88
|
|
@@ -93,20 +102,30 @@
|
|
93
102
|
return this.filters.render(this.data);
|
94
103
|
};
|
95
104
|
|
96
|
-
List.prototype.
|
97
|
-
var
|
105
|
+
List.prototype.selections = function() {
|
106
|
+
var filters,
|
98
107
|
_this = this;
|
108
|
+
filters = {};
|
109
|
+
_.each(this.filters.filters, function(filter) {
|
110
|
+
return filters[filter] = _this.filters.filterSelections(filter);
|
111
|
+
});
|
112
|
+
return filters;
|
113
|
+
};
|
114
|
+
|
115
|
+
List.prototype.fetch = function(options) {
|
116
|
+
var params, searchTerm;
|
99
117
|
if (this.fetchRequest) this.fetchRequest.abort();
|
100
118
|
searchTerm = this.search.searchTerm();
|
101
119
|
params = {
|
102
120
|
filters: {}
|
103
121
|
};
|
104
|
-
if ((
|
105
|
-
params.filters =
|
122
|
+
if (jQuery.isEmptyObject(options.presets)) {
|
123
|
+
params.filters = this.selections();
|
124
|
+
if (jQuery.cookie && !jQuery.isEmptyObject(params.filters)) {
|
125
|
+
jQuery.cookie(this.filters.cookieName, JSON.stringify(params.filters));
|
126
|
+
}
|
106
127
|
} else {
|
107
|
-
|
108
|
-
return params.filters[filter] = _this.filters.filterSelections(filter);
|
109
|
-
});
|
128
|
+
params.filters = options.presets;
|
110
129
|
}
|
111
130
|
if (searchTerm) params.q = searchTerm;
|
112
131
|
if (options.page) params.page = options.page;
|
@@ -132,6 +151,8 @@
|
|
132
151
|
|
133
152
|
})(Utilities);
|
134
153
|
|
154
|
+
window.LiveList.version = '0.0.3';
|
155
|
+
|
135
156
|
window.Filters = (function(_super) {
|
136
157
|
|
137
158
|
__extends(Filters, _super);
|
@@ -142,6 +163,9 @@
|
|
142
163
|
this.handleAdvancedOptionsClick = __bind(this.handleAdvancedOptionsClick, this);
|
143
164
|
this.setOptions(globalOptions);
|
144
165
|
this.filters = options.presets ? _.keys(options.presets) : [];
|
166
|
+
if (!this.filters.cookieName) {
|
167
|
+
this.filters.cookieName = 'livelist_filter_presets';
|
168
|
+
}
|
145
169
|
this.setOptions(options);
|
146
170
|
$('input.filter_option', this.renderTo).live('change', function() {
|
147
171
|
return $(_this.listSelector).trigger(_this.eventName);
|
@@ -159,8 +183,19 @@
|
|
159
183
|
return _.pluck($("#" + filter + "_filter_options input.filter_option:checked"), 'value');
|
160
184
|
};
|
161
185
|
|
186
|
+
Filters.prototype.noFiltersSelected = function(data) {
|
187
|
+
return _.all(data.filters, function(filter) {
|
188
|
+
return _.all(filter.options, function(option) {
|
189
|
+
return !option.selected;
|
190
|
+
});
|
191
|
+
});
|
192
|
+
};
|
193
|
+
|
162
194
|
Filters.prototype.render = function(data) {
|
163
|
-
|
195
|
+
$(this.renderTo).html(Mustache.to_html(this.filtersTemplate, data));
|
196
|
+
if (this.noFiltersSelected(data) && data[this.resourceName].length > 0) {
|
197
|
+
return $('input[type="checkbox"]', this.renderTo).attr('checked', 'checked');
|
198
|
+
}
|
164
199
|
};
|
165
200
|
|
166
201
|
Filters.prototype.handleAdvancedOptionsClick = function(event) {
|
@@ -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.globalOptions.listSelector=a.list.renderTo,this.globalOptions.eventName="livelist:"+a.global.resourceName,this.globalOptions.urlPrefix="/"+a.global.resourceName,this.setOptions(a.global,this.globalOptions),this.search=new Search(this.globalOptions,a.search),this.filters=new Filters(this.globalOptions,a.filters),this.pagination=new Pagination(this.globalOptions,a.pagination),this.list=new List(this.search,this.filters,this.pagination,this.globalOptions,a.list)}return c(b,a),b.prototype.globalOptions={data:null,resourceName:"items",resourceNameSingular:"item"},b}(Utilities),window.List=function(b){function d(b,c,d,e,f){var g=this;f==null&&(f={}),this.renderIndex=a(this.renderIndex,this),this.removeFetchingIndication=a(this.removeFetchingIndication,this),this.displayFetchingIndication=a(this.displayFetchingIndication,this),this.data=e.data,this.fetchRequest=null,this.search=b,this.filters=c,this.pagination=d,this.setOptions(e),this.listTemplate="{{#"+this.resourceName+"}}{{>"+this.resourceNameSingular+"}}{{/"+this.resourceName+"}}",this.listItemTemplate="<li>{{id}}</li>",this.fetchingIndicationClass="updating",this.setOptions(f),$(this.renderTo).bind(this.eventName,function(a,b){return
|
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.globalOptions.listSelector=a.list.renderTo,this.globalOptions.eventName="livelist:"+a.global.resourceName,this.globalOptions.urlPrefix="/"+a.global.resourceName,this.setOptions(a.global,this.globalOptions),this.search=new Search(this.globalOptions,a.search),this.filters=new Filters(this.globalOptions,a.filters),this.pagination=new Pagination(this.globalOptions,a.pagination),this.list=new List(this.search,this.filters,this.pagination,this.globalOptions,a.list)}return c(b,a),b.prototype.globalOptions={data:null,resourceName:"items",resourceNameSingular:"item"},b}(Utilities),window.List=function(b){function d(b,c,d,e,f){var g,h,i=this;f==null&&(f={}),this.renderIndex=a(this.renderIndex,this),this.removeFetchingIndication=a(this.removeFetchingIndication,this),this.displayFetchingIndication=a(this.displayFetchingIndication,this),this.data=e.data,this.fetchRequest=null,this.search=b,this.filters=c,this.pagination=d,this.setOptions(e),this.listTemplate="{{#"+this.resourceName+"}}{{>"+this.resourceNameSingular+"}}{{/"+this.resourceName+"}}",this.listItemTemplate="<li>{{id}}</li>",this.fetchingIndicationClass="updating",this.setOptions(f),$(this.renderTo).bind(this.eventName,function(a,b){return i.fetch({presets:null,page:b!=null?b.page:void 0})}),jQuery.cookie&&this.filters.useCookies&&(g=jQuery.cookie(this.filters.cookieName)),this.filters.useCookies&&g?h=JSON.parse(g):h=this.filters.presets,this.fetch({presets:h})}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.data=a,this.render(),this.pagination.render(this.data),this.filters.filters=_.pluck(this.data.filters,"filter_slug"),this.filters.render(this.data)},d.prototype.selections=function(){var a,b=this;return a={},_.each(this.filters.filters,function(c){return a[c]=b.filters.filterSelections(c)}),a},d.prototype.fetch=function(a){var b,c;return this.fetchRequest&&this.fetchRequest.abort(),c=this.search.searchTerm(),b={filters:{}},jQuery.isEmptyObject(a.presets)?(b.filters=this.selections(),jQuery.cookie&&!jQuery.isEmptyObject(b.filters)&&jQuery.cookie(this.filters.cookieName,JSON.stringify(b.filters))):b.filters=a.presets,c&&(b.q=c),a.page&&(b.page=a.page),this.fetchRequest=$.ajax({url:this.urlPrefix,dataType:"json",data:b,type:this.httpMethod,beforeSend:this.displayFetchingIndication,success:this.renderIndex})},d.prototype.render=function(){var a;return a={},a[this.resourceNameSingular]=this.listItemTemplate,$(this.renderTo).html(Mustache.to_html(this.listTemplate,this.data,a)),this.removeFetchingIndication()},d}(Utilities),window.LiveList.version="0.0.3",window.Filters=function(b){function d(b,c){var d=this;c==null&&(c={}),this.handleAdvancedOptionsClick=a(this.handleAdvancedOptionsClick,this),this.setOptions(b),this.filters=c.presets?_.keys(c.presets):[],this.filters.cookieName||(this.filters.cookieName="livelist_filter_presets"),this.setOptions(c),$("input.filter_option",this.renderTo).live("change",function(){return $(d.listSelector).trigger(d.eventName)}),$(this.advancedOptionsToggleSelector).click(this.handleAdvancedOptionsClick)}return c(d,b),d.prototype.filtersTemplate="{{#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.filterValues=function(a){return _.pluck($("."+a+"_filter_input"),"value")},d.prototype.filterSelections=function(a){return _.pluck($("#"+a+"_filter_options input.filter_option:checked"),"value")},d.prototype.noFiltersSelected=function(a){return _.all(a.filters,function(a){return _.all(a.options,function(a){return!a.selected})})},d.prototype.render=function(a){$(this.renderTo).html(Mustache.to_html(this.filtersTemplate,a));if(this.noFiltersSelected(a)&&a[this.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){c==null&&(c={}),this.handlePaginationLinkClick=a(this.handlePaginationLinkClick,this),this.pagination=null,this.maxPages=30,this.setOptions(b),this.emptyListMessage="<p>No "+this.resourceName+" matched your filter criteria</p>",this.setOptions(c),$(""+this.renderTo+" a").live("click",this.handlePaginationLinkClick)}return c(d,b),d.prototype.paginationTemplate="{{#isEmpty}}\n {{{emptyListMessage}}}\n{{/isEmpty}}\n{{^isEmpty}}\n{{#previousPage}}\n <a href='{{urlPrefix}}?page={{previousPage}}' data-page='{{previousPage}}'>← Previous</a>\n{{/previousPage}}\n{{^previousPage}}\n <span>← Previous</span>\n{{/previousPage}}\n{{#pages}}\n {{#currentPage}}\n <span>{{page}}</span>\n {{/currentPage}}\n {{^currentPage}}\n <a href='{{urlPrefix}}?page={{page}}' data-page='{{page}}'>{{page}}</a>\n {{/currentPage}}\n{{/pages}}\n{{#nextPage}}\n <a href='{{urlPrefix}}?page={{nextPage}}' data-page='{{nextPage}}'>Next →</a>\n{{/nextPage}}\n{{^nextPage}}\n <span>Next →</span>\n{{/nextPage}}\n{{/isEmpty}}",d.prototype.pagesJSON=function(a,b){var c,d,e,f,g,h;return d=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:function(){return 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.urlPrefix,pages:this.pagesJSON(a.current_page,a.total_pages)}},d.prototype.render=function(a){return this.pagination=this.paginationJSON(a.pagination),$(this.renderTo).html(Mustache.to_html(this.paginationTemplate,this.pagination))},d.prototype.handlePaginationLinkClick=function(a){return a.preventDefault(),$(this.listSelector).trigger(this.eventName,{page:$(a.target).data("page")})},d}(Utilities),window.Search=function(b){function d(b,c){var d=this;c==null&&(c={}),this.handleSearchFormSubmit=a(this.handleSearchFormSubmit,this),this.setOptions(b),this.setOptions(c),$(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.listSelector).trigger(this.eventName)},d}(Utilities)})).call(this);
|
@@ -27,8 +27,22 @@ module Livelist
|
|
27
27
|
}
|
28
28
|
end
|
29
29
|
|
30
|
+
define_method "#{filter_slug}_filter_option_key_name" do
|
31
|
+
new.respond_to?(filter_slug.to_sym) ? filter_slug.to_sym : :id
|
32
|
+
end
|
33
|
+
|
34
|
+
define_method "#{filter_slug}_filter_option_objects" do
|
35
|
+
select("distinct #{filter_slug}").all
|
36
|
+
end
|
37
|
+
|
30
38
|
define_method "#{filter_slug}_filter_values" do
|
31
|
-
|
39
|
+
key = send("#{filter_slug}_filter_option_key_name")
|
40
|
+
option_objects = send("#{filter_slug}_filter_option_objects")
|
41
|
+
if option_objects.any?{|object| object.kind_of?(Hash) && object.has_key?(key)}
|
42
|
+
option_objects.map{|object| object[key]}
|
43
|
+
elsif option_objects.any?{|object| object.respond_to?(key)}
|
44
|
+
option_objects.map(&key)
|
45
|
+
end
|
32
46
|
end
|
33
47
|
|
34
48
|
define_method "#{filter_slug}_filter_counts" do
|
@@ -36,36 +50,58 @@ module Livelist
|
|
36
50
|
end
|
37
51
|
|
38
52
|
define_method "#{filter_slug}_filter_option_slug" do |option|
|
39
|
-
option.
|
53
|
+
if [String, Integer].any?{|klass| option.kind_of?(klass)}
|
54
|
+
option.to_s
|
55
|
+
else
|
56
|
+
option.send(:id).to_s
|
57
|
+
end
|
40
58
|
end
|
41
59
|
|
42
60
|
define_method "#{filter_slug}_filter_option_name" do |option|
|
43
|
-
|
61
|
+
option_objects = send("#{filter_slug}_filter_option_objects")
|
62
|
+
if option_objects.any?{|object| object.kind_of?(Hash) && object.has_key?(:name)}
|
63
|
+
option_object = option_objects.detect{|object| object[:state] == option.to_s}
|
64
|
+
option_object[:name]
|
65
|
+
elsif option_objects.any?{|object| object.respond_to?(:name)}
|
66
|
+
option_object = option_objects.detect{|object| object.send(:id).to_s == option.to_s}
|
67
|
+
option_object.send(:name)
|
68
|
+
else
|
69
|
+
option.to_s
|
70
|
+
end
|
44
71
|
end
|
45
72
|
|
46
73
|
define_method "#{filter_slug}_filter_option_value" do |option|
|
47
|
-
option.
|
74
|
+
if [String, Integer].any?{|klass| option.kind_of?(klass)}
|
75
|
+
option.to_s
|
76
|
+
else
|
77
|
+
option.send(:id).to_s
|
78
|
+
end
|
48
79
|
end
|
49
80
|
|
50
81
|
define_method "#{filter_slug}_filter_option_count" do |option|
|
51
82
|
unless class_variables.include?("@@#{filter_slug}_filter_counts")
|
52
83
|
class_variable_set(:"@@#{filter_slug}_filter_counts", send("#{filter_slug}_filter_counts"))
|
53
84
|
end
|
54
|
-
class_variable_get(:"@@#{filter_slug}_filter_counts")[option]
|
85
|
+
class_variable_get(:"@@#{filter_slug}_filter_counts")[option.to_s] || 0
|
55
86
|
end
|
56
87
|
|
57
88
|
define_method "#{filter_slug}_filter_option" do |option, selected|
|
89
|
+
option_slug = send("#{filter_slug}_filter_option_slug", option)
|
90
|
+
option_name = send("#{filter_slug}_filter_option_name", option)
|
91
|
+
option_value = send("#{filter_slug}_filter_option_value", option)
|
92
|
+
option_count = send("#{filter_slug}_filter_option_count", option)
|
93
|
+
|
58
94
|
{
|
59
|
-
:slug
|
60
|
-
:name
|
61
|
-
:value
|
62
|
-
:count
|
95
|
+
:slug => option_slug,
|
96
|
+
:name => option_name,
|
97
|
+
:value => option_value,
|
98
|
+
:count => option_count,
|
63
99
|
:selected => selected
|
64
100
|
}
|
65
101
|
end
|
66
102
|
|
67
103
|
define_method "#{filter_slug}_filter_option_selected?" do |filter_params, option|
|
68
|
-
filter_params.nil? ?
|
104
|
+
filter_params.nil? ? false : filter_params.include?(option.to_s)
|
69
105
|
end
|
70
106
|
|
71
107
|
define_method "#{filter_slug}_filters" do |filter_params|
|
@@ -12,9 +12,8 @@ module Livelist
|
|
12
12
|
|
13
13
|
if ::Rails.version < "3.1.0"
|
14
14
|
config.before_configuration do
|
15
|
-
if ::Rails.
|
16
|
-
|
17
|
-
livelist_filename = 'livelist-min'
|
15
|
+
if %W(production staging).include?(::Rails.env)
|
16
|
+
livelist_filename = 'livelist.min'
|
18
17
|
else
|
19
18
|
livelist_filename = 'livelist'
|
20
19
|
end
|
data/livelist-rails.gemspec
CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
21
|
# specify any dependencies here; for example:
|
22
|
-
|
23
|
-
|
22
|
+
s.add_development_dependency "rspec"
|
23
|
+
s.add_development_dependency "activerecord"
|
24
|
+
#s.add_runtime_dependency "rest-client"
|
24
25
|
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
require File.expand_path('./lib/livelist/rails/active_record.rb')
|
3
|
+
|
4
|
+
describe Livelist::Rails::ActiveRecord do
|
5
|
+
class User
|
6
|
+
extend Livelist::Rails::ActiveRecord
|
7
|
+
filters :status, :state
|
8
|
+
end
|
9
|
+
|
10
|
+
subject { User }
|
11
|
+
|
12
|
+
context :filter_name do
|
13
|
+
it { subject.should respond_to(:state_filter_name) }
|
14
|
+
it { subject.should respond_to(:status_filter_name) }
|
15
|
+
|
16
|
+
it { subject.state_filter_name.should == 'State' }
|
17
|
+
end
|
18
|
+
|
19
|
+
context :filter_slug do
|
20
|
+
it { subject.should respond_to(:state_filter_slug) }
|
21
|
+
it { subject.should respond_to(:status_filter_slug) }
|
22
|
+
|
23
|
+
it { subject.state_filter_slug.should == 'state' }
|
24
|
+
end
|
25
|
+
|
26
|
+
context :filter do
|
27
|
+
let(:options) do
|
28
|
+
[{
|
29
|
+
:slug => 'virginia',
|
30
|
+
:name => 'Virginia',
|
31
|
+
:value => 'virginia',
|
32
|
+
:count => 1,
|
33
|
+
:selected => true
|
34
|
+
}]
|
35
|
+
end
|
36
|
+
|
37
|
+
it { subject.should respond_to(:state_filter) }
|
38
|
+
it { subject.should respond_to(:status_filter) }
|
39
|
+
|
40
|
+
it 'should be a hash with the proper keys/values' do
|
41
|
+
subject.should_receive(:state_filter_slug).and_return('state')
|
42
|
+
subject.should_receive(:state_filter_name).and_return('State')
|
43
|
+
subject.state_filter(options).should == {
|
44
|
+
:filter_slug => 'state',
|
45
|
+
:name => 'State',
|
46
|
+
:options => options
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context :filter_values do
|
52
|
+
let(:values) do
|
53
|
+
[
|
54
|
+
double('Object', :state => 'Virginia'),
|
55
|
+
double('Object', :state => 'South Carolina')
|
56
|
+
]
|
57
|
+
end
|
58
|
+
|
59
|
+
it { subject.should respond_to(:state_filter_values) }
|
60
|
+
it { subject.should respond_to(:status_filter_values) }
|
61
|
+
|
62
|
+
it 'should return a mapped list of values' do
|
63
|
+
subject.should_receive(:select).and_return(values)
|
64
|
+
subject.state_filter_values.should == ['Virginia', 'South Carolina']
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context :filter_counts do
|
69
|
+
it { subject.should respond_to(:state_filter_counts) }
|
70
|
+
it { subject.should respond_to(:status_filter_counts) }
|
71
|
+
|
72
|
+
it 'should be tested' do
|
73
|
+
pending
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context :filter_option_slug do
|
78
|
+
let(:option) { 'virginia' }
|
79
|
+
|
80
|
+
it { subject.should respond_to(:state_filter_option_slug) }
|
81
|
+
it { subject.should respond_to(:status_filter_option_slug) }
|
82
|
+
|
83
|
+
it { subject.state_filter_option_slug(option).should == 'virginia' }
|
84
|
+
end
|
85
|
+
|
86
|
+
context :filter_option_name do
|
87
|
+
let(:option) { 'virginia' }
|
88
|
+
|
89
|
+
it { subject.should respond_to(:state_filter_option_name) }
|
90
|
+
it { subject.should respond_to(:status_filter_option_name) }
|
91
|
+
|
92
|
+
it { subject.state_filter_option_name(option).should == 'Virginia' }
|
93
|
+
end
|
94
|
+
|
95
|
+
context :filter_option_value do
|
96
|
+
let(:option) { 'virginia' }
|
97
|
+
|
98
|
+
it { subject.should respond_to(:state_filter_option_count) }
|
99
|
+
it { subject.should respond_to(:status_filter_option_count) }
|
100
|
+
|
101
|
+
it { subject.state_filter_option_value(option).should == 'virginia' }
|
102
|
+
end
|
103
|
+
|
104
|
+
context :filter_option_count do
|
105
|
+
let(:option) { 'Virginia' }
|
106
|
+
let(:state_filter_counts) { { 'Virginia' => 1, 'South Carolina' => 2 } }
|
107
|
+
|
108
|
+
it { subject.should respond_to(:state_filter_option_count) }
|
109
|
+
it { subject.should respond_to(:status_filter_option_count) }
|
110
|
+
|
111
|
+
it 'option argument should be converted to a string' do
|
112
|
+
state_filter_counts['1'] = 3
|
113
|
+
subject.should_receive(:state_filter_counts).and_return(state_filter_counts)
|
114
|
+
subject.state_filter_option_count(1).should == 3
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should be the proper count for the option' do
|
118
|
+
subject.should_receive(:state_filter_counts).and_return(state_filter_counts)
|
119
|
+
subject.state_filter_option_count(option).should == 1
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should be 0 if the value for the option is nil' do
|
123
|
+
subject.should_receive(:state_filter_counts).and_return(state_filter_counts)
|
124
|
+
subject.state_filter_option_count('West Virginia').should == 0
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should cache the counts when the method is first called' do
|
128
|
+
pending
|
129
|
+
#subject.should_receive(:state_filter_counts).exactly(1).times.and_return(state_filter_counts)
|
130
|
+
#subject.state_filter_option_count(option)
|
131
|
+
#subject.state_filter_option_count('South Carolina')
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context :filter_option do
|
136
|
+
let(:option) { 'virginia' }
|
137
|
+
let(:selected) { true }
|
138
|
+
|
139
|
+
it { subject.should respond_to(:state_filter_option) }
|
140
|
+
it { subject.should respond_to(:status_filter_option) }
|
141
|
+
|
142
|
+
it 'should be a properly formatted hash' do
|
143
|
+
subject.should_receive(:state_filter_option_slug).and_return('virginia')
|
144
|
+
subject.should_receive(:state_filter_option_name).and_return('Virginia')
|
145
|
+
subject.should_receive(:state_filter_option_value).and_return('virginia')
|
146
|
+
subject.should_receive(:state_filter_option_count).and_return(1)
|
147
|
+
subject.state_filter_option(option, selected).should == {
|
148
|
+
:slug => 'virginia',
|
149
|
+
:name => 'Virginia',
|
150
|
+
:value => 'virginia',
|
151
|
+
:count => 1,
|
152
|
+
:selected => true
|
153
|
+
}
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context :filter_option_selected? do
|
158
|
+
let(:option) { 'Virginia' }
|
159
|
+
let(:filter_params) { ['Virginia', 'South Carolina'] }
|
160
|
+
|
161
|
+
it { subject.should respond_to(:state_filter_option_selected?) }
|
162
|
+
it { subject.should respond_to(:status_filter_option_selected?) }
|
163
|
+
|
164
|
+
it 'should be true if the option is included in the filter params' do
|
165
|
+
subject.state_filter_option_selected?(filter_params, option).should be_true
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'should be true if filter params is nil' do
|
169
|
+
subject.state_filter_option_selected?(nil, option).should be_true
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'should be false if the option is not included in the filter params' do
|
173
|
+
subject.state_filter_option_selected?(['West Virginia'], option).should be_false
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context :filters do
|
178
|
+
it { subject.should respond_to(:state_filters) }
|
179
|
+
it { subject.should respond_to(:status_filters) }
|
180
|
+
|
181
|
+
it 'should be tested' do
|
182
|
+
pending
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context :relation do
|
187
|
+
it { subject.should respond_to(:state_relation) }
|
188
|
+
it { subject.should respond_to(:status_relation) }
|
189
|
+
|
190
|
+
it 'should be tested' do
|
191
|
+
pending
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
context :filters_as_json do
|
196
|
+
it { subject.should respond_to(:filters_as_json) }
|
197
|
+
|
198
|
+
it 'should be tested' do
|
199
|
+
pending
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
context :filter do
|
204
|
+
it { subject.should respond_to(:filter) }
|
205
|
+
|
206
|
+
it 'should be tested' do
|
207
|
+
pending
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper.rb"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
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
|
+
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.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,30 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-01-
|
13
|
-
dependencies:
|
12
|
+
date: 2012-01-25 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &22782620 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *22782620
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activerecord
|
27
|
+
requirement: &22782200 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *22782200
|
14
36
|
description: ! 'livelist-rails is a Rails 3.1 Engine/Extensiont incorporating the
|
15
37
|
following javascript libraries: Mustache.js, underscore.js, jQuery and livelist.js,
|
16
38
|
and providing ActiveRecord filtering extenstions.'
|
@@ -21,6 +43,7 @@ extensions: []
|
|
21
43
|
extra_rdoc_files: []
|
22
44
|
files:
|
23
45
|
- .gitignore
|
46
|
+
- .rspec
|
24
47
|
- Gemfile
|
25
48
|
- README.md
|
26
49
|
- Rakefile
|
@@ -37,6 +60,9 @@ files:
|
|
37
60
|
- lib/livelist/rails/railtie.rb
|
38
61
|
- lib/livelist/rails/version.rb
|
39
62
|
- livelist-rails.gemspec
|
63
|
+
- spec/livelist/rails/active_record_spec.rb
|
64
|
+
- spec/livelist/spec_helper.rb
|
65
|
+
- spec/spec_helper.rb
|
40
66
|
homepage: ''
|
41
67
|
licenses: []
|
42
68
|
post_install_message:
|
@@ -57,8 +83,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
83
|
version: '0'
|
58
84
|
requirements: []
|
59
85
|
rubyforge_project: livelist-rails
|
60
|
-
rubygems_version: 1.8.
|
86
|
+
rubygems_version: 1.8.15
|
61
87
|
signing_key:
|
62
88
|
specification_version: 3
|
63
89
|
summary: A Rails Engine/Extension Incorporating Livelist.js
|
64
|
-
test_files:
|
90
|
+
test_files:
|
91
|
+
- spec/livelist/rails/active_record_spec.rb
|
92
|
+
- spec/livelist/spec_helper.rb
|
93
|
+
- spec/spec_helper.rb
|