slicejs-web-framework 2.2.13 ā 2.3.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.
- package/Slice/Components/Structural/ContextManager/ContextManager.js +361 -0
- package/Slice/Components/Structural/Controller/Controller.js +925 -890
- package/Slice/Components/Structural/EventManager/EventManager.js +329 -0
- package/Slice/Components/Structural/Router/Router.js +598 -589
- package/Slice/Slice.js +297 -249
- package/opencode.json +11 -0
- package/package.json +1 -1
- package/src/sliceConfig.json +60 -54
package/Slice/Slice.js
CHANGED
|
@@ -1,249 +1,297 @@
|
|
|
1
|
-
import Controller from './Components/Structural/Controller/Controller.js';
|
|
2
|
-
import StylesManager from './Components/Structural/StylesManager/StylesManager.js';
|
|
3
|
-
|
|
4
|
-
export default class Slice {
|
|
5
|
-
constructor(sliceConfig) {
|
|
6
|
-
this.controller = new Controller();
|
|
7
|
-
this.stylesManager = new StylesManager();
|
|
8
|
-
this.paths = sliceConfig.paths;
|
|
9
|
-
this.themeConfig = sliceConfig.themeManager;
|
|
10
|
-
this.stylesConfig = sliceConfig.stylesManager;
|
|
11
|
-
this.loggerConfig = sliceConfig.logger;
|
|
12
|
-
this.debuggerConfig = sliceConfig.debugger;
|
|
13
|
-
this.loadingConfig = sliceConfig.loading;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
let
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
this.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
this.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
this.logger.
|
|
154
|
-
return
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
this.
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const sliceConfig = await loadConfig();
|
|
190
|
-
if (!sliceConfig) {
|
|
191
|
-
//Display error message in console with colors and alert in english
|
|
192
|
-
console.error('%cāļø Error loading Slice configuration āļø', 'color: red; font-size: 20px;');
|
|
193
|
-
alert('Error loading Slice configuration');
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
);
|
|
217
|
-
window.slice.debugger
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
1
|
+
import Controller from './Components/Structural/Controller/Controller.js';
|
|
2
|
+
import StylesManager from './Components/Structural/StylesManager/StylesManager.js';
|
|
3
|
+
|
|
4
|
+
export default class Slice {
|
|
5
|
+
constructor(sliceConfig) {
|
|
6
|
+
this.controller = new Controller();
|
|
7
|
+
this.stylesManager = new StylesManager();
|
|
8
|
+
this.paths = sliceConfig.paths;
|
|
9
|
+
this.themeConfig = sliceConfig.themeManager;
|
|
10
|
+
this.stylesConfig = sliceConfig.stylesManager;
|
|
11
|
+
this.loggerConfig = sliceConfig.logger;
|
|
12
|
+
this.debuggerConfig = sliceConfig.debugger;
|
|
13
|
+
this.loadingConfig = sliceConfig.loading;
|
|
14
|
+
this.eventsConfig = sliceConfig.events;
|
|
15
|
+
|
|
16
|
+
// š¦ Bundle system is initialized automatically via import in index.js
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async getClass(module) {
|
|
20
|
+
try {
|
|
21
|
+
const { default: myClass } = await import(module);
|
|
22
|
+
return await myClass;
|
|
23
|
+
} catch (error) {
|
|
24
|
+
this.logger.logError('Slice', `Error loading class ${module}`, error);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
isProduction() {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getComponent(componentSliceId) {
|
|
33
|
+
return this.controller.activeComponents.get(componentSliceId);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async build(componentName, props = {}) {
|
|
37
|
+
if (!componentName) {
|
|
38
|
+
this.logger.logError('Slice', null, `Component name is required to build a component`);
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (typeof componentName !== 'string') {
|
|
43
|
+
this.logger.logError('Slice', null, `Component name must be a string`);
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!this.controller.componentCategories.has(componentName)) {
|
|
48
|
+
this.logger.logError('Slice', null, `Component ${componentName} not found in components.js file`);
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// š¦ Try to load from bundles first
|
|
53
|
+
const bundleName = this.controller.getBundleForComponent(componentName);
|
|
54
|
+
if (bundleName && !this.controller.loadedBundles.has(bundleName)) {
|
|
55
|
+
await this.controller.loadBundle(bundleName);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let componentCategory = this.controller.componentCategories.get(componentName);
|
|
59
|
+
|
|
60
|
+
// š¦ Check if component is already available from loaded bundles
|
|
61
|
+
const isFromBundle = this.controller.isComponentFromBundle(componentName);
|
|
62
|
+
|
|
63
|
+
if (componentCategory === 'Structural') {
|
|
64
|
+
this.logger.logError(
|
|
65
|
+
'Slice',
|
|
66
|
+
null,
|
|
67
|
+
`Component ${componentName} is a Structural component and cannot be built`
|
|
68
|
+
);
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let isVisual = slice.paths.components[componentCategory].type === 'Visual';
|
|
73
|
+
let modulePath = `${slice.paths.components[componentCategory].path}/${componentName}/${componentName}.js`;
|
|
74
|
+
|
|
75
|
+
// Load template, class, and CSS concurrently if needed
|
|
76
|
+
try {
|
|
77
|
+
// š¦ Skip individual loading if component is available from bundles
|
|
78
|
+
const loadTemplate =
|
|
79
|
+
isFromBundle || !isVisual || this.controller.templates.has(componentName)
|
|
80
|
+
? Promise.resolve(null)
|
|
81
|
+
: this.controller.fetchText(componentName, 'html', componentCategory);
|
|
82
|
+
|
|
83
|
+
const loadClass =
|
|
84
|
+
isFromBundle || this.controller.classes.has(componentName)
|
|
85
|
+
? Promise.resolve(null)
|
|
86
|
+
: this.getClass(modulePath);
|
|
87
|
+
|
|
88
|
+
const loadCSS =
|
|
89
|
+
isFromBundle || !isVisual || this.controller.requestedStyles.has(componentName)
|
|
90
|
+
? Promise.resolve(null)
|
|
91
|
+
: this.controller.fetchText(componentName, 'css', componentCategory);
|
|
92
|
+
|
|
93
|
+
const [html, ComponentClass, css] = await Promise.all([loadTemplate, loadClass, loadCSS]);
|
|
94
|
+
|
|
95
|
+
// š¦ If component is from bundle but not in cache, it should have been registered by registerBundle
|
|
96
|
+
if (isFromBundle) {
|
|
97
|
+
console.log(`š¦ Using bundled component: ${componentName}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (html || html === '') {
|
|
101
|
+
const template = document.createElement('template');
|
|
102
|
+
template.innerHTML = html;
|
|
103
|
+
this.controller.templates.set(componentName, template);
|
|
104
|
+
this.logger.logInfo('Slice', `Template ${componentName} loaded`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (ComponentClass) {
|
|
108
|
+
this.controller.classes.set(componentName, ComponentClass);
|
|
109
|
+
this.logger.logInfo('Slice', `Class ${componentName} loaded`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (css) {
|
|
113
|
+
this.stylesManager.registerComponentStyles(componentName, css);
|
|
114
|
+
this.logger.logInfo('Slice', `CSS ${componentName} loaded`);
|
|
115
|
+
}
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.log(error);
|
|
118
|
+
this.logger.logError('Slice', `Error loading resources for ${componentName}`, error);
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Create instance
|
|
123
|
+
try {
|
|
124
|
+
let componentIds = {};
|
|
125
|
+
if (props.id) componentIds.id = props.id;
|
|
126
|
+
if (props.sliceId) componentIds.sliceId = props.sliceId;
|
|
127
|
+
|
|
128
|
+
delete props.id;
|
|
129
|
+
delete props.sliceId;
|
|
130
|
+
|
|
131
|
+
const ComponentClass = this.controller.classes.get(componentName);
|
|
132
|
+
const componentInstance = new ComponentClass(props);
|
|
133
|
+
|
|
134
|
+
if (componentIds.id && isVisual) componentInstance.id = componentIds.id;
|
|
135
|
+
if (componentIds.sliceId) componentInstance.sliceId = componentIds.sliceId;
|
|
136
|
+
|
|
137
|
+
if (!this.controller.verifyComponentIds(componentInstance)) {
|
|
138
|
+
this.logger.logError('Slice', `Error registering instance ${componentName} ${componentInstance.sliceId}`);
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (componentInstance.init) await componentInstance.init();
|
|
143
|
+
|
|
144
|
+
if (slice.debuggerConfig.enabled && isVisual) {
|
|
145
|
+
this.debugger.attachDebugMode(componentInstance);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
this.controller.registerComponent(componentInstance);
|
|
149
|
+
if (isVisual) {
|
|
150
|
+
this.controller.registerComponentsRecursively(componentInstance);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this.logger.logInfo('Slice', `Instance ${componentInstance.sliceId} created`);
|
|
154
|
+
return componentInstance;
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.log(error);
|
|
157
|
+
this.logger.logError('Slice', `Error creating instance ${componentName}`, error);
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async setTheme(themeName) {
|
|
163
|
+
await this.stylesManager.themeManager.applyTheme(themeName);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
get theme() {
|
|
167
|
+
return this.stylesManager.themeManager.currentTheme;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
attachTemplate(componentInstance) {
|
|
171
|
+
this.controller.loadTemplateToComponent(componentInstance);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function loadConfig() {
|
|
176
|
+
try {
|
|
177
|
+
const response = await fetch('/sliceConfig.json'); // š¹ Express lo sirve desde `src/`
|
|
178
|
+
if (!response.ok) throw new Error('Error loading sliceConfig.json');
|
|
179
|
+
const json = await response.json();
|
|
180
|
+
console.log(json);
|
|
181
|
+
return json;
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.error(`Error loading config file: ${error.message}`);
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async function init() {
|
|
189
|
+
const sliceConfig = await loadConfig();
|
|
190
|
+
if (!sliceConfig) {
|
|
191
|
+
//Display error message in console with colors and alert in english
|
|
192
|
+
console.error('%cāļø Error loading Slice configuration āļø', 'color: red; font-size: 20px;');
|
|
193
|
+
alert('Error loading Slice configuration');
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
window.slice = new Slice(sliceConfig);
|
|
198
|
+
|
|
199
|
+
slice.paths.structuralComponentFolderPath = '/Slice/Components/Structural';
|
|
200
|
+
|
|
201
|
+
if (sliceConfig.logger.enabled) {
|
|
202
|
+
const LoggerModule = await window.slice.getClass(`${slice.paths.structuralComponentFolderPath}/Logger/Logger.js`);
|
|
203
|
+
window.slice.logger = new LoggerModule();
|
|
204
|
+
} else {
|
|
205
|
+
window.slice.logger = {
|
|
206
|
+
logError: () => {},
|
|
207
|
+
logWarning: () => {},
|
|
208
|
+
logInfo: () => {},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (sliceConfig.debugger.enabled) {
|
|
213
|
+
const DebuggerModule = await window.slice.getClass(
|
|
214
|
+
`${slice.paths.structuralComponentFolderPath}/Debugger/Debugger.js`
|
|
215
|
+
);
|
|
216
|
+
window.slice.debugger = new DebuggerModule();
|
|
217
|
+
await window.slice.debugger.enableDebugMode();
|
|
218
|
+
document.body.appendChild(window.slice.debugger);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (sliceConfig.events?.enabled) {
|
|
222
|
+
const EventManagerModule = await window.slice.getClass(
|
|
223
|
+
`${slice.paths.structuralComponentFolderPath}/EventManager/EventManager.js`
|
|
224
|
+
);
|
|
225
|
+
window.slice.events = new EventManagerModule();
|
|
226
|
+
if (typeof window.slice.events.init === 'function') {
|
|
227
|
+
await window.slice.events.init();
|
|
228
|
+
}
|
|
229
|
+
window.slice.logger.logError('Slice', 'EventManager enabled');
|
|
230
|
+
} else {
|
|
231
|
+
window.slice.events = {
|
|
232
|
+
subscribe: () => null,
|
|
233
|
+
subscribeOnce: () => null,
|
|
234
|
+
unsubscribe: () => false,
|
|
235
|
+
emit: () => {},
|
|
236
|
+
bind: () => ({
|
|
237
|
+
subscribe: () => null,
|
|
238
|
+
subscribeOnce: () => null,
|
|
239
|
+
emit: () => {},
|
|
240
|
+
}),
|
|
241
|
+
cleanupComponent: () => 0,
|
|
242
|
+
hasSubscribers: () => false,
|
|
243
|
+
subscriberCount: () => 0,
|
|
244
|
+
clear: () => {},
|
|
245
|
+
};
|
|
246
|
+
window.slice.logger.logError('Slice', 'EventManager disabled');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (sliceConfig.context?.enabled) {
|
|
250
|
+
const ContextManagerModule = await window.slice.getClass(
|
|
251
|
+
`${slice.paths.structuralComponentFolderPath}/ContextManager/ContextManager.js`
|
|
252
|
+
);
|
|
253
|
+
window.slice.context = new ContextManagerModule();
|
|
254
|
+
if (typeof window.slice.context.init === 'function') {
|
|
255
|
+
await window.slice.context.init();
|
|
256
|
+
}
|
|
257
|
+
window.slice.logger.logError('Slice', 'ContextManager enabled');
|
|
258
|
+
} else {
|
|
259
|
+
window.slice.context = {
|
|
260
|
+
create: () => false,
|
|
261
|
+
getState: () => null,
|
|
262
|
+
setState: () => {},
|
|
263
|
+
watch: () => null,
|
|
264
|
+
has: () => false,
|
|
265
|
+
destroy: () => false,
|
|
266
|
+
list: () => [],
|
|
267
|
+
};
|
|
268
|
+
window.slice.logger.logError('Slice', 'ContextManager disabled');
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (sliceConfig.loading.enabled) {
|
|
272
|
+
const loading = await window.slice.build('Loading', {});
|
|
273
|
+
window.slice.loading = loading;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
await window.slice.stylesManager.init();
|
|
277
|
+
|
|
278
|
+
const routesModule = await import(slice.paths.routesFile);
|
|
279
|
+
const routes = routesModule.default;
|
|
280
|
+
const RouterModule = await window.slice.getClass(`${slice.paths.structuralComponentFolderPath}/Router/Router.js`);
|
|
281
|
+
window.slice.router = new RouterModule(routes);
|
|
282
|
+
await window.slice.router.init();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
await init();
|
|
286
|
+
|
|
287
|
+
// Initialize bundles if available
|
|
288
|
+
try {
|
|
289
|
+
const { initializeBundles } = await import('/bundles/bundle.config.js');
|
|
290
|
+
if (initializeBundles) {
|
|
291
|
+
await initializeBundles(window.slice);
|
|
292
|
+
console.log('š¦ Bundles initialized automatically');
|
|
293
|
+
}
|
|
294
|
+
} catch (error) {
|
|
295
|
+
// Bundles not available, continue with individual component loading
|
|
296
|
+
console.log('š Using individual component loading (no bundles found)');
|
|
297
|
+
}
|
package/opencode.json
ADDED