glib-web 3.8.2 → 3.10.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.
Files changed (109) hide show
  1. package/LICENSE +0 -0
  2. package/actions/auth/creditCard.js +0 -0
  3. package/actions/auth/restart.js +0 -0
  4. package/actions/commands/copy.js +0 -0
  5. package/actions/dialogs/close.js +0 -0
  6. package/actions/dialogs/notification.js +0 -0
  7. package/actions/dialogs/oauth.js +0 -0
  8. package/actions/dialogs/open.js +0 -0
  9. package/actions/dialogs/options.js +0 -0
  10. package/actions/dialogs/reload.js +0 -0
  11. package/actions/dialogs/show.js +0 -0
  12. package/actions/forms/submit.js +2 -1
  13. package/actions/http/delete.js +0 -0
  14. package/actions/http/patch.js +0 -0
  15. package/actions/http/post.js +0 -0
  16. package/actions/http/put.js +0 -0
  17. package/actions/runMultiple.js +0 -0
  18. package/actions/sheets/select.js +0 -0
  19. package/actions/snackbars/alert.js +0 -0
  20. package/actions/snackbars/select.js +0 -0
  21. package/actions/timeouts/set.js +0 -0
  22. package/actions/windows/openWeb.js +0 -0
  23. package/actions/windows/print.js +0 -0
  24. package/components/_message.vue +0 -0
  25. package/components/calendar.vue +0 -0
  26. package/components/composable/dirtyState.js +5 -6
  27. package/components/fields/country/countries.js +0 -0
  28. package/components/fields/country/regions.js +0 -0
  29. package/components/fields/creditCard.vue +0 -0
  30. package/components/fields/dynamicGroup.vue +90 -43
  31. package/components/fields/googlePlace.vue +0 -0
  32. package/components/fields/phone/countries.js +0 -0
  33. package/components/fields/phone/sprite.css +0 -0
  34. package/components/fields/stripeToken.vue +0 -0
  35. package/components/h1.vue +0 -0
  36. package/components/h2.vue +0 -0
  37. package/components/h3.vue +0 -0
  38. package/components/h5.vue +0 -0
  39. package/components/h6.vue +0 -0
  40. package/components/hr.vue +0 -0
  41. package/components/html.vue +0 -0
  42. package/components/icon.vue +0 -0
  43. package/components/mixins/chart/annotation.js +0 -0
  44. package/components/mixins/chart/tooltip.js +0 -0
  45. package/components/mixins/dataset.js +0 -0
  46. package/components/mixins/extension.js +0 -0
  47. package/components/mixins/longClick.js +0 -0
  48. package/components/mixins/scrolling.js +0 -0
  49. package/components/mixins/styles.js +6 -0
  50. package/components/mixins/table/export.js +0 -0
  51. package/components/mixins/table/import.js +0 -0
  52. package/components/mixins/text.js +0 -0
  53. package/components/multimedia/video.vue +0 -0
  54. package/components/panels/carousel.vue +0 -0
  55. package/components/panels/form.vue +4 -4
  56. package/components/panels/list.vue +6 -2
  57. package/components/panels/web.vue +0 -0
  58. package/components/spacer.vue +0 -0
  59. package/keys.js +0 -0
  60. package/nav/dialog.vue +4 -3
  61. package/package.json +1 -1
  62. package/static/plugins/alignment/alignment.js +0 -0
  63. package/static/plugins/alignment/alignment.min.js +0 -0
  64. package/static/plugins/beyondgrammar/beyondgrammar.js +0 -0
  65. package/static/plugins/beyondgrammar/beyondgrammar.min.js +0 -0
  66. package/static/plugins/blockcode/blockcode.js +0 -0
  67. package/static/plugins/blockcode/blockcode.min.js +0 -0
  68. package/static/plugins/clips/clips.js +0 -0
  69. package/static/plugins/clips/clips.min.js +0 -0
  70. package/static/plugins/counter/counter.js +0 -0
  71. package/static/plugins/counter/counter.min.js +0 -0
  72. package/static/plugins/definedlinks/definedlinks.js +0 -0
  73. package/static/plugins/definedlinks/definedlinks.min.js +0 -0
  74. package/static/plugins/handle/handle.js +0 -0
  75. package/static/plugins/handle/handle.min.js +0 -0
  76. package/static/plugins/icons/icons.js +0 -0
  77. package/static/plugins/icons/icons.min.js +0 -0
  78. package/static/plugins/imageposition/imageposition.js +0 -0
  79. package/static/plugins/imageposition/imageposition.min.js +0 -0
  80. package/static/plugins/inlineformat/inlineformat.js +0 -0
  81. package/static/plugins/inlineformat/inlineformat.min.js +0 -0
  82. package/static/plugins/removeformat/removeformat.js +0 -0
  83. package/static/plugins/removeformat/removeformat.min.js +0 -0
  84. package/static/plugins/selector/selector.js +0 -0
  85. package/static/plugins/selector/selector.min.js +0 -0
  86. package/static/plugins/specialchars/specialchars.js +0 -0
  87. package/static/plugins/specialchars/specialchars.min.js +0 -0
  88. package/static/plugins/textdirection/textdirection.js +0 -0
  89. package/static/plugins/textdirection/textdirection.min.js +0 -0
  90. package/static/plugins/textexpander/textexpander.js +0 -0
  91. package/static/plugins/textexpander/textexpander.min.js +0 -0
  92. package/static/plugins/underline/underline.js +0 -0
  93. package/static/plugins/underline/underline.min.js +0 -0
  94. package/static/redactorx.css +0 -0
  95. package/static/redactorx.min.css +0 -0
  96. package/static/redactorx.min.js +0 -0
  97. package/static/redactorx.usm.min.js +0 -0
  98. package/store.js +2 -0
  99. package/styles/test.sass +0 -0
  100. package/styles/test.scss +0 -0
  101. package/templates/editable.vue +236 -0
  102. package/templates/thumbnail.vue +21 -10
  103. package/templates/unsupported.vue +0 -0
  104. package/utils/dom.js +0 -0
  105. package/utils/form.js +16 -5
  106. package/utils/helper.js +0 -0
  107. package/utils/http.js +6 -5
  108. package/utils/type.js +0 -0
  109. package/utils/url.js +4 -0
