glib-web 1.0.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/LICENSE +0 -0
  2. package/actions/auth/restart.js +0 -0
  3. package/actions/dialogs/oauth.js +0 -0
  4. package/actions/dialogs/options.js +0 -0
  5. package/actions/forms/submit.js +3 -1
  6. package/actions/windows/openWeb.js +0 -0
  7. package/components/_message.vue +0 -0
  8. package/components/datetime.vue +0 -0
  9. package/components/fab.vue +0 -0
  10. package/components/fields/country/countries.js +0 -0
  11. package/components/fields/country/field.vue +0 -0
  12. package/components/fields/country/regions.js +0 -0
  13. package/components/fields/datetime.vue +0 -0
  14. package/components/fields/dynamicSelect.vue +0 -0
  15. package/components/fields/richText.vue +127 -48
  16. package/components/fields/select.vue +0 -0
  17. package/components/fields/timeZone.vue +0 -0
  18. package/components/hr.vue +0 -0
  19. package/components/html.vue +0 -0
  20. package/components/map.vue +24 -7
  21. package/components/markdown.vue +9 -0
  22. package/components/mixins/generic.js +11 -0
  23. package/components/mixins/longClick.js +0 -0
  24. package/components/mixins/scrolling.js +0 -0
  25. package/components/mixins/table/export.js +0 -0
  26. package/components/mixins/table/import.js +0 -0
  27. package/components/p.vue +0 -0
  28. package/components/panels/form.vue +9 -5
  29. package/components/panels/timeline.vue +37 -54
  30. package/keys.js +0 -0
  31. package/nav/drawerButton.vue +0 -0
  32. package/package.json +2 -1
  33. package/settings.json.example +0 -0
  34. package/styles/test.sass +0 -0
  35. package/styles/test.scss +0 -0
  36. package/templates/unsupported.vue +0 -0
  37. package/utils/dom.js +0 -0
  38. package/utils/form.js +2 -2
  39. package/utils/public.js +0 -0
  40. package/utils/settings.js +0 -0
  41. package/utils/storage.js +0 -0
  42. package/utils/url.js +0 -0
package/LICENSE CHANGED
File without changes
File without changes
File without changes
File without changes
@@ -1,5 +1,7 @@
1
1
  export default class {
2
2
  execute(properties, component) {
3
- component.$dispatchEvent("forms/directSubmit");
3
+ component.$dispatchEvent("forms/directSubmit", {
4
+ url: properties.overrideUrl
5
+ });
4
6
  }
5
7
  }
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,34 +1,53 @@
1
1
  <template>
2
2
  <div :style="$styles()" :class="$classes()">
3
+ <v-tabs v-model="mode" fixed-tabs>
4
+ <v-tab>Editor</v-tab>
5
+ <v-tab>Code</v-tab>
6
+ </v-tabs>
7
+
3
8
  <v-progress-linear v-if="showProgress" v-model="progress.value" />
9
+
10
+ <!-- Remove the editor to avoid circular updating between this editor and the raw field. -->
4
11
  <VueEditor
5
- v-model="rawValue"
12
+ v-if="!rawMode"
13
+ id="rich-editor"
14
+ v-model="htmlValue"
6
15
  :editor-toolbar="customToolbar"
7
16
  use-custom-image-handler
8
- @text-change="separateOutImages"
17
+ @text-change="onEditorChange"
9
18
  @image-added="uploadImage"
10
19
  />
11
- <input type="hidden" :name="spec.name" :value="produceValue" />
12
- <input
13
- v-for="(imageKey, index) in imageKeys"
14
- :key="index"
15
- type="hidden"
16
- :name="imageUploader.name"
17
- :value="images[imageKey]"
18
- />
20
+ <!-- Hide these fields but don't remove them because these are the values that will get submitted. -->
21
+ <div :style="{ display: rawMode ? 'block' : 'none' }">
22
+ <v-textarea
23
+ id="raw-editor"
24
+ v-model="producedValue"
25
+ :name="spec.name"
26
+ :style="$styles()"
27
+ :class="$classes()"
28
+ :outlined="$classes().includes('outlined')"
29
+ @input="onCodeChange"
30
+ ></v-textarea>
31
+ <v-text-field
32
+ v-for="(imageKey, index) in imageKeys"
33
+ :key="index"
34
+ :label="`Image ${index + 1}`"
35
+ :style="$styles()"
36
+ :outlined="$classes().includes('outlined')"
37
+ type="text"
38
+ :name="imageUploader.name"
39
+ :value="images[imageKey]"
40
+ />
41
+ </div>
19
42
  </div>
