glib-web 2.3.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/LICENSE +0 -0
  2. package/action.js +1 -1
  3. package/actions/auth/restart.js +0 -0
  4. package/actions/dialogs/oauth.js +0 -0
  5. package/actions/dialogs/options.js +0 -0
  6. package/components/_badge.vue +3 -0
  7. package/components/_button.vue +16 -1
  8. package/components/_chip.vue +10 -9
  9. package/components/_message.vue +0 -0
  10. package/components/_responsive.vue +1 -8
  11. package/components/_tooltip.vue +48 -10
  12. package/components/button.vue +7 -1
  13. package/components/chip.vue +7 -1
  14. package/components/component.vue +3 -0
  15. package/components/datetime.vue +0 -0
  16. package/components/fab.vue +0 -0
  17. package/components/fields/_patternText.vue +11 -0
  18. package/components/fields/_select.vue +10 -8
  19. package/components/fields/country/countries.js +0 -0
  20. package/components/fields/country/field.vue +0 -0
  21. package/components/fields/country/regions.js +0 -0
  22. package/components/fields/date.vue +7 -0
  23. package/components/fields/datetime.vue +0 -0
  24. package/components/fields/dynamicSelect.vue +0 -0
  25. package/components/fields/select.vue +1 -1
  26. package/components/fields/timeZone.vue +0 -0
  27. package/components/h4.vue +5 -0
  28. package/components/hr.vue +0 -0
  29. package/components/html.vue +0 -0
  30. package/components/mixins/events.js +14 -0
  31. package/components/mixins/generic.js +1 -1
  32. package/components/mixins/longClick.js +0 -0
  33. package/components/mixins/scrolling.js +0 -0
  34. package/components/mixins/styles.js +6 -3
  35. package/components/mixins/table/export.js +0 -0
  36. package/components/mixins/table/import.js +0 -0
  37. package/components/p.vue +0 -0
  38. package/components/panels/horizontal.vue +17 -1
  39. package/components/panels/timeline.vue +47 -16
  40. package/extensions/array.js +4 -0
  41. package/extensions/string.js +4 -0
  42. package/index.js +2 -0
  43. package/keys.js +0 -0
  44. package/nav/drawer.vue +4 -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/thumbnail.vue +2 -2
  51. package/templates/unsupported.vue +0 -0
  52. package/utils/app.js +0 -4
  53. package/utils/component.js +18 -2
  54. package/utils/dom.js +0 -0
  55. package/utils/hash.js +25 -0
  56. package/utils/public.js +4 -0
  57. package/utils/settings.js +0 -0
  58. package/utils/storage.js +2 -3
  59. package/utils/url.js +10 -8
package/LICENSE CHANGED
File without changes
package/action.js CHANGED
@@ -146,7 +146,7 @@ export default class Action {
146
146
 
147
147
  static executeLocal(name, spec, component) {
148
148
  const methodName = name.replace(/^component\//, "");
149
- const componentName = Utils.app.vueName(component);
149
+ const componentName = GLib.component.vueName(component);
150
150
  console.log(
151
151
  `Executing component action on ${componentName}: ${methodName}`
152
152
  );
File without changes
File without changes
File without changes
@@ -36,6 +36,9 @@ export default {
36
36
  return { width: "100%" };
37
37
  }
38
38
  return {};
39
+ },
40
+ $registryEnabled() {
41
+ return false;
39
42
  }
40
43
  }
41
44
  };
@@ -1,5 +1,7 @@
1
1
  <template>
2
2
  <common-badge :spec="spec">
3
+ <!-- Use `click.prevent` to prevent bubbling when clicking a dropdown button that is
4
+ located in a list row that has href. -->
3
5
  <v-btn
4
6
  :type="type"
5
7
  :disabled="disabled || $isBusy || spec.disabled"
@@ -14,7 +16,7 @@
14
16
  :tile="$classes().includes('tile')"
15
17
  :rounded="$classes().includes('rounded')"
16
18
  :depressed="$classes().includes('depressed')"
17
- @click="type == 'submit' ? null : $onClick()"
19
+ @click.prevent="type == 'submit' ? null : $onClick()"
18
20
  v-on="eventHandlers"
19
21
  >
20
22
  <span><common-icon :spec="spec.icon || {}"/></span>
@@ -51,11 +53,24 @@ export default {
51
53
  styles["color"] = styles["color"] || "#1976d2";
52
54
  }
