turbograft 0.2.0 → 0.2.1

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
2
  SHA1:
3
- metadata.gz: 7c5cd11ad075c764ef8376a3e89011fd8a42c85b
4
- data.tar.gz: b8958bb7aea77497657f90dc1e0885512f073c90
3
+ metadata.gz: 2a50ca4a110827a3af168d5ff3647bc8fab4eba0
4
+ data.tar.gz: d3ab55d748cdec883171f4b3d37bc54ab00ef7c0
5
5
  SHA512:
6
- metadata.gz: 5ea57c380149b4d2f100f135b7a94429f6721e31ddf5196e3f9e5cd0135f16661d0d37c8981278fd2b1b7f28c1fc615f838cb7c7ccc80354edf5d6facb201fd5
7
- data.tar.gz: eead55c4918b3663e4f051a0688a3c33a193435603abefabdc2b8484ff2b2e47c4e4c5c771c4921524b631618dde68dd5d3ad7adcb1c2a21f38d16bfc074f7de
6
+ metadata.gz: 89c63f79978fb8052c060af6c089b404f10eafe4587b5c46c81d623199f1ac9477884636ac197e82076740eeeed00c28ffeb4f105d24e11132aaf3e80cea39da
7
+ data.tar.gz: 0e4d0f808b6ff7637d3590169a7d7faeba7cbc28fe98ac7563e54a735238c8f7895c9d999c8b8b9d524075eb0fd803e6903149b3773789ad549c228aee2f7b33
data/README.md CHANGED
@@ -3,7 +3,7 @@ Turbograft extends [Turbolinks](https://github.com/rails/turbolinks), allowing y
3
3
 
4
4
  `Graft` - (noun) a shoot or twig inserted into a slit on the trunk or stem of a living plant, from which it receives sap.
5
5
 
6
- In botony, one can take parts of a tree and splice it onto another tree. The DOM is a tree. In this library, we're cutting off sub-trees of the DOM and splicing new ones on.
6
+ In botany, one can take parts of a tree and splice it onto another tree. The DOM is a tree. In this library, we're cutting off sub-trees of the DOM and splicing new ones on.
7
7
 
8
8
  Turbolinks works by intercepting navigation requests and loading them via Ajax when possible, swapping the body tag of the document with the newly loaded copy. Turbograft builds on this to allow you to perform a partial page refresh on specified DOM nodes by adding a refresh key. This allows you reduce page load time, while the feeling of a native, single-page application.
9
9
 
@@ -71,6 +71,9 @@ The `data-tg-refresh-never` attribute will cause a node only appear once in the
71
71
  </div>
72
72
  ```
73
73
 
74
+ ### updatePushState
75
+ Defaults to `true`. When set to false it prevents `Page.refresh()` from updating the url in the browser.
76
+
74
77
  ## data-tg-remote
75
78
 
76
79
  The `data-tg-remote` option allows you to query methods on or submit forms to different endpoints, and gives partial page replacement on specified refresh keys depending on the response status.
@@ -84,7 +87,7 @@ It requires your `<form>`, `<a>`, or `<button>` to be marked up with:
84
87
  * `data-tg-refresh-on-error`: (optional) The refresh keys to be refreshed, but using body of XHR which has failed. Only works with error 422. If the XHR returns and error and you do not supply a refresh-on-error, nothing is changed
85
88
  * `data-tg-full-refresh-on-error-except`: (optional) Replaces body except for specified refresh keys, using the body of the XHR which has failed. Only works with error 422
86
89
  * `data-tg-remote-once`: (optional) The action will only be performed once. Removes `data-tg-remote-method` and `data-tg-remote-once` from element after consumption
87
- * `data-tg-full-refresh`: Rather than using the content of the XHR response for partial page replacement, a full page refresh is performed. If `data-tg-refresh-on-success` is defined, the page will be reloaded on these keys. If `data-tg-refresh-on-success` is not defined, a full page refresh is performed. Defaults to true if neither refresh-on-success nor refresh-on-error are provided
90
+ * `data-tg-full-refresh`: Rather than using the content of the XHR response for partial page replacement, a full page refresh is performed. If `data-tg-refresh-on-success` or `data-tg-refresh-on-error` is defined, the page will be reloaded on those keys. If both `data-tg-refresh-on-success` and `data-tg-refresh-on-error` are not defined, a full page refresh is performed. Defaults to true if neither refresh-on-success nor refresh-on-error are provided
88
91
  * `data-tg-remote-norefresh`: Prevents `Page.refresh()` from being called, allowing methods to be executed without updating client state
89
92
 
90
93
  Note that as `data-tg-refresh-on-*` pertains to partial refreshes and `data-tg-full-refresh-on-*-except` pertains to full refreshes, they are incompatible with each other and should not be combined.
@@ -122,7 +125,7 @@ Post to a remote form:
122
125
  * `turbograft:remote:always`: Always fires when XHR is complete
123
126
  * `turbograft:remote:success`: Always fires when XHR was successful
124
127
  * `turbograft:remote:fail`: Always fires when XHR failed
125
- * `turbograft:remote:fail:unhandled`: Fires after `turbograft:remote:fail`, but when no partial replacement with refresh-on-error was performed (because no `data-tg-refresh-on-error` was supplied)
128
+ * `turbograft:remote:fail:unhandled`: Fires after `turbograft:remote:fail`, but when no partial replacement with refresh-on-error was performed (because no `data-tg-refresh-on-error` was supplied or because `data-tg-remote-norefresh` was present)
126
129
 
127
130
  Each event also is sent with a copy of the XHR, as well as a reference to the element that initated the `data-tg-remote-method`.
128
131
 
@@ -153,14 +153,22 @@ class TurboGraft.Remote
153
153
  initiator: @initiator
154
154
  xhr: xhr
155
155
 
156
- if @refreshOnError
157
- Page.refresh
158
- response: xhr
159
- onlyKeys: @refreshOnError
160
- else if @refreshOnErrorExcept
161
- Page.refresh
162
- response: xhr
163
- exceptKeys: @refreshOnErrorExcept
164
- else
156
+ if TurboGraft.hasTGAttribute(@initiator, 'tg-remote-norefresh')
165
157
  triggerEventFor 'turbograft:remote:fail:unhandled', @initiator,
166
158
  xhr: xhr
159
+ else
160
+ if @opts.fullRefresh && @refreshOnError
161
+ Page.refresh(onlyKeys: @refreshOnError)
162
+ else if @opts.fullRefresh
163
+ Page.refresh()
164
+ else if @refreshOnError
165
+ Page.refresh
166
+ response: xhr
167
+ onlyKeys: @refreshOnError
168
+ else if @refreshOnErrorExcept
169
+ Page.refresh
170
+ response: xhr
171
+ exceptKeys: @refreshOnErrorExcept
172
+ else
173
+ triggerEventFor 'turbograft:remote:fail:unhandled', @initiator,
174
+ xhr: xhr
@@ -4,6 +4,7 @@ module TurboGraft
4
4
  module Redirection
5
5
  extend ActiveSupport::Concern
6
6
 
7
+ private
7
8
  def redirect_via_turbolinks_to(url = {}, response_status = {})
8
9
  redirect_to(url, response_status)
9
10
 
@@ -1,3 +1,3 @@
1
1
  module TurboGraft
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.1'
3
3
  end
data/lib/turbograft.js ADDED
@@ -0,0 +1,978 @@
1
+ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2
+ window.Click = (function() {
3
+ Click.installHandlerLast = function(event) {
4
+ if (!event.defaultPrevented) {
5
+ document.removeEventListener('click', Click.handle, false);
6
+ return document.addEventListener('click', Click.handle, false);
7
+ }
8
+ };
9
+
10
+ Click.handle = function(event) {
11
+ return new Click(event);
12
+ };
13
+
14
+ function Click(event) {
15
+ this.event = event;
16
+ if (this.event.defaultPrevented) {
17
+ return;
18
+ }
19
+ this._extractLink();
20
+ if (this._validForTurbolinks()) {
21
+ if (!this._pageChangePrevented()) {
22
+ Turbolinks.visit(this.link.href);
23
+ }
24
+ this.event.preventDefault();
25
+ }
26
+ }
27
+
28
+ Click.prototype._pageChangePrevented = function() {
29
+ return !triggerEvent('page:before-change');
30
+ };
31
+
32
+ Click.prototype._extractLink = function() {
33
+ var link;
34
+ link = this.event.target;
35
+ while (!(!link.parentNode || link.nodeName === 'A')) {
36
+ link = link.parentNode;
37
+ }
38
+ if (link.nodeName === 'A' && link.href.length !== 0) {
39
+ return this.link = new Link(link);
40
+ }
41
+ };
42
+
43
+ Click.prototype._validForTurbolinks = function() {
44
+ return (this.link != null) && !(this.link.shouldIgnore() || this._nonStandardClick());
45
+ };
46
+
47
+ Click.prototype._nonStandardClick = function() {
48
+ return this.event.which > 1 || this.event.metaKey || this.event.ctrlKey || this.event.shiftKey || this.event.altKey;
49
+ };
50
+
51
+ return Click;
52
+
53
+ })();
54
+
55
+
56
+
57
+ },{}],2:[function(require,module,exports){
58
+ window.ComponentUrl = (function() {
59
+ function ComponentUrl(original) {
60
+ this.original = original != null ? original : document.location.href;
61
+ if (this.original.constructor === ComponentUrl) {
62
+ return this.original;
63
+ }
64
+ this._parse();
65
+ }
66
+
67
+ ComponentUrl.prototype.withoutHash = function() {
68
+ return this.href.replace(this.hash, '');
69
+ };
70
+
71
+ ComponentUrl.prototype.withoutHashForIE10compatibility = function() {
72
+ return this.withoutHash();
73
+ };
74
+
75
+ ComponentUrl.prototype.hasNoHash = function() {
76
+ return this.hash.length === 0;
77
+ };
78
+
79
+ ComponentUrl.prototype._parse = function() {
80
+ var _ref;
81
+ (this.link != null ? this.link : this.link = document.createElement('a')).href = this.original;
82
+ _ref = this.link, this.href = _ref.href, this.protocol = _ref.protocol, this.host = _ref.host, this.hostname = _ref.hostname, this.port = _ref.port, this.pathname = _ref.pathname, this.search = _ref.search, this.hash = _ref.hash;
83
+ this.origin = [this.protocol, '//', this.hostname].join('');
84
+ if (this.port.length !== 0) {
85
+ this.origin += ":" + this.port;
86
+ }
87
+ this.relative = [this.pathname, this.search, this.hash].join('');
88
+ return this.absolute = this.href;
89
+ };
90
+
91
+ return ComponentUrl;
92
+
93
+ })();
94
+
95
+
96
+
97
+ },{}],3:[function(require,module,exports){
98
+ window.CSRFToken = (function() {
99
+ function CSRFToken() {}
100
+
101
+ CSRFToken.get = function(doc) {
102
+ var tag;
103
+ if (doc == null) {
104
+ doc = document;
105
+ }
106
+ return {
107
+ node: tag = doc.querySelector('meta[name="csrf-token"]'),
108
+ token: tag != null ? typeof tag.getAttribute === "function" ? tag.getAttribute('content') : void 0 : void 0
109
+ };
110
+ };
111
+
112
+ CSRFToken.update = function(latest) {
113
+ var current;
114
+ current = this.get();
115
+ if ((current.token != null) && (latest != null) && current.token !== latest) {
116
+ return current.node.setAttribute('content', latest);
117
+ }
118
+ };
119
+
120
+ return CSRFToken;
121
+
122
+ })();
123
+
124
+
125
+
126
+ },{}],4:[function(require,module,exports){
127
+ var documentListenerForButtons, hasClass, nodeIsDisabled;
128
+
129
+ window.TurboGraft = {
130
+ handlers: {}
131
+ };
132
+
133
+ hasClass = function(node, search) {
134
+ var className, _i, _len, _ref;
135
+ _ref = node.classList;
136
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
137
+ className = _ref[_i];
138
+ if (className === search) {
139
+ return true;
140
+ }
141
+ }
142
+ return false;
143
+ };
144
+
145
+ nodeIsDisabled = function(node) {
146
+ return node.getAttribute('disabled') || hasClass(node, 'disabled');
147
+ };
148
+
149
+ TurboGraft.handlers.partialGraftClickHandler = function(ev) {
150
+ var href, keys, partialGraft, refresh, target;
151
+ target = ev.target;
152
+ partialGraft = target.getAttribute("partial-graft");
153
+ if (partialGraft == null) {
154
+ return;
155
+ }
156
+ ev.preventDefault();
157
+ href = target.getAttribute("href");
158
+ refresh = target.getAttribute("refresh");
159
+ if (href == null) {
160
+ throw "TurboGraft developer error: href is not defined on node " + target;
161
+ }
162
+ if (refresh == null) {
163
+ throw "TurboGraft developer error: refresh is not defined on node " + target;
164
+ }
165
+ keys = refresh.trim().split(" ");
166
+ return Page.refresh({
167
+ url: href,
168
+ onlyKeys: keys
169
+ });
170
+ };
171
+
172
+ TurboGraft.handlers.remoteMethodHandler = function(ev) {
173
+ var httpRequestType, httpUrl, onlyOnce, options, remote, target;
174
+ target = ev.target;
175
+ if (!target.getAttribute('remote-method')) {
176
+ return;
177
+ }
178
+ ev.preventDefault();
179
+ httpUrl = target.getAttribute('href');
180
+ httpRequestType = target.getAttribute('remote-method');
181
+ if (!httpRequestType) {
182
+ throw "Turbograft developer error: You did not provide a request type for remote-method";
183
+ }
184
+ if (!httpUrl) {
185
+ throw "Turbograft developer error: You did not provide a URL for remote-method";
186
+ }
187
+ if (onlyOnce = target.getAttribute("remote-once")) {
188
+ target.removeAttribute("remote-once");
189
+ target.removeAttribute("remote-method");
190
+ }
191
+ options = {
192
+ httpRequestType: httpRequestType,
193
+ httpUrl: httpUrl,
194
+ fullRefresh: target.getAttribute('full-refresh') != null,
195
+ refreshOnSuccess: target.getAttribute('refresh-on-success'),
196
+ refreshOnError: target.getAttribute('refresh-on-error')
197
+ };
198
+ remote = new TurboGraft.Remote(options);
199
+ };
200
+
201
+ documentListenerForButtons = function(eventType, handler, useCapture) {
202
+ if (useCapture == null) {
203
+ useCapture = false;
204
+ }
205
+ return document.addEventListener(eventType, function(ev) {
206
+ var target;
207
+ target = ev.target;
208
+ if (!(target.nodeName === "A" || target.nodeName === "BUTTON") || nodeIsDisabled(target)) {
209
+ return;
210
+ }
211
+ return handler(ev);
212
+ });
213
+ };
214
+
215
+ documentListenerForButtons('click', TurboGraft.handlers.partialGraftClickHandler, true);
216
+
217
+ documentListenerForButtons('click', TurboGraft.handlers.remoteMethodHandler, true);
218
+
219
+
220
+
221
+ },{}],5:[function(require,module,exports){
222
+ var __hasProp = {}.hasOwnProperty,
223
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
224
+ __slice = [].slice;
225
+
226
+ window.Link = (function(_super) {
227
+ __extends(Link, _super);
228
+
229
+ Link.HTML_EXTENSIONS = ['html'];
230
+
231
+ Link.allowExtensions = function() {
232
+ var extension, extensions, _i, _len;
233
+ extensions = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
234
+ for (_i = 0, _len = extensions.length; _i < _len; _i++) {
235
+ extension = extensions[_i];
236
+ Link.HTML_EXTENSIONS.push(extension);
237
+ }
238
+ return Link.HTML_EXTENSIONS;
239
+ };
240
+
241
+ function Link(link) {
242
+ this.link = link;
243
+ if (this.link.constructor === Link) {
244
+ return this.link;
245
+ }
246
+ this.original = this.link.href;
247
+ Link.__super__.constructor.apply(this, arguments);
248
+ }
249
+
250
+ Link.prototype.shouldIgnore = function() {
251
+ return this._crossOrigin() || this._anchored() || this._nonHtml() || this._optOut() || this._target();
252
+ };
253
+
254
+ Link.prototype._crossOrigin = function() {
255
+ return this.origin !== (new ComponentUrl).origin;
256
+ };
257
+
258
+ Link.prototype._anchored = function() {
259
+ var current;
260
+ return ((this.hash && this.withoutHash()) === (current = new ComponentUrl).withoutHash()) || (this.href === current.href + '#');
261
+ };
262
+
263
+ Link.prototype._nonHtml = function() {
264
+ return this.pathname.match(/\.[a-z]+$/g) && !this.pathname.match(new RegExp("\\.(?:" + (Link.HTML_EXTENSIONS.join('|')) + ")?$", 'g'));
265
+ };
266
+
267
+ Link.prototype._optOut = function() {
268
+ var ignore, link;
269
+ link = this.link;
270
+ while (!(ignore || link === document || link === null)) {
271
+ ignore = link.getAttribute('data-no-turbolink') != null;
272
+ link = link.parentNode;
273
+ }
274
+ return ignore;
275
+ };
276
+
277
+ Link.prototype._target = function() {
278
+ return this.link.target.length !== 0;
279
+ };
280
+
281
+ return Link;
282
+
283
+ })(ComponentUrl);
284
+
285
+
286
+
287
+ },{}],6:[function(require,module,exports){
288
+ if (!window.Page) {
289
+ window.Page = {};
290
+ }
291
+
292
+ Page.visit = function(url, opts) {
293
+ if (opts == null) {
294
+ opts = {};
295
+ }
296
+ if (opts.reload) {
297
+ return window.location = url;
298
+ } else {
299
+ return Turbolinks.visit(url);
300
+ }
301
+ };
302
+
303
+ Page.refresh = function(options, callback) {
304
+ var newUrl, paramString;
305
+ if (options == null) {
306
+ options = {};
307
+ }
308
+ newUrl = options.url ? options.url : options.queryParams ? (paramString = $.param(options.queryParams), paramString ? paramString = "?" + paramString : void 0, location.pathname + paramString) : location.href;
309
+ if (options.response) {
310
+ return Turbolinks.loadPage(null, options.response, true, callback, options.onlyKeys || []);
311
+ } else {
312
+ return Turbolinks.visit(newUrl, true, options.onlyKeys || [], function() {
313
+ return typeof callback === "function" ? callback() : void 0;
314
+ });
315
+ }
316
+ };
317
+
318
+ Page.open = function() {
319
+ return window.open.apply(window, arguments);
320
+ };
321
+
322
+
323
+
324
+ },{}],7:[function(require,module,exports){
325
+ window.PageCache = (function() {
326
+ var simultaneousAdditionOffset, storage;
327
+
328
+ storage = {};
329
+
330
+ simultaneousAdditionOffset = 0;
331
+
332
+ function PageCache(cacheSize) {
333
+ this.cacheSize = cacheSize != null ? cacheSize : 10;
334
+ storage = {};
335
+ return this;
336
+ }
337
+
338
+ PageCache.prototype.get = function(key) {
339
+ return storage[key];
340
+ };
341
+
342
+ PageCache.prototype.set = function(key, value) {
343
+ if (typeof value !== "object") {
344
+ throw "Developer error: You must store objects in this cache";
345
+ }
346
+ value['cachedAt'] = new Date().getTime() + (simultaneousAdditionOffset += 1);
347
+ storage[key] = value;
348
+ return this.constrain();
349
+ };
350
+
351
+ PageCache.prototype.clear = function() {
352
+ return storage = {};
353
+ };
354
+
355
+ PageCache.prototype.setCacheSize = function(newSize) {
356
+ if (/^[\d]+$/.test(newSize)) {
357
+ this.cacheSize = parseInt(newSize, 10);
358
+ return this.constrain();
359
+ } else {
360
+ throw "Developer error: Invalid parameter '" + newSize + "' for PageCache; must be integer";
361
+ }
362
+ };
363
+
364
+ PageCache.prototype.constrain = function() {
365
+ var cacheTimesRecentFirst, key, pageCacheKeys, _i, _len, _results;
366
+ pageCacheKeys = Object.keys(storage);
367
+ cacheTimesRecentFirst = pageCacheKeys.map((function(_this) {
368
+ return function(url) {
369
+ return storage[url].cachedAt;
370
+ };
371
+ })(this)).sort(function(a, b) {
372
+ return b - a;
373
+ });
374
+ _results = [];
375
+ for (_i = 0, _len = pageCacheKeys.length; _i < _len; _i++) {
376
+ key = pageCacheKeys[_i];
377
+ if (!(storage[key].cachedAt <= cacheTimesRecentFirst[this.cacheSize])) {
378
+ continue;
379
+ }
380
+ triggerEvent('page:expire', storage[key]);
381
+ _results.push(delete storage[key]);
382
+ }
383
+ return _results;
384
+ };
385
+
386
+ PageCache.prototype.length = function() {
387
+ return Object.keys(storage).length;
388
+ };
389
+
390
+ return PageCache;
391
+
392
+ })();
393
+
394
+
395
+
396
+ },{}],8:[function(require,module,exports){
397
+ TurboGraft.Remote = (function() {
398
+ function Remote(opts, form) {
399
+ var actualRequestType, formData, xhr;
400
+ this.opts = opts;
401
+ if (form) {
402
+ formData = new FormData(form);
403
+ } else {
404
+ formData = new FormData();
405
+ }
406
+ actualRequestType = this.opts.httpRequestType.toLowerCase() === 'get' ? 'GET' : 'POST';
407
+ formData.append("_method", this.opts.httpRequestType);
408
+ if (this.opts.refreshOnSuccess) {
409
+ this.refreshOnSuccess = this.opts.refreshOnSuccess.split(" ");
410
+ }
411
+ if (this.opts.refreshOnError) {
412
+ this.refreshOnError = this.opts.refreshOnError.split(" ");
413
+ }
414
+ xhr = new XMLHttpRequest;
415
+ xhr.open(actualRequestType, this.opts.httpUrl, true);
416
+ xhr.setRequestHeader('Accept', 'text/html, application/xhtml+xml, application/xml');
417
+ xhr.addEventListener('loadstart', function() {
418
+ return triggerEvent('turbograft:remote:start', xhr);
419
+ });
420
+ xhr.addEventListener('error', this.onError);
421
+ xhr.addEventListener('load', (function(_this) {
422
+ return function(event) {
423
+ if (xhr.status < 400) {
424
+ return _this.onSuccess(event);
425
+ } else {
426
+ return _this.onError(event);
427
+ }
428
+ };
429
+ })(this));
430
+ xhr.addEventListener('loadend', function() {
431
+ return triggerEvent('turbograft:remote:always', xhr);
432
+ });
433
+ xhr.send(formData);
434
+ return xhr;
435
+ }
436
+
437
+ Remote.prototype.onSuccess = function(ev) {
438
+ var redirect, xhr;
439
+ xhr = ev.target;
440
+ triggerEvent('turbograft:remote:success', xhr);
441
+ if (redirect = xhr.getResponseHeader('X-Next-Redirect')) {
442
+ Page.visit(redirect, {
443
+ reload: true
444
+ });
445
+ return;
446
+ }
447
+ if (this.opts.fullRefresh) {
448
+ return Page.refresh({
449
+ onlyKeys: this.refreshOnSuccess
450
+ });
451
+ } else if (this.refreshOnSuccess) {
452
+ return Page.refresh({
453
+ response: xhr,
454
+ onlyKeys: this.refreshOnSuccess
455
+ });
456
+ }
457
+ };
458
+
459
+ Remote.prototype.onError = function(ev) {
460
+ var xhr;
461
+ xhr = ev.target;
462
+ triggerEvent('turbograft:remote:fail', xhr);
463
+ if (this.refreshOnError) {
464
+ return Page.refresh({
465
+ response: xhr,
466
+ onlyKeys: this.refreshOnError
467
+ });
468
+ } else {
469
+ return triggerEvent('turbograft:remote:fail:unhandled', xhr);
470
+ }
471
+ };
472
+
473
+ return Remote;
474
+
475
+ })();
476
+
477
+
478
+
479
+ },{}],9:[function(require,module,exports){
480
+ var browserIsntBuggy, browserSupportsCustomEvents, browserSupportsPushState, browserSupportsTurbolinks, historyStateIsDefined, installDocumentReadyPageEventTriggers, installJqueryAjaxSuccessPageUpdateTrigger, popCookie, requestMethodIsSafe, xhr, _ref,
481
+ __slice = [].slice,
482
+ __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
483
+
484
+ xhr = null;
485
+
486
+ installDocumentReadyPageEventTriggers = function() {
487
+ return document.addEventListener('DOMContentLoaded', (function() {
488
+ triggerEvent('page:change');
489
+ return triggerEvent('page:update');
490
+ }), true);
491
+ };
492
+
493
+ installJqueryAjaxSuccessPageUpdateTrigger = function() {
494
+ if (typeof jQuery !== 'undefined') {
495
+ return jQuery(document).on('ajaxSuccess', function(event, xhr, settings) {
496
+ if (!jQuery.trim(xhr.responseText)) {
497
+ return;
498
+ }
499
+ return triggerEvent('page:update');
500
+ });
501
+ }
502
+ };
503
+
504
+ historyStateIsDefined = window.history.state !== void 0 || navigator.userAgent.match(/Firefox\/2[6|7]/);
505
+
506
+ browserSupportsPushState = window.history && window.history.pushState && window.history.replaceState && historyStateIsDefined;
507
+
508
+ browserIsntBuggy = !navigator.userAgent.match(/CriOS\//);
509
+
510
+ window.triggerEvent = function(name, data) {
511
+ var event;
512
+ event = document.createEvent('Events');
513
+ if (data) {
514
+ event.data = data;
515
+ }
516
+ event.initEvent(name, true, true);
517
+ return document.dispatchEvent(event);
518
+ };
519
+
520
+ popCookie = function(name) {
521
+ var value, _ref;
522
+ value = ((_ref = document.cookie.match(new RegExp(name + "=(\\w+)"))) != null ? _ref[1].toUpperCase() : void 0) || '';
523
+ document.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/';
524
+ return value;
525
+ };
526
+
527
+ requestMethodIsSafe = (_ref = popCookie('request_method')) === 'GET' || _ref === '';
528
+
529
+ browserSupportsTurbolinks = browserSupportsPushState && browserIsntBuggy && requestMethodIsSafe;
530
+
531
+ browserSupportsCustomEvents = document.addEventListener && document.createEvent;
532
+
533
+ if (browserSupportsCustomEvents) {
534
+ installDocumentReadyPageEventTriggers();
535
+ installJqueryAjaxSuccessPageUpdateTrigger();
536
+ }
537
+
538
+ window.Turbolinks = (function() {
539
+ var browserCompatibleDocumentParser, bypassOnLoadPopstate, changePage, createDocument, currentState, deleteRefreshNeverNodes, executeScriptTag, executeScriptTags, extractTitleAndBody, fetch, fetchHistory, fetchReplacement, installHistoryChangeHandler, loadedAssets, pageCache, pageChangePrevented, processResponse, recallScrollPosition, referer, reflectNewUrl, reflectRedirectedUrl, refreshNodesWithKeys, rememberReferer, removeNoscriptTags, resetScrollPosition, transitionCacheFor, usePageCache;
540
+
541
+ function Turbolinks() {}
542
+
543
+ createDocument = null;
544
+
545
+ currentState = null;
546
+
547
+ loadedAssets = null;
548
+
549
+ referer = null;
550
+
551
+ usePageCache = false;
552
+
553
+ Turbolinks.pageCache = pageCache = new PageCache();
554
+
555
+ fetch = function(url, partialReplace, replaceContents, callback) {
556
+ var cachedPage;
557
+ if (partialReplace == null) {
558
+ partialReplace = false;
559
+ }
560
+ if (replaceContents == null) {
561
+ replaceContents = [];
562
+ }
563
+ url = new ComponentUrl(url);
564
+ rememberReferer();
565
+ if (usePageCache) {
566
+ Turbolinks.cacheCurrentPage();
567
+ }
568
+ if (usePageCache && (cachedPage = transitionCacheFor(url.absolute))) {
569
+ fetchHistory(cachedPage);
570
+ return fetchReplacement(url, partialReplace, null, replaceContents);
571
+ } else {
572
+ return fetchReplacement(url, partialReplace, function() {
573
+ if (!replaceContents.length) {
574
+ resetScrollPosition();
575
+ }
576
+ return typeof callback === "function" ? callback() : void 0;
577
+ }, replaceContents);
578
+ }
579
+ };
580
+
581
+ Turbolinks.pageCacheEnabled = function() {
582
+ return usePageCache;
583
+ };
584
+
585
+ Turbolinks.usePageCache = function(status) {
586
+ return usePageCache = status;
587
+ };
588
+
589
+ transitionCacheFor = function(url) {
590
+ var cachedPage;
591
+ cachedPage = pageCache.get(url);
592
+ if (cachedPage && !cachedPage.transitionCacheDisabled) {
593
+ return cachedPage;
594
+ }
595
+ };
596
+
597
+ Turbolinks.pushState = function(state, title, url) {
598
+ return window.history.pushState(state, title, url);
599
+ };
600
+
601
+ Turbolinks.replaceState = function(state, title, url) {
602
+ return window.history.replaceState(state, title, url);
603
+ };
604
+
605
+ fetchReplacement = function(url, partialReplace, onLoadFunction, replaceContents) {
606
+ triggerEvent('page:fetch', {
607
+ url: url.absolute
608
+ });
609
+ if (xhr != null) {
610
+ xhr.abort();
611
+ }
612
+ xhr = new XMLHttpRequest;
613
+ xhr.open('GET', url.withoutHashForIE10compatibility(), true);
614
+ xhr.setRequestHeader('Accept', 'text/html, application/xhtml+xml, application/xml');
615
+ xhr.setRequestHeader('X-XHR-Referer', referer);
616
+ xhr.onload = function() {
617
+ if (xhr.status >= 500) {
618
+ return document.location.href = url.absolute;
619
+ } else {
620
+ return Turbolinks.loadPage(url, xhr, partialReplace, onLoadFunction, replaceContents);
621
+ }
622
+ };
623
+ xhr.onloadend = function() {
624
+ return xhr = null;
625
+ };
626
+ xhr.onerror = function() {
627
+ return document.location.href = url.absolute;
628
+ };
629
+ xhr.send();
630
+ };
631
+
632
+ Turbolinks.loadPage = function(url, xhr, partialReplace, onLoadFunction, replaceContents) {
633
+ var doc, nodes;
634
+ if (partialReplace == null) {
635
+ partialReplace = false;
636
+ }
637
+ if (onLoadFunction == null) {
638
+ onLoadFunction = (function() {});
639
+ }
640
+ if (replaceContents == null) {
641
+ replaceContents = [];
642
+ }
643
+ triggerEvent('page:receive');
644
+ if (doc = processResponse(xhr, partialReplace)) {
645
+ reflectNewUrl(url);
646
+ nodes = changePage.apply(null, __slice.call(extractTitleAndBody(doc)).concat([partialReplace], [replaceContents]));
647
+ reflectRedirectedUrl(xhr);
648
+ triggerEvent('page:load', nodes);
649
+ if (typeof onLoadFunction === "function") {
650
+ onLoadFunction();
651
+ }
652
+ } else {
653
+ document.location.href = url.absolute;
654
+ }
655
+ };
656
+
657
+ fetchHistory = function(cachedPage) {
658
+ if (xhr != null) {
659
+ xhr.abort();
660
+ }
661
+ changePage(cachedPage.title, cachedPage.body, false);
662
+ recallScrollPosition(cachedPage);
663
+ return triggerEvent('page:restore');
664
+ };
665
+
666
+ Turbolinks.cacheCurrentPage = function() {
667
+ var currentStateUrl;
668
+ currentStateUrl = new ComponentUrl(currentState.url);
669
+ pageCache.set(currentStateUrl.absolute, {
670
+ url: currentStateUrl.relative,
671
+ body: document.body,
672
+ title: document.title,
673
+ positionY: window.pageYOffset,
674
+ positionX: window.pageXOffset,
675
+ transitionCacheDisabled: document.querySelector('[data-no-transition-cache]') != null
676
+ });
677
+ };
678
+
679
+ changePage = function(title, body, csrfToken, runScripts, partialReplace, replaceContents) {
680
+ if (replaceContents == null) {
681
+ replaceContents = [];
682
+ }
683
+ if (title) {
684
+ document.title = title;
685
+ }
686
+ if (replaceContents.length) {
687
+ return refreshNodesWithKeys(replaceContents, body);
688
+ } else {
689
+ deleteRefreshNeverNodes(body);
690
+ triggerEvent('page:before-replace');
691
+ document.documentElement.replaceChild(body, document.body);
692
+ if (csrfToken != null) {
693
+ CSRFToken.update(csrfToken);
694
+ }
695
+ if (runScripts) {
696
+ executeScriptTags();
697
+ }
698
+ currentState = window.history.state;
699
+ triggerEvent('page:change');
700
+ triggerEvent('page:update');
701
+ }
702
+ };
703
+
704
+ deleteRefreshNeverNodes = function(body) {
705
+ var node, _i, _len, _ref1;
706
+ _ref1 = body.querySelectorAll('[refresh-never]');
707
+ for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
708
+ node = _ref1[_i];
709
+ node.parentNode.removeChild(node);
710
+ }
711
+ };
712
+
713
+ refreshNodesWithKeys = function(keys, body) {
714
+ var allNodesToBeRefreshed, existingNode, key, newNode, node, nodeId, parentIsRefreshing, refreshedNodes, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref1, _ref2;
715
+ allNodesToBeRefreshed = [];
716
+ _ref1 = document.querySelectorAll("[refresh-always]");
717
+ for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
718
+ node = _ref1[_i];
719
+ allNodesToBeRefreshed.push(node);
720
+ }
721
+ for (_j = 0, _len1 = keys.length; _j < _len1; _j++) {
722
+ key = keys[_j];
723
+ _ref2 = document.querySelectorAll("[refresh=" + key + "]");
724
+ for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
725
+ node = _ref2[_k];
726
+ allNodesToBeRefreshed.push(node);
727
+ }
728
+ }
729
+ triggerEvent('page:before-partial-replace', allNodesToBeRefreshed);
730
+ parentIsRefreshing = function(node) {
731
+ var potentialParent, _l, _len3;
732
+ for (_l = 0, _len3 = allNodesToBeRefreshed.length; _l < _len3; _l++) {
733
+ potentialParent = allNodesToBeRefreshed[_l];
734
+ if (node !== potentialParent) {
735
+ if (potentialParent.contains(node)) {
736
+ return true;
737
+ }
738
+ }
739
+ }
740
+ return false;
741
+ };
742
+ refreshedNodes = [];
743
+ for (_l = 0, _len3 = allNodesToBeRefreshed.length; _l < _len3; _l++) {
744
+ existingNode = allNodesToBeRefreshed[_l];
745
+ if (parentIsRefreshing(existingNode)) {
746
+ continue;
747
+ }
748
+ if (!(nodeId = existingNode.getAttribute('id'))) {
749
+ throw new Error("Turbolinks refresh: Refresh key elements must have an id.");
750
+ }
751
+ if (newNode = body.querySelector("#" + nodeId)) {
752
+ existingNode.parentNode.replaceChild(newNode, existingNode);
753
+ if (newNode.nodeName === 'SCRIPT' && newNode.getAttribute("data-turbolinks-eval") !== "false") {
754
+ executeScriptTag(newNode);
755
+ } else {
756
+ refreshedNodes.push(newNode);
757
+ }
758
+ } else if (existingNode.getAttribute("refresh-always") === null) {
759
+ existingNode.parentNode.removeChild(existingNode);
760
+ }
761
+ }
762
+ return refreshedNodes;
763
+ };
764
+
765
+ executeScriptTags = function() {
766
+ var script, scripts, _i, _len, _ref1;
767
+ scripts = Array.prototype.slice.call(document.body.querySelectorAll('script:not([data-turbolinks-eval="false"])'));
768
+ for (_i = 0, _len = scripts.length; _i < _len; _i++) {
769
+ script = scripts[_i];
770
+ if ((_ref1 = script.type) === '' || _ref1 === 'text/javascript') {
771
+ executeScriptTag(script);
772
+ }
773
+ }
774
+ };
775
+
776
+ executeScriptTag = function(script) {
777
+ var attr, copy, nextSibling, parentNode, _i, _len, _ref1;
778
+ copy = document.createElement('script');
779
+ _ref1 = script.attributes;
780
+ for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
781
+ attr = _ref1[_i];
782
+ copy.setAttribute(attr.name, attr.value);
783
+ }
784
+ copy.appendChild(document.createTextNode(script.innerHTML));
785
+ parentNode = script.parentNode, nextSibling = script.nextSibling;
786
+ parentNode.removeChild(script);
787
+ parentNode.insertBefore(copy, nextSibling);
788
+ };
789
+
790
+ removeNoscriptTags = function(node) {
791
+ node.innerHTML = node.innerHTML.replace(/<noscript[\S\s]*?<\/noscript>/ig, '');
792
+ return node;
793
+ };
794
+
795
+ reflectNewUrl = function(url) {
796
+ if ((url = new ComponentUrl(url)).absolute !== referer) {
797
+ Turbolinks.pushState({
798
+ turbolinks: true,
799
+ url: url.absolute
800
+ }, '', url.absolute);
801
+ }
802
+ };
803
+
804
+ reflectRedirectedUrl = function(xhr) {
805
+ var location, preservedHash;
806
+ if (location = xhr.getResponseHeader('X-XHR-Redirected-To')) {
807
+ location = new ComponentUrl(location);
808
+ preservedHash = location.hasNoHash() ? document.location.hash : '';
809
+ Turbolinks.replaceState(currentState, '', location.href + preservedHash);
810
+ }
811
+ };
812
+
813
+ rememberReferer = function() {
814
+ return referer = document.location.href;
815
+ };
816
+
817
+ Turbolinks.rememberCurrentUrl = function() {
818
+ return Turbolinks.replaceState({
819
+ turbolinks: true,
820
+ url: document.location.href
821
+ }, '', document.location.href);
822
+ };
823
+
824
+ Turbolinks.rememberCurrentState = function() {
825
+ return currentState = window.history.state;
826
+ };
827
+
828
+ recallScrollPosition = function(page) {
829
+ return window.scrollTo(page.positionX, page.positionY);
830
+ };
831
+
832
+ resetScrollPosition = function() {
833
+ if (document.location.hash) {
834
+ return document.location.href = document.location.href;
835
+ } else {
836
+ return window.scrollTo(0, 0);
837
+ }
838
+ };
839
+
840
+ pageChangePrevented = function() {
841
+ return !triggerEvent('page:before-change');
842
+ };
843
+
844
+ processResponse = function(xhr, partial) {
845
+ var assetsChanged, changed, clientOrServerError, doc, extractTrackAssets, intersection, validContent;
846
+ if (partial == null) {
847
+ partial = false;
848
+ }
849
+ clientOrServerError = function() {
850
+ var _ref1;
851
+ if (xhr.status === 422) {
852
+ return false;
853
+ }
854
+ return (400 <= (_ref1 = xhr.status) && _ref1 < 600);
855
+ };
856
+ validContent = function() {
857
+ return xhr.getResponseHeader('Content-Type').match(/^(?:text\/html|application\/xhtml\+xml|application\/xml)(?:;|$)/);
858
+ };
859
+ extractTrackAssets = function(doc) {
860
+ var node, _i, _len, _ref1, _results;
861
+ _ref1 = doc.head.childNodes;
862
+ _results = [];
863
+ for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
864
+ node = _ref1[_i];
865
+ if ((typeof node.getAttribute === "function" ? node.getAttribute('data-turbolinks-track') : void 0) != null) {
866
+ _results.push(node.getAttribute('src') || node.getAttribute('href'));
867
+ }
868
+ }
869
+ return _results;
870
+ };
871
+ assetsChanged = function(doc) {
872
+ var fetchedAssets;
873
+ loadedAssets || (loadedAssets = extractTrackAssets(document));
874
+ fetchedAssets = extractTrackAssets(doc);
875
+ return fetchedAssets.length !== loadedAssets.length || intersection(fetchedAssets, loadedAssets).length !== loadedAssets.length;
876
+ };
877
+ intersection = function(a, b) {
878
+ var value, _i, _len, _ref1, _results;
879
+ if (a.length > b.length) {
880
+ _ref1 = [b, a], a = _ref1[0], b = _ref1[1];
881
+ }
882
+ _results = [];
883
+ for (_i = 0, _len = a.length; _i < _len; _i++) {
884
+ value = a[_i];
885
+ if (__indexOf.call(b, value) >= 0) {
886
+ _results.push(value);
887
+ }
888
+ }
889
+ return _results;
890
+ };
891
+ if (!clientOrServerError() && validContent()) {
892
+ doc = createDocument(xhr.responseText);
893
+ changed = assetsChanged(doc);
894
+ if (doc && (!changed || partial)) {
895
+ return doc;
896
+ }
897
+ }
898
+ };
899
+
900
+ extractTitleAndBody = function(doc) {
901
+ var title;
902
+ title = doc.querySelector('title');
903
+ return [title != null ? title.textContent : void 0, removeNoscriptTags(doc.body), CSRFToken.get(doc).token, 'runScripts'];
904
+ };
905
+
906
+ installHistoryChangeHandler = function(event) {
907
+ var cachedPage, _ref1;
908
+ if ((_ref1 = event.state) != null ? _ref1.turbolinks : void 0) {
909
+ if (cachedPage = pageCache.get((new ComponentUrl(event.state.url)).absolute)) {
910
+ Turbolinks.cacheCurrentPage();
911
+ return fetchHistory(cachedPage);
912
+ } else {
913
+ return Turbolinks.visit(event.target.location.href);
914
+ }
915
+ }
916
+ };
917
+
918
+ bypassOnLoadPopstate = function(fn) {
919
+ return setTimeout(fn, 500);
920
+ };
921
+
922
+ browserCompatibleDocumentParser = function() {
923
+ var createDocumentUsingDOM, createDocumentUsingParser, createDocumentUsingWrite, e, testDoc, _ref1;
924
+ createDocumentUsingParser = function(html) {
925
+ return (new DOMParser).parseFromString(html, 'text/html');
926
+ };
927
+ createDocumentUsingDOM = function(html) {
928
+ var doc;
929
+ doc = document.implementation.createHTMLDocument('');
930
+ doc.documentElement.innerHTML = html;
931
+ return doc;
932
+ };
933
+ createDocumentUsingWrite = function(html) {
934
+ var doc;
935
+ doc = document.implementation.createHTMLDocument('');
936
+ doc.open('replace');
937
+ doc.write(html);
938
+ doc.close();
939
+ return doc;
940
+ };
941
+ try {
942
+ if (window.DOMParser) {
943
+ testDoc = createDocumentUsingParser('<html><body><p>test');
944
+ return createDocumentUsingParser;
945
+ }
946
+ } catch (_error) {
947
+ e = _error;
948
+ testDoc = createDocumentUsingDOM('<html><body><p>test');
949
+ return createDocumentUsingDOM;
950
+ } finally {
951
+ if ((testDoc != null ? (_ref1 = testDoc.body) != null ? _ref1.childNodes.length : void 0 : void 0) !== 1) {
952
+ return createDocumentUsingWrite;
953
+ }
954
+ }
955
+ };
956
+
957
+ if (browserSupportsTurbolinks) {
958
+ Turbolinks.visit = fetch;
959
+ Turbolinks.rememberCurrentUrl();
960
+ Turbolinks.rememberCurrentState();
961
+ createDocument = browserCompatibleDocumentParser();
962
+ document.addEventListener('click', Click.installHandlerLast, true);
963
+ bypassOnLoadPopstate(function() {
964
+ return window.addEventListener('popstate', installHistoryChangeHandler, false);
965
+ });
966
+ } else {
967
+ Turbolinks.visit = function(url) {
968
+ return document.location.href = url;
969
+ };
970
+ }
971
+
972
+ return Turbolinks;
973
+
974
+ })();
975
+
976
+
977
+
978
+ },{}]},{},[1,2,3,5,6,7,9,4,8]);
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbograft
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kristian Plettenberg-Dussault
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2015-11-23 00:00:00.000000000 Z
16
+ date: 2016-05-25 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: coffee-rails
@@ -229,6 +229,7 @@ files:
229
229
  - lib/assets/javascripts/turbograft/page.coffee
230
230
  - lib/assets/javascripts/turbograft/remote.coffee
231
231
  - lib/assets/javascripts/turbograft/turbolinks.coffee
232
+ - lib/turbograft.js
232
233
  - lib/turbograft.rb
233
234
  - lib/turbograft/cookies.rb
234
235
  - lib/turbograft/redirection.rb
@@ -256,7 +257,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
256
257
  version: '0'
257
258
  requirements: []
258
259
  rubyforge_project:
259
- rubygems_version: 2.4.5.1
260
+ rubygems_version: 2.2.2
260
261
  signing_key:
261
262
  specification_version: 4
262
263
  summary: turbolinks with partial page replacement