@cocreate/local-storage 1.16.3 → 1.16.5

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.
@@ -22,13 +22,13 @@ jobs:
22
22
  runs-on: ubuntu-latest
23
23
  steps:
24
24
  - name: Checkout
25
- uses: actions/checkout@v3
25
+ uses: actions/checkout@v4
26
26
  - name: Setup Node.js
27
- uses: actions/setup-node@v3
27
+ uses: actions/setup-node@v4
28
28
  with:
29
- node-version: 14
29
+ node-version: 22 # Required for the latest semantic-release plugins
30
30
  - name: Semantic Release
31
- uses: cycjimmy/semantic-release-action@v3
31
+ uses: cycjimmy/semantic-release-action@v4 # Update to v4 for better Node 20+ support
32
32
  id: semantic
33
33
  with:
34
34
  extra_plugins: |
@@ -36,9 +36,8 @@ jobs:
36
36
  @semantic-release/git
37
37
  @semantic-release/github
38
38
  env:
39
- GITHUB_TOKEN: "${{ secrets.GITHUB }}"
39
+ GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" # Use the built-in token if possible
40
40
  NPM_TOKEN: "${{ secrets.NPM_TOKEN }}"
41
41
  outputs:
42
42
  new_release_published: "${{ steps.semantic.outputs.new_release_published }}"
43
43
  new_release_version: "${{ steps.semantic.outputs.new_release_version }}"
