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,97 @@
|
|
|
1
|
+
export class LoopContext {
|
|
2
|
+
constructor(parent = null) {
|
|
3
|
+
this.odd = true;
|
|
4
|
+
this.even = false;
|
|
5
|
+
this.first = false;
|
|
6
|
+
this.last = false;
|
|
7
|
+
this.iteration = 0;
|
|
8
|
+
this.index = 0;
|
|
9
|
+
this.remaining = null;
|
|
10
|
+
this.count = null;
|
|
11
|
+
this.depth = 0;
|
|
12
|
+
this.parent = parent;
|
|
13
|
+
|
|
14
|
+
this.type = 'increment';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
setType(type) {
|
|
18
|
+
if(type === 'increment' || type === 'decrement') {
|
|
19
|
+
this.type = type;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
reset() {
|
|
24
|
+
this.iteration = 0;
|
|
25
|
+
this.index = 0;
|
|
26
|
+
this.remaining = null;
|
|
27
|
+
this.count = null;
|
|
28
|
+
this.first = false;
|
|
29
|
+
this.last = false;
|
|
30
|
+
this.odd = true;
|
|
31
|
+
this.even = false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
increment() {
|
|
35
|
+
this.iteration++;
|
|
36
|
+
this.index++;
|
|
37
|
+
if (this.remaining !== null) {
|
|
38
|
+
this.remaining--;
|
|
39
|
+
}
|
|
40
|
+
this.first = this.iteration === 0;
|
|
41
|
+
this.last = this.iteration === this.count - 1;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
decrement() {
|
|
45
|
+
this.iteration--;
|
|
46
|
+
this.index--;
|
|
47
|
+
if (this.remaining !== null) {
|
|
48
|
+
this.remaining++;
|
|
49
|
+
}
|
|
50
|
+
this.last = this.iteration === this.count - 1;
|
|
51
|
+
this.odd = !this.odd;
|
|
52
|
+
this.even = !this.even;
|
|
53
|
+
}
|
|
54
|
+
next() {
|
|
55
|
+
if (this.type === 'increment') {
|
|
56
|
+
this.increment();
|
|
57
|
+
} else {
|
|
58
|
+
this.decrement();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
setCount(count) {
|
|
63
|
+
this.count = count;
|
|
64
|
+
this.remaining = count;
|
|
65
|
+
this.last = count === 1;
|
|
66
|
+
this.odd = false;
|
|
67
|
+
this.even = true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Set the current times of the loop (iteration)
|
|
72
|
+
* @param {number} iteration iteration của vòng lặp hiện tại
|
|
73
|
+
*/
|
|
74
|
+
setCurrentTimes(iteration) {
|
|
75
|
+
this.iteration = iteration;
|
|
76
|
+
if (this.remaining !== null) {
|
|
77
|
+
this.remaining--;
|
|
78
|
+
}
|
|
79
|
+
this.index = this.iteration;
|
|
80
|
+
this.first = this.iteration === 0;
|
|
81
|
+
this.last = this.iteration === this.count - 1;
|
|
82
|
+
this.odd = !this.odd;
|
|
83
|
+
this.even = !this.even;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
setParent(parent) {
|
|
87
|
+
this.parent = parent;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
getParent() {
|
|
91
|
+
return this.parent;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
newChild() {
|
|
95
|
+
return new LoopContext(this);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
export class OneDOM {
|
|
2
|
+
static validateElement(element) {
|
|
3
|
+
if (!(element instanceof Element || element instanceof Comment)) {
|
|
4
|
+
throw new Error('Provided value is not a valid DOM Element');
|
|
5
|
+
}
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Convert various input types to a safe DocumentFragment
|
|
10
|
+
* Supports: string, Element, NodeList, Array<Element|string>
|
|
11
|
+
*/
|
|
12
|
+
static toFragment(content) {
|
|
13
|
+
const fragment = document.createDocumentFragment();
|
|
14
|
+
|
|
15
|
+
const appendItem = (item) => {
|
|
16
|
+
if (!item) return;
|
|
17
|
+
if (typeof item === 'string') {
|
|
18
|
+
const template = document.createElement('template');
|
|
19
|
+
template.innerHTML = item.trim();
|
|
20
|
+
fragment.appendChild(template.content);
|
|
21
|
+
} else if (item instanceof Element || item instanceof DocumentFragment) {
|
|
22
|
+
fragment.appendChild(item);
|
|
23
|
+
} else if (Array.isArray(item) || item instanceof NodeList) {
|
|
24
|
+
item.forEach(appendItem);
|
|
25
|
+
}
|
|
26
|
+
else if (item instanceof Comment) {
|
|
27
|
+
fragment.appendChild(item);
|
|
28
|
+
}
|
|
29
|
+
else if (item instanceof Text) {
|
|
30
|
+
fragment.appendChild(item);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
console.warn('Unsupported content type:', item);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
appendItem(content);
|
|
38
|
+
return fragment;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Chèn nội dung trước đối tượng tham chiếu trong DOM
|
|
43
|
+
* @param {Element|Comment} target đối tường dùng để tham chiếu
|
|
44
|
+
* @param {*} content nội dung thêm vào
|
|
45
|
+
*/
|
|
46
|
+
static before(target, content) {
|
|
47
|
+
if (!(target instanceof Element || target instanceof Comment)) throw new Error('Target must be a DOM element');
|
|
48
|
+
target.parentNode.insertBefore(
|
|
49
|
+
this.toFragment(content),
|
|
50
|
+
target
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Chèn nội dung sau đối tượng tham chiếu trong DOM
|
|
56
|
+
* @param {Element|Comment} target đối tường dùng để tham chiếu
|
|
57
|
+
* @param {*} content nội dung thêm vào
|
|
58
|
+
*/
|
|
59
|
+
static after(target, content) {
|
|
60
|
+
if (!(target instanceof Element || target instanceof Comment)) throw new Error('Target must be a DOM element');
|
|
61
|
+
const frag = this.toFragment(content);
|
|
62
|
+
if (target.nextSibling) target.parentNode.insertBefore(frag, target.nextSibling);
|
|
63
|
+
else target.parentNode.appendChild(frag);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Thay thế đối tượng tham chiếu trong DOM bằng nội dung mới
|
|
68
|
+
* @param {Element|Comment} target đối tường dùng để tham chiếu
|
|
69
|
+
* @param {*} content nội dung thay thế
|
|
70
|
+
*/
|
|
71
|
+
static replace(target, content) {
|
|
72
|
+
if (!(target instanceof Element || target instanceof Comment)) throw new Error('Target must be a DOM element');
|
|
73
|
+
target.replaceWith(this.toFragment(content));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Thêm nội dung vào cuối phần tử tham chiếu trong DOM
|
|
78
|
+
* @param {Element} target phần tử dùng để tham chiếu
|
|
79
|
+
* @param {*} content nội dung thêm vào
|
|
80
|
+
*/
|
|
81
|
+
static append(target, content) {
|
|
82
|
+
if (!(target instanceof Element)) throw new Error('Target must be a DOM element');
|
|
83
|
+
target.appendChild(this.toFragment(content));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Thêm nội dung vào đầu phần tử tham chiếu trong DOM
|
|
88
|
+
* @param {Element} target phần tử dùng để tham chiếu
|
|
89
|
+
* @param {*} content nội dung thêm vào
|
|
90
|
+
*/
|
|
91
|
+
static prepend(target, content) {
|
|
92
|
+
if (!(target instanceof Element)) throw new Error('Target must be a DOM element');
|
|
93
|
+
if (!target.firstChild) {
|
|
94
|
+
target.appendChild(this.toFragment(content));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
target.insertBefore(this.toFragment(content), target.firstChild);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Thiết lập nội dung HTML cho phần tử tham chiếu trong DOM
|
|
101
|
+
* @param {Element} target phần tử dùng để tham chiếu
|
|
102
|
+
* @param {*} content nội dung thiết lập
|
|
103
|
+
*/
|
|
104
|
+
static setHTML(target, content) {
|
|
105
|
+
if (!(target instanceof Element)) throw new Error('Target must be a DOM element');
|
|
106
|
+
target.innerHTML = '';
|
|
107
|
+
target.appendChild(this.toFragment(content));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Thay thế toàn bộ nội dung của phần tử tham chiếu trong DOM
|
|
112
|
+
* @param {Element} target phần tử dùng để tham chiếu
|
|
113
|
+
* @param {*} content nội dung thay thế
|
|
114
|
+
*/
|
|
115
|
+
static replaceContent(target, content) {
|
|
116
|
+
if (!(target instanceof Element)) throw new Error('Target must be a DOM element');
|
|
117
|
+
target.innerHTML = '';
|
|
118
|
+
target.appendChild(this.toFragment(content));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
static content(target, content) {
|
|
122
|
+
if (content === undefined) {
|
|
123
|
+
// Lấy nội dung
|
|
124
|
+
if (!(target instanceof Element)) throw new Error('Target must be a DOM element');
|
|
125
|
+
return target.innerHTML;
|
|
126
|
+
} else {
|
|
127
|
+
// Thiết lập nội dung
|
|
128
|
+
this.setHTML(target, content);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
static children(target, children = null) {
|
|
133
|
+
if (!(target instanceof Element)) throw new Error('Target must be a DOM element');
|
|
134
|
+
if (children === null || children === undefined) {
|
|
135
|
+
return Array.from(target.children);
|
|
136
|
+
} else {
|
|
137
|
+
target.innerHTML = '';
|
|
138
|
+
target.appendChild(this.toFragment(children));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
static getInputValue(el) {
|
|
143
|
+
if (!el || !(el instanceof Element)) return null;
|
|
144
|
+
|
|
145
|
+
const tag = el.tagName.toLowerCase();
|
|
146
|
+
const type = (el.type || '').toLowerCase();
|
|
147
|
+
|
|
148
|
+
// Input
|
|
149
|
+
if (tag === 'input') {
|
|
150
|
+
switch (type) {
|
|
151
|
+
case 'checkbox':
|
|
152
|
+
return el.checked;
|
|
153
|
+
case 'radio':
|
|
154
|
+
return el.checked ? (el.value ? el.value : false) : null;
|
|
155
|
+
case 'file':
|
|
156
|
+
return el.multiple ? [...el.files] : el.files[0] || null;
|
|
157
|
+
case 'number':
|
|
158
|
+
case 'range':
|
|
159
|
+
return el.value === '' ? null : Number(el.value);
|
|
160
|
+
default:
|
|
161
|
+
return el.value;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Select
|
|
166
|
+
if (tag === 'select') {
|
|
167
|
+
if (el.multiple) {
|
|
168
|
+
return [...el.selectedOptions].map(o => o.value);
|
|
169
|
+
}
|
|
170
|
+
return el.value;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Textarea
|
|
174
|
+
if (tag === 'textarea') {
|
|
175
|
+
return el.value;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Contenteditable
|
|
179
|
+
if (el.isContentEditable) {
|
|
180
|
+
return el.innerText;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
static setInputValue(el, value) {
|
|
187
|
+
if (!el || !(el instanceof Element)) return;
|
|
188
|
+
|
|
189
|
+
const tag = el.tagName.toLowerCase();
|
|
190
|
+
const type = (el.type || '').toLowerCase();
|
|
191
|
+
|
|
192
|
+
// Input
|
|
193
|
+
if (tag === 'input') {
|
|
194
|
+
switch (type) {
|
|
195
|
+
case 'checkbox':
|
|
196
|
+
el.checked = Boolean(value);
|
|
197
|
+
return;
|
|
198
|
+
|
|
199
|
+
case 'radio':
|
|
200
|
+
el.checked = el.value === value;
|
|
201
|
+
return;
|
|
202
|
+
|
|
203
|
+
case 'file':
|
|
204
|
+
// Không thể set file programmatically (security)
|
|
205
|
+
return;
|
|
206
|
+
|
|
207
|
+
case 'number':
|
|
208
|
+
case 'range':
|
|
209
|
+
el.value = value ?? '';
|
|
210
|
+
return;
|
|
211
|
+
|
|
212
|
+
default:
|
|
213
|
+
el.value = value ?? '';
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Select
|
|
219
|
+
if (tag === 'select') {
|
|
220
|
+
if (el.multiple && Array.isArray(value)) {
|
|
221
|
+
[...el.options].forEach(opt => {
|
|
222
|
+
opt.selected = value.includes(opt.value);
|
|
223
|
+
});
|
|
224
|
+
} else {
|
|
225
|
+
el.value = value ?? '';
|
|
226
|
+
}
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Textarea
|
|
231
|
+
if (tag === 'textarea') {
|
|
232
|
+
el.value = value ?? '';
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Contenteditable
|
|
237
|
+
if (el.isContentEditable) {
|
|
238
|
+
el.innerText = value ?? '';
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export default OneDOM;
|