bigpipe-util 0.1.4 → 0.2.2

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/CHANGELOG.md CHANGED
@@ -4,23 +4,29 @@ All notable changes to `bigpipe-util` will be documented in this file.
4
4
 
5
5
  Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
6
6
 
7
- ## v0.1.1 - 2022-03-27
7
+ ## v0.2.2 - 2022-08-03
8
8
 
9
- ### Added
10
- - Part of BigPipe implementation for Webpack.
9
+ ### Fixed
10
+ - calls for modules without constructor
11
+ - dialog opening when using instant closing
11
12
 
12
- ## v0.1.2 - 2022-04-14
13
+ ## v0.2.1 - 2022-06-02
13
14
 
14
15
  ### Added
15
- - Dialogs support.
16
+ - Prevent links from being double-clicked
17
+ - Support for keyboard (close by escape)
16
18
 
17
- ## v0.1.3 - 2022-04-27
19
+ ### Fixed
20
+ - Closing dialogs with [esc] in the correct order
21
+
22
+ ## v0.2.0 - 2022-05-17
18
23
 
19
24
  ### Added
20
- - Method to close only current dialog
25
+ - Shield to prevent "JSON Hijacking"
26
+ - Invalid node checking for AsyncDOM
21
27
 
22
28
  ### Fixed
23
- - Dialog z-index
29
+ - Backdrop for 2+ opened dialogs
24
30
 
25
31
  ## v0.1.4 - 2022-05-06
26
32
 
@@ -30,3 +36,21 @@ Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) princip
30
36
 
31
37
  ### Fixed
32
38
  - Arguments for non-method require calls
