glib-web 2.6.4 → 2.6.6

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.
Files changed (60) hide show
  1. package/LICENSE +0 -0
  2. package/action.js +14 -28
  3. package/actions/analytics/logEvent.js +2 -2
  4. package/actions/auth/restart.js +0 -0
  5. package/actions/auth/saveCsrfToken.js +0 -6
  6. package/actions/cables/push.js +3 -1
  7. package/actions/dialogs/oauth.js +0 -0
  8. package/actions/dialogs/options.js +0 -0
  9. package/actions/http/get.js +27 -15
  10. package/actions/panels/scrollTo.js +1 -1
  11. package/actions/panels/scrollToBottom.js +1 -1
  12. package/actions/windows/closeWithReload.js +1 -1
  13. package/actions/ws/push.js +2 -2
  14. package/app.vue +2 -3
  15. package/components/_message.vue +0 -0
  16. package/components/datetime.vue +0 -2
  17. package/components/fab.vue +0 -0
  18. package/components/fields/country/countries.js +0 -0
  19. package/components/fields/country/field.vue +0 -0
  20. package/components/fields/country/regions.js +0 -0
  21. package/components/fields/datetime.vue +0 -0
  22. package/components/fields/dynamicSelect.vue +0 -0
  23. package/components/fields/newRichText.vue +1 -1
  24. package/components/fields/timeZone.vue +0 -0
  25. package/components/fields/timer.vue +1 -2
  26. package/components/hr.vue +0 -0
  27. package/components/html.vue +0 -0
  28. package/components/label.vue +8 -4
  29. package/components/markdown.vue +1 -1
  30. package/components/mixins/generic.js +2 -2
  31. package/components/mixins/longClick.js +0 -0
  32. package/components/mixins/scrolling.js +0 -0
  33. package/components/mixins/styles.js +2 -2
  34. package/components/mixins/table/export.js +0 -0
  35. package/components/mixins/table/import.js +0 -0
  36. package/components/mixins/ws/actionCable.js +2 -2
  37. package/components/mixins/ws/phoenixSocket.js +6 -7
  38. package/components/p.vue +0 -0
  39. package/components/panels/horizontal.vue +1 -3
  40. package/components/panels/list.vue +24 -4
  41. package/components/panels/scroll.vue +0 -3
  42. package/components/panels/table.vue +0 -3
  43. package/keys.js +0 -0
  44. package/nav/dialog.vue +1 -2
  45. package/nav/drawerButton.vue +0 -0
  46. package/package.json +1 -1
  47. package/settings.json.example +0 -0
  48. package/styles/test.sass +0 -0
  49. package/styles/test.scss +0 -0
  50. package/templates/unsupported.vue +0 -0
  51. package/utils/dom.js +0 -0
  52. package/utils/history.js +1 -1
  53. package/utils/http.js +47 -8
  54. package/utils/private/ws.js +2 -2
  55. package/utils/public.js +0 -6
  56. package/utils/settings.js +8 -0
  57. package/utils/storage.js +0 -0
  58. package/utils/url.js +0 -0
  59. package/actions/commands/enqueue.js +0 -17
  60. package/utils/queue.js +0 -104
package/LICENSE CHANGED
File without changes
package/action.js CHANGED
@@ -52,7 +52,6 @@ import ActionsAnalyticsLogEvent from "./actions/analytics/logEvent";
52
52
 
53
53
  import ActionCommandsCopy from "./actions/commands/copy";
54
54
  import ActionCommandsCustom from "./actions/commands/custom";
55
- import ActionCommandsEnqueue from "./actions/commands/enqueue";
56
55
 
57
56
  import ActionToursStart from "./actions/tours/start";
58
57
  import ActionToursStop from "./actions/tours/stop";
