glib-web 0.5.77

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 (204) hide show
  1. package/.eslintrc.js +37 -0
  2. package/LICENSE +201 -0
  3. package/README.md +33 -0
  4. package/action.js +167 -0
  5. package/actions/analytics/logEvent.js +26 -0
  6. package/actions/auth/creditCard.js +29 -0
  7. package/actions/auth/restart.js +5 -0
  8. package/actions/auth/saveCsrfToken.js +12 -0
  9. package/actions/cables/push.js +38 -0
  10. package/actions/dialogs/alert.js +15 -0
  11. package/actions/dialogs/close.js +7 -0
  12. package/actions/dialogs/notification.js +14 -0
  13. package/actions/dialogs/oauth.js +6 -0
  14. package/actions/dialogs/open.js +7 -0
  15. package/actions/dialogs/options.js +5 -0
  16. package/actions/dialogs/show.js +5 -0
  17. package/actions/forms/submit.js +15 -0
  18. package/actions/http/delete.js +7 -0
  19. package/actions/http/patch.js +7 -0
  20. package/actions/http/post.js +7 -0
  21. package/actions/http/put.js +7 -0
  22. package/actions/panels/scrollTo.js +18 -0
  23. package/actions/panels/scrollToBottom.js +11 -0
  24. package/actions/runMultiple.js +11 -0
  25. package/actions/sheets/select.js +5 -0
  26. package/actions/snackbars/alert.js +15 -0
  27. package/actions/snackbars/select.js +5 -0
  28. package/actions/timeouts/set.js +20 -0
  29. package/actions/windows/close.js +13 -0
  30. package/actions/windows/closeAll.js +16 -0
  31. package/actions/windows/closeWithReload.js +18 -0
  32. package/actions/windows/open.js +5 -0
  33. package/actions/windows/openWeb.js +5 -0
  34. package/actions/windows/refreshState.js +5 -0
  35. package/actions/windows/reload.js +24 -0
  36. package/actions/ws/push.js +35 -0
  37. package/app.vue +180 -0
  38. package/components/_button.vue +101 -0
  39. package/components/_dropdownMenu.vue +76 -0
  40. package/components/_icon.vue +50 -0
  41. package/components/_message.vue +25 -0
  42. package/components/avatar.vue +16 -0
  43. package/components/banners/alert.vue +49 -0
  44. package/components/banners/select.vue +82 -0
  45. package/components/button.vue +13 -0
  46. package/components/calendar.vue +105 -0
  47. package/components/charts/column.vue +26 -0
  48. package/components/charts/line.vue +61 -0
  49. package/components/chip.vue +24 -0
  50. package/components/component.vue +222 -0
  51. package/components/datetime.vue +54 -0
  52. package/components/fab.vue +33 -0
  53. package/components/fields/_patternText.vue +61 -0
  54. package/components/fields/_select.vue +86 -0
  55. package/components/fields/autocomplete.vue +73 -0
  56. package/components/fields/check.vue +104 -0
  57. package/components/fields/checkGroup.vue +51 -0
  58. package/components/fields/country/countries.js +251 -0
  59. package/components/fields/country/field.vue +81 -0
  60. package/components/fields/country/regions.js +12 -0
  61. package/components/fields/creditCard.vue +105 -0
  62. package/components/fields/date.vue +24 -0
  63. package/components/fields/datetime.vue +49 -0
  64. package/components/fields/dynamicGroup.vue +106 -0
  65. package/components/fields/dynamicSelect.vue +173 -0
  66. package/components/fields/file.vue +166 -0
  67. package/components/fields/googlePlace.vue +158 -0
  68. package/components/fields/hidden.vue +18 -0
  69. package/components/fields/location.vue +223 -0
  70. package/components/fields/newRichText.vue +191 -0
  71. package/components/fields/phone/countries.js +315 -0
  72. package/components/fields/phone/field.vue +348 -0
  73. package/components/fields/phone/sprite.css +1071 -0
  74. package/components/fields/radio.vue +64 -0
  75. package/components/fields/radioGroup.vue +93 -0
  76. package/components/fields/rating.vue +26 -0
  77. package/components/fields/richText.vue +172 -0
  78. package/components/fields/select.vue +17 -0
  79. package/components/fields/stripe/stripeFields.vue +93 -0
  80. package/components/fields/stripe/stripeIndividualFields.vue +207 -0
  81. package/components/fields/stripeExternalAccount.vue +135 -0
  82. package/components/fields/stripeToken.vue +59 -0
  83. package/components/fields/submit.vue +23 -0
  84. package/components/fields/text.vue +144 -0
  85. package/components/fields/textarea.vue +59 -0
  86. package/components/fields/timeZone.vue +22 -0
  87. package/components/fields/timer.vue +83 -0
  88. package/components/h1.vue +28 -0
  89. package/components/h2.vue +20 -0
  90. package/components/h3.vue +22 -0
  91. package/components/h4.vue +20 -0
  92. package/components/h5.vue +20 -0
  93. package/components/h6.vue +20 -0
  94. package/components/hr.vue +13 -0
  95. package/components/html.vue +13 -0
  96. package/components/icon.vue +25 -0
  97. package/components/image.vue +87 -0
  98. package/components/label.vue +62 -0
  99. package/components/map.vue +206 -0
  100. package/components/markdown.vue +52 -0
  101. package/components/mixins/events.js +178 -0
  102. package/components/mixins/generic.js +58 -0
  103. package/components/mixins/list/autoload.js +144 -0
  104. package/components/mixins/longClick.js +56 -0
  105. package/components/mixins/scrolling.js +35 -0
  106. package/components/mixins/styles.js +221 -0
  107. package/components/mixins/table/autoload.js +131 -0
  108. package/components/mixins/table/export.js +52 -0
  109. package/components/mixins/table/import.js +106 -0
  110. package/components/mixins/text.js +20 -0
  111. package/components/mixins/ws/actionCable.js +48 -0
  112. package/components/mixins/ws/phoenixSocket.js +117 -0
  113. package/components/p.vue +36 -0
  114. package/components/panels/carousel.vue +55 -0
  115. package/components/panels/column.vue +117 -0
  116. package/components/panels/custom.vue +52 -0
  117. package/components/panels/flow.vue +81 -0
  118. package/components/panels/form.vue +126 -0
  119. package/components/panels/horizontal.vue +73 -0
  120. package/components/panels/list.vue +241 -0
  121. package/components/panels/responsive.vue +88 -0
  122. package/components/panels/scroll.vue +68 -0
  123. package/components/panels/split.vue +52 -0
  124. package/components/panels/table.vue +234 -0
  125. package/components/panels/ul.vue +34 -0
  126. package/components/panels/vertical.vue +71 -0
  127. package/components/panels/web.vue +11 -0
  128. package/components/spacer.vue +11 -0
  129. package/components/switch.vue +42 -0
  130. package/components/tabBar.vue +44 -0
  131. package/extensions/array.js +20 -0
  132. package/extensions/string.js +21 -0
  133. package/index.js +195 -0
  134. package/keys.js +12 -0
  135. package/nav/appbar.vue +117 -0
  136. package/nav/content.vue +40 -0
  137. package/nav/dialog.vue +127 -0
  138. package/nav/drawer.vue +88 -0
  139. package/nav/drawerButton.vue +28 -0
  140. package/nav/drawerLabel.vue +21 -0
  141. package/nav/sheet.vue +57 -0
  142. package/nav/snackbar.vue +72 -0
  143. package/package.json +42 -0
  144. package/settings.json.example +21 -0
  145. package/static/plugins/alignment/alignment.js +76 -0
  146. package/static/plugins/alignment/alignment.min.js +1 -0
  147. package/static/plugins/beyondgrammar/beyondgrammar.js +46 -0
  148. package/static/plugins/beyondgrammar/beyondgrammar.min.js +1 -0
  149. package/static/plugins/blockcode/blockcode.js +110 -0
  150. package/static/plugins/blockcode/blockcode.min.js +1 -0
  151. package/static/plugins/clips/clips.js +44 -0
  152. package/static/plugins/clips/clips.min.js +1 -0
  153. package/static/plugins/counter/counter.js +60 -0
  154. package/static/plugins/counter/counter.min.js +1 -0
  155. package/static/plugins/definedlinks/definedlinks.js +64 -0
  156. package/static/plugins/definedlinks/definedlinks.min.js +1 -0
  157. package/static/plugins/handle/handle.js +173 -0
  158. package/static/plugins/handle/handle.min.js +1 -0
  159. package/static/plugins/icons/icons.js +72 -0
  160. package/static/plugins/icons/icons.min.js +1 -0
  161. package/static/plugins/imageposition/imageposition.js +85 -0
  162. package/static/plugins/imageposition/imageposition.min.js +1 -0
  163. package/static/plugins/inlineformat/inlineformat.js +85 -0
  164. package/static/plugins/inlineformat/inlineformat.min.js +1 -0
  165. package/static/plugins/removeformat/removeformat.js +28 -0
  166. package/static/plugins/removeformat/removeformat.min.js +1 -0
  167. package/static/plugins/selector/selector.js +96 -0
  168. package/static/plugins/selector/selector.min.js +1 -0
  169. package/static/plugins/specialchars/specialchars.js +63 -0
  170. package/static/plugins/specialchars/specialchars.min.js +1 -0
  171. package/static/plugins/textdirection/textdirection.js +55 -0
  172. package/static/plugins/textdirection/textdirection.min.js +1 -0
  173. package/static/plugins/textexpander/textexpander.js +46 -0
  174. package/static/plugins/textexpander/textexpander.min.js +1 -0
  175. package/static/plugins/underline/underline.js +27 -0
  176. package/static/plugins/underline/underline.min.js +1 -0
  177. package/static/redactorx.css +1344 -0
  178. package/static/redactorx.js +14254 -0
  179. package/static/redactorx.min.css +1 -0
  180. package/static/redactorx.min.js +1 -0
  181. package/static/redactorx.usm.min.js +2 -0
  182. package/styles/test.sass +3 -0
  183. package/styles/test.scss +5 -0
  184. package/templates/_menu.vue +38 -0
  185. package/templates/comment.vue +202 -0
  186. package/templates/featured.vue +32 -0
  187. package/templates/thumbnail.vue +138 -0
  188. package/templates/unsupported.vue +12 -0
  189. package/utils/app.js +14 -0
  190. package/utils/dom.js +13 -0
  191. package/utils/form.js +34 -0
  192. package/utils/format.js +14 -0
  193. package/utils/hash.js +29 -0
  194. package/utils/helper.js +44 -0
  195. package/utils/history.js +70 -0
  196. package/utils/http.js +209 -0
  197. package/utils/launch.js +135 -0
  198. package/utils/private/ws.js +22 -0
  199. package/utils/public.js +23 -0
  200. package/utils/settings.js +48 -0
  201. package/utils/storage.js +9 -0
  202. package/utils/type.js +69 -0
  203. package/utils/uploader.js +121 -0
  204. package/utils/url.js +132 -0
