grapple 0.2.1 → 0.3.0

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
- SHA256:
3
- metadata.gz: a00ec50832f4583379666e80a35b898efc63c066b1b19018efeccbfadefeb531
4
- data.tar.gz: fb7475bad8276a7f4867622aaf3fe47d09829853d12841795fb9ce4455697399
2
+ SHA1:
3
+ metadata.gz: 1d49408d1a5288a086cb3cb5016d2c6e68b09691
4
+ data.tar.gz: 6cbd12c3529aa3bb347771430e6bffab4926924b
5
5
  SHA512:
6
- metadata.gz: 9255cd578e733a19c272c73e47fc3fae1ac17838aa61f355a0fa150e6bd31d37ba0236a0f825cd441a9e082fb26241ddad3237bf041582ae0312275c9c8a3722
7
- data.tar.gz: 985d05b1ac0354f7ae92b5a78acf3a2236b2543bc083041009bc084539c09aa315b0f9becb1a99901944b7ece92c853f65ddb6fc6b759b3a19a04c4e4c6bd952
6
+ metadata.gz: e4fb86706c0372306b4381daa0224257b16589318d2726e9451294696e2bc5707359c29b6a2fcb907266bdca4493f7d385975b0c7e0d501cb6ec0f5cd017bb5c
7
+ data.tar.gz: 13e5c2b134d2930a836db20d3c8ea619cafccd0f69e43201171f178f1b1e3d9244468973878b8b85b4f3cd5c2d8da8cbc667df5ce9d9603ff695f612733f61f2
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,14 +21,12 @@ 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
  }
36
31
  this.init();
37
32
  };
@@ -44,7 +39,7 @@ GrappleTable.NON_TABLE_RESPONSE = '<!DOCTYPE html>';
44
39
  GrappleTable.prototype = {
45
40
 
46
41
  /**
47
- *
42
+ * Initialize the grapple table
48
43
  */
49
44
  init: function() {
50
45
  var self = this;
@@ -56,39 +51,29 @@ GrappleTable.prototype = {
56
51
  self.initSorting();
57
52
  self.initSearchForm();
58
53
  self.initPagination();
59
- self.initHistory();
54
+ self.initPlugins();
60
55
 
61
56
  self.element.removeClass(GrappleTable.CSS_AJAX_LOADING);
62
57
  },
63
58
 
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
- });
59
+ /**
60
+ * Initialize plugins
61
+ */
62
+ initPlugins: function() {
63
+ for(var name in this.plugins) {
64
+ this.plugins[name].init();
72
65
  }
73
66
  },
74
67
 
75
- onHistoryChange: function(params) {
76
- this._showLoading();
77
- this._updateTable($.param(params));
78
- },
79
-
80
68
  /**
81
- *
69
+ * Load the table contents
70
+ * @param {String} params - Query string of parameters to load the table with
71
+ * @fires Grapple#grapple:before_load
72
+ * @fires Grapple#grapple:after_load
82
73
  */
83
74
  loadTable: function(params) {
84
- this.element.trigger('grapple:before_load');
75
+ this.element.trigger('grapple:before_load', params);
85
76
  this._showLoading();
86
-
87
- if(this.history) {
88
- this.history.unsubscribe();
89
- this.history.add(params);
90
- }
91
-
92
77
  this._updateTable(params);
93
78
  },
94
79
 
@@ -117,7 +102,7 @@ GrappleTable.prototype = {
117
102
  }
118
103
  $.ajax(url, {
119
104
  success: function(data) {
120
- // HACK
105
+ // HACK: handle full page responses
121
106
  var nonTableKeyIndex = data.indexOf(GrappleTable.NON_TABLE_RESPONSE);
122
107
  if(nonTableKeyIndex > -1 && nonTableKeyIndex < 100) {
123
108
  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
  };
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.1
4
+ version: 0.3.0
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
@@ -207,7 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
207
207
  version: '0'
208
208
  requirements: []
209
209
  rubyforge_project:
210
- rubygems_version: 2.7.6.2
210
+ rubygems_version: 2.6.14.1
211
211
  signing_key:
212
212
  specification_version: 4
213
213
  summary: Customizable data grid for Rails