@ktjs/core 0.6.12 → 0.6.16
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/dist/index.d.ts +1 -5
- package/dist/index.iife.js +307 -1
- package/dist/index.legacy.js +320 -1
- package/dist/index.mjs +298 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -89,10 +89,6 @@ type KTEventHandlersOrAttribute = {
|
|
|
89
89
|
[EventName in keyof HTMLElementEventMap]?: ((ev: HTMLElementEventMap[EventName]) => void) | string;
|
|
90
90
|
};
|
|
91
91
|
|
|
92
|
-
/**
|
|
93
|
-
* Event handlers with @ prefix (e.g., @click, @input)
|
|
94
|
-
* When key starts with @, it's always registered as an event handler
|
|
95
|
-
*/
|
|
96
92
|
type KTPrefixedEventHandlers = {
|
|
97
93
|
[EventName in keyof HTMLElementEventMap as `on:${EventName}`]?: (ev: HTMLElementEventMap[EventName]) => void;
|
|
98
94
|
};
|
|
@@ -110,7 +106,7 @@ type HTML<T extends HTMLTag & otherstring> = T extends HTMLTag ? HTMLElementTagN
|
|
|
110
106
|
* ## About
|
|
111
107
|
* @package @ktjs/core
|
|
112
108
|
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
113
|
-
* @version 0.6.
|
|
109
|
+
* @version 0.6.16 (Last Update: 2025.12.24 22:15:40.697)
|
|
114
110
|
* @license MIT
|
|
115
111
|
* @link https://github.com/baendlorel/kt.js
|
|
116
112
|
* @link https://baendlorel.github.io/ Welcome to my site!
|
package/dist/index.iife.js
CHANGED
|
@@ -1 +1,307 @@
|
|
|
1
|
-
var __ktjs_core__
|
|
1
|
+
var __ktjs_core__ = (function (exports) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const $throw = (message) => {
|
|
5
|
+
throw new Error('kt.js: ' + message);
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const $isArray = Array.isArray;
|
|
9
|
+
const $keys = Object.keys;
|
|
10
|
+
const $defines = Object.defineProperties;
|
|
11
|
+
const $mark = (func, tag) => $defines(func, { __ktjs_h__: { value: tag, configurable: true } });
|
|
12
|
+
const emptyPromiseHandler = () => ({});
|
|
13
|
+
if (typeof Promise === 'undefined') {
|
|
14
|
+
window.Promise = { resolve: emptyPromiseHandler, reject: emptyPromiseHandler };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
(() => {
|
|
18
|
+
const runtimeKey = '__ktjs__';
|
|
19
|
+
if (runtimeKey in window) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const __ktjs__ = Object.create(null);
|
|
23
|
+
// & We can add new functions when we need more
|
|
24
|
+
const descriptor = {
|
|
25
|
+
throws: { value: $throw, enumerable: true },
|
|
26
|
+
defines: { value: $defines, enumerable: true },
|
|
27
|
+
mark: { value: $mark, enumerable: true },
|
|
28
|
+
};
|
|
29
|
+
$defines(__ktjs__, descriptor);
|
|
30
|
+
$defines(window, { [runtimeKey]: { value: __ktjs__, enumerable: true } });
|
|
31
|
+
return {};
|
|
32
|
+
})();
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* This is a `falsy` value used to indicate "no node" in `h` function.
|
|
36
|
+
* - It's an object, so it's guaranteed to be unique and no need for polyfill of `symbol`.
|
|
37
|
+
*/
|
|
38
|
+
const ktnull = Object.create(null);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* & Remove `bind` because it is shockingly slower than wrapper
|
|
42
|
+
* & `window.document` is safe because it is not configurable and its setter is undefined
|
|
43
|
+
*/
|
|
44
|
+
const $appendChild = HTMLElement.prototype.appendChild;
|
|
45
|
+
const originAppend = HTMLElement.prototype.append;
|
|
46
|
+
const $append = // for ie 9/10/11
|
|
47
|
+
typeof originAppend === 'function'
|
|
48
|
+
? function (...args) {
|
|
49
|
+
const nodes = args.filter((a) => a !== ktnull);
|
|
50
|
+
return originAppend.apply(this, nodes);
|
|
51
|
+
}
|
|
52
|
+
: function (...nodes) {
|
|
53
|
+
if (nodes.length < 50) {
|
|
54
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
55
|
+
const node = nodes[i];
|
|
56
|
+
if (typeof node === 'string') {
|
|
57
|
+
$appendChild.call(this, document.createTextNode(node));
|
|
58
|
+
}
|
|
59
|
+
else if (node !== ktnull) {
|
|
60
|
+
$appendChild.call(this, node);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
const fragment = document.createDocumentFragment();
|
|
66
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
67
|
+
const node = nodes[i];
|
|
68
|
+
if (typeof node === 'string') {
|
|
69
|
+
$appendChild.call(fragment, document.createTextNode(node));
|
|
70
|
+
}
|
|
71
|
+
else if (node !== ktnull) {
|
|
72
|
+
$appendChild.call(fragment, node);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
$appendChild.call(this, fragment);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
function booleanHandler(element, key, value) {
|
|
80
|
+
if (key in element) {
|
|
81
|
+
element[key] = !!value;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
element.setAttribute(key, value);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function valueHandler(element, key, value) {
|
|
88
|
+
if (key in element) {
|
|
89
|
+
element[key] = value;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
element.setAttribute(key, value);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Attribute handlers map for optimized lookup
|
|
96
|
+
const handlers = {
|
|
97
|
+
checked: booleanHandler,
|
|
98
|
+
selected: booleanHandler,
|
|
99
|
+
value: valueHandler,
|
|
100
|
+
valueAsDate: valueHandler,
|
|
101
|
+
valueAsNumber: valueHandler,
|
|
102
|
+
defaultValue: valueHandler,
|
|
103
|
+
defaultChecked: booleanHandler,
|
|
104
|
+
defaultSelected: booleanHandler,
|
|
105
|
+
disabled: booleanHandler,
|
|
106
|
+
readOnly: booleanHandler,
|
|
107
|
+
multiple: booleanHandler,
|
|
108
|
+
required: booleanHandler,
|
|
109
|
+
autofocus: booleanHandler,
|
|
110
|
+
open: booleanHandler,
|
|
111
|
+
controls: booleanHandler,
|
|
112
|
+
autoplay: booleanHandler,
|
|
113
|
+
loop: booleanHandler,
|
|
114
|
+
muted: booleanHandler,
|
|
115
|
+
defer: booleanHandler,
|
|
116
|
+
async: booleanHandler,
|
|
117
|
+
hidden: function (element, _key, value) {
|
|
118
|
+
element.hidden = !!value;
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
const defaultHandler = function (element, key, value) {
|
|
122
|
+
return element.setAttribute(key, value);
|
|
123
|
+
};
|
|
124
|
+
function attrIsObject(element, attr) {
|
|
125
|
+
const classValue = attr.class;
|
|
126
|
+
const style = attr.style;
|
|
127
|
+
if (classValue !== undefined) {
|
|
128
|
+
element.className = classValue;
|
|
129
|
+
delete attr.class;
|
|
130
|
+
}
|
|
131
|
+
if (style) {
|
|
132
|
+
if (typeof style === 'string') {
|
|
133
|
+
element.setAttribute('style', style);
|
|
134
|
+
}
|
|
135
|
+
else if (typeof style === 'object') {
|
|
136
|
+
for (const key in style) {
|
|
137
|
+
element.style[key] = style[key];
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
delete attr.style;
|
|
141
|
+
}
|
|
142
|
+
const keys = $keys(attr);
|
|
143
|
+
for (let i = keys.length - 1; i >= 0; i--) {
|
|
144
|
+
const key = keys[i];
|
|
145
|
+
const o = attr[key];
|
|
146
|
+
// force register on:xxx as an event handler
|
|
147
|
+
// !if o is not valid, the throwing job will be done by `on`, not kt.js
|
|
148
|
+
if (key.startsWith('on:')) {
|
|
149
|
+
element.addEventListener(key.slice(3), o); // chop off the `@`
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (typeof o !== 'function') {
|
|
153
|
+
(handlers[key] || defaultHandler)(element, key, o);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
element.addEventListener(key, o);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (classValue !== undefined) {
|
|
160
|
+
attr.class = classValue;
|
|
161
|
+
}
|
|
162
|
+
if (style !== undefined) {
|
|
163
|
+
attr.style = style;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function applyAttr(element, attr) {
|
|
167
|
+
if (typeof attr === 'string') {
|
|
168
|
+
element.className = attr;
|
|
169
|
+
}
|
|
170
|
+
else if (typeof attr === 'object' && attr !== null) {
|
|
171
|
+
attrIsObject(element, attr);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
$throw('attr must be an object/string.');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function applyContent(element, content) {
|
|
179
|
+
if ($isArray(content)) {
|
|
180
|
+
$append.apply(element, content);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
if (typeof content === 'number') {
|
|
184
|
+
$append.call(element, content.toString());
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
$append.call(element, content);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Create an enhanced HTMLElement.
|
|
194
|
+
* - Only supports HTMLElements, **NOT** SVGElements or other Elements.
|
|
195
|
+
* @param tag tag of an `HTMLElement`
|
|
196
|
+
* @param attr attribute object or className
|
|
197
|
+
* @param content a string or an array of HTMLEnhancedElement as child nodes
|
|
198
|
+
*
|
|
199
|
+
* ## About
|
|
200
|
+
* @package @ktjs/core
|
|
201
|
+
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
202
|
+
* @version 0.6.16 (Last Update: 2025.12.24 22:15:40.697)
|
|
203
|
+
* @license MIT
|
|
204
|
+
* @link https://github.com/baendlorel/kt.js
|
|
205
|
+
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
206
|
+
* @description Core functionality for kt.js - DOM manipulation utilities
|
|
207
|
+
* @copyright Copyright (c) 2025 Kasukabe Tsumugi. All rights reserved.
|
|
208
|
+
*/
|
|
209
|
+
const h = (tag, attr = '', content = '') => {
|
|
210
|
+
if (typeof tag !== 'string') {
|
|
211
|
+
$throw('__func__ tagName must be a string.');
|
|
212
|
+
}
|
|
213
|
+
// * start creating the element
|
|
214
|
+
const element = document.createElement(tag);
|
|
215
|
+
// * Handle content
|
|
216
|
+
applyAttr(element, attr);
|
|
217
|
+
applyContent(element, content);
|
|
218
|
+
return element;
|
|
219
|
+
};
|
|
220
|
+
$mark(h, 'h');
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* # Specialized Ehancement
|
|
224
|
+
*
|
|
225
|
+
* Different elements should be enhanced in different ways. For example, we should have `kvalue` to handle `<input>` values.
|
|
226
|
+
* While we have no need to have `ktext` for `<br>` tags.
|
|
227
|
+
*
|
|
228
|
+
* ## Tags where appending a text node has no effect
|
|
229
|
+
*
|
|
230
|
+
* There are some HTML elements that appending a text node as their child takes no effect.
|
|
231
|
+
* They are mostly void elements, but some non-void elements are also included.
|
|
232
|
+
*
|
|
233
|
+
* ## What means no effect
|
|
234
|
+
* 1. appending a text node to these tags takes no effect.
|
|
235
|
+
* 2. No effect means `innerText` does not include the text in the text node.
|
|
236
|
+
*
|
|
237
|
+
* After testing 15 browsers testing, I found that these elements are:
|
|
238
|
+
*
|
|
239
|
+
* - FireFox(as base):
|
|
240
|
+
* - script -- this is skipped due to some bugs in The World 7
|
|
241
|
+
* - area, audio, base, basefont, br, canvas, datalist, details, dialog, frameset, head, iframe, img, input, link, meta, meter, noembed, noframes, noscript, optgroup, param, progress, rp, select, style, template, textarea, title, video, wbr
|
|
242
|
+
* - 360: embed
|
|
243
|
+
* - 2345: embed
|
|
244
|
+
* - maxthon: embed
|
|
245
|
+
* - quark: embed
|
|
246
|
+
* - uc: embed
|
|
247
|
+
* - chrome: embed,frame
|
|
248
|
+
* - qq: embed
|
|
249
|
+
* - sogou: embed
|
|
250
|
+
* - cent: embed
|
|
251
|
+
* - world: embed,frame,keygen,option
|
|
252
|
+
* - opera: embed
|
|
253
|
+
* - edge: embed
|
|
254
|
+
* - liebao: embed
|
|
255
|
+
* - 360turbo: embed,frame
|
|
256
|
+
*
|
|
257
|
+
* Since `Set.prototype.has` is about 80 times faster than `Array.prototype.includes`,
|
|
258
|
+
* We put these tags into a `Set` object.
|
|
259
|
+
*/
|
|
260
|
+
const INVALID_TAGS = {
|
|
261
|
+
area: true,
|
|
262
|
+
audio: true,
|
|
263
|
+
base: true,
|
|
264
|
+
basefont: true,
|
|
265
|
+
br: true,
|
|
266
|
+
canvas: true,
|
|
267
|
+
datalist: true,
|
|
268
|
+
details: true,
|
|
269
|
+
dialog: true,
|
|
270
|
+
frameset: true,
|
|
271
|
+
head: true,
|
|
272
|
+
iframe: true,
|
|
273
|
+
img: true,
|
|
274
|
+
input: true,
|
|
275
|
+
link: true,
|
|
276
|
+
meta: true,
|
|
277
|
+
meter: true,
|
|
278
|
+
noembed: true,
|
|
279
|
+
noframes: true,
|
|
280
|
+
noscript: true,
|
|
281
|
+
optgroup: true,
|
|
282
|
+
param: true,
|
|
283
|
+
progress: true,
|
|
284
|
+
rp: true,
|
|
285
|
+
select: true,
|
|
286
|
+
style: true,
|
|
287
|
+
template: true,
|
|
288
|
+
textarea: true,
|
|
289
|
+
title: true,
|
|
290
|
+
video: true,
|
|
291
|
+
wbr: true,
|
|
292
|
+
embed: true,
|
|
293
|
+
frame: true,
|
|
294
|
+
keygen: true,
|
|
295
|
+
option: true,
|
|
296
|
+
};
|
|
297
|
+
function notSupportTextNode(tag) {
|
|
298
|
+
return INVALID_TAGS[tag];
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
exports.h = h;
|
|
302
|
+
exports.ktnull = ktnull;
|
|
303
|
+
exports.notSupportTextNode = notSupportTextNode;
|
|
304
|
+
|
|
305
|
+
return exports;
|
|
306
|
+
|
|
307
|
+
})({});
|
package/dist/index.legacy.js
CHANGED
|
@@ -1 +1,320 @@
|
|
|
1
|
-
var __ktjs_core__
|
|
1
|
+
var __ktjs_core__ = (function (exports) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var $throw = function (message) {
|
|
5
|
+
throw new Error('kt.js: ' + message);
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
var $isArray = Array.isArray;
|
|
9
|
+
var $keys = Object.keys;
|
|
10
|
+
var $defines = Object.defineProperties;
|
|
11
|
+
var $mark = function (func, tag) {
|
|
12
|
+
return $defines(func, { __ktjs_h__: { value: tag, configurable: true } });
|
|
13
|
+
};
|
|
14
|
+
var emptyPromiseHandler = function () { return ({}); };
|
|
15
|
+
if (typeof Promise === 'undefined') {
|
|
16
|
+
window.Promise = { resolve: emptyPromiseHandler, reject: emptyPromiseHandler };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
((function () {
|
|
20
|
+
var _a;
|
|
21
|
+
var runtimeKey = '__ktjs__';
|
|
22
|
+
if (runtimeKey in window) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
var __ktjs__ = Object.create(null);
|
|
26
|
+
// & We can add new functions when we need more
|
|
27
|
+
var descriptor = {
|
|
28
|
+
throws: { value: $throw, enumerable: true },
|
|
29
|
+
defines: { value: $defines, enumerable: true },
|
|
30
|
+
mark: { value: $mark, enumerable: true },
|
|
31
|
+
};
|
|
32
|
+
$defines(__ktjs__, descriptor);
|
|
33
|
+
$defines(window, (_a = {}, _a[runtimeKey] = { value: __ktjs__, enumerable: true }, _a));
|
|
34
|
+
return {};
|
|
35
|
+
}))();
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* This is a `falsy` value used to indicate "no node" in `h` function.
|
|
39
|
+
* - It's an object, so it's guaranteed to be unique and no need for polyfill of `symbol`.
|
|
40
|
+
*/
|
|
41
|
+
var ktnull = Object.create(null);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* & Remove `bind` because it is shockingly slower than wrapper
|
|
45
|
+
* & `window.document` is safe because it is not configurable and its setter is undefined
|
|
46
|
+
*/
|
|
47
|
+
var $appendChild = HTMLElement.prototype.appendChild;
|
|
48
|
+
var originAppend = HTMLElement.prototype.append;
|
|
49
|
+
var $append = // for ie 9/10/11
|
|
50
|
+
typeof originAppend === 'function'
|
|
51
|
+
? function () {
|
|
52
|
+
var args = [];
|
|
53
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
54
|
+
args[_i] = arguments[_i];
|
|
55
|
+
}
|
|
56
|
+
var nodes = args.filter(function (a) { return a !== ktnull; });
|
|
57
|
+
return originAppend.apply(this, nodes);
|
|
58
|
+
}
|
|
59
|
+
: function () {
|
|
60
|
+
var nodes = [];
|
|
61
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
62
|
+
nodes[_i] = arguments[_i];
|
|
63
|
+
}
|
|
64
|
+
if (nodes.length < 50) {
|
|
65
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
66
|
+
var node = nodes[i];
|
|
67
|
+
if (typeof node === 'string') {
|
|
68
|
+
$appendChild.call(this, document.createTextNode(node));
|
|
69
|
+
}
|
|
70
|
+
else if (node !== ktnull) {
|
|
71
|
+
$appendChild.call(this, node);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
var fragment = document.createDocumentFragment();
|
|
77
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
78
|
+
var node = nodes[i];
|
|
79
|
+
if (typeof node === 'string') {
|
|
80
|
+
$appendChild.call(fragment, document.createTextNode(node));
|
|
81
|
+
}
|
|
82
|
+
else if (node !== ktnull) {
|
|
83
|
+
$appendChild.call(fragment, node);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
$appendChild.call(this, fragment);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
function booleanHandler(element, key, value) {
|
|
91
|
+
if (key in element) {
|
|
92
|
+
element[key] = !!value;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
element.setAttribute(key, value);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function valueHandler(element, key, value) {
|
|
99
|
+
if (key in element) {
|
|
100
|
+
element[key] = value;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
element.setAttribute(key, value);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Attribute handlers map for optimized lookup
|
|
107
|
+
var handlers = {
|
|
108
|
+
checked: booleanHandler,
|
|
109
|
+
selected: booleanHandler,
|
|
110
|
+
value: valueHandler,
|
|
111
|
+
valueAsDate: valueHandler,
|
|
112
|
+
valueAsNumber: valueHandler,
|
|
113
|
+
defaultValue: valueHandler,
|
|
114
|
+
defaultChecked: booleanHandler,
|
|
115
|
+
defaultSelected: booleanHandler,
|
|
116
|
+
disabled: booleanHandler,
|
|
117
|
+
readOnly: booleanHandler,
|
|
118
|
+
multiple: booleanHandler,
|
|
119
|
+
required: booleanHandler,
|
|
120
|
+
autofocus: booleanHandler,
|
|
121
|
+
open: booleanHandler,
|
|
122
|
+
controls: booleanHandler,
|
|
123
|
+
autoplay: booleanHandler,
|
|
124
|
+
loop: booleanHandler,
|
|
125
|
+
muted: booleanHandler,
|
|
126
|
+
defer: booleanHandler,
|
|
127
|
+
async: booleanHandler,
|
|
128
|
+
hidden: function (element, _key, value) {
|
|
129
|
+
element.hidden = !!value;
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
var defaultHandler = function (element, key, value) {
|
|
133
|
+
return element.setAttribute(key, value);
|
|
134
|
+
};
|
|
135
|
+
function attrIsObject(element, attr) {
|
|
136
|
+
var classValue = attr.class;
|
|
137
|
+
var style = attr.style;
|
|
138
|
+
if (classValue !== undefined) {
|
|
139
|
+
element.className = classValue;
|
|
140
|
+
delete attr.class;
|
|
141
|
+
}
|
|
142
|
+
if (style) {
|
|
143
|
+
if (typeof style === 'string') {
|
|
144
|
+
element.setAttribute('style', style);
|
|
145
|
+
}
|
|
146
|
+
else if (typeof style === 'object') {
|
|
147
|
+
for (var key in style) {
|
|
148
|
+
element.style[key] = style[key];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
delete attr.style;
|
|
152
|
+
}
|
|
153
|
+
var keys = $keys(attr);
|
|
154
|
+
for (var i = keys.length - 1; i >= 0; i--) {
|
|
155
|
+
var key = keys[i];
|
|
156
|
+
var o = attr[key];
|
|
157
|
+
// force register on:xxx as an event handler
|
|
158
|
+
// !if o is not valid, the throwing job will be done by `on`, not kt.js
|
|
159
|
+
if (key.startsWith('on:')) {
|
|
160
|
+
element.addEventListener(key.slice(3), o); // chop off the `@`
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (typeof o !== 'function') {
|
|
164
|
+
(handlers[key] || defaultHandler)(element, key, o);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
element.addEventListener(key, o);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (classValue !== undefined) {
|
|
171
|
+
attr.class = classValue;
|
|
172
|
+
}
|
|
173
|
+
if (style !== undefined) {
|
|
174
|
+
attr.style = style;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function applyAttr(element, attr) {
|
|
178
|
+
if (typeof attr === 'string') {
|
|
179
|
+
element.className = attr;
|
|
180
|
+
}
|
|
181
|
+
else if (typeof attr === 'object' && attr !== null) {
|
|
182
|
+
attrIsObject(element, attr);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
$throw('attr must be an object/string.');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function applyContent(element, content) {
|
|
190
|
+
if ($isArray(content)) {
|
|
191
|
+
$append.apply(element, content);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
if (typeof content === 'number') {
|
|
195
|
+
$append.call(element, content.toString());
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
$append.call(element, content);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Create an enhanced HTMLElement.
|
|
205
|
+
* - Only supports HTMLElements, **NOT** SVGElements or other Elements.
|
|
206
|
+
* @param tag tag of an `HTMLElement`
|
|
207
|
+
* @param attr attribute object or className
|
|
208
|
+
* @param content a string or an array of HTMLEnhancedElement as child nodes
|
|
209
|
+
*
|
|
210
|
+
* ## About
|
|
211
|
+
* @package @ktjs/core
|
|
212
|
+
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
213
|
+
* @version 0.6.16 (Last Update: 2025.12.24 22:15:40.697)
|
|
214
|
+
* @license MIT
|
|
215
|
+
* @link https://github.com/baendlorel/kt.js
|
|
216
|
+
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
217
|
+
* @description Core functionality for kt.js - DOM manipulation utilities
|
|
218
|
+
* @copyright Copyright (c) 2025 Kasukabe Tsumugi. All rights reserved.
|
|
219
|
+
*/
|
|
220
|
+
var h = function (tag, attr, content) {
|
|
221
|
+
if (attr === void 0) { attr = ''; }
|
|
222
|
+
if (content === void 0) { content = ''; }
|
|
223
|
+
if (typeof tag !== 'string') {
|
|
224
|
+
$throw('__func__ tagName must be a string.');
|
|
225
|
+
}
|
|
226
|
+
// * start creating the element
|
|
227
|
+
var element = document.createElement(tag);
|
|
228
|
+
// * Handle content
|
|
229
|
+
applyAttr(element, attr);
|
|
230
|
+
applyContent(element, content);
|
|
231
|
+
return element;
|
|
232
|
+
};
|
|
233
|
+
$mark(h, 'h');
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* # Specialized Ehancement
|
|
237
|
+
*
|
|
238
|
+
* Different elements should be enhanced in different ways. For example, we should have `kvalue` to handle `<input>` values.
|
|
239
|
+
* While we have no need to have `ktext` for `<br>` tags.
|
|
240
|
+
*
|
|
241
|
+
* ## Tags where appending a text node has no effect
|
|
242
|
+
*
|
|
243
|
+
* There are some HTML elements that appending a text node as their child takes no effect.
|
|
244
|
+
* They are mostly void elements, but some non-void elements are also included.
|
|
245
|
+
*
|
|
246
|
+
* ## What means no effect
|
|
247
|
+
* 1. appending a text node to these tags takes no effect.
|
|
248
|
+
* 2. No effect means `innerText` does not include the text in the text node.
|
|
249
|
+
*
|
|
250
|
+
* After testing 15 browsers testing, I found that these elements are:
|
|
251
|
+
*
|
|
252
|
+
* - FireFox(as base):
|
|
253
|
+
* - script -- this is skipped due to some bugs in The World 7
|
|
254
|
+
* - area, audio, base, basefont, br, canvas, datalist, details, dialog, frameset, head, iframe, img, input, link, meta, meter, noembed, noframes, noscript, optgroup, param, progress, rp, select, style, template, textarea, title, video, wbr
|
|
255
|
+
* - 360: embed
|
|
256
|
+
* - 2345: embed
|
|
257
|
+
* - maxthon: embed
|
|
258
|
+
* - quark: embed
|
|
259
|
+
* - uc: embed
|
|
260
|
+
* - chrome: embed,frame
|
|
261
|
+
* - qq: embed
|
|
262
|
+
* - sogou: embed
|
|
263
|
+
* - cent: embed
|
|
264
|
+
* - world: embed,frame,keygen,option
|
|
265
|
+
* - opera: embed
|
|
266
|
+
* - edge: embed
|
|
267
|
+
* - liebao: embed
|
|
268
|
+
* - 360turbo: embed,frame
|
|
269
|
+
*
|
|
270
|
+
* Since `Set.prototype.has` is about 80 times faster than `Array.prototype.includes`,
|
|
271
|
+
* We put these tags into a `Set` object.
|
|
272
|
+
*/
|
|
273
|
+
var INVALID_TAGS = {
|
|
274
|
+
area: true,
|
|
275
|
+
audio: true,
|
|
276
|
+
base: true,
|
|
277
|
+
basefont: true,
|
|
278
|
+
br: true,
|
|
279
|
+
canvas: true,
|
|
280
|
+
datalist: true,
|
|
281
|
+
details: true,
|
|
282
|
+
dialog: true,
|
|
283
|
+
frameset: true,
|
|
284
|
+
head: true,
|
|
285
|
+
iframe: true,
|
|
286
|
+
img: true,
|
|
287
|
+
input: true,
|
|
288
|
+
link: true,
|
|
289
|
+
meta: true,
|
|
290
|
+
meter: true,
|
|
291
|
+
noembed: true,
|
|
292
|
+
noframes: true,
|
|
293
|
+
noscript: true,
|
|
294
|
+
optgroup: true,
|
|
295
|
+
param: true,
|
|
296
|
+
progress: true,
|
|
297
|
+
rp: true,
|
|
298
|
+
select: true,
|
|
299
|
+
style: true,
|
|
300
|
+
template: true,
|
|
301
|
+
textarea: true,
|
|
302
|
+
title: true,
|
|
303
|
+
video: true,
|
|
304
|
+
wbr: true,
|
|
305
|
+
embed: true,
|
|
306
|
+
frame: true,
|
|
307
|
+
keygen: true,
|
|
308
|
+
option: true,
|
|
309
|
+
};
|
|
310
|
+
function notSupportTextNode(tag) {
|
|
311
|
+
return INVALID_TAGS[tag];
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
exports.h = h;
|
|
315
|
+
exports.ktnull = ktnull;
|
|
316
|
+
exports.notSupportTextNode = notSupportTextNode;
|
|
317
|
+
|
|
318
|
+
return exports;
|
|
319
|
+
|
|
320
|
+
})({});
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1,298 @@
|
|
|
1
|
-
const
|
|
1
|
+
const $throw = (message) => {
|
|
2
|
+
throw new Error('kt.js: ' + message);
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
const $isArray = Array.isArray;
|
|
6
|
+
const $keys = Object.keys;
|
|
7
|
+
const $defines = Object.defineProperties;
|
|
8
|
+
const $mark = (func, tag) => $defines(func, { __ktjs_h__: { value: tag, configurable: true } });
|
|
9
|
+
const emptyPromiseHandler = () => ({});
|
|
10
|
+
if (typeof Promise === 'undefined') {
|
|
11
|
+
window.Promise = { resolve: emptyPromiseHandler, reject: emptyPromiseHandler };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
(() => {
|
|
15
|
+
const runtimeKey = '__ktjs__';
|
|
16
|
+
if (runtimeKey in window) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const __ktjs__ = Object.create(null);
|
|
20
|
+
// & We can add new functions when we need more
|
|
21
|
+
const descriptor = {
|
|
22
|
+
throws: { value: $throw, enumerable: true },
|
|
23
|
+
defines: { value: $defines, enumerable: true },
|
|
24
|
+
mark: { value: $mark, enumerable: true },
|
|
25
|
+
};
|
|
26
|
+
$defines(__ktjs__, descriptor);
|
|
27
|
+
$defines(window, { [runtimeKey]: { value: __ktjs__, enumerable: true } });
|
|
28
|
+
return {};
|
|
29
|
+
})();
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* This is a `falsy` value used to indicate "no node" in `h` function.
|
|
33
|
+
* - It's an object, so it's guaranteed to be unique and no need for polyfill of `symbol`.
|
|
34
|
+
*/
|
|
35
|
+
const ktnull = Object.create(null);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* & Remove `bind` because it is shockingly slower than wrapper
|
|
39
|
+
* & `window.document` is safe because it is not configurable and its setter is undefined
|
|
40
|
+
*/
|
|
41
|
+
const $appendChild = HTMLElement.prototype.appendChild;
|
|
42
|
+
const originAppend = HTMLElement.prototype.append;
|
|
43
|
+
const $append = // for ie 9/10/11
|
|
44
|
+
typeof originAppend === 'function'
|
|
45
|
+
? function (...args) {
|
|
46
|
+
const nodes = args.filter((a) => a !== ktnull);
|
|
47
|
+
return originAppend.apply(this, nodes);
|
|
48
|
+
}
|
|
49
|
+
: function (...nodes) {
|
|
50
|
+
if (nodes.length < 50) {
|
|
51
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
52
|
+
const node = nodes[i];
|
|
53
|
+
if (typeof node === 'string') {
|
|
54
|
+
$appendChild.call(this, document.createTextNode(node));
|
|
55
|
+
}
|
|
56
|
+
else if (node !== ktnull) {
|
|
57
|
+
$appendChild.call(this, node);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
const fragment = document.createDocumentFragment();
|
|
63
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
64
|
+
const node = nodes[i];
|
|
65
|
+
if (typeof node === 'string') {
|
|
66
|
+
$appendChild.call(fragment, document.createTextNode(node));
|
|
67
|
+
}
|
|
68
|
+
else if (node !== ktnull) {
|
|
69
|
+
$appendChild.call(fragment, node);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
$appendChild.call(this, fragment);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
function booleanHandler(element, key, value) {
|
|
77
|
+
if (key in element) {
|
|
78
|
+
element[key] = !!value;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
element.setAttribute(key, value);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function valueHandler(element, key, value) {
|
|
85
|
+
if (key in element) {
|
|
86
|
+
element[key] = value;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
element.setAttribute(key, value);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Attribute handlers map for optimized lookup
|
|
93
|
+
const handlers = {
|
|
94
|
+
checked: booleanHandler,
|
|
95
|
+
selected: booleanHandler,
|
|
96
|
+
value: valueHandler,
|
|
97
|
+
valueAsDate: valueHandler,
|
|
98
|
+
valueAsNumber: valueHandler,
|
|
99
|
+
defaultValue: valueHandler,
|
|
100
|
+
defaultChecked: booleanHandler,
|
|
101
|
+
defaultSelected: booleanHandler,
|
|
102
|
+
disabled: booleanHandler,
|
|
103
|
+
readOnly: booleanHandler,
|
|
104
|
+
multiple: booleanHandler,
|
|
105
|
+
required: booleanHandler,
|
|
106
|
+
autofocus: booleanHandler,
|
|
107
|
+
open: booleanHandler,
|
|
108
|
+
controls: booleanHandler,
|
|
109
|
+
autoplay: booleanHandler,
|
|
110
|
+
loop: booleanHandler,
|
|
111
|
+
muted: booleanHandler,
|
|
112
|
+
defer: booleanHandler,
|
|
113
|
+
async: booleanHandler,
|
|
114
|
+
hidden: function (element, _key, value) {
|
|
115
|
+
element.hidden = !!value;
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
const defaultHandler = function (element, key, value) {
|
|
119
|
+
return element.setAttribute(key, value);
|
|
120
|
+
};
|
|
121
|
+
function attrIsObject(element, attr) {
|
|
122
|
+
const classValue = attr.class;
|
|
123
|
+
const style = attr.style;
|
|
124
|
+
if (classValue !== undefined) {
|
|
125
|
+
element.className = classValue;
|
|
126
|
+
delete attr.class;
|
|
127
|
+
}
|
|
128
|
+
if (style) {
|
|
129
|
+
if (typeof style === 'string') {
|
|
130
|
+
element.setAttribute('style', style);
|
|
131
|
+
}
|
|
132
|
+
else if (typeof style === 'object') {
|
|
133
|
+
for (const key in style) {
|
|
134
|
+
element.style[key] = style[key];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
delete attr.style;
|
|
138
|
+
}
|
|
139
|
+
const keys = $keys(attr);
|
|
140
|
+
for (let i = keys.length - 1; i >= 0; i--) {
|
|
141
|
+
const key = keys[i];
|
|
142
|
+
const o = attr[key];
|
|
143
|
+
// force register on:xxx as an event handler
|
|
144
|
+
// !if o is not valid, the throwing job will be done by `on`, not kt.js
|
|
145
|
+
if (key.startsWith('on:')) {
|
|
146
|
+
element.addEventListener(key.slice(3), o); // chop off the `@`
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (typeof o !== 'function') {
|
|
150
|
+
(handlers[key] || defaultHandler)(element, key, o);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
element.addEventListener(key, o);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (classValue !== undefined) {
|
|
157
|
+
attr.class = classValue;
|
|
158
|
+
}
|
|
159
|
+
if (style !== undefined) {
|
|
160
|
+
attr.style = style;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function applyAttr(element, attr) {
|
|
164
|
+
if (typeof attr === 'string') {
|
|
165
|
+
element.className = attr;
|
|
166
|
+
}
|
|
167
|
+
else if (typeof attr === 'object' && attr !== null) {
|
|
168
|
+
attrIsObject(element, attr);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
$throw('attr must be an object/string.');
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function applyContent(element, content) {
|
|
176
|
+
if ($isArray(content)) {
|
|
177
|
+
$append.apply(element, content);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
if (typeof content === 'number') {
|
|
181
|
+
$append.call(element, content.toString());
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
$append.call(element, content);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Create an enhanced HTMLElement.
|
|
191
|
+
* - Only supports HTMLElements, **NOT** SVGElements or other Elements.
|
|
192
|
+
* @param tag tag of an `HTMLElement`
|
|
193
|
+
* @param attr attribute object or className
|
|
194
|
+
* @param content a string or an array of HTMLEnhancedElement as child nodes
|
|
195
|
+
*
|
|
196
|
+
* ## About
|
|
197
|
+
* @package @ktjs/core
|
|
198
|
+
* @author Kasukabe Tsumugi <futami16237@gmail.com>
|
|
199
|
+
* @version 0.6.16 (Last Update: 2025.12.24 22:15:40.697)
|
|
200
|
+
* @license MIT
|
|
201
|
+
* @link https://github.com/baendlorel/kt.js
|
|
202
|
+
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
203
|
+
* @description Core functionality for kt.js - DOM manipulation utilities
|
|
204
|
+
* @copyright Copyright (c) 2025 Kasukabe Tsumugi. All rights reserved.
|
|
205
|
+
*/
|
|
206
|
+
const h = (tag, attr = '', content = '') => {
|
|
207
|
+
if (typeof tag !== 'string') {
|
|
208
|
+
$throw('__func__ tagName must be a string.');
|
|
209
|
+
}
|
|
210
|
+
// * start creating the element
|
|
211
|
+
const element = document.createElement(tag);
|
|
212
|
+
// * Handle content
|
|
213
|
+
applyAttr(element, attr);
|
|
214
|
+
applyContent(element, content);
|
|
215
|
+
return element;
|
|
216
|
+
};
|
|
217
|
+
$mark(h, 'h');
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* # Specialized Ehancement
|
|
221
|
+
*
|
|
222
|
+
* Different elements should be enhanced in different ways. For example, we should have `kvalue` to handle `<input>` values.
|
|
223
|
+
* While we have no need to have `ktext` for `<br>` tags.
|
|
224
|
+
*
|
|
225
|
+
* ## Tags where appending a text node has no effect
|
|
226
|
+
*
|
|
227
|
+
* There are some HTML elements that appending a text node as their child takes no effect.
|
|
228
|
+
* They are mostly void elements, but some non-void elements are also included.
|
|
229
|
+
*
|
|
230
|
+
* ## What means no effect
|
|
231
|
+
* 1. appending a text node to these tags takes no effect.
|
|
232
|
+
* 2. No effect means `innerText` does not include the text in the text node.
|
|
233
|
+
*
|
|
234
|
+
* After testing 15 browsers testing, I found that these elements are:
|
|
235
|
+
*
|
|
236
|
+
* - FireFox(as base):
|
|
237
|
+
* - script -- this is skipped due to some bugs in The World 7
|
|
238
|
+
* - area, audio, base, basefont, br, canvas, datalist, details, dialog, frameset, head, iframe, img, input, link, meta, meter, noembed, noframes, noscript, optgroup, param, progress, rp, select, style, template, textarea, title, video, wbr
|
|
239
|
+
* - 360: embed
|
|
240
|
+
* - 2345: embed
|
|
241
|
+
* - maxthon: embed
|
|
242
|
+
* - quark: embed
|
|
243
|
+
* - uc: embed
|
|
244
|
+
* - chrome: embed,frame
|
|
245
|
+
* - qq: embed
|
|
246
|
+
* - sogou: embed
|
|
247
|
+
* - cent: embed
|
|
248
|
+
* - world: embed,frame,keygen,option
|
|
249
|
+
* - opera: embed
|
|
250
|
+
* - edge: embed
|
|
251
|
+
* - liebao: embed
|
|
252
|
+
* - 360turbo: embed,frame
|
|
253
|
+
*
|
|
254
|
+
* Since `Set.prototype.has` is about 80 times faster than `Array.prototype.includes`,
|
|
255
|
+
* We put these tags into a `Set` object.
|
|
256
|
+
*/
|
|
257
|
+
const INVALID_TAGS = {
|
|
258
|
+
area: true,
|
|
259
|
+
audio: true,
|
|
260
|
+
base: true,
|
|
261
|
+
basefont: true,
|
|
262
|
+
br: true,
|
|
263
|
+
canvas: true,
|
|
264
|
+
datalist: true,
|
|
265
|
+
details: true,
|
|
266
|
+
dialog: true,
|
|
267
|
+
frameset: true,
|
|
268
|
+
head: true,
|
|
269
|
+
iframe: true,
|
|
270
|
+
img: true,
|
|
271
|
+
input: true,
|
|
272
|
+
link: true,
|
|
273
|
+
meta: true,
|
|
274
|
+
meter: true,
|
|
275
|
+
noembed: true,
|
|
276
|
+
noframes: true,
|
|
277
|
+
noscript: true,
|
|
278
|
+
optgroup: true,
|
|
279
|
+
param: true,
|
|
280
|
+
progress: true,
|
|
281
|
+
rp: true,
|
|
282
|
+
select: true,
|
|
283
|
+
style: true,
|
|
284
|
+
template: true,
|
|
285
|
+
textarea: true,
|
|
286
|
+
title: true,
|
|
287
|
+
video: true,
|
|
288
|
+
wbr: true,
|
|
289
|
+
embed: true,
|
|
290
|
+
frame: true,
|
|
291
|
+
keygen: true,
|
|
292
|
+
option: true,
|
|
293
|
+
};
|
|
294
|
+
function notSupportTextNode(tag) {
|
|
295
|
+
return INVALID_TAGS[tag];
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export { h, ktnull, notSupportTextNode };
|