@@ -0,0 +1,12 @@
1
+ export default {
2
+ 'Australia': [
3
+ 'Australian Capital Territory',
4
+ 'New South Wales',
5
+ 'Northern Territory',
6
+ 'Queensland',
7
+ 'South Australia',
8
+ 'Tasmania',
9
+ 'Victoria',
10
+ 'Western Australia'
11
+ ]
12
+ }
@@ -0,0 +1,105 @@
1
+ <template>
2
+ <div :style="genericStyles()" :class="$classes()">
3
+ <StripeIndividualFields
4
+ v-if="$classes().includes('individual')"
5
+ :spec="spec"
6
+ :on-complete="_retrieveToken"
7
+ :on-error="_displayError"
8
+ />
9
+ <StripeFields
10
+ v-else
11
+ :spec="spec"
12
+ :on-complete="_retrieveToken"
13
+ :on-error="_displayError"
14
+ />
15
+ <div ref="error" style="color: red;"></div>
16
+ <!-- <input ref="token" type="hidden" :name="spec.name" /> -->
17
+
18
+ <input
19
+ type="hidden"
20
+ :name="spec.name + '[payment_method_id]'"
21
+ :value="paymentMethodId"
22
+ />
23
+ <input type="hidden" :name="spec.name + '[brand]'" :value="brand" />
24
+ <input type="hidden" :name="spec.name + '[country]'" :value="country" />
25
+ <input type="hidden" :name="spec.name + '[last4]'" :value="last4" />
26
+ </div>
27
+ </template>
28
+
29
+ <script>
30
+ import StripeIndividualFields from "./stripe/stripeIndividualFields.vue";
31
+ import StripeFields from "./stripe/stripeFields.vue";
32
+
33
+ export default {
34
+ components: {
35
+ StripeIndividualFields,
36
+ StripeFields
37
+ },
38
+ props: {
39
+ spec: { type: Object, required: true }
40
+ },
41
+ data() {
42
+ return {
43
+ stripe: null,
44
+ card: null,
45
+ paymentMethodId: null,
46
+ brand: null,
47
+ country: null,
48
+ last4: null
49
+ };
50
+ },
51
+ methods: {
52
+ $ready() {
53
+ this.paymentMethodId = null;
54
+ this.brand = null;
55
+ this.country = null;
56
+ this.last4 = null;
57
+ },
58
+ _displayError(message) {
59
+ const displayError = this.$refs.error;
60
+ displayError.textContent = message;
61
+ },
62
+ _retrieveToken(stripe, card) {
63
+ // this.$dispatchEvent("forms/setBusy", { value: true });
64
+ // const vm = this;
65
+ // stripe.createToken(card).then(function(result) {
66
+ // if (result.error) {
67
+ // vm._displayError(result.error.message);
68
+ // } else {
69
+ // vm._displayError("");
70
+ // const token = result.token;
71
+ // vm.$refs.token.setAttribute("value", token.id);
72
+ // }
73
+ // vm.$dispatchEvent("forms/setBusy", { value: false });
74
+ // });
75
+
76
+ this._createPaymentMethod(stripe, card);
77
+ },
78
+ _createPaymentMethod(stripe, card) {
79
+ this.$dispatchEvent("forms/setBusy", { value: true });
80
+
81
+ let vm = this;
82
+ stripe.createPaymentMethod("card", card).then(function(result) {
83
+ if (result.error) {
84
+ vm._displayError(result.error.message);
85
+
86
+ // // Show error in payment form
87
+ // vm.displayError.textContent = result.error.message;
88
+ // vm.clearData();
89
+ // setTimeout(function() {
90
+ // vm.retrieveToken.status = "complete";
91
+ // }, 50);
92
+ } else {
93
+ vm._displayError("");
94
+
95
+ vm.paymentMethodId = result.paymentMethod.id;
96
+ vm.brand = result.paymentMethod.card.brand;
97
+ vm.country = result.paymentMethod.card.country;
98
+ vm.last4 = result.paymentMethod.card.last4;
99
+ }
100
+ vm.$dispatchEvent("forms/setBusy", { value: false });
101
+ });
102
+ }
103
+ }
104
+ };
105
+ </script>
@@ -0,0 +1,24 @@
1
+ <template>
2
+ <!-- See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date for why we need to use `pattern` -->
3
+ <fields-patternText
4
+ :spec="spec"
5
+ type="date"
6
+ pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}"
7
+ />
8
+ </template>
9
+
10
+ <script>
11
+ import PatternTextField from "./_patternText";
12
+
13
+ export default {
14
+ components: {
15
+ // Need to start with `fields-` to enable jsonlogic in `styles.js#_linkFieldModels`
16
+ "fields-patternText": PatternTextField
17
+ },
18
+ props: {
19
+ spec: { type: Object, required: true }
20
+ }
21
+ };
22
+ </script>
23
+
24
+ <style lang="scss" scoped></style>
@@ -0,0 +1,49 @@
1
+ <template>
2
+ <!-- See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date for why we need to use `pattern` -->
3
+ <!-- <v-text-field
4
+ :label="spec.label"
5
+ :name="spec.name"
6
+ :value="value"
7
+ type="datetime-local"
8
+ :readonly="spec.readOnly || false"
9
+ :disabled="spec.readOnly"
10
+ :min="spec.min"
11
+ :max="spec.max"
12
+ pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}"
13
+ :outlined="$classes().includes('outlined')"
14
+ :style="genericStyles()"
15
+ /> -->
16
+ <fields-patternText
17
+ :spec="spec"
18
+ type="datetime-local"
19
+ pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}"
20
+ :value="value"
21
+ />
22
+ </template>
23
+
24
+ <script>
25
+ import PatternTextField from "./_patternText";
26
+
27
+ export default {
28
+ components: {
29
+ // Need to start with `fields-` to enable jsonlogic in `styles.js#_linkFieldModels`
30
+ "fields-patternText": PatternTextField
31
+ },
32
+ props: {
33
+ spec: { type: Object, required: true }
34
+ },
35
+ data() {
36
+ return {
37
+ value: null
38
+ };
39
+ }
40
+ // methods: {
41
+ // $ready() {
42
+ // this.value = this.spec.value.slice(0, 16);
43
+ // // this.value = moment(this.spec.value).format('YYYY-MM-DDThh:mm')
44
+ // }
45
+ // }
46
+ };
47
+ </script>
48
+
49
+ <style scoped></style>
@@ -0,0 +1,106 @@
1
+ <template>
2
+ <div :style="genericStyles()" :class="$classes()">
3
+ <div v-for="(group, groupIndex) in groupSpecs" :key="`group${groupIndex}`">
4
+ <input
5
+ v-if="isDeleted(groupIndex)"
6
+ type="hidden"
7
+ :name="`${spec.name}[${groupIndex}][_destroy]`"
8
+ value="1"
9
+ />
10
+ <div :style="{ display: isDeleted(groupIndex) ? 'none' : 'block' }">
11
+ <v-icon
12
+ class="float-left mr-2"
13
+ color="error"
14
+ @click="removeGroup(groupIndex)"
15
+ >remove_circle</v-icon
16
+ >
17
+ <h4>{{ spec.titlePrefix }} {{ groupIndex + 1 }}</h4>
18
+ <panels-responsive :spec="group" />
19
+ </div>
20
+ </div>
21
+
22
+ <v-icon color="success" @click="addGroup()">add_circle</v-icon>
23
+ </div>
24
+ </template>
25
+
26
+ <script>
27
+ export default {
28
+ props: {
29
+ spec: { type: Object, required: true }
30
+ },
31
+ data() {
32
+ return {
33
+ groupValues: [],
34
+ template: {},
35
+ templateViews: []
36
+ };
37
+ },
38
+ computed: {
39
+ groupSpecs() {
40
+ return this.groupValues.map((group, groupIndex) => {
41
+ const viewSpecs = this.processTemplate(
42
+ this.mapFieldProperties(group),
43
+ groupIndex,
44
+ (viewSpec, name, properties) => {
45
+ // Always reattach the data model to avoid losing entered data.
46
+ return Object.assign({}, viewSpec, properties, {
47
+ name: name,
48
+ value: this.$data._fieldModels[name]
49
+ });
50
+ }
51
+ );
52
+ return Object.assign({}, this.template, { childViews: viewSpecs });
53
+ });
54
+ }
55
+ },
56
+ methods: {
57
+ $ready() {
58
+ // this.groupValues = this.spec.value;
59
+ this.groupValues = this.spec.groupFieldProperties;
60
+
61
+ this.template = this.spec.template;
62
+ this.templateViews = this.template.childViews || [];
63
+
64
+ this.groupValues.forEach((group, groupIndex) => {
65
+ this.processTemplate(
66
+ this.mapFieldProperties(group),
67
+ groupIndex,
68
+ (viewSpec, fullName, properties) => {
69
+ // this.$data._fieldModels[name] = group[viewSpec.name];
70
+ this.$data._fieldModels[fullName] = properties.value;
71
+ }
72
+ );
73
+ });
74
+ },
75
+ mapFieldProperties(group) {
76
+ const fieldProperties = {};
77
+ group.forEach(field => {
78
+ fieldProperties[field.name] = field;
79
+ });
80
+ return fieldProperties;
81
+ },
82
+ processTemplate(properties, groupIndex, process) {
83
+ return this.templateViews.map(viewSpec => {
84
+ if (Utils.type.isString(viewSpec.name)) {
85
+ // Process only if it is a field
86
+ const fullName = `${this.spec.name}[${groupIndex}][${viewSpec.name}]`;
87
+ return process(viewSpec, fullName, properties[viewSpec.name] || {});
88
+ }
89
+ return viewSpec;
90
+ });
91
+ },
92
+ addGroup() {
93
+ this.groupValues.push([{}]);
94
+ },
95
+ removeGroup(index) {
96
+ Utils.launch.sheet.confirm({}, () => {
97
+ // Don't delete the group in order to maintain consistent indexes between model and view.
98
+ this.$set(this.groupValues[index], "_destroy", 1);
99
+ });
100
+ },
101
+ isDeleted(index) {
102
+ return this.groupValues[index]._destroy;
103
+ }
104
+ }
105
+ };
106
+ </script>
@@ -0,0 +1,173 @@
1
+ <template>
2
+ <div :style="genericStyles()">
3
+ <v-autocomplete
4
+ ref="autocomplete"
5
+ v-model="model"
6
+ :items="allItems"
7
+ :loading="$isBusy"
8
+ :search-input.sync="search"
9
+ :label="spec.label"
10
+ hide-no-data
11
+ hide-selected
12
+ no-filter
13
+ return-object
14
+ :chips="true"
15
+ :deletable-chips="true"
16
+ :multiple="spec.multiple"
17
+ >
18
+ <template v-slot:item="data">
19
+ {{ data.item.title }} - {{ data.item.subtitle }}
20
+ </template>
21
+
22
+ <v-list-item
23
+ v-if="!$isBusy && nextPageUrl"
24
+ slot="append-item"
25
+ class="load-more"
26
+ >
27
+ <v-list-item-content class="text-content" @click="loadMore">
28
+ <v-list-item-title>Load More</v-list-item-title>
29
+ </v-list-item-content>
30
+ </v-list-item>
31
+ </v-autocomplete>
32
+
33
+ <input
34
+ v-for="(item, index) in values"
35
+ :key="index"
36
+ type="hidden"
37
+ :name="spec.name"
38
+ :value="item.value"
39
+ />
40
+ </div>
41
+ </template>
42
+
43
+ <script>
44
+ import Http from "../../utils/http";
45
+
46
+ export default {
47
+ props: {
48
+ spec: { type: Object, required: true }
49
+ },
50
+ data() {
51
+ return {
52
+ model: null,
53
+ search: null,
54
+ nextPageUrl: null,
55
+ keyword: "",
56
+ items: [],
57
+ allItems: [],
58
+ http: null,
59
+ lastTypedAt: null
60
+ };
61
+ },
62
+ computed: {
63
+ values() {
64
+ if (this.model) {
65
+ // Depends on whether the field is single or multiple
66
+ return this.$type.isArray(this.model) ? this.model : [this.model];
67
+ }
68
+ // To avoid empty param error
69
+ return [{ value: null }];
70
+ }
71
+ },
72
+ watch: {
73
+ // From https://codepen.io/pen/?&editable=true&editors=101
74
+ search(val) {
75
+ // if (this.http) {
76
+ // this.http.cancel();
77
+ // this.http = null;
78
+ // }
79
+ // this.keyword = val;
80
+
81
+ if (!val || val.length <= 0) {
82
+ return;
83
+ }
84
+
85
+ // This is not necessary if the server is efficient, but the speed improvement can
86
+ // be noticeable for a server which is slow in handling all the requests (including
87
+ // the canceled ones)
88
+ this.lastTypedAt = Date.now();
89
+
90
+ const delay = 500;
91
+ setTimeout(() => {
92
+ const lastTypedDistance = Date.now() - this.lastTypedAt;
93
+ // If the user has stopped typing
94
+ if (lastTypedDistance >= delay) {
95
+ if (this.http) {
96
+ this.http.cancel();
97
+ this.http = null;
98
+ }
99
+ this.keyword = val;
100
+
101
+ this.loadItems(this.spec.url, false);
102
+ }
103
+ }, delay);
104
+ },
105
+ model(val) {
106
+ this.updateAllItems();
107
+ }
108
+ },
109
+ methods: {
110
+ $ready() {
111
+ const selectedItems = this.spec.selectedOptions;
112
+ this.model = this.spec.multiple ? selectedItems : selectedItems[0];
113
+ this.updateAllItems();
114
+ this.loadItems(this.spec.url, false);
115
+ },
116
+ loadMore() {
117
+ if (this.nextPageUrl) {
118
+ this.loadItems(this.nextPageUrl, true);
119
+ }
120
+ },
121
+ loadItems(url, append) {
122
+ const vm = this;
123
+ this.http = Http.execute(
124
+ { url: `${url}&q=${this.keyword}` },
125
+ "GET",
126
+ this,
127
+ (data, response) => {
128
+ this.nextPageUrl = data.nextPageUrl;
129
+
130
+ const rows = this.normalizedRows(data);
131
+ if (append) {
132
+ vm.items = vm.items.concat(rows);
133
+ } else {
134
+ vm.items = rows;
135
+ }
136
+
137
+ vm.updateAllItems();
138
+
139
+ // This causes `Cannot set property 'scrollTop' of undefined` presumably when dropdown is not shown.
140
+ if (append) {
141
+ // Workaround to refresh list after adding new items
142
+ // See https://github.com/vuetifyjs/vuetify/issues/4867
143
+ setTimeout(() => {
144
+ this.$refs.autocomplete.onScroll();
145
+ });
146
+ }
147
+ }
148
+ );
149
+ },
150
+ updateAllItems() {
151
+ // Make sure selected items/values are in the mix so they can be displayed in the select field.
152
+ this.allItems = this.values.concat(this.items);
153
+ },
154
+ normalizedRows(data) {
155
+ return data.rows.map(row => {
156
+ const extra = row.extra;
157
+ row.value = extra.value;
158
+ row.text = extra.text;
159
+ return row;
160
+ });
161
+ }
162
+ }
163
+ };
164
+ </script>
165
+
166
+ <style scoped>
167
+ .load-more {
168
+ cursor: pointer;
169
+ }
170
+ .load-more:hover {
171
+ background-color: lightgray;
172
+ }
173
+ </style>
@@ -0,0 +1,166 @@
1
+ <template>
2
+ <div ref="fileUploadContainer" class="mb-3" :style="$styles()">
3
+ <label class="v-label v-label--active">{{ spec.label }}</label>
4
+ <div class="preview-container">
5
+ <v-avatar
6
+ v-if="placeholder.type == 'avatar'"
7
+ :style="genericStyles(placeholder)"
8
+ >
9
+ <img :src="fileImage || placeholder.url" />
10
+ </v-avatar>
11
+ <img
12
+ v-else-if="placeholder.type == 'image'"
13
+ class="square-image"
14
+ :style="genericStyles(placeholder)"
15
+ :src="fileImage || placeholder.url"
16
+ />
17
+ <span v-else>{{ fileTitle }}</span>
18
+
19
+ <span class="action-container">
20
+ <v-btn icon @click="triggerUpload">
21
+ <v-icon>edit</v-icon>
22
+ </v-btn>
23
+
24
+ <v-btn icon @click="removeImage">
25
+ <v-icon>close</v-icon>
26
+ </v-btn>
27
+ </span>
28
+ </div>
29
+ <input
30
+ ref="directUploadFile"
31
+ style="display: none;"
32
+ type="file"
33
+ @change="uploadFiles"
34
+ />
35
+
36
+ <!-- <input type="file" :name="spec.name" ref='directUploadFile' @change='uploadFiles' v-show='!uploaded'/> -->
37
+ <v-progress-linear v-if="showProgress" v-model="progress.value" />
38
+ <!-- <div v-show='uploaded'>
39
+ <v-layout align-center justify-space-between row>
40
+ <v-chip @click='removeImage' class='mr-2' color='red' text-color="white">X</v-chip>
41
+ <span ref='fileName' class='w-full mr-2'></span>
42
+ <img ref='fileImage' class='place-image-preview' />
43
+ </v-layout>
44
+ </div> -->
45
+ <input type="hidden" :name="spec.name" :value="fileValue" />
46
+ </div>
47
+ </template>
48
+
49
+ <script>
50
+ // import * as ActiveStorage from "@rails/activestorage"
51
+ import Uploader from "../../utils/uploader";
52
+ // import EventController, {
53
+ // DISABLE_SUBMIT_BUTTON
54
+ // } from "../../utils/global-event-controller";
55
+
56
+ // ActiveStorage.start()
57
+
58
+ export default {
59
+ props: {
60
+ spec: { type: Object, required: true }
61
+ },
62
+ data() {
63
+ return {
64
+ uploaded: false,
65
+ progress: { value: -1 },
66
+ fileTitle: null,
67
+ fileImage: null,
68
+ fileValue: null,
69
+ inputElement: null,
70
+ placeholder: {}
71
+ };
72
+ },
73
+ computed: {
74
+ showProgress: function() {
75
+ return this.progress.value >= 0;
76
+ }
77
+ },
78
+ methods: {
79
+ $ready() {
80
+ if (Utils.type.isString(this.spec.value)) {
81
+ this.uploaded = true;
82
+ this.fileTitle = this.spec.fileTitle;
83
+ this.fileImage = this.spec.fileUrl;
84
+ this.fileValue = this.spec.value;
85
+ }
86
+
87
+ this.placeholder = this.spec.placeholderView || {};
88
+ this.inputElement = this.$refs.directUploadFile;
89
+ },
90
+ triggerUpload() {
91
+ this.inputElement.click();
92
+ },
93
+ removeImage() {
94
+ this.uploaded = false;
95
+ this.fileTitle = null;
96
+ this.fileImage = null;
97
+ this.fileValue = null;
98
+ },
99
+ displayImagePreview(file, blob) {
100
+ let reader = new FileReader();
101
+ reader.onload = e => {
102
+ this.fileTitle = file.name;
103
+ this.fileImage = e.target.result;
104
+ this.fileValue = blob.signed_id;
105
+ };
106
+ reader.readAsDataURL(file);
107
+ },
108
+ uploadFile(file) {
109
+ const upload = new Uploader(
110
+ file,
111
+ this.spec.directUploadUrl,
112
+ this.progress
113
+ );
114
+
115
+ const input = this.inputElement;
116
+ if (upload.validateFile(this.spec)) {
117
+ this.$dispatchEvent("forms/setBusy", { value: true });
118
+
119
+ // TODO: Delete
120
+ // EventController.$emit(DISABLE_SUBMIT_BUTTON, true);
121
+
122
+ input.disabled = true;
123
+ upload.start((error, blob) => {
124
+ if (error) {
125
+ Utils.launch.snackbar.error(error);
126
+ } else {
127
+ this.uploaded = true;
128
+ this.progress.value = -1;
129
+ this.displayImagePreview(file, blob);
130
+ }
131
+
132
+ input.disabled = false;
133
+ input.value = null;
134
+ // EventController.$emit(DISABLE_SUBMIT_BUTTON, false);
135
+
136
+ this.$dispatchEvent("forms/setBusy", { value: false });
137
+ });
138
+ } else {
139
+ input.value = null;
140
+ }
141
+ },
142
+ uploadFiles(e) {
143
+ Array.from(e.target.files).forEach(file => this.uploadFile(file));
144
+ }
145
+ // toggleDisplayProgressIndicator() {
146
+ // this.showProgress = !this.showProgress
147
+ // },
148
+ // updateProgressIndicator(e) {
149
+ // this.valueProgress = e.detail.progress
150
+ // }
151
+ }
152
+ };
153
+ </script>
154
+
155
+ <style lang="scss" scoped>
156
+ .preview-container {
157
+ .action-container {
158
+ padding-left: 10px;
159
+ }
160
+
161
+ .square-image {
162
+ // height: 50px;
163
+ vertical-align: middle;
164
+ }
165
+ }
166
+ </style>