glib-web 2.6.0 → 2.6.1

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/action.js CHANGED
@@ -53,6 +53,7 @@ import ActionCommandsCustom from "./actions/commands/custom";
53
53
  import ActionCommandsEnqueue from "./actions/commands/enqueue";
54
54
 
55
55
  import ActionToursStart from "./actions/tours/start";
56
+ import ActionToursStop from "./actions/tours/stop";
56
57
 
57
58
  import ActionComponentsUpdate from "./actions/components/update";
58
59
 
@@ -110,6 +111,7 @@ const actions = {
110
111
  "commands/enqueue": ActionCommandsEnqueue,
111
112
 
112
113
  "tours/start": ActionToursStart,
114
+ "tours/stop": ActionToursStop,
113
115
  "components/update": ActionComponentsUpdate
114
116
  };
115
117
 
@@ -170,10 +172,10 @@ export default class Action {
170
172
  }
171
173
  action.execute(spec, component, params);
172
174
  } catch (e) {
173
- console.error(
174
- "Failed executing command",
175
- actionName,
176
- `Error: '${e.message}'`
175
+ GLib.settings.errorHandler(
176
+ new Error(
177
+ `Failed executing command "${actionName}". Error: ${e.message}`
178
+ )
177
179
  );
178
180
  }
179
181
  }
@@ -1,7 +1,9 @@
1
1
  // Scroll the main body of the current window
