glib-web 0.16.0 → 0.18.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 (51) hide show
  1. package/LICENSE +0 -0
  2. package/action.js +1 -1
  3. package/actions/auth/restart.js +0 -0
  4. package/actions/components/update.js +15 -2
  5. package/actions/dialogs/oauth.js +0 -0
  6. package/actions/dialogs/options.js +0 -0
  7. package/actions/http/get.js +18 -3
  8. package/actions/windows/openWeb.js +0 -0
  9. package/app.vue +7 -6
  10. package/components/_message.vue +0 -0
  11. package/components/charts/pie.vue +34 -0
  12. package/components/component.vue +5 -1
  13. package/components/datetime.vue +0 -0
  14. package/components/fab.vue +0 -0
  15. package/components/fields/check.vue +1 -0
  16. package/components/fields/checkGroup.vue +8 -1
  17. package/components/fields/country/countries.js +0 -0
  18. package/components/fields/country/field.vue +0 -0
  19. package/components/fields/country/regions.js +0 -0
  20. package/components/fields/datetime.vue +0 -0
  21. package/components/fields/dynamicSelect.vue +0 -0
  22. package/components/fields/richText.vue +45 -16
  23. package/components/fields/select.vue +0 -0
  24. package/components/fields/text.vue +6 -2
  25. package/components/fields/timeZone.vue +0 -0
  26. package/components/hr.vue +0 -0
  27. package/components/html.vue +0 -0
  28. package/components/mixins/events.js +12 -4
  29. package/components/mixins/longClick.js +0 -0
  30. package/components/mixins/scrolling.js +0 -0
  31. package/components/mixins/table/export.js +0 -0
  32. package/components/mixins/table/import.js +0 -0
  33. package/components/p.vue +0 -0
  34. package/components/panels/form.vue +3 -2
  35. package/components/progressCircle.vue +22 -0
  36. package/components/shareButton.vue +2 -1
  37. package/keys.js +0 -0
  38. package/nav/drawer.vue +2 -79
  39. package/nav/drawerButton.vue +0 -0
  40. package/package.json +1 -1
  41. package/settings.json.example +0 -0
  42. package/styles/test.sass +0 -0
  43. package/styles/test.scss +0 -0
  44. package/templates/unsupported.vue +0 -0
  45. package/utils/dom.js +0 -0
  46. package/utils/eventFiltering.js +11 -0
  47. package/utils/format.js +1 -1
  48. package/utils/public.js +0 -0
  49. package/utils/settings.js +0 -0
  50. package/utils/storage.js +0 -0
  51. package/utils/url.js +0 -0
package/LICENSE CHANGED
File without changes
package/action.js CHANGED
@@ -166,7 +166,7 @@ export default class Action {
166
166
  }
167
167
  }
168
168
 
