@startinblox/core 0.0.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 (157) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +182 -0
  3. package/dist/_snowpack/pkg/autolinker.js +4429 -0
  4. package/dist/_snowpack/pkg/autolinker.js.map +1 -0
  5. package/dist/_snowpack/pkg/common/_baseUnary-c1edb653.js +353 -0
  6. package/dist/_snowpack/pkg/common/_baseUnary-c1edb653.js.map +1 -0
  7. package/dist/_snowpack/pkg/common/_commonjsHelpers-37fa8da4.js +26 -0
  8. package/dist/_snowpack/pkg/common/_commonjsHelpers-37fa8da4.js.map +1 -0
  9. package/dist/_snowpack/pkg/common/decode-26fbf385.js +185 -0
  10. package/dist/_snowpack/pkg/common/decode-26fbf385.js.map +1 -0
  11. package/dist/_snowpack/pkg/common/lit-html-3647afce.js +1104 -0
  12. package/dist/_snowpack/pkg/common/lit-html-3647afce.js.map +1 -0
  13. package/dist/_snowpack/pkg/delta-markdown-for-quill.js +26198 -0
  14. package/dist/_snowpack/pkg/delta-markdown-for-quill.js.map +1 -0
  15. package/dist/_snowpack/pkg/dialog-polyfill.js +827 -0
  16. package/dist/_snowpack/pkg/dialog-polyfill.js.map +1 -0
  17. package/dist/_snowpack/pkg/fusejs.js +1593 -0
  18. package/dist/_snowpack/pkg/fusejs.js.map +1 -0
  19. package/dist/_snowpack/pkg/import-map.json +24 -0
  20. package/dist/_snowpack/pkg/jsonld-context-parser.js +836 -0
  21. package/dist/_snowpack/pkg/jsonld-context-parser.js.map +1 -0
  22. package/dist/_snowpack/pkg/leaflet/dist/leaflet.css +640 -0
  23. package/dist/_snowpack/pkg/leaflet/dist/leaflet.css.proxy.js +10 -0
  24. package/dist/_snowpack/pkg/leaflet.markercluster/dist/MarkerCluster.Default.css +60 -0
  25. package/dist/_snowpack/pkg/leaflet.markercluster/dist/MarkerCluster.Default.css.proxy.js +10 -0
  26. package/dist/_snowpack/pkg/leaflet.markercluster/dist/MarkerCluster.css +14 -0
  27. package/dist/_snowpack/pkg/leaflet.markercluster/dist/MarkerCluster.css.proxy.js +10 -0
  28. package/dist/_snowpack/pkg/lit-html/directives/if-defined.js +39 -0
  29. package/dist/_snowpack/pkg/lit-html/directives/if-defined.js.map +1 -0
  30. package/dist/_snowpack/pkg/lit-html/directives/unsafe-html.js +48 -0
  31. package/dist/_snowpack/pkg/lit-html/directives/unsafe-html.js.map +1 -0
  32. package/dist/_snowpack/pkg/lit-html/directives/until.js +87 -0
  33. package/dist/_snowpack/pkg/lit-html/directives/until.js.map +1 -0
  34. package/dist/_snowpack/pkg/lit-html.js +94 -0
  35. package/dist/_snowpack/pkg/lit-html.js.map +1 -0
  36. package/dist/_snowpack/pkg/markdown-it-link-attributes.js +68 -0
  37. package/dist/_snowpack/pkg/markdown-it-link-attributes.js.map +1 -0
  38. package/dist/_snowpack/pkg/markdown-it.js +11307 -0
  39. package/dist/_snowpack/pkg/markdown-it.js.map +1 -0
  40. package/dist/_snowpack/pkg/quill/dist/quill.snow.css +945 -0
  41. package/dist/_snowpack/pkg/quill/dist/quill.snow.css.proxy.js +10 -0
  42. package/dist/_snowpack/pkg/quill-delta-to-markdown.js +971 -0
  43. package/dist/_snowpack/pkg/quill-delta-to-markdown.js.map +1 -0
  44. package/dist/_snowpack/pkg/quill.js +14442 -0
  45. package/dist/_snowpack/pkg/quill.js.map +1 -0
  46. package/dist/_snowpack/pkg/slim-select.js +714 -0
  47. package/dist/_snowpack/pkg/slim-select.js.map +1 -0
  48. package/dist/_snowpack/pkg/tui-calendar/dist/tui-calendar.css +1149 -0
  49. package/dist/_snowpack/pkg/tui-calendar/dist/tui-calendar.css.proxy.js +10 -0
  50. package/dist/_snowpack/pkg/tui-calendar.js +46507 -0
  51. package/dist/_snowpack/pkg/tui-calendar.js.map +1 -0
  52. package/dist/components/solid-ac-checker.js +45 -0
  53. package/dist/components/solid-calendar.js +66 -0
  54. package/dist/components/solid-delete.js +96 -0
  55. package/dist/components/solid-display.js +150 -0
  56. package/dist/components/solid-form-search.js +177 -0
  57. package/dist/components/solid-form.js +259 -0
  58. package/dist/components/solid-lang.js +35 -0
  59. package/dist/components/solid-map.js +204 -0
  60. package/dist/components/solid-table.js +181 -0
  61. package/dist/components/solid-widget.js +72 -0
  62. package/dist/import.css +4 -0
  63. package/dist/index.js +49 -0
  64. package/dist/libs/Component.js +13 -0
  65. package/dist/libs/ComponentFactory.js +168 -0
  66. package/dist/libs/Compositor.js +96 -0
  67. package/dist/libs/Sib.js +44 -0
  68. package/dist/libs/filter.js +184 -0
  69. package/dist/libs/helpers.js +194 -0
  70. package/dist/libs/interfaces.js +6 -0
  71. package/dist/libs/lit-helpers.js +142 -0
  72. package/dist/libs/polyfills.js +37 -0
  73. package/dist/libs/store/server-pagination.js +22 -0
  74. package/dist/libs/store/server-search.js +35 -0
  75. package/dist/libs/store/store.js +814 -0
  76. package/dist/locales/en.json +10 -0
  77. package/dist/locales/en.json.proxy.js +2 -0
  78. package/dist/locales/fr.json +10 -0
  79. package/dist/locales/fr.json.proxy.js +2 -0
  80. package/dist/mixins/attributeBinderMixin.js +116 -0
  81. package/dist/mixins/contextMixin.js +26 -0
  82. package/dist/mixins/counterMixin.js +54 -0
  83. package/dist/mixins/federationMixin.js +51 -0
  84. package/dist/mixins/filterMixin.js +155 -0
  85. package/dist/mixins/grouperMixin.js +73 -0
  86. package/dist/mixins/highlighterMixin.js +36 -0
  87. package/dist/mixins/interfaces.js +6 -0
  88. package/dist/mixins/listMixin.js +105 -0
  89. package/dist/mixins/nextMixin.js +23 -0
  90. package/dist/mixins/paginateMixin.js +97 -0
  91. package/dist/mixins/requiredMixin.js +26 -0
  92. package/dist/mixins/serverPaginationMixin.js +122 -0
  93. package/dist/mixins/sorterMixin.js +131 -0
  94. package/dist/mixins/storeMixin.js +109 -0
  95. package/dist/mixins/translationMixin.js +58 -0
  96. package/dist/mixins/validationMixin.js +95 -0
  97. package/dist/mixins/widgetMixin.js +351 -0
  98. package/dist/new-widgets/attributeMixins/actionMixin.js +13 -0
  99. package/dist/new-widgets/attributeMixins/blankMixin.js +7 -0
  100. package/dist/new-widgets/attributeMixins/booleanMixin.js +7 -0
  101. package/dist/new-widgets/attributeMixins/index.js +19 -0
  102. package/dist/new-widgets/attributeMixins/mailtoMixin.js +7 -0
  103. package/dist/new-widgets/attributeMixins/multipleMixin.js +27 -0
  104. package/dist/new-widgets/attributeMixins/numberMixin.js +7 -0
  105. package/dist/new-widgets/attributeMixins/placeholderMixin.js +16 -0
  106. package/dist/new-widgets/attributeMixins/telMixin.js +7 -0
  107. package/dist/new-widgets/baseWidgetMixin.js +109 -0
  108. package/dist/new-widgets/callbackMixins/autocompletionMixin.js +96 -0
  109. package/dist/new-widgets/callbackMixins/index.js +7 -0
  110. package/dist/new-widgets/callbackMixins/richtextMixin.js +37 -0
  111. package/dist/new-widgets/callbackMixins/slimselect.css +2 -0
  112. package/dist/new-widgets/callbackMixins/slimselect.css.proxy.js +10 -0
  113. package/dist/new-widgets/interfaces.js +1 -0
  114. package/dist/new-widgets/new-widget-factory.js +91 -0
  115. package/dist/new-widgets/templateAdditionMixins/addableMixin.js +26 -0
  116. package/dist/new-widgets/templateAdditionMixins/index.js +13 -0
  117. package/dist/new-widgets/templateAdditionMixins/labelLastMixin.js +16 -0
  118. package/dist/new-widgets/templateAdditionMixins/labelMixin.js +18 -0
  119. package/dist/new-widgets/templates/defaultTemplatesDirectory.js +29 -0
  120. package/dist/new-widgets/templates/displayTemplatesDirectory.js +54 -0
  121. package/dist/new-widgets/templates/formTemplatesDirectory.js +432 -0
  122. package/dist/new-widgets/templates/groupTemplatesDirectory.js +11 -0
  123. package/dist/new-widgets/templates/index.js +6 -0
  124. package/dist/new-widgets/templates/setTemplatesDirectory.js +16 -0
  125. package/dist/new-widgets/templatesDependencies/altMixin.js +12 -0
  126. package/dist/new-widgets/templatesDependencies/editableMixin.js +60 -0
  127. package/dist/new-widgets/templatesDependencies/filterRangeFormMixin.js +34 -0
  128. package/dist/new-widgets/templatesDependencies/formCheckboxMixin.js +10 -0
  129. package/dist/new-widgets/templatesDependencies/formCheckboxesMixin.js +41 -0
  130. package/dist/new-widgets/templatesDependencies/formDropdownMixin.js +56 -0
  131. package/dist/new-widgets/templatesDependencies/formFileMixin.js +82 -0
  132. package/dist/new-widgets/templatesDependencies/formLengthMixin.js +18 -0
  133. package/dist/new-widgets/templatesDependencies/formMinMaxMixin.js +18 -0
  134. package/dist/new-widgets/templatesDependencies/formMixin.js +56 -0
  135. package/dist/new-widgets/templatesDependencies/formNumberMixin.js +10 -0
  136. package/dist/new-widgets/templatesDependencies/formRadioMixin.js +12 -0
  137. package/dist/new-widgets/templatesDependencies/formStepMixin.js +12 -0
  138. package/dist/new-widgets/templatesDependencies/linkTextMixin.js +13 -0
  139. package/dist/new-widgets/templatesDependencies/multipleFormMixin.js +112 -0
  140. package/dist/new-widgets/templatesDependencies/multipleselectFormMixin.js +65 -0
  141. package/dist/new-widgets/templatesDependencies/patternMixin.js +18 -0
  142. package/dist/new-widgets/templatesDependencies/rangeMixin.js +100 -0
  143. package/dist/new-widgets/templatesDependencies/setMixin.js +9 -0
  144. package/dist/new-widgets/templatesDependencies/valueRichtextMixin.js +9 -0
  145. package/dist/new-widgets/valueTransformationMixins/autolinkMixin.js +14 -0
  146. package/dist/new-widgets/valueTransformationMixins/dateMixin.js +29 -0
  147. package/dist/new-widgets/valueTransformationMixins/dateTimeMixin.js +12 -0
  148. package/dist/new-widgets/valueTransformationMixins/index.js +15 -0
  149. package/dist/new-widgets/valueTransformationMixins/markdownMixin.js +30 -0
  150. package/dist/new-widgets/valueTransformationMixins/multilineMixin.js +13 -0
  151. package/dist/new-widgets/valueTransformationMixins/oembedMixin.js +21 -0
  152. package/dist/solid-template-element.js +144 -0
  153. package/dist/style/default-theme.css +24 -0
  154. package/dist/style/default-theme.css.proxy.js +10 -0
  155. package/dist/widgets/baseWidget.js +268 -0
  156. package/dist/widgets/widget-factory.js +22 -0
  157. package/package.json +117 -0
