@apigo.cc/state 1.0.11
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 +173 -0
- package/dist/state.js +681 -0
- package/dist/state.min.js +1 -0
- package/package.json +22 -0
package/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# State.js AI 开发指南
|
|
2
|
+
|
|
3
|
+
> ⚠️ **AI 强制指令 (AI Mandate):**
|
|
4
|
+
> 1. **尊重原创逻辑**:本项目(State.js)核心架构极其精炼且经过精雕细琢。**严禁擅自修改原有逻辑**(如 `_returnCode`, `_runCode`, `NewState` 等底层函数),除非你能证明修改后的质量、性能与简洁度均显著优于原版。
|
|
5
|
+
> 2. **禁止过度设计**:不要尝试引入复杂的编译器、多语句解析器或防御性代码。任何试图将“简单问题复杂化”的重构大概率会破坏现有结构。
|
|
6
|
+
> 3. **汇报与许可**:若你认为有必要修改库的核心逻辑,**必须首先向人类开发者汇报修改的必要性与潜在影响**,只有在得到明确允许后方可进行。
|
|
7
|
+
> 4. **回归测试**:任何改动必须通过现有 Playwright 自动化测试,确保 `DataTable` 等复杂组件场景的渲染与合并逻辑完全正常。
|
|
8
|
+
|
|
9
|
+
State.js 是基于 Vanilla JS 的无编译数据驱动 UI 框架。依赖原生 DOM 与 Proxy,通过解析 HTML `$指令` 属性映射状态。
|
|
10
|
+
|
|
11
|
+
> **核心设定:** 你是一个追求极致代码压缩和执行效率的资深极客。
|
|
12
|
+
> **编码原则:**
|
|
13
|
+
> 1. **拒绝废话变量:** 除非一个变量会被复用两次以上,否则**绝对禁止**声明临时变量。
|
|
14
|
+
> 2. **极致精简:** 极度偏爱链式调用(Chaining)、短路求值、三元运算符和 One-liner。能一行写完的逻辑,绝不拆成三行。
|
|
15
|
+
> 3. **无解释模式:** 假设你的对话者是顶尖黑客,不需要解释基础 API,不需要防御性废话,直接给出最硬核的最终代码即可。
|
|
16
|
+
|
|
17
|
+
## 一、 核心语法与指令字典
|
|
18
|
+
|
|
19
|
+
### 1\. 属性与数据绑定矩阵
|
|
20
|
+
|
|
21
|
+
| 语法 | 类型 | 解析与执行规则 |
|
|
22
|
+
| :--- | :--- | :--- |
|
|
23
|
+
| `$attr="exp"` | 动态 JS 表达式 | 映射为 HTML 属性。若包含 `\${}`,作为模板字符串计算;若不包含,作为纯 JS 表达式执行并保留返回值类型。 |
|
|
24
|
+
| `.prop="val"` | 静态 DOM 属性 | 将字符串字面量赋值给底层 DOM 节点的 JS 属性。 |
|
|
25
|
+
| `$.prop="exp"` | 动态 DOM 属性 | 将 JS 执行结果赋值给底层 DOM 节点的 JS 属性。<br>**对象自动初始化**:对深层路径(如 `$.state.schema`)赋值时,若路径上的中间节点不存在,框架会自动生成空对象(`{}`)以防止报错。 |
|
|
26
|
+
| `$bind="exp"` | 双向数据绑定 | 适用于原生表单元素及遵循 `$bind` 契约的组件(如 `<Modal>` 的显示状态绑定、`<AutoForm>` 的数据绑定)。 |
|
|
27
|
+
|
|
28
|
+
### 2. attr绑定规范 (例如 `$style` vs `style`)
|
|
29
|
+
* **唯一正确写法**:动态样式强制使用 `$style` 指令,并利用模板字符串 `${}` 进行变量插值,而不是字符串拼接。
|
|
30
|
+
* ❌ 不推荐:`$style="'transform:translateY(' + this.state.offsetY + 'px)'"`
|
|
31
|
+
* ❌ 不推荐:`$.style.transform="'transform:translateY(' + this.state.offsetY + 'px)'"`
|
|
32
|
+
* ✅ 正确:`$style="transform: translateY(\${this.state.offsetY}px);"`
|
|
33
|
+
* **覆盖原则**:`$style` 的优先级高于原生 `style` 属性。如果同一个节点同时存在 `$style` 和 `style`,`$style` 会**完全覆盖** `style` 的内容。因此,最佳实践是将该节点的所有静态和动态样式全部合并写在 `$style` 中。
|
|
34
|
+
|
|
35
|
+
### 3\. 控制流指令
|
|
36
|
+
|
|
37
|
+
* **`$if="exp"`**: 动态挂载/卸载 DOM 节点(布尔值映射)。
|
|
38
|
+
* **`$each="exp"`**: 遍历 Iterable 对象(Array, Object, Map, Set)。
|
|
39
|
+
* **默认变量**:单层循环时,默认可直接使用隐式变量 `item`(当前项)和 `index`(索引)。
|
|
40
|
+
* **嵌套约束**:当 `$each`存在嵌套时,**必须**使用 `as` 和 `index` 属性显式重命名迭代变量以防止遮蔽(Shadowing)。例:`<div $each="list" as="row" index="rowIdx">`。
|
|
41
|
+
* **作用域继承**:内层循环可直接访问外层作用域的变量及组件实例上下文。
|
|
42
|
+
|
|
43
|
+
### 4\. 文本、属性与 i18n 多语言
|
|
44
|
+
|
|
45
|
+
* **`$text="exp"`**: 将 JS 表达式结果渲染为 `textContent`。
|
|
46
|
+
* **原地解析 (`$text`)**: 仅声明属性不赋值,框架会提取节点原有文本,将其中的 `\${}` 表达式进行响应式计算。
|
|
47
|
+
* **i18n 多语言 (`{#...#}`)**:
|
|
48
|
+
* **自动解析**:框架在扫描 DOM 树时,会自动解析文本节点(TextNode)及静态属性(如 `placeholder`, `title`)中的 `{#...#}` 标签。
|
|
49
|
+
* **SetTranslator(fn)**: 导出一个全局 API,用于设置前端翻译逻辑。若不设置,框架会自动剥离 `{# #}` 符号并保留原文。
|
|
50
|
+
* **基础格式**:`{#文本#}`
|
|
51
|
+
* **带参格式**:`{#模板文本{变量名1}{变量名2} || 参数1 || 参数2#}`
|
|
52
|
+
* **示例**:`{#欢迎 {name} 来到 {place} || 怼怼 || 地球#}`。翻译器将接收到 `rawText="欢迎 {name} 来到 {place}"` 和 `args={name: "怼怼", place: "地球"}`。
|
|
53
|
+
|
|
54
|
+
## 二、 核心 API 导出清单
|
|
55
|
+
|
|
56
|
+
### 1. 状态管理 (Observer)
|
|
57
|
+
* **`NewState(defaults: Object, getter?: Function, setter?: Function): Proxy`**
|
|
58
|
+
* 创建单层响应式 Proxy。
|
|
59
|
+
* `getter(key)`: 自定义读取逻辑。
|
|
60
|
+
* `setter(key, value)`: 自定义写入逻辑。
|
|
61
|
+
* **`Hash: Proxy`**
|
|
62
|
+
* 映射 URL Hash 的响应式状态,修改属性将同步至 URL。
|
|
63
|
+
* **`LocalStorage: Proxy`**
|
|
64
|
+
* 映射 LocalStorage 的响应式状态,修改属性将持久化存储。
|
|
65
|
+
* **`<State>.__watch(key: string|null, callback: Function)`**
|
|
66
|
+
* 监听指定属性变化。若 `key` 为 `null`,则监听所有属性变化。
|
|
67
|
+
* **`<State>.__unwatch(key: string, callback: Function)`**
|
|
68
|
+
* 取消监听。
|
|
69
|
+
|
|
70
|
+
### 2. 系统 API (Global)
|
|
71
|
+
* **`RefreshState(node: HTMLElement)`**
|
|
72
|
+
* 手动触发指定节点及其子树的指令扫描与绑定。
|
|
73
|
+
* **`SetTranslator(fn: (rawText: string, args: Object) => string)`**
|
|
74
|
+
* 设置全局 i18n 翻译器。
|
|
75
|
+
|
|
76
|
+
### 3. 组件系统 (Component)
|
|
77
|
+
* **`Component.register(name: string, setupFunc: Function, template?: HTMLElement)`**
|
|
78
|
+
* 注册自定义组件。
|
|
79
|
+
* `setupFunc(container)`: 组件逻辑初始化入口。
|
|
80
|
+
* `template`: 组件的 DOM 模板。
|
|
81
|
+
|
|
82
|
+
### 4. 工具类 (Util)
|
|
83
|
+
* **`Util.makeDom(html: string): HTMLElement`**: HTML 字符串转 DOM。
|
|
84
|
+
* **`Util.copyFunction(to: Object, from: Object, ...names: string[])`**: 批量绑定方法。
|
|
85
|
+
* **`Util.safeJson(str: string): any`**: 安全解析 JSON。
|
|
86
|
+
|
|
87
|
+
### 5. DOM 查询
|
|
88
|
+
* **`$(selector: string, context?: HTMLElement): HTMLElement`**: querySelector 封装。
|
|
89
|
+
* **`$$(selector: string, context?: HTMLElement): NodeList`**: querySelectorAll 封装。
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
## 三、 自定义组件开发约束 (SOP)
|
|
93
|
+
|
|
94
|
+
### 1\. 组件模板转义规则 (Template Literal Escaping)
|
|
95
|
+
|
|
96
|
+
由于模板使用 JS 字符串声明,若模板内部需使用框架的 `\${}` 语法绑定动态属性,**必须进行反斜杠转义 (`\${...}`)**,防止被原生 JS 提前求值。
|
|
97
|
+
|
|
98
|
+
* **正确**:`<div $class="\${this.state.type}">`
|
|
99
|
+
|
|
100
|
+
### 2\. `$bind` 接口契约
|
|
101
|
+
|
|
102
|
+
若自定义组件需支持 `$bind` 双向绑定,需在 `setupFunc` 中实现:
|
|
103
|
+
|
|
104
|
+
* **数据输入 (响应更新)**:`container.addEventListener('bind', (e) => { const val = e.detail; ... })`
|
|
105
|
+
* **数据输出 (触发更新)**:`container.dispatchEvent(new CustomEvent('change', { bubbles: false, detail: newValue }))`
|
|
106
|
+
* **插槽注入规则**:消费者调用组件时,**必须**使用 `<div slot-id="插槽名">` 的形式显式向组件内注入对应节点。如果组件只有一个插槽位时调用代码可以直接写内容不需要使用模版来定义插槽。
|
|
107
|
+
|
|
108
|
+
### 3. 容器与 DOM 就绪机制 (DOM Readiness)
|
|
109
|
+
* **`container` 的本质**:在 `setupFunc` 中,传入的 `container` 参数**即为调用组件的 DOM 节点**。组件模板的根节点会合并到该节点变成同一个节点,但是调用组件时属性中的this指向上层组件,而组件内的this指向组件实例。
|
|
110
|
+
* **同步就绪**:当进入 `setupFunc` 时,组件的 DOM 树(包括插槽内容)已经**完全初始化并挂载就绪**,可以在 `setupFunc` 中直接使用。
|
|
111
|
+
|
|
112
|
+
### 4. 插槽 (Slot) 的渲染时序
|
|
113
|
+
* 组件框架在进入 setupFunc 之前就已经完成了插槽内容(`<div slot-id="...">`)的初始化注入。因此,在 setupFunc 中直接使用插槽内容是完全安全且符合预期的。
|
|
114
|
+
|
|
115
|
+
### 5. 高级状态管理与生命周期能力
|
|
116
|
+
* **隐式节点变量 (`thisNode`)**:
|
|
117
|
+
在 `$each` 循环或属性指令中,可以直接使用隐式变量 `thisNode` 获取当前执行上下文绑定的 DOM 节点对象自身。
|
|
118
|
+
|
|
119
|
+
## 四、 极简主义与高性能开发哲学
|
|
120
|
+
|
|
121
|
+
1. **拒绝过度工程 (No Over-engineering)**:严禁使用复杂的树结构或大段防御性代码。
|
|
122
|
+
2. **DOM 访问极小化**:优先通过 `this.state` 驱动 UI,避免在 JS 中手动调用 `element.style.xxx`。
|
|
123
|
+
3. **闭包与内存的权衡**:优先将逻辑挂载到 `container` 或 `container.state` 上。
|
|
124
|
+
4. **组件内聚**:能用指令解决的 UI 逻辑绝不写在 JS 里。
|
|
125
|
+
5. **思维重塑**:彻底抛弃 Vue/React 的生命周期崇拜,回归 DOM 本质。
|
|
126
|
+
6. **无分号运动**:除了必须的情况,代码结尾禁止使用分号 `;`。
|
|
127
|
+
|
|
128
|
+
## 五、 开发范例
|
|
129
|
+
|
|
130
|
+
### 范例 1:带插槽与 UI 的组件 (以 Modal 为例)
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
Component.register('Modal', container => {
|
|
134
|
+
container.modal = new bootstrap.Modal(container)
|
|
135
|
+
container.addEventListener('bind', e => e.detail ? container.modal.show() : container.modal.hide())
|
|
136
|
+
container.addEventListener('hide.bs.modal', () => {
|
|
137
|
+
document.activeElement?.blur()
|
|
138
|
+
container.dispatchEvent(new CustomEvent('change', { bubbles: false, detail: false }))
|
|
139
|
+
})
|
|
140
|
+
Util.copyFunction(container, container.modal, 'show', 'hide')
|
|
141
|
+
}, Util.makeDom(/*html*/`
|
|
142
|
+
<div class="modal fade" data-bs-backdrop="static">
|
|
143
|
+
<div class="modal-dialog modal-dialog-centered">
|
|
144
|
+
<div $class="modal-content text-bg-\${this.state?.type || 'body'}">
|
|
145
|
+
<div slot-id="header" class="modal-header">
|
|
146
|
+
<h6 class="modal-title" $text="this.state?.title"></h6>
|
|
147
|
+
<button type="button" class="btn-close btn-sm ms-2" data-bs-dismiss="modal"></button>
|
|
148
|
+
</div>
|
|
149
|
+
<div slot-id="body" class="modal-body"></div>
|
|
150
|
+
<div slot-id="footer" class="modal-footer"></div>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
`))
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 范例 2:无模板纯逻辑组件 (以 API 为例)
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
Component.register('API', container => {
|
|
161
|
+
container.request = NewState({ url: '', method: 'GET', headers: {}, data: null, timeout: 10000 })
|
|
162
|
+
container.response = NewState({ loading: false, result: null })
|
|
163
|
+
container.do = async (opt = {}) => {
|
|
164
|
+
const req = { ...container.request, ...opt }
|
|
165
|
+
container.response.loading = true
|
|
166
|
+
const resp = await fetch(req.url, req)
|
|
167
|
+
container.response.result = await resp.json()
|
|
168
|
+
container.response.loading = false
|
|
169
|
+
container.dispatchEvent(new CustomEvent('response', { detail: container.response }))
|
|
170
|
+
}
|
|
171
|
+
container.request.__watch(null, () => container.hasAttribute('auto') && container.request.url && container.do())
|
|
172
|
+
})
|
|
173
|
+
```
|
package/dist/state.js
ADDED
|
@@ -0,0 +1,681 @@
|
|
|
1
|
+
var _a;
|
|
2
|
+
let _activeBinding = null;
|
|
3
|
+
let _noWriteBack = null;
|
|
4
|
+
const setActiveBinding = (val) => _activeBinding = val;
|
|
5
|
+
const setNoWriteBack = (val) => _noWriteBack = val;
|
|
6
|
+
const _notifiers = /* @__PURE__ */ new Set();
|
|
7
|
+
const onNotifyUpdate = (fn) => _notifiers.add(fn);
|
|
8
|
+
function NewState(defaults = {}, getter = null, setter = null) {
|
|
9
|
+
const _defaults = {};
|
|
10
|
+
const _stateMappings = /* @__PURE__ */ new Map();
|
|
11
|
+
const _watchers = /* @__PURE__ */ new Map();
|
|
12
|
+
const _watchFunc = (k, cb) => {
|
|
13
|
+
if (!_watchers.has(k)) _watchers.set(k, /* @__PURE__ */ new Set());
|
|
14
|
+
!cb ? _watchers.get(k).clear() : _watchers.get(k).add(cb);
|
|
15
|
+
return () => _watchers.get(k).delete(cb);
|
|
16
|
+
};
|
|
17
|
+
const _unwatchFunc = (k, cb) => {
|
|
18
|
+
if (_watchers.has(k)) _watchers.get(k).delete(cb);
|
|
19
|
+
};
|
|
20
|
+
const __getter = getter || ((k) => _defaults[k]);
|
|
21
|
+
const __setter = setter || ((k, v) => _defaults[k] = v);
|
|
22
|
+
Object.assign(_defaults, defaults);
|
|
23
|
+
return new Proxy(_defaults, {
|
|
24
|
+
get(target, key) {
|
|
25
|
+
if (key === "__watch") return _watchFunc;
|
|
26
|
+
if (key === "__unwatch") return _unwatchFunc;
|
|
27
|
+
if (key === "__isProxy") return true;
|
|
28
|
+
if (_activeBinding) {
|
|
29
|
+
if (!_stateMappings.has(key)) _stateMappings.set(key, /* @__PURE__ */ new Set());
|
|
30
|
+
_stateMappings.get(key).add(_activeBinding);
|
|
31
|
+
if (!_activeBinding.node._states) _activeBinding.node._states = /* @__PURE__ */ new Set();
|
|
32
|
+
_activeBinding.node._states.add(_stateMappings);
|
|
33
|
+
}
|
|
34
|
+
return __getter(key);
|
|
35
|
+
},
|
|
36
|
+
set(target, key, value) {
|
|
37
|
+
if (__getter(key) !== value) {
|
|
38
|
+
__setter(key, value);
|
|
39
|
+
}
|
|
40
|
+
if (_watchers.has(key)) {
|
|
41
|
+
_watchers.get(key).forEach((cb) => {
|
|
42
|
+
const r = cb(value);
|
|
43
|
+
if (r !== void 0) {
|
|
44
|
+
value = r;
|
|
45
|
+
target[key] = value;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
if (_watchers.has(null)) {
|
|
50
|
+
_watchers.get(null).forEach((cb) => cb(value));
|
|
51
|
+
}
|
|
52
|
+
if (_stateMappings.has(key)) {
|
|
53
|
+
const bindings = _stateMappings.get(key);
|
|
54
|
+
for (const binding of bindings) {
|
|
55
|
+
if (!binding.node.isConnected) {
|
|
56
|
+
bindings.delete(binding);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (_noWriteBack !== binding.node) {
|
|
60
|
+
_notifiers.forEach((fn) => fn(binding));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const $ = (a, b) => b ? a.querySelector(b) : document.querySelector(a);
|
|
69
|
+
const $$ = (a, b) => b ? a.querySelectorAll(b) : document.querySelectorAll(a);
|
|
70
|
+
const _components = /* @__PURE__ */ new Map();
|
|
71
|
+
const _pendingTemplates = [];
|
|
72
|
+
const Component = {
|
|
73
|
+
getTemplate: (name) => document.querySelector(`template[component="${name.toUpperCase()}"]`),
|
|
74
|
+
register: (name, setupFunc, templateNode = null, ...globalNodes) => {
|
|
75
|
+
_components.set(name.toUpperCase(), setupFunc);
|
|
76
|
+
if (document.readyState !== "loading") Component._addTemplate(name, templateNode, globalNodes);
|
|
77
|
+
else _pendingTemplates.push([name, templateNode, globalNodes]);
|
|
78
|
+
},
|
|
79
|
+
exists: (name) => _components.has(name.toUpperCase()),
|
|
80
|
+
getSetupFunction: (name) => _components.get(name.toUpperCase()),
|
|
81
|
+
_addTemplate: (name, templateNode, globalNodes) => {
|
|
82
|
+
if (templateNode) {
|
|
83
|
+
const template = document.createElement("TEMPLATE");
|
|
84
|
+
template.setAttribute("component", name.toUpperCase());
|
|
85
|
+
template.content.appendChild(templateNode);
|
|
86
|
+
document.body.appendChild(template);
|
|
87
|
+
}
|
|
88
|
+
if (globalNodes) globalNodes.forEach((node) => document.body.appendChild(node));
|
|
89
|
+
},
|
|
90
|
+
_initPending: () => {
|
|
91
|
+
_pendingTemplates.forEach(([name, templateNode, globalNodes]) => Component._addTemplate(name, templateNode, globalNodes));
|
|
92
|
+
_pendingTemplates.length = 0;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
function _mergeNode(from, to, scanObj, exists = {}) {
|
|
96
|
+
if (from.attributes) {
|
|
97
|
+
Array.from(from.attributes).forEach((attr) => {
|
|
98
|
+
if (attr.name === "class") return;
|
|
99
|
+
if (attr.name === "style") {
|
|
100
|
+
if (to.hasAttribute("style")) to.setAttribute("style", `${attr.value}; ${to.getAttribute("style")}`);
|
|
101
|
+
else to.setAttribute("style", attr.value);
|
|
102
|
+
} else if (!to.hasAttribute(attr.name)) {
|
|
103
|
+
to.setAttribute(attr.name, attr.value);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
to.classList.add(...from.classList);
|
|
108
|
+
const fromContent = from.tagName === "TEMPLATE" ? from.content : from;
|
|
109
|
+
const toContent = to.tagName === "TEMPLATE" ? to.content : to;
|
|
110
|
+
Array.from(fromContent.childNodes).forEach((child) => toContent.appendChild(child));
|
|
111
|
+
if (from.tagName && Component.exists(from.tagName)) _makeComponent(from.tagName, to, scanObj, exists);
|
|
112
|
+
}
|
|
113
|
+
function _makeComponent(name, node, scanObj, exists = {}) {
|
|
114
|
+
if (exists[name]) return;
|
|
115
|
+
exists[name] = true;
|
|
116
|
+
if (scanObj.thisObj) {
|
|
117
|
+
Array.from(node.attributes).forEach((attr) => {
|
|
118
|
+
if ((attr.name.startsWith("$") || attr.name.startsWith("st-")) && attr.value.includes("this.")) {
|
|
119
|
+
attr.value = attr.value.replace(/\bthis\./g, "this.parent.");
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const componentFunc = Component.getSetupFunction(name);
|
|
124
|
+
const slots = {};
|
|
125
|
+
Array.from(node.childNodes).forEach((child) => {
|
|
126
|
+
if (child.nodeType === Node.ELEMENT_NODE && child.hasAttribute("slot")) {
|
|
127
|
+
slots[child.getAttribute("slot")] = child;
|
|
128
|
+
child.removeAttribute("slot");
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
node.innerHTML = "";
|
|
132
|
+
node.state = NewState(node.state || {});
|
|
133
|
+
const template = Component.getTemplate(name);
|
|
134
|
+
if (template) {
|
|
135
|
+
const tplnode = template.content.cloneNode(true);
|
|
136
|
+
if (tplnode.childNodes.length) {
|
|
137
|
+
const rootNode = Array.from(tplnode.childNodes).find((n) => n.nodeType === Node.ELEMENT_NODE);
|
|
138
|
+
if (rootNode) _mergeNode(rootNode, node, scanObj, exists);
|
|
139
|
+
$$(node, "[slot-id]").forEach((placeholder) => {
|
|
140
|
+
const slotName = placeholder.getAttribute("slot-id");
|
|
141
|
+
if (slots[slotName]) {
|
|
142
|
+
placeholder.removeAttribute("slot-id");
|
|
143
|
+
placeholder.innerHTML = "";
|
|
144
|
+
_mergeNode(slots[slotName], placeholder, scanObj, exists);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (componentFunc) componentFunc(node);
|
|
150
|
+
}
|
|
151
|
+
let _disableRunCodeError = false;
|
|
152
|
+
function setDisableRunCodeError(value) {
|
|
153
|
+
_disableRunCodeError = value;
|
|
154
|
+
}
|
|
155
|
+
const _fnCache = /* @__PURE__ */ new Map();
|
|
156
|
+
function _runCode(code, vars, thisObj, extendVars) {
|
|
157
|
+
const allVars = { ...extendVars || {}, ...vars || {} };
|
|
158
|
+
const argKeys = Object.keys(allVars);
|
|
159
|
+
const argValues = Object.values(allVars);
|
|
160
|
+
const cacheKey = code + argKeys.join(",");
|
|
161
|
+
try {
|
|
162
|
+
let fn = _fnCache.get(cacheKey);
|
|
163
|
+
if (!fn) {
|
|
164
|
+
fn = new Function("Hash", "LocalStorage", "State", ...argKeys, code);
|
|
165
|
+
_fnCache.set(cacheKey, fn);
|
|
166
|
+
}
|
|
167
|
+
return fn.apply(thisObj, [globalThis.Hash, globalThis.LocalStorage, globalThis.State, ...argValues]);
|
|
168
|
+
} catch (e) {
|
|
169
|
+
if (!_disableRunCodeError) console.error(e, extendVars, [code, extendVars, vars, thisObj]);
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function _returnCode(code, vars, thisObj, extendVars) {
|
|
174
|
+
if (code.includes("${")) return _runCode("return `" + code + "`", vars, thisObj, extendVars);
|
|
175
|
+
else return _runCode("return " + code, vars, thisObj, extendVars);
|
|
176
|
+
}
|
|
177
|
+
let _translator = (text, args) => {
|
|
178
|
+
if (!text || typeof text !== "string") return text;
|
|
179
|
+
return text.replace(/\{(.+?)\}/g, (match, key) => args.hasOwnProperty(key) ? args[key] : match);
|
|
180
|
+
};
|
|
181
|
+
const SetTranslator = (fn) => _translator = fn;
|
|
182
|
+
const _translate = (text) => {
|
|
183
|
+
if (!text || typeof text !== "string" || !text.includes("{#")) return text;
|
|
184
|
+
return text.replace(/\{#(.+?)#\}/g, (m, content) => {
|
|
185
|
+
const parts = content.split("||").map((s) => s.trim());
|
|
186
|
+
const args = {};
|
|
187
|
+
if (parts.length > 1) {
|
|
188
|
+
const matches = parts[0].match(/\{(.+?)\}/g);
|
|
189
|
+
if (matches) matches.forEach((match, i) => args[match.substring(1, match.length - 1)] = parts[i + 1] || "");
|
|
190
|
+
}
|
|
191
|
+
return _translator(parts[0], args);
|
|
192
|
+
});
|
|
193
|
+
};
|
|
194
|
+
if (typeof document !== "undefined") {
|
|
195
|
+
try {
|
|
196
|
+
document.createElement("div").setAttribute("$t", "1");
|
|
197
|
+
} catch (e) {
|
|
198
|
+
const originalSetAttribute = Element.prototype.setAttribute;
|
|
199
|
+
Element.prototype.setAttribute = function(name, value) {
|
|
200
|
+
if (!name.startsWith("$")) return originalSetAttribute.call(this, name, value);
|
|
201
|
+
return originalSetAttribute.call(this, "st-" + name.substring(1), value);
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
onNotifyUpdate((binding) => _updateBinding(binding));
|
|
206
|
+
function _clearRenderedNodes(node) {
|
|
207
|
+
if (node._renderedNodes) node._renderedNodes.forEach((nodes) => nodes.forEach((child) => {
|
|
208
|
+
child.remove();
|
|
209
|
+
if (child._renderedNodes) _clearRenderedNodes(child);
|
|
210
|
+
}));
|
|
211
|
+
}
|
|
212
|
+
function _updateBinding(binding) {
|
|
213
|
+
const node = binding.node;
|
|
214
|
+
if (!node.isConnected && node.tagName !== "TEMPLATE") return;
|
|
215
|
+
setActiveBinding(binding);
|
|
216
|
+
if (window.__perfTrace) window.__perfTrace.evalCount++;
|
|
217
|
+
const evalStart = window.__perfTrace ? performance.now() : 0;
|
|
218
|
+
let result = binding.exp ? binding.tpl ? _returnCode(binding.tpl, { thisNode: node }, node._thisObj || node, node._ref || null) : null : binding.tpl;
|
|
219
|
+
if (window.__perfTrace) window.__perfTrace.evalTotal += performance.now() - evalStart;
|
|
220
|
+
setActiveBinding(null);
|
|
221
|
+
if (binding.prop) {
|
|
222
|
+
const prop = binding.prop;
|
|
223
|
+
let o = node;
|
|
224
|
+
for (let i = 0; i < prop.length - 1; i++) {
|
|
225
|
+
if (!prop[i]) continue;
|
|
226
|
+
if (o[prop[i]] == null) o[prop[i]] = {};
|
|
227
|
+
o = o[prop[i]];
|
|
228
|
+
if (typeof o !== "object") break;
|
|
229
|
+
}
|
|
230
|
+
if (typeof o === "object" && o !== null) {
|
|
231
|
+
const lk = prop[prop.length - 1];
|
|
232
|
+
if (lk) {
|
|
233
|
+
if (typeof result === "object" && result != null && !Array.isArray(result) && o[lk] == null) o[lk] = {};
|
|
234
|
+
const lo = o[lk];
|
|
235
|
+
if (typeof lo === "object" && lo != null && lo.__watch) Object.assign(lo, result);
|
|
236
|
+
else o[lk] = result;
|
|
237
|
+
} else if (typeof result === "object" && result != null && !Array.isArray(result)) {
|
|
238
|
+
Object.assign(o, result);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
} else if (binding.attr) {
|
|
242
|
+
const attr = binding.attr;
|
|
243
|
+
if (attr === "if") {
|
|
244
|
+
if (result) {
|
|
245
|
+
if (!node._renderedNodes || node._renderedNodes.length === 0) {
|
|
246
|
+
node._children.forEach((child) => {
|
|
247
|
+
child._stManaged = true;
|
|
248
|
+
node.parentNode.insertBefore(child, node);
|
|
249
|
+
child._ref = { ...node._ref };
|
|
250
|
+
});
|
|
251
|
+
node._renderedNodes = [node._children];
|
|
252
|
+
} else {
|
|
253
|
+
node._renderedNodes[0].forEach((child) => _scanTree(child, { thisObj: node._thisObj, extendVars: child._ref }));
|
|
254
|
+
}
|
|
255
|
+
} else {
|
|
256
|
+
_clearRenderedNodes(node);
|
|
257
|
+
node._renderedNodes = [];
|
|
258
|
+
}
|
|
259
|
+
} else if (attr === "each") {
|
|
260
|
+
if (result && typeof result === "object") {
|
|
261
|
+
const asName = node.getAttribute("as") || "item";
|
|
262
|
+
const indexName = node.getAttribute("index") || "index";
|
|
263
|
+
const keyName = node.getAttribute("key");
|
|
264
|
+
let keys, getVal;
|
|
265
|
+
if (result instanceof Map) {
|
|
266
|
+
keys = Array.from(result.keys());
|
|
267
|
+
getVal = (k) => result.get(k);
|
|
268
|
+
} else if (typeof result[Symbol.iterator] === "function") {
|
|
269
|
+
const arr = Array.isArray(result) ? result : Array.from(result);
|
|
270
|
+
keys = new Array(arr.length);
|
|
271
|
+
for (let i = 0; i < arr.length; i++) keys[i] = i;
|
|
272
|
+
getVal = (k) => arr[k];
|
|
273
|
+
} else {
|
|
274
|
+
keys = Object.keys(result);
|
|
275
|
+
getVal = (k) => result[k];
|
|
276
|
+
}
|
|
277
|
+
if (!node._keyedNodes) node._keyedNodes = /* @__PURE__ */ new Map();
|
|
278
|
+
const newKeyedNodes = /* @__PURE__ */ new Map();
|
|
279
|
+
const currentRenderedNodes = [];
|
|
280
|
+
keys.forEach((k, i) => {
|
|
281
|
+
const item = getVal(k);
|
|
282
|
+
const rawKey = keyName ? item && typeof item === "object" ? item[keyName] : item : k;
|
|
283
|
+
const keyVal = rawKey === void 0 || rawKey === null || newKeyedNodes.has(rawKey) ? `st_key_fallback_${i}_${Math.random()}` : rawKey;
|
|
284
|
+
let existingNodes = node._keyedNodes.get(keyVal);
|
|
285
|
+
if (existingNodes) {
|
|
286
|
+
node._keyedNodes.delete(keyVal);
|
|
287
|
+
existingNodes.forEach((child) => {
|
|
288
|
+
if (window.__statePerformanceTelemetry) window.__statePerformanceTelemetry.reuseCount++;
|
|
289
|
+
let scopeChanged = false;
|
|
290
|
+
for (let key in node._ref) {
|
|
291
|
+
if (key === asName || key === indexName) continue;
|
|
292
|
+
if (child._ref[key] !== node._ref[key]) {
|
|
293
|
+
child._ref[key] = node._ref[key];
|
|
294
|
+
scopeChanged = true;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const indexChanged = child._ref[indexName] !== k;
|
|
298
|
+
if (indexChanged) child._ref[indexName] = k;
|
|
299
|
+
if (child._ref[asName] !== item || scopeChanged) {
|
|
300
|
+
child._ref[asName] = item;
|
|
301
|
+
if (window.__statePerformanceTelemetry) window.__statePerformanceTelemetry.scanCount++;
|
|
302
|
+
_scanTree(child, { thisObj: node._thisObj, extendVars: child._ref });
|
|
303
|
+
} else if (node.parentNode.lastChild !== child) {
|
|
304
|
+
if (window.__statePerformanceTelemetry) window.__statePerformanceTelemetry.moveCount++;
|
|
305
|
+
node.parentNode.insertBefore(child, node);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
} else {
|
|
309
|
+
existingNodes = [];
|
|
310
|
+
node._children.forEach((child) => {
|
|
311
|
+
const cloned = child.cloneNode(true);
|
|
312
|
+
cloned._stManaged = true;
|
|
313
|
+
cloned._ref = { ...node._ref, [indexName]: k, [asName]: item };
|
|
314
|
+
cloned._thisObj = node._thisObj;
|
|
315
|
+
node.parentNode.insertBefore(cloned, node);
|
|
316
|
+
existingNodes.push(cloned);
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
newKeyedNodes.set(keyVal, existingNodes);
|
|
320
|
+
currentRenderedNodes.push(existingNodes);
|
|
321
|
+
existingNodes.forEach((child) => node.parentNode.insertBefore(child, node));
|
|
322
|
+
});
|
|
323
|
+
node._keyedNodes.forEach((nodes) => nodes.forEach((child) => {
|
|
324
|
+
_clearRenderedNodes(child);
|
|
325
|
+
child.remove();
|
|
326
|
+
}));
|
|
327
|
+
node._keyedNodes = newKeyedNodes;
|
|
328
|
+
node._renderedNodes = currentRenderedNodes;
|
|
329
|
+
} else {
|
|
330
|
+
_clearRenderedNodes(node);
|
|
331
|
+
if (node._keyedNodes) node._keyedNodes.forEach((nodes) => nodes.forEach((child) => child.remove()));
|
|
332
|
+
node._keyedNodes = /* @__PURE__ */ new Map();
|
|
333
|
+
node._renderedNodes = [];
|
|
334
|
+
}
|
|
335
|
+
} else if (attr === "bind") {
|
|
336
|
+
if (["INPUT", "SELECT", "TEXTAREA"].includes(node.tagName) && !node.hasAttribute("autocomplete")) node.setAttribute("autocomplete", "off");
|
|
337
|
+
if (node.type === "checkbox") {
|
|
338
|
+
if (node.value !== "on" && !result) {
|
|
339
|
+
_runCode(`${binding.tpl} = []`, { thisNode: node }, node._thisObj || node, node._ref || {});
|
|
340
|
+
result = [];
|
|
341
|
+
}
|
|
342
|
+
node._checkboxMultiMode = result instanceof Array;
|
|
343
|
+
const isChecked = result instanceof Array ? result.includes(node.value) : !!result;
|
|
344
|
+
if (node.checked !== isChecked) node.checked = isChecked;
|
|
345
|
+
} else if (node.type === "radio") {
|
|
346
|
+
if (node.checked !== (node.value === String(result ?? ""))) node.checked = node.value === String(result ?? "");
|
|
347
|
+
} else if ("value" in node && node.type !== "file") {
|
|
348
|
+
setTimeout(() => {
|
|
349
|
+
if (node.value !== String(result ?? "")) node.value = result;
|
|
350
|
+
});
|
|
351
|
+
} else if (node.isContentEditable) {
|
|
352
|
+
if (node.innerHTML !== String(result ?? "")) node.innerHTML = result;
|
|
353
|
+
}
|
|
354
|
+
node.dispatchEvent(new CustomEvent("bind", { bubbles: false, detail: result }));
|
|
355
|
+
} else {
|
|
356
|
+
if (["checked", "disabled", "readonly"].includes(attr)) result = !!result;
|
|
357
|
+
if (typeof result === "boolean") result ? node.setAttribute(attr, "") : node.removeAttribute(attr);
|
|
358
|
+
else if (result !== void 0) {
|
|
359
|
+
if (typeof result !== "string") result = JSON.stringify(result);
|
|
360
|
+
if (attr === "text") node.textContent = result ?? "";
|
|
361
|
+
else if (attr === "html") node.innerHTML = result ?? "";
|
|
362
|
+
else if (node.tagName === "IMG" && attr === "src" && result.includes(".svg")) node.setAttribute("_src", result ?? "");
|
|
363
|
+
else node.setAttribute(attr, result ?? "");
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
const _initBinding = (binding) => {
|
|
369
|
+
if (!binding.node._bindings) binding.node._bindings = [];
|
|
370
|
+
binding.node._bindings.push({ attr: binding.attr, prop: binding.prop, tpl: binding.tpl, exp: binding.exp });
|
|
371
|
+
_updateBinding(binding);
|
|
372
|
+
};
|
|
373
|
+
const _parseNode = (node, scanObj) => {
|
|
374
|
+
let hasBindings = false;
|
|
375
|
+
if (node._bindings) {
|
|
376
|
+
node._states = /* @__PURE__ */ new Set();
|
|
377
|
+
node._bindings.forEach((b) => _updateBinding({ node, ...b }));
|
|
378
|
+
if (node._hasOnUpdate) node.dispatchEvent(new Event("update", { bubbles: false }));
|
|
379
|
+
hasBindings = true;
|
|
380
|
+
}
|
|
381
|
+
if (Component.exists(node.tagName) && !node._componentInitialized) {
|
|
382
|
+
Array.from(node.attributes).forEach((attr) => {
|
|
383
|
+
var _a2;
|
|
384
|
+
if (attr.name.startsWith("$.")) {
|
|
385
|
+
const realAttrName = attr.name.slice(2);
|
|
386
|
+
let tpl = _translate(attr.value);
|
|
387
|
+
if (tpl.includes("this.")) tpl = tpl.replace(/\bthis\./g, "this.parent.");
|
|
388
|
+
const result = _returnCode(tpl, { thisNode: node }, { parent: scanObj.thisObj || node }, node._ref || {});
|
|
389
|
+
let o = node;
|
|
390
|
+
const prop = realAttrName.split(".");
|
|
391
|
+
for (let i = 0; i < prop.length - 1; i++) {
|
|
392
|
+
if (prop[i]) o = o[_a2 = prop[i]] ?? (o[_a2] = {});
|
|
393
|
+
}
|
|
394
|
+
o[prop[prop.length - 1]] = result;
|
|
395
|
+
node.removeAttribute(attr.name);
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
_makeComponent(node.tagName, node, scanObj);
|
|
399
|
+
$$(node, "[slot-id]").forEach((p) => p.removeAttribute("slot-id"));
|
|
400
|
+
node._componentInitialized = true;
|
|
401
|
+
if (!node._thisObj) node._thisObj = node;
|
|
402
|
+
}
|
|
403
|
+
if (node.tagName === "TEMPLATE") {
|
|
404
|
+
node._children = [...node.content.childNodes];
|
|
405
|
+
if (!node._renderedNodes) node._renderedNodes = [];
|
|
406
|
+
}
|
|
407
|
+
if (hasBindings) return;
|
|
408
|
+
let attrs = [];
|
|
409
|
+
if (node.tagName === "TEMPLATE") {
|
|
410
|
+
["$if", "$each", "st-if", "st-each"].forEach((n) => node.hasAttribute(n) && attrs.push(node.getAttributeNode(n)));
|
|
411
|
+
} else {
|
|
412
|
+
attrs = Array.from(node.attributes).filter((a) => (a.name.startsWith("$") || a.name.startsWith("st-")) && !["$if", "$each", "st-if", "st-each"].includes(a.name) || a.name.includes("."));
|
|
413
|
+
}
|
|
414
|
+
if (node._thisObj && scanObj.thisObj) node._thisObj.parent = scanObj.thisObj;
|
|
415
|
+
if (!node._thisObj) node._thisObj = scanObj.thisObj || null;
|
|
416
|
+
if (!node._ref) node._ref = scanObj.extendVars || {};
|
|
417
|
+
node._states = /* @__PURE__ */ new Set();
|
|
418
|
+
attrs.forEach((attr) => {
|
|
419
|
+
const exp = attr.name.startsWith("$") || attr.name.startsWith("st-");
|
|
420
|
+
const realAttrName = exp ? attr.name.slice(attr.name.startsWith("$") ? 1 : 3) : attr.name;
|
|
421
|
+
let tpl = attr.value;
|
|
422
|
+
node.removeAttribute(attr.name);
|
|
423
|
+
if (realAttrName.startsWith(".")) _initBinding({ node, prop: realAttrName.split("."), tpl, exp });
|
|
424
|
+
else if (realAttrName.startsWith("on")) {
|
|
425
|
+
const eventName = realAttrName.slice(2);
|
|
426
|
+
if (eventName === "update") node._hasOnUpdate = true;
|
|
427
|
+
if (eventName === "load" && !["BODY", "IMG", "IFRAME"].includes(node.tagName)) node._hasOnLoad = true;
|
|
428
|
+
if (eventName === "unload" && !["BODY", "IMG", "IFRAME"].includes(node.tagName)) node._hasOnUnload = true;
|
|
429
|
+
node.addEventListener(eventName, (e) => _runCode(tpl, { event: e, thisNode: node, ...e.detail || {} }, scanObj.thisObj || node, node._ref || {}));
|
|
430
|
+
} else {
|
|
431
|
+
if (realAttrName === "bind") {
|
|
432
|
+
node.addEventListener(node.tagName === "TEXTAREA" || node.isContentEditable || node.type === "text" || node.type === "password" ? "input" : "change", (e) => {
|
|
433
|
+
let newVal = node.isContentEditable ? e.target.innerHTML : node.type === "checkbox" ? e.target.checked : e.target.files || e.target.value || e.detail;
|
|
434
|
+
setNoWriteBack(node);
|
|
435
|
+
setDisableRunCodeError(true);
|
|
436
|
+
if (node.type === "checkbox" && node._checkboxMultiMode) _runCode(`!!checked ? (!${tpl}.includes(val) && ${tpl}.push(val)) : (index = ${tpl}.indexOf(val), index > -1 && ${tpl}.splice(index, 1))`, { val: node.value, checked: newVal, thisNode: node }, scanObj.thisObj || node, node._ref || {});
|
|
437
|
+
else _runCode(`${tpl} = val`, { val: newVal, thisNode: node }, scanObj.thisObj || node, node._ref || {});
|
|
438
|
+
setDisableRunCodeError(false);
|
|
439
|
+
setNoWriteBack(null);
|
|
440
|
+
});
|
|
441
|
+
} else if (realAttrName === "text" && !tpl) {
|
|
442
|
+
tpl = node.textContent;
|
|
443
|
+
node.textContent = "";
|
|
444
|
+
}
|
|
445
|
+
if (tpl) {
|
|
446
|
+
tpl = _translate(tpl);
|
|
447
|
+
_initBinding({ node, attr: realAttrName, tpl, exp });
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
if (node._hasOnLoad || node._componentInitialized) Promise.resolve().then(() => node.dispatchEvent(new Event("load", { bubbles: false })));
|
|
452
|
+
if (node._hasOnUpdate) node.dispatchEvent(new Event("update", { bubbles: false }));
|
|
453
|
+
if (node._thisObj) scanObj.thisObj = node._thisObj;
|
|
454
|
+
};
|
|
455
|
+
const _scanTree = (node, scanObj = {}) => {
|
|
456
|
+
if (node.nodeType === 3) {
|
|
457
|
+
if (node._stTranslated) return;
|
|
458
|
+
const translated = _translate(node.textContent);
|
|
459
|
+
if (translated !== node.textContent) node.textContent = translated;
|
|
460
|
+
node._stTranslated = true;
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
if (node.nodeType !== 1) return;
|
|
464
|
+
if (!node._stTranslated) {
|
|
465
|
+
Array.from(node.attributes).forEach((attr) => {
|
|
466
|
+
if (!attr.name.startsWith("$") && !attr.name.startsWith("st-") && !attr.name.startsWith(".")) {
|
|
467
|
+
const translated = _translate(attr.value);
|
|
468
|
+
if (translated !== attr.value) attr.value = translated;
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
node._stTranslated = true;
|
|
472
|
+
}
|
|
473
|
+
let resolvedThisObj = node._thisObj;
|
|
474
|
+
let resolvedRef = node._ref;
|
|
475
|
+
if (resolvedThisObj === void 0 || resolvedRef === void 0) {
|
|
476
|
+
let curr = node;
|
|
477
|
+
while (curr && (resolvedThisObj === void 0 || resolvedRef === void 0)) {
|
|
478
|
+
if (resolvedThisObj === void 0 && curr._thisObj !== void 0) resolvedThisObj = curr._thisObj;
|
|
479
|
+
if (resolvedRef === void 0 && curr._ref !== void 0) resolvedRef = { ...curr._ref };
|
|
480
|
+
curr = curr.parentNode;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (resolvedThisObj === void 0) resolvedThisObj = scanObj.thisObj;
|
|
484
|
+
if (resolvedRef === void 0) resolvedRef = scanObj.extendVars;
|
|
485
|
+
if (node.tagName !== "TEMPLATE" && (node.hasAttribute("$if") || node.hasAttribute("$each") || node.hasAttribute("st-if") || node.hasAttribute("st-each"))) {
|
|
486
|
+
const template = document.createElement("TEMPLATE");
|
|
487
|
+
const attrs = Array.from(node.attributes).filter((attr) => ["$if", "$each", "st-if", "st-each"].includes(attr.name) || (node.hasAttribute("$each") || node.hasAttribute("st-each")) && ["as", "index"].includes(attr.name));
|
|
488
|
+
attrs.forEach((attr) => {
|
|
489
|
+
template.setAttribute(attr.name, attr.value);
|
|
490
|
+
node.removeAttribute(attr.name);
|
|
491
|
+
});
|
|
492
|
+
node.parentNode.insertBefore(template, node);
|
|
493
|
+
template.content.appendChild(node);
|
|
494
|
+
template._ref = resolvedRef;
|
|
495
|
+
template._thisObj = resolvedThisObj;
|
|
496
|
+
_scanTree(template, scanObj);
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
if (node.tagName === "TEMPLATE" && (node.hasAttribute("$if") || node.hasAttribute("st-if")) && (node.hasAttribute("$each") || node.hasAttribute("st-each"))) {
|
|
500
|
+
const template = document.createElement("TEMPLATE");
|
|
501
|
+
const attrs = Array.from(node.attributes).filter((attr2) => ["$if", "$each", "st-if", "st-each"].includes(attr2.name));
|
|
502
|
+
const attr = attrs[attrs.length - 1];
|
|
503
|
+
template.setAttribute(attr.name, attr.value);
|
|
504
|
+
node.removeAttribute(attr.name);
|
|
505
|
+
if (attr.name === "$each" || attr.name === "st-each") {
|
|
506
|
+
Array.from(node.attributes).filter((attr2) => ["as", "index"].includes(attr2.name)).forEach((attr2) => {
|
|
507
|
+
template.setAttribute(attr2.name, attr2.value);
|
|
508
|
+
node.removeAttribute(attr2.name);
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
Array.from(node.content.childNodes).forEach((child) => template.content.appendChild(child));
|
|
512
|
+
node.content.appendChild(template);
|
|
513
|
+
template._ref = resolvedRef;
|
|
514
|
+
template._thisObj = resolvedThisObj;
|
|
515
|
+
}
|
|
516
|
+
if (node.tagName === "IMG" && (node.hasAttribute("src") || node.hasAttribute("_src") || node.hasAttribute("$src"))) {
|
|
517
|
+
const imgNode = node;
|
|
518
|
+
Promise.resolve().then(() => {
|
|
519
|
+
const url = imgNode.getAttribute("_src") || imgNode.getAttribute("src");
|
|
520
|
+
if (url) fetch(url, { cache: "force-cache" }).then((r) => r.text()).then((svgText) => {
|
|
521
|
+
const realSvg = new DOMParser().parseFromString(svgText, "image/svg+xml").querySelector("svg");
|
|
522
|
+
if (realSvg) {
|
|
523
|
+
Array.from(imgNode.attributes).forEach((attr) => realSvg.setAttribute(attr.name, attr.value));
|
|
524
|
+
imgNode.replaceWith(realSvg);
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
if (node._thisObj !== void 0) scanObj.thisObj = node._thisObj || null;
|
|
530
|
+
else {
|
|
531
|
+
let curr = node;
|
|
532
|
+
while (curr && curr._thisObj === void 0) curr = curr.parentNode;
|
|
533
|
+
scanObj.thisObj = curr ? curr._thisObj : null;
|
|
534
|
+
}
|
|
535
|
+
if (node._ref === void 0) {
|
|
536
|
+
let curr = node;
|
|
537
|
+
while (curr && curr._ref === void 0) curr = curr.parentNode;
|
|
538
|
+
node._ref = curr ? { ...curr._ref } : {};
|
|
539
|
+
}
|
|
540
|
+
if (node._refExt !== void 0) {
|
|
541
|
+
Object.assign(node._ref, node._refExt);
|
|
542
|
+
}
|
|
543
|
+
if (scanObj.extendVars) Object.assign(node._ref, scanObj.extendVars);
|
|
544
|
+
_parseNode(node, { ...scanObj });
|
|
545
|
+
const nodes = [...node.childNodes || []];
|
|
546
|
+
const nextScanObj = { thisObj: scanObj.thisObj, extendVars: { ...node._ref } };
|
|
547
|
+
nodes.forEach((child) => {
|
|
548
|
+
if (!child._stManaged) _scanTree(child, nextScanObj);
|
|
549
|
+
});
|
|
550
|
+
};
|
|
551
|
+
const _unbindTree = (node) => {
|
|
552
|
+
if (node.nodeType !== 1) return;
|
|
553
|
+
if (node._hasOnUnload) node.dispatchEvent(new Event("unload", { bubbles: false }));
|
|
554
|
+
if (node._states) node._states.forEach((mappings) => {
|
|
555
|
+
for (const [key, bindingSet] of mappings) {
|
|
556
|
+
for (const binding of bindingSet) {
|
|
557
|
+
if (binding.node === node) bindingSet.delete(binding);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
node.childNodes && node.childNodes.forEach((child) => _unbindTree(child));
|
|
562
|
+
};
|
|
563
|
+
const RefreshState = _scanTree;
|
|
564
|
+
const Util = {
|
|
565
|
+
clone: window.structuredClone || ((obj) => JSON.parse(JSON.stringify(obj))),
|
|
566
|
+
base64: (str) => btoa(String.fromCharCode(...new TextEncoder().encode(str))),
|
|
567
|
+
unbase64: (str) => new TextDecoder().decode(Uint8Array.from(atob(str), (c) => c.charCodeAt(0))),
|
|
568
|
+
urlbase64: (str) => Util.base64(str).replace(/[+/=]/g, (m) => ({ "+": "-", "/": "", "=": "" })[m]),
|
|
569
|
+
unurlbase64: (str) => Util.unbase64(str.replace(/[-_.]/g, (m) => ({ "-": "+", "_": "/", ".": "=" })[m]).padEnd(Math.ceil(str.length / 4) * 4, "=")),
|
|
570
|
+
safeJson: (str) => {
|
|
571
|
+
try {
|
|
572
|
+
return JSON.parse(str);
|
|
573
|
+
} catch {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
updateDefaults: (obj, defaults) => {
|
|
578
|
+
for (const k in defaults) if (obj[k] === void 0) obj[k] = defaults[k];
|
|
579
|
+
},
|
|
580
|
+
copyFunction: (toObj, fromObj, ...funcNames) => {
|
|
581
|
+
funcNames.forEach((name) => toObj[name] = fromObj[name].bind(fromObj));
|
|
582
|
+
},
|
|
583
|
+
getFunctionBody: (fn) => {
|
|
584
|
+
const code = fn.toString();
|
|
585
|
+
return code.slice(code.indexOf("{") + 1, code.lastIndexOf("}")).trim();
|
|
586
|
+
},
|
|
587
|
+
makeDom: (html) => {
|
|
588
|
+
if (html.includes(">\n")) html = html.replace(/>\s+</g, "><").trim();
|
|
589
|
+
const node = document.createElement("div");
|
|
590
|
+
node.innerHTML = html;
|
|
591
|
+
return node.children[0];
|
|
592
|
+
},
|
|
593
|
+
newAvg: () => {
|
|
594
|
+
let total = 0, count = 0, avg = 0;
|
|
595
|
+
return {
|
|
596
|
+
add: (v) => {
|
|
597
|
+
total += v;
|
|
598
|
+
count++;
|
|
599
|
+
return avg = total / count;
|
|
600
|
+
},
|
|
601
|
+
get: () => avg,
|
|
602
|
+
clear: () => {
|
|
603
|
+
total = 0, count = 0, avg = 0;
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
},
|
|
607
|
+
newTimeCount: () => {
|
|
608
|
+
let startTime = 0, total = 0, count = 0;
|
|
609
|
+
return {
|
|
610
|
+
start: () => startTime = (/* @__PURE__ */ new Date()).getTime(),
|
|
611
|
+
end: () => {
|
|
612
|
+
const endTime = (/* @__PURE__ */ new Date()).getTime();
|
|
613
|
+
const left = endTime - startTime;
|
|
614
|
+
startTime = endTime;
|
|
615
|
+
total += left;
|
|
616
|
+
count++;
|
|
617
|
+
return left;
|
|
618
|
+
},
|
|
619
|
+
avg: () => total / count
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
globalThis.Util = Util;
|
|
624
|
+
let _hashParams = new URLSearchParams(((_a = window.location.hash) == null ? void 0 : _a.substring(1)) || "");
|
|
625
|
+
const Hash = NewState({}, (k) => Util.safeJson(_hashParams.get(k)), (k, v) => {
|
|
626
|
+
const oldStr = _hashParams.get(k);
|
|
627
|
+
const newStr = v === void 0 ? void 0 : JSON.stringify(v);
|
|
628
|
+
if (oldStr === newStr || oldStr === null && newStr === void 0) return;
|
|
629
|
+
v === void 0 ? _hashParams.delete(k) : _hashParams.set(k, newStr);
|
|
630
|
+
window.location.hash = "#" + _hashParams.toString();
|
|
631
|
+
});
|
|
632
|
+
if (typeof window !== "undefined") {
|
|
633
|
+
window.addEventListener("hashchange", () => {
|
|
634
|
+
var _a2;
|
|
635
|
+
const oldHashParams = _hashParams;
|
|
636
|
+
_hashParams = new URLSearchParams(((_a2 = window.location.hash) == null ? void 0 : _a2.substring(1)) || "");
|
|
637
|
+
_hashParams.forEach((v, k) => {
|
|
638
|
+
if (oldHashParams.get(k) !== v) Hash[k] = Util.safeJson(v);
|
|
639
|
+
});
|
|
640
|
+
oldHashParams.forEach((v, k) => {
|
|
641
|
+
if (_hashParams.get(k) === void 0) Hash[k] = void 0;
|
|
642
|
+
});
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
const LocalStorage = NewState({}, (k) => Util.safeJson(localStorage.getItem(k)), (k, v) => {
|
|
646
|
+
const oldStr = localStorage.getItem(k);
|
|
647
|
+
const newStr = v === void 0 ? void 0 : JSON.stringify(v);
|
|
648
|
+
if (oldStr === newStr || oldStr === null && newStr === void 0) return;
|
|
649
|
+
v === void 0 ? localStorage.removeItem(k) : localStorage.setItem(k, newStr);
|
|
650
|
+
});
|
|
651
|
+
globalThis.Hash = Hash;
|
|
652
|
+
globalThis.LocalStorage = LocalStorage;
|
|
653
|
+
if (typeof document !== "undefined") {
|
|
654
|
+
const init = () => {
|
|
655
|
+
Component._initPending();
|
|
656
|
+
new MutationObserver((mutations) => {
|
|
657
|
+
mutations.forEach((mutation) => {
|
|
658
|
+
mutation.addedNodes.forEach((newNode) => {
|
|
659
|
+
if (newNode.isConnected) _scanTree(newNode);
|
|
660
|
+
});
|
|
661
|
+
mutation.removedNodes.forEach((oldNode) => _unbindTree(oldNode));
|
|
662
|
+
});
|
|
663
|
+
}).observe(document.documentElement, { childList: true, subtree: true });
|
|
664
|
+
_scanTree(document.documentElement);
|
|
665
|
+
};
|
|
666
|
+
if (document.readyState !== "loading") init();
|
|
667
|
+
else document.addEventListener("DOMContentLoaded", init, true);
|
|
668
|
+
}
|
|
669
|
+
export {
|
|
670
|
+
$,
|
|
671
|
+
$$,
|
|
672
|
+
Component,
|
|
673
|
+
Hash,
|
|
674
|
+
LocalStorage,
|
|
675
|
+
NewState,
|
|
676
|
+
RefreshState,
|
|
677
|
+
SetTranslator,
|
|
678
|
+
Util,
|
|
679
|
+
_scanTree,
|
|
680
|
+
_unbindTree
|
|
681
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e;let t=null,n=null;const r=e=>t=e,a=e=>n=e,s=new Set;function o(e={},r=null,a=null){const o={},i=new Map,d=new Map,l=(e,t)=>(d.has(e)||d.set(e,new Set),t?d.get(e).add(t):d.get(e).clear(),()=>d.get(e).delete(t)),c=(e,t)=>{d.has(e)&&d.get(e).delete(t)},h=r||(e=>o[e]),u=a||((e,t)=>o[e]=t);return Object.assign(o,e),new Proxy(o,{get:(e,n)=>"__watch"===n?l:"__unwatch"===n?c:"__isProxy"===n||(t&&(i.has(n)||i.set(n,new Set),i.get(n).add(t),t.node._states||(t.node._states=new Set),t.node._states.add(i)),h(n)),set(e,t,r){if(h(t)!==r&&u(t,r),d.has(t)&&d.get(t).forEach(n=>{const a=n(r);void 0!==a&&(r=a,e[t]=r)}),d.has(null)&&d.get(null).forEach(e=>e(r)),i.has(t)){const e=i.get(t);for(const t of e)t.node.isConnected?n!==t.node&&s.forEach(e=>e(t)):e.delete(t)}return!0}})}const i=(e,t)=>t?e.querySelector(t):document.querySelector(e),d=(e,t)=>t?e.querySelectorAll(t):document.querySelectorAll(e),l=new Map,c=[],h={getTemplate:e=>document.querySelector(`template[component="${e.toUpperCase()}"]`),register:(e,t,n=null,...r)=>{l.set(e.toUpperCase(),t),"loading"!==document.readyState?h._addTemplate(e,n,r):c.push([e,n,r])},exists:e=>l.has(e.toUpperCase()),getSetupFunction:e=>l.get(e.toUpperCase()),_addTemplate:(e,t,n)=>{if(t){const n=document.createElement("TEMPLATE");n.setAttribute("component",e.toUpperCase()),n.content.appendChild(t),document.body.appendChild(n)}n&&n.forEach(e=>document.body.appendChild(e))},_initPending:()=>{c.forEach(([e,t,n])=>h._addTemplate(e,t,n)),c.length=0}};function u(e,t,n,r={}){e.attributes&&Array.from(e.attributes).forEach(e=>{"class"!==e.name&&("style"===e.name?t.hasAttribute("style")?t.setAttribute("style",`${e.value}; ${t.getAttribute("style")}`):t.setAttribute("style",e.value):t.hasAttribute(e.name)||t.setAttribute(e.name,e.value))}),t.classList.add(...e.classList);const a="TEMPLATE"===e.tagName?e.content:e,s="TEMPLATE"===t.tagName?t.content:t;Array.from(a.childNodes).forEach(e=>s.appendChild(e)),e.tagName&&h.exists(e.tagName)&&f(e.tagName,t,n,r)}function f(e,t,n,r={}){if(r[e])return;r[e]=!0,n.thisObj&&Array.from(t.attributes).forEach(e=>{(e.name.startsWith("$")||e.name.startsWith("st-"))&&e.value.includes("this.")&&(e.value=e.value.replace(/\bthis\./g,"this.parent."))});const a=h.getSetupFunction(e),s={};Array.from(t.childNodes).forEach(e=>{e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("slot")&&(s[e.getAttribute("slot")]=e,e.removeAttribute("slot"))}),t.innerHTML="",t.state=o(t.state||{});const i=h.getTemplate(e);if(i){const e=i.content.cloneNode(!0);if(e.childNodes.length){const a=Array.from(e.childNodes).find(e=>e.nodeType===Node.ELEMENT_NODE);a&&u(a,t,n,r),d(t,"[slot-id]").forEach(e=>{const t=e.getAttribute("slot-id");s[t]&&(e.removeAttribute("slot-id"),e.innerHTML="",u(s[t],e,n,r))})}}a&&a(t)}let b=!1;function m(e){b=e}const p=new Map;function _(e,t,n,r){const a={...r||{},...t||{}},s=Object.keys(a),o=Object.values(a),i=e+s.join(",");try{let t=p.get(i);return t||(t=new Function("Hash","LocalStorage","State",...s,e),p.set(i,t)),t.apply(n,[globalThis.Hash,globalThis.LocalStorage,globalThis.State,...o])}catch(a){return b||console.error(a,r,[e,r,t,n]),null}}function g(e,t,n,r){return e.includes("${")?_("return `"+e+"`",t,n,r):_("return "+e,t,n,r)}let v=(e,t)=>e&&"string"==typeof e?e.replace(/\{(.+?)\}/g,(e,n)=>t.hasOwnProperty(n)?t[n]:e):e;const E=e=>v=e,y=e=>e&&"string"==typeof e&&e.includes("{#")?e.replace(/\{#(.+?)#\}/g,(e,t)=>{const n=t.split("||").map(e=>e.trim()),r={};if(n.length>1){const e=n[0].match(/\{(.+?)\}/g);e&&e.forEach((e,t)=>r[e.substring(1,e.length-1)]=n[t+1]||"")}return v(n[0],r)}):e;if("undefined"!=typeof document)try{document.createElement("div").setAttribute("$t","1")}catch(e){const t=Element.prototype.setAttribute;Element.prototype.setAttribute=function(e,n){return e.startsWith("$")?t.call(this,"st-"+e.substring(1),n):t.call(this,e,n)}}var A;function N(e){e._renderedNodes&&e._renderedNodes.forEach(e=>e.forEach(e=>{e.remove(),e._renderedNodes&&N(e)}))}function T(e){const t=e.node;if(!t.isConnected&&"TEMPLATE"!==t.tagName)return;r(e),window.__perfTrace&&window.__perfTrace.evalCount++;const n=window.__perfTrace?performance.now():0;let a=e.exp?e.tpl?g(e.tpl,{thisNode:t},t._thisObj||t,t._ref||null):null:e.tpl;if(window.__perfTrace&&(window.__perfTrace.evalTotal+=performance.now()-n),r(null),e.prop){const n=e.prop;let r=t;for(let e=0;e<n.length-1&&(!n[e]||(null==r[n[e]]&&(r[n[e]]={}),r=r[n[e]],"object"==typeof r));e++);if("object"==typeof r&&null!==r){const e=n[n.length-1];if(e){"object"!=typeof a||null==a||Array.isArray(a)||null!=r[e]||(r[e]={});const t=r[e];"object"==typeof t&&null!=t&&t.__watch?Object.assign(t,a):r[e]=a}else"object"!=typeof a||null==a||Array.isArray(a)||Object.assign(r,a)}}else if(e.attr){const n=e.attr;if("if"===n)a?t._renderedNodes&&0!==t._renderedNodes.length?t._renderedNodes[0].forEach(e=>O(e,{thisObj:t._thisObj,extendVars:e._ref})):(t._children.forEach(e=>{e._stManaged=!0,t.parentNode.insertBefore(e,t),e._ref={...t._ref}}),t._renderedNodes=[t._children]):(N(t),t._renderedNodes=[]);else if("each"===n)if(a&&"object"==typeof a){const e=t.getAttribute("as")||"item",n=t.getAttribute("index")||"index",r=t.getAttribute("key");let s,o;if(a instanceof Map)s=Array.from(a.keys()),o=e=>a.get(e);else if("function"==typeof a[Symbol.iterator]){const e=Array.isArray(a)?a:Array.from(a);s=new Array(e.length);for(let t=0;t<e.length;t++)s[t]=t;o=t=>e[t]}else s=Object.keys(a),o=e=>a[e];t._keyedNodes||(t._keyedNodes=new Map);const i=new Map,d=[];s.forEach((a,s)=>{const l=o(a),c=r?l&&"object"==typeof l?l[r]:l:a,h=null==c||i.has(c)?`st_key_fallback_${s}_${Math.random()}`:c;let u=t._keyedNodes.get(h);u?(t._keyedNodes.delete(h),u.forEach(r=>{window.__statePerformanceTelemetry&&window.__statePerformanceTelemetry.reuseCount++;let s=!1;for(let a in t._ref)a!==e&&a!==n&&r._ref[a]!==t._ref[a]&&(r._ref[a]=t._ref[a],s=!0);r._ref[n]!==a&&(r._ref[n]=a),r._ref[e]!==l||s?(r._ref[e]=l,window.__statePerformanceTelemetry&&window.__statePerformanceTelemetry.scanCount++,O(r,{thisObj:t._thisObj,extendVars:r._ref})):t.parentNode.lastChild!==r&&(window.__statePerformanceTelemetry&&window.__statePerformanceTelemetry.moveCount++,t.parentNode.insertBefore(r,t))})):(u=[],t._children.forEach(r=>{const s=r.cloneNode(!0);s._stManaged=!0,s._ref={...t._ref,[n]:a,[e]:l},s._thisObj=t._thisObj,t.parentNode.insertBefore(s,t),u.push(s)})),i.set(h,u),d.push(u),u.forEach(e=>t.parentNode.insertBefore(e,t))}),t._keyedNodes.forEach(e=>e.forEach(e=>{N(e),e.remove()})),t._keyedNodes=i,t._renderedNodes=d}else N(t),t._keyedNodes&&t._keyedNodes.forEach(e=>e.forEach(e=>e.remove())),t._keyedNodes=new Map,t._renderedNodes=[];else if("bind"===n){if(["INPUT","SELECT","TEXTAREA"].includes(t.tagName)&&!t.hasAttribute("autocomplete")&&t.setAttribute("autocomplete","off"),"checkbox"===t.type){"on"===t.value||a||(_(`${e.tpl} = []`,{thisNode:t},t._thisObj||t,t._ref||{}),a=[]),t._checkboxMultiMode=a instanceof Array;const n=a instanceof Array?a.includes(t.value):!!a;t.checked!==n&&(t.checked=n)}else"radio"===t.type?t.checked!==(t.value===String(a??""))&&(t.checked=t.value===String(a??"")):"value"in t&&"file"!==t.type?setTimeout(()=>{t.value!==String(a??"")&&(t.value=a)}):t.isContentEditable&&t.innerHTML!==String(a??"")&&(t.innerHTML=a);t.dispatchEvent(new CustomEvent("bind",{bubbles:!1,detail:a}))}else["checked","disabled","readonly"].includes(n)&&(a=!!a),"boolean"==typeof a?a?t.setAttribute(n,""):t.removeAttribute(n):void 0!==a&&("string"!=typeof a&&(a=JSON.stringify(a)),"text"===n?t.textContent=a??"":"html"===n?t.innerHTML=a??"":"IMG"===t.tagName&&"src"===n&&a.includes(".svg")?t.setAttribute("_src",a??""):t.setAttribute(n,a??""))}}A=e=>T(e),s.add(A);const w=e=>{e.node._bindings||(e.node._bindings=[]),e.node._bindings.push({attr:e.attr,prop:e.prop,tpl:e.tpl,exp:e.exp}),T(e)},O=(e,t={})=>{if(3===e.nodeType){if(e._stTranslated)return;const t=y(e.textContent);return t!==e.textContent&&(e.textContent=t),void(e._stTranslated=!0)}if(1!==e.nodeType)return;e._stTranslated||(Array.from(e.attributes).forEach(e=>{if(!e.name.startsWith("$")&&!e.name.startsWith("st-")&&!e.name.startsWith(".")){const t=y(e.value);t!==e.value&&(e.value=t)}}),e._stTranslated=!0);let n=e._thisObj,r=e._ref;if(void 0===n||void 0===r){let t=e;for(;t&&(void 0===n||void 0===r);)void 0===n&&void 0!==t._thisObj&&(n=t._thisObj),void 0===r&&void 0!==t._ref&&(r={...t._ref}),t=t.parentNode}if(void 0===n&&(n=t.thisObj),void 0===r&&(r=t.extendVars),"TEMPLATE"!==e.tagName&&(e.hasAttribute("$if")||e.hasAttribute("$each")||e.hasAttribute("st-if")||e.hasAttribute("st-each"))){const a=document.createElement("TEMPLATE");return Array.from(e.attributes).filter(t=>["$if","$each","st-if","st-each"].includes(t.name)||(e.hasAttribute("$each")||e.hasAttribute("st-each"))&&["as","index"].includes(t.name)).forEach(t=>{a.setAttribute(t.name,t.value),e.removeAttribute(t.name)}),e.parentNode.insertBefore(a,e),a.content.appendChild(e),a._ref=r,a._thisObj=n,void O(a,t)}if("TEMPLATE"===e.tagName&&(e.hasAttribute("$if")||e.hasAttribute("st-if"))&&(e.hasAttribute("$each")||e.hasAttribute("st-each"))){const t=document.createElement("TEMPLATE"),a=Array.from(e.attributes).filter(e=>["$if","$each","st-if","st-each"].includes(e.name)),s=a[a.length-1];t.setAttribute(s.name,s.value),e.removeAttribute(s.name),"$each"!==s.name&&"st-each"!==s.name||Array.from(e.attributes).filter(e=>["as","index"].includes(e.name)).forEach(n=>{t.setAttribute(n.name,n.value),e.removeAttribute(n.name)}),Array.from(e.content.childNodes).forEach(e=>t.content.appendChild(e)),e.content.appendChild(t),t._ref=r,t._thisObj=n}if("IMG"===e.tagName&&(e.hasAttribute("src")||e.hasAttribute("_src")||e.hasAttribute("$src"))){const t=e;Promise.resolve().then(()=>{const e=t.getAttribute("_src")||t.getAttribute("src");e&&fetch(e,{cache:"force-cache"}).then(e=>e.text()).then(e=>{const n=(new DOMParser).parseFromString(e,"image/svg+xml").querySelector("svg");n&&(Array.from(t.attributes).forEach(e=>n.setAttribute(e.name,e.value)),t.replaceWith(n))})})}if(void 0!==e._thisObj)t.thisObj=e._thisObj||null;else{let n=e;for(;n&&void 0===n._thisObj;)n=n.parentNode;t.thisObj=n?n._thisObj:null}if(void 0===e._ref){let t=e;for(;t&&void 0===t._ref;)t=t.parentNode;e._ref=t?{...t._ref}:{}}void 0!==e._refExt&&Object.assign(e._ref,e._refExt),t.extendVars&&Object.assign(e._ref,t.extendVars),((e,t)=>{let n=!1;if(e._bindings&&(e._states=new Set,e._bindings.forEach(t=>T({node:e,...t})),e._hasOnUpdate&&e.dispatchEvent(new Event("update",{bubbles:!1})),n=!0),h.exists(e.tagName)&&!e._componentInitialized&&(Array.from(e.attributes).forEach(n=>{var r;if(n.name.startsWith("$.")){const a=n.name.slice(2);let s=y(n.value);s.includes("this.")&&(s=s.replace(/\bthis\./g,"this.parent."));const o=g(s,{thisNode:e},{parent:t.thisObj||e},e._ref||{});let i=e;const d=a.split(".");for(let e=0;e<d.length-1;e++)d[e]&&(i=i[r=d[e]]??(i[r]={}));i[d[d.length-1]]=o,e.removeAttribute(n.name)}}),f(e.tagName,e,t),d(e,"[slot-id]").forEach(e=>e.removeAttribute("slot-id")),e._componentInitialized=!0,e._thisObj||(e._thisObj=e)),"TEMPLATE"===e.tagName&&(e._children=[...e.content.childNodes],e._renderedNodes||(e._renderedNodes=[])),n)return;let r=[];"TEMPLATE"===e.tagName?["$if","$each","st-if","st-each"].forEach(t=>e.hasAttribute(t)&&r.push(e.getAttributeNode(t))):r=Array.from(e.attributes).filter(e=>(e.name.startsWith("$")||e.name.startsWith("st-"))&&!["$if","$each","st-if","st-each"].includes(e.name)||e.name.includes(".")),e._thisObj&&t.thisObj&&(e._thisObj.parent=t.thisObj),e._thisObj||(e._thisObj=t.thisObj||null),e._ref||(e._ref=t.extendVars||{}),e._states=new Set,r.forEach(n=>{const r=n.name.startsWith("$")||n.name.startsWith("st-"),s=r?n.name.slice(n.name.startsWith("$")?1:3):n.name;let o=n.value;if(e.removeAttribute(n.name),s.startsWith("."))w({node:e,prop:s.split("."),tpl:o,exp:r});else if(s.startsWith("on")){const n=s.slice(2);"update"===n&&(e._hasOnUpdate=!0),"load"!==n||["BODY","IMG","IFRAME"].includes(e.tagName)||(e._hasOnLoad=!0),"unload"!==n||["BODY","IMG","IFRAME"].includes(e.tagName)||(e._hasOnUnload=!0),e.addEventListener(n,n=>_(o,{event:n,thisNode:e,...n.detail||{}},t.thisObj||e,e._ref||{}))}else"bind"===s?e.addEventListener("TEXTAREA"===e.tagName||e.isContentEditable||"text"===e.type||"password"===e.type?"input":"change",n=>{let r=e.isContentEditable?n.target.innerHTML:"checkbox"===e.type?n.target.checked:n.target.files||n.target.value||n.detail;a(e),m(!0),"checkbox"===e.type&&e._checkboxMultiMode?_(`!!checked ? (!${o}.includes(val) && ${o}.push(val)) : (index = ${o}.indexOf(val), index > -1 && ${o}.splice(index, 1))`,{val:e.value,checked:r,thisNode:e},t.thisObj||e,e._ref||{}):_(`${o} = val`,{val:r,thisNode:e},t.thisObj||e,e._ref||{}),m(!1),a(null)}):"text"!==s||o||(o=e.textContent,e.textContent=""),o&&(o=y(o),w({node:e,attr:s,tpl:o,exp:r}))}),(e._hasOnLoad||e._componentInitialized)&&Promise.resolve().then(()=>e.dispatchEvent(new Event("load",{bubbles:!1}))),e._hasOnUpdate&&e.dispatchEvent(new Event("update",{bubbles:!1})),e._thisObj&&(t.thisObj=e._thisObj)})(e,{...t});const s=[...e.childNodes||[]],o={thisObj:t.thisObj,extendVars:{...e._ref}};s.forEach(e=>{e._stManaged||O(e,o)})},j=e=>{1===e.nodeType&&(e._hasOnUnload&&e.dispatchEvent(new Event("unload",{bubbles:!1})),e._states&&e._states.forEach(t=>{for(const[n,r]of t)for(const t of r)t.node===e&&r.delete(t)}),e.childNodes&&e.childNodes.forEach(e=>j(e)))},x=O,M={clone:window.structuredClone||(e=>JSON.parse(JSON.stringify(e))),base64:e=>btoa(String.fromCharCode(...(new TextEncoder).encode(e))),unbase64:e=>(new TextDecoder).decode(Uint8Array.from(atob(e),e=>e.charCodeAt(0))),urlbase64:e=>M.base64(e).replace(/[+/=]/g,e=>({"+":"-","/":"","=":""}[e])),unurlbase64:e=>M.unbase64(e.replace(/[-_.]/g,e=>({"-":"+",_:"/",".":"="}[e])).padEnd(4*Math.ceil(e.length/4),"=")),safeJson:e=>{try{return JSON.parse(e)}catch{return null}},updateDefaults:(e,t)=>{for(const n in t)void 0===e[n]&&(e[n]=t[n])},copyFunction:(e,t,...n)=>{n.forEach(n=>e[n]=t[n].bind(t))},getFunctionBody:e=>{const t=e.toString();return t.slice(t.indexOf("{")+1,t.lastIndexOf("}")).trim()},makeDom:e=>{e.includes(">\n")&&(e=e.replace(/>\s+</g,"><").trim());const t=document.createElement("div");return t.innerHTML=e,t.children[0]},newAvg:()=>{let e=0,t=0,n=0;return{add:r=>(e+=r,t++,n=e/t),get:()=>n,clear:()=>{e=0,t=0,n=0}}},newTimeCount:()=>{let e=0,t=0,n=0;return{start:()=>e=(new Date).getTime(),end:()=>{const r=(new Date).getTime(),a=r-e;return e=r,t+=a,n++,a},avg:()=>t/n}}};globalThis.Util=M;let S=new URLSearchParams((null==(e=window.location.hash)?void 0:e.substring(1))||"");const C=o({},e=>M.safeJson(S.get(e)),(e,t)=>{const n=S.get(e),r=void 0===t?void 0:JSON.stringify(t);n===r||null===n&&void 0===r||(void 0===t?S.delete(e):S.set(e,r),window.location.hash="#"+S.toString())});"undefined"!=typeof window&&window.addEventListener("hashchange",()=>{var e;const t=S;S=new URLSearchParams((null==(e=window.location.hash)?void 0:e.substring(1))||""),S.forEach((e,n)=>{t.get(n)!==e&&(C[n]=M.safeJson(e))}),t.forEach((e,t)=>{void 0===S.get(t)&&(C[t]=void 0)})});const L=o({},e=>M.safeJson(localStorage.getItem(e)),(e,t)=>{const n=localStorage.getItem(e),r=void 0===t?void 0:JSON.stringify(t);n===r||null===n&&void 0===r||(void 0===t?localStorage.removeItem(e):localStorage.setItem(e,r))});if(globalThis.Hash=C,globalThis.LocalStorage=L,"undefined"!=typeof document){const e=()=>{h._initPending(),new MutationObserver(e=>{e.forEach(e=>{e.addedNodes.forEach(e=>{e.isConnected&&O(e)}),e.removedNodes.forEach(e=>j(e))})}).observe(document.documentElement,{childList:!0,subtree:!0}),O(document.documentElement)};"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e,!0)}export{i as $,d as $$,h as Component,C as Hash,L as LocalStorage,o as NewState,x as RefreshState,E as SetTranslator,M as Util,O as _scanTree,j as _unbindTree};
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@apigo.cc/state",
|
|
3
|
+
"version": "1.0.11",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/state.js",
|
|
6
|
+
"module": "dist/state.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"dev": "vite",
|
|
12
|
+
"build": "vite build",
|
|
13
|
+
"test": "playwright test",
|
|
14
|
+
"publish": "node scripts/publish.js"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@playwright/test": "^1.40.0",
|
|
18
|
+
"@rollup/plugin-terser": "^1.0.0",
|
|
19
|
+
"terser": "^5.47.1",
|
|
20
|
+
"vite": "^5.0.0"
|
|
21
|
+
}
|
|
22
|
+
}
|