44
-
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [1.16.5](https://github.com/CoCreate-app/CoCreate-local-storage/compare/v1.16.4...v1.16.5) (2026-03-05)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * storage support for local and session storage, added fallback to Map for unsupported browsers ([9774762](https://github.com/CoCreate-app/CoCreate-local-storage/commit/9774762ed66298adaec453804835211930269519))
7
+
8
+ ## [1.16.4](https://github.com/CoCreate-app/CoCreate-local-storage/compare/v1.16.3...v1.16.4) (2026-02-04)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * update worklow ([84ed393](https://github.com/CoCreate-app/CoCreate-local-storage/commit/84ed39318d7838be935dc1e0d6542505536be44d))
14
+
1
15
  ## [1.16.3](https://github.com/CoCreate-app/CoCreate-local-storage/compare/v1.16.2...v1.16.3) (2025-05-01)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,18 +1,10 @@
1
1
  {
2
2
  "name": "@cocreate/local-storage",
3
- "version": "1.16.3",
3
+ "version": "1.16.5",
4
4
  "description": "A Simple component similar to CoCreate-input & CoCreate-fetch which Save and fetch data for inputs, textarea, selects from localstorage. Easily configured using HTML5 attributes and/or JavaScript API",
5
5
  "keywords": [
6
6
  "local-storage",
7
- "cocreate",
8
- "low-code-framework",
9
- "no-code-framework",
10
- "cocreatejs",
11
- "cocreatejs-component",
12
- "cocreate-framework",
13
- "no-code",
14
7
  "low-code",
15
- "collaborative-framework",
16
8
  "realtime",
17
9
  "realtime-framework",
18
10
  "collaboration",
package/src/index.js CHANGED
@@ -1,247 +1,313 @@
1
1
  import Observer from "@cocreate/observer";
2
2
  import Actions from "@cocreate/actions";
3
3
 
4
- const CoCreateLocalStorage = {
5
- support: true,
6
- storage: new Map(),
7
-
8
- init: function () {
9
- const self = this;
10
- var elements = document.querySelectorAll(
11
- "[localstorage-set], [localstorage-get]"
12
- );
13
- this.initElements(elements);
14
-
15
- window.addEventListener("storage", function (e) {
16
- elements = document.querySelectorAll(
17
- `[localstorage-get="${e.key}"]`
18
- );
19
- for (let element of elements) {
20
- // TODO: return if localstorage-query, etc...
21
- // - Decide how best to handle, considering localstorage is also handled by event.
22
- if (
23
- element.hasAttribute("localstorage-attribute") ||
24
- element.hasAttribute("localstorage-value") ||
25
- element.hasAttribute("localstorage-key")
26
- )
27
- return;
28
- let value = self.getItem(e.key);
29
- if (value != null) {
30
- element.setValue(value);
31
- }
32
- }
33
- });
34
- },
35
-
36
- /**
37
- * Initializes a collection of elements.
38
- * @param {Array<Element>} elements - An array of elements to be initialized.
39
- */
40
- initElements: function (elements) {
41
- for (let element of elements) this.initElement(element);
42
- },
43
-
44
- /**
45
- * Initializes a single element.
46
- * @param {Element} element - The element to initialize. This function expects an 'Element' type.
47
- */
48
- initElement: function (element) {
49
- let value = this.getItem(element);
50
- if (value) element.setValue(value);
51
- else {
52
- let inputEvent = new CustomEvent("input", {
53
- bubbles: true
54
- });
55
-
56
- Object.defineProperty(inputEvent, "target", {
57
- writable: false,
58
- value: element
59
- });
60
- element.dispatchEvent(inputEvent);
61
- }
62
- element.addEventListener("input", (e) => {
63
- let isRealtime = element.getAttribute("realtime");
64
- // Returns if realtime false.
65
- if (!isRealtime && isRealtime === "false") return;
66
-
67
- let key = e.target.getAttribute("localstorage-set");
68
- // Set the key and value in the localstorage.
69
- if (key) this.setItem(key, e.target.value);
70
-
71
- let elements = document.querySelectorAll(
72
- `[localstorage-get="${key}"]`
73
- );
74
- for (let el of elements) {
75
- if (el != element) {
76
- let value = this.getItem(key);
77
- // Set the value of the element.
78
- if (value != null) {
79
- el.setValue(value);
80
- }
81
- }
82
- }
83
- });
84
- },
85
-
86
- /**
87
- * @param key
88
- *
89
- * @return { Mixed } The value associated with the key or undefined if not found. Note that this will be returned as a string if the key is an array
90
- */
91
- getItem: function (key) {
92
- // Returns the value of the key in the storage.
93
- if (this.support) return window.localStorage.getItem(key);
94
- else return this.storage.get(key);
95
- },
96
-
97
- /**
98
- * @param key - key name to store the value under
99
- * @param value - value to store
100
- */
101
- setItem: function (key, value) {
102
- try {
103
- if (this.support) {
104
- const oldValue = localStorage.getItem(key);
105
-
106
- window.localStorage.setItem(key, value);
107
-
108
- const keys = [
109
- "organization_id",
110
- "user_id",
111
- "clientId",
112
- "session_id"
113
- ];
114
- if (keys.includes(key)) {
115
- const updateEvent = new CustomEvent("updateAttributes", {
116
- detail: { key, newValue: value, oldValue }
117
- });
118
- window.dispatchEvent(updateEvent);
119
- }
120
- } else this.storage.set(key, value);
121
- } catch (error) {
122
- if (
123
- error instanceof DOMException &&
124
- (error.code === 22 ||
125
- error.code === 1014 ||
126
- error.name === "QuotaExceededError" ||
127
- error.name === "NS_ERROR_DOM_QUOTA_REACHED")
128
- ) {
129
- // TODO: create a fallback method, perhaps setting in indexeddb if above a specific size
130
- console.log(
131
- "Local storage limit exceeded. Falling back to IndexedDB."
132
- );
133
- } else {
134
- console.error("Error setting item:", error);
135
- }
136
- }
137
- },
138
-
139
- /**
140
- * @param key - The key name to delete from the storage
141
- */
142
- removeItem: function (key) {
143
- // Removes an item from the storage.
144
- if (this.support) window.localStorage.removeItem(key);
145
- else this.storage.delete(key);
146
- },
147
-
148
- /**
149
- * @param action
150
- *
151
- * @return { undefined } No return
152
- */
153
- runStorage: async function (action) {
154
- const form = action.form;
155
- // If the form is not a form return false.
156
- if (!form) return;
157
-
158
- let set_els = form.querySelectorAll("[localstorage-set]");
159
- for (let el of set_els) {
160
- let key = el.getAttribute("localstorage-set");
161
- let value = await el.getValue();
162
- // Sets the value of an item.
163
- if (value && key) {
164
- this.setItem(key, value);
165
- }
166
- }
167
- let get_els = form.querySelectorAll("[localstorage-get]");
168
- for (let el of get_els) {
169
- let key = el.getAttribute("localstorage-get");
170
- // If key is not set return false.
171
- if (!key) return;
172
- let value = this.getItem(key);
173
- // Set the value of the element.
174
- if (value != null) {
175
- el.setValue(value);
176
- }
177
- }
178
- let remove_els = form.querySelectorAll("[localstorage-remove]");
179
- for (let el of remove_els) {
180
- el.setValue("");
181
- let key = el.getAttribute("localstorage-remove");
182
- // Removes an item from the list.
183
- if (key) {
184
- this.removeItem(key);
185
- }
186
- }
187
-
188
- action.element.dispatchEvent(
189
- new CustomEvent("localStorage", {
190
- detail: {}
191
- })
192
- );
193
- },
194
-
195
- checkSupport: function () {
196
- // Check if the browser supports localStorage.
197
- if (!("localStorage" in window)) {
198
- console.log("This browser doesn't support localStorage.");
199
- this.support = false;
200
- } else {
201
- try {
202
- let test = window.localStorage.getItem("test");
203
- // If the CoCreateConfig. localStorage is false this method will set support to false.
204
- if (window.CoCreateConfig)
205
- if (window.CoCreateConfig.localStorage === false)
206
- // If the server supports local storage
207
- this.support = false;
208
- } catch (e) {
209
- this.support = false;
210
- } finally {
211
- // Initialize the component. If support is enabled the method init is called.
212
- if (this.support) this.init();
213
- }
214
- }
215
- }
4
+ let support = true;
5
+ const storage = new Map();
6
+
7
+ function init() {
8
+ var elements = document.querySelectorAll(
9
+ "[localstorage-set], [localstorage-get], [sessionstorage-set], [sessionstorage-get]"
10
+ );
11
+ initElements(elements);
12
+
13
+ window.addEventListener("storage", function (e) {
14
+ // Determine which storage type triggered the event
15
+ const type = e.storageArea === window.sessionStorage ? "sessionstorage" : "localstorage";
16
+
17
+ elements = document.querySelectorAll(
18
+ `[${type}-get="${e.key}"]`
19
+ );
20
+ for (let element of elements) {
21
+ // TODO: Decide how best to handle considering storage is also handled by event.
22
+ if (
23
+ element.hasAttribute(`${type}-attribute`) ||
24
+ element.hasAttribute(`${type}-value`) ||
25
+ element.hasAttribute(`${type}-key`)
26
+ )
27
+ return;
28
+ let value = getItem(e.key, type);
29
+ if (value != null) {
30
+ element.setValue(value);
31
+ }
32
+ }
33
+ });
34
+ }
35
+
36
+ /**
37
+ * Initializes a collection of elements.
38
+ * @param {Array<Element>} elements - An array of elements to be initialized.
39
+ */
40
+ function initElements(elements) {
41
+ for (let element of elements) initElement(element);
42
+ }
43
+
44
+ /**
45
+ * Initializes a single element.
46
+ * @param {Element} element - The element to initialize. This function expects an 'Element' type.
47
+ */
48
+ function initElement(element) {
49
+ const types = ["localstorage", "sessionstorage"];
50
+ let hasValue = false;
51
+
52
+ for (let type of types) {
53
+ let key = element.getAttribute(`${type}-get`) || element.getAttribute(`${type}-set`);
54
+ if (!key) continue;
55
+
56
+ let value = getItem(key, type);
57
+ if (value) {
58
+ element.setValue(value);
59
+ hasValue = true;
60
+ }
61
+ }
62
+
63
+ if (!hasValue) {
64
+ let inputEvent = new CustomEvent("input", {
65
+ bubbles: true
66
+ });
67
+
68
+ Object.defineProperty(inputEvent, "target", {
69
+ writable: false,
70
+ value: element
71
+ });
72
+ element.dispatchEvent(inputEvent);
73
+ }
74
+
75
+ element.addEventListener("input", (e) => {
76
+ let isRealtime = element.getAttribute("realtime");
77
+ // Returns if realtime false.
78
+ if (!isRealtime && isRealtime === "false") return;
79
+
80
+ for (let type of types) {
81
+ let currentKey = e.target.getAttribute(`${type}-set`);
82
+ if (!currentKey) continue;
83
+
84
+ // Set the key and value in the respective storage.
85
+ setItem(currentKey, e.target.value, type);
86
+
87
+ let elements = document.querySelectorAll(
88
+ `[${type}-get="${currentKey}"]`
89
+ );
90
+ for (let el of elements) {
91
+ if (el != element) {
92
+ let value = getItem(currentKey, type);
93
+ // Set the value of the element.
94
+ if (value != null) {
95
+ el.setValue(value);
96
+ }
97
+ }
98
+ }
99
+ }
100
+ });
101
+ }
102
+
103
+ /**
104
+ * @param key
105
+ * @param type - 'localstorage' or 'sessionstorage'
106
+ * @return { Mixed } The value associated with the key or undefined if not found.
107
+ */
108
+ function getItem(key, type = "localstorage") {
109
+ if (support) {
110
+ return type === "sessionstorage" ? window.sessionStorage.getItem(key) : window.localStorage.getItem(key);
111
+ } else {
112
+ return storage.get(`${type}-${key}`);
113
+ }
114
+ }
115
+
116
+ /**
117
+ * @param key - key name to store the value under
118
+ * @param value - value to store
119
+ * @param type - 'localstorage' or 'sessionstorage'
120
+ */
121
+ function setItem(key, value, type = "localstorage") {
122
+ try {
123
+ if (support) {
124
+ const storageObj = type === "sessionstorage" ? window.sessionStorage : window.localStorage;
125
+ const oldValue = storageObj.getItem(key);
126
+
127
+ storageObj.setItem(key, value);
128
+
129
+ const keys = [
130
+ "organization_id",
131
+ "user_id",
132
+ "clientId",
133
+ "session_id"
134
+ ];
135
+ if (keys.includes(key)) {
136
+ const updateEvent = new CustomEvent("updateAttributes", {
137
+ detail: { key, newValue: value, oldValue, type }
138
+ });
139
+ window.dispatchEvent(updateEvent);
140
+ }
141
+ } else {
142
+ storage.set(`${type}-${key}`, value);
143
+ }
144
+ } catch (error) {
145
+ if (
146
+ error instanceof DOMException &&
147
+ (error.code === 22 ||
148
+ error.code === 1014 ||
149
+ error.name === "QuotaExceededError" ||
150
+ error.name === "NS_ERROR_DOM_QUOTA_REACHED")
151
+ ) {
152
+ console.log(
153
+ "Storage limit exceeded. Falling back to Map."
154
+ );
155
+ } else {
156
+ console.error("Error setting item:", error);
157
+ }
158
+ }
159
+ }
160
+
161
+ /**
162
+ * @param key - The key name to delete from the storage
163
+ * @param type - 'localstorage' or 'sessionstorage'
164
+ */
165
+ function removeItem(key, type = "localstorage") {
166
+ if (support) {
167
+ if (type === "sessionstorage") window.sessionStorage.removeItem(key);
168
+ else window.localStorage.removeItem(key);
169
+ } else {
170
+ storage.delete(`${type}-${key}`);
171
+ }
172
+ }
173
+
174
+ /**
175
+ * @param action
176
+ *
177
+ * @return { undefined } No return
178
+ */
179
+ async function runStorage(action) {
180
+ const form = action.form;
181
+ if (!form) return;
182
+
183
+ const types = ["localstorage", "sessionstorage"];
184
+
185
+ for (let type of types) {
186
+ let set_els = form.querySelectorAll(`[${type}-set]`);
187
+ for (let el of set_els) {
188
+ let key = el.getAttribute(`${type}-set`);
189
+ let value = await el.getValue();
190
+ if (value && key) {
191
+ setItem(key, value, type);
192
+ }
193
+ }
194
+
195
+ let get_els = form.querySelectorAll(`[${type}-get]`);
196
+ for (let el of get_els) {
197
+ let key = el.getAttribute(`${type}-get`);
198
+ if (!key) continue;
199
+ let value = getItem(key, type);
200
+ if (value != null) {
201
+ el.setValue(value);
202
+ }
203
+ }
204
+
205
+ let remove_els = form.querySelectorAll(`[${type}-remove]`);
206
+ for (let el of remove_els) {
207
+ el.setValue("");
208
+ let key = el.getAttribute(`${type}-remove`);
209
+ if (key) {
210
+ removeItem(key, type);
211
+ }
212
+ }
213
+ }
214
+
215
+ action.element.dispatchEvent(
216
+ new CustomEvent("localStorage", {
217
+ detail: {}
218
+ })
219
+ );
220
+ }
221
+
222
+ const localStorage = {
223
+ getItem: (key) => getItem(key, "localstorage"),
224
+ setItem: (key, value) => setItem(key, value, "localstorage"),
225
+ removeItem: (key) => removeItem(key, "localstorage")
226
+ };
227
+
228
+ const sessionStorage = {
229
+ getItem: (key) => getItem(key, "sessionstorage"),
230
+ setItem: (key, value) => setItem(key, value, "sessionstorage"),
231
+ removeItem: (key) => removeItem(key, "sessionstorage")
216
232
  };
217
233
 
234
+ function checkSupport() {
235
+ // Check if the browser supports Web Storage.
236
+ if (!("localStorage" in window) || !("sessionStorage" in window)) {
237
+ console.log("This browser doesn't support Web Storage.");
238
+ support = false;
239
+ } else {
240
+ try {
241
+ window.localStorage.getItem("test");
242
+ window.sessionStorage.getItem("test");
243
+ if (window.CoCreateConfig && window.CoCreateConfig.localStorage === false)
244
+ support = false;
245
+ } catch (e) {
246
+ support = false;
247
+ } finally {
248
+ if (support) init();
249
+ }
250
+ }
251
+ }
252
+
218
253
  Actions.init(
219
- {
220
- name: "localStorage",
221
- endEvent: "localStorage",
222
- callback: (data) => {
223
- CoCreateLocalStorage.runStorage(data);
224
- }
225
- },
226
- {
227
- name: "localStorageRemove",
228
- endEvent: "localStorageRemoved",
229
- callback: (data) => {
230
- CoCreateLocalStorage.runStorage(data);
231
- }
232
- }
254
+ {
255
+ name: "localStorage",
256
+ endEvent: "localStorage",
257
+ callback: (data) => {
258
+ runStorage(data);
259
+ }
260
+ },
261
+ {
262
+ name: "localStorageRemove",
263
+ endEvent: "localStorageRemoved",
264
+ callback: (data) => {
265
+ runStorage(data);
266
+ }
267
+ },
268
+ {
269
+ name: "sessionStorage",
270
+ endEvent: "sessionStorage",
271
+ callback: (data) => {
272
+ runStorage(data);
273
+ }
274
+ },
275
+ {
276
+ name: "sessionStorageRemove",
277
+ endEvent: "sessionStorageRemoved",
278
+ callback: (data) => {
279
+ runStorage(data);
280
+ }
281
+ }
233
282
  );
234
283
 
235
284
  Observer.init({
236
- types: ["addedNodes"],
237
- selector: "[localstorage-set]",
238
- callback: async function (mutation) {
239
- let key = mutation.target.getAttribute("localstorage-set");
240
- let value = await mutation.target.getValue();
241
- if (key && value) localStorage.setItem(key, value);
242
- }
285
+ types: ["addedNodes"],
286
+ selector: "[localstorage-set], [sessionstorage-set]",
287
+ callback: async function (mutation) {
288
+ const types = ["localstorage", "sessionstorage"];
289
+ for (let type of types) {
290
+ let key = mutation.target.getAttribute(`${type}-set`);
291
+ if (key) {
292
+ let value = await mutation.target.getValue();
293
+ if (value) setItem(key, value, type);
294
+ }
295
+ }
296
+ }
243
297
  });
244
298
 
245
- CoCreateLocalStorage.checkSupport();
299
+ checkSupport();
300
+
246
301
 
247
- export default CoCreateLocalStorage;
302
+ export default {
303
+ init,
304
+ initElements,
305
+ initElement,
306
+ getItem,
307
+ setItem,
308
+ removeItem,
309
+ runStorage,
310
+ checkSupport,
311
+ localStorage,
312
+ sessionStorage
313
+ };