livelist-rails 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|