@cocreate/plugins 1.0.2 → 1.0.3
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.
- package/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/index.js +147 -301
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [1.0.3](https://github.com/CoCreate-app/CoCreate-plugins/compare/v1.0.2...v1.0.3) (2025-12-26)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* update worklow ([8976d08](https://github.com/CoCreate-app/CoCreate-plugins/commit/8976d080f8972e840ff5530d5dfb15f839e9ac5b))
|
|
7
|
+
|
|
1
8
|
## [1.0.2](https://github.com/CoCreate-app/CoCreate-plugins/compare/v1.0.1...v1.0.2) (2025-12-25)
|
|
2
9
|
|
|
3
10
|
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -6,17 +6,14 @@ const plugins = {
|
|
|
6
6
|
Toastify: {
|
|
7
7
|
js: [{ src: "https://cdn.jsdelivr.net/npm/toastify-js", crossOrigin: "anonymous" }],
|
|
8
8
|
css: ["https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css"]
|
|
9
|
-
// attribute prefix: toastify-
|
|
10
9
|
},
|
|
11
10
|
Choices: {
|
|
12
11
|
js: [{ src: "https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js", crossOrigin: "anonymous" }],
|
|
13
12
|
css: ["https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css"]
|
|
14
|
-
// attribute prefix: choices-
|
|
15
13
|
},
|
|
16
14
|
flatpickr: {
|
|
17
15
|
js: [{ src: "https://cdn.jsdelivr.net/npm/flatpickr", crossOrigin: "anonymous" }],
|
|
18
16
|
css: ["https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css"]
|
|
19
|
-
// attribute prefix: flatpickr-
|
|
20
17
|
},
|
|
21
18
|
Quill: {
|
|
22
19
|
js: [{ src: "https://cdn.jsdelivr.net/npm/quill@2.0.2/dist/quill.min.js", crossOrigin: "anonymous" }],
|
|
@@ -25,47 +22,37 @@ const plugins = {
|
|
|
25
22
|
"https://cdn.jsdelivr.net/npm/quill@2.0.2/dist/quill.snow.css",
|
|
26
23
|
"https://cdn.jsdelivr.net/npm/quill@2.0.2/dist/quill.bubble.css"
|
|
27
24
|
]
|
|
28
|
-
// attribute prefix: quill-
|
|
29
25
|
},
|
|
30
26
|
ClassicEditor: {
|
|
31
27
|
js: [{ src: "https://cdn.ckeditor.com/ckeditor5/41.2.0/classic/ckeditor.js", crossOrigin: "anonymous" }]
|
|
32
|
-
// attribute prefix: classiceditor-
|
|
33
28
|
},
|
|
34
29
|
Dropzone: {
|
|
35
30
|
js: [{ src: "https://unpkg.com/dropzone@5/dist/min/dropzone.min.js", crossOrigin: "anonymous" }],
|
|
36
31
|
css: ["https://unpkg.com/dropzone@5/dist/min/dropzone.min.css"]
|
|
37
|
-
// attribute prefix: dropzone-
|
|
38
32
|
},
|
|
39
33
|
SimpleBar: {
|
|
40
34
|
js: [{ src: "https://cdn.jsdelivr.net/npm/simplebar@latest/dist/simplebar.min.js", crossOrigin: "anonymous" }],
|
|
41
35
|
css: ["https://cdn.jsdelivr.net/npm/simplebar@latest/dist/simplebar.css"]
|
|
42
|
-
// attribute prefix: simplebar-
|
|
43
36
|
},
|
|
44
37
|
GLightbox: {
|
|
45
38
|
js: [{ src: "https://cdn.jsdelivr.net/npm/glightbox/dist/js/glightbox.min.js", crossOrigin: "anonymous" }],
|
|
46
39
|
css: ["https://cdn.jsdelivr.net/npm/glightbox/dist/css/glightbox.min.css"]
|
|
47
|
-
// attribute prefix: glightbox-
|
|
48
40
|
},
|
|
49
41
|
FgEmojiPicker: {
|
|
50
42
|
js: [{ src: "https://cdn.jsdelivr.net/npm/fg-emoji-picker/fgEmojiPicker.js", crossOrigin: "anonymous" }]
|
|
51
|
-
// attribute prefix: fgemojipicker-
|
|
52
43
|
},
|
|
53
44
|
bootstrap: {
|
|
54
45
|
js: [{ src: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js", crossOrigin: "anonymous" }]
|
|
55
|
-
// attribute prefix: bootstrap-
|
|
56
46
|
},
|
|
57
47
|
Waves: {
|
|
58
48
|
js: [{ src: "https://cdn.jsdelivr.net/npm/node-waves/dist/waves.min.js", crossOrigin: "anonymous" }],
|
|
59
49
|
css: ["https://cdn.jsdelivr.net/npm/node-waves/dist/waves.min.css"]
|
|
60
|
-
// attribute prefix: waves-
|
|
61
50
|
},
|
|
62
51
|
feather: {
|
|
63
52
|
js: [{ src: "https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js", crossOrigin: "anonymous" }]
|
|
64
|
-
// attribute prefix: feather-
|
|
65
53
|
},
|
|
66
54
|
ApexCharts: {
|
|
67
55
|
js: [{ src: "https://cdn.jsdelivr.net/npm/apexcharts", crossOrigin: "anonymous" }]
|
|
68
|
-
// attribute prefix: apexcharts-
|
|
69
56
|
},
|
|
70
57
|
jsVectorMap: {
|
|
71
58
|
js: [
|
|
@@ -73,41 +60,33 @@ const plugins = {
|
|
|
73
60
|
{ src: "https://cdn.jsdelivr.net/npm/jsvectormap/dist/maps/world.js", crossOrigin: "anonymous" }
|
|
74
61
|
],
|
|
75
62
|
css: ["https://cdn.jsdelivr.net/npm/jsvectormap/dist/css/jsvectormap.min.css"]
|
|
76
|
-
// attribute prefix: jsvectormap-
|
|
77
63
|
},
|
|
78
64
|
Swiper: {
|
|
79
65
|
js: [{ src: "https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js", crossOrigin: "anonymous" }],
|
|
80
66
|
css: ["https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css"]
|
|
81
|
-
// attribute prefix: swiper-
|
|
82
67
|
},
|
|
83
68
|
List: {
|
|
84
69
|
js: [
|
|
85
70
|
{ src: "https://cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js", crossOrigin: "anonymous" },
|
|
86
71
|
{ src: "https://cdnjs.cloudflare.com/ajax/libs/list.pagination.js/0.1.1/list.pagination.min.js", crossOrigin: "anonymous" }
|
|
87
72
|
]
|
|
88
|
-
// attribute prefix: list-
|
|
89
73
|
},
|
|
90
74
|
Swal: {
|
|
91
75
|
js: [{ src: "https://cdn.jsdelivr.net/npm/sweetalert2@11", crossOrigin: "anonymous" }],
|
|
92
76
|
css: ["https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css"]
|
|
93
|
-
// attribute prefix: swal-
|
|
94
77
|
},
|
|
95
78
|
FullCalendar: {
|
|
96
79
|
js: [{ src: "https://cdn.jsdelivr.net/npm/fullcalendar@6.1.15/index.global.min.js", crossOrigin: "anonymous" }]
|
|
97
|
-
// attribute prefix: fullcalendar-
|
|
98
80
|
},
|
|
99
81
|
Cleave: {
|
|
100
82
|
js: [{ src: "https://cdn.jsdelivr.net/npm/cleave.js/dist/cleave.min.js", crossOrigin: "anonymous" }]
|
|
101
|
-
// attribute prefix: cleave-
|
|
102
83
|
},
|
|
103
84
|
noUiSlider: {
|
|
104
85
|
js: [{ src: "https://cdn.jsdelivr.net/npm/nouislider/dist/nouislider.min.js", crossOrigin: "anonymous" }],
|
|
105
86
|
css: ["https://cdn.jsdelivr.net/npm/nouislider/dist/nouislider.min.css"]
|
|
106
|
-
// attribute prefix: nouislider-
|
|
107
87
|
},
|
|
108
88
|
wNumb: {
|
|
109
89
|
js: [{ src: "https://cdn.jsdelivr.net/npm/wnumb/wNumb.min.js", crossOrigin: "anonymous" }]
|
|
110
|
-
// attribute prefix: wnumb-
|
|
111
90
|
},
|
|
112
91
|
Grid: {
|
|
113
92
|
js: [
|
|
@@ -115,7 +94,6 @@ const plugins = {
|
|
|
115
94
|
{ src: "https://unpkg.com/gridjs/plugins/selection/dist/selection.umd.js", crossOrigin: "anonymous" }
|
|
116
95
|
],
|
|
117
96
|
css: ["https://unpkg.com/gridjs/dist/theme/mermaid.min.css"]
|
|
118
|
-
// attribute prefix: grid-
|
|
119
97
|
},
|
|
120
98
|
FilePond: {
|
|
121
99
|
js: [
|
|
@@ -129,83 +107,72 @@ const plugins = {
|
|
|
129
107
|
"https://unpkg.com/filepond/dist/filepond.min.css",
|
|
130
108
|
"https://unpkg.com/filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css"
|
|
131
109
|
]
|
|
132
|
-
// attribute prefix: filepond-
|
|
133
110
|
},
|
|
134
111
|
Prism: {
|
|
135
112
|
js: [{ src: "https://cdn.jsdelivr.net/npm/prismjs/prism.min.js", crossOrigin: "anonymous" }],
|
|
136
113
|
css: ["https://cdn.jsdelivr.net/npm/prismjs/themes/prism.min.css"]
|
|
137
|
-
// attribute prefix: prism-
|
|
138
114
|
},
|
|
139
115
|
Isotope: {
|
|
140
116
|
js: [{ src: "https://unpkg.com/isotope-layout@3/dist/isotope.pkgd.min.js", crossOrigin: "anonymous" }]
|
|
141
|
-
// attribute prefix: isotope-
|
|
142
117
|
},
|
|
143
118
|
particlesJS: {
|
|
144
119
|
js: [{ src: "https://cdn.jsdelivr.net/npm/particles.js@2.0.0/particles.min.js", crossOrigin: "anonymous" }]
|
|
145
|
-
// attribute prefix: particlesjs-
|
|
146
120
|
},
|
|
147
121
|
dragula: {
|
|
148
122
|
js: [{ src: "https://cdn.jsdelivr.net/npm/dragula/dist/dragula.min.js", crossOrigin: "anonymous" }],
|
|
149
123
|
css: ["https://cdn.jsdelivr.net/npm/dragula/dist/dragula.min.css"]
|
|
150
|
-
// attribute prefix: dragula-
|
|
151
124
|
},
|
|
152
125
|
DomAutoscroller: {
|
|
153
126
|
js: [{ src: "https://cdn.jsdelivr.net/npm/dom-autoscroller", crossOrigin: "anonymous" }]
|
|
154
|
-
// attribute prefix: domautoscroller-
|
|
155
127
|
},
|
|
156
128
|
Card: {
|
|
157
129
|
js: [{ src: "https://cdn.jsdelivr.net/npm/card/dist/card.js", crossOrigin: "anonymous" }]
|
|
158
|
-
// attribute prefix: card-
|
|
159
130
|
},
|
|
160
131
|
Chart: {
|
|
161
132
|
js: [{ src: "https://cdn.jsdelivr.net/npm/chart.js", crossOrigin: "anonymous" }]
|
|
162
|
-
// attribute prefix: chart-
|
|
163
133
|
},
|
|
164
134
|
echarts: {
|
|
165
135
|
js: [{ src: "https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js", crossOrigin: "anonymous" }]
|
|
166
|
-
// attribute prefix: echarts-
|
|
167
136
|
},
|
|
168
137
|
Multi: {
|
|
169
138
|
js: [{ src: "https://cdn.jsdelivr.net/npm/multi.js/dist/multi.min.js", crossOrigin: "anonymous" }],
|
|
170
139
|
css: ["https://cdn.jsdelivr.net/npm/multi.js/dist/multi.min.css"]
|
|
171
|
-
// attribute prefix: multi-
|
|
172
140
|
},
|
|
173
141
|
autoComplete: {
|
|
174
142
|
js: [{ src: "https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.7/dist/autoComplete.min.js", crossOrigin: "anonymous" }],
|
|
175
143
|
css: ["https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.7/dist/css/autoComplete.01.min.css"]
|
|
176
|
-
// attribute prefix: autocomplete-
|
|
177
144
|
},
|
|
178
145
|
Pickr: {
|
|
179
146
|
js: [{ src: "https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/pickr.min.js", crossOrigin: "anonymous" }],
|
|
180
147
|
css: ["https://cdn.jsdelivr.net/npm/@simonwep/pickr/dist/themes/classic.min.css"]
|
|
181
|
-
// attribute prefix: pickr-
|
|
182
148
|
},
|
|
183
149
|
Shepherd: {
|
|
184
150
|
js: [{ src: "https://cdn.jsdelivr.net/npm/shepherd.js/dist/js/shepherd.min.js", crossOrigin: "anonymous" }],
|
|
185
151
|
css: ["https://cdn.jsdelivr.net/npm/shepherd.js/dist/css/shepherd.css"]
|
|
186
|
-
// attribute prefix: shepherd-
|
|
187
152
|
},
|
|
188
153
|
GMaps: {
|
|
189
154
|
js: [{ src: "https://cdn.jsdelivr.net/npm/gmaps/gmaps.min.js", crossOrigin: "anonymous" }]
|
|
190
|
-
// attribute prefix: gmaps-
|
|
191
155
|
},
|
|
192
156
|
L: {
|
|
193
157
|
js: [{ src: "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js", crossOrigin: "anonymous" }],
|
|
194
158
|
css: ["https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"]
|
|
195
|
-
// attribute prefix: l-
|
|
196
159
|
},
|
|
197
160
|
Masonry: {
|
|
198
161
|
js: [{ src: "https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js", crossOrigin: "anonymous" }]
|
|
199
|
-
// attribute prefix: masonry-
|
|
200
162
|
},
|
|
201
163
|
Rater: {
|
|
202
164
|
js: [{ src: "https://cdn.jsdelivr.net/npm/rater-js/index.js", crossOrigin: "anonymous" }]
|
|
203
|
-
|
|
165
|
+
},
|
|
166
|
+
Anime: {
|
|
167
|
+
js: [{ src: "https://cdn.jsdelivr.net/npm/animejs@3.2.2/lib/anime.min.js", crossOrigin: "anonymous" }]
|
|
204
168
|
}
|
|
205
169
|
};
|
|
206
170
|
|
|
207
171
|
// --- CORE ENGINE ---
|
|
208
172
|
|
|
173
|
+
// Global Cache for script promises to prevent race conditions and duplicate loads
|
|
174
|
+
const scriptCache = new Map();
|
|
175
|
+
|
|
209
176
|
/**
|
|
210
177
|
* Global Initialization Function
|
|
211
178
|
* Processes one or more elements to attach plugins.
|
|
@@ -214,323 +181,197 @@ const plugins = {
|
|
|
214
181
|
export function init(elements) {
|
|
215
182
|
if (!elements) return;
|
|
216
183
|
|
|
217
|
-
// 1. Detect Type & Normalize to Array
|
|
218
|
-
// Normalize string handling (removed), Element, NodeList, HTMLCollection, Array
|
|
219
184
|
let collection = [];
|
|
220
|
-
|
|
221
185
|
if (elements instanceof HTMLElement || elements instanceof Element) {
|
|
222
186
|
collection = [elements];
|
|
223
187
|
} else if (elements.length !== undefined && typeof elements !== 'function') {
|
|
224
|
-
// Handle Array-like objects (NodeList, HTMLCollection, Array)
|
|
225
188
|
collection = Array.from(elements);
|
|
226
189
|
} else {
|
|
227
|
-
// Fallback for single object that isn't element (unlikely given spec, but safe)
|
|
228
190
|
collection = [elements];
|
|
229
191
|
}
|
|
230
192
|
|
|
231
|
-
// 2. Iterate and Process
|
|
232
193
|
collection.forEach(el => {
|
|
233
|
-
// Ensure valid element before processing
|
|
234
194
|
if (el && typeof el.getAttribute === 'function') {
|
|
235
195
|
processPlugin(el);
|
|
236
196
|
}
|
|
237
197
|
});
|
|
238
198
|
}
|
|
239
199
|
|
|
240
|
-
// Auto-Init on load
|
|
241
|
-
if (typeof document !== 'undefined') {
|
|
242
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
243
|
-
init(document.querySelectorAll("[plugin]"));
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
|
|
247
200
|
async function processPlugin(el) {
|
|
248
201
|
const rawAttr = el.getAttribute("plugin");
|
|
249
202
|
if (!rawAttr) return;
|
|
250
203
|
|
|
251
|
-
const
|
|
204
|
+
const pluginNames = rawAttr.split(',').map(s => s.trim());
|
|
252
205
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (pluginDef) {
|
|
258
|
-
console.log(`[Plugin System] Loading ${pluginName}...`);
|
|
206
|
+
for (const pluginName of pluginNames) {
|
|
207
|
+
const pluginDef = plugins[pluginName];
|
|
208
|
+
if (!pluginDef) continue;
|
|
259
209
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
210
|
+
// Load CSS
|
|
211
|
+
if (pluginDef.css) pluginDef.css.forEach(href => {
|
|
212
|
+
if (!document.querySelector(`link[href="${href}"]`)) {
|
|
263
213
|
const link = document.createElement("link");
|
|
264
|
-
link.rel="stylesheet"; link.href=href; document.head.appendChild(link);
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
214
|
+
link.rel = "stylesheet"; link.href = href; document.head.appendChild(link);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Load JS with Promise Cache
|
|
219
|
+
if (pluginDef.js) {
|
|
220
|
+
for (const item of pluginDef.js) {
|
|
221
|
+
const src = typeof item === 'string' ? item : item.src;
|
|
222
|
+
const integrity = typeof item === 'object' ? item.integrity : null;
|
|
223
|
+
const crossOrigin = typeof item === 'object' ? item.crossOrigin : null;
|
|
224
|
+
|
|
225
|
+
if (!scriptCache.has(src)) {
|
|
226
|
+
const scriptPromise = new Promise((resolve, reject) => {
|
|
227
|
+
// Check if already in DOM (manual load)
|
|
228
|
+
const existing = document.querySelector(`script[src="${src}"]`);
|
|
229
|
+
if (existing) {
|
|
230
|
+
if (existing.dataset.loaded === "true") {
|
|
231
|
+
resolve();
|
|
232
|
+
} else {
|
|
233
|
+
const prevOnload = existing.onload;
|
|
234
|
+
existing.onload = () => {
|
|
235
|
+
if (prevOnload) prevOnload();
|
|
236
|
+
existing.dataset.loaded = "true";
|
|
237
|
+
resolve();
|
|
238
|
+
};
|
|
239
|
+
existing.onerror = reject;
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
const s = document.createElement("script");
|
|
243
|
+
s.src = src;
|
|
244
|
+
if (integrity) {
|
|
245
|
+
s.integrity = integrity;
|
|
246
|
+
s.crossOrigin = crossOrigin || "anonymous";
|
|
247
|
+
}
|
|
248
|
+
s.onload = () => {
|
|
249
|
+
s.dataset.loaded = "true";
|
|
250
|
+
resolve();
|
|
251
|
+
};
|
|
252
|
+
s.onerror = reject;
|
|
253
|
+
document.head.appendChild(s);
|
|
283
254
|
}
|
|
284
|
-
s.onload = resolve;
|
|
285
|
-
s.onerror = reject;
|
|
286
|
-
document.head.appendChild(s);
|
|
287
255
|
});
|
|
256
|
+
scriptCache.set(src, scriptPromise);
|
|
288
257
|
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Initialize after load
|
|
292
|
-
executeGenericPlugin(el, pluginName);
|
|
293
258
|
|
|
294
|
-
|
|
295
|
-
|
|
259
|
+
try {
|
|
260
|
+
await scriptCache.get(src);
|
|
261
|
+
} catch (e) {
|
|
262
|
+
console.error(`Failed to load script: ${src}`, e);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
executeGenericPlugin(el, pluginName);
|
|
296
268
|
}
|
|
297
269
|
}
|
|
298
270
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
// Now looks for attributes like `quill=""` and `quill-theme=""`.
|
|
302
|
-
const prefix = pluginName.toLowerCase();
|
|
271
|
+
function executeGenericPlugin(el, name) {
|
|
272
|
+
const prefix = name.toLowerCase();
|
|
303
273
|
const mainAttr = el.getAttribute(prefix);
|
|
274
|
+
let rawData;
|
|
304
275
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if (!attr.name.startsWith(prefix + '-')) return;
|
|
311
|
-
const key = attr.name.substring(prefix.length + 1);
|
|
312
|
-
|
|
313
|
-
if (key.startsWith('$')) return;
|
|
276
|
+
try {
|
|
277
|
+
rawData = JSON.parse(mainAttr);
|
|
278
|
+
} catch(e) {
|
|
279
|
+
rawData = {};
|
|
280
|
+
}
|
|
314
281
|
|
|
315
|
-
|
|
316
|
-
|
|
282
|
+
// 1. Gather configuration from attributes
|
|
283
|
+
if (rawData && typeof rawData === 'object' && !Array.isArray(rawData)) {
|
|
284
|
+
Array.from(el.attributes).forEach(attr => {
|
|
285
|
+
if (!attr.name.startsWith(prefix + '-')) return;
|
|
286
|
+
let key = attr.name.substring(prefix.length + 1);
|
|
287
|
+
if (key.startsWith('$')) key = key.substring(1);
|
|
288
|
+
let val = attr.value;
|
|
289
|
+
try { val = JSON.parse(val); } catch (e) { }
|
|
290
|
+
rawData[key] = val;
|
|
291
|
+
});
|
|
292
|
+
}
|
|
317
293
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
let target = config;
|
|
321
|
-
for(let i=0; i<parts.length-1; i++) {
|
|
322
|
-
if (!target[parts[i]]) target[parts[i]] = {};
|
|
323
|
-
target = target[parts[i]];
|
|
324
|
-
}
|
|
325
|
-
target[parts[parts.length-1]] = val;
|
|
326
|
-
} else {
|
|
327
|
-
config[key] = val;
|
|
328
|
-
}
|
|
329
|
-
});
|
|
294
|
+
// 2. Resolve parameters (Token Resolver)
|
|
295
|
+
const resolved = processParams(el, rawData);
|
|
330
296
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
if (!Constructor) {
|
|
335
|
-
console.error(`Constructor for ${pluginName} not found on window.`);
|
|
297
|
+
const Target = window[name] || window[prefix];
|
|
298
|
+
if (!Target) {
|
|
299
|
+
console.error(`Constructor for ${name} not found on window.`);
|
|
336
300
|
return;
|
|
337
301
|
}
|
|
338
302
|
|
|
339
|
-
let instance
|
|
303
|
+
let instance;
|
|
340
304
|
try {
|
|
341
|
-
|
|
342
|
-
if (
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
305
|
+
// 3. Determine if we call as a function (Anime) or as a Constructor (Swiper)
|
|
306
|
+
if (typeof Target === 'function' && (!Target.prototype || name === 'Anime')) {
|
|
307
|
+
instance = Target(resolved);
|
|
308
|
+
} else {
|
|
309
|
+
if (Array.isArray(resolved)) {
|
|
310
|
+
instance = new Target(...resolved);
|
|
311
|
+
} else {
|
|
312
|
+
instance = new Target(resolved);
|
|
313
|
+
}
|
|
349
314
|
}
|
|
350
|
-
|
|
351
|
-
} catch(e) {
|
|
352
|
-
console.error(`
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
if (instance) el[pluginName] = instance;
|
|
357
|
-
else return;
|
|
358
|
-
|
|
359
|
-
// 3. OPERATOR PIPELINE
|
|
360
|
-
const opPipeline = [];
|
|
361
|
-
attributes.forEach(attr => {
|
|
362
|
-
if (!attr.name.startsWith(prefix + '-')) return;
|
|
363
|
-
let key = attr.name.substring(prefix.length + 1);
|
|
364
|
-
if (!key.startsWith('$')) return;
|
|
365
|
-
let val = attr.value;
|
|
366
|
-
try { val = JSON.parse(val); } catch(e) {}
|
|
367
|
-
let opName = key;
|
|
368
|
-
opPipeline.push(opName, [val]);
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
if (opPipeline.length > 0) {
|
|
372
|
-
await executePipeline(el, opPipeline, pluginName, instance, config);
|
|
315
|
+
console.log(`Initialized ${name}`);
|
|
316
|
+
} catch (e) {
|
|
317
|
+
console.error(`Error initializing ${name}:`, e);
|
|
373
318
|
}
|
|
319
|
+
if (instance) el[name] = instance;
|
|
374
320
|
}
|
|
375
321
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
if (opName.startsWith('$')) {
|
|
403
|
-
if (!currentCtx) {
|
|
404
|
-
if (element[pluginName]) currentCtx = element[pluginName];
|
|
405
|
-
if (!currentCtx) {
|
|
406
|
-
console.warn(`Context undefined for operator ${opName}. Skipping.`);
|
|
407
|
-
continue;
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
let cleanName = opName.substring(1);
|
|
412
|
-
if (!cleanName.includes('.')) {
|
|
413
|
-
cleanName = cleanName.replace(/-/g, '');
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
let realKey = cleanName;
|
|
417
|
-
if (!cleanName.includes('.') && currentCtx && (typeof currentCtx === 'object' || typeof currentCtx === 'function')) {
|
|
418
|
-
try {
|
|
419
|
-
const keys = Object.keys(currentCtx.constructor?.prototype || currentCtx);
|
|
420
|
-
const found = keys.find(k => k.toLowerCase() === cleanName.toLowerCase());
|
|
421
|
-
if (found) realKey = found;
|
|
422
|
-
else {
|
|
423
|
-
const directFound = Object.keys(currentCtx).find(k => k.toLowerCase() === cleanName.toLowerCase());
|
|
424
|
-
if(directFound) realKey = directFound;
|
|
425
|
-
}
|
|
426
|
-
} catch (e) {}
|
|
322
|
+
/**
|
|
323
|
+
* Generic Parameter Processor
|
|
324
|
+
* Handles:
|
|
325
|
+
* - $this / $this.children
|
|
326
|
+
* - $window.path.to.function(arg)
|
|
327
|
+
* - $anime.stagger(100)
|
|
328
|
+
*/
|
|
329
|
+
function processParams(el, params) {
|
|
330
|
+
if (typeof params === 'string' && params.startsWith('$')) {
|
|
331
|
+
try {
|
|
332
|
+
// 1. Check for Method Call: $root.path.to.func(arg)
|
|
333
|
+
const callMatch = params.match(/^\$([^.]+)\.(.+)\((.*)\)$/);
|
|
334
|
+
if (callMatch) {
|
|
335
|
+
const [_, root, path, arg] = callMatch;
|
|
336
|
+
const obj = (root === 'this') ? el : window[root];
|
|
337
|
+
|
|
338
|
+
// If root object exists, drill down
|
|
339
|
+
if (obj) {
|
|
340
|
+
const func = path.split('.').reduce((o, k) => (o || {})[k], obj);
|
|
341
|
+
if (typeof func === 'function') {
|
|
342
|
+
// Parse argument if JSON-like, else string
|
|
343
|
+
const parsedArg = arg ? (function() { try { return JSON.parse(arg); } catch(e) { return arg; } })() : undefined;
|
|
344
|
+
return func(parsedArg);
|
|
345
|
+
}
|
|
427
346
|
}
|
|
428
|
-
opName = realKey;
|
|
429
347
|
}
|
|
430
|
-
|
|
431
|
-
const [parent, val] = resolvePath(i === 0 ? window : currentCtx, opName);
|
|
432
348
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
349
|
+
// 2. Check for Property Access: $root.path.to.prop or just $root
|
|
350
|
+
const propMatch = params.match(/^\$([^.]+)(?:\.(.+))?$/);
|
|
351
|
+
if (propMatch) {
|
|
352
|
+
const [_, root, path] = propMatch;
|
|
353
|
+
const obj = (root === 'this') ? el : window[root];
|
|
354
|
+
if (!obj) return params; // Return raw string if root not found
|
|
355
|
+
if (!path) return obj;
|
|
356
|
+
|
|
357
|
+
const val = path.split('.').reduce((o, k) => (o || {})[k], obj);
|
|
358
|
+
// Convert HTMLCollections to Arrays
|
|
359
|
+
return (val instanceof HTMLCollection) ? Array.from(val) : val;
|
|
436
360
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
currentCtx = val;
|
|
440
|
-
|
|
441
|
-
if (typeof currentCtx === 'function') {
|
|
442
|
-
let args = [];
|
|
443
|
-
if (i + 1 < pipelineArray.length && Array.isArray(pipelineArray[i + 1])) {
|
|
444
|
-
args = processParams(element, pipelineArray[i + 1], config, instance, pluginName);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
try {
|
|
448
|
-
const finalArgs = (args.length === 1) ? [args[0]] : args;
|
|
449
|
-
try {
|
|
450
|
-
currentCtx = await currentCtx.apply(parentCtx, finalArgs);
|
|
451
|
-
} catch (err) {
|
|
452
|
-
currentCtx = new currentCtx(...finalArgs);
|
|
453
|
-
parentCtx = currentCtx;
|
|
454
|
-
}
|
|
455
|
-
} catch(e) {
|
|
456
|
-
console.error(`Exec error ${opName}`, e);
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
return currentCtx;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// --- HELPERS ---
|
|
465
|
-
function applyMapping(element, instance, def) {
|
|
466
|
-
if (def.includes('=')) {
|
|
467
|
-
const [lhs, rhs] = def.split('=').map(s => s.trim());
|
|
468
|
-
const pathRaw = rhs;
|
|
469
|
-
const match = lhs.match(/^[$]?([\w\.]+)(\(\))?$/);
|
|
470
|
-
if (!match) return;
|
|
471
|
-
const alias = match[1];
|
|
472
|
-
const isFunction = match[2] === '()';
|
|
473
|
-
|
|
474
|
-
if (isFunction) {
|
|
475
|
-
element[alias] = function(val) {
|
|
476
|
-
if (arguments.length > 0) return assignDeep(instance, pathRaw, val);
|
|
477
|
-
else return resolveDeep(instance, pathRaw);
|
|
478
|
-
};
|
|
479
|
-
} else {
|
|
480
|
-
Object.defineProperty(element, alias, {
|
|
481
|
-
get: () => resolveDeep(instance, pathRaw),
|
|
482
|
-
set: (v) => assignDeep(instance, pathRaw, v),
|
|
483
|
-
configurable: true
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
} else {
|
|
487
|
-
if (typeof instance[def] === 'function') {
|
|
488
|
-
element[def] = instance[def].bind(instance);
|
|
361
|
+
} catch (e) {
|
|
362
|
+
console.warn("Failed to resolve dynamic token:", params);
|
|
489
363
|
}
|
|
490
364
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
function processParams(element, params, config, instance, pluginName) {
|
|
494
|
-
if (params === "$this") return element;
|
|
495
|
-
if (params === "$config") return config;
|
|
496
|
-
if (params === "$root" || params === "$instance") return instance;
|
|
497
|
-
if (typeof params === 'string' && params === `$${pluginName}`) return instance;
|
|
498
|
-
if (typeof params === 'string' && params.startsWith('$this.')) return resolveDeep(element, params.substring(6));
|
|
499
|
-
if (Array.isArray(params)) return params.map(p => processParams(element, p, config, instance, pluginName));
|
|
365
|
+
|
|
366
|
+
if (Array.isArray(params)) return params.map(p => processParams(el, p));
|
|
500
367
|
if (typeof params === 'object' && params !== null) {
|
|
501
368
|
const res = {};
|
|
502
|
-
for(let k in params) res[k] = processParams(
|
|
369
|
+
for (let k in params) res[k] = processParams(el, params[k]);
|
|
503
370
|
return res;
|
|
504
371
|
}
|
|
505
372
|
return params;
|
|
506
373
|
}
|
|
507
374
|
|
|
508
|
-
function resolveDeep(obj, path) {
|
|
509
|
-
if (!obj || !path) return undefined;
|
|
510
|
-
return path.split('.').reduce((o, k) => (o || {})[k], obj);
|
|
511
|
-
}
|
|
512
|
-
function assignDeep(obj, path, val) {
|
|
513
|
-
if (!obj || !path) return;
|
|
514
|
-
const parts = path.split('.');
|
|
515
|
-
let target = obj;
|
|
516
|
-
for(let i=0; i<parts.length-1; i++) target = target[parts[i]];
|
|
517
|
-
const last = parts[parts.length-1];
|
|
518
|
-
if(typeof target[last] === 'function') target[last](val);
|
|
519
|
-
else target[last] = val;
|
|
520
|
-
}
|
|
521
|
-
function resolvePath(obj, path) {
|
|
522
|
-
if (!obj || !path) return [null, undefined];
|
|
523
|
-
const parts = path.split('.');
|
|
524
|
-
let current = obj;
|
|
525
|
-
let parent = null;
|
|
526
|
-
for (const part of parts) {
|
|
527
|
-
if (!current) return [null, undefined];
|
|
528
|
-
parent = current;
|
|
529
|
-
current = current[part];
|
|
530
|
-
}
|
|
531
|
-
return [parent, current];
|
|
532
|
-
}
|
|
533
|
-
|
|
534
375
|
// --- OBSERVER INTEGRATION ---
|
|
535
376
|
Observer.init({
|
|
536
377
|
name: "plugin",
|
|
@@ -540,4 +381,9 @@ Observer.init({
|
|
|
540
381
|
callback: (mutation) => {
|
|
541
382
|
init(mutation.target);
|
|
542
383
|
}
|
|
543
|
-
});
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// Auto-init for existing elements
|
|
387
|
+
if (typeof document !== 'undefined') {
|
|
388
|
+
init(document.querySelectorAll("[plugin]"));
|
|
389
|
+
}
|