@cocreate/state 1.23.0 → 1.24.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 (3) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +1 -1
  3. package/src/index.js +222 -164
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ # [1.24.0](https://github.com/CoCreate-app/CoCreate-state/compare/v1.23.0...v1.24.0) (2024-12-14)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * support setting empty string ([ee2ad83](https://github.com/CoCreate-app/CoCreate-state/commit/ee2ad83dfddfb9209b64fdbd154c5ed85340b238))
7
+
8
+
9
+ ### Features
10
+
11
+ * support comma seperated states to apply multiple states ([1777635](https://github.com/CoCreate-app/CoCreate-state/commit/1777635b0d3f98979c08735e07d137d9bfc40230))
12
+
1
13
  # [1.23.0](https://github.com/CoCreate-app/CoCreate-state/compare/v1.22.2...v1.23.0) (2024-11-04)
2
14
 
3
15
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/state",
3
- "version": "1.23.0",
3
+ "version": "1.24.0",
4
4
  "description": "Data attributes which can be used for components in CoCreate framework combined as a group of attributes that dynamically change attributes & fetch custom data.",
5
5
  "keywords": [
6
6
  "state",
package/src/index.js CHANGED
@@ -1,205 +1,263 @@
1
- import '@cocreate/element-prototype';
2
- import observer from '@cocreate/observer';
3
- import action from '@cocreate/actions';
4
- import uid from '@cocreate/uuid';
5
- import localStorage from '@cocreate/local-storage';
6
-
1
+ import "@cocreate/element-prototype";
2
+ import observer from "@cocreate/observer";
3
+ import action from "@cocreate/actions";
4
+ import uid from "@cocreate/uuid";
5
+ import localStorage from "@cocreate/local-storage";
7
6
 
8
7
  function init() {
9
- let elements = document.querySelectorAll('[state_id]');
10
- initElements(elements);
11
- window.addEventListener('storage', function (e) {
12
- if (e.key == 'statedAttributes') {
13
- elements = document.querySelectorAll('[state_id]:not([state-onstoragechange="false"])')
14
- initElements(elements)
15
- }
16
- });
17
- document.addEventListener('click', function (e) {
18
- const target = e.target.closest('[state_to]');
19
- if (target) {
20
- if (target.closest('[actions*="state"]')) return;
21
- stateAttributes(target);
22
- }
23
- });
8
+ let elements = document.querySelectorAll("[state_id]");
9
+ initElements(elements);
10
+ window.addEventListener("storage", function (e) {
11
+ if (e.key == "statedAttributes") {
12
+ elements = document.querySelectorAll(
13
+ '[state_id]:not([state-onstoragechange="false"])'
14
+ );
15
+ initElements(elements);
16
+ }
17
+ });
18
+ document.addEventListener("click", function (e) {
19
+ const target = e.target.closest("[state_to]");
20
+ if (target) {
21
+ if (target.closest('[actions*="state"]')) return;
22
+ stateAttributes(target);
23
+ }
24
+ });
24
25
  }
25
26
 
26
27
  function initElements(elements) {
27
- for (let element of elements)
28
- initElement(element);
28
+ for (let element of elements) initElement(element);
29
29
  }
30
30
 
31
31
  function initElement(element) {
32
- let state_id = element.getAttribute('state_id');
33
- if (!state_id) return;
32
+ let state_id = element.getAttribute("state_id");
33
+ if (!state_id) return;
34
+
35
+ let statedAttributes = localStorage.getItem("statedAttributes");
34
36
 
35
- let statedAttributes = localStorage.getItem('statedAttributes');
37
+ if (!statedAttributes || statedAttributes.length == 0) return;
38
+ statedAttributes = JSON.parse(statedAttributes);
36
39
 
37
- if (!statedAttributes || statedAttributes.length == 0) return;
38
- statedAttributes = JSON.parse(statedAttributes);
40
+ if (state_id.includes(",")) state_id = state_id.split(",");
39
41
 
40
- let attrValues = statedAttributes[`${state_id}`];
41
- if (!attrValues) return;
42
- _setAttributeValues(element, attrValues);
42
+ if (!Array.isArray(state_id)) state_id = [state_id];
43
+
44
+ for (let i = 0; i < state_id.length; i++) {
45
+ let attrValues = statedAttributes[`${state_id[i].trim()}`];
46
+ if (!attrValues) return;
47
+ _setAttributeValues(element, attrValues);
48
+ }
43
49
  }
44
50
 
45
51
  function _setAttributeValues(el, attrValues) {
46
- let isOverwrite = el.getAttribute('state-overwrite');
47
- if (isOverwrite === null || isOverwrite === undefined)
48
- isOverwrite = attrValues['overwrite']
49
-
50
- if (isOverwrite && isOverwrite != 'false' || isOverwrite === '')
51
- isOverwrite = true;
52
- else if (!isOverwrite || isOverwrite === 'false')
53
- isOverwrite = false;
54
-
55
- delete attrValues['overwrite']
56
-
57
- for (const key of Object.keys(attrValues)) {
58
- _setAttributeValue(el, key, attrValues[key], isOverwrite);
59
- _setAttributeValue(el, `state-${key}`, attrValues[key], isOverwrite);
60
- if (key == 'array' || key == 'object' || key == 'name') {
61
- _setAttributeValue(el, `fetch-${key}`, attrValues[key], isOverwrite);
62
- _setAttributeValue(el, `state-fetch-${key}`, attrValues[key], isOverwrite);
63
- }
64
- if (key == 'template') {
65
- _setAttributeValue(el, 'template_id', attrValues[key], isOverwrite);
66
- }
67
- if (key == 'template_id') {
68
- _setAttributeValue(el, 'template', attrValues[key], isOverwrite);
69
- }
70
- }
52
+ let isOverwrite = el.getAttribute("state-overwrite");
53
+ if (isOverwrite === null || isOverwrite === undefined)
54
+ isOverwrite = attrValues["overwrite"];
55
+
56
+ if ((isOverwrite && isOverwrite != "false") || isOverwrite === "")
57
+ isOverwrite = true;
58
+ else if (!isOverwrite || isOverwrite === "false") isOverwrite = false;
59
+
60
+ // delete attrValues["overwrite"];
61
+
62
+ for (const key of Object.keys(attrValues)) {
63
+ _setAttributeValue(el, key, attrValues[key], isOverwrite);
64
+ _setAttributeValue(el, `state-${key}`, attrValues[key], isOverwrite);
65
+ if (key == "array" || key == "object" || key == "name") {
66
+ _setAttributeValue(
67
+ el,
68
+ `fetch-${key}`,
69
+ attrValues[key],
70
+ isOverwrite
71
+ );
72
+ _setAttributeValue(
73
+ el,
74
+ `state-fetch-${key}`,
75
+ attrValues[key],
76
+ isOverwrite
77
+ );
78
+ }
79
+ if (key == "template") {
80
+ _setAttributeValue(el, "template_id", attrValues[key], isOverwrite);
81
+ }
82
+ if (key == "template_id") {
83
+ _setAttributeValue(el, "template", attrValues[key], isOverwrite);
84
+ }
85
+ }
71
86
  }
72
87
 
73
88
  async function _setAttributeValue(element, attribute, value, isOverwrite) {
74
- // TODO: if (value !== undefined)???
75
- if (!element.getAttribute(attribute) || isOverwrite) {
76
- if (attribute == 'value') {
77
- if (element.value == '' || element.value && isOverwrite)
78
- element.value = value;
79
- else if (isOverwrite || element.hasAttribute('value') && !await element.getValue())
80
- element.setValue(value)
81
- } else if (element.hasAttribute(attribute) && value)
82
- element.setAttribute(attribute, value);
83
- }
89
+ // TODO: if (value !== undefined)???
90
+ if (!element.getAttribute(attribute) || isOverwrite) {
91
+ if (attribute == "value") {
92
+ if (element.value == "" || (element.value && isOverwrite))
93
+ element.value = value;
94
+ else if (
95
+ isOverwrite ||
96
+ (element.hasAttribute("value") && !(await element.getValue()))
97
+ )
98
+ element.setValue(value);
99
+ } else if (element.hasAttribute(attribute) && (value || value === ""))
100
+ element.setAttribute(attribute, value);
101
+ }
84
102
  }
85
103
 
86
104
  async function stateAttributes(element) {
87
- let statedAttributes = {};
88
- let elements = []
89
-
90
- let form = element.closest('form');
91
- if (form) {
92
- elements = form.querySelectorAll('[state_to]')
93
- } else {
94
- if (element.hasAttribute('state_to'))
95
- elements.push(element)
96
- let nestedElements = element.querySelectorAll('[state_to]')
97
- elements.push(...nestedElements)
98
- }
99
-
100
- let changeState = false
101
- for (let i = 0; i < elements.length; i++) {
102
- let attrValues = await _getAttributeValues(elements[i]);
103
- if (attrValues.src === '$back' || attrValues.href === '$back') {
104
- changeState = true
105
- window.history.back();
106
- break;
107
- } else if (attrValues.src === '$forward' || attrValues.href === '$forward') {
108
- changeState = true
109
- window.history.forward();
110
- break;
111
- }
112
-
113
- let state_to = elements[i].getAttribute('state_to');
114
- Object.assign(statedAttributes, { [`${state_to}`]: attrValues });
115
- _getStateId(attrValues, state_to);
116
- }
117
- statedAttributes = JSON.stringify(statedAttributes)
118
- let href = element.closest('href')
119
- if (!changeState && !href) {
120
- // TODO: Handle $title when adding statedAttributes
121
- let title = element.getAttribute('title') || document.title || '';
122
- history.pushState({ statedAttributes, title, url: location.href }, title, location.href);
123
- }
124
-
125
- if (!changeState)
126
- localStorage.setItem('statedAttributes', statedAttributes);
127
-
128
- document.dispatchEvent(new CustomEvent('stateEnd', {
129
- detail: {}
130
- }))
105
+ let statedAttributes = {};
106
+ try {
107
+ const storedAttributes = localStorage.getItem("statedAttributes");
108
+ if (storedAttributes) {
109
+ statedAttributes = JSON.parse(storedAttributes);
110
+ }
111
+ } catch (error) {
112
+ console.error(
113
+ "Failed to parse statedAttributes from localStorage:",
114
+ error
115
+ );
116
+ // Optionally reset `statedAttributes` in localStorage to ensure valid data:
117
+ localStorage.setItem("statedAttributes", JSON.stringify({}));
118
+ }
119
+ let elements = [];
120
+
121
+ let form = element.closest("form");
122
+ if (form) {
123
+ elements = form.querySelectorAll("[state_to]");
124
+ } else {
125
+ if (element.hasAttribute("state_to")) elements.push(element);
126
+ let nestedElements = element.querySelectorAll("[state_to]");
127
+ elements.push(...nestedElements);
128
+ }
131
129
 
130
+ let changeState = false;
131
+ for (let i = 0; i < elements.length; i++) {
132
+ let attrValues = await _getAttributeValues(elements[i]);
133
+ if (attrValues.src === "$back" || attrValues.href === "$back") {
134
+ changeState = true;
135
+ window.history.back();
136
+ break;
137
+ } else if (
138
+ attrValues.src === "$forward" ||
139
+ attrValues.href === "$forward"
140
+ ) {
141
+ changeState = true;
142
+ window.history.forward();
143
+ break;
144
+ }
145
+
146
+ let state_to = elements[i].getAttribute("state_to");
147
+ Object.assign(statedAttributes, { [`${state_to}`]: attrValues });
148
+ _getStateId(attrValues, state_to);
149
+ }
150
+ statedAttributes = JSON.stringify(statedAttributes);
151
+ let href = element.closest("href");
152
+ if (!changeState && !href) {
153
+ // TODO: Handle $title when adding statedAttributes
154
+ let title = element.getAttribute("title") || document.title || "";
155
+ history.pushState(
156
+ { statedAttributes, title, url: location.href },
157
+ title,
158
+ location.href
159
+ );
160
+ }
161
+
162
+ if (!changeState)
163
+ localStorage.setItem("statedAttributes", statedAttributes);
164
+
165
+ document.dispatchEvent(
166
+ new CustomEvent("stateEnd", {
167
+ detail: {}
168
+ })
169
+ );
132
170
  }
133
171
 
134
172
  async function _getAttributeValues(element) {
135
- let attributeValues = {};
136
- let attributes = element.attributes;
137
- for (let attribute of attributes) {
138
- if (attribute.name.startsWith('state-')) {
139
- if (attribute.value == '$uid')
140
- Object.assign(attributeValues, { [`${attribute.name.substring(5)}`]: uid.generate(6) });
141
- else if (attribute.name == 'state-value' && !attribute.value)
142
- Object.assign(attributeValues, { value: await element.getvalue() });
143
- else
144
- Object.assign(attributeValues, { [`${attribute.name.substring(6)}`]: attribute.value });
145
- }
146
- }
147
- if (element.value !== undefined && !element.hasAttribute('state-value') && element.getvalue)
148
- Object.assign(attributeValues, { value: await element.getvalue() });
149
-
150
- return attributeValues;
173
+ let attributeValues = {};
174
+ let attributes = element.attributes;
175
+ for (let attribute of attributes) {
176
+ if (attribute.name.startsWith("state-")) {
177
+ if (attribute.value == "$uid")
178
+ Object.assign(attributeValues, {
179
+ [`${attribute.name.substring(5)}`]: uid.generate(6)
180
+ });
181
+ else if (attribute.name == "state-value" && !attribute.value)
182
+ Object.assign(attributeValues, {
183
+ value: await element.getvalue()
184
+ });
185
+ else
186
+ Object.assign(attributeValues, {
187
+ [`${attribute.name.substring(6)}`]: attribute.value
188
+ });
189
+ }
190
+ }
191
+ if (
192
+ element.value !== undefined &&
193
+ !element.hasAttribute("state-value") &&
194
+ element.getvalue
195
+ )
196
+ Object.assign(attributeValues, { value: await element.getvalue() });
197
+
198
+ return attributeValues;
151
199
  }
152
200
 
153
201
  function _getStateId(attrValues, state_to) {
154
- const elements = document.querySelectorAll(`[state_id="${state_to}"]`);
155
- for (let element of elements)
156
- _setAttributeValues(element, attrValues);
202
+ const elements = document.querySelectorAll(`[state_id="${state_to}"]`);
203
+ for (let element of elements) _setAttributeValues(element, attrValues);
157
204
  }
158
205
 
159
206
  window.onload = function () {
160
- if (!history.length) {
161
- const statedAttributes = localStorage.getItem('statedAttributes') || '';
162
- history.replaceState({ statedAttributes, url: location.href, title: document.title }, document.title, location.href);
163
- } else if (!history.state || history.state.url !== location.href) {
164
- const statedAttributes = localStorage.getItem('statedAttributes') || '';
165
- history.pushState({ statedAttributes, url: location.href, title: document.title }, document.title, location.href);
166
- }
207
+ if (!history.length) {
208
+ const statedAttributes = localStorage.getItem("statedAttributes") || "";
209
+ history.replaceState(
210
+ { statedAttributes, url: location.href, title: document.title },
211
+ document.title,
212
+ location.href
213
+ );
214
+ } else if (!history.state || history.state.url !== location.href) {
215
+ const statedAttributes = localStorage.getItem("statedAttributes") || "";
216
+ history.pushState(
217
+ { statedAttributes, url: location.href, title: document.title },
218
+ document.title,
219
+ location.href
220
+ );
221
+ }
167
222
  };
168
223
 
169
- window.addEventListener('popstate', function (event) {
170
- if (event.state) {
171
- if (event.state.statedAttributes) {
172
- localStorage.setItem('statedAttributes', event.state.statedAttributes);
173
- let elements = document.querySelectorAll('[state_id]')
174
- initElements(elements)
175
- }
176
-
177
- if (event.state.url && event.state.url !== window.location.href) {
178
- if (event.state.title)
179
- sessionStorage.setItem('currentPageTitle', event.state.title); // Store title in session storage
180
-
181
- location.href = event.state.url; // Navigate if the URL is different
182
- } else if (event.state.title) {
183
- document.title = event.state.title; // Update the title if provided
184
- }
185
- }
224
+ window.addEventListener("popstate", function (event) {
225
+ if (event.state) {
226
+ if (event.state.statedAttributes) {
227
+ localStorage.setItem(
228
+ "statedAttributes",
229
+ event.state.statedAttributes
230
+ );
231
+ let elements = document.querySelectorAll("[state_id]");
232
+ initElements(elements);
233
+ }
234
+
235
+ if (event.state.url && event.state.url !== window.location.href) {
236
+ if (event.state.title)
237
+ sessionStorage.setItem("currentPageTitle", event.state.title); // Store title in session storage
238
+
239
+ location.href = event.state.url; // Navigate if the URL is different
240
+ } else if (event.state.title) {
241
+ document.title = event.state.title; // Update the title if provided
242
+ }
243
+ }
186
244
  });
187
245
 
188
246
  observer.init({
189
- name: 'CoCreateState',
190
- observe: ['addedNodes'],
191
- selector: '[state_id]',
192
- callback: function (mutation) {
193
- initElement(mutation.target);
194
- }
247
+ name: "CoCreateState",
248
+ observe: ["addedNodes"],
249
+ selector: "[state_id]",
250
+ callback: function (mutation) {
251
+ initElement(mutation.target);
252
+ }
195
253
  });
196
254
 
197
255
  action.init({
198
- name: "state",
199
- endEvent: "stateEnd",
200
- callback: (data) => {
201
- stateAttributes(data.element);
202
- },
256
+ name: "state",
257
+ endEvent: "stateEnd",
258
+ callback: (data) => {
259
+ stateAttributes(data.element);
260
+ }
203
261
  });
204
262
 
205
263
  init();