39
+
40
+ ## v0.1.3 - 2022-04-27
41
+
42
+ ### Added
43
+ - Method to close only current dialog
44
+
45
+ ### Fixed
46
+ - Dialog z-index
47
+
48
+ ## v0.1.2 - 2022-04-14
49
+
50
+ ### Added
51
+ - Dialogs support.
52
+
53
+ ## v0.1.1 - 2022-03-27
54
+
55
+ ### Added
56
+ - Part of BigPipe implementation for Webpack.
package/README.md CHANGED
@@ -58,7 +58,7 @@ export default class ServerJS extends ServerJSImpl {
58
58
  ```javascript
59
59
  import AsyncRequest from 'bigpipe-util/src/AsyncRequest';
60
60
 
61
- const request = AsyncRequest('/ajax/remove.php')
61
+ const request = (new AsyncRequest('/ajax/remove.php'))
62
62
  // or .setURI('/ajax/remove.php')
63
63
  .setMethod('POST')
64
64
  .setData({
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bigpipe-util",
3
3
  "description": "This library currently implements small part of Facebook BigPipe so far, but the advantage is to efficiently insert/replace content and work with the DOM. It is also possible to easily call JavaScript modules from PHP.",
4
- "version": "0.1.4",
4
+ "version": "0.2.2",
5
5
  "keywords": [
6
6
  "bigpipe",
7
7
  "xhr",
package/src/Primer.js CHANGED
@@ -19,6 +19,11 @@ export default function Primer() {
19
19
  let relationship = linkNodeOnClicked.rel && linkNodeOnClicked.rel.match(RELATIONSHIP_REGEX);
20
20
  relationship = relationship && relationship[0];
21
21
 
22
+ if (linkNodeOnClicked.classList.contains('async-saving')) {
23
+ event.preventDefault();
24
+ return;
25
+ }
26
+
22
27
  switch (relationship) {
23
28
  case "async":
24
29
  case "async-post":
@@ -26,6 +31,15 @@ export default function Primer() {
26
31
 
27
32
  (new AsyncRequest(linkNodeOnClicked.getAttribute("ajaxify")))
28
33
  .setRelative(linkNodeOnClicked)
34
+ .setInitialHandler(() => {
35
+ linkNodeOnClicked.classList.add("async-saving");
36
+ })
37
+ .setHandler(() => {
38
+ linkNodeOnClicked.classList.remove("async-saving");
39
+ })
40
+ .setErrorHandler(() => {
41
+ linkNodeOnClicked.classList.remove("async-saving");
42
+ })
29
43
  .setMethod(relationship === "async-post" ? "POST" : "GET")
30
44
  .send();
31
45
  break;
@@ -34,6 +48,15 @@ export default function Primer() {
34
48
 
35
49
  (new AsyncRequest(linkNodeOnClicked.getAttribute("ajaxify")))
36
50
  .setRelative(linkNodeOnClicked)
51
+ .setInitialHandler(() => {
52
+ linkNodeOnClicked.classList.add("async-saving");
53
+ })
54
+ .setHandler(() => {
55
+ linkNodeOnClicked.classList.remove("async-saving");
56
+ })
57
+ .setErrorHandler(() => {
58
+ linkNodeOnClicked.classList.remove("async-saving");
59
+ })
37
60
  .setMethod("POST")
38
61
  .send();
39
62
  break;
package/src/ServerJS.js CHANGED
@@ -21,7 +21,8 @@ export default class ServerJS {
21
21
  replaceTransportMarkers(this._relativeTo, marker);
22
22
  }
23
23
 
24
- const context = new (window.require(modulePath));
24
+ const factory = window.require(modulePath);
25
+ const context = typeof factory === 'function' ? new factory : factory;
25
26
 
26
27
  if (!context[method]) {
27
28
  throw new TypeError(`Module ${modulePath} has no method "${method}"`);
@@ -15,6 +15,11 @@ export default class AsyncDOM {
15
15
  node = (node || document.documentElement).querySelector(selector);
16
16
  }
17
17
 
18
+ if (!node) {
19
+ console.error(`Selector '${selector}' does not match anything!`)
20
+ continue;
21
+ }
22
+
18
23
  switch (type) {
19
24
  case "eval":
20
25
  (new Function(content)).apply(node);
@@ -121,6 +121,17 @@ AsyncRequest.prototype.abort = function () {
121
121
  }
122
122
  };
123
123
 
124
+ AsyncRequest.prototype._unshieldResponseText = function (text) {
125
+ const shield = "for (;;);";
126
+ const shieldLength = shield.length;
127
+
128
+ if (text.length <= shieldLength) {
129
+ throw new Error("Response too short on async to " + this.getURI());
130
+ }
131
+
132
+ return text.substring(shieldLength);
133
+ };
134
+
124
135
  AsyncRequest.prototype.send = function () {
125
136
  const {uri, method} = this;
126
137
  let { data } = this;
@@ -140,7 +151,8 @@ AsyncRequest.prototype.send = function () {
140
151
  if (this.status >= 200 && this.status < 400) {
141
152
  let response;
142
153
  try {
143
- response = eval("(" + this.responseText + ")");
154
+ const safeJson = self._unshieldResponseText(this.responseText);
155
+ response = eval("(" + safeJson + ")");
144
156
  } catch (e) {
145
157
  throw new Error("Failed to handle response: " + e.message + "\n" + this.responseText);
146
158
  }
@@ -3,11 +3,21 @@ import DOM from "./DOM";
3
3
 
4
4
  const DEFAULT_Z_INDEX = 1040;
5
5
 
6
- const stack = [];
6
+ let stack = [];
7
7
  let modalId = 1;
8
8
  let zIndex;
9
9
  let originalBodyPad = null;
10
10
 
11
+ Modal.prototype._handleKeydownEvent = function(e) {
12
+ if (e.which === 27 && this._options.keyboard) {
13
+ const currentModal = stack[stack.length - 1];
14
+ if (currentModal.el.isEqualNode(this.el)) {
15
+ this.emit('dismiss', this, e, null);
16
+ this.hide();
17
+ }
18
+ }
19
+ }
20
+
11
21
  export default class Dialog {
12
22
  close() {
13
23
  stack.forEach((dialog) => dialog.hide())
@@ -29,6 +39,7 @@ export default class Dialog {
29
39
  const _dialog = this._show({
30
40
  el: document.getElementById(this.id),
31
41
  animate: false,
42
+ keyboard: options.keyboard ?? true,
32
43
  backdrop: options.backdrop ?? true,
33
44
  transition: options.transition ?? 0,
34
45
  backdropTransition: options.backdropTransition ?? 0,
@@ -43,6 +54,7 @@ export default class Dialog {
43
54
  content: model.body,
44
55
  footer: model.footer || false,
45
56
  animate: false,
57
+ keyboard: model.keyboard ?? true,
46
58
  backdrop: model.backdrop ?? true,
47
59
  transition: model.transition ?? 0,
48
60
  backdropTransition: model.backdropTransition ?? 0,
@@ -69,7 +81,9 @@ export default class Dialog {
69
81
  el.style.zIndex = zIndex;
70
82
  setTimeout(() => document.querySelector('.modal-backdrop').style.zIndex = zIndex - 1);
71
83
  }).on('showBackdrop', this._fixBackdrop).on('hidden', function ({el}) {
72
- stack.pop();
84
+ stack = stack.filter((modal) => {
85
+ return ! modal.el.isEqualNode(el);
86
+ });
73
87
 
74
88
  if (stack.length) {
75
89
  document.body.classList.add('modal-open');
@@ -83,15 +97,17 @@ export default class Dialog {
83
97
  }).show();
84
98
  }
85
99
 
86
- _fixBackdrop(content) {
100
+ _fixBackdrop() {
87
101
  const backdrops = document.querySelectorAll('.modal-backdrop');
102
+ let shown = false;
88
103
 
89
104
  backdrops.forEach((backdrop, index) => {
90
- if (index > 0 && index === backdrops.length - 1) {
105
+ if (shown || index > 0 && index === backdrops.length - 1) {
91
106
  backdrop.style.display = 'none';
92
107
  } else {
93
108
  backdrop.style.zIndex = zIndex - 1;
94
109
  backdrop.style.display = '';
110
+ shown = true;
95
111
  }
96
112
  });
97
113
  }