@@ -112,7 +111,6 @@ const actions = {
112
111
 
113
112
  "commands/copy": ActionCommandsCopy,
114
113
  "commands/custom": ActionCommandsCustom,
115
- "commands/enqueue": ActionCommandsEnqueue,
116
114
 
117
115
  "tours/start": ActionToursStart,
118
116
  "tours/stop": ActionToursStop,
@@ -126,43 +124,34 @@ export default class Action {
126
124
  if (!TypeUtils.isObject(spec)) {
127
125
  return;
128
126
  }
127
+ if (!TypeUtils.isObject(component)) {
128
+ console.warn("Action requires a component");
129
+ return;
130
+ }
129
131
 
130
132
  const name = spec.action;
131
133
  if (TypeUtils.isString(name)) {
132
134
  if (name.startsWith("component/")) {
133
- this.executeLocal(name, spec, component);
135
+ return this.executeLocal(name, spec, component);
134
136
  } else {
135
- this.executeGlobal(name, spec, component, params);
137
+ return this.executeGlobal(name, spec, component, params);
136
138
  }
137
-
138
- // const actionName = name.replace(/-v1$/, "");
139
-
140
- // try {
141
- // const action = new actions[actionName]();
142
- // const logDisabled = action.logDisabled && action.logDisabled();
143
- // if (!logDisabled) {
144
- // console.log(`Executing "${actionName}"`);
145
- // }
146
- // action.execute(spec, null, component, params);
147
- // } catch (e) {
148
- // console.log(`Failed executing command: "${e.message}"`);
149
- // }
150
139
  } else {
151
- console.log(`Invalid action: "${name}"`);
140
+ console.warn(`Invalid action: "${name}"`);
152
141
  }
153
142
  }
154
143
 
155
144
  static executeLocal(name, spec, component) {
156
145
  const methodName = name.replace(/^component\//, "");
157
146
  const componentName = GLib.component.vueName(component);
158
- console.log(
147
+ console.debug(
159
148
  `Executing component action on ${componentName}: ${methodName}`
160
149
  );
161
150
  component[`action_${methodName}`](spec);
162
151
  }
163
152
 
164
153
  static executeGlobal(name, spec, component, params) {
165
- this._executeInternal(name, spec, component, params, actions);
154
+ return this._executeInternal(name, spec, component, params, actions);
166
155
  }
167
156
 
168
157
  static _executeInternal(name, spec, component, params, registry) {
@@ -172,15 +161,12 @@ export default class Action {
172
161
  const action = new registry[actionName]();
173
162
  const logDisabled = action.logDisabled && action.logDisabled();
174
163
  if (!logDisabled) {
175
- console.log(`Executing "${actionName}"`);
164
+ console.debug(`Executing "${actionName}"`);
176
165
  }
177
- action.execute(spec, component, params);
166
+ return action.execute(spec, component, params);
178
167
  } catch (e) {
179
- GLib.settings.errorHandler(
180
- new Error(
181
- `Failed executing command "${actionName}". Error: ${e.message}`
182
- )
183
- );
168
+ GLib.settings.errorHandler(e);
169
+ return null;
184
170
  }
185
171
  }
186
172
 
@@ -206,7 +192,7 @@ export default class Action {
206
192
  }
207
193
 
208
194
  static executeCustom(name, spec, component, params) {
209
- this._executeInternal(name, spec, component, params, customActions);
195
+ return this._executeInternal(name, spec, component, params, customActions);
210
196
  }
211
197
  }
212
198
 
@@ -14,10 +14,10 @@ export default class {
14
14
  const suffix = params.referer_group ? "w/ referer" : "w/o referer";
15
15
  params.build_env = Utils.settings.env;
16
16
  // params.build_version = Utils.settings.appVersion;
17
- console.log(`Logging ${suffix}:`, properties.name, params);
17
+ console.debug(`Logging ${suffix}:`, properties.name, params);
18
18
  firebase.analytics().logEvent(properties.name, params);
19
19
  } else {
20
- console.log("Waiting for firebase to be initialized...");
20
+ console.debug("Waiting for firebase to be initialized...");
21
21
  setTimeout(() => {
22
22
  this.execute(properties);
23
23
  }, 100);
File without changes
@@ -1,11 +1,5 @@
1
- // import Storage from '../../utils/storage'
2
- // import Keys from '../../keys'
3
-
4
1
  export default class {
5
2
  execute(properties, component) {
6
- // console.log(properties['token'])
7
- // Storage.setLocal(Keys.Db.csrfToken, properties['token'])
8
-
9
3
  Utils.dom.setCsrf(properties["token"]);
10
4
  Action.execute(properties["onSave"], component);
11
5
  }
@@ -4,7 +4,9 @@ export default class {
4
4
  const ws = window.vueApp.actionCable;
5
5
  const channel = ws.channels[channelName];
6
6
 
7
- console.log("Pushing to", channel);
7
+ // TODO: Use logDisabled() that reads params from server to decide whether we want to print the log or not.
8
+ // This is because `push` action's logs are a bit sensitive.
9
+ console.debug("Pushing to", channel);
8
10
 
9
11
  Utils.type.ifString(properties.event, eventName => {
10
12
  if (channel) {
File without changes
File without changes
@@ -1,22 +1,34 @@
1
1
  export default class {
2
- execute(properties, controller) {
2
+ execute(spec, component) {
3
+ return new Promise(resolve => {
4
+ GLib.http.execute(
5
+ spec,
6
+ "GET",
7
+ component,
8
+ (page, response) => {
9
+ this.handleSuccess(page, spec, component);
10
+ resolve({ page: page, response: response });
11
+ },
12
+ (error, response) => {
13
+ resolve({ error: error, response: response });
14
+ }
15
+ );
16
+ });
17
+ }
18
+
19
+ handleSuccess(page, spec, component) {
3
20
  const currentUrl = window.location.href;
4
- // const htmlUrl = Utils.url.htmlUrl(properties["url"]);
5
21
 
6
- GLib.http.execute(properties, "GET", controller, (page, response) => {
7
- Utils.type.ifString(properties.historyUrl, historyUrl => {
8
- const cleanUrl = Utils.url.htmlUrl(historyUrl);
9
- if (cleanUrl !== currentUrl) {
10
- console.log("URL", cleanUrl, response.url, response);
11
- const data = Object.assign({}, window.vueApp.page, {
12
- replayGetResponse: page.onResponse
13
- });
22
+ Utils.type.ifString(spec.historyUrl, historyUrl => {
23
+ const cleanUrl = Utils.url.htmlUrl(historyUrl);
24
+ if (cleanUrl !== currentUrl) {
25
+ const data = Object.assign({}, window.vueApp.page, {
26
+ replayGetResponse: page.onResponse
27
+ });
14
28
 
15
- // Utils.history.pushPage(data, historyUrl);
16
- Utils.history.pushPage(data, cleanUrl);
17
- }
18
- });
19
- GLib.action.handleResponse(page, controller);
29
+ Utils.history.pushPage(data, cleanUrl);
30
+ }
20
31
  });
32
+ GLib.action.handleResponse(page, component);
21
33
  }
22
34
  }
@@ -5,7 +5,7 @@ export default class {
5
5
  Utils.launch.dialog.closestBody(component) || Utils.history._pageBody;
6
6
 
7
7
  const selector = `#${properties.viewId}`;
8
- console.log("Scrolling to", selector);
8
+ console.debug("Scrolling to", selector);
9
9
  const element = pageBody.querySelector(selector);
10
10
  element.scrollIntoView({
11
11
  behavior: properties["animate"] ? "smooth" : "auto"
@@ -4,7 +4,7 @@ export default class {
4
4
  // TODO: make this support any panelId
5
5
  const target = properties.panelId ? `_innerBody` : "_pageBody";
6
6
  const pageBody = Utils.history[target];
7
- console.log(`Scrolling ${target} to bottom`);
7
+ console.debug(`Scrolling ${target} to bottom`);
8
8
  pageBody.scrollTo({
9
9
  top: pageBody.scrollHeight,
10
10
  behavior: properties["animate"] ? "smooth" : "auto"
@@ -6,7 +6,7 @@ export default class {
6
6
  const data = Object.assign({}, properties);
7
7
  if (!Utils.history.back()) {
8
8
  data.url = fallbackUrl;
9
- console.log("Use fallbackUrl", data.url);
9
+ console.debug("Use fallbackUrl", data.url);
10
10
  }
11
11
 
12
12
  // Allow time for history.back() to complete, which is important for actions that need
@@ -13,14 +13,14 @@ export default class {
13
13
  channel
14
14
  .push(eventName, payload)
15
15
  .receive("ok", resp => {
16
- console.log(
16
+ console.debug(
17
17
  `Push to '${topicName}/${eventName}' succeeded`,
18
18
  resp
19
19
  );
20
20
  Utils.ws.handleResponse(resp.onResponse, component);
21
21
  })
22
22
  .receive("error", resp => {
23
- console.log(`Push to '${topicName}/${eventName}' failed`, resp);
23
+ console.debug(`Push to '${topicName}/${eventName}' failed`, resp);
24
24
  Utils.ws.handleResponse(resp.onResponse, component);
25
25
  });
26
26
  } else {
package/app.vue CHANGED
@@ -91,7 +91,7 @@ export default {
91
91
  }
92
92
  },
93
93
  created() {
94
- console.log(
94
+ console.debug(
95
95
  `Version: ${Utils.settings.appVersion} (${Utils.settings.env})`
96
96
  );
97
97
  Utils.history.saveInitialContent(this.page);
@@ -145,7 +145,6 @@ export default {
145
145
  });
146
146
  },
147
147
  updateMainHeight() {
148
- console.debug("Setting body height");
149
148
  this.mainHeight = window.innerHeight - this.$refs.appBar.$el.offsetHeight;
150
149
  }
151
150
  }
@@ -196,7 +195,7 @@ body,
196
195
  background: yellow !important;
197
196
  }
198
197
  // Don't override the default button's effect.
199
- .glib-clickable:not(.v-btn) {
198
+ .glib-clickable:not(.v-btn):not(.disabled) {
200
199
  cursor: pointer;
201
200
 
202
201
  // // So that we can display a semi-transparent layer on hover (see below)
File without changes
@@ -34,10 +34,8 @@ export default {
34
34
  }
35
35
  },
36
36
  $tearDown() {
37
- console.log("TimeTicker destroyed");
38
37
  if (this.timer != null) {
39
38
  clearInterval(this.timer);
40
- console.log(`Timer stopped: ${this.timer}`);
41
39
  }
42
40
  },
43
41
  tick() {
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -147,7 +147,7 @@ export default {
147
147
  upload.start((error, blob) => {
148
148
  if (error) {
149
149
  // Handle the error
150
- console.log("Failed uploading image!");
150
+ console.warn("Failed uploading image!");
151
151
  } else {
152
152
  this.insertImage(file, blob, onComplete);
153
153
  }
File without changes
@@ -108,10 +108,9 @@ export default {
108
108
  }
109
109
  },
110
110
  $tearDown() {
111
- console.log("Cleaning up timer...");
112
111
  if (this.timer != null) {
113
112
  clearInterval(this.timer);
114
- console.log(`Timer stopped: ${this.timer}`);
113
+ console.debug(`Timer stopped: ${this.timer}`);
115
114
  this.timer == null;
116
115
  }
117
116
  },
package/components/hr.vue CHANGED
File without changes
File without changes
@@ -31,10 +31,14 @@ export default {
31
31
 
32
32
  this.text = this.spec.text;
33
33
  },
34
- action_set(spec) {
35
- if (spec.user_id !== spec.filterKey) {
36
- this.text = spec.text;
37
- }
34
+ // action_set(spec) {
35
+ // if (spec.user_id !== spec.filterKey) {
36
+ // this.text = spec.text;
37
+ // }
38
+ // },
39
+ action_merge(mergedSpec) {
40
+ Object.assign(this.spec, mergedSpec);
41
+ this.$ready();
38
42
  }
39
43
  }
40
44
  };
@@ -30,7 +30,7 @@ export default {
30
30
  $ready() {
31
31
  if (this.spec.previewVideo) {
32
32
  this.youtubeId = this.extractYoutubeId(this.spec.text);
33
- console.log("Detected Youtube ID", this.youtubeId);
33
+ console.debug("Detected Youtube ID", this.youtubeId);
34
34
  }
35
35
  // Set all links to be openWeb or open in a new tab by default
36
36
  if (!this.spec.openWeb) {
@@ -54,7 +54,7 @@ export default {
54
54
  const channel = ws.channels[topicName];
55
55
 
56
56
  if (!channel) {
57
- console.log(`Topic not ready: '${topicName}'`);
57
+ console.debug(`Topic not ready: '${topicName}'`);
58
58
  setTimeout(() => {
59
59
  // Wait until $wsInitPhoenixSocket() has executed.
60
60
  this.$wsSubscribeEvents(spec);
@@ -63,7 +63,7 @@ export default {
63
63
  }
64
64
 
65
65
  for (const eventName of events) {
66
- console.log(`Registering event '${eventName}'`);
66
+ console.debug(`Registering event '${eventName}'`);
67
67
  channel.on(eventName, payload => {
68
68
  console.debug(`Received '${eventName}' event`, payload);
69
69
  Utils.ws.handleResponse(payload.onResponse, this);
File without changes
File without changes
@@ -65,12 +65,12 @@ export default {
65
65
  const topDialog = Utils.launch.dialog.topDialog();
66
66
  if (topDialog) {
67
67
  if (!topDialog.isFormDirty) {
68
- console.log("Dialog form is now dirty");
68
+ console.debug("Dialog form is now dirty");
69
69
  topDialog.isFormDirty = true;
70
70
  }
71
71
  } else {
72
72
  if (!window.vueApp.isFormDirty) {
73
- console.log("Window form is now dirty");
73
+ console.debug("Window form is now dirty");
74
74
  window.vueApp.isFormDirty = true;
75
75
  }
76
76
  }
File without changes
File without changes
@@ -19,13 +19,13 @@ export default {
19
19
  channel: channelName
20
20
  });
21
21
 
22
- console.log("Connecting to channel", subscription);
22
+ console.debug("Connecting to channel", subscription);
23
23
 
24
24
  consumer.subscriptions.create(subscription, {
25
25
  connected() {
26
26
  const ws = window.vueApp.actionCable;
27
27
  ws.channels[channelName] = this;
28
- console.log("Connected to channel", channelName);
28
+ console.debug("Connected to channel", channelName);
29
29
  },
30
30
 
31
31
  disconnected() {},
@@ -12,7 +12,6 @@ export default {
12
12
  Utils.type.ifObject(
13
13
  spec,
14
14
  ws => {
15
- console.log("Connecting socket...");
16
15
  Utils.launch.snackbar.indicator("Connecting...");
17
16
  Utils.http.startIndicator(this);
18
17
 
@@ -54,14 +53,14 @@ export default {
54
53
 
55
54
  this._wsSocket = socket;
56
55
  socket.onOpen(() => {
57
- console.log("Connected socket");
56
+ console.debug("Connected socket");
58
57
  this._wsJoinChannel(socket, spec);
59
58
  Utils.http.stopIndicator(this);
60
59
  });
61
60
  socket.onError(() => {
62
61
  // Start the indicator again because this can trigger even after successfully connected.
63
62
  Utils.http.startIndicator(this);
64
- console.log("Unable to connect socket");
63
+ console.debug("Unable to connect socket");
65
64
  });
66
65
  socket.connect();
67
66
  },
@@ -80,7 +79,7 @@ export default {
80
79
  const channel = socket.channel(topicName, {});
81
80
 
82
81
  for (const eventName of events) {
83
- console.log(`Registering event '${eventName}'`);
82
+ console.debug(`Registering event '${eventName}'`);
84
83
  channel.on(eventName, payload => {
85
84
  console.debug(`Received '${eventName}' event`, payload);
86
85
  Utils.ws.handleResponse(payload.onResponse, this);
@@ -90,11 +89,11 @@ export default {
90
89
  channel
91
90
  .join()
92
91
  .receive("ok", resp => {
93
- console.log(`Channel joined '${topicName}'`, resp);
92
+ console.debug(`Channel joined '${topicName}'`, resp);
94
93
  ws.channels[topicName] = channel;
95
94
  })
96
95
  .receive("error", resp => {
97
- console.log(`Unable to join channel '${topicName}'`, resp);
96
+ console.debug(`Unable to join channel '${topicName}'`, resp);
98
97
  Utils.launch.snackbar.error(
99
98
  "Unable to connect. Please try again.",
100
99
  this
@@ -103,7 +102,7 @@ export default {
103
102
  },
104
103
  _wsDisconnectSocket() {
105
104
  if (this._wsSocket) {
106
- console.log("Disconnecting socket");
105
+ console.debug("Disconnecting socket");
107
106
  // Sometimes this doesn't prevent errorneous socket from trying to reconnect. In this case,
108
107
  // the socket will keep attempting to connect.
109
108
  this._wsSocket.disconnect();
package/components/p.vue CHANGED
File without changes
@@ -29,11 +29,9 @@
29
29
  >
30
30
  <!-- Using `item.id` as key is important to make sure the item gets updated
31
31
  when dragging ends. -->
32
- <!-- Use `display: contents` so this div doesn't intefere with the child's sizing behaviour. -->
33
32
  <div
34
33
  v-for="(item, index) in childViews"
35
34
  :key="item.id || index"
36
- style="display: contents;"
37
35
  :data-dragItemId="item.id"
38
36
  >
39
37
  <glib-component :spec="item" />
@@ -133,7 +131,7 @@ export default {
133
131
 
134
132
  const targetRowIndex = event.newIndex;
135
133
  if (event.from == event.to && event.oldIndex == targetRowIndex) {
136
- console.log("Reordering canceled");
134
+ console.debug("Reordering canceled");
137
135
  return;
138
136
  }
139
137
 
@@ -22,9 +22,10 @@
22
22
  >
23
23
  <div
24
24
  v-for="(row, rowIndex) in section.rows"
25
- :key="`${sectionIndex}_${rowIndex}`"
25
+ :key="row.id || `${sectionIndex}_${rowIndex}`"
26
26
  :ref="`row_${sectionIndex}_${rowIndex}`"
27
27
  :data-dragRowId="row.id"
28
+ class="row_container"
28
29
  >
29
30
  <!-- <v-divider v-if="!spec.responsiveCols && rowIndex == 0" /> -->
30
31
 
@@ -109,7 +110,6 @@ export default {
109
110
  return row;
110
111
  },
111
112
  action_loadNext(spec) {
112
- console.log("TODO: load new comments and append to this list", spec);
113
113
  // TODO
114
114
  // - Load next rows/items from the Rails server
115
115
  // - You can pass some parameters (e.g. currentItemId) for pagination
@@ -197,7 +197,7 @@ export default {
197
197
  const targetSectionedRowIndex = event.newIndex;
198
198
  // const sourceSectionedRowIndex = event.oldIndex;
199
199
  if (event.from == event.to && event.oldIndex == targetSectionedRowIndex) {
200
- console.log("Reordering canceled");
200
+ console.debug("Reordering canceled");
201
201
  return;
202
202
  }
203
203
 
@@ -205,7 +205,6 @@ export default {
205
205
  this.$recursiveUpdate();
206
206
 
207
207
  const targetSectionIndex = this.getSectionIndex(event.to);
208
- // const targetSection = this.getSection(targetSectionIndex);
209
208
 
210
209
  const targetAbsoluteIndex =
211
210
  this.previousSectionsRowCount(event.to) + targetSectionedRowIndex;
@@ -230,6 +229,27 @@ export default {
230
229
  });
231
230
 
232
231
  GLib.action.execute(mergedSpec, this);
232
+
233
+ this.hackLingeringHighlight();
234
+ },
235
+ hackLingeringHighlight() {
236
+ // After a row finished dragging, the row below it will automatically be
237
+ // "active&hover" for some reason, which will cause it to be incorrectly
238
+ // highlighted
239
+ // This seems to be a browser/library bug, so as a workaround, we temporarily
240
+ // apply the "disabled" class so the highlighting doesn't happen.
241
+ this.$el
242
+ .querySelectorAll(":active .row_container > .glib-clickable:hover")
243
+ .forEach(activeRow => {
244
+ activeRow.classList.add("disabled");
245
+ document.addEventListener(
246
+ "mousemove",
247
+ function() {
248
+ activeRow.classList.remove("disabled");
249
+ },
250
+ { once: true }
251
+ );
252
+ });
233
253
  },
234
254
  getSectionIndex(element) {
235
255
  return element.dataset.dragsectionindex;
@@ -23,7 +23,6 @@ export default {
23
23
  // // Let the styles be handled by the child panel.
24
24
  // const outerSpec = {};
25
25
  // outerSpec["padding"] = this.spec["outerPadding"];
26
- // console.log("outerSpec", outerSpec);
27
26
  // const styles = this.$styles(outerSpec);
28
27
  //
29
28
  // const styles = this.genericStyles();
@@ -36,8 +35,6 @@ export default {
36
35
  // width: this.spec.width,
37
36
  // height: this.spec.height
38
37
  // });
39
- //
40
- // console.log("styles", styles);
41
38
 
42
39
  // Let the specified styles be handled by the child panel.
43
40
  const styles = this.$styles({
@@ -139,9 +139,6 @@ export default {
139
139
  // const createdAt = row[5]
140
140
  // const activationState = row[14] ? 'active' : 'pending'
141
141
  // count += 1
142
- // if (email.includes("'")) {
143
- // console.log("INVALID NAME", name)
144
- // }
145
142
  // str += `{ name: "${name}".to_s, email: '${email}'.to_s, created_at: '${createdAt}', activation_state: '${activationState}'},\n`
146
143
  // }
147
144
  // }
package/keys.js CHANGED
File without changes
package/nav/dialog.vue CHANGED
@@ -134,7 +134,7 @@ export default {
134
134
  });
135
135
  },
136
136
  $tearDown() {
137
- console.log("Dialog destroyed");
137
+ console.debug("Dialog destroyed");
138
138
  this.stack.remove(this);
139
139
  },
140
140
  close() {
@@ -192,7 +192,6 @@ export default {
192
192
  this.model = true;
193
193
  },
194
194
  updateMainHeight() {
195
- console.debug("Setting body height");
196
195
  this.mainHeight = window.innerHeight - 140;
197
196
  }
198
197
  }
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glib-web",
3
- "version": "2.6.4",
3
+ "version": "2.6.6",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
File without changes
package/styles/test.sass CHANGED
File without changes
package/styles/test.scss CHANGED
File without changes
File without changes
package/utils/dom.js CHANGED
File without changes
package/utils/history.js CHANGED
@@ -77,7 +77,7 @@ export default class {
77
77
  window.history.back();
78
78
  return true;
79
79
  } else {
80
- console.log("Reached beginning of navigation stack");
80
+ console.debug("Reached beginning of navigation stack");
81
81
  return false;
82
82
  }
83
83
  }
package/utils/http.js CHANGED
@@ -31,7 +31,8 @@ export default class {
31
31
  const formData = new FormData();
32
32
  var params = data || {};
33
33
  for (const key in params) {
34
- formData.append(key, params[key]);
34
+ // formData.append(key, params[key]);
35
+ this._populateFormData(formData, key, params[key]);
35
36
  }
36
37
 
37
38
  if (needCsrfToken && !Type.isString(params["authenticity_token"])) {
@@ -40,8 +41,33 @@ export default class {
40
41
  return formData;
41
42
  }
42
43
 
44
+ static _populateFormData(formData, key, value) {
45
+ if (GLib.type.isArray(value)) {
46
+ for (const item of value) {
47
+ this._populateFormData(formData, `${key}[]`, item);
48
+ }
49
+ } else if (GLib.type.isObject(value)) {
50
+ for (const innerKey in value) {
51
+ this._populateFormData(
52
+ formData,
53
+ `${key}[${innerKey}]`,
54
+ value[innerKey]
55
+ );
56
+ }
57
+ } else {
58
+ formData.append(key, value);
59
+ }
60
+ }
61
+
43
62
  static load(properties, component) {
44
- const url = new URL(properties["url"]);
63
+ const urlString = properties["url"];
64
+ let url;
65
+ try {
66
+ url = new URL(urlString);
67
+ } catch (e) {
68
+ console.warn("Invalid URL", urlString);
69
+ throw e;
70
+ }
45
71
  const domainMatched = window.location.hostname == url.hostname;
46
72
 
47
73
  // If this is an external domain, we rely on `onUnload()` instead.
@@ -123,7 +149,7 @@ export default class {
123
149
  });
124
150
  }
125
151
 
126
- static execute(properties, methodName, component, jsonHandler) {
152
+ static execute(properties, methodName, component, jsonHandler, errorHandler) {
127
153
  this.startIndicator(component);
128
154
 
129
155
  // `fetch()` only supports uppercase
@@ -134,18 +160,23 @@ export default class {
134
160
  url = Utils.url.appendParams(url, body);
135
161
  body = null;
136
162
  }
137
- console.log(`${method} ${url}`);
163
+ console.debug(`${method} ${url}`);
138
164
 
139
165
  const request = new HttpRequest();
140
166
  let response = null;
141
167
  const vm = this;
142
168
 
143
169
  const analyticsHeaders = this.analyticsHeaders(component);
170
+ const headers = Object.assign(
171
+ { Accept: "text/html" },
172
+ analyticsHeaders,
173
+ GLib.settings.headerAugmenter(url, method)
174
+ );
144
175
 
145
176
  fetch(url, {
146
177
  method: method,
147
178
  body: body,
148
- headers: Object.assign({ Accept: "text/html" }, analyticsHeaders),
179
+ headers: headers,
149
180
  // Make sure to pass cookies for same origin URLs.
150
181
  // Needed for some browsers, e.g. Edge and Android's native.
151
182
  credentials: "same-origin",
@@ -154,12 +185,12 @@ export default class {
154
185
  .then(res => {
155
186
  vm.stopIndicator(component);
156
187
 
188
+ response = res;
157
189
  if (res.status >= 500) {
158
190
  throw "Server error";
159
191
  } else if (res.status >= 400) {
160
192
  throw "Not accessible";
161
193
  } else {
162
- response = res;
163
194
  return res.json();
164
195
  }
165
196
  })
@@ -169,9 +200,17 @@ export default class {
169
200
  })
170
201
  .catch(error => {
171
202
  vm.stopIndicator(component);
203
+
172
204
  if (!request.canceled) {
173
- console.error("Error:", error);
174
- Utils.launch.snackbar.error(error, component);
205
+ const message = error.toString();
206
+
207
+ console.error("Error:", message);
208
+
209
+ if (errorHandler) {
210
+ errorHandler(error, response);
211
+ } else {
212
+ Utils.launch.snackbar.error(message, component);
213
+ }
175
214
  } else {
176
215
  console.info("Canceled");
177
216
  }
@@ -7,13 +7,13 @@ export default class {
7
7
  const ws = window.vueApp.webSocket;
8
8
  Utils.type.ifObject(payload.wsHeader, header => {
9
9
  Object.assign(ws.header, header);
10
- console.log("New header: ", ws.header);
10
+ console.debug("New header: ", ws.header);
11
11
  });
12
12
 
13
13
  const actionName = payload.action;
14
14
  if (actionName.startsWith("component/")) {
15
15
  const methodName = actionName.replace(/^component\//, "");
16
- console.log(`Executing component action: ${methodName}`);
16
+ console.debug(`Executing component action: ${methodName}`);
17
17
  component[`action_${methodName}`](payload);
18
18
  } else {
19
19
  GLib.action.execute(payload, component);
package/utils/public.js CHANGED
@@ -5,11 +5,8 @@ import Type from "./type";
5
5
  import Form from "./form";
6
6
  import Component from "./component";
7
7
  import Hash from "./hash";
8
- import Queue from "./queue";
9
8
  import Settings from "./settings";
10
9
 
11
- const _queue = new Queue();
12
-
13
10
  export default class {
14
11
  static get action() {
15
12
  return Action;
@@ -35,7 +32,4 @@ export default class {
35
32
  static get settings() {
36
33
  return Settings;
37
34
  }
38
- static get queue() {
39
- return _queue;
40
- }
41
35
  }
package/utils/settings.js CHANGED
@@ -6,6 +6,10 @@ class MutableSettings {
6
6
  this.errorHandler = err => {
7
7
  console.error(err.message);
8
8
  };
9
+ this.headerAugmenter = (_url, _method) => {
10
+ // Set a custom augmenter to add custom HTTP headers.
11
+ return {};
12
+ };
9
13
  }
10
14
  }
11
15
  const settings = new MutableSettings();
@@ -24,6 +28,10 @@ export default class ImmutableSettings {
24
28
  return settings.errorHandler;
25
29
  }
26
30
 
31
+ static get headerAugmenter() {
32
+ return settings.headerAugmenter;
33
+ }
34
+
27
35
  static get env() {
28
36
  return process.env.NODE_ENV;
29
37
  }
package/utils/storage.js CHANGED
File without changes
package/utils/url.js CHANGED
File without changes
@@ -1,17 +0,0 @@
1
- // import Hash from "../../utils/hash";
2
-
3
- export default class {
4
- // async executeJob(spec, component) {
5
- // console.log("Waiting for next job1...");
6
- // GLib.action.execute(spec.onExecute, component);
7
- // await this.sleep(2000);
8
- // console.log("Waiting for next job2...");
9
- // }
10
- execute(spec, component) {
11
- GLib.queue.enqueue(() => {
12
- GLib.action.execute(spec.onExecute, component);
13
- // console.log("Waiting for next job0...");
14
- // this.executeJob(spec, component);
15
- });
16
- }
17
- }
package/utils/queue.js DELETED
@@ -1,104 +0,0 @@
1
- // From https://stackoverflow.com/questions/47157428/how-to-implement-a-pseudo-blocking-async-queue-in-js-ts
2
-
3
- import Vue from "vue";
4
-
5
- // const jobQueue = [];
6
- export default class {
7
- constructor() {
8
- // invariant: at least one of the arrays is empty
9
- this.resolvers = [];
10
- this.promises = [];
11
- }
12
- _add() {
13
- this.promises.push(
14
- new Promise(resolve => {
15
- this.resolvers.push(resolve);
16
- })
17
- );
18
- }
19
- enqueue(t) {
20
- // if (this.resolvers.length) this.resolvers.shift()(t);
21
- // else this.promises.push(Promise.resolve(t));
22
- if (!this.resolvers.length) this._add();
23
- this.resolvers.shift()(t);
24
- }
25
- dequeue() {
26
- if (!this.promises.length) this._add();
27
- return this.promises.shift();
28
- }
29
- // now some utilities:
30
- isEmpty() {
31
- // there are no values available
32
- return !this.promises.length; // this.length <= 0
33
- }
34
- isBlocked() {
35
- // it's waiting for values
36
- return !!this.resolvers.length; // this.length < 0
37
- }
38
- get length() {
39
- return this.promises.length - this.resolvers.length;
40
- }
41
- sleep(ms) {
42
- return new Promise(resolve => setTimeout(resolve, ms));
43
- }
44
- async start() {
45
- // TODO: This is experimental
46
- const delayBetweenJobs = 2000;
47
-
48
- for await (const job of this) {
49
- console.log("Executing job...");
50
- job();
51
- if (delayBetweenJobs) {
52
- console.log("Waiting for next job1...");
53
- await this.sleep(delayBetweenJobs);
54
- console.log("Waiting for next job2...");
55
- }
56
- }
57
- }
58
- [Symbol.asyncIterator]() {
59
- // Todo: Use AsyncIterator.from()
60
- return {
61
- next: () => this.dequeue().then(value => ({ done: false, value })),
62
- [Symbol.asyncIterator]() {
63
- return this;
64
- }
65
- };
66
- }
67
- }
68
-
69
- // export default class {
70
- // constructor() {
71
- // this.jobQueue = [];
72
- // this.timerHandle = null;
73
- // }
74
- // // static get csrfElement() {
75
- // // return document.querySelector(`meta[name="csrf-token"]`);
76
- // // }
77
-
78
- // // static getCsrf() {
79
- // // return this.csrfElement.getAttribute("content");
80
- // // }
81
-
82
- // // static setCsrf(value) {
83
- // // return this.csrfElement.setAttribute("content", value);
84
- // // }
85
-
86
- // start(interval) {
87
- // this.timerHandle = setInterval(() => {
88
- // console.log("DEQUQE1");
89
- // const oldestJob = this.jobQueue.shift();
90
- // if (oldestJob) {
91
- // console.log("DEQUQE2");
92
- // oldestJob();
93
- // }
94
- // }, interval);
95
- // }
96
-
97
- // stop() {
98
- // clearInterval(this.timerHandle);
99
- // }
100
-
101
- // enqueue(job) {
102
- // this.jobQueue.push(job);
103
- // }
104
- // }