53
55
  return styles;
56
+ },
57
+ $registryEnabled() {
58
+ return false;
54
59
  }
55
60
  }
56
61
  };
57
62
  </script>
58
63
 
64
+ <style lang="scss">
65
+ .v-btn {
66
+ &.link {
67
+ .v-icon {
68
+ font-size: 16px;
69
+ }
70
+ }
71
+ }
72
+ </style>
73
+
59
74
  <style lang="scss" scoped>
60
75
  a,
61
76
  button {
@@ -21,20 +21,21 @@
21
21
  </template>
22
22
 
23
23
  <script>
24
- // import TooltipMixins from "./mixins/tooltip";
25
24
  export default {
26
- // mixins: [TooltipMixins],
27
25
  props: {
28
26
  spec: { type: Object, required: true }
29
27
  },
30
- data: function() {
31
- return {
32
- tooltip: {}
33
- };
34
- },
28
+ // data: function() {
29
+ // return {
30
+ // tooltip: {}
31
+ // };
32
+ // },
35
33
  methods: {
36
- $ready() {
37
- this.tooltip = this.spec.tooltip || {};
34
+ // $ready() {
35
+ // this.tooltip = this.spec.tooltip || {};
36
+ // },
37
+ $registryEnabled() {
38
+ return false;
38
39
  }
39
40
  }
40
41
  };
File without changes
@@ -43,14 +43,7 @@ export default {
43
43
  computed: {
44
44
  cssClasses() {
45
45
  // Provide a default name so the panel will not be nameless when used in predefined layouts (e.g. page.body, list.header, etc.)
46
- return this.$classes(
47
- Object.assign(
48
- {
49
- view: "panels/responsive"
50
- },
51
- this.spec
52
- )
53
- );
46
+ return this.$classes(this.spec, "panels/responsive");
54
47
  },
55
48
  componentName() {
56
49
  return this.spec.onClick ? "a" : "div";
@@ -1,37 +1,63 @@
1
1
  <template>
2
+ <v-menu v-if="spec.childButtons" left bottom>
3
+ <template v-slot:activator="{ on: onMenu }">
4
+ <v-tooltip
5
+ :disabled="tooltip.disabled"
6
+ :top="tooltipPositionMatches('top')"
7
+ :right="tooltipPositionMatches('right')"
8
+ :bottom="tooltipPositionMatches('bottom')"
9
+ :left="tooltipPositionMatches('left')"
10
+ >
11
+ <template v-slot:activator="{ on: onTooltip }">
12
+ <slot name="activator" :on="{ ...onMenu, ...onTooltip }" />
13
+ </template>
14
+ <span> {{ tooltip.text }} </span>
15
+ </v-tooltip>
16
+ </template>
17
+
18
+ <v-list>
19
+ <v-list-item
20
+ v-for="(childItem, childIndex) in spec.childButtons"
21
+ :key="childIndex"
22
+ >
23
+ <common-button
24
+ :spec="buttonSpec(childItem)"
25
+ :disabled="childItem.disabled || $isBusy"
26
+ />
27
+ </v-list-item>
28
+ </v-list>
29
+ </v-menu>
2
30
  <v-tooltip
31
+ v-else
3
32
  :disabled="tooltip.disabled"
4
33
  :top="tooltipPositionMatches('top')"
5
34
  :right="tooltipPositionMatches('right')"
6
35
  :bottom="tooltipPositionMatches('bottom')"
7
36
  :left="tooltipPositionMatches('left')"
8
37
  >
9
- <template v-slot:activator="{ on }">
10
- <!-- Pass the slot props through to the caller using the same slot name (i.e. `activator`) -->
11
- <slot name="activator" :on="on" />
38
+ <template v-slot:activator="{ on: onTooltip }">
39
+ <slot name="activator" :on="{ ...onTooltip }" />
12
40
  </template>
13
41
  <span> {{ tooltip.text }} </span>
14
42
  </v-tooltip>
15
43
  </template>
16
44
 
17
45
  <script>
18
- // import tooltipMixin from "./mixins/tooltip";
19
-
20
46
  export default {
21
- // mixins: [tooltipMixin],
22
47
  props: {
23
48
  spec: { type: Object, required: true }
24
49
  },
25
50
  data() {
26
51
  return {
27
- tooltip: {},
28
- childSpec: Object.assign({}, this.spec, { id: undefined })
52
+ tooltip: {}
53
+ // childSpec: Object.assign({}, this.spec, { id: undefined })
29
54
  };
30
55
  },
31
56
  methods: {
32
57
  $ready() {
33
- this.tooltip = this.spec.tooltip || { disabled: true };
34
- this.childSpec = Object.assign({}, this.spec, { id: undefined });
58
+ this.updateData();
59
+ // this.tooltip = this.spec.tooltip || { disabled: true };
60
+ // this.childSpec = Object.assign({}, this.spec, { id: undefined });
35
61
  },
36
62
  // $initAccessories() {
37
63
  // this.tooltip = this.spec.tooltip || { disabled: true };
@@ -42,6 +68,18 @@ export default {
42
68
  } else {
43
69
  return position == "bottom";
44
70
  }
71
+ },
72
+ buttonSpec(item) {
73
+ return Object.assign({}, item, {
74
+ view: "button-v1",
75
+ styleClasses: ["text"]
76
+ });
77
+ },
78
+ $registryEnabled() {
79
+ return false;
80
+ },
81
+ updateData() {
82
+ this.tooltip = this.spec.tooltip || { disabled: true };
45
83
  }
46
84
  }
47
85
  };
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <common-tooltip :spec="spec">
2
+ <common-tooltip ref="tooltip" :spec="spec">
3
3
  <template v-slot:activator="{ on }">
4
4
  <common-button :spec="spec" :disabled="$isBusy" :event-handlers="on" />
5
5
  </template>
@@ -10,6 +10,12 @@
10
10
  export default {
11
11
  props: {
12
12
  spec: { type: Object, required: true }
13
+ },
14
+ methods: {
15
+ action_merge(mergedSpec) {
16
+ Object.assign(this.spec, mergedSpec);
17
+ this.$refs.tooltip.updateData();
18
+ }
13
19
  }
14
20
  };
15
21
  </script>
@@ -1,11 +1,17 @@
1
1
  <template>
2
- <common-chip :spec="spec" />
2
+ <common-chip ref="delegate" :spec="spec" />
3
3
  </template>
4
4
 
5
5
  <script>
6
6
  export default {
7
7
  props: {
8
8
  spec: { type: Object, required: true }
9
+ },
10
+ methods: {
11
+ action_merge(mergedSpec) {
12
+ Object.assign(this.spec, mergedSpec);
13
+ // this.$refs.delegate.updateData();
14
+ }
9
15
  }
10
16
  };
11
17
  </script>
@@ -232,6 +232,9 @@ export default {
232
232
  this.name = name;
233
233
  }
234
234
  }
235
+ },
236
+ $registryEnabled() {
237
+ return false;
235
238
  }
236
239
  }
237
240
  };
