@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,10 @@
1
+ {
2
+ "autocompletion.placeholder": "Select a value",
3
+ "autocompletion.searchPlaceholder": "Search",
4
+ "autocompletion.searchText": "No result",
5
+ "solid-delete.button": "Delete",
6
+ "solid-form.submit-button": "Submit",
7
+ "validation.message": "Please, confirm your choice",
8
+ "validation.submit-text": "Yes",
9
+ "validation.cancel-text": "Cancel"
10
+ }
@@ -0,0 +1,2 @@
1
+ let json = {"autocompletion.placeholder":"Select a value","autocompletion.searchPlaceholder":"Search","autocompletion.searchText":"No result","solid-delete.button":"Delete","solid-form.submit-button":"Submit","validation.message":"Please, confirm your choice","validation.submit-text":"Yes","validation.cancel-text":"Cancel"};
2
+ export default json;
@@ -0,0 +1,10 @@
1
+ {
2
+ "autocompletion.placeholder": "Sélectionner une valeur",
3
+ "autocompletion.searchPlaceholder": "Rechercher",
4
+ "autocompletion.searchText": "Aucun résultat",
5
+ "solid-delete.button": "Supprimer",
6
+ "solid-form.submit-button": "Envoyer",
7
+ "validation.message": "Merci de confirmer votre choix",
8
+ "validation.submit-text": "Oui",
9
+ "validation.cancel-text": "Annuler"
10
+ }
@@ -0,0 +1,2 @@
1
+ let json = {"autocompletion.placeholder":"Sélectionner une valeur","autocompletion.searchPlaceholder":"Rechercher","autocompletion.searchText":"Aucun résultat","solid-delete.button":"Supprimer","solid-form.submit-button":"Envoyer","validation.message":"Merci de confirmer votre choix","validation.submit-text":"Oui","validation.cancel-text":"Annuler"};
2
+ export default json;
@@ -0,0 +1,116 @@
1
+ import { base_context, store } from '../libs/store/store.js';
2
+ const AttributeBinderMixin = {
3
+ name: 'attribute-binder-mixin',
4
+ use: [],
5
+ initialState: {
6
+ bindedAttributes: null
7
+ },
8
+ created() {
9
+ this.bindedAttributes = {};
10
+ },
11
+ /**
12
+ * Reset attributes values
13
+ */
14
+ resetAttributesData() {
15
+ for (let attr of Object.keys(this.bindedAttributes)) {
16
+ this.element.setAttribute(attr, this.bindedAttributes[attr]);
17
+ }
18
+ },
19
+ /**
20
+ * Replace store://XXX attributes by corresponding data
21
+ * @param reset - set to false if no need to reset data
22
+ */
23
+ async replaceAttributesData() {
24
+ let reset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
25
+ if (reset) this.resetAttributesData();
26
+ const oldAttributes = Array.from(this.element.attributes) // transform NamedNodeMap in object
27
+ .reduce((obj, attr) => {
28
+ // Keep only attributes starting with `store://...`
29
+ if (!attr.value.match(/^store:\/\/(resource|container|user)/)) return {
30
+ ...obj
31
+ };
32
+
33
+ // Save attr for reset later
34
+ if (!this.bindedAttributes[attr.name]) this.bindedAttributes[attr.name] = attr.value;
35
+ return {
36
+ ...obj,
37
+ [attr.name]: attr.value // add "key: value"
38
+ };
39
+ }, {});
40
+ const newAttributes = await this.transformAttributes({
41
+ ...oldAttributes
42
+ }, this.resource); // generate new attributes
43
+
44
+ for (let attr of Object.keys(newAttributes)) {
45
+ // set attributes on element
46
+ if (oldAttributes[attr] == newAttributes[attr]) continue; // only if it changed
47
+ this.element.setAttribute(attr, newAttributes[attr]);
48
+ }
49
+ },
50
+ /**
51
+ * Transform attributes from `store://...` to their actual value
52
+ * @param attributes - object representing attributes of an element
53
+ * @param resource - resource to use to resolve attributes
54
+ * @returns - object representing attributes of an element with resolved values
55
+ */
56
+ async transformAttributes(attributes, resource) {
57
+ const isContainer = resource && resource.isContainer?.();
58
+ for (let attr of Object.keys(attributes)) {
59
+ const value = attributes[attr];
60
+ // Avoid error if value is a number
61
+ if (typeof value === 'string') {
62
+ // Replace attribute value
63
+ if (!isContainer && resource && value.startsWith('store://resource')) {
64
+ // RESOURCE
65
+ let path = value.replace('store://resource.', '');
66
+ attributes[attr] = resource ? await resource[path] : '';
67
+ } else if (isContainer && resource && value.startsWith('store://container')) {
68
+ // CONTAINER
69
+ let path = value.replace('store://container.', '');
70
+ attributes[attr] = resource ? await resource[path] : '';
71
+ } else if (value.startsWith('store://user')) {
72
+ // USER
73
+ const userId = await this.retry(this.getUser.bind(this)); // retry until sibAuth is defined
74
+ const user = userId && userId['@id'] ? await store.getData(userId['@id'], this.context || base_context) : null;
75
+ if (!user) {
76
+ attributes[attr] = '';
77
+ continue;
78
+ }
79
+ let path = value.replace('store://user.', '');
80
+ attributes[attr] = user ? await user[path] : '';
81
+ }
82
+ }
83
+ }
84
+ return attributes;
85
+ },
86
+ /**
87
+ * Returns logged in user from sib-auth
88
+ * @returns userId
89
+ */
90
+ async getUser() {
91
+ const sibAuth = document.querySelector('sib-auth');
92
+ return sibAuth.getUser();
93
+ },
94
+ /**
95
+ * Retry [fn] for [maxRetries] times every [ms]
96
+ * @param fn
97
+ * @param ms
98
+ * @param maxRetries
99
+ * @returns
100
+ */
101
+ async retry(fn) {
102
+ let ms = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 200;
103
+ let maxRetries = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 5;
104
+ return new Promise((resolve, reject) => {
105
+ let retries = 0;
106
+ fn().then(resolve).catch(() => {
107
+ setTimeout(() => {
108
+ ++retries;
109
+ if (retries == maxRetries) return reject();
110
+ this.retry(fn, ms).then(resolve);
111
+ }, ms);
112
+ });
113
+ });
114
+ }
115
+ };
116
+ export { AttributeBinderMixin };
@@ -0,0 +1,26 @@
1
+ import { base_context } from '../libs/store/store.js';
2
+ const ContextMixin = {
3
+ name: 'store-mixin',
4
+ use: [],
5
+ attributes: {
6
+ extraContext: {
7
+ type: String,
8
+ default: null
9
+ }
10
+ },
11
+ get context() {
12
+ return {
13
+ ...base_context,
14
+ ...this.extra_context
15
+ };
16
+ },
17
+ get extra_context() {
18
+ let extraContextElement = this.extraContext ? document.getElementById(this.extraContext) :
19
+ // take element extra context first
20
+ document.querySelector('[data-default-context]'); // ... or look for a default extra context
21
+
22
+ if (extraContextElement) return JSON.parse(extraContextElement.textContent || "{}");
23
+ return {};
24
+ }
25
+ };
26
+ export { ContextMixin };
@@ -0,0 +1,54 @@
1
+ import { html } from '../_snowpack/pkg/lit-html.js';
2
+ import { unsafeHTML } from '../_snowpack/pkg/lit-html/directives/unsafe-html.js';
3
+ import { evalTemplateString } from '../libs/helpers.js';
4
+ const CounterMixin = {
5
+ name: 'counter-mixin',
6
+ use: [],
7
+ attributes: {
8
+ counterTemplate: {
9
+ type: String,
10
+ default: null
11
+ }
12
+ },
13
+ initialState: {
14
+ counter: null,
15
+ parentCounterDiv: null
16
+ },
17
+ attached() {
18
+ this.listPostProcessors.push(this.countResources.bind(this));
19
+ },
20
+ async countResources(resources, listPostProcessors, div, context) {
21
+ if (this.counterTemplate) {
22
+ this.initParentCounterDiv(div);
23
+ this.renderCallbacks.push({
24
+ // add counter template to render callback
25
+ template: await this.renderCounter(resources.length),
26
+ parent: this.parentCounterDiv
27
+ });
28
+ }
29
+ const nextProcessor = listPostProcessors.shift();
30
+ if (nextProcessor) await nextProcessor(resources, listPostProcessors, div, context);
31
+ },
32
+ /**
33
+ * Create the parent div of the counter in the component.
34
+ * @param div: parent div where to insert the counter div
35
+ */
36
+ initParentCounterDiv(div) {
37
+ if (this.parentCounterDiv) return;
38
+ this.parentCounterDiv = document.createElement('div');
39
+ this.element.insertBefore(this.parentCounterDiv, div);
40
+ },
41
+ async renderCounter(resourceNumber) {
42
+ let htmlCounter;
43
+ try {
44
+ htmlCounter = await evalTemplateString(this.counterTemplate, {
45
+ counter: resourceNumber
46
+ });
47
+ } catch (e) {
48
+ console.error(new Error('error in counter-template'), e);
49
+ throw e;
50
+ }
51
+ return html`${unsafeHTML(htmlCounter)}`;
52
+ }
53
+ };
54
+ export { CounterMixin };
@@ -0,0 +1,51 @@
1
+ import { store } from '../libs/store/store.js';
2
+ const FederationMixin = {
3
+ name: 'federation-mixin',
4
+ use: [],
5
+ initialState: {
6
+ containerFetched: null
7
+ },
8
+ attached() {
9
+ this.listPostProcessors.push(this.fetchSources.bind(this));
10
+ },
11
+ async fetchSources(resources, listPostProcessors, div, context) {
12
+ this.containerFetched = [];
13
+ let newResources = await this.getResources(resources);
14
+ newResources = [...new Set(newResources)]; // remove possible duplicates
15
+
16
+ const nextProcessor = listPostProcessors.shift();
17
+ if (nextProcessor) await nextProcessor(newResources, listPostProcessors, div, context);
18
+ },
19
+ async getResources(resources) {
20
+ const newResources = [];
21
+ const getChildResources = async res => {
22
+ if (!res) return;
23
+ if (res.isContainer?.()) {
24
+ // if this is a container
25
+ const containerId = res['@id'];
26
+ if (!this.containerFetched.includes(containerId)) {
27
+ // prevent from including twice the same source
28
+ this.containerFetched.push(containerId);
29
+ const resourcesFetched = await this.fetchSource(containerId); // fetch the resources of this container
30
+ if (resourcesFetched) newResources.push(...(await this.getResources(resourcesFetched))); // Add content of source to array...
31
+ }
32
+ } else {
33
+ newResources.push(res); // Or resource directly if not a container
34
+ }
35
+ };
36
+
37
+ await Promise.all(resources.map(res => getChildResources(res)));
38
+ return newResources;
39
+ },
40
+ async fetchSource(containerId) {
41
+ const cachedContainer = store.get(containerId); // find container in cache
42
+ if (!cachedContainer || cachedContainer['ldp:contains'] === null) {
43
+ // if container not fetched
44
+ store.clearCache(containerId); // empty cache
45
+ }
46
+
47
+ const container = await store.getData(containerId, this.context); // and fetch it
48
+ return container ? container['ldp:contains'] : null;
49
+ }
50
+ };
51
+ export { FederationMixin };
@@ -0,0 +1,155 @@
1
+ import { searchInResources } from '../libs/filter.js';
2
+ const FilterMixin = {
3
+ name: 'filter-mixin',
4
+ use: [],
5
+ initialState: {
6
+ searchCount: null
7
+ },
8
+ attributes: {
9
+ searchFields: {
10
+ type: String,
11
+ default: null
12
+ },
13
+ filteredBy: {
14
+ type: String,
15
+ default: null,
16
+ callback(newValue) {
17
+ // if we change search form, re-populate
18
+ if (newValue && this.searchForm && newValue !== this.searchForm.getAttribute('id')) {
19
+ this.searchForm.component.detach(this);
20
+ this.searchForm = null;
21
+ this.populate();
22
+ }
23
+ }
24
+ },
25
+ filteredOn: {
26
+ type: String,
27
+ // 'server' | 'client'
28
+ default: 'client'
29
+ }
30
+ },
31
+ created() {
32
+ this.searchCount = new Map();
33
+ this.element.addEventListener('populate', () => {
34
+ if (!window.document.contains(this.element)) return;
35
+ this.searchForm?.component.updateAutoRanges();
36
+ });
37
+ },
38
+ attached() {
39
+ const filteredBy = this.filteredBy;
40
+ if (this.isFilteredOnServer() && filteredBy) {
41
+ this.searchForm = document.getElementById(filteredBy);
42
+ if (!this.searchForm) throw `#${filteredBy} is not in DOM`;
43
+ // this.searchForm.component.attach(this); // is it necessary?
44
+ this.searchForm.addEventListener('formChange', () => this.onServerSearchChange());
45
+ } else {
46
+ this.listPostProcessors.push(this.filterCallback.bind(this));
47
+ }
48
+ },
49
+ get filters() {
50
+ return this.searchForm?.component?.value ?? {};
51
+ },
52
+ set filters(filters) {
53
+ if (this.searchForm?.component?.value) {
54
+ this.searchForm.component.value = filters;
55
+ this.filterList();
56
+ }
57
+ },
58
+ isFilteredOnServer() {
59
+ return this.filteredOn === 'server' && !!this.fetchData;
60
+ },
61
+ async onServerSearchChange() {
62
+ await this.fetchData(this.dataSrc);
63
+ this.empty();
64
+ await this.populate();
65
+ },
66
+ getDynamicServerSearch() {
67
+ const filters = this.filters;
68
+ if (this.isFilteredOnServer() && filters) {
69
+ const fields = Object.keys(filters);
70
+ const value = Object.values(filters).map(_ref => {
71
+ let {
72
+ value
73
+ } = _ref;
74
+ return value;
75
+ }).filter(value => !!value).join(' ').trim();
76
+ if (fields.length > 0 && value) {
77
+ return {
78
+ fields,
79
+ value
80
+ };
81
+ }
82
+ }
83
+ return;
84
+ },
85
+ async filterCallback(resources, listPostProcessors, div, context) {
86
+ if (this.filteredBy || this.searchFields) {
87
+ if (!this.searchCount.has(context)) this.searchCount.set(context, 1);
88
+ if (!this.searchForm) await this.createFilter(context);
89
+ const filteredResources = await searchInResources(resources, this.filters, this.fields, this.searchForm);
90
+ resources = resources.filter((_v, index) => filteredResources[index]);
91
+ }
92
+ const nextProcessor = listPostProcessors.shift();
93
+ if (nextProcessor) await nextProcessor(resources, listPostProcessors, div, context + (this.searchCount.get(context) || ''));
94
+ },
95
+ async filterList(context) {
96
+ this.searchCount.set(context, this.searchCount.get(context) + 1);
97
+ if (!this.resource) return;
98
+ this.empty();
99
+ await this.populate();
100
+ },
101
+ async getValuesOfField(field) {
102
+ const arrayOfDataObjects = this.resource['ldp:contains'];
103
+ const arrayOfDataIds = [];
104
+ for (const obj of arrayOfDataObjects) {
105
+ // for each element, if it's an object, catch all elements in 'ldp:contains' key
106
+ const nextArrayOfObjects = await obj[field];
107
+ if (!nextArrayOfObjects) continue;
108
+ if (typeof nextArrayOfObjects !== "object") {
109
+ console.warn(`The format value of ${field} is not suitable with auto-range-[field] attribute`);
110
+ continue;
111
+ }
112
+ const nextArrayOfIds = nextArrayOfObjects['ldp:contains'];
113
+ for (const obj of nextArrayOfIds) {
114
+ // catch each element id
115
+ arrayOfDataIds.push(obj['@id']);
116
+ }
117
+ if (nextArrayOfObjects['@type'] !== 'ldp:Container') {
118
+ // if no element in 'ldp:contains', catch object id
119
+ arrayOfDataIds.push(nextArrayOfObjects['@id']);
120
+ }
121
+ }
122
+ return arrayOfDataIds;
123
+ },
124
+ async createFilter(context) {
125
+ const filteredBy = this.filteredBy;
126
+ if (filteredBy != null) {
127
+ this.searchForm = document.getElementById(filteredBy);
128
+ if (!this.searchForm) throw `#${filteredBy} is not in DOM`;
129
+ } else {
130
+ this.searchForm = document.createElement(`solid-form-search`);
131
+ }
132
+ this.searchForm.component.attach(this);
133
+ this.searchForm.addEventListener('formChange', () => {
134
+ this.filterList(context);
135
+ });
136
+ this.searchForm.toggleAttribute('naked', true);
137
+ if (filteredBy) return;
138
+
139
+ //pass attributes to search form
140
+ const searchAttributes = Array.from(this.element.attributes).filter(attr => attr['name'].startsWith('search-')).map(attr => ({
141
+ name: attr['name'].replace('search-', ''),
142
+ value: attr['value']
143
+ }));
144
+ searchAttributes.forEach(_ref2 => {
145
+ let {
146
+ name,
147
+ value
148
+ } = _ref2;
149
+ this.searchForm.setAttribute(name, value);
150
+ });
151
+ this.element.insertBefore(this.searchForm, this.element.firstChild);
152
+ await this.searchForm.component.populate();
153
+ }
154
+ };
155
+ export { FilterMixin };
@@ -0,0 +1,73 @@
1
+ const GrouperMixin = {
2
+ name: 'grouper-mixin',
3
+ use: [],
4
+ attributes: {
5
+ groupBy: {
6
+ type: String,
7
+ default: null
8
+ },
9
+ groupWidget: {
10
+ type: String,
11
+ default: 'solid-group-default'
12
+ },
13
+ groupClass: {
14
+ type: String,
15
+ default: ''
16
+ }
17
+ },
18
+ attached() {
19
+ this.listPostProcessors.push(this.groupResources.bind(this));
20
+ },
21
+ async groupResources(resources, listPostProcessors, div, context) {
22
+ const nextProcessor = listPostProcessors.shift();
23
+ if (this.groupBy) {
24
+ let groups = {};
25
+ for (let resource of resources) {
26
+ const valueGroup = await resource[this.groupBy];
27
+ if (valueGroup == null) continue;
28
+ if (!groups[valueGroup]) groups[valueGroup] = {
29
+ resources: []
30
+ }; // if no group yet, we create one...
31
+ groups[valueGroup].resources.push(resource); // ...and push corresponding resource into it
32
+ }
33
+
34
+ // For each group, get group widget and call next processors
35
+ const parents = Object.keys(groups).map(g => ({
36
+ group: g,
37
+ parent: this.renderGroup(g, div)
38
+ }));
39
+ for (let {
40
+ group,
41
+ parent
42
+ } of parents) {
43
+ if (nextProcessor) await nextProcessor(groups[group].resources,
44
+ // give only resources from group
45
+ [...listPostProcessors],
46
+ // copy post processors
47
+ parent,
48
+ // parent is group widget
49
+ context + "_" + group);
50
+ }
51
+ } else {
52
+ if (nextProcessor) await nextProcessor(resources, listPostProcessors, div, context);
53
+ }
54
+ },
55
+ /**
56
+ * Create a group widget or find if it already exists
57
+ * @param groupName
58
+ */
59
+ renderGroup(groupName, div) {
60
+ let groupElt = this.element.querySelector(`${this.groupWidget}[value="${groupName}"]`);
61
+ if (!groupElt) {
62
+ groupElt = document.createElement(this.groupWidget);
63
+ groupElt.setAttribute('value', groupName);
64
+ if (this.groupClass) groupElt.setAttribute('class', this.groupClass);
65
+ if (groupElt.component) groupElt.component.render(); // Force the rendering of the widget
66
+ div.appendChild(groupElt); // and append it to the parent div
67
+ }
68
+
69
+ return groupElt.querySelector('[data-content]') || groupElt; // return the node where to insert content
70
+ }
71
+ };
72
+
73
+ export { GrouperMixin };
@@ -0,0 +1,36 @@
1
+ const HighlighterMixin = {
2
+ name: 'highlighter-mixin',
3
+ use: [],
4
+ attached() {
5
+ this.listPostProcessors.push(this.hightlightCallback.bind(this));
6
+ },
7
+ async hightlightCallback(resources, listPostProcessors, div, context) {
8
+ for (let attr of this.element.attributes) {
9
+ if (attr.name.startsWith('highlight-')) {
10
+ const field = attr.name.split('highlight-')[1];
11
+ resources = await Promise.all(resources.map(async resource => ({
12
+ sortingKey: await resource[field],
13
+ // fetch sorting value
14
+ proxy: resource // and keep proxy
15
+ })));
16
+
17
+ resources = this.sortHighlighted(resources, "sortingKey", attr.value); // highlight element
18
+ resources = resources.map(resource => resource.proxy); // and re-transform in arra of resources
19
+ }
20
+ }
21
+
22
+ const nextProcessor = listPostProcessors.shift();
23
+ if (nextProcessor) await nextProcessor(resources, listPostProcessors, div, context);
24
+ },
25
+ sortHighlighted(resources, field, value) {
26
+ for (let [index, res] of resources.entries()) {
27
+ if (res[field] && res[field] == value) {
28
+ // put the current element at the beginning of the array
29
+ resources.splice(0, 0, resources.splice(index, 1)[0]); // TODO : test with sort
30
+ }
31
+ }
32
+
33
+ return resources;
34
+ }
35
+ };
36
+ export { HighlighterMixin };
@@ -0,0 +1,6 @@
1
+ export let WidgetType = /*#__PURE__*/function (WidgetType) {
2
+ WidgetType["CUSTOM"] = "custom";
3
+ WidgetType["USER"] = "user";
4
+ WidgetType["NATIVE"] = "native";
5
+ return WidgetType;
6
+ }({});
@@ -0,0 +1,105 @@
1
+ import { html, render } from '../_snowpack/pkg/lit-html.js';
2
+ import { preHTML } from '../libs/lit-helpers.js';
3
+ import { ifDefined } from '../_snowpack/pkg/lit-html/directives/if-defined.js';
4
+ const ListMixin = {
5
+ name: 'list-mixin',
6
+ use: [],
7
+ attributes: {
8
+ emptyWidget: {
9
+ type: String,
10
+ default: null
11
+ },
12
+ emptyValue: {
13
+ type: String,
14
+ default: ''
15
+ }
16
+ },
17
+ initialState: {
18
+ // Processors functions to execute on the list before rendering
19
+ listPostProcessors: [],
20
+ // Rendering to execute after all the processors have been executed
21
+ renderCallbacks: []
22
+ },
23
+ created() {
24
+ this.listPostProcessors = [];
25
+ this.renderCallbacks = [];
26
+ },
27
+ appendSingleElt(parent) {
28
+ this.appendChildElt(this.resource['@id'], parent);
29
+ },
30
+ setElementAttribute(attr) {
31
+ const containerAttribute = "solid-container";
32
+ const resourceAttribute = "solid-resource";
33
+ if (attr === "resource") {
34
+ this.element.removeAttribute(containerAttribute);
35
+ this.element.setAttribute(resourceAttribute, "");
36
+ } else {
37
+ this.element.removeAttribute(resourceAttribute);
38
+ this.element.setAttribute(containerAttribute, "");
39
+ }
40
+ },
41
+ async populate() {
42
+ const div = this.div;
43
+ if (!this.resource) return;
44
+
45
+ // Not a container but a single resource
46
+ if (!this.resource.isContainer?.()) {
47
+ this.setElementAttribute("resource");
48
+ this.appendSingleElt(div);
49
+ return;
50
+ }
51
+ this.setElementAttribute("container");
52
+ const listPostProcessors = [...this.listPostProcessors];
53
+ this.renderCallbacks = [];
54
+ listPostProcessors.push(this.renderDOM.bind(this));
55
+ listPostProcessors.push(this.handleEmptyWidget.bind(this));
56
+
57
+ // Execute the first post-processor of the list
58
+ const nextProcessor = listPostProcessors.shift();
59
+ await nextProcessor(this.resource['ldp:contains'], listPostProcessors, div, this.dataSrc);
60
+
61
+ // Execute the render callbacks
62
+ for (const renderCallback of this.renderCallbacks) {
63
+ // Render the template in the given parent element
64
+ render(renderCallback.template, renderCallback.parent);
65
+ }
66
+ },
67
+ /**
68
+ * Render resources in the DOM
69
+ * @param resources
70
+ * @param listPostProcessors
71
+ * @param div
72
+ * @param context
73
+ */
74
+ async renderDOM(resources, listPostProcessors, div, context) {
75
+ // Create child components
76
+ for (let resource of resources) {
77
+ if (!resource) continue;
78
+ this.appendChildElt(resource['@id'], div);
79
+ }
80
+ const nextProcessor = listPostProcessors.shift();
81
+ if (nextProcessor) await nextProcessor(resources, listPostProcessors, div, context);
82
+ },
83
+ /**
84
+ * Show empty widget if no resources in the list
85
+ * @param resources
86
+ * @param listPostProcessors
87
+ * @param div
88
+ * @param context
89
+ */
90
+ async handleEmptyWidget(resources, listPostProcessors, div, context) {
91
+ if (this.emptyWidget) {
92
+ const emptyWidgetTemplate = preHTML`
93
+ <${this.emptyWidget} value=${ifDefined(this.emptyValue)}></${this.emptyWidget}>
94
+ `;
95
+ if (!this.emptyWrapper) {
96
+ this.emptyWrapper = document.createElement('span');
97
+ this.element.appendChild(this.emptyWrapper);
98
+ }
99
+ render(resources.length > 0 ? html`` : emptyWidgetTemplate, this.emptyWrapper);
100
+ }
101
+ const nextProcessor = listPostProcessors.shift();
102
+ if (nextProcessor) await nextProcessor(resources, listPostProcessors, div, context);
103
+ }
104
+ };
105
+ export { ListMixin };
@@ -0,0 +1,23 @@
1
+ const NextMixin = {
2
+ name: 'next-mixin',
3
+ use: [],
4
+ attributes: {
5
+ next: {
6
+ type: String,
7
+ default: ''
8
+ }
9
+ },
10
+ // Here "even.target" points to the content of the widgets of the children of solid-display
11
+ goToNext(resource) {
12
+ if (this.next) {
13
+ this.element.dispatchEvent(new CustomEvent('requestNavigation', {
14
+ bubbles: true,
15
+ detail: {
16
+ route: this.next,
17
+ resource: resource
18
+ }
19
+ }));
20
+ }
21
+ }
22
+ };
23
+ export { NextMixin };