20
43
  </template>
21
44
 
22
45
  <script>
23
46
  import Uploader from "../../utils/uploader";
24
- import { VueEditor } from "vue2-editor";
47
+ import { VueEditor, Quill } from "vue2-editor";
25
48
  import TurndownService from "turndown";
26
49
  import { gfm } from "turndown-plugin-gfm";
27
50
 
28
- // import EventController, {
29
- // DISABLE_SUBMIT_BUTTON
30
- // } from "../../utils/global-event-controller";
31
-
32
51
  export default {
33
52
  components: { VueEditor },
34
53
  props: {
@@ -41,26 +60,52 @@ export default {
41
60
  [{ list: "ordered" }, { list: "bullet" }],
42
61
  ["image", "link"]
43
62
  ],
44
- rawValue: "",
45
- cleanValue: "",
63
+ htmlValue: "",
64
+ cleanValue: null,
65
+ producedValue: "",
46
66
  images: {},
47
67
  imageKeys: [],
48
68
  progress: { value: -1 },
49
69
  imageUploader: {},
50
- produce: "markdown",
70
+ produce: null,
71
+ mode: null,
51
72
  turndownService: new TurndownService({ headingStyle: "atx" })
52
73
  }),
53
74
  computed: {
54
- showProgress: function() {
75
+ showProgress() {
55
76
  return this.progress.value >= 0;
56
77
  },
57
- produceValue: function() {
58
- if (this.produce == "html") {
59
- return this.cleanValue;
60
- } else if (this.produce == "markdown") {
61
- return this.turndownService.turndown(this.cleanValue);
62
- } else {
63
- return null;
78
+ rawMode() {
79
+ return this.mode == 1;
80
+ }
81
+ },
82
+ watch: {
83
+ cleanValue(val, oldVal) {
84
+ if (oldVal == null) {
85
+ // Don't update `producedValue` if this is first-time initialization to preserve the original value.
86
+ return;
87
+ }
88
+ switch (this.produce) {
89
+ case "html":
90
+ this.producedValue = val;
91
+ break;
92
+ case "markdown":
93
+ this.producedValue = this.turndownService.turndown(val);
94
+ break;
95
+ default:
96
+ console.log(`Unsupported format: ${this.produce}`);
97
+ }
98
+ },
99
+ producedValue(val) {
100
+ switch (this.produce) {
101
+ case "html":
102
+ this.htmlValue = val;
103
+ break;
104
+ case "markdown":
105
+ this.htmlValue = this.toHtmlValue(val);
106
+ break;
107
+ default:
108
+ console.log(`Unsupported format: ${this.produce}`);
64
109
  }
65
110
  }
66
111
  },
@@ -69,6 +114,8 @@ export default {
69
114
  },
70
115
  methods: {
71
116
  $ready() {
117
+ this.produce = this.spec.produce || "markdown";
118
+
72
119
  this.turndownService.use(gfm);
73
120
  this.turndownService.addRule("strikethrough", {
74
121
  filter: ["del", "s", "strike"],
@@ -77,29 +124,39 @@ export default {
77
124
  }
78
125
  });
79
126
 
80
- const vm = this;
81
- this.rawValue = (this.spec.value || "").replace(
82
- /\{\{image([0-9]+)\}\}/g,
83
- function(_, index) {
84
- const image = vm.spec.images[index - 1];
85
- if (
86
- image &&
87
- vm.$type.isString(image.value) &&
88
- vm.$type.isString(image.fileUrl)
89
- ) {
90
- const url = image.fileUrl;
91
- const key = url.hashCode().toString();
92
- vm.images[key] = image.value;
93
- return url;
94
- }
95
- return "{{IMAGE_NOT_FOUND}}";
127
+ this.turndownService.addRule("codeblock", {
128
+ filter: ["pre"],
129
+ replacement: function(content) {
130
+ return "```\n" + content + "```";
96
131
  }
97
- );
132
+ });
98
133
 
99
134
  this.imageUploader = this.spec.imageUploader;
100
- if (this.spec.produce) {
101
- this.produce = this.spec.produce;
102
- }
135
+
136
+ // Convert initial markdown value to html for displaying.
137
+ this.producedValue = this.spec.value || "";
138
+ this.htmlValue = this.toHtmlValue(this.producedValue);
139
+ },
140
+ toHtmlValue(producedValue) {
141
+ const vm = this;
142
+ var value = producedValue.replace(/\{\{image([0-9]+)\}\}/g, function(
143
+ _,
144
+ index
145
+ ) {
146
+ const image = vm.spec.images[index - 1];
147
+ if (
148
+ image &&
149
+ vm.$type.isString(image.value) &&
150
+ vm.$type.isString(image.fileUrl)
151
+ ) {
152
+ const url = image.fileUrl;
153
+ const key = url.hashCode().toString();
154
+ vm.images[key] = image.value;
155
+ return url;
156
+ }
157
+ return "{{IMAGE_NOT_FOUND}}";
158
+ });
159
+ return this.produce == "markdown" ? Utils.format.markdown(value) : value;
103
160
  },
104
161
  uploadImage: function(file, editor, cursorLocation) {
105
162
  let vm = this;
@@ -127,12 +184,30 @@ export default {
127
184
  });
128
185
  }
129
186
  },
187
+ onEditorChange() {
188
+ this.separateOutImages();
189
+ this.onCodeChange();
190
+ },
191
+ onCodeChange() {
192
+ Utils.type.ifObject(this.spec.onChange, onChange => {
193
+ this.$nextTick(() => {
194
+ const params = {
195
+ [this.spec.paramNameForFormData || "formData"]: {
196
+ [this.fieldName]: this.fieldModel
197
+ }
198
+ };
199
+
200
+ const data = Object.assign({}, onChange, params);
201
+ GLib.action.execute(data, this);
202
+ });
203
+ });
204
+ },
130
205
  separateOutImages: function() {
131
206
  const vm = this;
132
207
  var index = 0;
133
208
  vm.imageKeys.clear();
134
209
  // TODO: Fix to avoid replacing <video src="">
135
- this.cleanValue = this.rawValue.replace(/src="([^"]+)"/g, function(
210
+ this.cleanValue = this.htmlValue.replace(/src="([^"]+)"/g, function(
136
211
  _,
137
212
  imageValue
138
213
  ) {
@@ -204,9 +279,13 @@ export default {
204
279
  height: 375px;
205
280
  }
206
281
  */
207
- .ql-toolbar.sticky {
282
+ /* .ql-toolbar.sticky {
208
283
  position: fixed;
209
284
  z-index: 99;
210
285
  background-color: white;
286
+ } */
287
+ #rich-editor,
288
+ #raw-editor {
289
+ height: 350px;
211
290
  }
212
291
  </style>
File without changes
File without changes
package/components/hr.vue CHANGED
File without changes
File without changes
@@ -39,26 +39,35 @@
39
39
  :clickable="true"
40
40
  :title="String(marker.clusterSize || 1)"
41
41
  @click="onMarkerClick(marker, index)"
42
- ></gmap-marker>
42
+ >
43
+ </gmap-marker>
43
44
  </gmap-cluster>
44
45
  <template v-else>
45
- <gmap-marker
46
+ <gmap-custom-marker
46
47
  v-for="(marker, index) in markers"
47
48
  :key="index"
48
- :position="{ lat: marker.latitude, lng: marker.longitude }"
49
- :clickable="true"
50
- @click="onMarkerClick(marker, index)"
51
- ></gmap-marker>
49
+ :marker="{ lat: marker.latitude, lng: marker.longitude }"
50
+ @click.native="onMarkerClick(marker, index)"
51
+ >
52
+ <img v-if="marker.imageUrl" :src="marker.imageUrl" class="marker" />
53
+ <common-icon
54
+ v-else
55
+ class="marker"
56
+ :spec="{ material: { name: 'place', size: 40 }, color: '#c92b2a' }"
57
+ />
58
+ </gmap-custom-marker>
52
59
  </template>
53
60
  </gmap-map>
54
61
  </template>
55
62
 
56
63
  <script>
57
64
  import GmapCluster from "vue2-google-maps/dist/components/cluster";
65
+ import GmapCustomMarker from "vue2-gmap-custom-marker";
58
66
 
59
67
  export default {
60
68
  components: {
61
- "gmap-cluster": GmapCluster
69
+ "gmap-cluster": GmapCluster,
70
+ "gmap-custom-marker": GmapCustomMarker
62
71
  },
63
72
  props: {
64
73
  spec: { type: Object, required: true }
@@ -204,3 +213,11 @@ export default {
204
213
  // }
205
214
  };
206
215
  </script>
216
+
217
+ <style lang="scss" scoped>
218
+ .marker {
219
+ width: 40px;
220
+ height: 40px;
221
+ cursor: pointer;
222
+ }
223
+ </style>
@@ -61,6 +61,15 @@ export default {
61
61
  & > span > :last-child {
62
62
  margin-bottom: 0;
63
63
  }
64
+ pre {
65
+ background-color: #f0f0f0;
66
+ padding: 8px 10px;
67
+
68
+ & > code {
69
+ background-color: transparent;
70
+ padding: 0;
71
+ }
72
+ }
64
73
  }
65
74
  .line-clamp {
66
75
  display: -webkit-box;
@@ -20,6 +20,17 @@ export default {
20
20
  v => (v ? true : spec.message)
21
21
  ]);
22
22
  });
23
+ Utils.type.ifObject(val.format, spec => {
24
+ augmentedRules = augmentedRules.concat([
25
+ v => {
26
+ console.log("VALIDATE1");
27
+ if (v && !v.match(spec.regex)) {
28
+ return spec.message;
29
+ }
30
+ return true;
31
+ }
32
+ ]);
33
+ });
23
34
  });