package/LICENSE CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,7 +1,8 @@
1
1
  export default class {
2
2
  execute(properties, component) {
3
3
  component.$dispatchEvent("forms/directSubmit", {
4
- url: properties.overrideUrl
4
+ url: properties.overrideUrl,
5
+ method: properties.overrideMethod
5
6
  })
6
7
  }
7
8
  }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,27 +1,26 @@
1
1
  import { watchEffect } from "vue";
2
- import { vueApp, glibevent, dialogStates } from "../../store";
2
+ import { glibevent, ctx } from "../../store";
3
3
 
4
4
  export function useDirtyState() {
5
- const ctx = dialogStates.slice(-1)[0] || vueApp;
6
5
  const prompt = "Changes you made have not been saved. Are you sure?";
7
6
 
8
7
  const isDirty = () => {
9
- return ctx.isFormDirty && !ctx.isFormSubmitted && !confirm(prompt);
8
+ return ctx().isFormDirty && !ctx().isFormSubmitted && !confirm(prompt);
10
9
  };
11
10
 
12
11
  const clearDirtyState = () => {
13
- ctx.isFormDirty = false;
12
+ ctx().isFormDirty = false;
14
13
  };
15
14
 
16
15
  const updateDirtyState = (val, oldVal, spec) => {
17
16
  if (!spec.disableDirtyCheck && val != oldVal && val != spec.value) {
18
- ctx.isFormDirty = true;
17
+ ctx().isFormDirty = true;
19
18
  }
20
19
  };
21
20
 
22
21
  const watchDirtyState = () => {
23
22
  return watchEffect(() => {
24
- if (ctx.isFormDirty) {
23
+ if (ctx().isFormDirty) {
25
24
  window.onbeforeunload = () => !isDirty();
26
25
  glibevent.onbeforewindowsopen = () => !isDirty();
27
26
  glibevent.onbeforewindowsclose = () => !isDirty();
File without changes
File without changes
File without changes
@@ -4,7 +4,7 @@
4
4
  <input v-if="isDeleted(groupIndex)" type="hidden" :name="`${spec.name}[${groupIndex}][_destroy]`" value="1" />
5
5
  <div :style="{ display: isDeleted(groupIndex) ? 'none' : 'block' }">
6
6
  <v-icon class="float-left mr-2" color="error" @click="removeGroup(groupIndex)">remove_circle</v-icon>
7
- <h4 v-if="spec.titlePrefix">{{ spec.titlePrefix }} {{ groupIndex + 1 }}</h4>
7
+ <h4 v-if="spec.titlePrefix">{{ spec.titlePrefix }}{{ group.actualIndex }}</h4>
8
8
  <panels-responsive :spec="group" />
9
9
  </div>
10
10
  </div>
@@ -22,46 +22,47 @@ export default {
22
22
  return {
23
23
  groupValues: [],
24
24
  template: {},
25
- templateViews: []
25
+ templateViews: [],
26
+ groupSpecs: []
26
27
  };
27
28
  },
28
- computed: {
29
- groupSpecs() {
30
- return this.groupValues.map((group, groupIndex) => {
31
- const viewSpecs = this.processTemplate(
32
- this.mapFieldProperties(group),
33
- groupIndex,
34
- (viewSpec, name, properties) => {
35
- // Always reattach the data model to avoid losing entered data.
36
- return Object.assign({}, viewSpec, properties, {
37
- name: name,
38
- value: this.$data._fieldModels[name]
39
- });
29
+ watch: {
30
+ spec: {
31
+ handler(spec) {
32
+ this.template = spec.template;
33
+ this.templateViews = this.template.childViews || [];
34
+
35
+ spec.groupFieldProperties.forEach((group, groupIndex) => {
36
+ group.forEach((properties) => {
37
+ const fullName = this.prefixFieldName(groupIndex, properties.name)
38
+ this.setFieldModel(fullName, properties.value)
39
+ })
40
+ });
41
+
42
+ this.groupValues = spec.groupFieldProperties;
43
+ },
44
+ immediate: true
45
+ },
46
+ groupValues: {
47
+ handler(groupValues) {
48
+ var actualIndex = 0
49
+ this.groupSpecs = groupValues.map((group, groupIndex) => {
50
+ if (!this.isDeleted(groupIndex)) {
51
+ ++actualIndex
40
52
  }
41
- );
42
- return Object.assign({}, this.template, { childViews: viewSpecs });
43
- });
53
+
54
+ const viewSpecs = this.processTemplate(
55
+ this.mapFieldProperties(group),
56
+ groupIndex
57
+ );
58
+ return Object.assign({}, this.template, { childViews: viewSpecs, actualIndex: actualIndex });
59
+ });
60
+ },
61
+ immediate: true,
62
+ deep: true // Watch insertion and deletion
44
63
  }
45
64
  },
46
65
  methods: {
47
- $ready() {
48
- // this.groupValues = this.spec.value;
49
- this.groupValues = this.spec.groupFieldProperties;
50
-
51
- this.template = this.spec.template;
52
- this.templateViews = this.template.childViews || [];
53
-
54
- this.groupValues.forEach((group, groupIndex) => {
55
- this.processTemplate(
56
- this.mapFieldProperties(group),
57
- groupIndex,
58
- (viewSpec, fullName, properties) => {
59
- // this.$data._fieldModels[name] = group[viewSpec.name];
60
- this.$data._fieldModels[fullName] = properties.value;
61
- }
62
- );
63
- });
64
- },
65
66
  mapFieldProperties(group) {
66
67
  const fieldProperties = {};
67
68
  group.forEach(field => {
@@ -69,14 +70,60 @@ export default {
69
70
  });
70
71
  return fieldProperties;
71
72
  },
72
- processTemplate(properties, groupIndex, process) {
73
- return this.templateViews.map(viewSpec => {
74
- if (Utils.type.isString(viewSpec.name)) {
75
- // Process only if it is a field
76
- const fullName = `${this.spec.name}[${groupIndex}][${viewSpec.name}]`;
77
- return process(viewSpec, fullName, properties[viewSpec.name] || {});
73
+ // Replace every occurrence of `{{index}}` within any string.
74
+ populateIndexes(object, groupIndex) {
75
+ if (this.$type.isString(object)) {
76
+ return object.replace('{{index}}', groupIndex)
77
+ }
78
+ if (this.$type.isArray(object)) {
79
+ return object.map((o) => this.populateIndexes(o, groupIndex));
80
+
81
+ } else if (this.$type.isObject(object)) {
82
+ const newObject = {}
83
+ for (const key in object) {
84
+ newObject[key] = this.populateIndexes(object[key], groupIndex)
85
+ }
86
+ return newObject
87
+ }
88
+ return object
89
+ },
90
+ processTemplate(properties, groupIndex, processField, processNonField) {
91
+ return this.processViews(
92
+ this.templateViews, properties, groupIndex, processField, processNonField
93
+ )
94
+ },
95
+ prefixFieldName(groupIndex, fieldName) {
96
+ if (fieldName.search(/\[.*\]/) >= 0) {
97
+ return `${this.spec.name}[${groupIndex}]${fieldName}`;
98
+ } else {
99
+ return `${this.spec.name}[${groupIndex}][${fieldName}]`;
100
+ }
101
+ },
102
+ processField(viewSpec, name, groupIndex) {
103
+ const indexedName = this.populateIndexes(name, groupIndex)
104
+ Object.assign(viewSpec, {
105
+ name: indexedName,
106
+ value: this.getFieldModel(indexedName)
107
+ });
108
+ return viewSpec
109
+ },
110
+ processViews(viewSpecs, properties, groupIndex) {
111
+ return viewSpecs.map(origSpec => {
112
+ const viewSpec = Object.assign({}, origSpec)
113
+
114
+ viewSpec.showIf = this.populateIndexes(viewSpec.showIf, groupIndex)
115
+ viewSpec.loadIf = this.populateIndexes(viewSpec.loadIf, groupIndex)
116
+
117
+ if (Utils.type.isString(viewSpec.name)) { // This is a field
118
+ const fullName = this.prefixFieldName(groupIndex, viewSpec.name)
119
+ return this.processField(viewSpec, fullName, groupIndex);
78
120
  }
79
- return viewSpec;
121
+
122
+ if (Utils.type.isObject(viewSpec.childViews)) {
123
+ viewSpec.childViews = this.processViews(viewSpec.childViews, properties, groupIndex)
124
+ }
125
+
126
+ return viewSpec
80
127
  });
81
128
  },
82
129
  addGroup() {
@@ -87,7 +134,7 @@ export default {
87
134
  {},
88
135
  () => {
89
136
  // Don't delete the group in order to maintain consistent indexes between model and view.
90
- this.$set(this.groupValues[index], "_destroy", 1);
137
+ Object.assign(this.groupValues[index], { _destroy: 1 });
91
138
  },
92
139
  this
93
140
  );
File without changes
File without changes
File without changes
File without changes
package/components/h1.vue CHANGED
File without changes
package/components/h2.vue CHANGED
File without changes
package/components/h3.vue CHANGED
File without changes
package/components/h5.vue CHANGED
File without changes
package/components/h6.vue CHANGED
File without changes
package/components/hr.vue CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -114,6 +114,12 @@ export default {
114
114
  genericStyles(spec) {
115
115
  return this.$styles(spec);
116
116
  },
117
+ setFieldModel(name, value) {
118
+ fieldModels[name] = value;
119
+ },
120
+ getFieldModel(name) {
121
+ return fieldModels[name];
122
+ },
117
123
  // _checkDirtyState(val, oldVal) {
118
124
  // const dirtyCheckEnabled = !this.spec.disableDirtyCheck;
119
125
  // // Make sure value has changed and make sure that it is different from the original value.
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -86,7 +86,7 @@ export default {
86
86
  });
87
87
 
88
88
  this.$onEvent("forms/directSubmit", (e) => {
89
- this.directSubmit(e.data.url);
89
+ this.directSubmit(e.data.url, e.data.method);
90
90
  });
91
91
  },
92
92
  $ready() {
@@ -141,9 +141,9 @@ export default {
141
141
  );
142
142
  });
143
143
  },
144
- directSubmit(overrideUrl = null) {
145
- if (overrideUrl) {
146
- GLib.form.submitData(this.formElement, this, overrideUrl);
144
+ directSubmit(overrideUrl = null, overrideMethod = null) {
145
+ if (overrideUrl || overrideMethod) {
146
+ GLib.form.submitData(this.formElement, this, overrideUrl, overrideMethod);
147
147
  } else {
148
148
  this.validate(() => {
149
149
  GLib.form.submitData(this.formElement, this);
@@ -20,7 +20,7 @@
20
20
  :data-dragSectionIndex="sectionIndex" :disabled="!$type.isObject(dragSupport)" @start="onDragStart"
21
21
  @end="onDragEnd" item-key="id">
22
22
  <template #item="{ element }">
23
- <component :is="template(element)" :spec="rowSpec(element)" :responsive-cols="spec.responsiveCols"
23
+ <component :is="template(element)" :spec="element" :responsive-cols="spec.responsiveCols"
24
24
  :data-dragRowId="element.id" />
25
25
  </template>
26
26
  </draggable>
@@ -48,6 +48,7 @@ import { vueApp } from "../../store";
48
48
  import draggable from "vuedraggable";
49
49
  import autoloadMixin from "../mixins/list/autoload.js";
50
50
  import ThumbnailTemplate from "../../templates/thumbnail.vue";
51
+ import EditableTemplate from "../../templates/editable.vue";
51
52
  import FeaturedTemplate from "../../templates/featured.vue";
52
53
  import CommentTemplate from "../../templates/comment.vue";
53
54
 
@@ -55,6 +56,7 @@ export default {
55
56
  components: {
56
57
  draggable,
57
58
  "template-thumbnail": ThumbnailTemplate,
59
+ "template-editable": EditableTemplate,
58
60
  "template-featured": FeaturedTemplate,
59
61
  "template-commentOutgoing": CommentTemplate,
60
62
  "template-commentIncoming": CommentTemplate,
@@ -83,7 +85,9 @@ export default {
83
85
  this.enableInfiniteScrollIfApplicable(spec);
84
86
 
85
87
  for (const section of this.sections) {
86
- section.rows = section.rows || [];
88
+ section.rows = (section.rows || []).map((row) => {
89
+ return this.rowSpec(row)
90
+ })
87
91
  }
88
92
  },
89
93
  immediate: true
File without changes
File without changes
package/keys.js CHANGED
File without changes
package/nav/dialog.vue CHANGED
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <v-dialog :model-value="model" :width="spec.width || 600" :dark="false" :fullscreen="fullscreen" :sm-and-down="false"
2
+ <v-dialog class="dialog-container" :model-value="model" :width="spec.width || 600" :dark="false" :fullscreen="fullscreen" :sm-and-down="false"
3
3
  :persistent="true" @click:outside="clickOutside">
4
4
  <v-card :style="hamburgerStyles" class="hamburger">
5
5
 
@@ -15,7 +15,7 @@
15
15
  </v-btn>
16
16
  </div>
17
17
 
18
- <div class="dialogs-body relative">
18
+ <div class="dialog-body relative">
19
19
  <component :is="containerComponent" :spec="formSpec">
20
20
  <div v-if="message" class="dialog-message">
21
21
  <common-message :spec="{ message: message }" />
@@ -209,7 +209,8 @@ export default {
209
209
  }
210
210
 
211
211
  .dialog-message {
212
- padding: 16px 16px 20px 16px;
212
+ padding: 0px 20px;
213
+ //padding: 16px 16px 20px 16px;
213
214
  /* white-space: pre-wrap; */
214
215
  }
215
216
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glib-web",
3
- "version": "3.8.2",
3
+ "version": "3.10.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/store.js CHANGED
@@ -19,6 +19,8 @@ export const vueApp = reactive({
19
19
 
20
20
  export const dialogStates = reactive([]);
21
21
 
22
+ export const ctx = () => dialogStates.slice(-1)[0] || vueApp;
23
+
22
24
  export const glibevent = reactive({
23
25
  onbeforewindowsopen: null,
24
26
  onbeforewindowsclose: null,
package/styles/test.sass CHANGED
File without changes
package/styles/test.scss CHANGED
File without changes
@@ -0,0 +1,236 @@
1
+ <template>
2
+ <component :is="componentName" :href="$href()" class="thumbnail" :class="cssClasses" @[clickCondition]="$onClick()">
3
+ <panels-responsive :spec="spec.header" />
4
+ <div style="display:flex;">
5
+ <!-- <div v-if="spec.leftOuterButtons" style="display:flex; margin-top:10px;">
6
+ <template v-for="(item, index) in spec.leftOuterButtons" :key="index">
7
+ <common-button
8
+ :spec="buttonSpec(item)"
9
+ :disabled="$isBusy"
10
+ />
11
+ </template>
12
+ </div> -->
13
+
14
+ <v-list-item v-longclick="$onLongPress" class="item-content" :style="columnStyles()">
15
+ <!-- <v-icon v-if="spec.onReorder" class="handle">drag_indicator</v-icon> -->
16
+
17
+ <!-- Specify a key to prevent reuse which causes an issue where the checkbox would use the previous name. -->
18
+ <fields-check v-if="checkSpec" :key="checkSpec.name" :spec="checkSpec" />
19
+
20
+ <template v-slot:prepend>
21
+ <div style="display: flex">
22
+ <div v-if="spec.leftButtons">
23
+ <template v-for="(item, index) in spec.leftButtons" :key="index">
24
+ <glib-button :spec="buttonSpec(item)" :disabled="$isBusy" />
25
+ </template>
26
+ </div>
27
+
28
+ <common-icon v-if="spec.icon" :spec="spec.icon" />
29
+ </div>
30
+ </template>
31
+
32
+ <!-- <v-list-item-avatar
33
+ v-if="$type.isString(spec.imageUrl)"
34
+ :tile="!spec.avatar"
35
+ style="display:flex;"
36
+ class="left-thumbnail"
37
+ :size="spec.imageSize"
38
+ >
39
+ <img :src="spec.imageUrl" />
40
+ </v-list-item-avatar> -->
41
+
42
+ <!-- <div v-else class="left-icon">
43
+ <v-list-item-avatar v-if="$type.isObject(spec.icon)">
44
+ <common-icon :spec="spec.icon" />
45
+ </v-list-item-avatar>
46
+ </div> -->
47
+
48
+ <div>
49
+ <v-text-field v-if="spec.fieldTitleName" :name="spec.fieldTitleName" :value="spec.title" />
50
+ <v-list-item-title v-else>{{ spec.title }}</v-list-item-title>
51
+
52
+ <v-list-item-subtitle v-if="spec.subtitle">{{
53
+ spec.subtitle
54
+ }}</v-list-item-subtitle>
55
+ <v-list-item-subtitle v-if="spec.subsubtitle">{{
56
+ spec.subsubtitle
57
+ }}</v-list-item-subtitle>
58
+
59
+ <div v-if="hasChips" class="chips">
60
+ <template v-for="(item, index) in chips" :key="index">
61
+ <common-chip :spec="item" />
62
+ </template>
63
+ </div>
64
+
65
+ <panels-responsive v-if="spec.body" :spec="spec.body" />
66
+ </div>
67
+
68
+ <template v-slot:append>
69
+ <template v-for="(item, index) in spec.rightButtons" :key="index">
70
+ <glib-button :spec="buttonSpec(item)" :disabled="$isBusy" />
71
+ </template>
72
+ </template>
73
+
74
+ </v-list-item>
75
+ <panels-responsive :spec="spec.right" />
76
+ </div>
77
+ <panels-responsive :spec="spec.footer" />
78
+ </component>
79
+ </template>
80
+
81
+ <script>
82
+ import CheckField from "../components/fields/check.vue";
83
+
84
+ export default {
85
+ components: {
86
+ "fields-check": CheckField
87
+ },
88
+ props: {
89
+ spec: { type: Object, required: true },
90
+ responsiveCols: { type: Number, default: () => 0 }
91
+ },
92
+ data() {
93
+ return {
94
+ // editButtons: []
95
+ };
96
+ },
97
+ computed: {
98
+ componentName() {
99
+ // Use `a` to enable "open in new tab".
100
+ return this.clickCondition ? "a" : "div";
101
+ // return "div"
102
+ },
103
+ cssClasses() {
104
+ return this.$classes(this.spec, "templates/thumbnail");
105
+ },
106
+ clickCondition() {
107
+ if (this.spec.onClick || this.spec.onLongPress) {
108
+ // This will show the clickable indication
109
+ return "click";
110
+ }
111
+ return null;
112
+ },
113
+ hasChips() {
114
+ return this.spec.chips && this.spec.chips.length > 0;
115
+ },
116
+ // Implemented as computed so that it gets reflected when reordering
117
+ chips() {
118
+ return (this.spec.chips || []).map(item => {
119
+ var color = null;
120
+ this.$type.ifArray(item.styleClasses, classes => {
121
+ for (const val of ["success", "info", "warning", "error"]) {
122
+ if (classes.includes(val)) {
123
+ color = val;
124
+ }
125
+ }
126
+ });
127
+ return Object.assign({}, item, { color: color, view: "chip" });
128
+ });
129
+ },
130
+ // Implemented as computed so that it gets reflected when navigating to another list containing check fields.
131
+ checkSpec() {
132
+ if (this.spec.fieldCheckName) {
133
+ return {
134
+ view: "fields/checkGroup",
135
+ name: this.spec.fieldCheckName,
136
+ checkValue: true,
137
+ valueIf: this.spec.fieldCheckValueIf,
138
+ padding: { left: 16 }
139
+ };
140
+ }
141
+ return null;
142
+ }
143
+ // cssStyles() {
144
+ // const styles = this.$styles();
145
+ // // switch(this.spec.align) {
146
+ // // case 'middle':
147
+ // // styles['align-items'] = 'center'
148
+ // // break
149
+ // // case 'bottom':
150
+ // // styles['align-items'] = 'flex-end'
151
+ // // break
152
+ // // default:
153
+ // // styles['align-items'] = 'flex-start'
154
+ // // }
155
+ // return styles;
156
+ // },
157
+ },
158
+ methods: {
159
+ $ready() {
160
+ // this.editButtons = this.spec.editButtons || [];
161
+ },
162
+ buttonSpec(item) {
163
+ // Classes should be coming from the backend
164
+ // const styleClasses = ["text", "x-small"]
165
+ // if (!item.text) {
166
+ // styleClasses.push("icon")
167
+ // }
168
+
169
+ return Object.assign({}, item, {
170
+ view: "button"
171
+ });
172
+ },
173
+ columnStyles() {
174
+ if (this.responsiveCols) {
175
+ return `width: ${100 / this.responsiveCols}%; float: left;`;
176
+ }
177
+ }
178
+ }
179
+ };
180
+ </script>
181
+
182
+ <style lang="scss">
183
+ .chips>* {
184
+ margin-right: 10px;
185
+ }
186
+
187
+ .v-list-item__content {
188
+ width: 100%;
189
+ }
190
+
191
+ .thumbnail {
192
+
193
+ // Override this when using the `right` property.
194
+ .item-content {
195
+ width: 100%;
196
+ }
197
+ }
198
+ </style>
199
+
200
+ <style lang="scss" scoped>
201
+ a.thumbnail {
202
+ color: inherit;
203
+ text-decoration: inherit;
204
+ display: block;
205
+ }
206
+
207
+ .item-content {
208
+ display: flex;
209
+
210
+ &.v-list-item--density-default:not(.v-list-item--nav).v-list-item--one-line {
211
+ padding-inline-start: 0;
212
+ padding-inline-end: 0;
213
+ }
214
+ }
215
+
216
+ @media (min-width: 600px) {
217
+ .left-thumbnail.v-avatar.v-list-item__avatar {
218
+ margin: 6px 6px 6px 6px;
219
+ width: 60px;
220
+ height: 60px;
221
+ }
222
+
223
+ .left-icon {
224
+ // margin-left: 16px;
225
+ margin-left: 4px;
226
+ }
227
+
228
+ // .left-universal {
229
+ // padding-left: 16px;
230
+ // }
231
+ // .handle {
232
+ // // margin-left: 10px;
233
+ // cursor: move;
234
+ // }
235
+ }
236
+ </style>
@@ -14,11 +14,11 @@
14
14
  <v-list-item v-longclick="$onLongPress" class="item-content" :style="columnStyles()">
15
15
  <!-- <v-icon v-if="spec.onReorder" class="handle">drag_indicator</v-icon> -->
16
16
 
17
- <!-- Specify a key to prevent reuse which causes an issue where the checkbox would use the previous name. -->
18
- <fields-check v-if="checkSpec" :key="checkSpec.name" :spec="checkSpec" />
19
-
20
17
  <template v-slot:prepend>
21
18
  <div style="display: flex">
19
+ <!-- Specify a key to prevent reuse which causes an issue where the checkbox would use the previous name. -->
20
+ <fields-check v-if="checkSpec" :key="checkSpec.name" :spec="checkSpec" />
21
+
22
22
  <div v-if="spec.leftButtons">
23
23
  <template v-for="(item, index) in spec.leftButtons" :key="index">
24
24
  <glib-button :spec="buttonSpec(item)" :disabled="$isBusy" />
@@ -46,8 +46,7 @@
46
46
  </div> -->
47
47
 
48
48
  <div>
49
- <v-text-field v-if="spec.fieldTitleName" :name="spec.fieldTitleName" :value="spec.title" />
50
- <v-list-item-title v-else>{{ spec.title }}</v-list-item-title>
49
+ <v-list-item-title>{{ spec.title }}</v-list-item-title>
51
50
 
52
51
  <v-list-item-subtitle v-if="spec.subtitle">{{
53
52
  spec.subtitle
@@ -71,8 +70,6 @@
71
70
  </template>
72
71
  </template>
73
72
 
74
- <!-- Deprecated -->
75
- <!-- <templates-menu :edit-buttons="editButtons" /> -->
76
73
  </v-list-item>
77
74
  <panels-responsive :spec="spec.right" />
78
75
  </div>
@@ -93,9 +90,24 @@ export default {
93
90
  },
94
91
  data() {
95
92
  return {
96
- // editButtons: []
93
+ // checkSpec: null
97
94
  };
98
95
  },
96
+ // watch: {
97
+ // spec: {
98
+ // handler(spec) {
99
+ // if (this.spec.fieldCheckName) {
100
+ // this.checkSpec = {
101
+ // view: "fields/checkGroup",
102
+ // name: this.spec.fieldCheckName,
103
+ // checkValue: true,
104
+ // valueIf: this.spec.fieldCheckValueIf
105
+ // };
106
+ // }
107
+ // },
108
+ // immediate: true
109
+ // }
110
+ // },
99
111
  computed: {
100
112
  componentName() {
101
113
  // Use `a` to enable "open in new tab".
@@ -136,8 +148,7 @@ export default {
136
148
  view: "fields/checkGroup",
137
149
  name: this.spec.fieldCheckName,
138
150
  checkValue: true,
139
- valueIf: this.spec.fieldCheckValueIf,
140
- padding: { left: 16 }
151
+ valueIf: this.spec.fieldCheckValueIf
141
152
  };
142
153
  }
143
154
  return null;
File without changes
package/utils/dom.js CHANGED
File without changes
package/utils/form.js CHANGED
@@ -1,22 +1,33 @@
1
- import { vueApp } from "../store";
1
+ import { ctx } from "../store";
2
2
 
3
3
  export default class {
4
4
  // Execution flows:
5
5
  // Button -> Button.onClick() -> Utils.http.execute() -- doesn't save autofill values
6
6
  // Button -> Button.onClick() -> form.submit() -- doesn't execute Form.onSubmit(), so cannot call Utils.http.execute() there
7
7
  // Submit -> Form.onSubmit() -> Utils.http.execute() -- save autofill values and auto-submit when ENTER is pressed
8
- static submitData(form, component, overrideUrl = null) {
8
+ static submitData(form, component, overrideUrl = null, overrideMethod = null) {
9
9
  // Analogous to Rails' form_with's `local: true`
10
10
  if (form.dataset.local) {
11
+ if (overrideUrl) {
12
+ component.$data.url = overrideUrl
13
+ }
14
+
11
15
  // Prevent onUnload dirty prompt.
12
16
  // Utils.http.clearDirtyState();
13
- vueApp.isFormDirty = false;
14
- form.submit();
17
+
18
+ // Use nextTick to wait for overrideUrl get picked up.
19
+ component.$nextTick(() => {
20
+ ctx().isFormDirty = false;
21
+ form.submit();
22
+ });
15
23
  } else {
16
24
  const url = overrideUrl ? overrideUrl : form.getAttribute("action");
17
25
  const formData = new FormData(form);
18
- const method = form.getAttribute("method");
26
+ const method = overrideMethod ? overrideMethod : form.getAttribute("method");
27
+
19
28
  if (method.toUpperCase() === "GET") {
29
+ // Don't include this token in GET requests.
30
+ formData.delete("authenticity_token")
20
31
  const data = {
21
32
  url: Utils.url.appendParams(url, formData)
22
33
  };
package/utils/helper.js CHANGED
File without changes
package/utils/http.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import Type from "./type";
2
2
  import Action from "../action";
3
3
  import { nextTick } from 'vue';
4
- import { vueApp } from "../store";
4
+ import { ctx, vueApp } from "../store";
5
5
 
6
6
  let loading = false;
7
7
 
@@ -137,7 +137,8 @@ export default class {
137
137
  static reload(properties, component) {
138
138
  const currentUrl = window.location.href;
139
139
  const data = {
140
- url: properties.url || currentUrl
140
+ url: properties.url || currentUrl,
141
+ formData: properties.formData
141
142
  };
142
143
 
143
144
  Utils.http.execute(data, "GET", component, (page, response) => {
@@ -257,8 +258,8 @@ export default class {
257
258
  static forceComponentUpdate(handler) {
258
259
  // GLib.component.clearRegistry();
259
260
  vueApp.isStale = true;
260
- vueApp.isFormSubmitted = false;
261
- vueApp.isFormDirty = false;
261
+ ctx().isFormSubmitted = false;
262
+ ctx().isFormDirty = false;
262
263
  handler();
263
264
 
264
265
  // Queue the execution so the first isStale has time to resets state before handler gets executed
@@ -272,7 +273,7 @@ export default class {
272
273
  // }
273
274
 
274
275
  static notifyFormSubmitted() {
275
- vueApp.isFormSubmitted = true;
276
+ ctx().isFormSubmitted = true;
276
277
  }
277
278
 
278
279
  // `context` can be either window or dialog.
package/utils/type.js CHANGED
File without changes
package/utils/url.js CHANGED
@@ -100,6 +100,10 @@ export default class {
100
100
 
101
101
  // // https://gist.github.com/pirate/9298155edda679510723
102
102
  static _extractUrlParams(search) {
103
+ if (search.indexOf("?") <= -1) {
104
+ return {};
105
+ }
106
+
103
107
  const hashes = search.slice(search.indexOf("?") + 1).split("&");
104
108
  return hashes.reduce((params, hash) => {
105
109
  const split = hash.indexOf("=");