onelaraveljs 1.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.
- package/README.md +87 -0
- package/docs/integration_analysis.md +116 -0
- package/docs/onejs_analysis.md +108 -0
- package/docs/optimization_implementation_group2.md +458 -0
- package/docs/optimization_plan.md +130 -0
- package/index.js +16 -0
- package/package.json +13 -0
- package/src/app.js +61 -0
- package/src/core/API.js +72 -0
- package/src/core/ChildrenRegistry.js +410 -0
- package/src/core/DOMBatcher.js +207 -0
- package/src/core/ErrorBoundary.js +226 -0
- package/src/core/EventDelegator.js +416 -0
- package/src/core/Helper.js +817 -0
- package/src/core/LoopContext.js +97 -0
- package/src/core/OneDOM.js +246 -0
- package/src/core/OneMarkup.js +444 -0
- package/src/core/Router.js +996 -0
- package/src/core/SEOConfig.js +321 -0
- package/src/core/SectionEngine.js +75 -0
- package/src/core/TemplateEngine.js +83 -0
- package/src/core/View.js +273 -0
- package/src/core/ViewConfig.js +229 -0
- package/src/core/ViewController.js +1410 -0
- package/src/core/ViewControllerOptimized.js +164 -0
- package/src/core/ViewIdentifier.js +361 -0
- package/src/core/ViewLoader.js +272 -0
- package/src/core/ViewManager.js +1962 -0
- package/src/core/ViewState.js +761 -0
- package/src/core/ViewSystem.js +301 -0
- package/src/core/ViewTemplate.js +4 -0
- package/src/core/helpers/BindingHelper.js +239 -0
- package/src/core/helpers/ConfigHelper.js +37 -0
- package/src/core/helpers/EventHelper.js +172 -0
- package/src/core/helpers/LifecycleHelper.js +17 -0
- package/src/core/helpers/ReactiveHelper.js +169 -0
- package/src/core/helpers/RenderHelper.js +15 -0
- package/src/core/helpers/ResourceHelper.js +89 -0
- package/src/core/helpers/TemplateHelper.js +11 -0
- package/src/core/managers/BindingManager.js +671 -0
- package/src/core/managers/ConfigurationManager.js +136 -0
- package/src/core/managers/EventManager.js +309 -0
- package/src/core/managers/LifecycleManager.js +356 -0
- package/src/core/managers/ReactiveManager.js +334 -0
- package/src/core/managers/RenderEngine.js +292 -0
- package/src/core/managers/ResourceManager.js +441 -0
- package/src/core/managers/ViewHierarchyManager.js +258 -0
- package/src/core/managers/ViewTemplateManager.js +127 -0
- package/src/core/reactive/ReactiveComponent.js +592 -0
- package/src/core/services/EventService.js +418 -0
- package/src/core/services/HttpService.js +106 -0
- package/src/core/services/LoggerService.js +57 -0
- package/src/core/services/StateService.js +512 -0
- package/src/core/services/StorageService.js +856 -0
- package/src/core/services/StoreService.js +258 -0
- package/src/core/services/TemplateDetectorService.js +361 -0
- package/src/core/services/Test.js +18 -0
- package/src/helpers/devWarnings.js +205 -0
- package/src/helpers/performance.js +226 -0
- package/src/helpers/utils.js +287 -0
- package/src/init.js +343 -0
- package/src/plugins/auto-plugin.js +34 -0
- package/src/services/Test.js +18 -0
- package/src/types/index.js +193 -0
- package/src/utils/date-helper.js +51 -0
- package/src/utils/helpers.js +39 -0
- package/src/utils/validation.js +32 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfigurationManager - Manages view configuration, data, and property definitions
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Process defined properties and methods from config
|
|
6
|
+
* - Commit constructor data
|
|
7
|
+
* - Update view data and variables
|
|
8
|
+
* - Handle userDefined properties
|
|
9
|
+
*
|
|
10
|
+
* Extracted from ViewController.js (Phase 9) to reduce complexity
|
|
11
|
+
* @author GitHub Copilot
|
|
12
|
+
* @date 2025-12-29
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { __defineProps, __defineMethods, hasData } from '../../helpers/utils.js';
|
|
16
|
+
import { FORBIDDEN_KEYS } from '../ViewConfig.js';
|
|
17
|
+
|
|
18
|
+
export class ConfigurationManager {
|
|
19
|
+
/**
|
|
20
|
+
* @param {ViewController} controller - Parent controller instance
|
|
21
|
+
*/
|
|
22
|
+
constructor(controller) {
|
|
23
|
+
this.controller = controller;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Process defined properties and methods from config
|
|
28
|
+
* Extracts properties and methods from config.__props__ and userDefined
|
|
29
|
+
* Binds methods to controller context
|
|
30
|
+
*
|
|
31
|
+
* @param {Object} config - View configuration
|
|
32
|
+
*/
|
|
33
|
+
processDefinedProperties(config) {
|
|
34
|
+
let definedProps = {};
|
|
35
|
+
let definedMethods = {};
|
|
36
|
+
|
|
37
|
+
// Process config.__props__
|
|
38
|
+
if (config.__props__ && config.__props__.length > 0) {
|
|
39
|
+
config.__props__.forEach(prop => {
|
|
40
|
+
if (typeof config[prop] === 'function') {
|
|
41
|
+
definedMethods[prop] = config[prop].bind(this.controller);
|
|
42
|
+
}
|
|
43
|
+
else if (typeof config[prop] !== 'undefined') {
|
|
44
|
+
definedProps[prop] = config[prop];
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Define properties and methods on controller
|
|
50
|
+
__defineProps(this.controller, definedProps, {
|
|
51
|
+
writable: true,
|
|
52
|
+
configurable: true,
|
|
53
|
+
enumerable: true,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
__defineMethods(this.controller, definedMethods);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Commit constructor data to view
|
|
61
|
+
* Updates variable data and calls commitConstructorData callback
|
|
62
|
+
*/
|
|
63
|
+
commitConstructorData() {
|
|
64
|
+
if (this.controller.isCommitedConstructorData) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (hasData(this.controller.data) && typeof this.controller.config.updateVariableData === 'function') {
|
|
69
|
+
this.controller.config.updateVariableData.apply(this.controller, [
|
|
70
|
+
{ ...this.controller.App.View.data, ...this.controller.data }
|
|
71
|
+
]);
|
|
72
|
+
this.controller.isCommitedConstructorData = true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (typeof this.controller.config.commitConstructorData === 'function') {
|
|
76
|
+
this.controller.config.commitConstructorData.apply(this.controller, []);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Update view data
|
|
82
|
+
* Merges new data into existing data
|
|
83
|
+
*
|
|
84
|
+
* @param {Object} __data - New data to merge
|
|
85
|
+
* @returns {ViewController} Controller instance for chaining
|
|
86
|
+
*/
|
|
87
|
+
updateData(__data = {}) {
|
|
88
|
+
this.controller.data = { ...this.controller.data, ...__data };
|
|
89
|
+
return this.controller;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Update variable data via config callback
|
|
94
|
+
*
|
|
95
|
+
* @param {Object} data - Variable data to update
|
|
96
|
+
* @returns {ViewController} Controller instance for chaining
|
|
97
|
+
*/
|
|
98
|
+
updateVariableData(data = {}) {
|
|
99
|
+
if (typeof this.controller.config.updateVariableData === 'function') {
|
|
100
|
+
this.controller.config.updateVariableData.call(this.controller, data);
|
|
101
|
+
this.controller.isCommitedConstructorData = true;
|
|
102
|
+
}
|
|
103
|
+
return this.controller;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Update single variable item via config callback
|
|
108
|
+
*
|
|
109
|
+
* @param {string} key - Variable key
|
|
110
|
+
* @param {*} value - Variable value
|
|
111
|
+
* @returns {ViewController} Controller instance for chaining
|
|
112
|
+
*/
|
|
113
|
+
updateVariableItem(key, value) {
|
|
114
|
+
if (typeof this.controller.config.updateVariableItemData === 'function') {
|
|
115
|
+
this.controller.config.updateVariableItemData.call(this.controller, key, value);
|
|
116
|
+
}
|
|
117
|
+
return this.controller;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Set scope for the view
|
|
122
|
+
*
|
|
123
|
+
* @param {Object} scope - Scope object containing name, id, index, etc.
|
|
124
|
+
*/
|
|
125
|
+
setScope(scope) {
|
|
126
|
+
this.controller.__scope = scope;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
get App() {
|
|
130
|
+
return this.controller.App;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
set App(value) {
|
|
134
|
+
devLog('ConfigurationManager.App is read-only.');
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventManager - Quản lý tất cả chức năng liên quan đến events cho ViewController
|
|
3
|
+
*
|
|
4
|
+
* Trách nhiệm:
|
|
5
|
+
* - Khởi động/dừng event listeners
|
|
6
|
+
* - Parse event handlers và parameters
|
|
7
|
+
* - Dọn dẹp orphaned event data
|
|
8
|
+
* - Phân giải event handler (view methods, controller methods, window functions, etc.)
|
|
9
|
+
*
|
|
10
|
+
* Sử dụng EventDelegator để tối ưu hiệu suất:
|
|
11
|
+
* - Giảm số lượng listeners từ O(n) xuống O(1) mỗi event type
|
|
12
|
+
* - Tự động hỗ trợ dynamic content
|
|
13
|
+
* - Giảm memory footprint
|
|
14
|
+
*
|
|
15
|
+
* Extracted from ViewController.js to improve separation of concerns
|
|
16
|
+
* @module core/managers/EventManager
|
|
17
|
+
* @author OneLaravel Team
|
|
18
|
+
* @since 2025-12-29
|
|
19
|
+
* @updated 2025-01-06 - Integrated EventDelegator
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import logger from '../services/LoggerService.js';
|
|
23
|
+
import EventDelegator from '../EventDelegator.js';
|
|
24
|
+
|
|
25
|
+
export class EventManager {
|
|
26
|
+
constructor(controller) {
|
|
27
|
+
this.controller = controller;
|
|
28
|
+
this.view = controller.view;
|
|
29
|
+
this.path = controller.path;
|
|
30
|
+
this.id = controller.id;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Track delegated event unsubscribers
|
|
34
|
+
* @type {Map<string, Function>}
|
|
35
|
+
*/
|
|
36
|
+
this.delegatedUnsubscribers = new Map();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
updateController(newController) {
|
|
40
|
+
this.controller = newController;
|
|
41
|
+
this.view = newController.view;
|
|
42
|
+
this.path = newController.path;
|
|
43
|
+
this.id = newController.id;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Khởi động event listeners cho tất cả registered events
|
|
48
|
+
* Sử dụng event delegation thay vì attach listener riêng cho từng element
|
|
49
|
+
*
|
|
50
|
+
* Cải tiến hiệu suất:
|
|
51
|
+
* - Trước: O(n) listeners (mỗi element một listener)
|
|
52
|
+
* - Sau: O(1) listeners (một listener cho mỗi event type)
|
|
53
|
+
* - Tự động hỗ trợ dynamic content (ReactiveComponent updates)
|
|
54
|
+
* - Giảm memory usage đáng kể
|
|
55
|
+
*/
|
|
56
|
+
startEventListener() {
|
|
57
|
+
const needDeleted = [];
|
|
58
|
+
|
|
59
|
+
Object.entries(this.controller.events).forEach(([eventType, eventMap]) => {
|
|
60
|
+
Object.entries(eventMap).forEach(([eventID, handlers]) => {
|
|
61
|
+
const selector = `[data-${eventType}-id="${eventID}"]`;
|
|
62
|
+
const elements = document.querySelectorAll(selector);
|
|
63
|
+
const parsedHandlers = this.parseEventHandlerFunctions(handlers);
|
|
64
|
+
|
|
65
|
+
if (parsedHandlers.length !== 0 && elements.length > 0) {
|
|
66
|
+
// Tạo unique key cho delegated handler
|
|
67
|
+
const delegateKey = `${eventType}:${eventID}:${this.id}`;
|
|
68
|
+
|
|
69
|
+
// Unsubscribe nếu đã tồn tại (prevent duplicates)
|
|
70
|
+
if (this.delegatedUnsubscribers.has(delegateKey)) {
|
|
71
|
+
this.delegatedUnsubscribers.get(delegateKey)();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Sử dụng EventDelegator để attach delegated listener
|
|
75
|
+
const unsubscribe = EventDelegator.on(eventType, selector, (event) => {
|
|
76
|
+
let returnValue = null;
|
|
77
|
+
for (let i = 0; i < parsedHandlers.length; i++) {
|
|
78
|
+
const handlerFn = parsedHandlers[i];
|
|
79
|
+
try {
|
|
80
|
+
returnValue = handlerFn(event);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.error('[EventManager] Handler execution error:', error, {
|
|
83
|
+
eventType,
|
|
84
|
+
selector,
|
|
85
|
+
handlerIndex: i,
|
|
86
|
+
event: event.type
|
|
87
|
+
});
|
|
88
|
+
throw error; // Re-throw để EventDelegator catch
|
|
89
|
+
}
|
|
90
|
+
if (returnValue === false || event.defaultPrevented) {
|
|
91
|
+
event.preventDefault();
|
|
92
|
+
event.stopPropagation();
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (returnValue === false || returnValue === true) {
|
|
97
|
+
return returnValue;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Lưu unsubscriber để cleanup sau này
|
|
102
|
+
this.delegatedUnsubscribers.set(delegateKey, unsubscribe);
|
|
103
|
+
} else {
|
|
104
|
+
needDeleted.push({ eventType, eventID });
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
needDeleted.forEach(({ eventType, eventID }) => {
|
|
109
|
+
delete this.controller.events[eventType][eventID];
|
|
110
|
+
// If no more event handlers for this eventType, remove the entire eventType
|
|
111
|
+
if (Object.keys(this.controller.events[eventType]).length === 0) {
|
|
112
|
+
delete this.controller.events[eventType];
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
this.controller.eventListenerStatus = true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Dừng tất cả event listeners
|
|
120
|
+
* Gỡ bỏ tất cả delegated event listeners và clear tracking structures
|
|
121
|
+
*
|
|
122
|
+
* Với event delegation:
|
|
123
|
+
* - Không cần loop qua từng element
|
|
124
|
+
* - Chỉ cần unsubscribe delegated handlers
|
|
125
|
+
* - Nhanh hơn và đơn giản hơn
|
|
126
|
+
*/
|
|
127
|
+
stopEventListener() {
|
|
128
|
+
// Unsubscribe tất cả delegated handlers
|
|
129
|
+
this.delegatedUnsubscribers.forEach(unsubscribe => {
|
|
130
|
+
unsubscribe();
|
|
131
|
+
});
|
|
132
|
+
this.delegatedUnsubscribers.clear();
|
|
133
|
+
|
|
134
|
+
// Keep backward compatibility: clean up old individual listeners (nếu có)
|
|
135
|
+
if (this.controller.eventListeners && this.controller.eventListeners.length > 0) {
|
|
136
|
+
this.controller.eventListeners.forEach(({ element, eventType, handler }) => {
|
|
137
|
+
element.removeEventListener(eventType, handler);
|
|
138
|
+
});
|
|
139
|
+
this.controller.eventListeners = [];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
this.controller.eventListenerStatus = false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Clear all event data when elements are not found
|
|
147
|
+
* This helps prevent memory leaks from orphaned event handlers
|
|
148
|
+
*/
|
|
149
|
+
clearOrphanedEventData() {
|
|
150
|
+
const needDeleted = [];
|
|
151
|
+
Object.entries(this.controller.events).forEach(([eventType, eventMap]) => {
|
|
152
|
+
Object.entries(eventMap).forEach(([eventID, handlers]) => {
|
|
153
|
+
const selector = `[data-${eventType}-id="${eventID}"]`;
|
|
154
|
+
const elements = document.querySelectorAll(selector);
|
|
155
|
+
if (elements.length === 0) {
|
|
156
|
+
needDeleted.push({ eventType, eventID });
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
needDeleted.forEach(({ eventType, eventID }) => {
|
|
162
|
+
delete this.controller.events[eventType][eventID];
|
|
163
|
+
// If no more event handlers for this eventType, remove the entire eventType
|
|
164
|
+
if (Object.keys(this.controller.events[eventType]).length === 0) {
|
|
165
|
+
delete this.controller.events[eventType];
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
if (needDeleted.length > 0) {
|
|
170
|
+
logger.log(`🗑️ ViewEngine.clearOrphanedEventData: Cleaned up ${needDeleted.length} orphaned event handlers`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Parse event handler functions from handler objects
|
|
176
|
+
* @param {Array} handlers - Array of handler objects or functions
|
|
177
|
+
* @returns {Array} Array of parsed handler functions
|
|
178
|
+
*/
|
|
179
|
+
parseEventHandlerFunctions(handlers) {
|
|
180
|
+
let parsedHandlers = [];
|
|
181
|
+
handlers.forEach(handlerObj => {
|
|
182
|
+
const handlerName = typeof handlerObj == "function" ? handlerObj : handlerObj.handler;
|
|
183
|
+
const params = typeof handlerObj == "function" ? [] : handlerObj.params || [];
|
|
184
|
+
const func = this.parseHandlerFunction(handlerName);
|
|
185
|
+
const fn = (event) => func(...this.parseEventHandlerParams(event, params));
|
|
186
|
+
parsedHandlers.push(fn);
|
|
187
|
+
});
|
|
188
|
+
return parsedHandlers;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Parse handler function
|
|
193
|
+
* @param {string|Function} funcName - Function name or function
|
|
194
|
+
* @returns {Function} Parsed function bound to correct context
|
|
195
|
+
*/
|
|
196
|
+
parseHandlerFunction(funcName) {
|
|
197
|
+
if (!(typeof funcName === 'string' || typeof funcName === 'function')) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Handle function directly passed
|
|
202
|
+
if (typeof funcName === 'function') {
|
|
203
|
+
// Always bind to view to maintain context
|
|
204
|
+
return funcName.bind(this.view);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Handle function name as string - check in order: view, controller, setters, data, window
|
|
208
|
+
|
|
209
|
+
// Check in view
|
|
210
|
+
if (typeof this.view[funcName] === 'function') {
|
|
211
|
+
return this.view[funcName].bind(this.view);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Check in controller
|
|
215
|
+
if (typeof this.controller[funcName] === 'function') {
|
|
216
|
+
return this.controller[funcName].bind(this.controller);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Check in states setters
|
|
220
|
+
if (typeof this.controller.states.__.setters[funcName] === 'function') {
|
|
221
|
+
return this.controller.states.__.setters[funcName].bind(this.view);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Check in data
|
|
225
|
+
if (typeof this.controller.data[funcName] === 'function') {
|
|
226
|
+
return this.controller.data[funcName].bind(this.controller.data);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Check in window (global functions)
|
|
230
|
+
if (window && typeof window[funcName] === 'function') {
|
|
231
|
+
return window[funcName].bind(window);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Function not found
|
|
235
|
+
return (event) => logger.warn(`⚠️ Event handler ${funcName} is not defined`, event);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Parse event handler parameters
|
|
240
|
+
* @param {Event} event - DOM event object
|
|
241
|
+
* @param {Array} params - Array of parameter definitions
|
|
242
|
+
* @returns {Array} Parsed parameters
|
|
243
|
+
*/
|
|
244
|
+
parseEventHandlerParams(event, params = []) {
|
|
245
|
+
return params.map(param => {
|
|
246
|
+
if (param === '@EVENT') {
|
|
247
|
+
return event;
|
|
248
|
+
}
|
|
249
|
+
else if (typeof param === 'object' && param !== null) {
|
|
250
|
+
if (typeof param.handler === 'string' && (Array.isArray(param.params) || (typeof param.params == 'object' && param.params !== null && param.params.constructor === Array))) {
|
|
251
|
+
const func = this.parseHandlerFunction(param.handler);
|
|
252
|
+
return func(...this.parseEventHandlerParams(event, param.params));
|
|
253
|
+
}
|
|
254
|
+
return this.parseEventHandlerObject(event, param);
|
|
255
|
+
}
|
|
256
|
+
else if (Array.isArray(param) || (typeof param === 'object' && param !== null && param.constructor === Array)) {
|
|
257
|
+
return this.parseEventHandlerParams(event, param);
|
|
258
|
+
}
|
|
259
|
+
else if (typeof param === 'function') {
|
|
260
|
+
// Bind function to view context before calling
|
|
261
|
+
const boundFunc = param.bind(this.view);
|
|
262
|
+
return boundFunc(event);
|
|
263
|
+
}
|
|
264
|
+
return param;
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Parse event handler object parameters
|
|
270
|
+
* @param {Event} event - DOM event object
|
|
271
|
+
* @param {Object} object - Object with parameter definitions
|
|
272
|
+
* @returns {Object} Parsed object with evaluated parameters
|
|
273
|
+
*/
|
|
274
|
+
parseEventHandlerObject(event, object = {}) {
|
|
275
|
+
let parsedObject = {};
|
|
276
|
+
Object.entries(object).forEach(([key, value]) => {
|
|
277
|
+
if (value === '@EVENT') {
|
|
278
|
+
parsedObject[key] = event;
|
|
279
|
+
}
|
|
280
|
+
else if (typeof value === 'object' && value !== null) {
|
|
281
|
+
if (typeof value.handler === 'string' && (Array.isArray(value.params) || (typeof value.params == 'object' && value.params !== null && value.params.constructor === Array))) {
|
|
282
|
+
const func = this.parseHandlerFunction(value.handler);
|
|
283
|
+
parsedObject[key] = func(...this.parseEventHandlerParams(event, value.params));
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
parsedObject[key] = this.parseEventHandlerObject(event, value);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
else if (Array.isArray(value) || (typeof value === 'object' && value !== null && value.constructor === Array)) {
|
|
290
|
+
parsedObject[key] = this.parseEventHandlerParams(event, value);
|
|
291
|
+
}
|
|
292
|
+
else if (typeof value === 'function') {
|
|
293
|
+
parsedObject[key] = value(event);
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
parsedObject[key] = value;
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
return parsedObject;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
get App() {
|
|
303
|
+
return this.controller.App;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
set App(value) {
|
|
307
|
+
devLog('EventManager.App is read-only.');
|
|
308
|
+
}
|
|
309
|
+
}
|