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
package/src/init.js
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* init Module
|
|
3
|
+
* ES6 Module for Blade Compiler
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// import { App } from './app.js';
|
|
7
|
+
|
|
8
|
+
function initApp(App) {
|
|
9
|
+
App = App || window.App;
|
|
10
|
+
|
|
11
|
+
// Check if APP_CONFIGS is available
|
|
12
|
+
if (typeof window.APP_CONFIGS === 'undefined') {
|
|
13
|
+
console.error('APP_CONFIGS not found! Please define window.APP_CONFIGS in your HTML.');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
console.log('✅ APP_CONFIGS found:', window.APP_CONFIGS);
|
|
18
|
+
|
|
19
|
+
const config = window.APP_CONFIGS;
|
|
20
|
+
|
|
21
|
+
// Validate required App modules
|
|
22
|
+
if (typeof App === 'undefined') {
|
|
23
|
+
console.error('App core module not found! Please ensure app.main.js is loaded.');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Validate config structure
|
|
28
|
+
if (!config || typeof config !== 'object') {
|
|
29
|
+
console.error('Invalid APP_CONFIGS! Config must be an object.');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Initialize view container first
|
|
34
|
+
const container = config.container ? (
|
|
35
|
+
typeof config.container === 'string' ? (
|
|
36
|
+
document.querySelector(config.container) || document.body
|
|
37
|
+
) : (config.container instanceof HTMLElement ? config.container : document.body)
|
|
38
|
+
) : document.body;
|
|
39
|
+
if (container) {
|
|
40
|
+
App.View.setContainer(container);
|
|
41
|
+
} else {
|
|
42
|
+
console.warn('⚠️ No container specified and no default container found');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const isServerRendered = container.getAttribute('data-server-rendered') === 'true';
|
|
46
|
+
|
|
47
|
+
App.env = {...App.env, ...config.env};
|
|
48
|
+
|
|
49
|
+
if (App.View) {
|
|
50
|
+
// If server-rendered, ensure view container is properly hydrated
|
|
51
|
+
if (isServerRendered) {
|
|
52
|
+
// Mark container as hydrated without re-rendering content
|
|
53
|
+
App.View._isHydrated = true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Initialize View configuration
|
|
57
|
+
if (App.View && config.view) {
|
|
58
|
+
App.View.init(config.view);
|
|
59
|
+
} else if (config.view) {
|
|
60
|
+
console.warn('⚠️ View configuration provided but App.View not found');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Initialize API configuration
|
|
66
|
+
if (config.api && App.Http) {
|
|
67
|
+
if (config.api.baseUrl) {
|
|
68
|
+
App.Http.setBaseUrl(config.api.baseUrl);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Set default headers including CSRF token
|
|
72
|
+
const defaultHeaders = {
|
|
73
|
+
'Content-Type': 'application/json',
|
|
74
|
+
'X-Requested-With': 'XMLHttpRequest'
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
if (config.api.csrfToken) {
|
|
78
|
+
defaultHeaders['X-CSRF-TOKEN'] = config.api.csrfToken;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
App.Http.setDefaultHeaders(defaultHeaders);
|
|
82
|
+
App.Http.setTimeout(config.api.timeout || 10000);
|
|
83
|
+
|
|
84
|
+
} else if (config.api) {
|
|
85
|
+
console.warn('⚠️ API configuration provided but AppInstance.HttpService not found');
|
|
86
|
+
} else {
|
|
87
|
+
console.warn('⚠️ No API configuration provided');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Initialize router configuration
|
|
91
|
+
if (App.Router) {
|
|
92
|
+
if (config.router.allRoutes) {
|
|
93
|
+
App.Router.setAllRoutes(config.router.allRoutes);
|
|
94
|
+
}
|
|
95
|
+
// Get routes from router config or fallback to top-level routes
|
|
96
|
+
let routes = config.router?.routes || config.routes;
|
|
97
|
+
if (!routes || !Array.isArray(routes) || routes.length === 0) {
|
|
98
|
+
const scope = config.appScope || 'web';
|
|
99
|
+
routes = [
|
|
100
|
+
{ path: `/${scope}`, view: `${scope}.home` },
|
|
101
|
+
{ path: `/${scope}/about`, view: `${scope}.about` },
|
|
102
|
+
{ path: `/${scope}/users`, view: `${scope}.users` },
|
|
103
|
+
{ path: `/${scope}/users/:id`, view: `${scope}.user-detail` },
|
|
104
|
+
{ path: `/${scope}/contact`, view: `${scope}.contact` }
|
|
105
|
+
];
|
|
106
|
+
} else {
|
|
107
|
+
console.log('🔧 Using provided routes:', routes.length);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Register routes
|
|
111
|
+
routes.forEach(route => {
|
|
112
|
+
if (route.path && (route.view || route.component)) {
|
|
113
|
+
const viewName = route.view || route.component;
|
|
114
|
+
App.Router.addRoute(route.path, viewName, route.options || {});
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Configure router options
|
|
119
|
+
if (config.router) {
|
|
120
|
+
if (config.router.mode) {
|
|
121
|
+
App.Router.setMode(config.router.mode);
|
|
122
|
+
}
|
|
123
|
+
if (config.router.base) {
|
|
124
|
+
App.Router.setBase(config.router.base);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Setup default router hooks if not provided
|
|
128
|
+
if (!config.router.beforeEach) {
|
|
129
|
+
App.Router.beforeEach(function(to, from) {
|
|
130
|
+
if (App.mode === 'development') {
|
|
131
|
+
console.log('Navigating to:', to.path);
|
|
132
|
+
}
|
|
133
|
+
return true;
|
|
134
|
+
});
|
|
135
|
+
} else {
|
|
136
|
+
App.Router.beforeEach(config.router.beforeEach);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (!config.router.afterEach) {
|
|
140
|
+
App.Router.afterEach(function(to, from) {
|
|
141
|
+
if (App.mode === 'development') {
|
|
142
|
+
console.log('Navigation complete:', to.path || to);
|
|
143
|
+
}
|
|
144
|
+
// to.path should be set from Router, fallback to window.location.pathname
|
|
145
|
+
const path = to.path || window.location.pathname;
|
|
146
|
+
updateActiveNav(path);
|
|
147
|
+
});
|
|
148
|
+
} else {
|
|
149
|
+
App.Router.afterEach(function(to, from) {
|
|
150
|
+
// Call custom afterEach if provided
|
|
151
|
+
if (typeof config.router.afterEach === 'function') {
|
|
152
|
+
config.router.afterEach(to, from);
|
|
153
|
+
}
|
|
154
|
+
// Always update navigation
|
|
155
|
+
// to.path should be set from Router, fallback to window.location.pathname
|
|
156
|
+
const path = to.path || window.location.pathname;
|
|
157
|
+
updateActiveNav(path);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
console.log('✅ Router configuration applied');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Set default route
|
|
164
|
+
const defaultRoute = config.defaultRoute || `/${config.appScope || 'web'}`;
|
|
165
|
+
App.Router.setDefaultRoute(defaultRoute);
|
|
166
|
+
|
|
167
|
+
if (isServerRendered) {
|
|
168
|
+
// Start router but don't handle initial route
|
|
169
|
+
App.Router.start(true); // Pass true to skip initial route handling
|
|
170
|
+
|
|
171
|
+
// Mark as client-side ready after a short delay
|
|
172
|
+
setTimeout(() => {
|
|
173
|
+
if (container) {
|
|
174
|
+
container.setAttribute('data-server-rendered', 'false');
|
|
175
|
+
}
|
|
176
|
+
}, 100);
|
|
177
|
+
} else {
|
|
178
|
+
// Start the router normally
|
|
179
|
+
App.Router.start();
|
|
180
|
+
console.log('✅ Router started');
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
console.warn('⚠️ Router not available - AppInstance.Router not found');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if(config.view){
|
|
187
|
+
if(config.view.superView){
|
|
188
|
+
App.View.setSuperViewPath(config.view.superView);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Initialize system data
|
|
192
|
+
// Initialize mode (development/production)
|
|
193
|
+
if (config.mode) {
|
|
194
|
+
App.mode = config.mode;
|
|
195
|
+
|
|
196
|
+
// Enable/disable debug logging based on mode
|
|
197
|
+
if (config.mode === 'development') {
|
|
198
|
+
console.log('🔧 Development mode enabled - debug logging active');
|
|
199
|
+
} else {
|
|
200
|
+
console.log('🏭 Production mode enabled');
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
// Set default mode
|
|
204
|
+
App.mode = 'development';
|
|
205
|
+
console.warn('⚠️ No mode specified in config, using default: development');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Initialize global data
|
|
209
|
+
App.globalData = {
|
|
210
|
+
siteName: 'One App',
|
|
211
|
+
version: '1.0.0',
|
|
212
|
+
csrfToken: config.api?.csrfToken,
|
|
213
|
+
appScope: config.appScope,
|
|
214
|
+
currentUser: config.currentUser,
|
|
215
|
+
...(config.data || {})
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// Initialize language configuration
|
|
219
|
+
if (config.lang) {
|
|
220
|
+
App.lang = {
|
|
221
|
+
current: config.lang.locale || 'en',
|
|
222
|
+
fallback: config.lang.fallback || 'en',
|
|
223
|
+
...config.lang
|
|
224
|
+
};
|
|
225
|
+
console.log('✅ Language configuration initialized:', App.lang);
|
|
226
|
+
} else {
|
|
227
|
+
// Set default language configuration
|
|
228
|
+
App.lang = {
|
|
229
|
+
current: 'en',
|
|
230
|
+
fallback: 'en'
|
|
231
|
+
};
|
|
232
|
+
console.warn('⚠️ No language configuration provided, using defaults');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
// Setup navigation updates
|
|
237
|
+
if (App.View) {
|
|
238
|
+
App.View.on('view:rendered', function (viewName) {
|
|
239
|
+
console.log('View rendered:', viewName);
|
|
240
|
+
updateActiveNav();
|
|
241
|
+
});
|
|
242
|
+
} else {
|
|
243
|
+
console.warn('⚠️ Navigation updates not available - App.View not found');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Custom initialization callback
|
|
247
|
+
if (config.onInit && typeof config.onInit === 'function') {
|
|
248
|
+
try {
|
|
249
|
+
config.onInit(App, config);
|
|
250
|
+
console.log('✅ Custom initialization callback executed');
|
|
251
|
+
} catch (error) {
|
|
252
|
+
console.error('❌ Error in custom initialization callback:', error);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Dispatch App ready event
|
|
257
|
+
try {
|
|
258
|
+
const appReadyEvent = new CustomEvent('app:ready', {
|
|
259
|
+
detail: { App: App, config }
|
|
260
|
+
});
|
|
261
|
+
document.dispatchEvent(appReadyEvent);
|
|
262
|
+
console.log('✅ App ready event dispatched');
|
|
263
|
+
} catch (error) {
|
|
264
|
+
console.error('❌ Error dispatching App ready event:', error);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
console.log('🎉 App initialization completed successfully!');
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Navigation helper function - updates active navigation link
|
|
271
|
+
export function updateActiveNav(currentPath) {
|
|
272
|
+
// Use provided path or current location
|
|
273
|
+
const path = currentPath || window.location.pathname;
|
|
274
|
+
|
|
275
|
+
// Find all navigation links (support multiple selectors)
|
|
276
|
+
const navLinks = document.querySelectorAll('.nav-menu a, .nav-link, nav a[data-navigate]');
|
|
277
|
+
|
|
278
|
+
navLinks.forEach(link => {
|
|
279
|
+
link.classList.remove('active');
|
|
280
|
+
|
|
281
|
+
// Check href attribute
|
|
282
|
+
const href = link.getAttribute('href');
|
|
283
|
+
// Check data-navigate attribute
|
|
284
|
+
const navigatePath = link.getAttribute('data-navigate');
|
|
285
|
+
|
|
286
|
+
// Match if href or data-navigate matches current path
|
|
287
|
+
let isActive = false;
|
|
288
|
+
|
|
289
|
+
// 1. Exact match
|
|
290
|
+
if (href === path || navigatePath === path) {
|
|
291
|
+
isActive = true;
|
|
292
|
+
}
|
|
293
|
+
// 2. Check full URL match
|
|
294
|
+
else {
|
|
295
|
+
const fullUrl = window.location.protocol + '//' + window.location.host + path;
|
|
296
|
+
if (href === fullUrl) {
|
|
297
|
+
isActive = true;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// 3. Partial/prefix match for paths with query parameters or dynamic segments
|
|
302
|
+
// e.g., /demo matches /demo/section-name
|
|
303
|
+
if (!isActive && (href || navigatePath)) {
|
|
304
|
+
const basePath = href || navigatePath;
|
|
305
|
+
// Extract base path without query string
|
|
306
|
+
const basePathWithoutQuery = basePath.split('?')[0];
|
|
307
|
+
const currentPathWithoutQuery = path.split('?')[0];
|
|
308
|
+
|
|
309
|
+
// Check if current path starts with nav link path (for routes with parameters)
|
|
310
|
+
if (basePathWithoutQuery && currentPathWithoutQuery.startsWith(basePathWithoutQuery + '/')) {
|
|
311
|
+
isActive = true;
|
|
312
|
+
}
|
|
313
|
+
// Also check exact match after removing query string
|
|
314
|
+
else if (basePathWithoutQuery === currentPathWithoutQuery) {
|
|
315
|
+
isActive = true;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (isActive) {
|
|
320
|
+
link.classList.add('active');
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Make updateActiveNav globally available for router hooks
|
|
326
|
+
if (typeof window !== 'undefined') {
|
|
327
|
+
window.updateActiveNav = updateActiveNav;
|
|
328
|
+
}
|
|
329
|
+
// try {
|
|
330
|
+
// // Make updateActiveNav globally available for router config
|
|
331
|
+
// window.updateActiveNav = updateActiveNav;
|
|
332
|
+
|
|
333
|
+
// // Initialize when DOM is ready
|
|
334
|
+
// if (document.readyState === 'loading') {
|
|
335
|
+
// document.addEventListener('DOMContentLoaded', initApp);
|
|
336
|
+
// } else {
|
|
337
|
+
// initApp();
|
|
338
|
+
// }
|
|
339
|
+
// } catch (error) {
|
|
340
|
+
// console.error('❌ Error in init:', error);
|
|
341
|
+
// }
|
|
342
|
+
|
|
343
|
+
export default initApp;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto Plugin Module
|
|
3
|
+
* This file in a subdirectory will be automatically discovered
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export class AutoPlugin {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.name = 'AutoPlugin';
|
|
9
|
+
this.type = 'plugin';
|
|
10
|
+
this.version = '1.0.0';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
initialize() {
|
|
14
|
+
console.log(`🚀 ${this.name} initialized!`);
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getInfo() {
|
|
19
|
+
return {
|
|
20
|
+
name: this.name,
|
|
21
|
+
type: this.type,
|
|
22
|
+
version: this.version,
|
|
23
|
+
timestamp: new Date().toISOString()
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Register with global App object
|
|
29
|
+
if (typeof window !== 'undefined' && window.App) {
|
|
30
|
+
window.App.AutoPlugin = AutoPlugin;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Export for ES6 modules
|
|
34
|
+
export default AutoPlugin;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test service để demo alias @app
|
|
3
|
+
*/
|
|
4
|
+
export class TestService {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'TestService';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
getMessage() {
|
|
10
|
+
return `Hello from ${this.name}!`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static create() {
|
|
14
|
+
return new TestService();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default TestService;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript-style type definitions using JSDoc
|
|
3
|
+
* This file provides type hints for better IDE support and documentation
|
|
4
|
+
*
|
|
5
|
+
* @module types/index
|
|
6
|
+
* @author OneLaravel Team
|
|
7
|
+
* @since 2025-12-29
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {Object} Application
|
|
12
|
+
* @property {string} name - Application name
|
|
13
|
+
* @property {Helper} Helper - Helper instance
|
|
14
|
+
* @property {Router} Router - Router instance
|
|
15
|
+
* @property {ViewManager} View - ViewManager instance
|
|
16
|
+
* @property {typeof HttpService} HttpService - HttpService class
|
|
17
|
+
* @property {HttpService} Http - HttpService instance
|
|
18
|
+
* @property {OneMarkup} OneMarkup - OneMarkup class
|
|
19
|
+
* @property {API} Api - API class
|
|
20
|
+
* @property {string} mode - Application mode (development/production)
|
|
21
|
+
* @property {boolean} isInitialized - Initialization status
|
|
22
|
+
* @property {AppEnvironment} env - Environment configuration
|
|
23
|
+
* @property {Function} init - Initialize application
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @typedef {Object} AppEnvironment
|
|
28
|
+
* @property {string} mode - Environment mode (web/mobile)
|
|
29
|
+
* @property {boolean} debug - Debug mode flag
|
|
30
|
+
* @property {string} base_url - Base URL
|
|
31
|
+
* @property {string} csrf_token - CSRF token
|
|
32
|
+
* @property {string} router_mode - Router mode (history/hash)
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @typedef {Object} ViewData
|
|
37
|
+
* @property {string} [__SSR_VIEW_ID__] - Server-side rendered view ID
|
|
38
|
+
* @property {*} [key: string] - Additional data properties
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @typedef {Object} SystemData
|
|
43
|
+
* @property {Application} App - Application instance
|
|
44
|
+
* @property {typeof View} View - View class
|
|
45
|
+
* @property {string} __base__ - Base path
|
|
46
|
+
* @property {string} __layout__ - Layout path
|
|
47
|
+
* @property {string} __page__ - Page path
|
|
48
|
+
* @property {string} __component__ - Component path
|
|
49
|
+
* @property {string} __template__ - Template path
|
|
50
|
+
* @property {string} __partial__ - Partial path
|
|
51
|
+
* @property {string} __system__ - System path
|
|
52
|
+
* @property {Object} __env - Environment data
|
|
53
|
+
* @property {Object} __helper - Helper functions
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @typedef {Object} ViewConfig
|
|
58
|
+
* @property {string} superView - Super view path
|
|
59
|
+
* @property {boolean} hasSuperView - Has super view flag
|
|
60
|
+
* @property {string} viewType - View type (view/layout/component)
|
|
61
|
+
* @property {Object} sections - Section definitions
|
|
62
|
+
* @property {WrapperConfig} wrapperConfig - Wrapper configuration
|
|
63
|
+
* @property {Array<string>} __props__ - Property names
|
|
64
|
+
* @property {boolean} hasAwaitData - Has await data flag
|
|
65
|
+
* @property {boolean} hasFetchData - Has fetch data flag
|
|
66
|
+
* @property {boolean} subscribe - Subscribe flag
|
|
67
|
+
* @property {Object|null} fetch - Fetch configuration
|
|
68
|
+
* @property {ViewData} data - View data
|
|
69
|
+
* @property {string} viewId - View ID
|
|
70
|
+
* @property {string} path - View path
|
|
71
|
+
* @property {boolean} usesVars - Uses vars flag
|
|
72
|
+
* @property {boolean} hasSections - Has sections flag
|
|
73
|
+
* @property {boolean} hasSectionPreload - Has section preload flag
|
|
74
|
+
* @property {boolean} hasPrerender - Has prerender flag
|
|
75
|
+
* @property {Array<string>} renderLongSections - Long sections to render
|
|
76
|
+
* @property {Array<string>} renderSections - Sections to render
|
|
77
|
+
* @property {Array<string>} prerenderSections - Sections to prerender
|
|
78
|
+
* @property {Array<ScriptResource>} scripts - Script resources
|
|
79
|
+
* @property {Array<StyleResource>} styles - Style resources
|
|
80
|
+
* @property {Array<Resource>} resources - Other resources
|
|
81
|
+
* @property {Function} commitConstructorData - Commit constructor data
|
|
82
|
+
* @property {Function} updateVariableData - Update variable data
|
|
83
|
+
* @property {Function} updateVariableItem - Update variable item
|
|
84
|
+
* @property {Function} loadServerData - Load server data
|
|
85
|
+
* @property {Function} prerender - Prerender function
|
|
86
|
+
* @property {Function} render - Render function
|
|
87
|
+
* @property {Function} init - Init function
|
|
88
|
+
* @property {Function} destroy - Destroy function
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @typedef {Object} WrapperConfig
|
|
93
|
+
* @property {boolean} enable - Enable wrapper
|
|
94
|
+
* @property {string|null} tag - Wrapper tag name
|
|
95
|
+
* @property {boolean} subscribe - Subscribe to state changes
|
|
96
|
+
* @property {Object} attributes - Wrapper attributes
|
|
97
|
+
*/
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @typedef {Object} Resource
|
|
101
|
+
* @property {string} type - Resource type (src/href/code)
|
|
102
|
+
* @property {string} resourceType - Resource type (script/style)
|
|
103
|
+
* @property {string} [src] - External resource URL
|
|
104
|
+
* @property {string} [href] - External stylesheet URL
|
|
105
|
+
* @property {string} [content] - Inline content
|
|
106
|
+
* @property {string} [function] - Function name for code type
|
|
107
|
+
* @property {string} [id] - Resource ID
|
|
108
|
+
* @property {Object} [attributes] - Additional attributes
|
|
109
|
+
*/
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @typedef {Resource} ScriptResource
|
|
113
|
+
* @property {'script'} resourceType
|
|
114
|
+
*/
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @typedef {Resource} StyleResource
|
|
118
|
+
* @property {'style'} resourceType
|
|
119
|
+
*/
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @typedef {Object} StateDefinition
|
|
123
|
+
* @property {*} value - State value
|
|
124
|
+
* @property {Function} setValue - State setter
|
|
125
|
+
* @property {string} key - State key
|
|
126
|
+
* @property {Array<Function>} subscribers - State subscribers
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @typedef {Object} EventConfig
|
|
131
|
+
* @property {string} eventType - Event type (click/input/etc)
|
|
132
|
+
* @property {Array<EventHandler>} handlers - Event handlers
|
|
133
|
+
* @property {string} eventID - Event ID
|
|
134
|
+
*/
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @typedef {Object} EventHandler
|
|
138
|
+
* @property {string|Function} handler - Handler function or name
|
|
139
|
+
* @property {Array<*>} params - Handler parameters
|
|
140
|
+
* @property {Object} options - Handler options
|
|
141
|
+
*/
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @typedef {Object} OutputComponentConfig
|
|
145
|
+
* @property {string} outputId - Output ID
|
|
146
|
+
* @property {string} stateKey - State key to watch
|
|
147
|
+
* @property {boolean} escaped - Escape HTML flag
|
|
148
|
+
* @property {HTMLElement} element - Output element
|
|
149
|
+
*/
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @typedef {Object} WatchComponentConfig
|
|
153
|
+
* @property {string} watchId - Watch ID
|
|
154
|
+
* @property {string} stateKey - State key to watch
|
|
155
|
+
* @property {Function} callback - Watch callback
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @typedef {Object} RouteConfig
|
|
160
|
+
* @property {string} path - Route path
|
|
161
|
+
* @property {string} name - Route name
|
|
162
|
+
* @property {Function|string} handler - Route handler
|
|
163
|
+
* @property {Object} [meta] - Route metadata
|
|
164
|
+
* @property {Array<Function>} [middleware] - Route middleware
|
|
165
|
+
*/
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @typedef {Object} RouterConfig
|
|
169
|
+
* @property {string} mode - Router mode (history/hash)
|
|
170
|
+
* @property {string} base - Base path
|
|
171
|
+
* @property {Function} [scrollBehavior] - Scroll behavior function
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @typedef {Object} HTTPConfig
|
|
176
|
+
* @property {string} baseURL - Base URL
|
|
177
|
+
* @property {Object} headers - Default headers
|
|
178
|
+
* @property {number} timeout - Request timeout
|
|
179
|
+
* @property {Function} [onRequest] - Request interceptor
|
|
180
|
+
* @property {Function} [onResponse] - Response interceptor
|
|
181
|
+
* @property {Function} [onError] - Error interceptor
|
|
182
|
+
*/
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @typedef {Object} SSRViewData
|
|
186
|
+
* @property {string} viewId - View ID
|
|
187
|
+
* @property {ViewData} data - View data
|
|
188
|
+
* @property {Object} events - Event configurations
|
|
189
|
+
* @property {Array<string>} children - Child view IDs
|
|
190
|
+
*/
|
|
191
|
+
|
|
192
|
+
// Export empty object to make this a module
|
|
193
|
+
export { };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Date Helper Utility Module
|
|
3
|
+
* ES6 Module for date operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export class DateHelper {
|
|
7
|
+
static formatDate(date, format = 'YYYY-MM-DD') {
|
|
8
|
+
const d = new Date(date);
|
|
9
|
+
const year = d.getFullYear();
|
|
10
|
+
const month = String(d.getMonth() + 1).padStart(2, '0');
|
|
11
|
+
const day = String(d.getDate()).padStart(2, '0');
|
|
12
|
+
|
|
13
|
+
return format
|
|
14
|
+
.replace('YYYY', year)
|
|
15
|
+
.replace('MM', month)
|
|
16
|
+
.replace('DD', day);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static addDays(date, days) {
|
|
20
|
+
const result = new Date(date);
|
|
21
|
+
result.setDate(result.getDate() + days);
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static addMonths(date, months) {
|
|
26
|
+
const result = new Date(date);
|
|
27
|
+
result.setMonth(result.getMonth() + months);
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static isToday(date) {
|
|
32
|
+
const today = new Date();
|
|
33
|
+
const checkDate = new Date(date);
|
|
34
|
+
return today.toDateString() === checkDate.toDateString();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static getDaysBetween(date1, date2) {
|
|
38
|
+
const oneDay = 24 * 60 * 60 * 1000;
|
|
39
|
+
const firstDate = new Date(date1);
|
|
40
|
+
const secondDate = new Date(date2);
|
|
41
|
+
return Math.round(Math.abs((firstDate - secondDate) / oneDay));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Register with global App object
|
|
46
|
+
if (typeof window !== 'undefined' && window.App) {
|
|
47
|
+
window.App.DateHelper = DateHelper;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Export for ES6 modules
|
|
51
|
+
export default DateHelper;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers Utility Module
|
|
3
|
+
* ES6 Module for Blade Compiler
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { App } from '../app.js';
|
|
7
|
+
|
|
8
|
+
export class Helpers {
|
|
9
|
+
static formatDate(date) {
|
|
10
|
+
return new Date(date).toLocaleDateString();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static formatCurrency(amount) {
|
|
14
|
+
return new Intl.NumberFormat('vi-VN', {
|
|
15
|
+
style: 'currency',
|
|
16
|
+
currency: 'VND'
|
|
17
|
+
}).format(amount);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static debounce(func, wait) {
|
|
21
|
+
let timeout;
|
|
22
|
+
return function executedFunction(...args) {
|
|
23
|
+
const later = () => {
|
|
24
|
+
clearTimeout(timeout);
|
|
25
|
+
func(...args);
|
|
26
|
+
};
|
|
27
|
+
clearTimeout(timeout);
|
|
28
|
+
timeout = setTimeout(later, wait);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Register with global App object
|
|
34
|
+
if (typeof window !== 'undefined') {
|
|
35
|
+
window.App.Helpers = Helpers;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Export for ES6 modules
|
|
39
|
+
export default Helpers;
|