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.
- package/LICENSE +0 -0
- package/action.js +14 -28
- package/actions/analytics/logEvent.js +2 -2
- package/actions/auth/restart.js +0 -0
- package/actions/auth/saveCsrfToken.js +0 -6
- package/actions/cables/push.js +3 -1
- package/actions/dialogs/oauth.js +0 -0
- package/actions/dialogs/options.js +0 -0
- package/actions/http/get.js +27 -15
- package/actions/panels/scrollTo.js +1 -1
- package/actions/panels/scrollToBottom.js +1 -1
- package/actions/windows/closeWithReload.js +1 -1
- package/actions/ws/push.js +2 -2
- package/app.vue +2 -3
- package/components/_message.vue +0 -0
- package/components/datetime.vue +0 -2
- package/components/fab.vue +0 -0
- package/components/fields/country/countries.js +0 -0
- package/components/fields/country/field.vue +0 -0
- package/components/fields/country/regions.js +0 -0
- package/components/fields/datetime.vue +0 -0
- package/components/fields/dynamicSelect.vue +0 -0
- package/components/fields/newRichText.vue +1 -1
- package/components/fields/timeZone.vue +0 -0
- package/components/fields/timer.vue +1 -2
- package/components/hr.vue +0 -0
- package/components/html.vue +0 -0
- package/components/label.vue +8 -4
- package/components/markdown.vue +1 -1
- package/components/mixins/generic.js +2 -2
- package/components/mixins/longClick.js +0 -0
- package/components/mixins/scrolling.js +0 -0
- package/components/mixins/styles.js +2 -2
- package/components/mixins/table/export.js +0 -0
- package/components/mixins/table/import.js +0 -0
- package/components/mixins/ws/actionCable.js +2 -2
- package/components/mixins/ws/phoenixSocket.js +6 -7
- package/components/p.vue +0 -0
- package/components/panels/horizontal.vue +1 -3
- package/components/panels/list.vue +24 -4
- package/components/panels/scroll.vue +0 -3
- package/components/panels/table.vue +0 -3
- package/keys.js +0 -0
- package/nav/dialog.vue +1 -2
- package/nav/drawerButton.vue +0 -0
- package/package.json +1 -1
- package/settings.json.example +0 -0
- package/styles/test.sass +0 -0
- package/styles/test.scss +0 -0
- package/templates/unsupported.vue +0 -0
- package/utils/dom.js +0 -0
- package/utils/history.js +1 -1
- package/utils/http.js +47 -8
- package/utils/private/ws.js +2 -2
- package/utils/public.js +0 -6
- package/utils/settings.js +8 -0
- package/utils/storage.js +0 -0
- package/utils/url.js +0 -0
- package/actions/commands/enqueue.js +0 -17
- 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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
17
|
+
console.debug(`Logging ${suffix}:`, properties.name, params);
|
|
18
18
|
firebase.analytics().logEvent(properties.name, params);
|
|
19
19
|
} else {
|
|
20
|
-
console.
|
|
20
|
+
console.debug("Waiting for firebase to be initialized...");
|
|
21
21
|
setTimeout(() => {
|
|
22
22
|
this.execute(properties);
|
|
23
23
|
}, 100);
|
package/actions/auth/restart.js
CHANGED
|
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
|
}
|
package/actions/cables/push.js
CHANGED
|
@@ -4,7 +4,9 @@ export default class {
|
|
|
4
4
|
const ws = window.vueApp.actionCable;
|
|
5
5
|
const channel = ws.channels[channelName];
|
|
6
6
|
|
|
7
|
-
|
|
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) {
|
package/actions/dialogs/oauth.js
CHANGED
|
File without changes
|
|
File without changes
|
package/actions/http/get.js
CHANGED
|
@@ -1,22 +1,34 @@
|
|
|
1
1
|
export default class {
|
|
2
|
-
execute(
|
|
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
|
-
|
|
7
|
-
Utils.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
16
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
package/actions/ws/push.js
CHANGED
|
@@ -13,14 +13,14 @@ export default class {
|
|
|
13
13
|
channel
|
|
14
14
|
.push(eventName, payload)
|
|
15
15
|
.receive("ok", resp => {
|
|
16
|
-
console.
|
|
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.
|
|
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.
|
|
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)
|
package/components/_message.vue
CHANGED
|
File without changes
|
package/components/datetime.vue
CHANGED
package/components/fab.vue
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.
|
|
113
|
+
console.debug(`Timer stopped: ${this.timer}`);
|
|
115
114
|
this.timer == null;
|
|
116
115
|
}
|
|
117
116
|
},
|
package/components/hr.vue
CHANGED
|
File without changes
|
package/components/html.vue
CHANGED
|
File without changes
|
package/components/label.vue
CHANGED
|
@@ -31,10 +31,14 @@ export default {
|
|
|
31
31
|
|
|
32
32
|
this.text = this.spec.text;
|
|
33
33
|
},
|
|
34
|
-
action_set(spec) {
|
|
35
|
-
|
|
36
|
-
|
|
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
|
};
|
package/components/markdown.vue
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
92
|
+
console.debug(`Channel joined '${topicName}'`, resp);
|
|
94
93
|
ws.channels[topicName] = channel;
|
|
95
94
|
})
|
|
96
95
|
.receive("error", resp => {
|
|
97
|
-
console.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
}
|
package/nav/drawerButton.vue
CHANGED
|
File without changes
|
package/package.json
CHANGED
package/settings.json.example
CHANGED
|
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
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
|
|
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.
|
|
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:
|
|
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
|
-
|
|
174
|
-
|
|
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
|
}
|
package/utils/private/ws.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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
|
-
// }
|