File without changes
File without changes
@@ -16,7 +16,9 @@
16
16
  :rules="$validation()"
17
17
  :outlined="$classes().includes('outlined')"
18
18
  :style="$styles()"
19
+ :dense="$classes().includes('dense')"
19
20
  clearable
21
+ @input="onChange"
20
22
  />
21
23
  </div>
22
24
  </template>
@@ -58,6 +60,15 @@ export default {
58
60
  },
59
61
  classes() {
60
62
  return this.$classes().concat("g-text-field--hintless");
63
+ },
64
+ onChange() {
65
+ this.$executeOnChange();
66
+ },
67
+ $registryEnabled() {
68
+ return false;
69
+ },
70
+ updateData() {
71
+ this.fieldModel = this.spec.value;
61
72
  }
62
73
  }
63
74
  };
@@ -15,6 +15,7 @@
15
15
  validate-on-blur
16
16
  persistent-hint
17
17
  :class="$classes()"
18
+ :dense="$classes().includes('dense')"
18
19
  :outlined="$classes().includes('outlined')"
19
20
  :append-icon="append.icon"
20
21
  @change="onChange"
@@ -60,7 +61,7 @@ export default {
60
61
  },
61
62
  methods: {
62
63
  $ready() {
63
- this.updateData();
64
+ this.updateData(false);
64
65
  },
65
66
  normalizedOptions() {
66
67
  return this.spec.options.map(i => {
@@ -78,17 +79,18 @@ export default {
78
79
  return this.$classes().concat("g-text-field--hintless");
79
80
  },
80
81
  onChange() {
81
- Utils.type.ifObject(this.spec.onChange, onChange => {
82
- this.$nextTick(() => {
83
- GLib.action.execute(onChange, this);
84
- });
85
- });
82
+ this.$executeOnChange();
86
83
  },
87
- updateData() {
84
+ updateData(reinitValue) {
88
85
  this.options = this.normalizedOptions();
89
86
  this.append = this.spec.append || {};
90
87
  this.rules = this.$validation();
91
- if (this.defaultValue) {
88
+
89
+ if (reinitValue) {
90
+ this.fieldModel = this.spec.value || this.defaultValue;
91
+ } else if (this.defaultValue) {
92
+ // Don't execute if null because that will trigger an unnecessary update which will break
93
+ // select fields with `unspecified` value. See `/glib/json_ui_garage?path=forms%2Fselects`.
92
94
  this.fieldModel = this.defaultValue;
93
95
  }
94
96
  },
File without changes
File without changes
File without changes
@@ -1,6 +1,7 @@
1
1
  <template>
2
2
  <!-- See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date for why we need to use `pattern` -->
3
3
  <fields-patternText
4
+ ref="delegate"
4
5
  :spec="spec"
5
6
  :type="spec.type || 'date'"
6
7
  pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}"
@@ -17,6 +18,12 @@ export default {
17
18
  },
18
19
  props: {
19
20
  spec: { type: Object, required: true }
21
+ },
22
+ methods: {
23
+ action_merge(mergedSpec) {
24
+ Object.assign(this.spec, mergedSpec);
25
+ this.$refs.delegate.updateData();
26
+ }
20
27
  }
21
28
  };
22
29
  </script>
File without changes
File without changes
@@ -24,7 +24,7 @@ export default {
24
24
  },
25
25
  action_merge(mergedSpec) {
26
26
  Object.assign(this.updatedSpec, mergedSpec);
27
- this.$refs.delegate.updateData();
27
+ this.$refs.delegate.updateData(true);
28
28
  }
29
29
  }
30
30
  };
File without changes
package/components/h4.vue CHANGED
@@ -17,6 +17,11 @@ export default {
17
17
  mixins: [textMixin],
18
18
  props: {
19
19
  spec: { type: Object, required: true }
20
+ },
21
+ methods: {
22
+ action_merge(mergedSpec) {
23
+ Object.assign(this.spec, mergedSpec);
24
+ }
20
25
  }
21
26
  };
22
27
  </script>
package/components/hr.vue CHANGED
File without changes
File without changes
@@ -177,6 +177,20 @@ export default {
177
177
  this._typingTimer = null;
178
178
  GLib.action.execute(this.spec.onTypeEnd, this);
179
179
  }, duration);
180
+ },
181
+ $executeOnChange(newValue) {
182
+ Utils.type.ifObject(this.spec.onChange, onChange => {
183
+ this.$nextTick(() => {
184
+ const value = newValue || this.fieldModel;
185
+ const params = {
186
+ [this.spec.paramNameForFormData || "formData"]: {
187
+ [this.fieldName]: value
188
+ }
189
+ };
190
+ const data = Object.assign({}, onChange, params);
191
+ GLib.action.execute(data, this);
192
+ });
193
+ });
180
194
  }