169
- static handleResponse(response, component) {
169
+ static handleResponse(response, component, url) {
170
170
  // TODO: The execution should be in the following order: onResponse, page render, onLoad
171
171
  if (response.header || response.body || response.footer) {
172
172
  Utils.http.forceComponentUpdate(() => {
File without changes
@@ -1,3 +1,5 @@
1
+ import Vue from "vue";
2
+
1
3
  export default class {
2
4
  execute(spec, component) {
3
5
  if (!spec.views.length > 1) {
@@ -7,7 +9,18 @@ export default class {
7
9
  if (!target) console.error("no component found :" + spec.targetId);
8
10
 
9
11
  Object.assign(target.spec, spec.views[0]);
10
- target.$ready();
11
- target.$forceUpdate();
12
+ this.updateComponent(target);
13
+ }
14
+
15
+ updateComponent(component) {
16
+ component.$ready();
17
+ component.$forceUpdate();
18
+
19
+ // Execute on next tick to ensure that the child has received the updated spec.
20
+ Vue.nextTick(() => {
21
+ component.$children.find(child => {
22
+ this.updateComponent(child);
23
+ });
24
+ });
12
25
  }
13
26
  }
File without changes
File without changes
@@ -1,7 +1,22 @@
1
1
  export default class {
2
2
  execute(properties, controller) {
3
- GLib.http.execute(properties, "GET", controller, response =>
4
- GLib.action.handleResponse(response, controller)
5
- );
3
+ const currentUrl = window.location.href;
4
+ // const htmlUrl = Utils.url.htmlUrl(properties["url"]);
5
+
6
+ GLib.http.execute(properties, "GET", controller, (page, response) => {
7
+ Utils.type.ifString(properties.historyUrl, historyUrl => {
8
+ const cleanUrl = Utils.url.htmlUrl(historyUrl);
9
+ if (cleanUrl !== currentUrl) {
10
+ console.log("URL", cleanUrl, response.url, response);
11
+ const data = Object.assign({}, window.vueApp.page, {
12
+ replayGetResponse: page.onResponse
13
+ });
14
+
15
+ // Utils.history.pushPage(data, historyUrl);
16
+ Utils.history.pushPage(data, cleanUrl);
17
+ }
18
+ });
19
+ GLib.action.handleResponse(page, controller);
20
+ });
6
21
  }
7
22
  }
File without changes
package/app.vue CHANGED
@@ -58,8 +58,7 @@ export default {
58
58
  },
59
59
  data() {
60
60
  return {
61
- title: "...",
62
- formSpec: null
61
+ title: "..."
63
62
  };
64
63
  },
65
64
  computed: {
@@ -77,6 +76,10 @@ export default {
77
76
  return "panels-form";
78
77
  }
79
78
  return "div";
79
+ },
80
+ // Use computed to ensure that the spec gets updated when the user navigates to another page.
81
+ formSpec() {
82
+ return this.page.fullPageForm;
80
83
  }
81
84
  },
82
85
  watch: {
@@ -93,9 +96,8 @@ export default {
93
96
  Utils.http.promptIfDirtyOnUnload();
94
97
  },
95
98
  methods: {
96
- $ready: function() {
99
+ $ready() {
97
100
  document.title = this.page.title;
98
- this.formSpec = this.page.fullPageForm;
99
101
 
100
102
  this.$wsInitPhoenixSocket(this.page.phoenixSocket);
101
103
  this.$wsInitActionCable(this.page.actionCable);
@@ -103,8 +105,6 @@ export default {
103
105
  if (this.$gtag) {
104
106
  if (!Utils.settings.isDev) {
105
107
  console.log(`Tracking analytics: ${window.location}`);
106
- // this.$ga.page(window.location);
107
-
108
108
  this.$gtag.pageview({
109
109
  page_location: window.location
110
110
  });
@@ -117,6 +117,7 @@ export default {
117
117
  setTimeout(() => {
118
118
  // Wait until page is rendered
119
119
  GLib.action.execute(this.page.onRefocus, this);
120
+ GLib.action.execute(this.page.replayGetResponse, this);
120
121
  });
121
122
  } else {
122
123
  setTimeout(() => {
File without changes
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <pie-chart
3
+ :style="genericStyles()"
4
+ :class="$classes()"
5
+ :data="series"
6
+ :library="options"
7
+ ></pie-chart>
8
+ </template>
9
+
10
+ <script>
11
+ export default {
12
+ mixins: [],
13
+ props: {
14
+ spec: { type: Object, required: true }
15
+ },
16
+ data: function() {
17
+ return {
18
+ series: []
19
+ };
20
+ },
21
+ methods: {
22
+ $ready() {
23
+ this.series = this.spec.dataSeries.reduce((prev, curr) => {
24
+ let obj = {};
25
+ obj[curr.title] = curr.value;
26
+
27
+ return Object.assign(prev, obj);
28
+ }, {});
29
+ }
30
+ }
31
+ };
32
+ </script>
33
+
34
+ <style scoped></style>
@@ -46,6 +46,7 @@ import Chip from "./chip";
46
46
  import Datetime from "./datetime";
47
47
 
48
48
  import ProgressBar from "./progressbar";
49
+ import ProgressCircle from "./progressCircle.vue";
49
50
 
50
51
  import Image from "./image";
51
52
  import Avatar from "./avatar";
@@ -114,6 +115,7 @@ import SelectBanner from "./banners/select";
114
115
 
115
116
  import LineChart from "./charts/line";
116
117
  import ColumnChart from "./charts/column";
118
+ import PieChart from "./charts/pie";
117
119
 
118
120
  import ShareButton from "./shareButton";
119
121
 
@@ -132,6 +134,7 @@ export default {
132
134
  "views-chip": Chip,
133
135
  "views-datetime": Datetime,
134
136
  "views-progressBar": ProgressBar,
137
+ "views-progressCircle": ProgressCircle,
135
138
 
136
139
  "views-image": Image,
137
140
  "views-avatar": Avatar,
@@ -200,7 +203,8 @@ export default {
200
203
  "banners-select": SelectBanner,
201
204
 
202
205
  "charts-line": LineChart,
203
- "charts-column": ColumnChart
206
+ "charts-column": ColumnChart,
207
+ "charts-pie": PieChart
204
208
  },
205
209
  props: {
206
210
  spec: { type: Object, required: true }
File without changes
File without changes
@@ -6,6 +6,7 @@
6
6
  <v-checkbox
7
7
  v-model="fieldModel"
8
8
  :name="fieldName"
9
+ :disabled="spec.readOnly"
9
10
  :value="spec.checkValue"
10
11
  :label="fieldModel ? spec.onLabel || spec.label : spec.label"
11
12
  :on-icon="spec.onIcon"
@@ -8,7 +8,7 @@
8
8
  <!-- <fields-hidden v-if="!anyChecked" :spec="uncheckSpec" /> -->
9
9
 
10
10
  <div v-for="(item, index) in spec.childViews" :key="index">
11
- <glib-component :spec="item" />
11
+ <glib-component :spec="childSpec(item)" />
12
12
  </div>
13
13
 
14
14
  <v-text-field
@@ -76,6 +76,13 @@ export default {
76
76
  return;
77
77
  }
78
78
  });
79
+ },
80
+ childSpec(item) {
81
+ if (this.spec.readOnly) {
82
+ return Object.assign(item, { readOnly: this.spec.readOnly });
83
+ }
84
+
85
+ return item;
79
86
  }
80
87
  }
81
88
  };
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,13 +1,7 @@
1
1
  <template>
2
2
  <div :style="$styles()" :class="$classes()">
3
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
- />
4
+ <VueEditor v-model="rawValue" :editor-toolbar="customToolbar" />
11
5
  <input type="hidden" :name="spec.name" :value="markdownValue" />
12
6
  <input
13
7
  v-for="(imageKey, index) in imageKeys"
@@ -39,7 +33,7 @@ export default {
39
33
  ["bold", "italic", "strike"],
40
34
  [{ header: 1 }, { header: 2 }],
41
35
  [{ list: "ordered" }, { list: "bullet" }],
42
- ["blockquote", "link"]
36
+ ["image", "link"]
43
37
  ],
44
38
  rawValue: "",
45
39
  cleanValue: "",
@@ -49,6 +43,14 @@ export default {
49
43
  imageUploader: {},
50
44
  turndownService: new TurndownService({ headingStyle: "atx" })
51
45
  }),
46
+ computed: {
47
+ showProgress: function() {
48
+ return this.progress.value >= 0;
49
+ },
50
+ markdownValue: function() {
51
+ return this.turndownService.turndown(this.rawValue);
52
+ }
53
+ },
52
54
  // mounted: function () {
53
55
  // const vm = this
54
56
  // this.rawValue = (this.spec.value || "").replace(/\{\{image([0-9]+)\}\}/g, function (_, index) {
@@ -62,13 +64,8 @@ export default {
62
64
  // return "{{IMAGE_NOT_FOUND}}"
63
65
  // })
64
66
  // },
65
- computed: {
66
- showProgress: function() {
67
- return this.progress.value >= 0;
68
- },
69
- markdownValue: function() {
70
- return this.turndownService.turndown(this.rawValue);
71
- }
67
+ mounted() {
68
+ this.registerScrollEvent();
72
69
  },
73
70
  methods: {
74
71
  $ready() {
@@ -162,12 +159,39 @@ export default {
162
159
  };
163
160
  reader.readAsDataURL(file);
164
161
  vm.progress.value = -1;
162
+ },
163
+ updateToolbar: function(wrapper, toolbar, container) {
164
+ if (wrapper.scrollTop >= container.offsetTop) {
165
+ toolbar.classList.add("sticky");
166
+ toolbar.style.top = `${wrapper.offsetTop}px`;
167
+ toolbar.style.left = `${wrapper.offsetLeft}px`;
168
+ toolbar.style.width = `${wrapper.offsetWidth}px`;
169
+ } else {
170
+ toolbar.classList.remove("sticky");
171
+ toolbar.style.top = "auto";
172
+ toolbar.style.left = "auto";
173
+ toolbar.style.width = "auto";
174
+ }
175
+ },
176
+ registerScrollEvent: function() {
177
+ const wrapper = document.querySelector(".v-dialog") || window;
178
+ const toolbar = this.$el.querySelector(".ql-toolbar");
179
+ const container = this.$el.querySelector(".ql-container");
180
+
181
+ if (wrapper) {
182
+ wrapper.addEventListener("scroll", () =>
183
+ this.updateToolbar(wrapper, toolbar, container)
184
+ );
185
+ window.addEventListener("resize", () =>
186
+ this.updateToolbar(wrapper, toolbar, container)
187
+ );
188
+ }
165
189
  }
166
190
  }
167
191
  };
168
192
  </script>
169
193
 
170
- <style scoped>
194
+ <style>
171
195
  /*
172
196
  @import "~vue2-editor/dist/vue2-editor.css";
173
197
  @import '~quill/dist/quill.core.css';
@@ -177,4 +201,9 @@ export default {
177
201
  height: 375px;
178
202
  }
179
203
  */
204
+ .ql-toolbar.sticky {
205
+ position: fixed;
206
+ z-index: 99;
207
+ background-color: white;
208
+ }
180
209
  </style>
File without changes
@@ -35,6 +35,8 @@
35
35
  </template>
36
36
 
37
37
  <script>
38
+ import eventFiltering from "../../utils/eventFiltering";
39
+
38
40
  export default {
39
41
  props: {
40
42
  spec: { type: Object, required: true },
@@ -125,8 +127,10 @@ export default {
125
127
  classes() {
126
128
  return this.$classes().concat("g-text-field--hintless");
127
129
  },
128
- // TODO: Consider using debounce to wait until user has finished typing.
129
- onChange() {
130
+ onChange: eventFiltering.debounce(function() {
131
+ this.executeActionWithParams();
132
+ }, 300),
133
+ executeActionWithParams() {
130
134
  Utils.type.ifObject(this.spec.onChange, onChange => {
131
135
  this.$nextTick(() => {
132
136
  const params = {
File without changes
package/components/hr.vue CHANGED
File without changes
File without changes
@@ -25,6 +25,9 @@ export default {
25
25
  return this.$data._events === null;
26
26
  }
27
27
  },
28
+ created() {
29
+ this.$created();
30
+ },
28
31
  mounted() {
29
32
  this._executeIfReady(false);
30
33
  this.$mounted();
@@ -129,14 +132,22 @@ export default {
129
132
  }
130
133
  this.$data._events = null;
131
134
  },
135
+ // Order of execution:
136
+ // Initial page load: $created() -> $ready() -> $mounted() -> $updated() (because of $ready(), may get called multiple times)
137
+ // windows_open: $created() (only if it isn't reused) -> $ready() -> $mounted() (only if it isn't reused) -> $updated()
138
+ // components_update: $ready() -> $updated() (because of $ready(), may get called multiple times)
132
139
  $ready() {
140
+ // To be overridden. Initialize component data here.
141
+ // This method has to be idempotent because it might get called multiple times (due to components_update).
142
+ },
143
+ $created() {
133
144
  // To be overridden
134
145
  },
135
146
  $tearDown() {
136
147
  // To be overridden
137
148
  },
138
149
  $mounted() {
139
- // To be overridden
150
+ // To be overridden. Put one-off event listener initialization here (e.g. $onEvent()).
140
151
  },
141
152
  $updated() {
142
153
  // To be overridden
@@ -167,8 +178,5 @@ export default {
167
178
  GLib.action.execute(this.spec.onTypeEnd, this);
168
179
  }, duration);
169
180
  }
170
- // $onZero() {
171
- // GLib.action.execute(this.spec.onZero, null, this);
172
- // },
173
181
  }
174
182
  };
File without changes
File without changes
File without changes
File without changes
package/components/p.vue CHANGED
File without changes
@@ -46,7 +46,7 @@ export default {
46
46
  }
47
47
  },
48
48
  methods: {
49
- $ready: function() {
49
+ $mounted() {
50
50
  this.$onEvent("forms/addSubmit", e => {
51
51
  this.submitButtons.push(e.data);
52
52
  });
@@ -66,7 +66,8 @@ export default {
66
66
  this.$onEvent("forms/directSubmit", e => {
67
67
  this.directSubmit();
68
68
  });
69
-
69
+ },
70
+ $ready() {
70
71
  this.formElement = this.$refs.form.$el;
71
72
  this.parentStyles = this.genericStyles({ width: this.spec.width });
72
73
 
@@ -0,0 +1,22 @@
1
+ <template>
2
+ <v-progress-circular
3
+ :class="$classes()"
4
+ :rotate="spec.rotate || 270"
5
+ :size="spec.size || 100"
6
+ :width="spec.width || 20"
7
+ :color="spec.color"
8
+ :value="spec.value"
9
+ >
10
+ <span class="grey--text text--lighten-1 text-h5">{{ spec.text }}</span>
11
+ </v-progress-circular>
12
+ </template>
13
+
14
+ <script>
15
+ export default {
16
+ props: {
17
+ spec: { type: Object, required: true }
18
+ }
19
+ };
20
+ </script>
21
+
22
+ <style scoped></style>
@@ -101,7 +101,8 @@ export default {
101
101
  // manually attach event listener because @click not working
102
102
  parentElement
103
103
  .querySelector(`a.${this.$el.classList[0]}`)
104
- .addEventListener("click", () => {
104
+ .addEventListener("click", e => {
105
+ e.preventDefault();
105
106
  Action.execute(this.spec.onClick, this);
106
107
  });
107
108
  }
package/keys.js CHANGED
File without changes
package/nav/drawer.vue CHANGED
@@ -26,6 +26,8 @@
26
26
  <panels-responsive :spec="spec.header" />
27
27
  </template>
28
28
 
29
+ <glib-component v-if="spec.custom" :spec="spec.custom" />
30
+
29
31
  <v-list dense class="pt-0">
30
32
  <div v-for="(item, index) in spec.rows" :key="index" class="nav-item">
31
33
  <div v-if="item.type == 'button'" class="indicator"></div>
@@ -50,75 +52,6 @@
50
52
  import NavDrawerButton from "./drawerButton";
51
53
  import NavDrawerLabel from "./drawerLabel";
52
54
 
53
- const activeClass = (element, action) => {
54
- let indicator = element.querySelector(".indicator");
55
- if (indicator) {
56
- indicator.classList[action]("active");
57
- }
58
- let icon = element.querySelector(".v-list-item__action");
59
- if (icon) {
60
- icon.classList[action]("active");
61
- }
62
- };
63
-
64
- const comparePathname = (hrefPathname, locationPathname) => {
65
- let value = 0;
66
- const loc = locationPathname.split("/").filter(v => v);
67
- const hr = hrefPathname.split("/").filter(v => v);
68
-
69
- if (loc.length == hr.length) value = value + 1;
70
-
71
- loc.forEach((route, index) => {
72
- if (!hr[index]) {
73
- value = value + 0;
74
- } else if (hr[index] == route) {
75
- value = value + 1;
76
- } else if (hr[index] != route) {
77
- value = value - 2;
78
- }
79
- });
80
-
81
- return value;
82
- };
83
-
84
- const navigationMap = (element, locationPathname) => {
85
- return Array.from(element.querySelectorAll(".nav-item")).reduce(
86
- (prev, curr) => {
87
- let a = curr.querySelector("a");
88
- if (a) {
89
- let obj = {};
90
- obj[new URL(a.href).pathname] = {
91
- element: curr,
92
- matchValue: comparePathname(
93
- new URL(a.href).pathname,
94
- locationPathname
95
- )
96
- };
97
- return Object.assign(prev, obj);
98
- } else {
99
- return prev;
100
- }
101
- },
102
- {}
103
- );
104
- };
105
-
106
- const getActiveNav = navigationMap => {
107
- let currentRoute = "";
108
- let maxMatchValue = null;
109
-
110
- for (let route in navigationMap) {
111
- if (!maxMatchValue) {
112
- maxMatchValue = navigationMap[route].matchValue;
113
- currentRoute = route;
114
- } else if (maxMatchValue < navigationMap[route].matchValue) {
115
- maxMatchValue = navigationMap[route].matchValue;
116
- currentRoute = route;
117
- }
118
- }
119
- return navigationMap[currentRoute];
120
- };
121
-
122
55
  export default {
123
56
  components: {
124
57
  "nav-drawerButton": NavDrawerButton,
@@ -169,7 +102,6 @@ export default {
169
102
  methods: {
170
103
  $ready() {
171
104
  this.shrunk = this.mini = this.cssClasses.includes("mini");
172
- this.updateNavigationStyle(window.location);
173
105
 
174
106
  // this.$el.addEventListener('drawers/clickButton', () => { this.updateState(false) }, false)
175
107
  this.$el.addEventListener("drawers/clickButton", () => {
@@ -183,15 +115,6 @@ export default {
183
115
  },
184
116
  expandOnHover() {
185
117
  return this.mini;
186
- },
187
- updateNavigationStyle(urlObject) {
188
- const navMap = navigationMap(this.$el, urlObject.pathname);
189
- // remove all active class
190
- for (let route in navMap) {
191
- activeClass(navMap[route].element, "remove");
192
- }
193
- // add active class to nav
194
- activeClass(getActiveNav(navMap).element, "add");
195
118
  }
196
119
  }
197
120
  };
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glib-web",
3
- "version": "0.16.0",
3
+ "version": "0.18.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
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
@@ -0,0 +1,11 @@
1
+ export default class {
2
+ static debounce(func, timeout = 300) {
3
+ let timer;
4
+ return function(...args) {
5
+ clearTimeout(timer);
6
+ timer = setTimeout(() => {
7
+ func.apply(this, args);
8
+ }, timeout);
9
+ };
10
+ }
11
+ }
package/utils/format.js CHANGED
@@ -2,7 +2,7 @@ import { marked } from "marked";
2
2
 
3
3
  export default class {
4
4
  static markdown(text) {
5
- return marked(text, { sanitize: true });
5
+ return marked(text);
6
6
  }
7
7
 
8
8
  static local_iso8601(date) {
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