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,64 @@
1
+ <template>
2
+ <v-radio
3
+ :label="spec.label"
4
+ :value="spec.value.presence() || vuetifyEmptyString"
5
+ :off-icon="data.icon || '$vuetify.icons.radioOff'"
6
+ :on-icon="data.icon || '$vuetify.icons.radioOn'"
7
+ :class="$classes()"
8
+ :disabled="spec.readOnly"
9
+ @change="changed"
10
+ ></v-radio>
11
+ </template>
12
+
13
+ <script>
14
+ export default {
15
+ props: {
16
+ spec: { type: Object, required: true }
17
+ },
18
+ data() {
19
+ return {
20
+ groupElement: null,
21
+ data: { value: this.spec.value, icon: null }
22
+ };
23
+ },
24
+ methods: {
25
+ $ready() {
26
+ this.groupElement = this.$el.closest("[data-component=radioGroup]");
27
+
28
+ // Execute later to ensure the radioGroup has registered its event listener
29
+ const vm = this;
30
+ setTimeout(function() {
31
+ const ev = new Event("add");
32
+ ev.spec = vm.data;
33
+ vm.$type.ifObject(vm.groupElement, val => val.dispatchEvent(ev));
34
+ }, 100);
35
+ },
36
+ changed(event) {
37
+ // Execute later to ensure the checkbox's checked state has been updated.
38
+ const vm = this;
39
+ setTimeout(function() {
40
+ vm.$type.ifObject(vm.groupElement, val =>
41
+ val.dispatchEvent(new Event("change"))
42
+ );
43
+ }, 100);
44
+ }
45
+ }
46
+ };
47
+ </script>
48
+
49
+ <style lang="scss">
50
+ .v-input--selection-controls {
51
+ .v-radio.vertical {
52
+ display: inline-block;
53
+ text-align: center;
54
+
55
+ .v-input--selection-controls__input {
56
+ margin-right: 0;
57
+ }
58
+
59
+ label {
60
+ display: block;
61
+ }
62
+ }
63
+ }
64
+ </style>
@@ -0,0 +1,93 @@
1
+ <template>
2
+ <v-radio-group
3
+ v-model="fieldModel"
4
+ data-component="radioGroup"
5
+ :name="fieldName"
6
+ :disabled="spec.readOnly"
7
+ >
8
+ <div v-for="(item, index) in spec.childViews" :key="index">
9
+ <ui-component :spec="item" />
10
+ </div>
11
+
12
+ <input
13
+ v-if="spec.readOnly"
14
+ type="hidden"
15
+ :name="fieldName"
16
+ :value="fieldModel"
17
+ />
18
+ </v-radio-group>
19
+ </template>
20
+
21
+ <script>
22
+ export default {
23
+ props: {
24
+ spec: { type: Object, required: true }
25
+ },
26
+ data() {
27
+ return {
28
+ // value: null,
29
+ radios: []
30
+ };
31
+ },
32
+ methods: {
33
+ $ready() {
34
+ // this.value = this.spec.value
35
+
36
+ const vm = this;
37
+ this.$el.addEventListener(
38
+ "change",
39
+ function(e) {
40
+ vm.radioChanged();
41
+ },
42
+ false
43
+ );
44
+ this.$el.addEventListener(
45
+ "add",
46
+ function(e) {
47
+ vm.radioAdded(e.spec);
48
+ },
49
+ false
50
+ );
51
+ },
52
+ radioChanged() {
53
+ if (
54
+ this.$type.isString(this.spec.iconOfBeforeSelected) &&
55
+ this.$type.isString(this.spec.iconOfSelected) &&
56
+ this.$type.isString(this.spec.iconOfAfterSelected)
57
+ ) {
58
+ let icon = this.value
59
+ ? this.spec.iconOfBeforeSelected
60
+ : this.spec.iconOfAfterSelected;
61
+ for (const radio of this.radios) {
62
+ if (this.value === radio.value) {
63
+ radio.icon = this.spec.iconOfSelected;
64
+ icon = this.spec.iconOfAfterSelected;
65
+ } else {
66
+ radio.icon = icon;
67
+ }
68
+ }
69
+ }
70
+ },
71
+ radioAdded(spec) {
72
+ this.radios.push(spec);
73
+ this.radioChanged();
74
+ }
75
+ }
76
+ };
77
+ </script>
78
+
79
+ <style scoped>
80
+ /* TODO: Review this after upgrading to vuetify 2.0 */
81
+ div.v-input--radio-group {
82
+ margin-top: 0;
83
+ }
84
+ </style>
85
+
86
+ <style>
87
+ div.v-input--radio-group .v-messages {
88
+ min-height: 0;
89
+ }
90
+ div.v-input--radio-group.v-input--selection-controls .v-input__slot {
91
+ margin-bottom: 0;
92
+ }
93
+ </style>
@@ -0,0 +1,26 @@
1
+ <template>
2
+ <div>
3
+ <v-rating
4
+ v-model="fieldModel"
5
+ :name="fieldName"
6
+ :value="spec.value"
7
+ empty-icon="star_outline"
8
+ full-icon="star"
9
+ half-icon="star_half"
10
+ :half-increments="spec.halfIncrements"
11
+ hover
12
+ length="5"
13
+ :readonly="spec.readOnly"
14
+ :color="spec.color"
15
+ :background-color="spec.color"
16
+ :size="spec.size"
17
+ ></v-rating>
18
+ <input type="hidden" :name="fieldName" :value="fieldModel" />
19
+ </div>
20
+ </template>
21
+
22
+ <script>
23
+ export default {
24
+ props: { spec: { type: Object, required: true } }
25
+ };
26
+ </script>
@@ -0,0 +1,172 @@
1
+ <template>
2
+ <div>
3
+ <v-progress-linear v-if="showProgress" v-model="progress.value" />
4
+ <VueEditor
5
+ v-model="rawValue"
6
+ :editor-toolbar="customToolbar"
7
+ :use-custom-image-handler="true"
8
+ @text-change="separateOutImages"
9
+ @image-added="uploadImage"
10
+ />
11
+ <input type="hidden" :name="spec.name" :value="cleanValue" />
12
+ <input
13
+ v-for="(imageKey, index) in imageKeys"
14
+ :key="index"
15
+ type="hidden"
16
+ name="imageUrls[]"
17
+ :value="images[imageKey]"
18
+ />
19
+
20
+ <p>{{ cleanValue }}</p>
21
+
22
+ <ol>
23
+ <li v-for="(imageKey, index) in imageKeys" :key="index">
24
+ {{ images[imageKey] }}
25
+ </li>
26
+ </ol>
27
+ </div>
28
+ </template>
29
+
30
+ <script>
31
+ import Uploader from "../../utils/uploader";
32
+ import { VueEditor } from "vue2-editor";
33
+ // import EventController, {
34
+ // DISABLE_SUBMIT_BUTTON
35
+ // } from "../../utils/global-event-controller";
36
+
37
+ export default {
38
+ components: { VueEditor },
39
+ props: {
40
+ spec: { type: Object, required: true }
41
+ },
42
+ data: () => ({
43
+ customToolbar: [
44
+ ["bold", "italic", "underline", "strike"],
45
+ [{ color: [] }, { background: [] }],
46
+ [{ header: 1 }, { header: 2 }],
47
+ [{ list: "ordered" }, { list: "bullet" }],
48
+ ["link", "image", "video"],
49
+ ["clean"]
50
+ ],
51
+ rawValue: "",
52
+ cleanValue: "",
53
+ images: {},
54
+ imageKeys: [],
55
+ progress: { value: -1 }
56
+ }),
57
+ // mounted: function () {
58
+ // const vm = this
59
+ // this.rawValue = (this.spec.value || "").replace(/\{\{image([0-9]+)\}\}/g, function (_, index) {
60
+ // const image = vm.spec.images[index - 1]
61
+ // if (image && vm.$type.isString(image.value) && vm.$type.isString(image.fileUrl)) {
62
+ // const url = image.fileUrl
63
+ // const key = url.hashCode().toString()
64
+ // vm.images[key] = image.value
65
+ // return `<img src="${url}">`
66
+ // }
67
+ // return "{{IMAGE_NOT_FOUND}}"
68
+ // })
69
+ // },
70
+ computed: {
71
+ showProgress: function() {
72
+ return this.progress.value >= 0;
73
+ }
74
+ },
75
+ methods: {
76
+ $ready() {
77
+ const vm = this;
78
+ this.rawValue = (this.spec.value || "").replace(
79
+ /\{\{image([0-9]+)\}\}/g,
80
+ function(_, index) {
81
+ const image = vm.spec.images[index - 1];
82
+ if (
83
+ image &&
84
+ vm.$type.isString(image.value) &&
85
+ vm.$type.isString(image.fileUrl)
86
+ ) {
87
+ const url = image.fileUrl;
88
+ const key = url.hashCode().toString();
89
+ vm.images[key] = image.value;
90
+ return `<img src="${url}">`;
91
+ }
92
+ return "{{IMAGE_NOT_FOUND}}";
93
+ }
94
+ );
95
+ },
96
+ uploadImage: function(file, editor, cursorLocation) {
97
+ let vm = this;
98
+ const uploaderSpec = this.spec.imageUploader;
99
+ // const input = this.$refs.directUploadFile
100
+ const upload = new Uploader(
101
+ file,
102
+ uploaderSpec.directUploadUrl,
103
+ this.progress
104
+ );
105
+
106
+ if (upload.validateFile(uploaderSpec)) {
107
+ // TODO
108
+ // EventController.$emit(DISABLE_SUBMIT_BUTTON, true);
109
+
110
+ upload.start((error, blob) => {
111
+ if (error) {
112
+ // Handle the error
113
+ } else {
114
+ vm.insertImage(file, editor, cursorLocation, blob);
115
+ }
116
+
117
+ // TODO
118
+ // EventController.$emit(DISABLE_SUBMIT_BUTTON, false);
119
+ });
120
+ }
121
+ },
122
+ separateOutImages: function() {
123
+ const vm = this;
124
+ var index = 0;
125
+ vm.imageKeys.clear();
126
+ // TODO: Fix to avoid replacing <video src="">
127
+ this.cleanValue = this.rawValue.replace(/src="([^"]+)"/g, function(
128
+ _,
129
+ imageValue
130
+ ) {
131
+ // It seems that quill encodes '&' in the URL to '&amp;' which would screw up key matching.
132
+ var decodedValue = imageValue.replace(/&amp;/g, "&");
133
+ const key = decodedValue.hashCode().toString();
134
+ vm.imageKeys.push(key);
135
+ return `src="{{image${++index}}}"`;
136
+ });
137
+ },
138
+ insertImage: function(file, Editor, cursorLocation, blob) {
139
+ let vm = this;
140
+ var reader = new FileReader();
141
+ reader.onload = function(e) {
142
+ // vm.fileUrl = e.target.result;
143
+ if (file.type.indexOf("image") !== -1) {
144
+ var image = new Image();
145
+ image.src = e.target.result;
146
+
147
+ image.onload = function() {
148
+ Editor.insertEmbed(cursorLocation, "image", image.src);
149
+ };
150
+
151
+ const key = image.src.hashCode().toString();
152
+ vm.images[key] = blob.signed_id;
153
+ }
154
+ };
155
+ reader.readAsDataURL(file);
156
+ vm.progress.value = -1;
157
+ }
158
+ }
159
+ };
160
+ </script>
161
+
162
+ <style scoped>
163
+ /*
164
+ @import "~vue2-editor/dist/vue2-editor.css";
165
+ @import '~quill/dist/quill.core.css';
166
+ @import '~quill/dist/quill.snow.css';
167
+
168
+ #editor-container {
169
+ height: 375px;
170
+ }
171
+ */
172
+ </style>
@@ -0,0 +1,17 @@
1
+ <template>
2
+ <fields-genericSelect :spec="spec" />
3
+ </template>
4
+
5
+ <script>
6
+ import SelectField from "./_select";
7
+
8
+ export default {
9
+ components: {
10
+ // Need to start with `fields-` to enable jsonlogic in `styles.js#_linkFieldModels`
11
+ "fields-genericSelect": SelectField
12
+ },
13
+ props: {
14
+ spec: { type: Object, required: true }
15
+ }
16
+ };
17
+ </script>
@@ -0,0 +1,93 @@
1
+ <template>
2
+ <div>
3
+ <div ref="container">
4
+ <!-- A Stripe Element will be inserted here. -->
5
+ </div>
6
+ </div>
7
+ </template>
8
+
9
+ <script>
10
+ export default {
11
+ props: {
12
+ spec: { type: Object, required: true },
13
+ onComplete: {
14
+ type: Function,
15
+ required: true
16
+ },
17
+ onError: {
18
+ type: Function,
19
+ required: true
20
+ }
21
+ },
22
+ data() {
23
+ return {
24
+ stripe: null,
25
+ card: null
26
+ };
27
+ },
28
+ watch: {
29
+ "$root.vueApp.stateUpdatedAt": function(val, oldVal) {
30
+ this.onComplete(this.stripe, this.card);
31
+ }
32
+ },
33
+ mounted() {
34
+ this.stripe = Stripe(this.spec.publicKey);
35
+ const elements = this.stripe.elements();
36
+
37
+ const style = {
38
+ base: {
39
+ fontSize: "16px",
40
+ color: "#32325d"
41
+ }
42
+ };
43
+
44
+ this.card = elements.create("card", { style: style });
45
+ this.card.mount(this.$refs.container);
46
+
47
+ this._registerEvent();
48
+ },
49
+ methods: {
50
+ _registerEvent() {
51
+ this.card.addEventListener("change", event => {
52
+ const error = event.error;
53
+ if (error) {
54
+ this.onError(error.message);
55
+ } else {
56
+ this.onError("");
57
+ }
58
+ if (event.complete) {
59
+ this.onComplete(this.stripe, this.card);
60
+ }
61
+ });
62
+ }
63
+ }
64
+ };
65
+ </script>
66
+
67
+ <style lang="scss" scoped>
68
+ .outlined {
69
+ .StripeElement {
70
+ box-sizing: border-box;
71
+ height: 60px;
72
+ padding: 18px 12px;
73
+ border: 1px solid #999999;
74
+ border-radius: 4px;
75
+ background-color: white;
76
+ box-shadow: 0 1px 3px 0 #e6ebf1;
77
+ -webkit-transition: box-shadow 150ms ease;
78
+ transition: box-shadow 150ms ease;
79
+ }
80
+ .StripeElement:hover {
81
+ border-color: #000000;
82
+ cursor: text;
83
+ }
84
+ .StripeElement--focus {
85
+ border-color: #1976d2;
86
+ border-width: 2px;
87
+ }
88
+ .StripeElement--invalid {
89
+ border-color: #f44336;
90
+ border-width: 2px;
91
+ }
92
+ }
93
+ </style>
@@ -0,0 +1,207 @@
1
+ <template>
2
+ <div>
3
+ <div class="field">
4
+ <div class="outlined">
5
+ <div id="cardNumber" ref="cardNumber" class="input"></div>
6
+ <label for="cardNumber">{{ spec.label || "Card Number" }}</label>
7
+ <div class="baseline"></div>
8
+ </div>
9
+ </div>
10
+ <v-row>
11
+ <v-col>
12
+ <div class="field">
13
+ <div class="outlined">
14
+ <div id="cardExpiry" ref="cardExpiry" class="input"></div>
15
+ <label for="cardExpiry">Expiry Date</label>
16
+ <div class="baseline"></div>
17
+ </div>
18
+ </div>
19
+ </v-col>
20
+ <v-col>
21
+ <div class="field">
22
+ <div class="outlined">
23
+ <div id="cardCvc" ref="cardCvc" class="input"></div>
24
+ <label for="cardCvc">CVC</label>
25
+ <div class="baseline"></div>
26
+ </div>
27
+ </div>
28
+ </v-col>
29
+ </v-row>
30
+ </div>
31
+ </template>
32
+
33
+ <script>
34
+ export default {
35
+ props: {
36
+ spec: { type: Object, required: true },
37
+ onComplete: {
38
+ type: Function,
39
+ required: true
40
+ },
41
+ onError: {
42
+ type: Function,
43
+ required: true
44
+ }
45
+ },
46
+ data() {
47
+ return {
48
+ stripe: null,
49
+ card: null,
50
+ errorMessages: []
51
+ };
52
+ },
53
+ watch: {
54
+ "$root.vueApp.stateUpdatedAt": function(val, oldVal) {
55
+ this.onComplete(this.stripe, this.card);
56
+ }
57
+ },
58
+ methods: {
59
+ $ready() {
60
+ this.stripe = Stripe(this.spec.publicKey);
61
+ const elements = this.stripe.elements();
62
+
63
+ const style = {
64
+ base: {
65
+ fontSize: "16px",
66
+ color: "#32325d"
67
+ }
68
+ };
69
+
70
+ const cardNumber = elements.create("cardNumber", {
71
+ showIcon: true,
72
+ style
73
+ });
74
+ cardNumber.mount(this.$refs.cardNumber);
75
+
76
+ const cardExpiry = elements.create("cardExpiry", {
77
+ style
78
+ });
79
+ cardExpiry.mount(this.$refs.cardExpiry);
80
+
81
+ const cardCvc = elements.create("cardCvc", {
82
+ style
83
+ });
84
+ cardCvc.mount(this.$refs.cardCvc);
85
+
86
+ this.card = cardNumber;
87
+ this._registerEvent([cardNumber, cardExpiry, cardCvc]);
88
+ },
89
+ _registerEvent(elements) {
90
+ elements.forEach((el, index) => {
91
+ el.addEventListener("change", event => {
92
+ const error = event.error;
93
+ if (error) {
94
+ this.errorMessages[index] = error.message;
95
+ } else {
96
+ this.errorMessages[index] = null;
97
+ }
98
+
99
+ this.onError(this.errorMessages.join(" "));
100
+ if (event.complete) {
101
+ this.onComplete(this.stripe, this.card);
102
+ }
103
+ });
104
+ });
105
+ }
106
+ }
107
+ };
108
+ </script>
109
+
110
+ <style lang="scss" scoped>
111
+ .field {
112
+ position: relative;
113
+ width: 100%;
114
+ height: 60px;
115
+
116
+ label {
117
+ font-size: 16px;
118
+ font-weight: bolder;
119
+ color: #000000;
120
+ position: absolute;
121
+ left: 0;
122
+ bottom: 8px;
123
+ color: rgba(0, 0, 0, 0.6);
124
+ overflow: hidden;
125
+ text-overflow: ellipsis;
126
+ white-space: nowrap;
127
+ transform-origin: 0 50%;
128
+ cursor: text;
129
+ pointer-events: none;
130
+ }
131
+
132
+ .input {
133
+ position: absolute;
134
+ width: 100%;
135
+ left: 0;
136
+ bottom: 0;
137
+ padding-bottom: 7px;
138
+ color: #32325d;
139
+ background-color: transparent;
140
+ }
141
+
142
+ .baseline {
143
+ position: absolute;
144
+ width: 100%;
145
+ }
146
+
147
+ .input.StripeElement--focus + label {
148
+ color: #1976d2 !important;
149
+ }
150
+
151
+ .input.StripeElement--invalid + label {
152
+ color: #f44336 !important;
153
+ }
154
+
155
+ .input:hover + label + .baseline {
156
+ border-color: #000000;
157
+ }
158
+
159
+ .input.StripeElement--focus + label + .baseline {
160
+ border-color: #1976d2;
161
+ border-width: 2px;
162
+ }
163
+
164
+ .input.StripeElement--invalid + label + .baseline {
165
+ border-color: #f44336;
166
+ border-width: 2px;
167
+ }
168
+
169
+ .individual {
170
+ &:not(.outlined) {
171
+ label {
172
+ width: 100%;
173
+ transform: scale(0.75) translateY(-25px);
174
+ }
175
+
176
+ .baseline {
177
+ height: 1px;
178
+ left: 0;
179
+ bottom: 0;
180
+ border-bottom: solid 1px #999999;
181
+ }
182
+ }
183
+ }
184
+
185
+ .outlined {
186
+ label {
187
+ transform: scale(0.75) translateY(-52px);
188
+ background: white;
189
+ padding: 0 5px;
190
+ margin-left: 10px;
191
+ z-index: 10;
192
+ }
193
+
194
+ .baseline {
195
+ height: 60px;
196
+ border: solid 1px #999999;
197
+ border-radius: 4px;
198
+ }
199
+
200
+ .input {
201
+ padding: 0 12px;
202
+ transform: translateY(-20px);
203
+ z-index: 8;
204
+ }
205
+ }
206
+ }
207
+ </style>