rytm-webflow 1.1.5 → 2.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 CHANGED
@@ -11,7 +11,6 @@ $ npm install rytm-webflow --save
11
11
  ## Dependencies
12
12
  - gsap
13
13
  - imagesloaded
14
- - jquery
15
14
  - scrollmagic
16
15
  - scrollmagic-plugin-gsap
17
16
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rytm-webflow",
3
- "version": "1.1.5",
3
+ "version": "2.0.0",
4
4
  "description": "rytm webflow pack - ASwap, ShowUp",
5
5
  "main": "scripts/index.js",
6
6
  "scripts": {
@@ -18,7 +18,6 @@
18
18
  "dependencies": {
19
19
  "gsap": "^3.5.1",
20
20
  "imagesloaded": "^4.1.4",
21
- "jquery": "^3.1.1",
22
21
  "scrollmagic": "^2.0.7",
23
22
  "scrollmagic-plugin-gsap": "^1.0.4"
24
23
  }
@@ -1,4 +1,3 @@
1
- import $ from "jquery"
2
1
 
3
2
  import ASwapDispatcher from "./ASwapDispatcher";
4
3
  import Events from "./Events";
@@ -103,7 +102,7 @@ class ASwap {
103
102
  this.events.onRequestLoad()
104
103
  }
105
104
  onRequestLoaded(e) {
106
- this.getControllersFromContainer(e.target.$freshContent).forEach( (c, index)=> {
105
+ this.getControllersFromContainer(e.target.freshContent).forEach( (c, index)=> {
107
106
  c.onRequestLoaded(e);
108
107
  });
109
108
  document.documentElement.classList.remove("as-request-loading");
@@ -113,7 +112,7 @@ class ASwap {
113
112
  document.documentElement.classList.add('as-hide');
114
113
  this.getActiveControlles().forEach( (c, index)=> {
115
114
  // if view is not present in fresh content then call controller hide
116
- if (!c.getViewContainer(e.target.$freshContent).length) {
115
+ if (!c.getViewContainer(e.target.freshContent)) {
117
116
  c.onViewHide(e);
118
117
  }
119
118
  });
@@ -123,34 +122,34 @@ class ASwap {
123
122
  document.documentElement.classList.remove('as-hide');
124
123
  this.getActiveControlles().forEach( (c, index)=> {
125
124
  // if view is not present in fresh content then call controller hidden
126
- if (!c.getViewContainer(e.target.$freshContent).length) {
125
+ if (!c.getViewContainer(e.target.freshContent)) {
127
126
  c.onViewHidden(e);
128
127
  }
129
128
  });
130
129
  this.events.onViewHidden()
131
130
  }
132
131
  onViewSwapStart(e) {
133
- this.getControllersFromContainer(e.target.$freshContent).forEach( (c, index)=> {
132
+ this.getControllersFromContainer(e.target.freshContent).forEach( (c, index)=> {
134
133
  c.onViewSwapStart(e);
135
134
  });
136
135
  this.events.onViewSwapStart()
137
136
  }
138
137
  onViewSwapComplete(e) {
139
- this.getControllersFromContainer(e.target.$freshContent).forEach( (c, index)=> {
138
+ this.getControllersFromContainer(e.target.freshContent).forEach( (c, index)=> {
140
139
  c.onViewSwapComplete(e);
141
140
  });
142
141
  this.events.onViewSwapComplete()
143
142
  }
144
143
  onViewShow(e) {
145
144
  document.documentElement.classList.add('as-show');
146
- this.getControllersFromContainer(e.target.$freshContent).forEach( (c, index)=> {
145
+ this.getControllersFromContainer(e.target.freshContent).forEach( (c, index)=> {
147
146
  c.onViewShow(e);
148
147
  });
149
148
  this.events.onViewShow()
150
149
  }
151
150
  onViewShown(e) {
152
151
  document.documentElement.classList.add('as-show');
153
- this.getControllersFromContainer(e.target.$freshContent).forEach( (c, index)=> {
152
+ this.getControllersFromContainer(e.target.freshContent).forEach( (c, index)=> {
154
153
  c.onViewShown(e);
155
154
  });
156
155
  document.documentElement.classList.remove('as-in-progress');
@@ -173,22 +172,20 @@ class ASwap {
173
172
  }
174
173
  /**
175
174
  * get controllers from container based on view's included in the container
176
- * @param {jQuery} $container
175
+ * @param container
177
176
  * @returns {Array}
178
177
  **/
179
- getControllersFromContainer($container) {
178
+ getControllersFromContainer(container) {
180
179
  let arr = [];
181
- $container.find("*[data-as-view]").each( (index, el)=> {
182
- let name = $(el).data("as-view");
183
- let id = $(el).data("as-id");
184
- if (!id) {
185
- id = name;
186
- }
187
- let c = this.getController(name, id);
180
+ const list = [...container.querySelectorAll("*[data-as-view]")]
181
+ list.forEach((el, index) => {
182
+ const name = el.dataset.asView
183
+ const id = el.dataset.asId ? el.dataset.asId : name
184
+ const c = this.getController(name, id)
188
185
  if (c) {
189
- arr.push(c);
186
+ arr.push(c)
190
187
  }
191
- });
188
+ })
192
189
  return arr;
193
190
  }
194
191
  /**
@@ -1,4 +1,3 @@
1
- import $ from "jquery"
2
1
  import Events from "./Events"
3
2
  import EventDispatcher from "./EventDispatcher"
4
3
 
@@ -24,7 +23,7 @@ class ASwapDispatcher extends EventDispatcher {
24
23
  this.prevUrl = null;
25
24
  this.ajaxStore = [];
26
25
  this.asHistory = [];
27
- this.$freshContent = $(this.swapSelector);
26
+ this.freshContent = document.querySelector(this.swapSelector);
28
27
 
29
28
  }
30
29
 
@@ -65,48 +64,61 @@ class ASwapDispatcher extends EventDispatcher {
65
64
  * @param tag {String} the tag name, eg. body
66
65
  * @returns {String|Boolean}
67
66
  **/
68
- getTagFromResult(result, tag) {
67
+ getTagFromResult(result, tag, index = 0) {
69
68
  let regex = new RegExp('<' + tag + '[^>]*>((.|[\n\r])*)<\/' + tag + '>');
70
69
  let body = regex.exec(result);
71
- if (body) {
72
- return body[0];
70
+ if (body && body[index]) {
71
+ return body[index];
73
72
  } else {
74
- this.warning("AS problem - " + tag + " could not be extracted");
73
+ this.warning("AS problem - " + tag + " could not be extracted, index:", idnex);
75
74
  return false;
76
75
  }
77
76
  }
77
+ /**
78
+ * ###
79
+ */
80
+ getElementFromResult(result, tagName) {
81
+ let htmlStr = this.getTagFromResult(result, tagName, 1)
82
+ let el = document.createElement(tagName)
83
+ el.innerHTML = htmlStr.trim()
84
+ return el
85
+ }
78
86
 
79
87
  /**
80
88
  * swap the meta and title tags in document's <head>
81
89
  * @param result {String} the ajax request result
82
90
  **/
83
91
  swapHeadMeta(result) {
84
- let head = this.getTagFromResult(result, "head");
85
- if (!head) {
92
+ const freshHead = this.getElementFromResult(result, "head")
93
+ if (!freshHead) {
86
94
  this.warning("AS problem - head was not found in result");
87
95
  return false;
88
96
  }
89
- let $head = $(head);
90
- $head.each( (index, el)=>{
91
- // swap only meta and title
92
- if ($(el).is('title')) {
93
- document.title = $(el).html();
94
- }
95
- if ($(el).is('meta')) {
96
- let name = $(el).attr("name");
97
- if (name) {
98
- $("html head meta[name='" + name + "']").attr("content", $(el).attr("content"));
99
- }
100
- let itemprop = $(el).attr("name");
101
- if (itemprop) {
102
- $("html head meta[itemprop='" + itemprop + "']").attr("content", $(el).attr("content"));
103
- }
104
- let property = $(el).attr("property");
105
- if (property) {
106
- $("html head meta[property='" + property + "']").attr("content", $(el).attr("content"));
107
- }
97
+ const list = [...freshHead.querySelectorAll("*")]
98
+ list.forEach((el, index) => {
99
+ // swap if TITLE or META
100
+ switch (el.nodeName.toLowerCase()) {
101
+ case "title":
102
+ document.title = el.innerHTML
103
+ break;
104
+ case "meta":
105
+ const name = el.getAttribute("name")
106
+ const property = el.getAttribute("property")
107
+ const itemprop = el.getAttribute("itemprop")
108
+ const content = el.getAttribute("content")
109
+ // get the meta query string
110
+ let query = 'html head meta'
111
+ query += (name ? '[name="' + name + '"' : '')
112
+ query += (property ? '[property="' + property + '"' : '')
113
+ query += (itemprop ? '[itemprop="' + itemprop + '"' : '')
114
+ let metaEl = document.querySelector(query)
115
+ if (metaEl && content) {
116
+ metaEl.setAttribute("content", content)
117
+ }
118
+ break;
108
119
  }
109
- });
120
+ })
121
+
110
122
  }
111
123
  /**
112
124
  * swap the HTML class names
@@ -134,8 +146,7 @@ class ASwapDispatcher extends EventDispatcher {
134
146
  }
135
147
  let html = document.createElement('html');
136
148
  html.innerHTML = body;
137
- let $resultBody = $(html).find('body');
138
- return $resultBody.find(this.swapSelector);
149
+ return html.querySelector(this.swapSelector)
139
150
  }
140
151
 
141
152
  /**
@@ -144,8 +155,8 @@ class ASwapDispatcher extends EventDispatcher {
144
155
  **/
145
156
  handleResult(result) {
146
157
  // store fresh content in public variable
147
- this.$freshContent = this.getFreshContentFromResult(result);
148
- let $swap = $(this.swapSelector);
158
+ this.freshContent = this.getFreshContentFromResult(result);
159
+ const swap = document.querySelector(this.swapSelector)
149
160
  // dispatch event
150
161
  this.dispatch(Events.NAV_REQUEST_LOADED);
151
162
  this.dispatch(Events.NAV_VIEW_HIDE);
@@ -155,17 +166,17 @@ class ASwapDispatcher extends EventDispatcher {
155
166
  this.asAnimTimeout1 = setTimeout(()=> {
156
167
  this.dispatch(Events.NAV_VIEW_HIDDEN);
157
168
  this.dispatch(Events.NAV_SWAP_START);
158
- if (this.$freshContent.length) {
159
- $swap.attr("class", this.$freshContent.attr("class")); // stage class
160
- $swap.html(this.$freshContent.html());
169
+ if (this.freshContent) {
170
+ // swap stage classes
171
+ swap.setAttribute("class", this.freshContent.getAttribute("class"))
172
+ // swap content
173
+ swap.innerHTML = this.freshContent.innerHTML
161
174
  }
162
175
  // swap head (meta)
163
176
  this.swapHeadMeta(result);
164
177
  setTimeout(() => {
165
178
  this.swapBodyToHtmlClasses(result);
166
179
  }, 10)
167
-
168
-
169
180
  // scroll up
170
181
  if (!this.currentTrigger || !this.currentTrigger.classList.contains(this.noScrollClassName)) {
171
182
  this.resetScrollPosition();
@@ -179,6 +190,7 @@ class ASwapDispatcher extends EventDispatcher {
179
190
  this.dispatch(Events.NAV_VIEW_SHOWN);
180
191
  }, this.animationTimeShow);
181
192
  }, this.animationTimeHide);
193
+
182
194
  }
183
195
  /**
184
196
  * get current URL
@@ -242,6 +254,7 @@ class ASwapDispatcher extends EventDispatcher {
242
254
  document.documentElement.style.scrollBehavior = this.defaultDocumentScrollBehavior ? this.defaultDocumentScrollBehavior : 'smooth';
243
255
  }, 5)
244
256
  }
257
+
245
258
  /**
246
259
  * Preload URL
247
260
  * @param url {String}
@@ -254,12 +267,15 @@ class ASwapDispatcher extends EventDispatcher {
254
267
  if (result) {
255
268
  return false
256
269
  }
257
- $.get(url, {}, (result)=> {
258
- if (result) {
259
- this.trace('URL was preloaded', url)
260
- this.storeResult(url, result);
270
+ let xhr = new XMLHttpRequest();
271
+ xhr.onreadystatechange = () => {
272
+ if (xhr.readyState === 4) {
273
+ // this.trace('URL was preloaded', url, xhr.responseText)
274
+ this.storeResult(url, xhr.responseText);
261
275
  }
262
- });
276
+ };
277
+ xhr.open('GET', url);
278
+ xhr.send();
263
279
 
264
280
  }
265
281
  /**
@@ -309,22 +325,21 @@ class ASwapDispatcher extends EventDispatcher {
309
325
  loadURL(url, data = {}, method = 'get', useCache = true) {
310
326
  // dispatch event
311
327
  this.dispatch(Events.NAV_REQUEST_LOAD);
312
- this.trace("ASwap load: ", url);
313
- $.ajax({
314
- type: method,
315
- url,
316
- data,
317
- success: (result) => {
318
- if (result) {
319
- if (useCache) {
320
- this.storeResult(url, result);
321
- }
322
- this.handleResult(result);
323
- } else {
324
- this.warning("AS problem - GET", url, "returned no result");
325
- }
326
- }
327
- });
328
+ this.trace("ASwap load: ", url);
329
+
330
+ let xhr = new XMLHttpRequest();
331
+ xhr.onreadystatechange = () => {
332
+ if (xhr.readyState === 4) {
333
+ if (useCache) {
334
+ this.storeResult(url, xhr.responseText);
335
+ }
336
+ this.handleResult(xhr.responseText);
337
+ } else {
338
+ this.warning("AS problem - GET", url, "returned no result");
339
+ }
340
+ };
341
+ xhr.open(method, url);
342
+ xhr.send(data);
328
343
  }
329
344
  /**
330
345
  * history pushState (URL)
@@ -345,7 +360,9 @@ class ASwapDispatcher extends EventDispatcher {
345
360
  * @param e {Event}
346
361
  **/
347
362
  onHistoryBack(e) {
363
+ e.preventDefault();
348
364
  let url = window.location.pathname + window.location.search;
365
+ console.log("HISTORY BACK", url)
349
366
  this.openURL(url, true);
350
367
  }
351
368
  /**
@@ -357,76 +374,94 @@ class ASwapDispatcher extends EventDispatcher {
357
374
  this.storeResult(url, result);
358
375
  this.currentUrl = url;
359
376
  }
360
- isLinkElementValid($a) {
377
+ isLinkElementValid(a) {
361
378
  let result = false
362
- if ($a.length) {
363
- if (!$a.hasClass(this.noSwapClassName) && $a.attr("target") != "_blank") {
379
+ if (a) {
380
+ if (!a.classList.contains(this.noSwapClassName) && a.getAttribute("target") != "_blank") {
364
381
  result = true
365
382
  }
366
383
  }
367
384
  return result
368
385
  }
369
- isFormElementValid($f) {
386
+ isFormElementValid(f) {
370
387
  let result = false
371
- if ($f.length) {
372
- if (!$f.hasClass(this.noSwapClassName)) {
388
+ if (f) {
389
+ if (!f.classList.contains(this.noSwapClassName)) {
373
390
  result = true
374
391
  }
375
392
  }
376
393
  return result
377
394
  }
395
+
396
+ /**
397
+ * ### Event handlers ###
398
+ */
399
+ onDocumentClick(e) {
400
+ if (e.target.tagName !== 'A') {
401
+ return;
402
+ }
403
+ const a = e.target
404
+ if (this.isLinkElementValid(a) && !e.metaKey & !e.ctrlKey) {
405
+ const useCache = !a.classList.contains(this.noCacheClassName);
406
+ const url = a.getAttribute("href");
407
+ if (url.indexOf('://') < 0) {
408
+ e.preventDefault()
409
+ this.currentTrigger = a
410
+ this.openURL(url, false, useCache);
411
+ }
412
+ }
413
+ }
414
+
415
+ onDocumentMouseover(e) {
416
+ if (e.target.tagName !== 'A') {
417
+ return;
418
+ }
419
+ const a = e.target
420
+ if (this.isLinkElementValid(a)) {
421
+ const useCache = !a.classList.contains(this.noCacheClassName);
422
+ if (useCache) {
423
+ const url = a.getAttribute("href");
424
+ this.preloadURL(url)
425
+ }
426
+ }
427
+ }
428
+ onDocumentSubmit(e) {
429
+ e.preventDefault();
430
+ if (e.target.tagName !== 'FORM') {
431
+ return;
432
+ }
433
+ const f = e.target
434
+ if (this.isFormElementValid(f)) {
435
+ const useCache = !f.classList.contains(this.noCacheClassName);
436
+ const url = f.getAttribute("action");
437
+ if (url.indexOf('://') < 0) {
438
+ e.preventDefault()
439
+ this.currentTrigger = f
440
+ const method = f.getAttribute('method') ? f.getAttribute('method') : 'get'
441
+ const dataStr = new URLSearchParams(new FormData(f)).toString()
442
+ const requestUrl = method == 'get' ? (url + '?' + dataStr) : url
443
+ this.submit(requestUrl, dataStr, method, false, useCache)
444
+ }
445
+
446
+ }
447
+
448
+ }
378
449
  /**
379
450
  * add event listeners
380
451
  **/
381
452
  addEventListeners() {
382
453
  // catch all a click events
383
- $("body").on("click", "a", (e)=> {
384
- let $a = $(e.currentTarget);
385
- // check black list, target _blank and if ctrl or cmd is not pressed
386
- if (this.isLinkElementValid($a) && !e.metaKey & !e.ctrlKey) {
387
- let useCache = !$a.hasClass(this.noCacheClassName);
388
- let url = $a.attr("href");
389
- if (url.indexOf('://') < 0) {
390
- e.preventDefault();
391
- this.currentTrigger = e.currentTarget
392
- this.openURL(url, false, useCache);
393
- }
394
- }
395
- });
454
+ document.addEventListener('click', this.onDocumentClick.bind(this), false)
396
455
  // preload on hover
397
456
  if (this.preloadOnHover) {
398
- $("body").on("mouseover", "a", (e)=> {
399
- let $a = $(e.currentTarget);
400
- if (this.isLinkElementValid($a)) {
401
- let useCache = !$a.hasClass(this.noCacheClassName);
402
- let url = $a.attr("href");
403
- if (useCache) {
404
- this.preloadURL(url)
405
- }
406
- }
407
- })
457
+ document.addEventListener('mouseover', this.onDocumentMouseover.bind(this), false)
408
458
  }
409
459
  // forms?
410
460
  if (this.formsEnabled) {
411
- $("body").on("submit", this.formsSelector, (e) => {
412
- let $f = $(e.currentTarget)
413
- if (this.isFormElementValid($f)) {
414
- let useCache = !$f.hasClass(this.noCacheClassName)
415
- let url = $f.attr('action')
416
- if (url.indexOf('://') < 0) {
417
- e.preventDefault()
418
- this.currentTrigger = e.currentTarget
419
- const data = $f.serialize()
420
- const method = $f.attr('method') ? $f.attr('method') : 'get'
421
- const requestUrl = method == 'get' ? (url + '?' + data) : url
422
- this.submit(requestUrl, data, method, false, useCache)
423
- }
424
- }
425
-
426
- })
461
+ document.addEventListener('submit', this.onDocumentSubmit.bind(this), false)
427
462
  }
428
- // window back button support
429
- $(window).on("popstate", this.onHistoryBack.bind(this));
463
+ // browser back button
464
+ window.addEventListener('popstate', this.onHistoryBack.bind(this), false)
430
465
  }
431
466
 
432
467
  initialDispatch() {
@@ -487,8 +522,8 @@ class ASwapDispatcher extends EventDispatcher {
487
522
  * init
488
523
  **/
489
524
  init() {
490
- let $swap = $(this.swapSelector);
491
- if (!$swap.length) {
525
+ const swap = document.querySelector(this.swapSelector)
526
+ if (!swap) {
492
527
  this.warning("AS problem - swap container not found!", this.swapSelector);
493
528
  return false;
494
529
  }
@@ -29,12 +29,10 @@ class Controller {
29
29
  return this.active;
30
30
  }
31
31
  /**
32
- * find my $view container in wrapper
33
- * @param {jQuery} $wrapper - search within this element
34
- * @retunrs {jQuery|Boolean} $view | false
32
+ * find my view container in wrapper
35
33
  **/
36
- getViewContainer($wrapper) {
37
- return $wrapper.find('*[data-as-id="' + this.id + '"]');
34
+ getViewContainer(wrapper) {
35
+ return wrapper.querySelector('*[data-as-id="' + this.id + '"]');
38
36
  }
39
37
 
40
38
  getContainerSelector() {
@@ -72,13 +70,13 @@ class Controller {
72
70
  **/
73
71
  onRequestLoaded(e) {
74
72
  if (!this.active && this.view) {
75
- this.view.prepare(e.target.$freshContent.get(0));
73
+ this.view.prepare(e.target.freshContent.get(0));
76
74
  }
77
75
  }
78
76
  /**
79
77
  * on view hide - animation out / hide start
80
78
  * request is loaded and fresh content is ready to init
81
- * loaded content available <code>e.target.$freshContent</code>
79
+ * loaded content available <code>e.target.freshContent</code>
82
80
  * @param {Event} e
83
81
  **/
84
82
  onViewHide(e) {
@@ -24,7 +24,7 @@ class ControllerImgLoad extends Controller {
24
24
  container.classList.add("as-images-loading")
25
25
  this.view.loadImagesStart(container);
26
26
  }
27
- imagesLoaded(this.getContainerSelector(), $.proxy(this.loadImagesComplete, this));
27
+ imagesLoaded(this.getContainerSelector(), this.loadImagesComplete.bind(this));
28
28
  }
29
29
  /**
30
30
  * load images complete
@@ -44,7 +44,7 @@ class ControllerImgLoad extends Controller {
44
44
  /**
45
45
  * on view hide - animation out / hide start
46
46
  * request is loaded and fresh content is ready to init
47
- * loaded content available <code>e.target.$freshContent</code>
47
+ * loaded content available <code>e.target.freshContent</code>
48
48
  * @param {Event} e
49
49
  **/
50
50
  onViewHide(e) {
@@ -20,7 +20,6 @@ class View {
20
20
  }
21
21
  /**
22
22
  * prepare (before show)
23
- * @param {jQuery} $container
24
23
  **/
25
24
  prepare(container) {
26
25
  }
@@ -24,21 +24,35 @@ class ShowUp {
24
24
  this.buildParallaxScenes()
25
25
  this.addEventListeners()
26
26
  }
27
+ /**
28
+ * Class event handlers
29
+ */
30
+ handleEvent(e) {
31
+ switch (e.type) {
32
+ case 'resize':
33
+ this.onWindowUpdate(e)
34
+ break;
35
+ case 'DOMContentLoaded':
36
+ this.onWindowUpdate(e)
37
+ break;
38
+ }
39
+ }
27
40
  /**
28
41
  * Add event listeners
29
42
  */
30
43
  addEventListeners() {
31
- $(document).on('DOMContentLoaded load', $.proxy(this.onWindowUpdate, this))
32
- $(window).on('resize', $.proxy(this.onWindowUpdate, this))
44
+ window.addEventListener('resize', this)
45
+ document.addEventListener('DOMContentLoaded', this)
33
46
  }
34
47
  /**
35
48
  * Remove event listeners
36
49
  */
37
50
  removeEventListeners() {
38
- $(document).off('DOMContentLoaded load', $.proxy(this.onWindowUpdate, this));
39
- $(window).off('resize', $.proxy(this.onWindowUpdate, this));
51
+ window.removeEventListener('resize', this)
52
+ document.removeEventListener('DOMContentLoaded', this)
40
53
  }
41
54
  onWindowUpdate(e) {
55
+ console.log("show up WINDOW UPDATE,", this)
42
56
  if (this.scenes.length > 0) {
43
57
  scrollController.refresh()
44
58
  }