grapple 0.2.0 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 670fc0f6b9406162b5de3113dc4869e181f64b73
4
- data.tar.gz: da7f27323caa88f1847c1a58f753ca94a96d1888
2
+ SHA256:
3
+ metadata.gz: 9a76259d2dd289df0f09d714b30fa6ead30003ac4b63554c8232027f0f729317
4
+ data.tar.gz: 47fad8fb8ea7b8e3015d4598301149f0a3fb7c2a761a464be85081d0865ea339
5
5
  SHA512:
6
- metadata.gz: a6bd235b2e4ad38bb45cf7755f5b84b82e0461d2f7124e3131d11a85f64f8f57d69619d8135531c475682559e2570b4946c807796413b2c9121873ba53c37412
7
- data.tar.gz: bc324f20226c679b46f848032a5eabdf00502a395afd12ff2e61962c244304fe56a09f0da3717d22cf418cf5d64f9d5a39583e28b9b6dd40f0cf4101bfdad633
6
+ metadata.gz: de415d06be64cd90a834600fe9964f3d5df2a65e361e8175789a9a5e4d240d4d4b12ec0c061c4cbddc450708422f2da1c164c269b484ecd3b6844cb10f5d3729
7
+ data.tar.gz: 995d9c603e2f9a09ef9ede25a26af02a51aa112ae3bdb4756542d234dd2fdb07af4772a99634c4a7241e70a9831483ba6fe704205c77f4542d2e1fc49dbda986
data/README.md CHANGED
@@ -189,7 +189,7 @@ Render the table using `table_for` in `app/views/posts/_table.html.erb`
189
189
 
190
190
  ## History w/AJAX (back button)
191
191
 
