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
package/utils/http.js ADDED
@@ -0,0 +1,209 @@
1
+ import Type from "./type";
2
+ import Action from "../action";
3
+
4
+ let loading = false;
5
+
6
+ class HttpRequest {
7
+ constructor() {
8
+ this.controller = new AbortController();
9
+ this.canceled = false;
10
+ }
11
+
12
+ cancel() {
13
+ this.canceled = true;
14
+ this.controller.abort();
15
+ }
16
+ }
17
+
18
+ export default class {
19
+ static _extractFormData(properties, needCsrfToken) {
20
+ // if (properties["formDataEncoded"]) {
21
+ // return properties["formData"];
22
+ // }
23
+
24
+ const data = properties.formData;
25
+ if (data instanceof FormData) {
26
+ return data;
27
+ }
28
+
29
+ const formData = new FormData();
30
+ var params = data || {};
31
+ for (const key in params) {
32
+ formData.append(key, params[key]);
33
+ }
34
+
35
+ if (needCsrfToken && !Type.isString(params["authenticity_token"])) {
36
+ formData.append("authenticity_token", Utils.dom.getCsrf());
37
+ }
38
+ return formData;
39
+ }
40
+
41
+ static load(properties, target, component) {
42
+ const url = new URL(properties["url"]);
43
+ const domainMatched = window.location.hostname == url.hostname;
44
+ if (Utils.settings.reactive && domainMatched) {
45
+ const currentUrl = window.location.href;
46
+ const htmlUrl = Utils.url.htmlUrl(properties["url"]);
47
+
48
+ Utils.http.execute(properties, "GET", component, (data, response) => {
49
+ if (htmlUrl !== currentUrl) {
50
+ const redirectUrl = Utils.url.htmlUrl(response.url);
51
+ Utils.history.pushPage(data, redirectUrl);
52
+ }
53
+
54
+ this.forceComponentUpdate(() => {
55
+ Utils.history.resetScroll();
56
+ window.vueApp.page = data;
57
+ Action.execute(properties["onOpen"], target, component);
58
+ });
59
+ });
60
+ } else {
61
+ window.location = Utils.url.htmlUrl(properties["url"]);
62
+ }
63
+ }
64
+
65
+ static analyticsHeaders(component) {
66
+ const pageAnalytics =
67
+ window.vueApp.temp.analytics || window.vueApp.page.analytics || {};
68
+ const featureAnalytics = pageAnalytics.feature;
69
+
70
+ const headers = {};
71
+ if (featureAnalytics) {
72
+ const componentAnalytics = component.spec.analytics || {};
73
+ if (componentAnalytics.disabled) {
74
+ return headers;
75
+ }
76
+
77
+ Utils.type.ifString(
78
+ componentAnalytics.group || featureAnalytics.group,
79
+ value => (headers["GApp-Analytics-Referer-Group"] = value)
80
+ );
81
+
82
+ Utils.type.ifString(
83
+ componentAnalytics.action || featureAnalytics.action,
84
+ value => (headers["GApp-Analytics-Referer-Action"] = value)
85
+ );
86
+
87
+ Utils.type.ifString(
88
+ componentAnalytics.segment || featureAnalytics.segment,
89
+ value => (headers["GApp-Analytics-Referer-Segment"] = value)
90
+ );
91
+
92
+ Utils.type.ifString(
93
+ componentAnalytics.placement,
94
+ value => (headers["GApp-Analytics-Referer-Placement"] = value)
95
+ );
96
+ }
97
+ return headers;
98
+ }
99
+
100
+ static reload(properties, component) {
101
+ const currentUrl = window.location.href;
102
+ const data = {
103
+ url: properties.url || currentUrl
104
+ };
105
+
106
+ Utils.http.execute(data, "GET", component, (page, response) => {
107
+ Utils.http.forceComponentUpdate(() => {
108
+ window.vueApp.page = page;
109
+ const redirectUrl = Utils.url.htmlUrl(response.url);
110
+ Utils.history.updatePage(redirectUrl);
111
+
112
+ GLib.action.execute(properties["onReload"], null, component);
113
+ });
114
+ });
115
+ }
116
+
117
+ static execute(properties, methodName, component, jsonHandler) {
118
+ this.startIndicator(component);
119
+
120
+ // `fetch()` only supports uppercase
121
+ const method = methodName.toUpperCase();
122
+ let url = Utils.url.jsonUrl(properties["url"]);
123
+ let body = this._extractFormData(properties, method !== "GET");
124
+ if (method === "GET") {
125
+ url = Utils.url.appendParams(url, body);
126
+ body = null;
127
+ }
128
+ console.log(`${method} ${url}`);
129
+
130
+ const request = new HttpRequest();
131
+ let response = null;
132
+ const vm = this;
133
+
134
+ const analyticsHeaders = this.analyticsHeaders(component);
135
+
136
+ fetch(url, {
137
+ method: method,
138
+ body: body,
139
+ headers: Object.assign({ Accept: "text/html" }, analyticsHeaders),
140
+ // Make sure to pass cookies for same origin URLs.
141
+ // Needed for some browsers, e.g. Edge and Android's native.
142
+ credentials: "same-origin",
143
+ signal: request.controller.signal
144
+ })
145
+ .then(res => {
146
+ vm.stopIndicator(component);
147
+
148
+ if (res.status >= 500) {
149
+ throw "Server error";
150
+ } else if (res.status >= 400) {
151
+ throw "Not accessible";
152
+ } else {
153
+ response = res;
154
+ return res.json();
155
+ }
156
+ })
157
+ .then(data => {
158
+ console.debug("Success", data);
159
+ jsonHandler(data, response);
160
+ })
161
+ .catch(error => {
162
+ vm.stopIndicator(component);
163
+ if (!request.canceled) {
164
+ console.error("Error:", error);
165
+ Utils.launch.snackbar.error(error);
166
+ } else {
167
+ console.info("Canceled");
168
+ }
169
+ });
170
+
171
+ return request;
172
+ }
173
+
174
+ static startIndicator(component) {
175
+ this._showIndicator();
176
+ component.$data._isBusy = true;
177
+ }
178
+
179
+ static stopIndicator(component) {
180
+ this._hideIndicator();
181
+ component.$data._isBusy = false;
182
+ }
183
+
184
+ static _showIndicator() {
185
+ loading = true;
186
+ setTimeout(() => {
187
+ if (loading) {
188
+ loading = false;
189
+ window.vueApp.indicator = true;
190
+ }
191
+ }, 200);
192
+ }
193
+
194
+ static _hideIndicator() {
195
+ loading = false;
196
+ window.vueApp.indicator = false;
197
+ }
198
+
199
+ // See generic.js
200
+ static forceComponentUpdate(handler) {
201
+ window.vueApp.isStale = true;
202
+
203
+ // Queue the execution so the first isStale has time to resets state before handler gets executed
204
+ setTimeout(() => {
205
+ handler();
206
+ window.vueApp.isStale = false;
207
+ }, 0);
208
+ }
209
+ }
@@ -0,0 +1,135 @@
1
+ import Vue from "vue";
2
+ import Dialog from "../nav/dialog";
3
+ import Sheet from "../nav/sheet";
4
+ import Snackbar from "../nav/snackbar";
5
+ import Vuetify from "vuetify";
6
+
7
+ export default class {
8
+ static dialog(properties, target) {
9
+ if (!this.stack) {
10
+ this.stack = [];
11
+ }
12
+
13
+ // https://css-tricks.com/creating-vue-js-component-instances-programmatically/
14
+ const DialogClass = Vue.extend(Dialog);
15
+ const instance = new DialogClass({
16
+ vuetify: new Vuetify({
17
+ theme: {
18
+ themes: Utils.settings.themes
19
+ }
20
+ }),
21
+ propsData: {
22
+ spec: properties,
23
+ stack: this.stack,
24
+ target: target,
25
+ vueApp: window.vueApp
26
+ }
27
+ });
28
+ // instance.stack = this.stack;
29
+
30
+ const placeholder = document.body.appendChild(
31
+ document.createElement("div")
32
+ );
33
+ instance.$mount(placeholder);
34
+ }
35
+
36
+ static closeDialog(properties, target, component) {
37
+ if (!this.stack) {
38
+ this.stack = [];
39
+ }
40
+
41
+ Utils.type.ifObject(this.stack.last(), dialog => {
42
+ dialog.close();
43
+ });
44
+
45
+ Utils.type.ifObject(properties["onClose"], it => {
46
+ Action.execute(it, target, component);
47
+ });
48
+ }
49
+
50
+ static get sheet() {
51
+ return LaunchSheet;
52
+ }
53
+
54
+ static get snackbar() {
55
+ return LaunchSnackbar;
56
+ }
57
+
58
+ static alert(message, target) {
59
+ const properties = {
60
+ message: message
61
+ };
62
+ const spec = Object.assign({}, properties, {
63
+ buttons: [
64
+ {
65
+ text: "OK",
66
+ onClick: properties.onClose
67
+ }
68
+ ]
69
+ });
70
+ this.dialog(spec, target);
71
+ }
72
+ }
73
+
74
+ class LaunchSheet {
75
+ static open(properties) {
76
+ const SheetClass = Vue.extend(Sheet);
77
+ const instance = new SheetClass({
78
+ vuetify: new Vuetify({
79
+ theme: {
80
+ themes: Utils.settings.themes
81
+ }
82
+ }),
83
+ propsData: { spec: properties }
84
+ });
85
+ const placeholder = document.body.appendChild(
86
+ document.createElement("div")
87
+ );
88
+ instance.$mount(placeholder);
89
+ // instance.show = true
90
+ return instance;
91
+ }
92
+
93
+ static confirm(properties, onConfirm) {
94
+ const spec = Object.assign({}, properties, {
95
+ buttons: [
96
+ {
97
+ text: "Confirm",
98
+ onClickFunction: onConfirm
99
+ }
100
+ ]
101
+ });
102
+ this.open(spec);
103
+ }
104
+
105
+ static alert(message, buttons) {
106
+ const spec = { message: message, buttons: buttons };
107
+ this.open(spec);
108
+ }
109
+ }
110
+
111
+ class LaunchSnackbar {
112
+ static open(properties) {
113
+ const SnackbarClass = Vue.extend(Snackbar);
114
+ const instance = new SnackbarClass({
115
+ vuetify: window.vueApp.vuetify,
116
+ propsData: { spec: properties, vueApp: window.vueApp }
117
+ });
118
+
119
+ const placeholder = document.body.appendChild(
120
+ document.createElement("div")
121
+ );
122
+ instance.$mount(placeholder);
123
+ instance.show = true;
124
+ return instance;
125
+ }
126
+
127
+ static error(message) {
128
+ this.open({ message: message, styleClasses: ["error"] });
129
+ }
130
+
131
+ static indicator(message) {
132
+ const instance = this.open({ message: message, timeout: -1 });
133
+ instance.indicator = true;
134
+ }
135
+ }
@@ -0,0 +1,22 @@
1
+ export default class {
2
+ static handleResponse(payload, component) {
3
+ if (!Utils.type.isObject(payload)) {
4
+ return;
5
+ }
6
+
7
+ const ws = window.vueApp.webSocket;
8
+ Utils.type.ifObject(payload.wsHeader, header => {
9
+ Object.assign(ws.header, header);
10
+ console.log("New header: ", ws.header);
11
+ });
12
+
13
+ const actionName = payload.action;
14
+ if (actionName.startsWith("component/")) {
15
+ const methodName = actionName.replace(/^component\//, "");
16
+ console.log(`Executing component action: ${methodName}`);
17
+ component[`action_${methodName}`](payload);
18
+ } else {
19
+ GLib.action.execute(payload, null, component);
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,23 @@
1
+ import Action from "../action";
2
+ import Url from "./url";
3
+ import Http from "./http";
4
+ import Type from "./type";
5
+ import Form from "./form";
6
+
7
+ export default class {
8
+ static get action() {
9
+ return Action;
10
+ }
11
+ static get url() {
12
+ return Url;
13
+ }
14
+ static get http() {
15
+ return Http;
16
+ }
17
+ static get type() {
18
+ return Type;
19
+ }
20
+ static get form() {
21
+ return Form;
22
+ }
23
+ }
@@ -0,0 +1,48 @@
1
+ class MutableSettings {
2
+ constructor() {
3
+ this.reactive = true;
4
+ this.themes = {};
5
+ this.gtagId = null;
6
+ }
7
+ }
8
+ const settings = new MutableSettings();
9
+ export { settings };
10
+
11
+ export default class ImmutableSettings {
12
+ static get reactive() {
13
+ return settings.reactive;
14
+ }
15
+
16
+ static get themes() {
17
+ return settings.themes;
18
+ }
19
+
20
+ static get env() {
21
+ return process.env.NODE_ENV;
22
+ }
23
+
24
+ static get appVersion() {
25
+ return require("../package.json").version;
26
+ }
27
+
28
+ // static get build() {
29
+ // switch (this.env) {
30
+ // case 'development':
31
+ // return new DevBuild()
32
+ // default:
33
+ // return new ProdBuild()
34
+ // }
35
+ // }
36
+
37
+ static get assetCdn() {
38
+ return `${this.build.assetDomain}/${this.appVersion}`;
39
+ }
40
+
41
+ static get apiHost() {
42
+ return this.build.apiDomain;
43
+ }
44
+
45
+ static get isDev() {
46
+ return this.env == "development";
47
+ }
48
+ }
@@ -0,0 +1,9 @@
1
+ export default class {
2
+ static setLocal(key, obj) {
3
+ localStorage.setItem(key, JSON.stringify(obj))
4
+ }
5
+ static getLocal(key) {
6
+ return JSON.parse(localStorage.getItem(key))
7
+ }
8
+ }
9
+
package/utils/type.js ADDED
@@ -0,0 +1,69 @@
1
+ export default class {
2
+ static isObject(obj) {
3
+ return typeof obj === "object" && obj !== null;
4
+ }
5
+ static isString(obj) {
6
+ return typeof obj === "string";
7
+ }
8
+ static isNumber(obj) {
9
+ return typeof obj === "number" && !isNaN(obj);
10
+ }
11
+ static isBoolean(obj) {
12
+ return typeof obj === "boolean";
13
+ }
14
+ static isArray(obj) {
15
+ return this.isObject(obj) && Array.isArray(obj);
16
+ }
17
+ static isFunction(obj) {
18
+ return typeof obj === "function";
19
+ }
20
+ static isNotNull(obj) {
21
+ return typeof obj !== "undefined" && obj !== null;
22
+ }
23
+
24
+ static ifObject(obj, ifCommand, elseCommand) {
25
+ if (this.isObject(obj)) {
26
+ ifCommand(obj);
27
+ } else if (elseCommand) {
28
+ elseCommand();
29
+ }
30
+ }
31
+ static ifString(obj, command) {
32
+ if (this.isString(obj)) {
33
+ command(obj);
34
+ }
35
+ }
36
+ static ifNumber(obj, command) {
37
+ if (this.isNumber(obj)) {
38
+ command(obj);
39
+ }
40
+ }
41
+ static ifBoolean(obj, command) {
42
+ if (this.isBoolean(obj)) {
43
+ command(obj);
44
+ }
45
+ }
46
+ static ifArray(obj, command) {
47
+ if (this.isArray(obj)) {
48
+ command(obj);
49
+ }
50
+ }
51
+ static ifFunction(obj, command) {
52
+ if (this.isFunction(obj)) {
53
+ command(obj);
54
+ }
55
+ }
56
+ static ifNotNull(obj, command) {
57
+ if (this.isNotNull(obj)) {
58
+ command(obj);
59
+ }
60
+ }
61
+
62
+ static floatValue(obj) {
63
+ return this.float(obj) || 0;
64
+ }
65
+ static float(obj) {
66
+ const val = parseFloat(obj);
67
+ return isNaN(val) ? null : val;
68
+ }
69
+ }
@@ -0,0 +1,121 @@
1
+ import { DirectUpload } from "@rails/activestorage";
2
+ import Type from "../utils/type";
3
+
4
+ const MB_SIZE = 1000;
5
+
6
+ export default class Uploader {
7
+ // constructor(input, file, url) {
8
+ // this.input = input
9
+ // this.file = file
10
+ // this.url = url
11
+ // this.upload = new DirectUpload(this.file, this.url, this)
12
+ // }
13
+
14
+ constructor(file, url, progress) {
15
+ this.file = file;
16
+ this.url = url;
17
+ this.progress = progress;
18
+ this.upload = new DirectUpload(this.file, this.url, this);
19
+ }
20
+
21
+ start(callback) {
22
+ this.progress.value = 0;
23
+ // this.dispatch("start")
24
+ this.upload.create((error, blob) => callback(error, blob));
25
+ }
26
+
27
+ // dispatchEvent(element, type, eventInit = {}) {
28
+ // const { disabled } = element
29
+ // const { bubbles, cancelable, detail } = eventInit
30
+ // const event = document.createEvent("Event")
31
+
32
+ // event.initEvent(type, bubbles || true, cancelable || true)
33
+ // event.detail = detail || {}
34
+
35
+ // try {
36
+ // element.disabled = false
37
+ // element.dispatchEvent(event)
38
+ // } finally {
39
+ // element.disabled = disabled
40
+ // }
41
+
42
+ // return event
43
+ // }
44
+
45
+ // dispatch(name, detail = {}) {
46
+ // detail.file = this.file
47
+ // return this.dispatchEvent(this.input, `direct-upload:${name}`, { detail })
48
+ // }
49
+
50
+ // Called by DirectUpload
51
+ directUploadWillStoreFileWithXHR(request) {
52
+ request.upload.addEventListener("progress", event =>
53
+ this.directUploadDidProgress(event)
54
+ );
55
+ }
56
+
57
+ directUploadDidProgress(event) {
58
+ // const progress = event.loaded / event.total * 100
59
+ // if (progress)
60
+ // this.dispatch("progress", { progress })
61
+ this.progress.value = (event.loaded / event.total) * 100;
62
+ }
63
+
64
+ validateFile(spec) {
65
+ return this.validateFileAccordingToRules(spec.accepts);
66
+
67
+ // if (Type.isString(spec.accepts)) {
68
+ // if (spec.accepts) {
69
+ // const acceptsRegex = new RegExp(spec.accepts);
70
+
71
+ // if (!acceptsRegex.test(this.file.type)) {
72
+ // alert("Invalid file type.");
73
+ // return false;
74
+ // }
75
+ // }
76
+
77
+ // if (spec.file_size_limit) {
78
+ // if (this.file.size > spec.file_size_limit * MB_SIZE) {
79
+ // alert(spec.file_size_limit_alert_text);
80
+ // return false;
81
+ // }
82
+ // }
83
+ // } else {
84
+ // return this.validateFileAccordingToRules(spec.accepts);
85
+ // }
86
+
87
+ // return true;
88
+ }
89
+
90
+ validateFileAccordingToRules(spec) {
91
+ if (Type.isObject(spec)) {
92
+ let mimeType;
93
+ switch (spec.fileType) {
94
+ case "image/*": // Legacy
95
+ case "image":
96
+ mimeType = "image/*";
97
+ break;
98
+ case "pdf":
99
+ mimeType = "application/pdf";
100
+ break;
101
+ default:
102
+ return;
103
+ }
104
+
105
+ const acceptsRegex = new RegExp(mimeType);
106
+ if (!acceptsRegex.test(this.file.type)) {
107
+ alert(spec.fileTypeErrorText || "Invalid file type");
108
+ return false;
109
+ }
110
+
111
+ if (spec.maxFileSize) {
112
+ if (this.file.size > spec.maxFileSize * MB_SIZE) {
113
+ alert(spec.maxFileSizeErrorText || "File too big");
114
+ return false;
115
+ }
116
+ }
117
+ }
118
+
119
+ return true;
120
+ }
121
+ }