ex4nicegui 0.8.10__py3-none-any.whl → 0.9.1__py3-none-any.whl
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.
- ex4nicegui/__init__.py +3 -2
- ex4nicegui/bi/dataSource.py +1 -2
- ex4nicegui/bi/elements/ui_aggrid.py +1 -2
- ex4nicegui/bi/protocols.py +10 -20
- ex4nicegui/layout/rxFlex/index.py +0 -1
- ex4nicegui/reactive/EChartsComponent/ECharts.js +1 -1
- ex4nicegui/reactive/EChartsComponent/ECharts.py +1 -5
- ex4nicegui/reactive/UseDraggable/UseDraggable.py +3 -3
- ex4nicegui/reactive/__init__.py +2 -3
- ex4nicegui/reactive/_vmodel.py +150 -0
- ex4nicegui/reactive/base.py +2 -3
- ex4nicegui/reactive/deferredTask.py +2 -5
- ex4nicegui/reactive/mermaid/{mermaid.js → ex4ng_mermaid.js} +1 -1
- ex4nicegui/reactive/mermaid/mermaid.py +1 -6
- ex4nicegui/reactive/mixins/flexLayout.py +4 -8
- ex4nicegui/reactive/mixins/value_element.py +1 -2
- ex4nicegui/reactive/officials/echarts.py +1 -1
- ex4nicegui/reactive/systems/object_system.py +2 -4
- ex4nicegui/reactive/usePagination.py +2 -4
- ex4nicegui/reactive/vfor.py +1 -0
- ex4nicegui/toolbox/core/vue_use.py +1 -1
- ex4nicegui/utils/apiEffect.py +1 -2
- ex4nicegui/utils/clientScope.py +5 -8
- ex4nicegui/utils/effect.py +1 -2
- ex4nicegui/utils/page_state.py +70 -0
- ex4nicegui/utils/proxy/descriptor.py +0 -1
- ex4nicegui/utils/refComputed.py +1 -2
- ex4nicegui/utils/refreshable.py +122 -0
- ex4nicegui/utils/signals.py +5 -88
- {ex4nicegui-0.8.10.dist-info → ex4nicegui-0.9.1.dist-info}/METADATA +62 -21
- {ex4nicegui-0.8.10.dist-info → ex4nicegui-0.9.1.dist-info}/RECORD +54 -80
- {ex4nicegui-0.8.10.dist-info → ex4nicegui-0.9.1.dist-info}/WHEEL +1 -1
- ex4nicegui/gsap/__init__.py +0 -23
- ex4nicegui/gsap/gsap.py +0 -145
- ex4nicegui/gsap/timeline.js +0 -56
- ex4nicegui/gsap/timeline.py +0 -78
- ex4nicegui/gsap/wrapGsap.js +0 -48
- ex4nicegui/libs/gsap/.DS_Store +0 -0
- ex4nicegui/libs/gsap/CSSPlugin.js +0 -1577
- ex4nicegui/libs/gsap/CSSRulePlugin.js +0 -134
- ex4nicegui/libs/gsap/CustomEase.js +0 -371
- ex4nicegui/libs/gsap/Draggable.js +0 -2699
- ex4nicegui/libs/gsap/EasePack.js +0 -212
- ex4nicegui/libs/gsap/EaselPlugin.js +0 -341
- ex4nicegui/libs/gsap/Flip.js +0 -1518
- ex4nicegui/libs/gsap/MotionPathPlugin.js +0 -368
- ex4nicegui/libs/gsap/Observer.js +0 -686
- ex4nicegui/libs/gsap/PixiPlugin.js +0 -461
- ex4nicegui/libs/gsap/ScrollToPlugin.js +0 -273
- ex4nicegui/libs/gsap/ScrollTrigger.js +0 -2658
- ex4nicegui/libs/gsap/TextPlugin.js +0 -166
- ex4nicegui/libs/gsap/__init__.py +0 -0
- ex4nicegui/libs/gsap/all.js +0 -31
- ex4nicegui/libs/gsap/gsap-core.js +0 -4487
- ex4nicegui/libs/gsap/gsap.mjs +0 -6
- ex4nicegui/libs/gsap/utils/__init__.py +0 -0
- ex4nicegui/libs/gsap/utils/matrix.js +0 -420
- ex4nicegui/libs/gsap/utils/paths.js +0 -1487
- ex4nicegui/libs/gsap/utils/strings.js +0 -107
- ex4nicegui/reactive/local_file_picker.py +0 -208
- ex4nicegui/reactive/vmodel.py +0 -237
- {ex4nicegui-0.8.10.dist-info → ex4nicegui-0.9.1.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* strings: 3.12.5
|
|
3
|
-
* https://gsap.com
|
|
4
|
-
*
|
|
5
|
-
* Copyright 2008-2024, GreenSock. All rights reserved.
|
|
6
|
-
* Subject to the terms at https://gsap.com/standard-license or for
|
|
7
|
-
* Club GSAP members, the agreement issued with that membership.
|
|
8
|
-
* @author: Jack Doyle, jack@greensock.com
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/* eslint-disable */
|
|
12
|
-
var _trimExp = /(?:^\s+|\s+$)/g;
|
|
13
|
-
export var emojiExp = /([\uD800-\uDBFF][\uDC00-\uDFFF](?:[\u200D\uFE0F][\uD800-\uDBFF][\uDC00-\uDFFF]){2,}|\uD83D\uDC69(?:\u200D(?:(?:\uD83D\uDC69\u200D)?\uD83D\uDC67|(?:\uD83D\uDC69\u200D)?\uD83D\uDC66)|\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D(?:\uD83D\uDC69\u200D)?\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D(?:\uD83D\uDC69\u200D)?\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]\uFE0F|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC6F\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3C-\uDD3E\uDDD6-\uDDDF])\u200D[\u2640\u2642]\uFE0F|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F\u200D[\u2640\u2642]|(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642])\uFE0F|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2695\u2696\u2708]|\uD83D\uDC69\u200D[\u2695\u2696\u2708]|\uD83D\uDC68(?:(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708]))\uFE0F|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83D\uDC69\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|[#\*0-9]\uFE0F\u20E3|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|\uD83D\uDC68(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:(?:\uD83D[\uDC68\uDC69])\u200D)?\uD83D\uDC66\u200D\uD83D\uDC66|(?:(?:\uD83D[\uDC68\uDC69])\u200D)?\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|(?:\uD83C[\uDFFB-\uDFFF])\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]))|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270A-\u270D]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC70\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDCAA\uDD74\uDD7A\uDD90\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD36\uDDD1-\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\u200D(?:(?:(?:\uD83D[\uDC68\uDC69])\u200D)?\uD83D\uDC67|(?:(?:\uD83D[\uDC68\uDC69])\u200D)?\uD83D\uDC66)|\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC69\uDC6E\uDC70-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD18-\uDD1C\uDD1E\uDD1F\uDD26\uDD30-\uDD39\uDD3D\uDD3E\uDDD1-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])?|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDEEB\uDEEC\uDEF4-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])\uFE0F)/;
|
|
14
|
-
export function getText(e) {
|
|
15
|
-
var type = e.nodeType,
|
|
16
|
-
result = "";
|
|
17
|
-
|
|
18
|
-
if (type === 1 || type === 9 || type === 11) {
|
|
19
|
-
if (typeof e.textContent === "string") {
|
|
20
|
-
return e.textContent;
|
|
21
|
-
} else {
|
|
22
|
-
for (e = e.firstChild; e; e = e.nextSibling) {
|
|
23
|
-
result += getText(e);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
} else if (type === 3 || type === 4) {
|
|
27
|
-
return e.nodeValue;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return result;
|
|
31
|
-
}
|
|
32
|
-
export function splitInnerHTML(element, delimiter, trim, preserveSpaces) {
|
|
33
|
-
var node = element.firstChild,
|
|
34
|
-
result = [],
|
|
35
|
-
s;
|
|
36
|
-
|
|
37
|
-
while (node) {
|
|
38
|
-
if (node.nodeType === 3) {
|
|
39
|
-
s = (node.nodeValue + "").replace(/^\n+/g, "");
|
|
40
|
-
|
|
41
|
-
if (!preserveSpaces) {
|
|
42
|
-
s = s.replace(/\s+/g, " ");
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
result.push.apply(result, emojiSafeSplit(s, delimiter, trim, preserveSpaces));
|
|
46
|
-
} else if ((node.nodeName + "").toLowerCase() === "br") {
|
|
47
|
-
result[result.length - 1] += "<br>";
|
|
48
|
-
} else {
|
|
49
|
-
result.push(node.outerHTML);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
node = node.nextSibling;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
s = result.length;
|
|
56
|
-
|
|
57
|
-
while (s--) {
|
|
58
|
-
result[s] === "&" && result.splice(s, 1, "&");
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return result;
|
|
62
|
-
}
|
|
63
|
-
/*
|
|
64
|
-
//smaller kb version that only handles the simpler emoji's, which is often perfectly adequate.
|
|
65
|
-
|
|
66
|
-
let _emoji = "[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2694-\u2697]|\uD83E[\uDD10-\uDD5D]|[\uD800-\uDBFF][\uDC00-\uDFFF]",
|
|
67
|
-
_emojiExp = new RegExp(_emoji),
|
|
68
|
-
_emojiAndCharsExp = new RegExp(_emoji + "|.", "g"),
|
|
69
|
-
_emojiSafeSplit = (text, delimiter, trim) => {
|
|
70
|
-
if (trim) {
|
|
71
|
-
text = text.replace(_trimExp, "");
|
|
72
|
-
}
|
|
73
|
-
return ((delimiter === "" || !delimiter) && _emojiExp.test(text)) ? text.match(_emojiAndCharsExp) : text.split(delimiter || "");
|
|
74
|
-
};
|
|
75
|
-
*/
|
|
76
|
-
|
|
77
|
-
export function emojiSafeSplit(text, delimiter, trim, preserveSpaces) {
|
|
78
|
-
text += ""; // make sure it's cast as a string. Someone may pass in a number.
|
|
79
|
-
|
|
80
|
-
trim && (text = text.trim ? text.trim() : text.replace(_trimExp, "")); // IE9 and earlier compatibility
|
|
81
|
-
|
|
82
|
-
if (delimiter && delimiter !== "") {
|
|
83
|
-
return text.replace(/>/g, ">").replace(/</g, "<").split(delimiter);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
var result = [],
|
|
87
|
-
l = text.length,
|
|
88
|
-
i = 0,
|
|
89
|
-
j,
|
|
90
|
-
character;
|
|
91
|
-
|
|
92
|
-
for (; i < l; i++) {
|
|
93
|
-
character = text.charAt(i);
|
|
94
|
-
|
|
95
|
-
if (character.charCodeAt(0) >= 0xD800 && character.charCodeAt(0) <= 0xDBFF || text.charCodeAt(i + 1) >= 0xFE00 && text.charCodeAt(i + 1) <= 0xFE0F) {
|
|
96
|
-
//special emoji characters use 2 or 4 unicode characters that we must keep together.
|
|
97
|
-
j = ((text.substr(i, 12).split(emojiExp) || [])[1] || "").length || 2;
|
|
98
|
-
character = text.substr(i, j);
|
|
99
|
-
result.emoji = 1;
|
|
100
|
-
i += j - 1;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
result.push(character === ">" ? ">" : character === "<" ? "<" : preserveSpaces && character === " " && (text.charAt(i - 1) === " " || text.charAt(i + 1) === " ") ? " " : character);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return result;
|
|
107
|
-
}
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
from typing import Callable, Optional, List, Union
|
|
2
|
-
from typing_extensions import Literal
|
|
3
|
-
from nicegui import ui, Tailwind
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
from ex4nicegui.utils.signals import (
|
|
7
|
-
Ref,
|
|
8
|
-
effect_refreshable,
|
|
9
|
-
effect,
|
|
10
|
-
ref_computed as computed,
|
|
11
|
-
to_ref,
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
SelectMode = Literal["dir", "file"]
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class LocalFilePickerResult:
|
|
19
|
-
def __init__(self, ref: Ref[str], open_fn: Callable[..., None]) -> None:
|
|
20
|
-
self.__open_fn = open_fn
|
|
21
|
-
self._ref = ref
|
|
22
|
-
|
|
23
|
-
def open(self):
|
|
24
|
-
self.__open_fn()
|
|
25
|
-
|
|
26
|
-
def bind_ref(self, ref: Ref[str]):
|
|
27
|
-
@effect
|
|
28
|
-
def _():
|
|
29
|
-
ref.value = self._ref.value
|
|
30
|
-
|
|
31
|
-
return self
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def local_file_picker(
|
|
35
|
-
title: Optional[str] = None,
|
|
36
|
-
dir: Optional[Union[str, Path]] = None,
|
|
37
|
-
mode: SelectMode = "file",
|
|
38
|
-
ext: Optional[List[str]] = None,
|
|
39
|
-
):
|
|
40
|
-
"""本地文件目录选择框
|
|
41
|
-
|
|
42
|
-
Args:
|
|
43
|
-
title (Optional[str], optional): 标题. Defaults to None.
|
|
44
|
-
dir (Optional[str], optional): 起始目录,默认为当前目录. Defaults to None.
|
|
45
|
-
mode (SelectMode, optional): 选择文件或选择目录,'file' | 'dir'. Defaults to "file".
|
|
46
|
-
ext (Optional[List[str]], optional): 当 `mode` 为 'file' 时,保留指定的文件后缀.例如: ```ext=['.xlsx','.csv']```. Defaults to None.
|
|
47
|
-
|
|
48
|
-
Returns:
|
|
49
|
-
_type_: open,result
|
|
50
|
-
open:打开选择框函数
|
|
51
|
-
result: 获取结果的信号函数。
|
|
52
|
-
|
|
53
|
-
例子:
|
|
54
|
-
```python
|
|
55
|
-
|
|
56
|
-
fp = local_file_picker(dir=r"D://dataset", ext=[".xlsx"])
|
|
57
|
-
fp.open()
|
|
58
|
-
|
|
59
|
-
# 获取结果
|
|
60
|
-
fp.value
|
|
61
|
-
```
|
|
62
|
-
"""
|
|
63
|
-
# data define
|
|
64
|
-
title = title or "选择文件" if mode == "file" else "选择文件夹"
|
|
65
|
-
dir_path = Path(dir).absolute() if dir else Path("./").absolute()
|
|
66
|
-
|
|
67
|
-
# 当前所在目录
|
|
68
|
-
cur_dir = to_ref(dir_path)
|
|
69
|
-
cur_name = computed(lambda: str(cur_dir.value.absolute()))
|
|
70
|
-
|
|
71
|
-
# 选中的路径
|
|
72
|
-
selected = to_ref("")
|
|
73
|
-
|
|
74
|
-
# 返回外部的结果路径
|
|
75
|
-
result = to_ref("")
|
|
76
|
-
|
|
77
|
-
no_ex_filter = ext is None
|
|
78
|
-
ext_set = set(ext or [])
|
|
79
|
-
|
|
80
|
-
def filter_ex(p: Path):
|
|
81
|
-
if mode == "dir" or p.is_dir() or no_ex_filter:
|
|
82
|
-
return True
|
|
83
|
-
|
|
84
|
-
return p.suffix in ext_set
|
|
85
|
-
|
|
86
|
-
# 当前目录下的文件(或目录)的列表
|
|
87
|
-
@computed
|
|
88
|
-
def paths():
|
|
89
|
-
all_paths = sorted(cur_dir.value.glob("*"), key=lambda x: not x.is_dir())
|
|
90
|
-
|
|
91
|
-
all_paths = (p for p in all_paths if mode == "file" or p.is_dir())
|
|
92
|
-
all_paths = [p for p in all_paths if filter_ex(p)]
|
|
93
|
-
|
|
94
|
-
return all_paths
|
|
95
|
-
|
|
96
|
-
# ui define
|
|
97
|
-
row_text_style = Tailwind().align_items("center").justify_content("center")
|
|
98
|
-
|
|
99
|
-
dia = ui.dialog().props("persistent")
|
|
100
|
-
|
|
101
|
-
with dia, ui.card().style("max-width:fit-content"):
|
|
102
|
-
with ui.row().classes("w-full"):
|
|
103
|
-
ui.label(title).classes("mr-auto")
|
|
104
|
-
|
|
105
|
-
ui.icon("close", size="xs").classes("cursor-pointer").on(
|
|
106
|
-
"click", handler=lambda: dia.close()
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
with ui.row().classes("w-full") as row:
|
|
110
|
-
row.tailwind(row_text_style)
|
|
111
|
-
|
|
112
|
-
# ui_cur_dir = ui.label()
|
|
113
|
-
# bind_from(ui_cur_dir, cur_name)
|
|
114
|
-
|
|
115
|
-
def onenter():
|
|
116
|
-
cur_dir.value = Path(ui_cur_dir.value)
|
|
117
|
-
|
|
118
|
-
ui_cur_dir = ui.input(
|
|
119
|
-
"当前路径", validation={"无效路径": lambda value: Path(value).exists()}
|
|
120
|
-
).on("keydown.enter", handler=onenter)
|
|
121
|
-
ui_cur_dir.classes("mr-auto grow")
|
|
122
|
-
|
|
123
|
-
@effect
|
|
124
|
-
def _():
|
|
125
|
-
ui_cur_dir.value = cur_name()
|
|
126
|
-
|
|
127
|
-
@effect_refreshable
|
|
128
|
-
def pre_btn():
|
|
129
|
-
dir = cur_dir.value
|
|
130
|
-
if dir.is_dir() and dir.parent.is_dir():
|
|
131
|
-
|
|
132
|
-
def onclick():
|
|
133
|
-
cur_dir.value = dir.parent
|
|
134
|
-
|
|
135
|
-
ui.button("上一级", on_click=onclick)
|
|
136
|
-
|
|
137
|
-
# 文件或目录的表格
|
|
138
|
-
@effect_refreshable
|
|
139
|
-
def paths_table():
|
|
140
|
-
rowData = [
|
|
141
|
-
{"名称": p.name, "类型": "文件夹" if p.is_dir() else "文件"}
|
|
142
|
-
for p in paths()
|
|
143
|
-
]
|
|
144
|
-
|
|
145
|
-
grid = ui.aggrid(
|
|
146
|
-
{
|
|
147
|
-
"defaultColDef": {
|
|
148
|
-
"resizable": True,
|
|
149
|
-
},
|
|
150
|
-
"columnDefs": [
|
|
151
|
-
{
|
|
152
|
-
"field": "名称",
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
"field": "类型",
|
|
156
|
-
},
|
|
157
|
-
# {'field':'修改日期',},
|
|
158
|
-
# {'field':'大小',},
|
|
159
|
-
],
|
|
160
|
-
"rowData": rowData,
|
|
161
|
-
}
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
grid.style("width:50vw")
|
|
165
|
-
# grid.tailwind("w-96")
|
|
166
|
-
|
|
167
|
-
def dblClicked(e):
|
|
168
|
-
path = cur_dir.value / Path(e.args["data"]["名称"])
|
|
169
|
-
|
|
170
|
-
if path.is_dir():
|
|
171
|
-
cur_dir.value = path
|
|
172
|
-
return
|
|
173
|
-
|
|
174
|
-
if mode == "file" and path.is_file():
|
|
175
|
-
result.value = str(path.absolute())
|
|
176
|
-
dia.close()
|
|
177
|
-
|
|
178
|
-
def clicked(e):
|
|
179
|
-
path = cur_dir.value / Path(e.args["data"]["名称"])
|
|
180
|
-
|
|
181
|
-
if mode == "file" and path.is_dir():
|
|
182
|
-
return
|
|
183
|
-
selected.value = str(path)
|
|
184
|
-
|
|
185
|
-
grid.on("cellDoubleClicked", handler=dblClicked)
|
|
186
|
-
grid.on("cellClicked", handler=clicked)
|
|
187
|
-
|
|
188
|
-
# 页脚部分
|
|
189
|
-
with ui.row():
|
|
190
|
-
ui_selected_label = ui.label("当前选择:")
|
|
191
|
-
|
|
192
|
-
@effect
|
|
193
|
-
def _():
|
|
194
|
-
ui_selected_label.text = f"当前选择: {Path(selected.value).name}"
|
|
195
|
-
|
|
196
|
-
def onclick_ok():
|
|
197
|
-
dia.close()
|
|
198
|
-
result.value = selected.value
|
|
199
|
-
|
|
200
|
-
ok_btn = ui.button("ok", on_click=onclick_ok)
|
|
201
|
-
|
|
202
|
-
@effect
|
|
203
|
-
def _():
|
|
204
|
-
ok_btn.set_enabled(len(selected.value) > 0)
|
|
205
|
-
|
|
206
|
-
file_picker_result = LocalFilePickerResult(result, dia.open)
|
|
207
|
-
|
|
208
|
-
return file_picker_result
|
ex4nicegui/reactive/vmodel.py
DELETED
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
import inspect
|
|
3
|
-
from io import BytesIO
|
|
4
|
-
from ex4nicegui.utils.signals import (
|
|
5
|
-
RefWrapper,
|
|
6
|
-
TRef,
|
|
7
|
-
to_raw,
|
|
8
|
-
is_setter_ref,
|
|
9
|
-
to_ref_wrapper,
|
|
10
|
-
to_value,
|
|
11
|
-
is_reactive,
|
|
12
|
-
)
|
|
13
|
-
from typing import (
|
|
14
|
-
Any,
|
|
15
|
-
Callable,
|
|
16
|
-
TypeVar,
|
|
17
|
-
Union,
|
|
18
|
-
cast,
|
|
19
|
-
Tuple,
|
|
20
|
-
NamedTuple,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
from types import FrameType
|
|
24
|
-
import tokenize
|
|
25
|
-
import executing
|
|
26
|
-
import ast
|
|
27
|
-
import warnings
|
|
28
|
-
from ex4nicegui.reactive.systems.object_system import get_attribute, set_attribute
|
|
29
|
-
from ex4nicegui.utils.types import _TMaybeRef as TMaybeRef, Ref
|
|
30
|
-
|
|
31
|
-
_T = TypeVar("_T")
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def get_caller() -> FrameType:
|
|
35
|
-
return inspect.currentframe().f_back.f_back # type: ignore
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def get_args_code(caller: FrameType) -> str:
|
|
39
|
-
node = executing.Source.executing(caller).node
|
|
40
|
-
|
|
41
|
-
assert isinstance(node, ast.Call)
|
|
42
|
-
|
|
43
|
-
source = inspect.getsource(inspect.getmodule(caller)) # type: ignore
|
|
44
|
-
key_code = ast.get_source_segment(source, node.args[0])
|
|
45
|
-
return key_code # type: ignore
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class CodeInfo(NamedTuple):
|
|
49
|
-
model: str
|
|
50
|
-
is_ref: bool
|
|
51
|
-
keys: Tuple[Union[str, int], ...] = tuple() # type: ignore
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def normalize(token: tokenize.TokenInfo):
|
|
55
|
-
if token.type == tokenize.NUMBER:
|
|
56
|
-
return int(token.string)
|
|
57
|
-
|
|
58
|
-
if token.type == tokenize.STRING:
|
|
59
|
-
return token.string[1:-1]
|
|
60
|
-
|
|
61
|
-
return token.string
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def parse_code(code: str) -> CodeInfo:
|
|
65
|
-
tokens = [
|
|
66
|
-
t
|
|
67
|
-
for t in tokenize.tokenize(BytesIO(code.encode("utf8")).readline)
|
|
68
|
-
if t.type in (tokenize.NAME, tokenize.NUMBER, tokenize.OP, tokenize.STRING)
|
|
69
|
-
]
|
|
70
|
-
|
|
71
|
-
model = tokens[0].string
|
|
72
|
-
is_ref = (
|
|
73
|
-
len(tokens) >= 3
|
|
74
|
-
and tokens[1].type == tokenize.OP
|
|
75
|
-
and tokens[1].string == "."
|
|
76
|
-
and tokens[2].string == "value"
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
keys_search_start = 3 if is_ref else 1
|
|
80
|
-
|
|
81
|
-
keys = tuple(
|
|
82
|
-
normalize(token)
|
|
83
|
-
for token in tokens[keys_search_start:]
|
|
84
|
-
if token.type != tokenize.OP
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
return CodeInfo(model, is_ref, keys)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def create_writeable_wrapper(expr, ref_data, attrs: Tuple[Union[str, int], ...]):
|
|
91
|
-
if not attrs:
|
|
92
|
-
|
|
93
|
-
def maybe_ref_getter():
|
|
94
|
-
return to_value(expr)
|
|
95
|
-
|
|
96
|
-
def reactive_getter():
|
|
97
|
-
return to_raw(expr)
|
|
98
|
-
|
|
99
|
-
def setter(value):
|
|
100
|
-
pass
|
|
101
|
-
|
|
102
|
-
wrapper = to_ref_wrapper(
|
|
103
|
-
reactive_getter if is_reactive(expr) else maybe_ref_getter,
|
|
104
|
-
setter,
|
|
105
|
-
)
|
|
106
|
-
wrapper._is_readonly = False
|
|
107
|
-
return wrapper
|
|
108
|
-
|
|
109
|
-
def getter():
|
|
110
|
-
obj = get_attribute(to_value(ref_data), attrs[0])
|
|
111
|
-
for attr in attrs[1:]:
|
|
112
|
-
obj = get_attribute(obj, attr)
|
|
113
|
-
|
|
114
|
-
return obj
|
|
115
|
-
|
|
116
|
-
def setter(value):
|
|
117
|
-
obj = to_value(ref_data)
|
|
118
|
-
|
|
119
|
-
for attr in attrs[:-1]:
|
|
120
|
-
obj = get_attribute(obj, attr)
|
|
121
|
-
|
|
122
|
-
set_attribute(obj, attrs[-1], value)
|
|
123
|
-
|
|
124
|
-
wrapper = to_ref_wrapper(
|
|
125
|
-
getter,
|
|
126
|
-
setter,
|
|
127
|
-
)
|
|
128
|
-
wrapper._is_readonly = False
|
|
129
|
-
return wrapper
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
def vmodel(expr: Any, *attrs: Union[str, int]) -> TRef[Any]:
|
|
133
|
-
"""Create a two-way binding on a form input element or a component.
|
|
134
|
-
|
|
135
|
-
@see - https://github.com/CrystalWindSnake/ex4nicegui/blob/main/README.en.md#vmodel
|
|
136
|
-
@中文文档 - https://gitee.com/carson_add/ex4nicegui/tree/main/#vmodel
|
|
137
|
-
|
|
138
|
-
Args:
|
|
139
|
-
expr (Any): _description_
|
|
140
|
-
|
|
141
|
-
## Examples
|
|
142
|
-
|
|
143
|
-
.. code-block:: python
|
|
144
|
-
from ex4nicegui.reactive import rxui
|
|
145
|
-
from ex4nicegui import deep_ref
|
|
146
|
-
|
|
147
|
-
data = deep_ref({"a": 1, "b": [1, 2, 3, 4]})
|
|
148
|
-
|
|
149
|
-
rxui.label(lambda: f"{data.value=!s}")
|
|
150
|
-
|
|
151
|
-
# No binding effect
|
|
152
|
-
rxui.input(value=data.value["a"])
|
|
153
|
-
|
|
154
|
-
# readonly binding
|
|
155
|
-
rxui.input(value=lambda: data.value["a"])
|
|
156
|
-
|
|
157
|
-
# two-way binding
|
|
158
|
-
rxui.input(value=rxui.vmodel(data.value,'a'))
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
"""
|
|
162
|
-
|
|
163
|
-
assert not isinstance(expr, Callable), "argument expr cannot be a function"
|
|
164
|
-
|
|
165
|
-
if isinstance(expr, RefWrapper):
|
|
166
|
-
expr._is_readonly = False
|
|
167
|
-
|
|
168
|
-
if is_setter_ref(expr):
|
|
169
|
-
if attrs:
|
|
170
|
-
wrapper = create_writeable_wrapper(expr, expr, attrs)
|
|
171
|
-
|
|
172
|
-
return cast(
|
|
173
|
-
TRef,
|
|
174
|
-
wrapper,
|
|
175
|
-
)
|
|
176
|
-
|
|
177
|
-
return cast(
|
|
178
|
-
TRef,
|
|
179
|
-
expr,
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
caller = get_caller()
|
|
183
|
-
code = get_args_code(caller)
|
|
184
|
-
|
|
185
|
-
info = parse_code(code)
|
|
186
|
-
ref_data = caller.f_locals.get(info.model) or caller.f_globals.get(info.model)
|
|
187
|
-
assert ref_data is not None, f"{info.model} not found"
|
|
188
|
-
all_attrs = (*info.keys, *attrs)
|
|
189
|
-
|
|
190
|
-
if not all_attrs:
|
|
191
|
-
warn_mes = ""
|
|
192
|
-
if is_reactive(expr) or is_setter_ref(expr):
|
|
193
|
-
warn_mes = rf"""Expression missing the key,result is read-only binding.Maybe you meant `{code}['key']`"""
|
|
194
|
-
elif not info.is_ref:
|
|
195
|
-
warn_mes = """Maybe you don't need to use vmodel"""
|
|
196
|
-
else:
|
|
197
|
-
warn_mes = rf"""No binding.Maybe you meant `{info.model}`"""
|
|
198
|
-
|
|
199
|
-
warnings.warn(
|
|
200
|
-
warn_mes,
|
|
201
|
-
stacklevel=2,
|
|
202
|
-
)
|
|
203
|
-
|
|
204
|
-
wrapper = create_writeable_wrapper(expr, ref_data, all_attrs)
|
|
205
|
-
|
|
206
|
-
return cast(
|
|
207
|
-
TRef,
|
|
208
|
-
wrapper,
|
|
209
|
-
)
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
def vmodel_with_index(ref: Ref, index: TMaybeRef[int], *keys: Union[str, int]) -> Ref:
|
|
213
|
-
proxy = ref.value
|
|
214
|
-
|
|
215
|
-
def getter():
|
|
216
|
-
item = proxy[to_value(index)]
|
|
217
|
-
result = item
|
|
218
|
-
|
|
219
|
-
for k in keys:
|
|
220
|
-
result = get_attribute(result, k)
|
|
221
|
-
return result
|
|
222
|
-
|
|
223
|
-
def setter(value):
|
|
224
|
-
item = proxy[to_value(index)]
|
|
225
|
-
|
|
226
|
-
if len(keys) == 1:
|
|
227
|
-
set_attribute(item, keys[0], value)
|
|
228
|
-
return
|
|
229
|
-
|
|
230
|
-
obj = get_attribute(item, keys[0])
|
|
231
|
-
|
|
232
|
-
for k in keys[1:-1]:
|
|
233
|
-
set_attribute(obj, k, get_attribute(obj, k))
|
|
234
|
-
|
|
235
|
-
set_attribute(obj, keys[-1], value)
|
|
236
|
-
|
|
237
|
-
return RefWrapper(getter, setter) # type: ignore
|
|
File without changes
|