192
- Requires: https://github.com/browserstate/history.js/
192
+ Uses the native `window.history` API by default. If History.js is present it will use that instead for compatibility with older browsers (https://github.com/browserstate/history.js/).
193
193
 
194
194
  ``` javascript
195
195
  // app/assets/javascripts/application.js
@@ -4,25 +4,62 @@
4
4
  var urlQuery = Grapple.Util.urlQuery,
5
5
  parseUrlQuery = Grapple.Util.parseUrlQuery;
6
6
 
7
- var GrappleHistory = function(namespace) {
8
- this.namespace = namespace;
9
- if(History.init) {
10
- // https://github.com/browserstate/history.js/
11
- this.api = History;
7
+ // History.js for backwards compatibility with older browsers
8
+ // https://github.com/browserstate/history.js/
9
+ var LegacyHistory = function() {
10
+ var api = History;
12
11
 
13
- // Initialization of history.js can be delayed
14
- // if it was do it now
15
- if(this.api.options && this.api.options.delayInit) {
16
- this.api.options.delayInit = false;
17
- this.api.init();
18
- }
12
+ // Initialization of history.js can be delayed
13
+ // if it was do it now
14
+ if(api.options && api.options.delayInit) {
15
+ api.options.delayInit = false;
16
+ api.init();
19
17
  }
20
- else {
21
- // TODO: support native history api
22
- this.api = window.history;
18
+ this.api = api;
19
+ };
20
+
21
+ LegacyHistory.prototype = {
22
+ push: function(params) {
23
+ return this.api.pushState(null, document.title, '?' + params);
24
+ },
25
+ get: function() {
26
+ return urlQuery(this.api.getState().url);
27
+ },
28
+ bind: function(callback) {
29
+ $(window).bind('statechange', callback);
30
+ },
31
+ unbind: function(callback) {
32
+ $(window).unbind('statechange', callback);
23
33
  }
24
- this.api = History;
25
- this.changeCallback = null;
34
+ };
35
+
36
+ // Native Browser History API
37
+ var ModernHistory = function() {
38
+
39
+ };
40
+
41
+ ModernHistory.prototype = {
42
+ push: function(params) {
43
+ if(window.history && window.history.pushState) {
44
+ return window.history.pushState(params, document.title, '?' + params);
45
+ }
46
+ },
47
+ get: function() {
48
+ if(window.history) {
49
+ return window.history.state || urlQuery(document.location.toString());
50
+ }
51
+ },
52
+ bind: function(callback) {
53
+ $(window).bind('popstate', callback);
54
+ },
55
+ unbind: function(callback) {
56
+ $(window).unbind('popstate', callback);
57
+ }
58
+ };
59
+
60
+ var GrappleHistory = function(grappleTable) {
61
+ this.grappleTable = grappleTable;
62
+ this._historyChangeCallback = null;
26
63
  };
27
64
 
28
65
  // Don't clutter the url with rails form parameters
@@ -30,10 +67,20 @@ GrappleHistory.IGNORE_PARAMS = { 'utf8': true, 'authenticity_token': true };
30
67
 
31
68
  GrappleHistory.prototype = {
32
69
 
33
- add: function(params) {
34
- var namespace = this.namespace;
35
- var state = this.api.getState();
36
- var historyParams = parseUrlQuery(urlQuery(state.url));
70
+ init: function() {
71
+ // Use the History.js wrapper if History.js has been loaded
72
+ this.api = typeof History !== 'undefined' && History.init ? new LegacyHistory() : new ModernHistory();
73
+ this._subscribeToTableChange();
74
+ this._subscribeToHistoryChange();
75
+ },
76
+
77
+ /**
78
+ * Add an entry to the history
79
+ * @param {String} params
80
+ */
81
+ _addHistoryEntry: function(params) {
82
+ var namespace = this.grappleTable.namespace;
83
+ var historyParams = parseUrlQuery(this.api.get());
37
84
  var newParams = parseUrlQuery(params);
38
85
 
39
86
  // Remove any parameters from the current state
@@ -57,14 +104,45 @@ GrappleHistory.prototype = {
57
104
  historyParams[x] = newParams[x];
58
105
  }
59
106
 
60
- this.api.pushState(null, document.title, '?' + $.param(historyParams));
107
+ this.api.push($.param(historyParams));
61
108
  },
62
109
 
63
- subscribe: function(callback) {
64
- var api = this.api, namespace = this.namespace;
65
- this.changeCallback = function(event) {
66
- var state = api.getState();
67
- var params = parseUrlQuery(urlQuery(state.url));
110
+ /**
111
+ * Listen for changes to the table to add them to the history
112
+ */
113
+ _subscribeToTableChange: function() {
114
+ var self = this;
115
+ this._beforeLoadCallback = function(e, params) {
116
+ self._unsubscribeFromTableChange();
117
+ self._unsubscribeFromHistoryChange();
118
+ // Don't add params to history if this was triggered by history change
119
+ if(self._ignoreNextLoad) {
120
+ self._ignoreNextLoad = false;
121
+ }
122
+ else {
123
+ self._addHistoryEntry(params);
124
+ }
125
+ };
126
+ this.grappleTable.element.on('grapple:before_load', this._beforeLoadCallback);
127
+ },
128
+
129
+ /**
130
+ * Stop listening for changes to the table
131
+ */
132
+ _unsubscribeFromTableChange: function() {
133
+ if(this._beforeLoadCallback) {
134
+ this.grappleTable.element.unbind('grapple:before_load', this._beforeLoadCallback);
135
+ this._beforeLoadCallback = null;
136
+ }
137
+ },
138
+
139
+ /**
140
+ * Listen for changes to the history (back button clicks)
141
+ */
142
+ _subscribeToHistoryChange: function() {
143
+ var api = this.api, namespace = this.grappleTable.namespace, self = this;
144
+ this._historyChangeCallback = function(event) {
145
+ var params = parseUrlQuery(api.get());
68
146
  // Only include the parameters for this namespace
69
147
  if(namespace) {
70
148
  var r = new RegExp('^' + namespace + '\\[([^\\]]+)\\]$')
@@ -74,15 +152,19 @@ GrappleHistory.prototype = {
74
152
  }
75
153
  }
76
154
  }
77
- callback(params);
155
+ self._ignoreNextLoad = true;
156
+ self.grappleTable.loadTable($.param(params));
78
157
  };
79
- $(window).bind('statechange', this.changeCallback);
158
+ this.api.bind(this._historyChangeCallback);
80
159
  },
81
160
 
82
- unsubscribe: function() {
83
- if(this.changeCallback) {
84
- $(window).unbind('statechange', this.changeCallback);
85
- this.changeCallback = null;
161
+ /**
162
+ * Stop listening for history changes
163
+ */
164
+ _unsubscribeFromHistoryChange: function() {
165
+ if(this._historyChangeCallback) {
166
+ this.api.unbind(this._historyChangeCallback);
167
+ this._historyChangeCallback = null;
86
168
  }
87
169
  }
88
170
 
@@ -1,8 +1,5 @@
1
1
  (function(Grapple, $) {
2
2
  'use strict';
3
-
4
- var urlQuery = Grapple.Util.urlQuery,
5
- parseUrlQuery = Grapple.Util.parseUrlQuery;
6
3
 
7
4
  var overrideLink = function(clickable, anchor, callback) {
8
5
  var href = $(anchor).attr('href');
@@ -15,8 +12,8 @@ var overrideLink = function(clickable, anchor, callback) {
15
12
  /**
16
13
  * Creates a new instance of the Grapple AJAX widget.
17
14
  *
18
- * @param {String} Selector for the table container element.
19
- * @param {Object} Hash of options for the table (url, namespace, history)
15
+ * @param {String} element - Selector for the table container element.
16
+ * @param {Object} options - Hash of options for the table (url, namespace, history)
20
17
  */
21
18
  var GrappleTable = function(element, options) {
22
19
  options = options || {};
@@ -24,16 +21,19 @@ var GrappleTable = function(element, options) {
24
21
  this.url = options.url || this.element.data('grapple-ajax-url');
25
22
  this.namespace = options.namespace || this.element.data('grapple-ajax-namespace') || null;
26
23
  this.currentParams = options.params || '';
24
+ this.plugins = {};
27
25
  if(typeof options.history !== 'undefined' && options.history !== true) {
28
- this.history = options.history;
26
+ this.plugins.history = options.history;
29
27
  }
30
28
  else if(this.element.data('grapple-ajax-history') == 1 || options.history === true) {
31
- this.history = new Grapple.History(this.namespace);
32
- }
33
- else {
34
- this.history = null;
29
+ this.plugins.history = new Grapple.History(this);
35
30
  }
31
+
36
32
  this.init();
33
+
34
+ if (this.element.data('grapple-ajax-init-params')) {
35
+ this.loadTable(this.element.data('grapple-ajax-init-params'))
36
+ }
37
37
  };
38
38
 
39
39
  GrappleTable.CSS_AJAX_LOADING = 'grapple-ajax-loading';
@@ -44,7 +44,7 @@ GrappleTable.NON_TABLE_RESPONSE = '<!DOCTYPE html>';
44
44
  GrappleTable.prototype = {
45
45
 
46
46
  /**
47
- *
47
+ * Initialize the grapple table
48
48
  */
49
49
  init: function() {
50
50
  var self = this;
@@ -56,39 +56,29 @@ GrappleTable.prototype = {
56
56
  self.initSorting();
57
57
  self.initSearchForm();
58
58
  self.initPagination();
59
- self.initHistory();
59
+ self.initPlugins();
60
60
 
61
61
  self.element.removeClass(GrappleTable.CSS_AJAX_LOADING);
62
62
  },
63
63
 
64
- initHistory: function() {
65
- if(this.history) {
66
- var self = this;
67
- this.history.unsubscribe();
68
- this.history = new Grapple.History(this.namespace);
69
- this.history.subscribe(function(params) {
70
- self.onHistoryChange(params);
71
- });
64
+ /**
65
+ * Initialize plugins
66
+ */
67
+ initPlugins: function() {
68
+ for(var name in this.plugins) {
69
+ this.plugins[name].init();
72
70
  }
73
71
  },
74
72
 
75
- onHistoryChange: function(params) {
76
- this._showLoading();
77
- this._updateTable($.param(params));
78
- },
79
-
80
73
  /**
81
- *
74
+ * Load the table contents
75
+ * @param {String} params - Query string of parameters to load the table with
76
+ * @fires Grapple#grapple:before_load
77
+ * @fires Grapple#grapple:after_load
82
78
  */
83
79
  loadTable: function(params) {
84
- this.element.trigger('grapple:before_load');
80
+ this.element.trigger('grapple:before_load', params);
85
81
  this._showLoading();
86
-
87
- if(this.history) {
88
- this.history.unsubscribe();
89
- this.history.add(params);
90
- }
91
-
92
82
  this._updateTable(params);
93
83
  },
94
84
 
@@ -117,7 +107,7 @@ GrappleTable.prototype = {
117
107
  }
118
108
  $.ajax(url, {
119
109
  success: function(data) {
120
- // HACK
110
+ // HACK: handle full page responses
121
111
  var nonTableKeyIndex = data.indexOf(GrappleTable.NON_TABLE_RESPONSE);
122
112
  if(nonTableKeyIndex > -1 && nonTableKeyIndex < 100) {
123
113
  data = "Failed to load table";
@@ -1,9 +1,6 @@
1
1
  (function(globals) {
2
2
  'use strict';
3
3
 
4
- // Namespace
5
- var Grapple = {};
6
-
7
4
  var decodeParam = function(str) {
8
5
  return decodeURIComponent(str.replace(/\+/g, " "));
9
6
  };
@@ -1,2 +1,5 @@
1
1
  en:
2
- no_search_results: "We're sorry. No results were found."
2
+ displaying_x_y_of_z_results: "Displaying %{x} - %{y} of %{z} results"
3
+ no_search_results: "We're sorry. No results were found."
4
+ search: "Search"
5
+ zero_results: "0 results"
@@ -9,7 +9,7 @@ module Grapple
9
9
  template.text_field_tag(
10
10
  search_query_param.to_s,
11
11
  params[search_query_param.to_sym],
12
- { :class => search_query_field_class, placeholder: "Search" }
12
+ { class: search_query_field_class, placeholder: I18n.translate(:search) }
13
13
  )
14
14
  end
15
15
 
@@ -2,9 +2,6 @@ module Grapple
2
2
  module Components
3
3
  class WillPaginateInfobar < HtmlComponent
4
4
 
5
- setting :message, "Displaying %s - %s of %s results"
6
- setting :no_results_message, "0 results"
7
-
8
5
  def render
9
6
  if records.total_entries > 0
10
7
  start_range = records.offset + 1
@@ -14,12 +11,12 @@ module Grapple
14
11
  end_range = ActiveSupport::NumberHelper.number_to_delimited(end_range)
15
12
  total = ActiveSupport::NumberHelper.number_to_delimited(records.total_entries)
16
13
 
17
- html = sprintf(message, start_range, end_range, total)
14
+ html = I18n.translate(:displaying_x_y_of_z_results, x: start_range, y: end_range, z: total)
18
15
  else
19
- html = no_results_message
16
+ html = I18n.translate(:zero_results)
20
17
  end
21
18
 
22
- builder.row "<th colspan=\"#{num_columns}\">#{html}</th>", :class => 'infobar'
19
+ builder.row "<th colspan=\"#{num_columns}\">#{html}</th>", class: 'infobar'
23
20
  end
24
21
 
25
22
  end
@@ -19,9 +19,9 @@ module Grapple
19
19
 
20
20
  if records.instance_of?(Array)
21
21
  html = '&nbsp;'
22
- elsif params.has_key?(:query) && records.empty?
22
+ elsif records.empty?
23
23
  html = h(t(no_results_message))
24
- td_class = "class='text-left'"
24
+ td_class = "class='no-results-message text-left'"
25
25
  else
26
26
  paginate_parameters[:param_name] = url_parameter(:page) if builder.namespace
27
27
  options = { renderer: renderer }.select { |_, value| !value.nil? }.merge(paginate_parameters)
File without changes
File without changes
File without changes
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grapple
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Edward Potocko
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2019-11-18 00:00:00.000000000 Z
13
+ date: 2020-12-11 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: actionpack
@@ -206,8 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
206
206
  - !ruby/object:Gem::Version
207
207
  version: '0'
208
208
  requirements: []
209
- rubyforge_project:
210
- rubygems_version: 2.6.14.1
209
+ rubygems_version: 3.1.2
211
210
  signing_key:
212
211
  specification_version: 4
213
212
  summary: Customizable data grid for Rails