181
195
  }
182
196
  };
@@ -5,7 +5,7 @@ export default {
5
5
  while (parent != null) {
6
6
  if (
7
7
  Utils.type.isObject(parent.spec) &&
8
- Utils.app.vueName(parent) == name
8
+ GLib.component.vueName(parent) == name
9
9
  ) {
10
10
  return parent;
11
11
  }
File without changes
File without changes
@@ -191,7 +191,7 @@ export default {
191
191
  },
192
192
  _linkFieldModels() {
193
193
  const hasCondition = this.spec && this.spec.showIf;
194
- const name = Utils.app.vueName(this);
194
+ const name = GLib.component.vueName(this);
195
195
  const isField = name && name.startsWith("fields-");
196
196
  if (hasCondition || isField) {
197
197
  const form = this.$closest("panels-form");
@@ -205,8 +205,11 @@ export default {
205
205
  this.fieldModel = this._sanitizeValue(this.spec.value);
206
206
  }
207
207
  },
208
- $classes(spec) {
209
- const properties = spec || this.spec;
208
+ $classes(spec, defaultViewName) {
209
+ const properties = Object.assign(
210
+ { view: defaultViewName },
211
+ spec || this.spec
212
+ );
210
213
  const componentName = Utils.app.componentName(properties.view);
211
214
  const classes = (properties.styleClasses || []).concat(componentName);
212
215
 
File without changes
File without changes
package/components/p.vue CHANGED
File without changes
@@ -6,7 +6,7 @@
6
6
  :href="$href()"
7
7
  @click="$onClick()"
8
8
  >
9
- <template v-for="(item, index) in spec.childViews">
9
+ <template v-for="(item, index) in childViews">
10
10
  <glib-component :key="index" :spec="item" />
11
11
  </template>
12
12
  </component>
@@ -17,6 +17,11 @@ export default {
17
17
  props: {
18
18
  spec: { type: Object, required: true }
19
19
  },
20
+ data() {
21
+ return {
22
+ childViews: null
23
+ };
24
+ },
20
25
  computed: {
21
26
  cssClasses: function() {
22
27
  const classes = this.$classes().concat("layouts-horizontal");
@@ -58,8 +63,19 @@ export default {
58
63
  }
59
64
  },
60
65
  methods: {
66
+ $ready() {
67
+ this.childViews = this.spec.childViews;
68
+ console.log("C1", this.childViews);
69
+ },
61
70
  $displayValue() {
62
71
  return "flex";
72
+ },
73
+ action_merge(mergedSpec) {
74
+ console.log("mergedSpec1", this.spec, this.spec.childViews);
75
+ Object.assign(this.spec, mergedSpec);
76
+ console.log("mergedSpec2", this.spec, this.spec.childViews);
77
+ // this.$refs.delegate.updateData();
78
+ this.$ready();
63
79
  }
64
80
  }
65
81
  };
@@ -1,35 +1,46 @@
1
1
  <template>
2
- <v-container :class="$classes()">
2
+ <!-- Paddings cannot be applied to v-timeline directly -->
3
+ <div :style="$styles()" :class="$classes()">
3
4
  <v-timeline v-if="events" dense align-top>
4
5
  <v-timeline-item
5
6
  v-for="(item, index) in events"
6
7
  :key="index"
7
- color="white"
8
- fill-dot
9
- :small="$classes().includes('small')"
10
- :large="$classes().includes('large')"
11
- class="my-6"
8
+ :color="item.backgroundColor || 'white'"
9
+ :small="itemClasses(item).includes('small')"
10
+ :large="itemClasses(item).includes('large')"
12
11
  :hide-dot="item.hide_dot"
12
+ fill-dot
13
13
  >
14
14
  <template v-slot:icon>
15
- <div :class="$classes().includes('outlined') ? 'outlined-dots' : ''">
16
- <div v-if="item.label" class="number-circle">
17
- {{ item.label }}
15
+ <div
16
+ :class="
17
+ itemClasses(item).includes('outlined') ? 'outlined-dots' : ''
18
+ "
19
+ >
20
+ <div
21
+ v-if="item.text"
22
+ class="number-circle"
23
+ :style="{ color: item.color }"
24
+ >
25
+ {{ item.text }}
18
26
  </div>
19
27
  <div v-else class="icon">
20
28
  <common-icon
21
29
  :spec="{
22
- material: { name: item.icon, size: iconSize() },
30
+ material: { name: item.icon, size: iconSize(item) },
23
31
  color: item.color
24
32
  }"
25
33
  />
26
34
  </div>
27
35
  </div>
28
36
  </template>
29
- <panels-responsive :spec="{ childViews: [childViews[index]] }" />
37
+ <panels-responsive
38
+ v-if="childViews"
39
+ :spec="{ childViews: [childViews[index]] }"
40
+ />
30
41
  </v-timeline-item>
31
42
  </v-timeline>
32
- </v-container>
43
+ </div>
33
44
  </template>
34
45
 
35
46
  <script>
@@ -48,19 +59,38 @@ export default {
48
59
  this.events = this.spec.events;
49
60
  this.childViews = this.spec.childViews;
50
61
  },
51
- iconSize() {
52
- return this.$classes().includes("small") ? 16 : 24;
62
+ iconSize(item) {
63
+ return this.itemClasses(item).includes("small") ? 20 : 24;
64
+ },
65
+ itemClasses(item) {
66
+ return item.styleClasses || [];
67
+ },
68
+ action_merge(mergedSpec) {
69
+ Object.assign(this.spec, mergedSpec);
70
+ this.$ready();
53
71
  }
54
72
  }
55
73
  };
56
74
  </script>
57
75
 
76
+ <style lang="scss">
77
+ .v-timeline-item__dot {
78
+ height: 36px;
79
+ width: 36px;
80
+ }
81
+ .v-timeline-item__dot--small {
82
+ height: 20px;
83
+ width: 20px;
84
+ }
85
+ </style>
86
+
58
87
  <style lang="scss" scoped>
59
88
  .v-timeline {
60
89
  padding-top: 0px;
61
90
  }
62
91
  .v-timeline-item {
63
- padding-bottom: 0px !important;
92
+ // Minimum line distance
93
+ padding-bottom: 10px;
64
94
  }
65
95
  .container {
66
96
  padding-top: 0px;
@@ -73,7 +103,8 @@ export default {
73
103
  margin: auto;
74
104
  text-align: center;
75
105
  font-weight: bold;
76
- font-size: 22px;
106
+ padding: 4px 0;
107
+ // font-size: 22px;
77
108
  }
78
109
  .outlined .v-timeline-item {
79
110
  ::v-deep .v-timeline-item__dot {
@@ -22,3 +22,7 @@ Array.prototype.first = function() {
22
22
  Array.prototype.last = function() {
23
23
  return this[this.length - 1];
24
24
  };
25
+
26
+ Array.prototype.random = function() {
27
+ return this[Math.floor(Math.random() * this.length)];
28
+ };
@@ -19,3 +19,7 @@ String.prototype.contains = function(substr) {
19
19
  String.prototype.presence = function() {
20
20
  return this.length > 0 ? this.toString() : null;
21
21
  };
22
+
23
+ String.prototype.truncate = function(n) {
24
+ return this.length > n ? this.slice(0, n - 1) + "..." : this.toString();
25
+ };
package/index.js CHANGED
@@ -57,6 +57,7 @@ import CommonMessage from "./components/_message";
57
57
  import CommonDropdownMenu from "./components/_dropdownMenu";
58
58
  import CommonResponsive from "./components/_responsive";
59
59
  import CommonTemplateMenu from "./templates/_menu";
60
+ import RichButton from "./components/button";
60
61
  Vue.component("panels-vertical", VerticalPanel);
61
62
  Vue.component("panels-responsive", ResponsivePanel);
62
63
  Vue.component("common-button", CommonButton);
@@ -68,6 +69,7 @@ Vue.component("common-message", CommonMessage);
68
69
  Vue.component("common-dropdownMenu", CommonDropdownMenu);
69
70
  Vue.component("common-responsive", CommonResponsive);
70
71
  Vue.component("templates-menu", CommonTemplateMenu);
72
+ Vue.component("rich-button", RichButton);
71
73
 
72
74
  Vue.component("glib-component", Component);
73
75
  Vue.component("glib-icon", CommonIcon);
package/keys.js CHANGED
File without changes
package/nav/drawer.vue CHANGED
@@ -76,8 +76,10 @@ export default {
76
76
  computed: {
77
77
  cssClasses() {
78
78
  // To make sure a css class name is assigned to this component
79
- this.spec.view = this.spec.view || "pages/leftDrawer";
80
- return this.$classes();
79
+ // this.spec.view = this.spec.view || "pages/leftDrawer";
80
+
81
+ // Make sure it has a view name.
82
+ return this.$classes(this.spec, "pages/leftDrawer");
81
83
  },
82
84
  style() {
83
85
  // Increase z-index so that the drawer is above the page header.
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glib-web",
3
- "version": "2.3.1",
3
+ "version": "2.4.0",
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
@@ -28,7 +28,7 @@
28
28
 
29
29
  <div v-if="spec.leftButtons" class="left-universal">
30
30
  <template v-for="(item, index) in spec.leftButtons">
31
- <common-button
31
+ <rich-button
32
32
  :key="index"
33
33
  :spec="buttonSpec(item)"
34
34
  :disabled="$isBusy"
@@ -80,7 +80,7 @@
80
80
  </v-list-item-content>
81
81
 
82
82
  <template v-for="(item, index) in spec.rightButtons">
83
- <common-button
83
+ <rich-button
84
84
  :key="index"
85
85
  :spec="buttonSpec(item)"
86
86
  :disabled="$isBusy"
File without changes
package/utils/app.js CHANGED
@@ -8,8 +8,4 @@ export default class {
8
8
  }
9
9
  return name;
10
10
  }
11
-
12
- static vueName(component) {
13
- return component.$options._componentTag;
14
- }
15
11
  }
@@ -1,12 +1,28 @@
1
1
  export default class {
2
+ static get _registry() {
3
+ return window.vueApp.registeredComponents;
4
+ }
2
5
  static findById(id) {
3
- const component = window.vueApp.registeredComponents[id];
6
+ const component = this._registry[id];
4
7
  if (component) {
5
8
  return component;
6
9
  }
7
10
  console.error("Component not found: " + id);
8
11
  }
9
12
  static register(id, component) {
10
- window.vueApp.registeredComponents[id] = component;
13
+ if (this._registry[id]) {
14
+ console.warn(
15
+ "Duplicate component ID:",
16
+ id,
17
+ "Existing:",
18
+ this.vueName(this._registry[id]),
19
+ "New:",
20
+ this.vueName(component)
21
+ );
22
+ }
23
+ this._registry[id] = component;
24
+ }
25
+ static vueName(component) {
26
+ return component.$options._componentTag;
11
27
  }
12
28
  }
package/utils/dom.js CHANGED
File without changes
package/utils/hash.js CHANGED
@@ -26,4 +26,29 @@ export default class Hash {
26
26
  }
27
27
  return this;
28
28
  }
29
+
30
+ map(handler) {
31
+ return this.reduce((accumulator, key, value, index) => {
32
+ accumulator[index] = handler(key, value, index);
33
+ return accumulator;
34
+ }, []);
35
+ }
36
+
37
+ reduce(handler, initialValue) {
38
+ const keys = Object.keys(this);
39
+ let index = 0;
40
+ let accumulator = initialValue;
41
+ for (const key of keys) {
42
+ accumulator = handler(accumulator, key, this[key], index);
43
+ index++;
44
+ }
45
+ return accumulator;
46
+ }
47
+
48
+ forEach(handler) {
49
+ const keys = Object.keys(this);
50
+ for (const key of keys) {
51
+ handler(key, this[key]);
52
+ }
53
+ }
29
54
  }
package/utils/public.js CHANGED
@@ -4,6 +4,7 @@ import Http from "./http";
4
4
  import Type from "./type";
5
5
  import Form from "./form";
6
6
  import Component from "./component";
7
+ import Hash from "./hash";
7
8
 
8
9
  export default class {
9
10
  static get action() {
@@ -24,4 +25,7 @@ export default class {
24
25
  static get component() {
25
26
  return Component;
26
27
  }
28
+ static get Hash() {
29
+ return Hash;
30
+ }
27
31
  }
package/utils/settings.js CHANGED
File without changes
package/utils/storage.js CHANGED
@@ -1,9 +1,8 @@
1
1
  export default class {
2
2
  static setLocal(key, obj) {
3
- localStorage.setItem(key, JSON.stringify(obj))
3
+ localStorage.setItem(key, JSON.stringify(obj));
4
4
  }
5
5
  static getLocal(key) {
6
- return JSON.parse(localStorage.getItem(key))
6
+ return JSON.parse(localStorage.getItem(key));
7
7
  }
8
8
  }
9
-
package/utils/url.js CHANGED
@@ -21,20 +21,22 @@ export default class {
21
21
 
22
22
  static jsonUrl(originalUrl) {
23
23
  if (typeof originalUrl === "string") {
24
- let url = originalUrl;
25
- if (originalUrl.indexOf("?") > -1) {
24
+ const fragments = originalUrl.split("#");
25
+ let url = fragments[0];
26
+ const anchor = fragments[1];
27
+ if (url.indexOf("?") > -1) {
26
28
  if (
27
- originalUrl.indexOf(".json?") == -1 &&
28
- originalUrl.search(/[\&\?]format=json/) == -1
29
+ url.indexOf(".json?") == -1 &&
30
+ url.search(/[\&\?]format=json/) == -1
29
31
  ) {
30
- url = originalUrl + "&format=json";
32
+ url = url + "&format=json";
31
33
  }
32
34
  } else {
33
- if (!originalUrl.endsWith(".json")) {
34
- url = originalUrl + "?format=json";
35
+ if (!url.endsWith(".json")) {
36
+ url = url + "?format=json";
35
37
  }
36
38
  }
37
- return url;
39
+ return anchor ? `${url}#${anchor}` : url;
38
40
  }
39
41
  return "";
40
42
  }