create-gardener 2.0.9 → 2.1.1
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 +328 -140
- package/package.json +1 -1
- package/template/src/backend/controllers/gardener/addPage.ts +25 -21
- package/template/src/backend/controllers/gardener/createStatic.ts +1 -0
- package/template/src/backend/libs/generateWebp.ts +0 -2
- package/template/src/frontend/static/cache/gardener_100x100.webp +0 -0
- package/template/src/frontend/static/components/copybtn.js +16 -3
- package/template/src/frontend/static/components/footer.js +33 -0
- package/template/src/frontend/static/components/gardener/errorBox.js +47 -0
- package/template/src/frontend/static/components/gardener/hotReloadbtn.js +82 -0
- package/template/src/frontend/static/components/gardener/pageOverlayBtn.js +138 -0
- package/template/src/frontend/static/components/gardener/parserWindow.js +159 -0
- package/template/src/frontend/static/components/nonui/api.js +15 -2
- package/template/src/frontend/static/gardener.js +129 -58
- package/template/src/frontend/static/gardenerDev.js +65 -399
- package/template/src/frontend/static/global.js +1 -1
- package/template/src/frontend/static/pages/pages._.js +5 -0
- package/template/src/frontend/static/style.css +101 -0
- package/template/src/frontend/static/style2.css +2 -2
- package/template/src/frontend/template/template._.ejs +121 -0
|
@@ -1,89 +1,160 @@
|
|
|
1
|
+
import { gardenerError } from "./components/gardener/errorBox.js";
|
|
2
|
+
|
|
1
3
|
|
|
2
4
|
export function fetchElement(param) {
|
|
3
|
-
|
|
5
|
+
const element = document.querySelector(param);
|
|
6
|
+
if (!element) {
|
|
7
|
+
console.warn(`Element not found: ${param}`);
|
|
8
|
+
}
|
|
9
|
+
return element;
|
|
4
10
|
}
|
|
5
11
|
|
|
6
12
|
export function appendElement(parent, child) {
|
|
7
|
-
|
|
8
|
-
parent
|
|
13
|
+
try {
|
|
14
|
+
if (typeof parent === 'string') {
|
|
15
|
+
parent = fetchElement(parent);
|
|
16
|
+
}
|
|
17
|
+
if (!parent) {
|
|
18
|
+
throw new Error('Parent element is null or undefined');
|
|
19
|
+
}
|
|
20
|
+
if (!child) {
|
|
21
|
+
throw new Error('Child element is null or undefined');
|
|
22
|
+
}
|
|
23
|
+
parent.appendChild(child);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
gardenerError(error);
|
|
9
26
|
}
|
|
10
|
-
parent.appendChild(child);
|
|
11
27
|
}
|
|
12
28
|
|
|
13
29
|
export function createElement(type, classname) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
30
|
+
try {
|
|
31
|
+
if (!type) {
|
|
32
|
+
throw new Error('Element type is required');
|
|
33
|
+
}
|
|
34
|
+
let element = document.createElement(type);
|
|
35
|
+
if (classname)
|
|
36
|
+
element.classList.add(...classname);
|
|
37
|
+
return element;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
gardenerError(error);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
18
42
|
}
|
|
19
43
|
|
|
20
44
|
export function insertText(element, text) {
|
|
21
|
-
element
|
|
45
|
+
if (!element) {
|
|
46
|
+
console.warn('insertText: Element is null or undefined');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
element.textContent = text;
|
|
22
50
|
}
|
|
23
51
|
|
|
24
52
|
export function replaceElement(original, New) {
|
|
25
|
-
|
|
26
|
-
original
|
|
53
|
+
try {
|
|
54
|
+
if (typeof original === 'string') {
|
|
55
|
+
original = fetchElement(original);
|
|
56
|
+
}
|
|
57
|
+
if (!original) {
|
|
58
|
+
throw new Error('Original element is null or undefined');
|
|
59
|
+
}
|
|
60
|
+
if (!New) {
|
|
61
|
+
throw new Error('New element is null or undefined');
|
|
62
|
+
}
|
|
63
|
+
original.replaceWith(New);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
gardenerError(error);
|
|
27
66
|
}
|
|
28
|
-
original.replaceWith(New);
|
|
29
67
|
}
|
|
30
68
|
|
|
31
69
|
export function gardener(Dom) {
|
|
70
|
+
try {
|
|
71
|
+
if (!Dom) {
|
|
72
|
+
throw new Error('DOM configuration is null or undefined');
|
|
73
|
+
}
|
|
32
74
|
|
|
33
|
-
|
|
34
|
-
// detect if this is an SVG element
|
|
35
|
-
const isSVG = [
|
|
36
|
-
'svg', 'path', 'circle', 'rect', 'line', 'polygon', 'polyline', 'g', 'defs', 'clipPath', 'use'
|
|
37
|
-
].includes(Dom.t);
|
|
75
|
+
if (Dom.nodeType === 1) return Dom;
|
|
38
76
|
|
|
39
|
-
|
|
40
|
-
|
|
77
|
+
if (!Dom.t) {
|
|
78
|
+
throw new Error('Element type (t) is required in DOM configuration');
|
|
79
|
+
}
|
|
41
80
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
element = createElement(Dom.t, Dom.cn);
|
|
49
|
-
}
|
|
81
|
+
// detect if this is an SVG element
|
|
82
|
+
const isSVG = [
|
|
83
|
+
'svg', 'path', 'circle', 'rect', 'line', 'polygon', 'polyline', 'g', 'defs', 'clipPath', 'use'
|
|
84
|
+
].includes(Dom.t);
|
|
50
85
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
86
|
+
// create element accordingly
|
|
87
|
+
let element;
|
|
88
|
+
|
|
89
|
+
if (isSVG) {
|
|
90
|
+
element = document.createElementNS('http://www.w3.org/2000/svg', Dom.t);
|
|
91
|
+
if (Dom.cn)
|
|
92
|
+
element.classList.add(...Dom.cn);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
element = createElement(Dom.t, Dom.cn);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!element) {
|
|
99
|
+
throw new Error(`Failed to create element: ${Dom.t}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// text content (skip for SVG like <path>)
|
|
103
|
+
if (Dom.txt) {
|
|
104
|
+
insertText(element, Dom.txt);
|
|
105
|
+
}
|
|
55
106
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
107
|
+
// apply attributes safely
|
|
108
|
+
const propertyNames = new Set([
|
|
109
|
+
'value', 'selected', 'muted', 'disabled',
|
|
110
|
+
'selectedIndex', 'volume', // etc.
|
|
111
|
+
]);
|
|
112
|
+
|
|
113
|
+
if (Dom.attr) {
|
|
114
|
+
for (const [key, value] of Object.entries(Dom.attr)) {
|
|
115
|
+
try {
|
|
116
|
+
if (isSVG || key.startsWith('data-') || key.startsWith('aria-')) {
|
|
117
|
+
element.setAttribute(key, value);
|
|
118
|
+
} else if (key in element && !propertyNames.has(key)) {
|
|
119
|
+
// Prefer property for known safe cases
|
|
120
|
+
try { element[key] = value === '' ? true : value; } catch (e) { element.setAttribute(key, value); }
|
|
121
|
+
} else {
|
|
122
|
+
element.setAttribute(key, value);
|
|
123
|
+
}
|
|
124
|
+
} catch (attrError) {
|
|
125
|
+
console.warn(`Failed to set attribute ${key}:`, attrError);
|
|
126
|
+
}
|
|
71
127
|
}
|
|
72
128
|
}
|
|
73
|
-
}
|
|
74
129
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
130
|
+
if (Dom.events) {
|
|
131
|
+
Object.entries(Dom.events).forEach(([eventName, handler]) => {
|
|
132
|
+
try {
|
|
133
|
+
if (typeof handler !== 'function') {
|
|
134
|
+
throw new Error(`Event handler for '${eventName}' must be a function`);
|
|
135
|
+
}
|
|
136
|
+
element.addEventListener(eventName, handler);
|
|
137
|
+
} catch (eventError) {
|
|
138
|
+
console.warn(`Failed to add event listener ${eventName}:`, eventError);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
80
142
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
143
|
+
// recursively handle children
|
|
144
|
+
if (Dom.children) {
|
|
145
|
+
Dom.children.forEach(child => {
|
|
146
|
+
try {
|
|
147
|
+
appendElement(element, gardener(child));
|
|
148
|
+
} catch (childError) {
|
|
149
|
+
console.warn('Failed to append child:', childError);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
85
153
|
|
|
86
|
-
|
|
154
|
+
return element;
|
|
155
|
+
} catch (error) {
|
|
156
|
+
gardenerError(error);
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
87
159
|
}
|
|
88
160
|
|
|
89
|
-
|