@glitchr/transparent 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/package.json +15 -0
- package/src/css/index.css +15 -0
- package/src/index.js +1645 -0
package/src/index.js
ADDED
|
@@ -0,0 +1,1645 @@
|
|
|
1
|
+
(function(namespace) {
|
|
2
|
+
|
|
3
|
+
namespace.replaceHash = function(newHash, triggerHashChange = true, skipIfEmptyIdentifier = true) {
|
|
4
|
+
|
|
5
|
+
if(!newHash) newHash = "";
|
|
6
|
+
if (newHash !== "" && (''+newHash).charAt(0) !== '#')
|
|
7
|
+
newHash = '#' + newHash;
|
|
8
|
+
|
|
9
|
+
var oldURL = location.origin+location.pathname+location.hash;
|
|
10
|
+
var newURL = location.origin+location.pathname+newHash;
|
|
11
|
+
|
|
12
|
+
var fallback = $(newHash).length === 0;
|
|
13
|
+
|
|
14
|
+
var hashElement = $(newHash)[0] ?? undefined;
|
|
15
|
+
if (hashElement !== undefined) // Update hash only if element is displayed
|
|
16
|
+
fallback |= window.getComputedStyle(hashElement)["display"] == "none";
|
|
17
|
+
|
|
18
|
+
if((skipIfEmptyIdentifier && !newHash) || fallback){
|
|
19
|
+
|
|
20
|
+
dispatchEvent(new HashChangeEvent("hashfallback", {oldURL:oldURL, newURL:newURL}));
|
|
21
|
+
newHash = "";
|
|
22
|
+
|
|
23
|
+
oldURL = location.origin+location.pathname+location.hash;
|
|
24
|
+
newURL = location.origin+location.pathname+newHash;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if(oldURL == newURL) return false;
|
|
28
|
+
|
|
29
|
+
var state = Object.assign({}, history.state, {href: newURL});
|
|
30
|
+
history.replaceState(state, '', newURL);
|
|
31
|
+
|
|
32
|
+
if(triggerHashChange)
|
|
33
|
+
dispatchEvent(new HashChangeEvent("hashchange", {oldURL:oldURL, newURL:newURL}));
|
|
34
|
+
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
})(window);
|
|
39
|
+
|
|
40
|
+
$.fn.serializeObject = function() {
|
|
41
|
+
var o = {};
|
|
42
|
+
var a = this.serializeArray();
|
|
43
|
+
$.each(a, function() {
|
|
44
|
+
if (o[this.name]) {
|
|
45
|
+
if (!o[this.name].push) {
|
|
46
|
+
o[this.name] = [o[this.name]];
|
|
47
|
+
}
|
|
48
|
+
o[this.name].push(this.value || '');
|
|
49
|
+
} else {
|
|
50
|
+
o[this.name] = this.value || '';
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return o;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
$.fn.isScrollable = function()
|
|
57
|
+
{
|
|
58
|
+
for (let el of $(this).isScrollableX())
|
|
59
|
+
if(el) return true;
|
|
60
|
+
|
|
61
|
+
for (let el of $(this).isScrollableY())
|
|
62
|
+
if(el) return true;
|
|
63
|
+
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
$.fn.isScrollableX = function() {
|
|
68
|
+
|
|
69
|
+
return $(this).map(function(i) {
|
|
70
|
+
|
|
71
|
+
var el = this[i] === window ? document.documentElement : this[i];
|
|
72
|
+
var isDom = el == document.documentElement;
|
|
73
|
+
|
|
74
|
+
var hasScrollableContent = el.scrollWidth > el.clientWidth;
|
|
75
|
+
|
|
76
|
+
var overflowStyle = window.getComputedStyle(el).overflowX;
|
|
77
|
+
var isOverflowScroll = overflowStyle.indexOf('scroll') !== -1;
|
|
78
|
+
|
|
79
|
+
return hasScrollableContent && (isOverflowScroll || isDom);
|
|
80
|
+
|
|
81
|
+
}.bind(this));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
$.fn.isScrollableY = function() {
|
|
85
|
+
|
|
86
|
+
return $(this).map(function(i) {
|
|
87
|
+
|
|
88
|
+
var el = this[i] === window ? document.documentElement : this[i];
|
|
89
|
+
var isDom = el == document.documentElement;
|
|
90
|
+
|
|
91
|
+
var hasScrollableContent = el.scrollHeight > el.clientHeight;
|
|
92
|
+
|
|
93
|
+
var overflowStyle = window.getComputedStyle(el).overflowY;
|
|
94
|
+
var isOverflowScroll = overflowStyle.indexOf('scroll') !== -1;
|
|
95
|
+
|
|
96
|
+
return hasScrollableContent && (isOverflowScroll || isDom);
|
|
97
|
+
|
|
98
|
+
}.bind(this));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
$.fn.closestScrollable = function()
|
|
102
|
+
{
|
|
103
|
+
return $(this).map((i) => {
|
|
104
|
+
|
|
105
|
+
var target = this[i] === window ? document.documentElement : this[i];
|
|
106
|
+
if (target === undefined) target = document.documentElement;
|
|
107
|
+
|
|
108
|
+
while (target !== document.documentElement) {
|
|
109
|
+
|
|
110
|
+
if($(target).isScrollable()) return target;
|
|
111
|
+
|
|
112
|
+
if(target.parentElement === undefined) return undefined;
|
|
113
|
+
if(target.parentElement === null) return null;
|
|
114
|
+
|
|
115
|
+
target = target.parentElement;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return $(target).isScrollable() ? target : undefined;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
$.fn.repaint = function(duration = 1000, reiteration=5) {
|
|
123
|
+
|
|
124
|
+
var time = 0;
|
|
125
|
+
var interval = undefined;
|
|
126
|
+
var fn = function () {
|
|
127
|
+
|
|
128
|
+
$(this).each(function (_, el) {
|
|
129
|
+
|
|
130
|
+
var displayBak = el.style.display;
|
|
131
|
+
|
|
132
|
+
el.style.display = "none";
|
|
133
|
+
el.style.display = displayBak;
|
|
134
|
+
el.offsetHeight;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
if (time > duration) clearInterval(interval);
|
|
138
|
+
time += duration/reiteration;
|
|
139
|
+
|
|
140
|
+
}.bind(this);
|
|
141
|
+
|
|
142
|
+
fn();
|
|
143
|
+
if(reiteration > 0)
|
|
144
|
+
interval = setInterval(fn, duration/reiteration);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
;(function (root, factory) {
|
|
148
|
+
|
|
149
|
+
if (typeof define === 'function' && define.amd) {
|
|
150
|
+
define(factory);
|
|
151
|
+
} else if (typeof exports === 'object') {
|
|
152
|
+
module.exports = factory();
|
|
153
|
+
} else {
|
|
154
|
+
root.Transparent = factory();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
})(this, function () {
|
|
158
|
+
|
|
159
|
+
var Transparent = {};
|
|
160
|
+
Transparent.version = '0.1.0';
|
|
161
|
+
|
|
162
|
+
var Settings = Transparent.settings = {
|
|
163
|
+
"headers": {},
|
|
164
|
+
"data": {},
|
|
165
|
+
"disable": false,
|
|
166
|
+
"global_code": true,
|
|
167
|
+
"debug": true,
|
|
168
|
+
"lazyload": true,
|
|
169
|
+
"response_text": {},
|
|
170
|
+
"response_limit": 25,
|
|
171
|
+
"throttle": 1000,
|
|
172
|
+
"identifier": "#page",
|
|
173
|
+
"loader": "#loader",
|
|
174
|
+
"smoothscroll_duration": "200ms",
|
|
175
|
+
"smoothscroll_speed" : 0,
|
|
176
|
+
"smoothscroll_easing" : "swing",
|
|
177
|
+
"exceptions": []
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const State = Transparent.state = {
|
|
181
|
+
|
|
182
|
+
ROOT : "transparent",
|
|
183
|
+
|
|
184
|
+
SWITCH : "X-to-Y",
|
|
185
|
+
SAME : "same",
|
|
186
|
+
READY : "ready",
|
|
187
|
+
RELOAD : "reload",
|
|
188
|
+
DISABLE : "disable",
|
|
189
|
+
LOADING : "loading",
|
|
190
|
+
NEW : "new",
|
|
191
|
+
FIRST : "first",
|
|
192
|
+
SUBMIT : "submit",
|
|
193
|
+
POPSTATE : "popstate",
|
|
194
|
+
HASHCHANGE : "hashchange",
|
|
195
|
+
CLICK : "click",
|
|
196
|
+
|
|
197
|
+
PREACTIVE : "pre-active",
|
|
198
|
+
ACTIVEIN : "active-in",
|
|
199
|
+
ACTIVE : "active",
|
|
200
|
+
ACTIVEOUT : "active-out",
|
|
201
|
+
POSTACTIVE : "post-active",
|
|
202
|
+
|
|
203
|
+
NOTIFICATION: "notification"
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
var isReady = false;
|
|
207
|
+
var rescueMode = false;
|
|
208
|
+
|
|
209
|
+
Transparent.html = $($(document).find("html")[0]);
|
|
210
|
+
Transparent.html.addClass(Transparent.state.ROOT+ " " + Transparent.state.LOADING + " " + Transparent.state.FIRST);
|
|
211
|
+
|
|
212
|
+
if(!Transparent.html.hasClass(Transparent.state.ACTIVE)) {
|
|
213
|
+
Transparent.html.addClass(Transparent.state.ACTIVE);
|
|
214
|
+
dispatchEvent(new Event('transparent:'+Transparent.state.ACTIVE));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
window.addEventListener("DOMContentLoaded", function()
|
|
218
|
+
{
|
|
219
|
+
Transparent.loader = $($(document).find(Settings.loader)[0] ?? Transparent.html);
|
|
220
|
+
Transparent.lazyLoad();
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
Transparent.isRescueMode = function() { return rescueMode; }
|
|
224
|
+
Transparent.getData = function(uuid)
|
|
225
|
+
{
|
|
226
|
+
return (Settings["data"][uuid] ? Settings["data"][uuid] : {});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
Transparent.setData = function(uuid, data)
|
|
230
|
+
{
|
|
231
|
+
Settings["data"][uuid] = data;
|
|
232
|
+
return this;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
Transparent.getResponseText = function(uuid)
|
|
236
|
+
{
|
|
237
|
+
var array = JSON.parse(sessionStorage.getItem('transparent')) || [];
|
|
238
|
+
|
|
239
|
+
// Bubble up the most recent uuid
|
|
240
|
+
var index = array.indexOf(uuid);
|
|
241
|
+
if (index > -1) {
|
|
242
|
+
array.splice(index, 1);
|
|
243
|
+
array.push(uuid);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// If no response refresh page based on the requested url
|
|
247
|
+
return sessionStorage.getItem('transparent[response]['+uuid+']') || null;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
Transparent.getResponsePosition = function(uuid)
|
|
251
|
+
{
|
|
252
|
+
var array = JSON.parse(sessionStorage.getItem('transparent')) || [];
|
|
253
|
+
|
|
254
|
+
// Bubble up the most recent uuid
|
|
255
|
+
var index = array.indexOf(uuid);
|
|
256
|
+
if (index > -1) {
|
|
257
|
+
array.splice(index, 1);
|
|
258
|
+
array.push(uuid);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// If no response refresh page based on the requested url
|
|
262
|
+
var position = sessionStorage.getItem('transparent[position]['+uuid+']');
|
|
263
|
+
return position != "undefined" ? (JSON.parse(position) || []) : [];
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
Transparent.getResponse = function(uuid)
|
|
267
|
+
{
|
|
268
|
+
return [ Transparent.getResponseText(uuid), Transparent.getResponsePosition(uuid) ];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function isDomEntity(entity)
|
|
272
|
+
{
|
|
273
|
+
return typeof entity === 'object' && entity.nodeType !== undefined;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
Transparent.setResponse = function(uuid, responseText, scrollableXY = [], exceptionRaised = false)
|
|
277
|
+
{
|
|
278
|
+
if(isDomEntity(responseText))
|
|
279
|
+
responseText = responseText.outerHTML;
|
|
280
|
+
|
|
281
|
+
var array = JSON.parse(sessionStorage.getItem('transparent')) || [];
|
|
282
|
+
array.push(uuid);
|
|
283
|
+
|
|
284
|
+
while(array.length > Settings["response_limit"])
|
|
285
|
+
sessionStorage.removeItem('transparent['+array.shift()+']');
|
|
286
|
+
|
|
287
|
+
try {
|
|
288
|
+
|
|
289
|
+
if(isLocalStorageNameSupported()) {
|
|
290
|
+
|
|
291
|
+
sessionStorage.setItem('transparent', JSON.stringify(array));
|
|
292
|
+
sessionStorage.setItem('transparent[response]['+uuid+']', responseText);
|
|
293
|
+
sessionStorage.setItem('transparent[position]['+uuid+']', JSON.stringify(scrollableXY));
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
} catch(e) {
|
|
297
|
+
|
|
298
|
+
if (e.name === 'QuotaExceededError')
|
|
299
|
+
sessionStorage.clear();
|
|
300
|
+
|
|
301
|
+
return exceptionRaised === false ? Transparent.setResponse(uuid, responseText, scrollableXY, true) : this;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return this;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
Transparent.setResponse = function(uuid, responseText, scrollableXY, exceptionRaised = false)
|
|
308
|
+
{
|
|
309
|
+
if(isDomEntity(responseText))
|
|
310
|
+
responseText = responseText.outerHTML;
|
|
311
|
+
|
|
312
|
+
var array = JSON.parse(sessionStorage.getItem('transparent')) || [];
|
|
313
|
+
if( ! (uuid in array) ) {
|
|
314
|
+
|
|
315
|
+
array.push(uuid);
|
|
316
|
+
while(array.length > Settings["response_limit"])
|
|
317
|
+
sessionStorage.removeItem('transparent['+array.shift()+']');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
try {
|
|
321
|
+
|
|
322
|
+
if(isLocalStorageNameSupported()) {
|
|
323
|
+
|
|
324
|
+
sessionStorage.setItem('transparent', JSON.stringify(array));
|
|
325
|
+
sessionStorage.setItem('transparent[response]['+uuid+']', responseText);
|
|
326
|
+
sessionStorage.setItem('transparent[position]['+uuid+']', JSON.stringify(scrollableXY));
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
} catch(e) {
|
|
330
|
+
|
|
331
|
+
if (e.name === 'QuotaExceededError')
|
|
332
|
+
sessionStorage.clear();
|
|
333
|
+
|
|
334
|
+
return exceptionRaised === false ? Transparent.setResponse(uuid, responseText, scrollableXY, true) : this;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return this;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
Transparent.setResponseText = function(uuid, responseText, exceptionRaised = false)
|
|
341
|
+
{
|
|
342
|
+
if(isDomEntity(responseText))
|
|
343
|
+
responseText = responseText.outerHTML;
|
|
344
|
+
|
|
345
|
+
var array = JSON.parse(sessionStorage.getItem('transparent')) || [];
|
|
346
|
+
if( ! (uuid in array) ) {
|
|
347
|
+
|
|
348
|
+
array.push(uuid);
|
|
349
|
+
while(array.length > Settings["response_limit"])
|
|
350
|
+
sessionStorage.removeItem('transparent['+array.shift()+']');
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
try {
|
|
354
|
+
|
|
355
|
+
if(isLocalStorageNameSupported()) {
|
|
356
|
+
|
|
357
|
+
sessionStorage.setItem('transparent', JSON.stringify(array));
|
|
358
|
+
sessionStorage.setItem('transparent[response]['+uuid+']', responseText);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
} catch(e) {
|
|
362
|
+
|
|
363
|
+
if (e.name === 'QuotaExceededError')
|
|
364
|
+
sessionStorage.clear();
|
|
365
|
+
|
|
366
|
+
return exceptionRaised === false ? Transparent.setResponseText(uuid, responseText, true) : this;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return this;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
Transparent.setResponsePosition = function(uuid, scrollableXY, exceptionRaised = false)
|
|
373
|
+
{
|
|
374
|
+
var array = JSON.parse(sessionStorage.getItem('transparent')) || [];
|
|
375
|
+
if( ! (uuid in array) ) {
|
|
376
|
+
|
|
377
|
+
array.push(uuid);
|
|
378
|
+
while(array.length > Settings["response_limit"])
|
|
379
|
+
sessionStorage.removeItem('transparent['+array.shift()+']');
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
try {
|
|
383
|
+
|
|
384
|
+
if(isLocalStorageNameSupported()) {
|
|
385
|
+
|
|
386
|
+
sessionStorage.setItem('transparent', JSON.stringify(array));
|
|
387
|
+
sessionStorage.setItem('transparent[position]['+uuid+']', JSON.stringify(scrollableXY));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
} catch(e) {
|
|
391
|
+
|
|
392
|
+
if (e.name === 'QuotaExceededError')
|
|
393
|
+
sessionStorage.clear();
|
|
394
|
+
|
|
395
|
+
return exceptionRaised === false ? Transparent.setResponsePosition(uuid, scrollableXY, true) : this;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return this;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
Transparent.hasResponse = function(uuid)
|
|
402
|
+
{
|
|
403
|
+
if(isLocalStorageNameSupported())
|
|
404
|
+
return 'transparent[response]['+uuid+']' in sessionStorage;
|
|
405
|
+
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
Transparent.configure = function (options) {
|
|
410
|
+
|
|
411
|
+
var key, value;
|
|
412
|
+
for (key in options) {
|
|
413
|
+
value = options[key];
|
|
414
|
+
if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return this;
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
Transparent.ready = function (options = {}) {
|
|
421
|
+
|
|
422
|
+
Transparent.configure({'x-ajax-request': true});
|
|
423
|
+
Transparent.configure(options);
|
|
424
|
+
|
|
425
|
+
isReady = true;
|
|
426
|
+
|
|
427
|
+
dispatchEvent(new Event('transparent:'+Transparent.state.READY));
|
|
428
|
+
Transparent.html.addClass(Transparent.state.READY);
|
|
429
|
+
|
|
430
|
+
Transparent.addLayout();
|
|
431
|
+
Transparent.lazyLoad();
|
|
432
|
+
|
|
433
|
+
Transparent.scrollToHash(location.hash, {}, function() {
|
|
434
|
+
|
|
435
|
+
Transparent.activeOut(() => Transparent.html.removeClass(Transparent.state.FIRST));
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
return this;
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
Transparent.addLayout = function() {
|
|
442
|
+
|
|
443
|
+
var id = Transparent.getLayout();
|
|
444
|
+
if(id === undefined) return false;
|
|
445
|
+
|
|
446
|
+
var isKnown = knownLayout.indexOf(id) !== -1;
|
|
447
|
+
if(!isKnown) knownLayout.push(id);
|
|
448
|
+
|
|
449
|
+
return !isKnown;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
Transparent.getLayout = function(dom = null) {
|
|
453
|
+
|
|
454
|
+
var layout = dom !== null ? $(dom).find(Settings.identifier) : $(Settings.identifier);
|
|
455
|
+
if(!layout.length) return undefined;
|
|
456
|
+
|
|
457
|
+
return layout.data("layout");
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
Transparent.findNearestForm = function (el) {
|
|
461
|
+
|
|
462
|
+
switch (el.tagName) {
|
|
463
|
+
case "FORM":
|
|
464
|
+
var form = $(el);
|
|
465
|
+
return (form.length ? form[0] : undefined);
|
|
466
|
+
case "INPUT":
|
|
467
|
+
case "BUTTON":
|
|
468
|
+
var form = $(el).closest("form");
|
|
469
|
+
return (form.length ? form[0] : undefined);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Try to detect target element
|
|
473
|
+
if (el.target) {
|
|
474
|
+
|
|
475
|
+
if (el.target.tagName == "FORM")
|
|
476
|
+
return Transparent.findNearestForm(el.target);
|
|
477
|
+
|
|
478
|
+
if (el.target.tagName == "BUTTON" && el.target.getAttribute("type") == "submit")
|
|
479
|
+
return Transparent.findNearestForm(el.target);
|
|
480
|
+
|
|
481
|
+
if (el.target.tagName == "INPUT" && el.target.getAttribute("type") == "submit")
|
|
482
|
+
return Transparent.findNearestForm(el.target);
|
|
483
|
+
|
|
484
|
+
var form = $(el.target).closest("form");
|
|
485
|
+
return (form.length ? form[0] : undefined);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
window.previousLocation = window.location.toString();
|
|
492
|
+
Transparent.findLink = function (el) {
|
|
493
|
+
|
|
494
|
+
if (el.type == Transparent.state.HASHCHANGE) {
|
|
495
|
+
|
|
496
|
+
var href = el.newURL;
|
|
497
|
+
if(!href) return null;
|
|
498
|
+
|
|
499
|
+
if (href.startsWith("#")) href = location.pathname + href;
|
|
500
|
+
if (href.endsWith ("#")) href = href.slice(0, -1);
|
|
501
|
+
|
|
502
|
+
var data = history.state ? Transparent.getData(history.state.uuid) : {};
|
|
503
|
+
return ["GET", new URL(el.newURL), data];
|
|
504
|
+
|
|
505
|
+
} else if (el.type == Transparent.state.POPSTATE) {
|
|
506
|
+
|
|
507
|
+
if(!el.state) return;
|
|
508
|
+
|
|
509
|
+
var href = el.state.href;
|
|
510
|
+
if (href.startsWith("#")) href = location.pathname + href;
|
|
511
|
+
if (href.endsWith ("#")) href = href.slice(0, -1);
|
|
512
|
+
|
|
513
|
+
var type = el.state.type;
|
|
514
|
+
var data = Transparent.getData(el.state.uuid);
|
|
515
|
+
|
|
516
|
+
var https = /^https?:\/\//i;
|
|
517
|
+
if (https.test(href)) return [type, new URL(href), data];
|
|
518
|
+
|
|
519
|
+
var hash = /^\#\w*/i;
|
|
520
|
+
if (hash.test(href)) return [type, new URL(location.origin+location.pathname+href), data];
|
|
521
|
+
|
|
522
|
+
return [type, new URL(href, location.origin), data];
|
|
523
|
+
|
|
524
|
+
} else if(el.type == Transparent.state.SUBMIT) {
|
|
525
|
+
|
|
526
|
+
if(el.target && el.target.tagName == "FORM") {
|
|
527
|
+
|
|
528
|
+
// Action must be prevented here
|
|
529
|
+
// This is specific to form submission
|
|
530
|
+
el.preventDefault();
|
|
531
|
+
|
|
532
|
+
var href = el.target.getAttribute("action");
|
|
533
|
+
if(!href) href = location.pathname + href;
|
|
534
|
+
|
|
535
|
+
if (href.startsWith("#")) href = location.pathname + href;
|
|
536
|
+
if (href.endsWith ("#")) href = href.slice(0, -1);
|
|
537
|
+
|
|
538
|
+
var method = el.target.getAttribute("method") || "GET";
|
|
539
|
+
method = method.toUpperCase();
|
|
540
|
+
|
|
541
|
+
var form = Transparent.findNearestForm(el);
|
|
542
|
+
if (form == null) {
|
|
543
|
+
console.error("No form found upstream of ", el);
|
|
544
|
+
return null;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
if(!form.checkValidity()) return null;
|
|
548
|
+
|
|
549
|
+
var pat = /^https?:\/\//i;
|
|
550
|
+
if (pat.test(href)) return [method, new URL(href), form];
|
|
551
|
+
return [method, new URL(href, location.origin), form];
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
closestEl = $(el).closest("a");
|
|
556
|
+
if(!closestEl.length) closestEl = $(el).closest("button");
|
|
557
|
+
if(!closestEl.length) closestEl = $(el).closest("input");
|
|
558
|
+
if (closestEl.length) el = closestEl[0];
|
|
559
|
+
switch (el.tagName) {
|
|
560
|
+
|
|
561
|
+
case "A":
|
|
562
|
+
var href = el.href;
|
|
563
|
+
if(!href) return null;
|
|
564
|
+
|
|
565
|
+
if (href.startsWith("#")) href = location.pathname + href;
|
|
566
|
+
if (href.endsWith ("#")) href = href.slice(0, -1);
|
|
567
|
+
|
|
568
|
+
var pat = /^https?:\/\//i;
|
|
569
|
+
if (pat.test(href)) return ["GET", new URL(href), el];
|
|
570
|
+
|
|
571
|
+
return ["GET", new URL(href, location.origin), el];
|
|
572
|
+
|
|
573
|
+
case "INPUT":
|
|
574
|
+
case "BUTTON":
|
|
575
|
+
var domainBaseURI = el.baseURI.split('/').slice(0, 3).join('/');
|
|
576
|
+
var domainFormAction = el.formAction.split('/').slice(0, 3).join('/');
|
|
577
|
+
|
|
578
|
+
var pathname = el.formAction.replace(domainFormAction, "");
|
|
579
|
+
if(!pathname) return null;
|
|
580
|
+
|
|
581
|
+
if (domainBaseURI == domainFormAction && el.getAttribute("type") == "submit") {
|
|
582
|
+
|
|
583
|
+
var form = Transparent.findNearestForm(el);
|
|
584
|
+
if (form == null) {
|
|
585
|
+
console.error("No form found upstream of ", el);
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
if(!form.checkValidity()) return null;
|
|
590
|
+
|
|
591
|
+
var pat = /^https?:\/\//i;
|
|
592
|
+
if (pat.test(href)) return ["POST", new URL(pathname), form];
|
|
593
|
+
return ["POST", new URL(pathname, location.origin), form];
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// Try to detect target element
|
|
598
|
+
if (el.target) {
|
|
599
|
+
|
|
600
|
+
if (el.target.tagName == "A" && el.target.href)
|
|
601
|
+
return Transparent.findLink(el.target);
|
|
602
|
+
|
|
603
|
+
if (el.target.tagName == "BUTTON" && el.target.getAttribute("type") == "submit")
|
|
604
|
+
return Transparent.findLink(el.target);
|
|
605
|
+
|
|
606
|
+
if (el.target.tagName == "INPUT" && el.target.getAttribute("type") == "submit")
|
|
607
|
+
return Transparent.findLink(el.target);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// Try to catch a custom href attribute without "A" tag
|
|
611
|
+
if (el.target && $(el.target).attr("href")) {
|
|
612
|
+
|
|
613
|
+
var href = $(el.target).attr("href");
|
|
614
|
+
if(!href) return null;
|
|
615
|
+
|
|
616
|
+
if (href.startsWith("#")) href = location.pathname + href;
|
|
617
|
+
if (href.endsWith ("#")) href = href.slice(0, -1);
|
|
618
|
+
|
|
619
|
+
var form = Transparent.findNearestForm(el);
|
|
620
|
+
if (form == null) return null;
|
|
621
|
+
|
|
622
|
+
var pat = /^https?:\/\//i;
|
|
623
|
+
if (pat.test(href)) return ["GET", new URL(href), form];
|
|
624
|
+
return ["GET", new URL(href, location.origin), form];
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
if (el.target && el.target.parentElement)
|
|
628
|
+
return Transparent.findLink(el.target.parentElement);
|
|
629
|
+
|
|
630
|
+
return null;
|
|
631
|
+
};
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
Transparent.preload = function (link, callback = function(preload = []) {}) {
|
|
635
|
+
|
|
636
|
+
var nPreload = 0;
|
|
637
|
+
for (var as in link) {
|
|
638
|
+
|
|
639
|
+
link[as] = link[as].filter(url => url !== null && url.length > 0);
|
|
640
|
+
nPreload += link[as].length;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
if(nPreload == 0)
|
|
644
|
+
return callback();
|
|
645
|
+
|
|
646
|
+
var preloads = [];
|
|
647
|
+
var nPreloaded = 0;
|
|
648
|
+
for (var as in link) {
|
|
649
|
+
|
|
650
|
+
for (var i = 0; i < link[as].length; i++) {
|
|
651
|
+
|
|
652
|
+
var url = link[as][i];
|
|
653
|
+
if(url === null || url === "") continue;
|
|
654
|
+
|
|
655
|
+
var preload = document.createElement("link");
|
|
656
|
+
preloads.push(preload);
|
|
657
|
+
|
|
658
|
+
preload.onload = function () {
|
|
659
|
+
|
|
660
|
+
if (++nPreloaded == nPreload)
|
|
661
|
+
return callback(preloads);
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
preload.setAttribute("rel", "preload");
|
|
665
|
+
preload.setAttribute("as", as);
|
|
666
|
+
preload.setAttribute("crossorigin","");
|
|
667
|
+
preload.href = url;
|
|
668
|
+
|
|
669
|
+
document.head.append(preload);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
Transparent.findElementFromParents = function(el, parents, from = -1) {
|
|
675
|
+
|
|
676
|
+
var that = $(el).find(Settings.identifier);
|
|
677
|
+
for (var i = parents.length - 1, j = 0; i >= 0; i--) {
|
|
678
|
+
|
|
679
|
+
if (j++ < from) continue;
|
|
680
|
+
|
|
681
|
+
var that = that.children(parents[i].tagName);
|
|
682
|
+
if (that.length != 1) return undefined;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
return that;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
Transparent.isPage = function(dom) {
|
|
689
|
+
|
|
690
|
+
// Check if page block found
|
|
691
|
+
var page = $(dom).find(Settings.identifier)[0] || undefined;
|
|
692
|
+
if (page === undefined) return false;
|
|
693
|
+
|
|
694
|
+
return true;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
var knownLayout = [];
|
|
698
|
+
Transparent.isKnownLayout = function(dom)
|
|
699
|
+
{
|
|
700
|
+
var page = (dom ? $(dom).find(Settings.identifier) : $(Settings.identifier))[0];
|
|
701
|
+
if (page === undefined) return false;
|
|
702
|
+
|
|
703
|
+
var layout = $(page).data("layout");
|
|
704
|
+
return knownLayout.indexOf(layout) !== -1;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
Transparent.isCompatiblePage = function(dom, method = null, data = null)
|
|
708
|
+
{
|
|
709
|
+
// If no html response.. skip
|
|
710
|
+
if(!dom) return false;
|
|
711
|
+
|
|
712
|
+
// An exception applies here..
|
|
713
|
+
// in case the page contains data transferred to the server
|
|
714
|
+
if(method == "POST" && !jQuery.isEmptyObject(data)) return true;
|
|
715
|
+
|
|
716
|
+
var page = $(dom).find(Settings.identifier)[0] || undefined;
|
|
717
|
+
if (page === undefined) return false;
|
|
718
|
+
|
|
719
|
+
var currentPage = $(Settings.identifier)[0] || undefined;
|
|
720
|
+
if (currentPage === undefined) return false;
|
|
721
|
+
|
|
722
|
+
var name = currentPage.getAttribute("data-name") || "default";
|
|
723
|
+
var newName = page.getAttribute("data-name") || "default";
|
|
724
|
+
|
|
725
|
+
return name == newName;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
Transparent.parseDuration = function(str) {
|
|
729
|
+
|
|
730
|
+
var array = String(str).split(", ");
|
|
731
|
+
array = array.map(function(t) {
|
|
732
|
+
|
|
733
|
+
if(String(t).endsWith("ms")) return parseFloat(String(t))/1000;
|
|
734
|
+
return parseFloat(String(t));
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
return Math.max(...array);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
Transparent.callback = function(fn = function() {}, delay = 0) {
|
|
741
|
+
|
|
742
|
+
if(delay == 0) fn();
|
|
743
|
+
else setTimeout(fn, delay);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
Transparent.activeTime = function(el = undefined) {
|
|
747
|
+
|
|
748
|
+
var delay = 0, duration = 0;
|
|
749
|
+
if(el === undefined)
|
|
750
|
+
el = Transparent.loader[0];
|
|
751
|
+
|
|
752
|
+
var style = window.getComputedStyle(el);
|
|
753
|
+
delay = Math.max(delay, 1000*Math.max(Transparent.parseDuration(style["animation-delay"]), Transparent.parseDuration(style["transition-delay"])));
|
|
754
|
+
duration = Math.max(duration, 1000*Math.max(Transparent.parseDuration(style["animation-duration"]), Transparent.parseDuration(style["transition-duration"])));
|
|
755
|
+
|
|
756
|
+
var style = window.getComputedStyle(el, ":before");
|
|
757
|
+
delay = Math.max(delay, 1000*Math.max(Transparent.parseDuration(style["animation-delay"]), Transparent.parseDuration(style["transition-delay"])));
|
|
758
|
+
duration = Math.max(duration, 1000*Math.max(Transparent.parseDuration(style["animation-duration"]), Transparent.parseDuration(style["transition-duration"])));
|
|
759
|
+
|
|
760
|
+
var style = window.getComputedStyle(el, ":after");
|
|
761
|
+
delay = Math.max(delay, 1000*Math.max(Transparent.parseDuration(style["animation-delay"]), Transparent.parseDuration(style["transition-delay"])));
|
|
762
|
+
duration = Math.max(duration, 1000*Math.max(Transparent.parseDuration(style["animation-duration"]), Transparent.parseDuration(style["transition-duration"])));
|
|
763
|
+
|
|
764
|
+
return {delay:delay, duration:duration};
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
Transparent.activeIn = function(activeCallback = function() {}) {
|
|
768
|
+
|
|
769
|
+
if(!Transparent.html.hasClass(Transparent.state.PREACTIVE)) {
|
|
770
|
+
Transparent.html.addClass(Transparent.state.PREACTIVE);
|
|
771
|
+
dispatchEvent(new Event('transparent:'+Transparent.state.PREACTIVE));
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
var active = Transparent.activeTime();
|
|
775
|
+
|
|
776
|
+
Transparent.html.removeClass(Transparent.state.PREACTIVE);
|
|
777
|
+
if(!Transparent.html.hasClass(Transparent.state.ACTIVEIN)) {
|
|
778
|
+
Transparent.html.addClass(Transparent.state.ACTIVEIN);
|
|
779
|
+
dispatchEvent(new Event('transparent:'+Transparent.state.ACTIVEIN));
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
Transparent.callback(function() {
|
|
783
|
+
|
|
784
|
+
Transparent.html.removeClass(Transparent.state.ACTIVEIN);
|
|
785
|
+
if(!Transparent.html.hasClass(Transparent.state.ACTIVE)) {
|
|
786
|
+
Transparent.html.addClass(Transparent.state.ACTIVE);
|
|
787
|
+
dispatchEvent(new Event('transparent:'+Transparent.state.ACTIVE));
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
var active = Transparent.activeTime();
|
|
791
|
+
Transparent.callback(function() {
|
|
792
|
+
|
|
793
|
+
activeCallback();
|
|
794
|
+
|
|
795
|
+
}.bind(this), active.duration);
|
|
796
|
+
|
|
797
|
+
}.bind(this), active.delay);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
Transparent.activeOut = function(activeCallback = function() {}) {
|
|
801
|
+
|
|
802
|
+
if(!Transparent.html.hasClass(Transparent.state.ACTIVE)) {
|
|
803
|
+
Transparent.html.addClass(Transparent.state.ACTIVE);
|
|
804
|
+
dispatchEvent(new Event('transparent:'+Transparent.state.ACTIVE));
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
if(!Transparent.html.hasClass(Transparent.state.ACTIVEOUT)) {
|
|
808
|
+
Transparent.html.addClass(Transparent.state.ACTIVEOUT);
|
|
809
|
+
dispatchEvent(new Event('transparent:'+Transparent.state.ACTIVEOUT));
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
var active = Transparent.activeTime();
|
|
813
|
+
Transparent.callback(function() {
|
|
814
|
+
|
|
815
|
+
activeCallback();
|
|
816
|
+
Transparent.html.removeClass(Transparent.state.ACTIVE);
|
|
817
|
+
|
|
818
|
+
var active = Transparent.activeTime();
|
|
819
|
+
Transparent.callback(function() {
|
|
820
|
+
|
|
821
|
+
Transparent.html.removeClass(Transparent.state.ACTIVEOUT);
|
|
822
|
+
if(!Transparent.html.hasClass(Transparent.state.POSTACTIVE)){
|
|
823
|
+
|
|
824
|
+
Transparent.html.removeClass(Transparent.state.POSTACTIVE);
|
|
825
|
+
dispatchEvent(new Event('transparent:'+Transparent.state.POSTACTIVE));
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
if(Transparent.html.hasClass(Transparent.state.LOADING)) {
|
|
829
|
+
|
|
830
|
+
dispatchEvent(new Event('transparent:load'));
|
|
831
|
+
|
|
832
|
+
Object.values(Transparent.state).forEach(e => Transparent.html.removeClass(e));
|
|
833
|
+
Transparent.html.addClass(Transparent.state.ROOT + " " + Transparent.state.READY);
|
|
834
|
+
|
|
835
|
+
} else {
|
|
836
|
+
|
|
837
|
+
Transparent.html.removeClass(Transparent.state.POSTACTIVE);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
}, active.duration);
|
|
841
|
+
|
|
842
|
+
}.bind(this), active.delay);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
Transparent.replaceCanvases = function(dom) {
|
|
846
|
+
|
|
847
|
+
// Extract existing canvas to avoid redrawing them.. (time consuming)
|
|
848
|
+
$.each($('html').find("canvas"), function () {
|
|
849
|
+
|
|
850
|
+
var parent = $(this).parent();
|
|
851
|
+
if(!parent.length) return;
|
|
852
|
+
|
|
853
|
+
var id = this.getAttribute("id");
|
|
854
|
+
if (id) {
|
|
855
|
+
|
|
856
|
+
var canvas = $(dom).find("#page #" + id);
|
|
857
|
+
canvas.replaceWith(this);
|
|
858
|
+
|
|
859
|
+
} else {
|
|
860
|
+
|
|
861
|
+
if(dom === undefined)
|
|
862
|
+
console.alert("Response missing..");
|
|
863
|
+
|
|
864
|
+
var parent = Transparent.findElementFromParents(dom, $(this).parents(), 3);
|
|
865
|
+
if (parent === undefined) {
|
|
866
|
+
console.error("Unexpected canvas without ID found..", this)
|
|
867
|
+
return false;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
parent.append(this);
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
Transparent.evalScript = function(el)
|
|
876
|
+
{
|
|
877
|
+
function scriptCloneEl(el){
|
|
878
|
+
var script = document.createElement("script");
|
|
879
|
+
script.text = el.innerHTML;
|
|
880
|
+
|
|
881
|
+
var i = -1, attrs = el.attributes, attr;
|
|
882
|
+
var N = attrs.length;
|
|
883
|
+
while ( ++i < N ) {
|
|
884
|
+
script.setAttribute( (attr = attrs[i]).name, attr.value );
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
eval($(script).text());
|
|
888
|
+
return script;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
if (el.tagName === 'SCRIPT' ) el.parentNode.replaceChild( scriptCloneEl(el) , el );
|
|
892
|
+
else {
|
|
893
|
+
|
|
894
|
+
var i = -1, children = el.childNodes;
|
|
895
|
+
var N = children.length;
|
|
896
|
+
while ( ++i < N ) {
|
|
897
|
+
Transparent.evalScript( children[i] );
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
return el;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
Transparent.rescue = function(dom)
|
|
905
|
+
{
|
|
906
|
+
console.error("Rescue mode.. called");
|
|
907
|
+
rescueMode = true;
|
|
908
|
+
|
|
909
|
+
var head = $(dom).find("head").html();
|
|
910
|
+
var body = $(dom).find("body").html();
|
|
911
|
+
if(head == undefined || body == undefined)
|
|
912
|
+
window.reload();
|
|
913
|
+
|
|
914
|
+
document.head.innerHTML = $(dom).find("head").html();
|
|
915
|
+
document.body.innerHTML = $(dom).find("body").html();
|
|
916
|
+
|
|
917
|
+
Transparent.evalScript($("head")[0]);
|
|
918
|
+
Transparent.evalScript($("body")[0]);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
Transparent.userScroll = function(el = undefined) { return $(el === undefined ? document.documentElement : el).closestScrollable().prop("user-scroll") ?? true; }
|
|
922
|
+
Transparent.scrollTo = function(dict, el = window, callback = function() {})
|
|
923
|
+
{
|
|
924
|
+
el = $(el).length ? $(el)[0] : window;
|
|
925
|
+
if (el === window )
|
|
926
|
+
el = document.documentElement;
|
|
927
|
+
if (el === document)
|
|
928
|
+
el = document.documentElement;
|
|
929
|
+
|
|
930
|
+
var maxScrollX = $(el).prop("scrollWidth") - Math.round($(el).prop("clientWidth"));
|
|
931
|
+
if (maxScrollX == 0) maxScrollX = Math.round($(el).prop("clientWidth"));
|
|
932
|
+
var maxScrollY = $(el).prop("scrollHeight") - Math.round($(el).prop("clientHeight"));
|
|
933
|
+
if (maxScrollY == 0) maxScrollY = Math.round($(el).prop("clientHeight"));
|
|
934
|
+
|
|
935
|
+
scrollTop = Math.max(0, Math.min(dict["top"] ?? $(el).prop("scrollTop"), maxScrollY));
|
|
936
|
+
scrollLeft = Math.max(0, Math.min(dict["left"] ?? $(el).prop("scrollLeft"), maxScrollX));
|
|
937
|
+
|
|
938
|
+
speed = parseFloat(dict["speed"] ?? 0);
|
|
939
|
+
easing = dict["easing"] ?? "swing";
|
|
940
|
+
debounce = dict["debounce"] ?? 0;
|
|
941
|
+
|
|
942
|
+
duration = 1000*Transparent.parseDuration(dict["duration"] ?? 0);
|
|
943
|
+
durationX = 1000*Transparent.parseDuration(dict["duration-x"] ?? dict["duration"] ?? 0);
|
|
944
|
+
durationY = 1000*Transparent.parseDuration(dict["duration-y"] ?? dict["duration"] ?? 0);
|
|
945
|
+
|
|
946
|
+
if(speed) {
|
|
947
|
+
|
|
948
|
+
var currentScrollX = $(el)[0].scrollLeft;
|
|
949
|
+
if(currentScrollX < scrollLeft || scrollLeft == 0) // Going to the right
|
|
950
|
+
distanceX = Math.abs(scrollLeft - currentScrollX);
|
|
951
|
+
else // Going back to 0 position
|
|
952
|
+
distanceX = currentScrollX;
|
|
953
|
+
|
|
954
|
+
var currentScrollY = $(el)[0].scrollTop;
|
|
955
|
+
if(currentScrollY <= scrollTop || scrollTop == 0) // Going to the right
|
|
956
|
+
distanceY = Math.abs(scrollTop - currentScrollY);
|
|
957
|
+
else // Going back to 0 position
|
|
958
|
+
distanceY = currentScrollY;
|
|
959
|
+
|
|
960
|
+
durationX = speed ? 1000*distanceX/speed : durationX;
|
|
961
|
+
durationY = speed ? 1000*distanceY/speed : durationY;
|
|
962
|
+
duration = durationX+durationY;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
var callbackWrapper = function() {
|
|
966
|
+
|
|
967
|
+
el.dispatchEvent(new Event('scroll'));
|
|
968
|
+
callback();
|
|
969
|
+
|
|
970
|
+
$(el).prop("user-scroll", true);
|
|
971
|
+
};
|
|
972
|
+
|
|
973
|
+
if(duration == 0) {
|
|
974
|
+
|
|
975
|
+
el.scrollTo(scrollLeft, scrollTop);
|
|
976
|
+
el.dispatchEvent(new Event('scroll'));
|
|
977
|
+
callback();
|
|
978
|
+
|
|
979
|
+
$(el).prop("user-scroll", true);
|
|
980
|
+
|
|
981
|
+
} else {
|
|
982
|
+
|
|
983
|
+
$(el).animate({scrollTop: scrollTop}, durationY, easing,
|
|
984
|
+
() => $(el).animate({scrollLeft: scrollLeft}, durationX, easing, Transparent.debounce(callbackWrapper, debounce))
|
|
985
|
+
);
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
return this;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
Transparent.debounce = function(func, wait, immediate) {
|
|
992
|
+
|
|
993
|
+
var timeout;
|
|
994
|
+
|
|
995
|
+
return function() {
|
|
996
|
+
|
|
997
|
+
var context = this, args = arguments;
|
|
998
|
+
var later = function() {
|
|
999
|
+
|
|
1000
|
+
timeout = null;
|
|
1001
|
+
if (!immediate) func.apply(context, args);
|
|
1002
|
+
};
|
|
1003
|
+
|
|
1004
|
+
var callNow = immediate && !timeout;
|
|
1005
|
+
clearTimeout(timeout);
|
|
1006
|
+
|
|
1007
|
+
timeout = setTimeout(later, wait);
|
|
1008
|
+
if (callNow) func.apply(context, args);
|
|
1009
|
+
};
|
|
1010
|
+
};
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
Transparent.findImages = function () {
|
|
1014
|
+
|
|
1015
|
+
var doc = document.documentElement;
|
|
1016
|
+
const srcChecker = /url\(\s*?['"]?\s*?(\S+?)\s*?["']?\s*?\)/i
|
|
1017
|
+
return Array.from(doc.querySelectorAll('*'))
|
|
1018
|
+
.reduce((collection, node) => {
|
|
1019
|
+
|
|
1020
|
+
let prop = window.getComputedStyle(node, null).getPropertyValue('background-image')
|
|
1021
|
+
let match = srcChecker.exec(prop);
|
|
1022
|
+
if (match) collection.add(match[1]);
|
|
1023
|
+
|
|
1024
|
+
if (/^img$/i.test(node.tagName)) collection.add(node.src)
|
|
1025
|
+
else if (/^frame$/i.test(node.tagName)) {
|
|
1026
|
+
|
|
1027
|
+
try {
|
|
1028
|
+
searchDOM(node.contentDocument || node.contentWindow.document)
|
|
1029
|
+
.forEach(img => { if (img) collection.add(img); })
|
|
1030
|
+
} catch (e) {}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
return collection;
|
|
1034
|
+
|
|
1035
|
+
}, new Set());
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
Transparent.lazyLoad = function (lazyloadImages = undefined)
|
|
1039
|
+
{
|
|
1040
|
+
lazyloadImages = lazyloadImages || document.querySelectorAll("img[data-src]:not(.loaded)");
|
|
1041
|
+
if ("IntersectionObserver" in window) {
|
|
1042
|
+
|
|
1043
|
+
var imageObserver = new IntersectionObserver(function (entries, observer) {
|
|
1044
|
+
entries.forEach(function (entry) {
|
|
1045
|
+
if (entry.isIntersecting) {
|
|
1046
|
+
var image = entry.target;
|
|
1047
|
+
var lazybox = image.closest(".lazybox");
|
|
1048
|
+
|
|
1049
|
+
image.onload = function() {
|
|
1050
|
+
this.classList.add("loaded");
|
|
1051
|
+
this.classList.remove("loading");
|
|
1052
|
+
if(lazybox) lazybox.classList.add("loaded");
|
|
1053
|
+
if(lazybox) lazybox.classList.remove("loading");
|
|
1054
|
+
};
|
|
1055
|
+
|
|
1056
|
+
if(lazybox) lazybox.classList.add("loading");
|
|
1057
|
+
image.classList.add("loading");
|
|
1058
|
+
image.src = image.dataset.src;
|
|
1059
|
+
|
|
1060
|
+
imageObserver.unobserve(image);
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
lazyloadImages.forEach(function (image) {
|
|
1066
|
+
imageObserver.observe(image);
|
|
1067
|
+
});
|
|
1068
|
+
|
|
1069
|
+
} else {
|
|
1070
|
+
|
|
1071
|
+
var lazyloadThrottleTimeout;
|
|
1072
|
+
|
|
1073
|
+
function lazyload() {
|
|
1074
|
+
if (lazyloadThrottleTimeout) {
|
|
1075
|
+
clearTimeout(lazyloadThrottleTimeout);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
lazyloadThrottleTimeout = setTimeout(function () {
|
|
1079
|
+
var scrollTop = window.pageYOffset;
|
|
1080
|
+
lazyloadImages.forEach(function (img) {
|
|
1081
|
+
if (img.offsetTop < (window.innerHeight + scrollTop)) {
|
|
1082
|
+
img.src = img.dataset.src;
|
|
1083
|
+
img.classList.add('loaded');
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
if (lazyloadImages.length == 0) {
|
|
1087
|
+
document.removeEventListener("scroll", lazyload);
|
|
1088
|
+
window.removeEventListener("resize", lazyload);
|
|
1089
|
+
window.removeEventListener("orientationChange", lazyload);
|
|
1090
|
+
}
|
|
1091
|
+
}, 20);
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
document.addEventListener("scroll", lazyload);
|
|
1095
|
+
window.addEventListener("resize", lazyload);
|
|
1096
|
+
window.addEventListener("orientationChange", lazyload);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
Transparent.loadImages = function()
|
|
1101
|
+
{
|
|
1102
|
+
function loadImg (src, timeout = 500) {
|
|
1103
|
+
var imgPromise = new Promise((resolve, reject) => {
|
|
1104
|
+
|
|
1105
|
+
let img = new Image()
|
|
1106
|
+
img.onload = () => {
|
|
1107
|
+
resolve({
|
|
1108
|
+
src: src,
|
|
1109
|
+
width: img.naturalWidth,
|
|
1110
|
+
height: img.naturalHeight
|
|
1111
|
+
})
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
img.onerror = reject
|
|
1115
|
+
img.src = src
|
|
1116
|
+
})
|
|
1117
|
+
|
|
1118
|
+
var timer = new Promise((resolve, reject) => { setTimeout(reject, timeout) })
|
|
1119
|
+
return Promise.race([imgPromise, timer])
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
function loadImgAll (imgList, timeout = 500) {
|
|
1123
|
+
return new Promise((resolve, reject) => {
|
|
1124
|
+
Promise.all(imgList
|
|
1125
|
+
.map(src => loadImg(src, timeout))
|
|
1126
|
+
.map(p => p.catch(e => false))
|
|
1127
|
+
).then(results => resolve(results.filter(r => r)))
|
|
1128
|
+
})
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
return new Promise((resolve, reject) => {
|
|
1132
|
+
loadImgAll(Array.from(Transparent.findImages(document.documentElement))).then(resolve, reject)
|
|
1133
|
+
})
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
Transparent.transferAttributes = function(dom) {
|
|
1137
|
+
|
|
1138
|
+
var html = $(dom).find("html");
|
|
1139
|
+
$($("html")[0].attributes).each(function(i, attr) {
|
|
1140
|
+
if(attr.name == "class") return;
|
|
1141
|
+
$("html").removeAttr(attr.name);
|
|
1142
|
+
});
|
|
1143
|
+
|
|
1144
|
+
$($(html)[0].attributes).each(function(i, attr) {
|
|
1145
|
+
if(attr.name == "class") return;
|
|
1146
|
+
$("html").attr(attr.name, attr.value);
|
|
1147
|
+
});
|
|
1148
|
+
|
|
1149
|
+
var head = $(dom).find("head");
|
|
1150
|
+
$($("head")[0].attributes).each(function(i, attr) {
|
|
1151
|
+
$("head").removeAttr(attr.name);
|
|
1152
|
+
});
|
|
1153
|
+
|
|
1154
|
+
$($(head)[0].attributes).each(function(i, attr) {
|
|
1155
|
+
$("head").attr(attr.name, attr.value);
|
|
1156
|
+
});
|
|
1157
|
+
|
|
1158
|
+
var body = $(dom).find("body");
|
|
1159
|
+
$($("body")[0].attributes).each(function(i, attr) {
|
|
1160
|
+
$("body").removeAttr(attr.name);
|
|
1161
|
+
});
|
|
1162
|
+
$($(body)[0].attributes).each(function(i, attr) {
|
|
1163
|
+
$("body").attr(attr.name, attr.value);
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
Transparent.onLoad = function(uuid, dom, callback = null, scrollTo = false) {
|
|
1168
|
+
|
|
1169
|
+
window.previousHash = window.location.hash;
|
|
1170
|
+
window.previousLocation = window.location.toString();
|
|
1171
|
+
if(callback === null) callback = function() {};
|
|
1172
|
+
|
|
1173
|
+
// Transfert attributes
|
|
1174
|
+
Transparent.transferAttributes(dom);
|
|
1175
|
+
|
|
1176
|
+
// Replace head..
|
|
1177
|
+
var head = $(dom).find("head");
|
|
1178
|
+
$("head").children().each(function() {
|
|
1179
|
+
|
|
1180
|
+
var el = this;
|
|
1181
|
+
var found = false;
|
|
1182
|
+
|
|
1183
|
+
head.children().each(function() {
|
|
1184
|
+
|
|
1185
|
+
found = this.isEqualNode(el);
|
|
1186
|
+
return !found;
|
|
1187
|
+
});
|
|
1188
|
+
|
|
1189
|
+
if(!found) this.remove();
|
|
1190
|
+
});
|
|
1191
|
+
|
|
1192
|
+
head.children().each(function() {
|
|
1193
|
+
|
|
1194
|
+
var el = this;
|
|
1195
|
+
var found = false;
|
|
1196
|
+
|
|
1197
|
+
$("head").children().each(function() { found |= this.isEqualNode(el); });
|
|
1198
|
+
if(!found) {
|
|
1199
|
+
|
|
1200
|
+
if(this.tagName != "SCRIPT" || Settings["global_code"] == true) $("head").append(this.cloneNode(true));
|
|
1201
|
+
else $("head").append(this);
|
|
1202
|
+
}
|
|
1203
|
+
});
|
|
1204
|
+
|
|
1205
|
+
// Replace canvases..
|
|
1206
|
+
Transparent.replaceCanvases(dom);
|
|
1207
|
+
|
|
1208
|
+
// Extract page block to be loaded
|
|
1209
|
+
var page = $(dom).find(Settings.identifier);
|
|
1210
|
+
if(dom == undefined || page == undefined) window.reload(); // Error a posteriori
|
|
1211
|
+
|
|
1212
|
+
var oldPage = $(Settings.identifier);
|
|
1213
|
+
|
|
1214
|
+
// Make sure name/layout keep the same after a page change (tolerance for POST or GET requests)
|
|
1215
|
+
if(oldPage.attr("data-layout") != undefined && page.attr("data-layout") != undefined) {
|
|
1216
|
+
|
|
1217
|
+
var switchLayout = Transparent.state.SWITCH.replace("X", page.attr("data-layout")).replace("Y", oldPage.attr("data-layout"));
|
|
1218
|
+
page.attr("data-layout-prev", oldPage.attr("data-layout"));
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
var states = Object.values(Transparent.state);
|
|
1222
|
+
var htmlClass = Array.from(($(dom).find("html").attr("class") || "").split(" ")).filter(x => !states.includes(x));
|
|
1223
|
+
var oldHtmlClass = Array.from(($(Transparent.html).attr("class") || "").split(" "));
|
|
1224
|
+
var removeHtmlClass = oldHtmlClass.filter(x => !htmlClass.includes(x) && switchLayout != x && !states.includes(x));
|
|
1225
|
+
|
|
1226
|
+
Transparent.html.removeClass(removeHtmlClass).addClass(htmlClass);
|
|
1227
|
+
$(page).insertBefore(oldPage);
|
|
1228
|
+
|
|
1229
|
+
oldPage.remove();
|
|
1230
|
+
|
|
1231
|
+
if(Settings["global_code"] == true) Transparent.evalScript($(page)[0]);
|
|
1232
|
+
dispatchEvent(new Event('DOMContentLoaded'));
|
|
1233
|
+
|
|
1234
|
+
Transparent.addLayout();
|
|
1235
|
+
|
|
1236
|
+
if(scrollTo) {
|
|
1237
|
+
|
|
1238
|
+
// Go back to top of the page..
|
|
1239
|
+
var scrollableElements = Transparent.getScrollableElement();
|
|
1240
|
+
var scrollableElementsXY = Transparent.getResponsePosition(uuid);
|
|
1241
|
+
|
|
1242
|
+
for(i = 0; i < scrollableElements.length; i++) {
|
|
1243
|
+
|
|
1244
|
+
var el = scrollableElements[i];
|
|
1245
|
+
var positionXY = undefined;
|
|
1246
|
+
|
|
1247
|
+
if(scrollableElementsXY.length == scrollableElements.length)
|
|
1248
|
+
positionXY = scrollableElementsXY[i] || undefined;
|
|
1249
|
+
|
|
1250
|
+
if(el == window || el == document.documentElement) {
|
|
1251
|
+
|
|
1252
|
+
if(positionXY != undefined) Transparent.scrollTo({top:positionXY[0], left:positionXY[1], duration:0});
|
|
1253
|
+
else if (location.hash) Transparent.scrollToHash(location.hash, {duration:0});
|
|
1254
|
+
else Transparent.scrollTo({top:0, left:0, duration:0});
|
|
1255
|
+
|
|
1256
|
+
} else {
|
|
1257
|
+
|
|
1258
|
+
if(positionXY != undefined) Transparent.scrollTo({top:positionXY[0], left:positionXY[1], duration:0}, el);
|
|
1259
|
+
else Transparent.scrollTo({top:0, left:0, duration:0}, el);
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
$('head').append(function() {
|
|
1265
|
+
|
|
1266
|
+
$(Settings.identifier).append(function() {
|
|
1267
|
+
|
|
1268
|
+
setTimeout(function() {
|
|
1269
|
+
|
|
1270
|
+
// Callback if needed, or any other actions
|
|
1271
|
+
callback();
|
|
1272
|
+
|
|
1273
|
+
// Trigger onload event
|
|
1274
|
+
dispatchEvent(new Event('transparent:load'));
|
|
1275
|
+
dispatchEvent(new Event('load'));
|
|
1276
|
+
|
|
1277
|
+
}.bind(this), 1);
|
|
1278
|
+
});
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
function uuidv4() {
|
|
1283
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
1284
|
+
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
|
1285
|
+
return v.toString(16);
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
function isLocalStorageNameSupported() {
|
|
1290
|
+
|
|
1291
|
+
var testKey = 'test', storage = window.localStorage;
|
|
1292
|
+
try {
|
|
1293
|
+
|
|
1294
|
+
storage.setItem(testKey, '1');
|
|
1295
|
+
storage.removeItem(testKey);
|
|
1296
|
+
return true;
|
|
1297
|
+
|
|
1298
|
+
} catch (error) { return false; }
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
Transparent.remToPixel = function(rem) { return parseFloat(rem) * parseFloat(getComputedStyle(document.documentElement).fontSize); }
|
|
1302
|
+
Transparent.emToPixel = function(em, el) { return parseFloat(em ) * parseFloat(getComputedStyle(el.parentElement).fontSize); }
|
|
1303
|
+
Transparent.percentToPixel = function(p , el) { return parseFloat(p ) * el.outerWidth(); }
|
|
1304
|
+
Transparent.parseToPixel = function(str, el) {
|
|
1305
|
+
|
|
1306
|
+
if(str === undefined) return undefined;
|
|
1307
|
+
|
|
1308
|
+
var array = String(str).split(", ");
|
|
1309
|
+
array = array.map(function(s) {
|
|
1310
|
+
|
|
1311
|
+
if(s.endsWith("rem")) return Transparent.remToPixel (s);
|
|
1312
|
+
else if(s.endsWith("em") ) return Transparent.emToPixel (s, el);
|
|
1313
|
+
else if(s.endsWith("%") ) return Transparent.percentToPixel(s, el);
|
|
1314
|
+
return parseFloat(s);
|
|
1315
|
+
});
|
|
1316
|
+
|
|
1317
|
+
return Math.max(...array);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
Transparent.getScrollPadding = function(el = document.documentElement) {
|
|
1321
|
+
|
|
1322
|
+
var style = window.getComputedStyle(el);
|
|
1323
|
+
var dict = {};
|
|
1324
|
+
dict["top" ] = Transparent.parseToPixel(style["scroll-padding-top" ] || 0, el);
|
|
1325
|
+
dict["left" ] = Transparent.parseToPixel(style["scroll-padding-left" ] || 0, el);
|
|
1326
|
+
dict["right" ] = Transparent.parseToPixel(style["scroll-padding-right" ] || 0, el);
|
|
1327
|
+
dict["bottom"] = Transparent.parseToPixel(style["scroll-padding-bottom"] || 0, el);
|
|
1328
|
+
|
|
1329
|
+
if(isNaN(dict["top" ])) dict["top"] = 0;
|
|
1330
|
+
if(isNaN(dict["left" ])) dict["left"] = 0;
|
|
1331
|
+
if(isNaN(dict["right" ])) dict["right"] = 0;
|
|
1332
|
+
if(isNaN(dict["bottom"])) dict["bottom"] = 0;
|
|
1333
|
+
|
|
1334
|
+
return dict;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
Transparent.scrollToHash = function(hash = window.location.hash, options = {}, callback = function() {}, el = window)
|
|
1338
|
+
{
|
|
1339
|
+
if (hash !== "") {
|
|
1340
|
+
|
|
1341
|
+
if ((''+hash).charAt(0) !== '#')
|
|
1342
|
+
hash = '#' + hash;
|
|
1343
|
+
|
|
1344
|
+
var hashElement = $(hash)[0] ?? undefined;
|
|
1345
|
+
if (hashElement !== undefined) {
|
|
1346
|
+
|
|
1347
|
+
var scrollTop = hashElement.getBoundingClientRect().top + document.documentElement.scrollTop - Transparent.getScrollPadding().top;
|
|
1348
|
+
var scrollLeft = hashElement.getBoundingClientRect().left + document.documentElement.scrollLeft - Transparent.getScrollPadding().left;
|
|
1349
|
+
|
|
1350
|
+
options = Object.assign({duration: Settings["smoothscroll_duration"], speed: Settings["smoothscroll_speed"]}, options, {left:scrollLeft, top:scrollTop});
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
var bottomReach = document.body.scrollHeight - (window.scrollY + window.innerHeight) < 1;
|
|
1354
|
+
var bottomOverflow = scrollTop > window.scrollY + window.innerHeight;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
if(hash === "" || (bottomReach && bottomOverflow)) callback({}, el);
|
|
1358
|
+
else Transparent.scrollTo(options, el, callback);
|
|
1359
|
+
|
|
1360
|
+
return this;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
Transparent.isElement = function(obj){
|
|
1364
|
+
try { return Boolean(obj.constructor.__proto__.prototype.constructor.name); }
|
|
1365
|
+
catch(e) { return false; }
|
|
1366
|
+
};
|
|
1367
|
+
|
|
1368
|
+
Transparent.getScrollableElement = function(el = document.documentElement)
|
|
1369
|
+
{
|
|
1370
|
+
return $(el).find('*').add(el).filter(function() { return $(this).isScrollable(); });
|
|
1371
|
+
};
|
|
1372
|
+
|
|
1373
|
+
Transparent.getScrollableElementXY = function() {
|
|
1374
|
+
|
|
1375
|
+
var elementsXY = [];
|
|
1376
|
+
var elements = Transparent.getScrollableElement();
|
|
1377
|
+
|
|
1378
|
+
for(i = 0; i < elements.length; i++)
|
|
1379
|
+
elementsXY.push([$(elements[i]).scrollTop(), $(elements[i]).scrollLeft()]);
|
|
1380
|
+
|
|
1381
|
+
return elementsXY;
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
function __main__(e) {
|
|
1385
|
+
|
|
1386
|
+
// Disable transparent JS (e.g. during development..)
|
|
1387
|
+
if(Settings.disable) return;
|
|
1388
|
+
|
|
1389
|
+
// Determine link
|
|
1390
|
+
const link = Transparent.findLink(e);
|
|
1391
|
+
if (link == null) return;
|
|
1392
|
+
|
|
1393
|
+
dispatchEvent(new CustomEvent('transparent:link', {link:link}));
|
|
1394
|
+
|
|
1395
|
+
const uuid = uuidv4();
|
|
1396
|
+
const type = link[0];
|
|
1397
|
+
const url = link[1];
|
|
1398
|
+
|
|
1399
|
+
var target = Transparent.isElement(link[2]) ? link[2] : undefined;
|
|
1400
|
+
var data = Transparent.isElement(link[2]) ? undefined : link[2];
|
|
1401
|
+
|
|
1402
|
+
var form = target != undefined && target.tagName == "FORM" ? target : undefined;
|
|
1403
|
+
if (form) {
|
|
1404
|
+
data = $(form).serialize();
|
|
1405
|
+
$(form).find(':submit').attr('disabled', 'disabled');
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
// Wait for transparent window event to be triggered
|
|
1409
|
+
if (!isReady) return;
|
|
1410
|
+
|
|
1411
|
+
if (e.type != Transparent.state.POPSTATE &&
|
|
1412
|
+
e.type != Transparent.state.HASHCHANGE && !$(this).find(Settings.identifier).length) return;
|
|
1413
|
+
|
|
1414
|
+
// Specific page exception
|
|
1415
|
+
for(i = 0; i < Settings.exceptions.length; i++) {
|
|
1416
|
+
|
|
1417
|
+
exception = Settings.exceptions[i];
|
|
1418
|
+
if (url.pathname.startsWith(exception)) return;
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
// Ressources files rejected
|
|
1422
|
+
if (url.pathname.startsWith("/css")) return;
|
|
1423
|
+
if (url.pathname.startsWith("/js")) return;
|
|
1424
|
+
if (url.pathname.startsWith("/images")) return;
|
|
1425
|
+
if (url.pathname.startsWith("/vendor")) return;
|
|
1426
|
+
|
|
1427
|
+
// Unsecure url
|
|
1428
|
+
if (url.origin != location.origin) return;
|
|
1429
|
+
|
|
1430
|
+
e.preventDefault();
|
|
1431
|
+
|
|
1432
|
+
if (url == location) return;
|
|
1433
|
+
|
|
1434
|
+
if((e.type == Transparent.state.CLICK || e.type == Transparent.state.HASHCHANGE) && url.pathname == location.pathname && url.search == location.search && type != "POST") {
|
|
1435
|
+
|
|
1436
|
+
if(!url.hash) return;
|
|
1437
|
+
Transparent.scrollToHash(url.hash ?? "", {easing:Settings["smoothscroll_easing"], duration:Settings["smoothscroll_duration"], speed:Settings["smoothscroll_speed"]}, function() {
|
|
1438
|
+
|
|
1439
|
+
if (e.target != undefined && $(e.target).data("skip-hash") != true)
|
|
1440
|
+
window.replaceHash(url.hash);
|
|
1441
|
+
|
|
1442
|
+
}, $(e.target).closestScrollable());
|
|
1443
|
+
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
if(e.metaKey && e.altKey) return window.open(url).focus();
|
|
1448
|
+
if(e.metaKey && e.shiftKey) return window.open(url, '_blank').focus(); // Safari not focusing..
|
|
1449
|
+
if(e.metaKey || $(target).attr("target") == "_blank") return window.open(url, '_blank');
|
|
1450
|
+
|
|
1451
|
+
dispatchEvent(new Event('transparent:onbeforeunload'));
|
|
1452
|
+
dispatchEvent(new Event('onbeforeunload'));
|
|
1453
|
+
|
|
1454
|
+
$(Transparent.html).prop("user-scroll", true);
|
|
1455
|
+
$(Transparent.html).stop();
|
|
1456
|
+
|
|
1457
|
+
function isJsonResponse(str) {
|
|
1458
|
+
try { JSON.parse(str); return true; }
|
|
1459
|
+
catch (e) { return false; }
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
function handleResponse(uuid, status = 200, method = null, data = null, xhr = null, request = null) {
|
|
1463
|
+
|
|
1464
|
+
var responseURL;
|
|
1465
|
+
responseURL = xhr !== null ? xhr.responseURL : url.href;
|
|
1466
|
+
|
|
1467
|
+
responseText = Transparent.getResponseText(uuid);
|
|
1468
|
+
|
|
1469
|
+
var fragmentPos = responseURL.indexOf("#");
|
|
1470
|
+
var strippedResponseUrl = (fragmentPos < 0 ? responseURL : responseURL.substring(0, fragmentPos)).trimEnd("/");
|
|
1471
|
+
|
|
1472
|
+
var fragmentPos = url.href.indexOf("#");
|
|
1473
|
+
var strippedUrlHref = (fragmentPos < 0 ? url.href : url.href.substring(0, fragmentPos)).trimEnd("/");
|
|
1474
|
+
if( strippedUrlHref == strippedResponseUrl )
|
|
1475
|
+
responseURL = url.href; // NB: xhr.responseURL strips away #fragments
|
|
1476
|
+
|
|
1477
|
+
if(!responseText) {
|
|
1478
|
+
|
|
1479
|
+
if(!request && responseText === null) {
|
|
1480
|
+
|
|
1481
|
+
setTimeout(function() { window.location.href = responseURL; }, Settings["throttle"]);
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
responseText = request.responseText;
|
|
1486
|
+
if(status >= 500) {
|
|
1487
|
+
|
|
1488
|
+
console.error("Unexpected XHR response from "+uuid+": error code "+request.status);
|
|
1489
|
+
console.error(sessionStorage);
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
if(!Transparent.hasResponse(uuid))
|
|
1493
|
+
Transparent.setResponse(uuid, responseText);
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
var dom = new DOMParser().parseFromString(responseText, "text/html");
|
|
1497
|
+
if(request && request.getResponseHeader("Content-Type") == "application/json") {
|
|
1498
|
+
|
|
1499
|
+
if(!isJsonResponse(responseText)) {
|
|
1500
|
+
console.error("Invalid response received for "+ responseURL);
|
|
1501
|
+
if(Settings.debug) return Transparent.rescue(dom);
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
if(form) {
|
|
1505
|
+
$(form).find(':submit').removeAttr('disabled');
|
|
1506
|
+
form.reset();
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
var response = JSON.parse(responseText);
|
|
1510
|
+
if(Settings.debug) console.log(response);
|
|
1511
|
+
|
|
1512
|
+
if(response.code == "302") {
|
|
1513
|
+
|
|
1514
|
+
if(response.target) location.href = response.target;
|
|
1515
|
+
else location.reload();
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
return dispatchEvent(new Event('load'));
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
// From here the page is valid..
|
|
1522
|
+
// so the new page is added to history..
|
|
1523
|
+
if(xhr)
|
|
1524
|
+
history.pushState({uuid: uuid, status:status, method: method, data: data, href: responseURL}, '', responseURL);
|
|
1525
|
+
|
|
1526
|
+
var dom = new DOMParser().parseFromString(responseText, "text/html");
|
|
1527
|
+
if(status != 200) // Blatant error received..
|
|
1528
|
+
return Transparent.rescue(dom);
|
|
1529
|
+
|
|
1530
|
+
// Page not recognized.. just go there.. no POST information transmitted..
|
|
1531
|
+
if(!Transparent.isPage(dom))
|
|
1532
|
+
return window.location.href = url;
|
|
1533
|
+
|
|
1534
|
+
// Layout not compatible.. needs to be reloaded (exception when POST is detected..)
|
|
1535
|
+
if(!Transparent.isCompatiblePage(dom, method, data))
|
|
1536
|
+
return window.location.href = url;
|
|
1537
|
+
|
|
1538
|
+
// Mark layout as known
|
|
1539
|
+
if(!Transparent.isKnownLayout(dom)) {
|
|
1540
|
+
|
|
1541
|
+
Transparent.html.addClass(Transparent.state.NEW);
|
|
1542
|
+
dispatchEvent(new Event('transparent:'+Transparent.state.NEW));
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
// Mark active as popstate or submit
|
|
1546
|
+
if(e.type == Transparent.state.POPSTATE) {
|
|
1547
|
+
|
|
1548
|
+
Transparent.html.addClass(Transparent.state.POPSTATE);
|
|
1549
|
+
dispatchEvent(new Event('transparent:'+Transparent.state.POPSTATE));
|
|
1550
|
+
|
|
1551
|
+
} else if(e.type == Transparent.state.SUBMIT) {
|
|
1552
|
+
|
|
1553
|
+
Transparent.html.addClass(Transparent.state.SUBMIT);
|
|
1554
|
+
dispatchEvent(new Event('transparent:'+Transparent.state.SUBMIT));
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
// Callback active
|
|
1558
|
+
var prevLayout = Transparent.getLayout();
|
|
1559
|
+
var newLayout = Transparent.getLayout(dom);
|
|
1560
|
+
if(prevLayout == newLayout)
|
|
1561
|
+
Transparent.html.addClass(Transparent.state.SAME);
|
|
1562
|
+
|
|
1563
|
+
var switchLayout = Transparent.state.SWITCH.replace("X", prevLayout).replace("Y", newLayout);
|
|
1564
|
+
Transparent.html.addClass(switchLayout);
|
|
1565
|
+
|
|
1566
|
+
dispatchEvent(new Event('transparent:'+switchLayout));
|
|
1567
|
+
|
|
1568
|
+
if($(dom).find("html").hasClass(Transparent.state.RELOAD))
|
|
1569
|
+
window.location.reload();
|
|
1570
|
+
|
|
1571
|
+
Transparent.html.addClass(Transparent.state.LOADING);
|
|
1572
|
+
|
|
1573
|
+
return Transparent.activeIn(function() {
|
|
1574
|
+
|
|
1575
|
+
if($(dom).find("html").hasClass(Transparent.state.RELOAD))
|
|
1576
|
+
return; // Reload state found..
|
|
1577
|
+
|
|
1578
|
+
Transparent.onLoad(uuid, dom, function() {
|
|
1579
|
+
|
|
1580
|
+
Transparent.activeOut(function() {
|
|
1581
|
+
|
|
1582
|
+
Transparent.html
|
|
1583
|
+
.removeClass(switchLayout)
|
|
1584
|
+
.removeClass(Transparent.state.SUBMIT)
|
|
1585
|
+
.removeClass(Transparent.state.POPSTATE)
|
|
1586
|
+
.removeClass(Transparent.state.NEW);
|
|
1587
|
+
});
|
|
1588
|
+
|
|
1589
|
+
}, type != "POST");
|
|
1590
|
+
});
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
if(history.state && !Transparent.hasResponse(history.state.uuid))
|
|
1594
|
+
Transparent.setResponse(history.state.uuid, Transparent.html[0], Transparent.getScrollableElementXY());
|
|
1595
|
+
|
|
1596
|
+
// This append on user click (e.g. when user push a link)
|
|
1597
|
+
// It is null when dev is pushing or replacing state
|
|
1598
|
+
var addNewState = !e.state;
|
|
1599
|
+
if (addNewState) {
|
|
1600
|
+
|
|
1601
|
+
if(history.state)
|
|
1602
|
+
Transparent.setResponsePosition(history.state.uuid, Transparent.getScrollableElementXY());
|
|
1603
|
+
|
|
1604
|
+
$(Transparent.html).prop("user-scroll", false); // make sure to avoid page jump during transition (cancelled in activeIn callback)
|
|
1605
|
+
|
|
1606
|
+
// Submit ajax request..
|
|
1607
|
+
var xhr = new XMLHttpRequest();
|
|
1608
|
+
return jQuery.ajax({
|
|
1609
|
+
url: url.href,
|
|
1610
|
+
type: type,
|
|
1611
|
+
data: data,
|
|
1612
|
+
dataType: 'html',
|
|
1613
|
+
headers: Settings["headers"] || {},
|
|
1614
|
+
xhr: function () { return xhr; },
|
|
1615
|
+
success: function (html, status, request) { return handleResponse(uuid, request.status, type, data, xhr, request); },
|
|
1616
|
+
error: function (request, ajaxOptions, thrownError) { return handleResponse(uuid, request.status, type, data, xhr, request); }
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
return handleResponse(history.state.uuid, history.state.status, history.state.method, history.state.data);
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
// Update history if not refreshing page or different page (avoid double pushState)
|
|
1624
|
+
var href = history.state ? history.state.href : null;
|
|
1625
|
+
if (href != location.origin + location.pathname + location.hash)
|
|
1626
|
+
history.replaceState({uuid: uuidv4(), status: history.state ? history.state.status : 200, data:{}, method: history.state ? history.state.method : "GET", href: location.origin + location.pathname + location.hash}, '', location.origin + location.pathname + location.hash);
|
|
1627
|
+
|
|
1628
|
+
// Overload onpopstate
|
|
1629
|
+
if(Settings.disable) {
|
|
1630
|
+
|
|
1631
|
+
var states = Object.values(Transparent.state);
|
|
1632
|
+
var htmlClass = Array.from(($("html").attr("class") || "").split(" ")).filter(x => !states.includes(x));
|
|
1633
|
+
Transparent.html.removeClass(states).addClass(htmlClass.join(" ")+" "+Transparent.state.ROOT+" "+Transparent.state.READY+" "+Transparent.state.DISABLE);
|
|
1634
|
+
|
|
1635
|
+
} else {
|
|
1636
|
+
|
|
1637
|
+
window.onpopstate = __main__; // Onpopstate pop out straight to previous page.. this creates a jump while changing pages with hash..
|
|
1638
|
+
window.onhashchange = __main__;
|
|
1639
|
+
document.addEventListener('click', __main__, false);
|
|
1640
|
+
|
|
1641
|
+
$("form").submit(__main__);
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
return Transparent;
|
|
1645
|
+
});
|