2
2
  export default class {
3
- execute(properties) {
4
- const pageBody = Utils.history._pageBody;
3
+ execute(properties, component) {
4
+ const pageBody =
5
+ Utils.launch.dialog.closestBody(component) || Utils.history._pageBody;
6
+
5
7
  const selector = `#${properties.viewId}`;
6
8
  console.log("Scrolling to", selector);
7
9
  const element = pageBody.querySelector(selector);
@@ -1,9 +1,11 @@
1
1
  import Driver from "driver.js";
2
2
  import "driver.js/dist/driver.min.css";
3
3
 
4
+ let driver = null;
5
+
4
6
  export default class {
5
7
  execute(spec, component) {
6
- let driver = new Driver(spec.options || {});
8
+ driver = new Driver(spec.options || {});
7
9
  let steps = spec.steps;
8
10
  steps
9
11
  .filter(value => value.customBehavior)
@@ -14,4 +16,11 @@ export default class {
14
16
  driver.defineSteps(steps);
15
17
  driver.start(spec.startFrom || 0);
16
18
  }
19
+
20
+ static stopTour() {
21
+ if (driver) {
22
+ driver.reset();
23
+ driver = null;
24
+ }
25
+ }
17
26
  }
@@ -0,0 +1,7 @@
1
+ import tour from "./start.js";
2
+
3
+ export default class {
4
+ execute(spec, component) {
5
+ tour.stopTour();
6
+ }
7
+ }
@@ -58,11 +58,7 @@ export default {
58
58
  );
59
59
  }, 100);
60
60
 
61
- Utils.type.ifObject(this.spec.onChange, onChange => {
62
- this.$nextTick(() => {
63
- GLib.action.execute(onChange, this);
64
- });
65
- });
61
+ this.$executeOnChange();
66
62
  },
67
63
  $internalizeValue(val) {
68
64
  if (val == this.spec.checkValue) {
@@ -2,14 +2,28 @@
2
2
  <div ref="fileUploadContainer" class="mb-3" :style="$styles()">
3
3
  <label class="v-label v-label--active">{{ spec.label }}</label>
4
4
  <div class="preview-container">
5
- <v-avatar v-if="placeholder.type == 'avatar'" :style="genericStyles(placeholder)" class="mr-4">
5
+ <v-avatar
6
+ v-if="placeholder.type == 'avatar'"
7
+ :style="genericStyles(placeholder)"
8
+ class="mr-4"
9
+ >
6
10
  <img :src="fileImage || placeholder.url" />
7
11
  </v-avatar>
8
- <img v-else-if="placeholder.type == 'image'" class="square-image mr-4" :style="genericStyles(placeholder)"
9
- :src="fileImage || placeholder.url" />
10
-
11
- <v-text-field v-else-if="placeholder.type == 'input'" :value="fileTitle" outlined prominent
12
- placholder="Upload your file" disabled />
12
+ <img
13
+ v-else-if="placeholder.type == 'image'"
14
+ class="square-image mr-4"
15
+ :style="genericStyles(placeholder)"
16
+ :src="fileImage || placeholder.url"
17
+ />
18
+
19
+ <v-text-field
20
+ v-else-if="placeholder.type == 'input'"
21
+ :value="fileTitle"
22
+ outlined
23
+ prominent
24
+ placholder="Upload your file"
25
+ disabled
26
+ />
13
27
 
14
28
  <span v-else class="mr-4">{{ fileTitle }}</span>
15
29
 
@@ -33,7 +47,12 @@
33
47
  </v-btn>
34
48
  </span>
35
49
  </div>
36
- <input ref="directUploadFile" style="display: none;" type="file" @change="uploadFiles" />
50
+ <input
51
+ ref="directUploadFile"
52
+ style="display: none;"
53
+ type="file"
54
+ @change="uploadFiles"
55
+ />
37
56
 
38
57
  <!-- <input type="file" :name="spec.name" ref='directUploadFile' @change='uploadFiles' v-show='!uploaded'/> -->
39
58
  <v-progress-linear v-if="showProgress" v-model="progress.value" />
@@ -73,7 +92,7 @@ export default {
73
92
  };
74
93
  },
75
94
  computed: {
76
- showProgress: function () {
95
+ showProgress: function() {
77
96
  return this.progress.value >= 0;
78
97
  }
79
98
  },
@@ -129,6 +148,10 @@ export default {
129
148
  this.uploaded = true;
130
149
  this.progress.value = -1;
131
150
  this.displayImagePreview(file, blob);
151
+
152
+ // This only works for single uploads. For multi-uploads, we'll need to make sure
153
+ // that all uploads have finished successfully.
154
+ this.$executeOnChange();
132
155
  }
133
156
 
134
157
  input.disabled = false;
@@ -1,18 +1,40 @@
1
1
  <template>
2
2
  <div>
3
- <input
4
- v-for="(digit, index) in digits"
5
- ref="input"
6
- :key="index"
7
- v-model="otp[index]"
8
- maxlength="1"
9
- class="otp-input"
10
- @input="handleInput($event, index)"
11
- @keydown="handleKeydown($event, index)"
12
- @paste="handlePaste($event, index)"
13
- @focus="handleFocus($event, index)"
14
- @blur="handleBlur($event, index)"
15
- />
3
+ <div v-if="spec.type === 'text'">
4
+ <input
5
+ v-for="(digit, index) in digits"
6
+ ref="input"
7
+ :key="index"
8
+ v-model="otp[index]"
9
+ type="text"
10
+ maxlength="1"
11
+ class="otp-input"
12
+ @input="handleInput($event, index)"
13
+ @keydown="handleKeydown($event, index)"
14
+ @paste="handlePaste($event, index)"
15
+ @focus="handleFocus($event, index)"
16
+ @blur="handleBlur($event, index)"
17
+ @click="handleClick($event)"
18
+ />
19
+ </div>
20
+ <div v-else>
21
+ <input
22
+ v-for="(digit, index) in digits"
23
+ ref="input"
24
+ :key="index"
25
+ v-model="otp[index]"
26
+ type="number"
27
+ oninput="javascript: if (this.value.length > this.maxLength) this.value = this.value.slice(0, this.maxLength);"
28
+ maxlength="1"
29
+ class="otp-input"
30
+ @input="handleInput($event, index)"
31
+ @keydown="handleKeydown($event, index)"
32
+ @paste="handlePaste($event, index)"
33
+ @focus="handleFocus($event, index)"
34
+ @blur="handleBlur($event, index)"
35
+ @click="handleClick($event)"
36
+ />
37
+ </div>
16
38
  <input type="hidden" :name="spec.name" :value="otpValue" />
17
39
  </div>
18
40
  </template>
@@ -37,8 +59,8 @@ export default {
37
59
  },
38
60
  methods: {
39
61
  $ready() {
40
- this.digits = this.spec.lengths;
41
- this.otp = Array(this.spec.lengths).fill("");
62
+ this.digits = this.spec.length;
63
+ this.otp = Array(this.spec.length).fill("");
42
64
  },
43
65
  handleInput(event, index) {
44
66
  if (event.target.value.length === 1) {
@@ -48,8 +70,12 @@ export default {
48
70
  handleKeydown(event, index) {
49
71
  if (event.key === "Backspace") {
50
72
  event.preventDefault();
51
- this.focusPrevious(index);
52
- this.$set(this.otp, index, "");
73
+ if (this.otp[index] !== "") {
74
+ this.$set(this.otp, index, "");
75
+ } else {
76
+ this.focusPrevious(index);
77
+ this.$set(this.otp, index - 1, "");
78
+ }
53
79
  }
54
80
  },
55
81
  handlePaste(event, index) {
@@ -81,6 +107,9 @@ export default {
81
107
  if (index > 0) {
82
108
  this.$refs.input[index - 1].focus();
83
109
  }
110
+ },
111
+ handleClick(event) {
112
+ event.target.select();
84
113
  }
85
114
  }
86
115
  };
@@ -95,4 +124,16 @@ export default {
95
124
  font-size: 24px;
96
125
  margin: 8px;
97
126
  }
127
+
128
+ /* Chrome, Safari, Edge, Opera */
129
+ input::-webkit-outer-spin-button,
130
+ input::-webkit-inner-spin-button {
131
+ -webkit-appearance: none;
132
+ margin: 0;
133
+ }
134
+
135
+ /* Firefox */
136
+ input[type="number"] {
137
+ -moz-appearance: textfield;
138
+ }
98
139
  </style>
@@ -34,11 +34,7 @@ export default {
34
34
  },
35
35
  methods: {
36
36
  onChange() {
37
- Utils.type.ifObject(this.spec.onChange, onChange => {
38
- this.$nextTick(() => {
39
- GLib.action.execute(onChange, this);
40
- });
41
- });
37
+ this.$executeOnChange();
42
38
  },
43
39
  updateValue(variable) {
44
40
  if (variable.value) {
@@ -14,9 +14,9 @@
14
14
  v-model="richEditorValue"
15
15
  :editor-toolbar="customToolbar"
16
16
  use-custom-image-handler
17
+ :editor-options="editorSettings"
17
18
  @text-change="onRichTextEditorChanged"
18
19
  @image-added="uploadImage"
19
- :editorOptions="editorSettings"
20
20
  />
21
21
  <!-- Hide these fields but don't remove them because these are the values that will get submitted. -->
22
22
  <div :style="{ display: rawMode ? 'block' : 'none' }">
@@ -55,7 +55,7 @@ import bus from "../../utils/eventBus";
55
55
  Quill.register("modules/imageDropAndPaste", QuillImageDropAndPaste);
56
56
 
57
57
  var ImageBlot = Quill.import("formats/image");
58
- ImageBlot.sanitize = function (url) {
58
+ ImageBlot.sanitize = function(url) {
59
59
  return url;
60
60
  };
61
61
 
@@ -69,16 +69,16 @@ class Parser {
69
69
  turndownService.use(gfm);
70
70
  turndownService.addRule("strikethrough", {
71
71
  filter: ["del", "s", "strike"],
72
- replacement: function (content) {
72
+ replacement: function(content) {
73
73
  return "~~" + content + "~~";
74
- },
74
+ }
75
75
  });
76
76
 
77
77
  turndownService.addRule("codeblock", {
78
78
  filter: ["pre"],
79
- replacement: function (content) {
79
+ replacement: function(content) {
80
80
  return "```\n" + content + "```";
81
- },
81
+ }
82
82
  });
83
83
  return turndownService.turndown(data);
84
84
  }
@@ -125,7 +125,7 @@ class TextEditor {
125
125
  // replace {{image1}} to real image1 url
126
126
  replaceWithRealImage(html) {
127
127
  const vm = this.context;
128
- return html.replace(/\{\{image([0-9]+)\}\}/g, function (_, index) {
128
+ return html.replace(/\{\{image([0-9]+)\}\}/g, function(_, index) {
129
129
  const image = vm.spec.images[index - 1];
130
130
  if (
131
131
  image &&
@@ -146,7 +146,7 @@ class TextEditor {
146
146
  const vm = this.context;
147
147
  let index = 0;
148
148
  vm.imageKeys.clear();
149
- return html.replace(/src="([^"]+)"|\!\[\]\((.+)\)/g, function (_, g1, g2) {
149
+ return html.replace(/src="([^"]+)"|\!\[\]\((.+)\)/g, function(_, g1, g2) {
150
150
  var imageValue = g1 || g2;
151
151
  // It seems that quill encodes '&' in the URL to '&amp;' which would screw up key matching.
152
152
  var decodedValue = imageValue.replace(/&amp;/g, "&");
@@ -164,28 +164,28 @@ class TextEditor {
164
164
  export default {
165
165
  components: { VueEditor },
166
166
  props: {
167
- spec: { type: Object, required: true },
167
+ spec: { type: Object, required: true }
168
168
  },
169
169
  data: () => ({
170
170
  customToolbar: [
171
171
  ["bold", "italic", "strike"],
172
172
  [{ header: 1 }, { header: 2 }, { header: 3 }],
173
173
  [{ list: "ordered" }, { list: "bullet" }],
174
- ["image", "link"],
174
+ ["image", "link"]
175
175
  ],
176
176
  editorSettings: {
177
177
  modules: {
178
178
  imageDropAndPaste: {
179
179
  // add an custom image handler
180
- handler: function (imageDataUrl, type, imageData) {
180
+ handler: function(imageDataUrl, type, imageData) {
181
181
  bus.$emit("richText/dropOrPaste", {
182
182
  file: imageData.toFile(),
183
183
  editor: this.quill,
184
- cursorLocation: this.getIndex(),
184
+ cursorLocation: this.getIndex()
185
185
  });
186
- },
187
- },
188
- },
186
+ }
187
+ }
188
+ }
189
189
  },
190
190
  richEditorValue: "",
191
191
  rawEditorValue: "",
@@ -197,7 +197,7 @@ export default {
197
197
  textEditor: null,
198
198
  mode: null,
199
199
  produce: null,
200
- accept: null,
200
+ accept: null
201
201
  }),
202
202
  computed: {
203
203
  showProgress() {
@@ -205,7 +205,7 @@ export default {
205
205
  },
206
206
  rawMode() {
207
207
  return this.mode == 1;
208
- },
208
+ }
209
209
  },
210
210
  watch: {},
211
211
  mounted() {
@@ -235,7 +235,7 @@ export default {
235
235
  this.produce
236
236
  );
237
237
  },
238
- uploadImage: function (file, editor, cursorLocation) {
238
+ uploadImage: function(file, editor, cursorLocation) {
239
239
  let vm = this;
240
240
  const uploaderSpec = this.imageUploader;
241
241
  // const input = this.$refs.directUploadFile
@@ -274,48 +274,34 @@ export default {
274
274
  "html"
275
275
  );
276
276
  },
277
- onRichTextEditorChanged: eventFiltering.debounce(function () {
277
+ onRichTextEditorChanged: eventFiltering.debounce(function() {
278
278
  this.producedValue = this.textEditor.producedValue(
279
279
  this.richEditorValue,
280
280
  "html",
281
281
  this.produce
282
282
  );
283
283
 
284
- this.onChange(this.producedValue);
284
+ this.$executeOnChange();
285
285
  }),
286
- onRawTextEditorChanged: eventFiltering.debounce(function () {
286
+ onRawTextEditorChanged: eventFiltering.debounce(function() {
287
287
  this.producedValue = this.textEditor.producedValue(
288
288
  this.rawEditorValue,
289
289
  "markdown",
290
290
  this.produce
291
291
  );
292
292
 
293
- this.onChange(this.producedValue);
293
+ this.$executeOnChange();
294
294
  }),
295
- onChange(producedValue) {
296
- Utils.type.ifObject(this.spec.onChange, (onChange) => {
297
- this.$nextTick(() => {
298
- const params = {
299
- [this.spec.paramNameForFormData || "formData"]: {
300
- [this.fieldName]: producedValue,
301
- },
302
- };
303
-
304
- const data = Object.assign({}, onChange, params);
305
- GLib.action.execute(data, this);
306
- });
307
- });
308
- },
309
- insertImage: function (file, Editor, cursorLocation, blob) {
295
+ insertImage: function(file, Editor, cursorLocation, blob) {
310
296
  let vm = this;
311
297
  var reader = new FileReader();
312
- reader.onload = function (e) {
298
+ reader.onload = function(e) {
313
299
  // vm.fileUrl = e.target.result;
314
300
  if (file.type.indexOf("image") !== -1) {
315
301
  var image = new Image();
316
302
  image.src = URL.createObjectURL(file);
317
303
 
318
- image.onload = function () {
304
+ image.onload = function() {
319
305
  Editor.insertEmbed(cursorLocation, "image", image.src);
320
306
  };
321
307
 
@@ -326,7 +312,7 @@ export default {
326
312
  reader.readAsDataURL(file);
327
313
  vm.progress.value = -1;
328
314
  },
329
- updateToolbar: function (wrapper, toolbar, container) {
315
+ updateToolbar: function(wrapper, toolbar, container) {
330
316
  if (wrapper.scrollTop >= container.offsetTop) {
331
317
  toolbar.classList.add("sticky");
332
318
  toolbar.style.top = `${wrapper.offsetTop}px`;
@@ -339,7 +325,7 @@ export default {
339
325
  toolbar.style.width = "auto";
340
326
  }
341
327
  },
342
- registerScrollEvent: function () {
328
+ registerScrollEvent: function() {
343
329
  const wrapper = document.querySelector(".v-dialog") || window;
344
330
  const toolbar = this.$el.querySelector(".ql-toolbar");
345
331
  const container = this.$el.querySelector(".ql-container");
@@ -352,8 +338,8 @@ export default {
352
338
  this.updateToolbar(wrapper, toolbar, container)
353
339
  );
354
340
  }
355
- },
356
- },
341
+ }
342
+ }
357
343
  };
358
344
  </script>
359
345
 
@@ -137,22 +137,8 @@ export default {
137
137
  return this.$classes().concat("g-text-field--hintless");
138
138
  },
139
139
  onChange: eventFiltering.debounce(function() {
140
- this.executeActionWithParams();
141
- }, 300),
142
- executeActionWithParams() {
143
- Utils.type.ifObject(this.spec.onChange, onChange => {
144
- this.$nextTick(() => {
145
- const params = {
146
- [this.spec.paramNameForFormData || "formData"]: {
147
- [this.fieldName]: this.fieldModel
148
- }
149
- };
150
-
151
- const data = Object.assign({}, onChange, params);
152
- GLib.action.execute(data, this);
153
- });
154
- });
155
- }
140
+ this.$executeOnChange();
141
+ }, 300)
156
142
  }
157
143
  };
158
144
  </script>
@@ -16,6 +16,7 @@
16
16
  :no-resize="$classes().includes('no-resize')"
17
17
  validate-on-blur
18
18
  @keyup="$onTyping"
19
+ @input="onChange"
19
20
  ></v-textarea>
20
21
  <input
21
22
  v-if="spec.readOnly"
@@ -27,6 +28,8 @@
27
28
  </template>
28
29
 
29
30
  <script>
31
+ import eventFiltering from "../../utils/eventFiltering";
32
+
30
33
  export default {
31
34
  props: {
32
35
  spec: { type: Object, required: true }
@@ -45,7 +48,10 @@ export default {
45
48
  },
46
49
  classes() {
47
50
  return this.$classes().concat("g-text-field--hintless");
48
- }
51
+ },
52
+ onChange: eventFiltering.debounce(function() {
53
+ this.$executeOnChange();
54
+ }, 300)
49
55
  }
50
56
  };
51
57
  </script>
package/nav/dialog.vue CHANGED
@@ -7,24 +7,34 @@
7
7
  :sm-and-down="false"
8
8
  :persistent="true"
9
9
  >
10
- <v-card>
11
- <v-card-title v-if="title || showClose" class="text-h5" primary-title>
12
- {{ title }}
10
+ <v-card :style="hamburgerStyles" class="hamburger">
11
+ <!-- <v-card-title v-if="title || showClose" class="text-h5" primary-title> -->
12
+ <div>
13
+ <panels-responsive v-if="header" :spec="header" />
14
+ <div v-if="title" class="dialogs-title theme--light v-subheader">
15
+ {{ title }}
16
+ </div>
17
+
13
18
  <v-btn v-if="showClose" text icon class="dialog-close" @click="close">
14
19
  <v-icon>close</v-icon>
15
20
  </v-btn>
16
- </v-card-title>
21
+ </div>
22
+ <!-- </v-card-title> -->
17
23
 
18
- <component :is="containerComponent" :spec="formSpec">
19
- <div v-if="message" class="dialog-message">
20
- <common-message :spec="{ message: message }" />
21
- </div>
22
- <panels-responsive v-if="body" :spec="body" />
23
- </component>
24
+ <div class="dialogs-body">
25
+ <component :is="containerComponent" :spec="formSpec">
26
+ <div v-if="message" class="dialog-message">
27
+ <common-message :spec="{ message: message }" />
28
+ </div>
29
+ <panels-responsive v-if="body" :spec="body" />
30
+ </component>
31
+ </div>
24
32
 
25
- <v-divider></v-divider>
33
+ <panels-responsive v-if="footer" :spec="footer" />
26
34
 
27
35
  <v-card-actions v-if="spec.buttons">
36
+ <v-divider></v-divider>
37
+
28
38
  <v-spacer></v-spacer>
29
39
 
30
40
  <v-btn
@@ -36,8 +46,6 @@
36
46
  >
37
47
  {{ button.text }}
38
48
  </v-btn>
39
-
40
- <panels-responsive v-if="footer" :spec="footer" />
41
49
  </v-card-actions>
42
50
  </v-card>
43
51
  </v-dialog>
@@ -59,9 +67,11 @@ export default {
59
67
  },
60
68
  data: function() {
61
69
  return {
70
+ mainHeight: 0,
62
71
  title: null,
63
72
  message: null,
64
73
  body: null,
74
+ header: null,
65
75
  footer: null,
66
76
  model: null,
67
77
  url: null,
@@ -88,6 +98,12 @@ export default {
88
98
  } else {
89
99
  return false;
90
100
  }
101
+ },
102
+ hamburgerStyles() {
103
+ if (this.spec.height == "matchParent") {
104
+ return `height: ${this.mainHeight}px;`;
105
+ }
106
+ return null;
91
107
  }
92
108
  },
93
109
  watch: {
@@ -98,11 +114,24 @@ export default {
98
114
  }
99
115
  },
100
116
  methods: {
117
+ $mounted() {
118
+ window.addEventListener(
119
+ "resize",
120
+ event => {
121
+ this.updateMainHeight();
122
+ },
123
+ true
124
+ );
125
+ },
101
126
  $ready() {
102
127
  this.$root.vueApp = this.vueApp;
103
128
  this.onResize();
104
129
  this.show(false);
105
130
  this.stack.push(this);
131
+
132
+ this.$nextTick(() => {
133
+ this.updateMainHeight();
134
+ });
106
135
  },
107
136
  $tearDown() {
108
137
  console.log("Dialog destroyed");
@@ -128,7 +157,6 @@ export default {
128
157
  onResize() {
129
158
  this.isMobile = window.innerWidth < 600;
130
159
  },
131
-
132
160
  show(reload) {
133
161
  const spec = this.spec;
134
162
  this.url = spec.url;
@@ -146,6 +174,7 @@ export default {
146
174
  this.title = response.title;
147
175
  this.message = "";
148
176
  this.formSpec = response.fullPageForm;
177
+ this.header = response.header;
149
178
  this.body = response.body;
150
179
  this.footer = response.footer;
151
180
  this.showClose = this.spec.showClose || false;
@@ -161,12 +190,19 @@ export default {
161
190
  }
162
191
 
163
192
  this.model = true;
193
+ },
194
+ updateMainHeight() {
195
+ console.debug("Setting body height");
196
+ this.mainHeight = window.innerHeight - 140;
164
197
  }
165
198
  }
166
199
  };
167
200
  </script>
168
201
 
169
- <style scoped>
202
+ <style lang="scss" scoped>
203
+ .dialogs-title {
204
+ padding: 16px 16px 0px 16px;
205
+ }
170
206
  .dialog-message {
171
207
  padding: 16px 16px 20px 16px;
172
208
  /* white-space: pre-wrap; */
@@ -179,4 +215,31 @@ export default {
179
215
  .v-card__text {
180
216
  padding: 0 !important;
181
217
  }
218
+ .hamburger {
219
+ display: flex;
220
+ flex-direction: column;
221
+ justify-content: space-between;
222
+ height: 100%;
223
+ padding: 0;
224
+ }
225
+ .dialogs-body {
226
+ // height: 100%;
227
+ // overflow-y: overlay;
228
+ overflow-y: auto;
229
+ }
230
+ </style>
231
+
232
+ <style lang="scss">
233
+ .v-dialog {
234
+ // Hide superfluous scrollbar (Edge)
235
+ -ms-overflow-style: none;
236
+ * {
237
+ -ms-overflow-style: initial;
238
+ }
239
+
240
+ // Hide superfluous scrollbar (Webkit)
241
+ &::-webkit-scrollbar {
242
+ display: none;
243
+ }
244
+ }
182
245
  </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glib-web",
3
- "version": "2.6.0",
3
+ "version": "2.6.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/utils/launch.js CHANGED
@@ -19,6 +19,14 @@ export default class {
19
19
  }
20
20
 
21
21
  class LaunchDialog {
22
+ static closestBody(component) {
23
+ const dialog = component.$el.closest(".v-dialog");
24
+ if (dialog) {
25
+ return dialog.querySelector(".dialogs-body");
26
+ }
27
+ return null;
28
+ }
29
+
22
30
  static _initStack() {
23
31
  if (!this.stack) {
24
32
  this.stack = [];
package/utils/public.js CHANGED
@@ -6,6 +6,7 @@ import Form from "./form";
6
6
  import Component from "./component";
7
7
  import Hash from "./hash";
8
8
  import Queue from "./queue";
9
+ import Settings from "./settings";
9
10
 
10
11
  const _queue = new Queue();
11
12
 
@@ -31,6 +32,9 @@ export default class {
31
32
  static get Hash() {
32
33
  return Hash;
33
34
  }
35
+ static get settings() {
36
+ return Settings;
37
+ }
34
38
  static get queue() {
35
39
  return _queue;
36
40
  }
package/utils/queue.js CHANGED
File without changes
package/utils/settings.js CHANGED
@@ -3,6 +3,9 @@ class MutableSettings {
3
3
  this.reactive = true;
4
4
  this.themes = {};
5
5
  this.gtagId = null;
6
+ this.errorHandler = err => {
7
+ console.error(err.message);
8
+ };
6
9
  }
7
10
  }
8
11
  const settings = new MutableSettings();
@@ -17,6 +20,10 @@ export default class ImmutableSettings {
17
20
  return settings.themes;
18
21
  }
19
22
 
23
+ static get errorHandler() {
24
+ return settings.errorHandler;
25
+ }
26
+
20
27
  static get env() {
21
28
  return process.env.NODE_ENV;
22
29
  }