24
35
  return augmentedRules;
25
36
  },
File without changes
File without changes
File without changes
File without changes
package/components/p.vue CHANGED
File without changes
@@ -64,7 +64,7 @@ export default {
64
64
  });
65
65
 
66
66
  this.$onEvent("forms/directSubmit", e => {
67
- this.directSubmit();
67
+ this.directSubmit(e.data.url);
68
68
  });
69
69
  },
70
70
  $ready() {
@@ -117,10 +117,14 @@ export default {
117
117
  );
118
118
  });
119
119
  },
120
- directSubmit() {
121
- this.validate(() => {
122
- GLib.form.submitData(this.formElement, this);
123
- });
120
+ directSubmit(overrideUrl = null) {
121
+ if (overrideUrl) {
122
+ GLib.form.submitData(this.formElement, this, overrideUrl);
123
+ } else {
124
+ this.validate(() => {
125
+ GLib.form.submitData(this.formElement, this);
126
+ });
127
+ }
124
128
  },
125
129
  validate(onPassed) {
126
130
  if (this.$refs.form.validate()) {
@@ -1,42 +1,32 @@
1
1
  <template>
2
2
  <v-container :class="$classes()">
3
- <v-timeline v-if="items" dense align-top>
3
+ <v-timeline v-if="events" dense align-top>
4
4
  <v-timeline-item
5
- v-for="(item, item_key) in items"
6
- :key="item_key"
5
+ v-for="(item, index) in events"
6
+ :key="index"
7
7
  color="white"
8
8
  fill-dot
9
9
  :small="$classes().includes('small')"
10
10
  :large="$classes().includes('large')"
11
- :class="timelineItemClasses(item)"
11
+ class="my-6"
12
12
  :hide-dot="item.hide_dot"
13
13
  >
14
14
  <template v-slot:icon>
15
- <div
16
- :class="$classes().includes('outlined') ? 'outlined-dots' : ''"
17
- :style="`border-color: ${dotColor(item)};`"
18
- >
19
- <div v-if="item.left_label" class="number-circle">
20
- {{ item.left_label }}
15
+ <div :class="$classes().includes('outlined') ? 'outlined-dots' : ''">
16
+ <div v-if="item.label" class="number-circle">
17
+ {{ item.label }}
18
+ </div>
19
+ <div v-else class="icon">
20
+ <common-icon
21
+ :spec="{
22
+ material: { name: item.icon, size: iconSize() },
23
+ color: item.color
24
+ }"
25
+ />
21
26
  </div>
22
- <!-- TODO: Use common-icon -->
23
- <v-icon v-else size="24" :color="dotColor(item)">
24
- {{ dotIcon(item) }}
25
- </v-icon>
26
27
  </div>
27
28
  </template>
28
-
29
- <div :class="item.subtitle ? 'mt-5' : 'mt-2'" class="content">
30
- <div
31
- :class="item.active ? 'font-weight-bold' : 'font-weight-regular'"
32
- >
33
- {{ item.label }}
34
- </div>
35
- <div class="font-weight-regular">
36
- {{ item.subtitle }}
37
- </div>
38
- <panels-responsive v-if="item.active" :spec="spec" />
39
- </div>
29
+ <panels-responsive :spec="{ childViews: [childViews[index]] }" />
40
30
  </v-timeline-item>
41
31
  </v-timeline>
42
32
  </v-container>
@@ -49,32 +39,17 @@ export default {
49
39
  },
50
40
  data() {
51
41
  return {
52
- items: this.spec.items,
53
- uncompletedIcon: this.spec.uncompletedIcon || "check_circle",
54
- completedIcon: this.spec.completedIcon || "radio_button_unchecked",
55
- completedColor: this.spec.completedColor || "blue",
56
- uncompletedColor: this.spec.uncompletedColor || "grey"
42
+ events: null,
43
+ childViews: null
57
44
  };
58
45
  },
59
46
  methods: {
60
- timelineItemClasses(item) {
61
- let classes = !item.completed && !item.active ? "uncompleted" : "";
62
-
63
- if (!this.$classes().includes("small")) {
64
- classes += " my-6";
65
- }
66
-
67
- return classes;
68
- },
69
- dotColor(item) {
70
- return !item.completed && !item.active
71
- ? this.uncompletedColor
72
- : this.completedColor;
47
+ $ready() {
48
+ this.events = this.spec.events;
49
+ this.childViews = this.spec.childViews;
73
50
  },
74
- dotIcon(item) {
75
- return item.active || item.completed
76
- ? item.uncompletedIcon || this.uncompletedIcon
77
- : item.completedIcon || this.completedIcon
51
+ iconSize() {
52
+ return this.$classes().includes("small") ? 16 : 24;
78
53
  }
79
54
  }
80
55
  };
@@ -84,18 +59,12 @@ export default {
84
59
  .v-timeline {
85
60
  padding-top: 0px;
86
61
  }
87
-
88
62
  .v-timeline-item {
89
63
  padding-bottom: 0px !important;
90
64
  }
91
65
  .container {
92
66
  padding-top: 0px;
93
67
  }
94
- .small {
95
- > .number-circle {
96
- font-size: 14px;
97
- }
98
- }
99
68
  .outlined-dots {
100
69
  border-radius: 50%;
101
70
  width: 100%;
@@ -111,4 +80,18 @@ export default {
111
80
  box-shadow: none;
112
81
  }
113
82
  }
83
+ .icon {
84
+ display: inline-flex;
85
+ vertical-align: middle;
86
+ }
87
+
88
+ // Size variations
89
+ .number-circle {
90
+ font-size: 16px;
91
+ }
92
+ .small {
93
+ .number-circle {
94
+ font-size: 14px;
95
+ }
96
+ }
114
97
  </style>
package/keys.js CHANGED
File without changes
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glib-web",
3
- "version": "1.0.1",
3
+ "version": "2.2.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -30,6 +30,7 @@
30
30
  "vue-youtube": "^1.4.0",
31
31
  "vue2-editor": "^2.9.1",
32
32
  "vue2-google-maps": "^0.10.6",
33
+ "vue2-gmap-custom-marker": "^6.1.1",
33
34
  "vuedraggable": "^2.24.1",
34
35
  "vuetify": "2.3.9"
35
36
  },
File without changes
package/styles/test.sass CHANGED
File without changes
package/styles/test.scss CHANGED
File without changes
File without changes
package/utils/dom.js CHANGED
File without changes
package/utils/form.js CHANGED
@@ -3,14 +3,14 @@ export default class {
3
3
  // Button -> Button.onClick() -> Utils.http.execute() -- doesn't save autofill values
4
4
  // Button -> Button.onClick() -> form.submit() -- doesn't execute Form.onSubmit(), so cannot call Utils.http.execute() there
5
5
  // Submit -> Form.onSubmit() -> Utils.http.execute() -- save autofill values and auto-submit when ENTER is pressed
6
- static submitData(form, component) {
6
+ static submitData(form, component, overrideUrl = null) {
7
7
  // Analogous to Rails' form_with's `local: true`
8
8
  if (form.dataset.local) {
9
9
  // Prevent onUnload dirty prompt.
10
10
  Utils.http.clearDirtyState();
11
11
  form.submit();
12
12
  } else {
13
- const url = form.getAttribute("action");
13
+ const url = overrideUrl ? overrideUrl : form.getAttribute("action");
14
14
  const formData = new FormData(form);
15
15
  const method = form.getAttribute("method");
16
16
  if (method.toUpperCase() === "GET") {
package/utils/public.js CHANGED
File without changes
package/utils/settings.js CHANGED
File without changes
package/utils/storage.js CHANGED
File without changes
package/utils/url.js CHANGED
File without changes