@@ -0,0 +1,97 @@
1
+ import { html } from "../_snowpack/pkg/lit-html.js";
2
+ const PaginateMixin = {
3
+ name: 'paginate-mixin',
4
+ use: [],
5
+ attributes: {
6
+ paginateBy: {
7
+ type: Number,
8
+ default: 0
9
+ },
10
+ paginateLoop: {
11
+ type: String,
12
+ default: null
13
+ }
14
+ },
15
+ initialState: {
16
+ currentPage: []
17
+ },
18
+ created() {
19
+ this.currentPage = [];
20
+ },
21
+ attached() {
22
+ this.listPostProcessors.push(this.paginateCallback.bind(this));
23
+ },
24
+ async paginateCallback(resources, listPostProcessors, div, context) {
25
+ if (this.paginateBy > 0) {
26
+ if (!this.currentPage[context]) this.currentPage[context] = 1;
27
+ const parentDiv = this.initParentPaginationDiv(div, context);
28
+ this.renderCallbacks.push({
29
+ template: this.renderPaginationNav(this.getPageCount(resources.length), context, div),
30
+ parent: parentDiv
31
+ });
32
+ const firstElementIndex = (this.getCurrentPage(context) - 1) * this.paginateBy;
33
+ resources = resources.slice(firstElementIndex, firstElementIndex + this.paginateBy);
34
+ }
35
+ const nextProcessor = listPostProcessors.shift();
36
+ if (nextProcessor) await nextProcessor(resources, listPostProcessors, div, context);
37
+ },
38
+ getNavElement(div) {
39
+ const insertNode = div.parentNode || div;
40
+ return insertNode.querySelector(`nav[data-id="nav"]`);
41
+ },
42
+ /**
43
+ * Find nav element or create it if not existing
44
+ * @param div - insert nav next to this div
45
+ */
46
+ initParentPaginationDiv(div) {
47
+ let nav = this.getNavElement(div);
48
+ if (!nav) {
49
+ nav = document.createElement('nav');
50
+ nav.setAttribute('data-id', 'nav');
51
+ const insertNode = div.parentNode || div;
52
+ insertNode.appendChild(nav);
53
+ }
54
+ return nav;
55
+ },
56
+ getCurrentPage(context) {
57
+ return this.currentPage[context];
58
+ },
59
+ setCurrentPage(page, context, pageCount) {
60
+ if (page < 1) page = !this.shouldLoop() ? 1 : pageCount;
61
+ if (page > pageCount) page = !this.shouldLoop() ? pageCount : 1;
62
+ this.currentPage[context] = page;
63
+ this.empty();
64
+ this.populate();
65
+ },
66
+ getPageCount(size) {
67
+ return Math.max(1, Math.ceil(size / this.paginateBy));
68
+ },
69
+ shouldLoop() {
70
+ return this.paginateLoop !== null;
71
+ },
72
+ /**
73
+ * Create pagination template
74
+ * @param pageCount
75
+ * @param context
76
+ */
77
+ renderPaginationNav(pageCount, context, div) {
78
+ this.getNavElement(div).toggleAttribute('hidden', pageCount <= 1);
79
+ const currentPage = this.getCurrentPage(context);
80
+ return html`
81
+ <button
82
+ data-id="prev"
83
+ ?disabled=${!this.shouldLoop() && currentPage <= 1}
84
+ @click=${() => this.setCurrentPage(currentPage - 1, context, pageCount)}
85
+ >←</button>
86
+ <button
87
+ data-id="next"
88
+ ?disabled=${!this.shouldLoop() && currentPage >= pageCount}
89
+ @click=${() => this.setCurrentPage(currentPage + 1, context, pageCount)}
90
+ >→</button>
91
+ <span>
92
+ <span data-id="current">${currentPage}</span> / <span data-id="count">${String(pageCount)}</span>
93
+ </span>
94
+ `;
95
+ }
96
+ };
97
+ export { PaginateMixin };
@@ -0,0 +1,26 @@
1
+ const RequiredMixin = {
2
+ name: 'required-mixin',
3
+ use: [],
4
+ attached() {
5
+ this.listPostProcessors.push(this.requiredResources.bind(this));
6
+ },
7
+ async requiredResources(resources, listPostProcessors, div, context) {
8
+ const displays = [];
9
+ const requiredFields = Array.from(this.element.attributes).filter(attr => attr.name.startsWith('required-')).map(attr => attr['name'].replace('required-', ''));
10
+ if (requiredFields.length) {
11
+ for (let resource of resources) {
12
+ let hasProps = true;
13
+ for (let field of requiredFields) {
14
+ if ((await resource[field]) == null || (await resource[field]) == "") {
15
+ hasProps = false;
16
+ continue;
17
+ }
18
+ }
19
+ if (hasProps) displays.push(resource);
20
+ }
21
+ }
22
+ const nextProcessor = listPostProcessors.shift();
23
+ if (nextProcessor) await nextProcessor(requiredFields.length ? displays : resources, listPostProcessors, div, context);
24
+ }
25
+ };
26
+ export { RequiredMixin };
@@ -0,0 +1,122 @@
1
+ import { html, render } from "../_snowpack/pkg/lit-html.js";
2
+ const ServerPaginationMixin = {
3
+ name: 'server-pagination-mixin',
4
+ use: [],
5
+ attributes: {
6
+ limit: {
7
+ type: Number,
8
+ default: undefined
9
+ },
10
+ offset: {
11
+ type: Number,
12
+ default: undefined
13
+ },
14
+ pageCount: {
15
+ type: Number,
16
+ default: 1000
17
+ },
18
+ pageNumber: {
19
+ type: Number,
20
+ default: 0
21
+ }
22
+ },
23
+ initialState: {
24
+ currentOffset: []
25
+ },
26
+ attached() {
27
+ if (this.limit) {
28
+ this.setCurrentOffset(this.resourceId, 0);
29
+ const parentDiv = this.initServerPaginationDiv(this.div);
30
+ this.renderCallbacks.push({
31
+ template: this.renderServerPaginationNav(this.resourceId, parentDiv),
32
+ parent: parentDiv
33
+ });
34
+ }
35
+ },
36
+ getCurrentOffset(resourceId, limit) {
37
+ return this.currentOffset[resourceId + "#p" + limit];
38
+ },
39
+ async setCurrentOffset(resourceId, offset) {
40
+ let index = resourceId + "#p" + this.limit;
41
+ this.currentOffset[index] = this.offset = offset;
42
+ this.pageNumber = Number(this.offset / this.limit);
43
+ this.currentPage[resourceId] = this.pageNumber;
44
+ await this.fetchData(this.dataSrc);
45
+ },
46
+ async decreaseCurrentOffset(resourceId) {
47
+ let index = resourceId + "#p" + this.limit;
48
+ this.currentOffset[index] = this.offset = this.offset - this.limit;
49
+ this.currentPage[index] = this.offset / this.limit;
50
+ this.pageNumber = this.offset / this.limit;
51
+ this.updateNavButtons(resourceId, index, -1);
52
+ await this.fetchData(this.dataSrc);
53
+ },
54
+ async increaseCurrentOffset(resourceId) {
55
+ let index = resourceId + "#p" + this.limit;
56
+ this.currentOffset[index] = this.offset = this.offset + this.limit;
57
+ this.currentPage[index] = this.offset / this.limit;
58
+ this.updateNavButtons(resourceId, index, 1);
59
+ await this.fetchData(this.dataSrc);
60
+ },
61
+ updateNavButtons(resourceId, index, variance) {
62
+ this.element.querySelector("[data-id='prev']").disabled = this.currentOffset[index] <= 0;
63
+ this.element.querySelector("[data-id='next']").disabled = this.currentOffset[index] * this.limit >= this.pageCount;
64
+ this.element.querySelector("[data-id='current']").innerText = this.getCurrentServedPage(resourceId, variance);
65
+ },
66
+ getServerNavElement(div) {
67
+ if (div) {
68
+ const insertNode = div.parentNode || div;
69
+ return insertNode.querySelector(`nav[data-id="nav"]`);
70
+ }
71
+ return null;
72
+ },
73
+ getCurrentServedPage(context, variance) {
74
+ this.currentPage[context] = Number(this.currentPage[context]) + variance;
75
+ return this.currentPage[context];
76
+ },
77
+ /**
78
+ * Find nav element or create it if not existing
79
+ * @param div - insert nav next to this div
80
+ */
81
+ initServerPaginationDiv(div) {
82
+ let nav = this.getServerNavElement(div);
83
+ if (!nav) {
84
+ nav = document.createElement('nav');
85
+ nav.setAttribute('data-id', 'nav');
86
+ const insertNode = div.parentNode || div;
87
+ insertNode.appendChild(nav);
88
+ }
89
+ return nav;
90
+ },
91
+ /**
92
+ * Create pagination template
93
+ */
94
+ renderServerPaginationNav(resourceId, div) {
95
+ if (this.limit) {
96
+ const currentOffset = this.getCurrentOffset(resourceId, this.limit);
97
+ var currentPageNumber = this.getCurrentServedPage(resourceId, 1);
98
+ const pageCount = Math.ceil(this.pageCount / this.limit);
99
+ render(html`
100
+ <button
101
+ data-id="prev"
102
+ ?disabled=${currentOffset <= 0}
103
+ @click=${() => this.decreaseCurrentOffset(resourceId)}
104
+ >←</button>
105
+ <button
106
+ data-id="next"
107
+ ?disabled=${currentOffset >= (pageCount - 1) * this.limit}
108
+ @click=${() => this.increaseCurrentOffset(resourceId)}
109
+ >→</button>
110
+ <span>
111
+ <span data-id="current">
112
+ ${currentPageNumber}
113
+ </span> /
114
+ <span data-id="count">
115
+ ${this.pageCount}
116
+ </span>
117
+ </span>
118
+ `, div);
119
+ }
120
+ }
121
+ };
122
+ export { ServerPaginationMixin };
@@ -0,0 +1,131 @@
1
+ const SorterMixin = {
2
+ name: 'sorter-mixin',
3
+ use: [],
4
+ attributes: {
5
+ orderBy: {
6
+ type: String,
7
+ default: null
8
+ },
9
+ orderAsc: {
10
+ type: String,
11
+ default: null
12
+ },
13
+ orderDesc: {
14
+ type: String,
15
+ default: null
16
+ },
17
+ orderByRandom: {
18
+ type: String,
19
+ default: null
20
+ },
21
+ sortedBy: {
22
+ type: String,
23
+ default: null,
24
+ callback(newValue) {
25
+ // if we change search form, re-populate
26
+ if (newValue && this.sortForm && newValue !== this.sortForm.getAttribute('id')) {
27
+ this.sortForm = null;
28
+ this.populate();
29
+ }
30
+ }
31
+ }
32
+ },
33
+ initialState: {
34
+ randomOrder: null
35
+ },
36
+ attached() {
37
+ this.listPostProcessors.push(this.orderCallback.bind(this));
38
+ },
39
+ created() {
40
+ this.randomOrder = [];
41
+ },
42
+ async sorterList() {
43
+ if (!this.resource) return;
44
+ this.empty();
45
+ await this.populate();
46
+ },
47
+ linkSorterForm() {
48
+ this.sortForm.addEventListener('formChange', () => {
49
+ this.sorterList();
50
+ });
51
+ },
52
+ async orderCallback(resources, listPostProcessors, div, context) {
53
+ if (this.orderBy) this.orderAsc = this.orderBy; // retrocompatibility. remove in 0.15
54
+ let sortingKey = '';
55
+ let orderValueToSort = '';
56
+
57
+ // if order-asc or order-desc attribute
58
+ if (this.orderAsc || this.orderDesc) {
59
+ sortingKey = this.orderAsc || this.orderDesc;
60
+ }
61
+ // if sorted-by attribute (solid-form-search data used)
62
+ else if (this.sortedBy) {
63
+ const sortedBy = this.sortedBy;
64
+ if (sortedBy != null) {
65
+ if (!this.sortForm) {
66
+ this.sortForm = document.getElementById(sortedBy);
67
+ if (!this.sortForm) throw `#${sortedBy} is not in DOM`;
68
+ this.linkSorterForm();
69
+ }
70
+ if (!this.sortForm.component.value.field) {
71
+ console.warn('The attribute field does not exist');
72
+ } else {
73
+ sortingKey = this.sortForm.component.value.field['value'];
74
+ }
75
+ const orderField = this.sortForm.component.value.order;
76
+ orderValueToSort = orderField && orderField.value ? orderField.value : 'asc';
77
+ }
78
+ }
79
+ // sorting data according to the defined value of sortingKey
80
+ if (sortingKey) {
81
+ let orderToSort = true; // set 'asc' by default
82
+ if (this.orderDesc || orderValueToSort == "desc") orderToSort = false;
83
+ resources = (await Promise.all(resources.map(async resource => ({
84
+ sortingKey: await resource[sortingKey],
85
+ // fetch sorting value
86
+ proxy: resource // and keep proxy
87
+ })))).sort(this.sortValuesByKey("sortingKey", orderToSort)) // sort this array
88
+ .map(r => r.proxy); // re-create array
89
+ }
90
+ // if order-by-random attribute
91
+ else if (this.isRandomSorted()) {
92
+ resources = this.shuffleResources(resources); // shuffle resources
93
+ }
94
+
95
+ const nextProcessor = listPostProcessors.shift();
96
+ if (nextProcessor) await nextProcessor(resources, listPostProcessors, div, context);
97
+ },
98
+ isRandomSorted() {
99
+ return this.orderByRandom !== null;
100
+ },
101
+ sortValuesByKey(key, asc) {
102
+ return function (a, b) {
103
+ if (!a[key]) return 1;
104
+ if (!b[key]) return -1;
105
+ const varA = typeof a[key] === 'string' ? a[key].toUpperCase() : a[key];
106
+ const varB = typeof b[key] === 'string' ? b[key].toUpperCase() : b[key];
107
+ let comparison = 0;
108
+ if (varA > varB) comparison = asc ? 1 : -1;else if (varA < varB) comparison = asc ? -1 : 1;
109
+ return comparison;
110
+ };
111
+ },
112
+ shuffleResources(array) {
113
+ let currentIndex = array.length;
114
+ let temporaryValue;
115
+ let randomIndex;
116
+ if (this.randomOrder.length !== array.length) {
117
+ // if no random order existing
118
+ this.randomOrder = [...Array(array.length).keys()]; // generate array of indexes
119
+ while (0 !== currentIndex) {
120
+ randomIndex = Math.floor(Math.random() * currentIndex);
121
+ currentIndex -= 1;
122
+ temporaryValue = this.randomOrder[currentIndex];
123
+ this.randomOrder[currentIndex] = this.randomOrder[randomIndex];
124
+ this.randomOrder[randomIndex] = temporaryValue;
125
+ }
126
+ }
127
+ return this.randomOrder.map(i => array[i]); // rebuild array with random order
128
+ }
129
+ };
130
+
131
+ export { SorterMixin };
@@ -0,0 +1,109 @@
1
+ import { store } from '../libs/store/store.js';
2
+ import { formatAttributesToServerSearchOptions, mergeServerSearchOptions } from '../libs/store/server-search.js';
3
+ import { AttributeBinderMixin } from './attributeBinderMixin.js';
4
+ import { ContextMixin } from './contextMixin.js';
5
+ import { ServerPaginationMixin } from './serverPaginationMixin.js';
6
+ import { formatAttributesToServerPaginationOptions } from '../libs/store/server-pagination.js';
7
+ const StoreMixin = {
8
+ name: 'store-mixin',
9
+ use: [AttributeBinderMixin, ContextMixin, ServerPaginationMixin],
10
+ attributes: {
11
+ noRender: {
12
+ type: String,
13
+ default: null,
14
+ callback: function (value) {
15
+ if (value === null) this.fetchData(this.dataSrc);
16
+ }
17
+ },
18
+ dataSrc: {
19
+ type: String,
20
+ default: null,
21
+ callback: async function (value) {
22
+ const filteredOnServer = this.element.attributes['filtered-on']?.value === 'server';
23
+ const limited = this.element.attributes['limit']?.value !== undefined;
24
+ if (this.noRender === null && !filteredOnServer && !limited) {
25
+ await this.fetchData(value);
26
+ } else if (this.noRender === null && !filteredOnServer) {
27
+ this.resourceId = value;
28
+ }
29
+ }
30
+ },
31
+ loaderId: {
32
+ type: String,
33
+ default: ''
34
+ },
35
+ nestedField: {
36
+ type: String,
37
+ default: null
38
+ }
39
+ },
40
+ initialState: {
41
+ resourceId: null,
42
+ subscription: null
43
+ },
44
+ created() {
45
+ if (this.element.closest('[no-render]')) this.noRender = ''; // if embedded in no-render, apply no-render to himself
46
+ },
47
+
48
+ detached() {
49
+ if (this.subscription) PubSub.unsubscribe(this.subscription);
50
+ },
51
+ get resource() {
52
+ let id = this.resourceId;
53
+ if (this.limit) {
54
+ id = this.resourceId + "#p" + this.limit + "?o" + this.offset;
55
+ }
56
+ const serverSearch = mergeServerSearchOptions(formatAttributesToServerSearchOptions(this.element.attributes), this.getDynamicServerSearch?.() // from `filterMixin`
57
+ );
58
+
59
+ return id ? store.get(id, serverSearch) : null;
60
+ },
61
+ get loader() {
62
+ return this.loaderId ? document.getElementById(this.loaderId) : null;
63
+ },
64
+ async fetchData(value) {
65
+ this.empty();
66
+ if (this.subscription) PubSub.unsubscribe(this.subscription);
67
+ if (!value || value == "undefined") return;
68
+ this.resourceId = value;
69
+ if (this.nestedField) {
70
+ const resource = await store.getData(value, this.context);
71
+ const nestedResource = resource ? await resource[this.nestedField] : null;
72
+ this.resourceId = nestedResource ? nestedResource['@id'] : null;
73
+ if (!this.resourceId) throw `Error: the key "${this.nestedField}" does not exist on the resource`;
74
+ }
75
+ this.updateNavigateSubscription();
76
+ this.subscription = PubSub.subscribe(this.resourceId, this.updateDOM.bind(this));
77
+ const serverPagination = formatAttributesToServerPaginationOptions(this.element.attributes);
78
+ const dynamicServerSearch = this.getDynamicServerSearch?.(); // from `filterMixin`
79
+ const serverSearch = mergeServerSearchOptions(formatAttributesToServerSearchOptions(this.element.attributes), dynamicServerSearch);
80
+ const forceRefetch = !!dynamicServerSearch;
81
+ await store.getData(this.resourceId, this.context, undefined, undefined, forceRefetch, serverPagination, serverSearch);
82
+ this.updateDOM();
83
+ },
84
+ toggleLoaderHidden(toggle) {
85
+ if (this.loader) this.loader.toggleAttribute('hidden', toggle);
86
+ },
87
+ updateNavigateSubscription() {},
88
+ async updateDOM() {
89
+ this.toggleLoaderHidden(false); // brings a loader out if the attribute is set
90
+ this.empty();
91
+ await this.replaceAttributesData();
92
+ await this.populate();
93
+ setTimeout(() =>
94
+ // Brings the dispatchEvent at the end of the queue
95
+ this.element.dispatchEvent(new CustomEvent('populate', {
96
+ detail: {
97
+ resource: {
98
+ "@id": this.dataSrc
99
+ }
100
+ }
101
+ })));
102
+ this.toggleLoaderHidden(true);
103
+ },
104
+ empty() {},
105
+ update() {
106
+ if (this.noRender === null) this.updateDOM();
107
+ }
108
+ };
109
+ export { StoreMixin };
@@ -0,0 +1,58 @@
1
+ import { store } from "../libs/store/store.js";
2
+ const TranslationMixin = {
3
+ name: 'translation-mixin',
4
+ use: [],
5
+ initialState: {
6
+ translationData: {}
7
+ },
8
+ created() {
9
+ this.getLang();
10
+ },
11
+ /**
12
+ * Returns the translation module
13
+ * @param langCode - string: language needed in 2 char
14
+ * @returns - object: {key: translation}
15
+ */
16
+ async getTranslationModule(langCode) {
17
+ const translationsModules = {
18
+ // define modules in a static way, snowpack does not support dynamic strings here
19
+ en: () => import("../locales/en.json.proxy.js"),
20
+ fr: () => import("../locales/fr.json.proxy.js")
21
+ };
22
+ if (!translationsModules[langCode]) {
23
+ // set default to EN if the file does not exist
24
+ console.warn(`${langCode}.json translation file may not exist, English is setted by default`);
25
+ langCode = 'en';
26
+ }
27
+ const module = await translationsModules[langCode]();
28
+ return module.default;
29
+ },
30
+ /**
31
+ * Loads the right translation file and reload the component
32
+ */
33
+ getLang() {
34
+ const languageStorage = store._getLanguage();
35
+ if (languageStorage) {
36
+ if (window.fetchTranslationPromise === undefined) {
37
+ // if translation data are not already fetched
38
+ window.fetchTranslationPromise = this.getTranslationModule(languageStorage);
39
+ }
40
+ window.fetchTranslationPromise.then(res => {
41
+ if (res) {
42
+ this.translationData = res; // stock data in object passed to traduction method below
43
+ this.update(); // update the rendering in components and widgets
44
+ }
45
+ });
46
+ }
47
+ },
48
+
49
+ /**
50
+ * Returns translation for a given key
51
+ * @param tradKey - string: key
52
+ * @returns - string: translation
53
+ */
54
+ t(tradKey) {
55
+ return this.translationData[tradKey] || '';
56
+ }
57
+ };
58
+ export { TranslationMixin };
@@ -0,0 +1,95 @@
1
+ import dialogPolyfill from '../_snowpack/pkg/dialog-polyfill.js';
2
+ import { html } from '../_snowpack/pkg/lit-html.js';
3
+ import { ifDefined } from '../_snowpack/pkg/lit-html/directives/if-defined.js';
4
+ import { uniqID } from '../libs/helpers.js';
5
+ import { TranslationMixin } from './translationMixin.js';
6
+ import { preHTML } from '../libs/lit-helpers.js';
7
+ const ValidationMixin = {
8
+ name: 'validation-mixin',
9
+ use: [TranslationMixin],
10
+ attributes: {
11
+ confirmationMessage: {
12
+ type: String,
13
+ default: null
14
+ },
15
+ confirmationType: {
16
+ type: String,
17
+ default: null
18
+ },
19
+ confirmationSubmitText: {
20
+ type: String,
21
+ default: null
22
+ },
23
+ confirmationCancelText: {
24
+ type: String,
25
+ default: null
26
+ },
27
+ confirmationSubmitClass: {
28
+ type: String,
29
+ default: undefined
30
+ },
31
+ confirmationCancelClass: {
32
+ type: String,
33
+ default: undefined
34
+ },
35
+ confirmationWidget: {
36
+ type: String,
37
+ default: undefined
38
+ }
39
+ },
40
+ created() {
41
+ this.dialogID = uniqID();
42
+ },
43
+ showModal() {
44
+ var dialog = document.getElementById(this.dialogID);
45
+ dialogPolyfill.registerDialog(dialog);
46
+ return dialog.showModal();
47
+ },
48
+ performAction() {
49
+ // Console warning if conf-type attr not filled AND conf-message filled
50
+ if (this.element.hasAttribute('confirmation-message') && !this.confirmationType) console.warn('confirmation-type attribute is missing.');
51
+ // Data directly submitted OR confirm dialog modal displayed
52
+ if (!this.confirmationType || this.confirmationType == "confirm" && confirm(this.confirmationMessage || this.t("validation.message"))) this.validateModal();
53
+ // Customisable dialog modal opened
54
+ if (this.confirmationType == "dialog") {
55
+ this.showModal();
56
+ }
57
+ },
58
+ getModalDialog() {
59
+ if (this.confirmationType == 'dialog') {
60
+ const quitDialog = () => {
61
+ var dialog = document.getElementById(this.dialogID);
62
+ if (dialog == null) return;
63
+ dialog.close();
64
+ };
65
+ const confirmChoice = () => {
66
+ this.validateModal();
67
+ quitDialog();
68
+ };
69
+ return html`
70
+ <dialog id="${this.dialogID}">
71
+ ${this.confirmationWidget ? preHTML`
72
+ <${this.confirmationWidget} value=${this.resourceId}></${this.confirmationWidget}>
73
+ ` : html`
74
+ <p>${this.confirmationMessage || this.t("validation.message")}</p>
75
+ `}
76
+ <div>
77
+ <button
78
+ @click=${confirmChoice}
79
+ class=${ifDefined(this.confirmationSubmitClass)}
80
+ >
81
+ ${this.confirmationSubmitText || this.t("validation.submit-text")}
82
+ </button>
83
+ <button
84
+ @click=${quitDialog}
85
+ class=${ifDefined(this.confirmationCancelClass)}
86
+ >
87
+ ${this.confirmationCancelText || this.t("validation.cancel-text")}
88
+ </button>
89
+ </div>
90
+ </dialog>
91
+ `;
92
+ } else return '';
93
+ }
94
+ };
95
+ export { ValidationMixin };