├── .gitignore ├── Actions ├── Beautify.taioactions ├── Clean Clipboard.taioactions ├── Copy Content.taioactions ├── Edit Clip.taioactions ├── Installer.taioactions ├── Json Format.taioactions ├── Juice.taioactions ├── Open URL.taioactions ├── URL Decode.taioactions ├── URL Encode.taioactions └── b23clean.taioactions ├── Juice ├── README.md ├── build.js ├── config.json ├── dist │ ├── Juice.js │ └── Juice.json ├── main.js ├── package.json ├── scripts │ ├── app.js │ ├── lib │ │ ├── easy-jsbox.js │ │ └── juice.min.js │ └── ui │ │ └── main.js ├── strings │ ├── en.strings │ └── zh-Hans.strings └── template.json ├── LICENSE ├── README.md └── b23clean ├── README.md ├── build.js ├── config.json ├── dist ├── b23clean.js └── b23clean.json ├── main.js ├── package.json ├── scripts ├── app.js └── libs │ ├── toast.js │ └── ui-kit.js ├── strings ├── en.strings └── zh-Hans.strings └── template.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .output 3 | .parcel-cache -------------------------------------------------------------------------------- /Actions/Clean Clipboard.taioactions: -------------------------------------------------------------------------------- 1 | { 2 | "actions" : [ 3 | { 4 | "type" : "@comment", 5 | "parameters" : { 6 | "text" : { 7 | "value" : "Clean clipboard (set to empty text)." 8 | } 9 | } 10 | }, 11 | { 12 | "type" : "@util.set-clipboard", 13 | "parameters" : { 14 | "mode" : 0, 15 | "localOnly" : true, 16 | "text" : { 17 | "value" : "" 18 | } 19 | } 20 | }, 21 | { 22 | "type" : "@ui.toast", 23 | "parameters" : { 24 | "style" : 1, 25 | "waitUntilDone" : false, 26 | "title" : { 27 | "value" : "Cleared" 28 | } 29 | } 30 | } 31 | ], 32 | "buildVersion" : 1, 33 | "name" : "Clean Clipboard", 34 | "clientMinVersion" : 1, 35 | "summary" : "", 36 | "icon" : { 37 | "glyph" : "trash", 38 | "color" : "#A777FF" 39 | }, 40 | "clientVersion" : 2 41 | } -------------------------------------------------------------------------------- /Actions/Copy Content.taioactions: -------------------------------------------------------------------------------- 1 | { 2 | "actions" : [ 3 | { 4 | "type" : "@comment", 5 | "parameters" : { 6 | "text" : { 7 | "value" : "EditorOnly", 8 | "tokens" : [ 9 | 10 | ] 11 | } 12 | } 13 | }, 14 | { 15 | "type" : "@flow.environment" 16 | }, 17 | { 18 | "type" : "@flow.if", 19 | "parameters" : { 20 | "blockIdentifier" : "8669DA7E-015B-4EC9-86D2-267D94A292FC", 21 | "condition" : 1, 22 | "rhs" : { 23 | "value" : "editor" 24 | }, 25 | "lhs" : { 26 | "value" : "$", 27 | "tokens" : [ 28 | { 29 | "location" : 0, 30 | "value" : "@input" 31 | } 32 | ] 33 | } 34 | } 35 | }, 36 | { 37 | "type" : "@flow.javascript", 38 | "parameters" : { 39 | "script" : { 40 | "value" : "$app.strings = {\n \"en\": {\n \"editorOnly\": \"Editor Only\"\n },\n \"zh-Hans\": {\n \"editorOnly\": \"仅在编辑器中可用\"\n }\n}\n$actions.resolve($l10n(\"editorOnly\"))\n" 41 | } 42 | } 43 | }, 44 | { 45 | "type" : "@ui.toast", 46 | "parameters" : { 47 | "style" : 0, 48 | "waitUntilDone" : false, 49 | "title" : { 50 | "value" : "$", 51 | "tokens" : [ 52 | { 53 | "location" : 0, 54 | "value" : "@input" 55 | } 56 | ] 57 | } 58 | } 59 | }, 60 | { 61 | "type" : "@flow.finish" 62 | }, 63 | { 64 | "type" : "@flow.else", 65 | "parameters" : { 66 | "blockIdentifier" : "8669DA7E-015B-4EC9-86D2-267D94A292FC" 67 | } 68 | }, 69 | { 70 | "type" : "@flow.endif", 71 | "parameters" : { 72 | "blockIdentifier" : "8669DA7E-015B-4EC9-86D2-267D94A292FC" 73 | } 74 | }, 75 | { 76 | "type" : "@util.set-clipboard", 77 | "parameters" : { 78 | "mode" : 0, 79 | "localOnly" : true, 80 | "text" : { 81 | "value" : "$", 82 | "tokens" : [ 83 | { 84 | "location" : 0, 85 | "value" : "@editor.full-text" 86 | } 87 | ] 88 | }, 89 | "expireAfter" : { 90 | "value" : "0" 91 | } 92 | } 93 | }, 94 | { 95 | "type" : "@ui.toast", 96 | "parameters" : { 97 | "style" : 0, 98 | "waitUntilDone" : false, 99 | "title" : { 100 | "value" : "Copied" 101 | } 102 | } 103 | } 104 | ], 105 | "buildVersion" : 1, 106 | "name" : "Copy Content", 107 | "clientMinVersion" : 1, 108 | "summary" : "", 109 | "icon" : { 110 | "glyph" : "doc.on.doc", 111 | "color" : "#FB6666" 112 | }, 113 | "clientVersion" : 1156 114 | } -------------------------------------------------------------------------------- /Actions/Edit Clip.taioactions: -------------------------------------------------------------------------------- 1 | { 2 | "actions" : [ 3 | { 4 | "type" : "@editor.new", 5 | "parameters" : { 6 | "location" : 1, 7 | "openInEditor" : true, 8 | "filename" : { 9 | "value" : "ClipEditor.md" 10 | }, 11 | "text" : { 12 | "value" : "$", 13 | "tokens" : [ 14 | { 15 | "location" : 0, 16 | "value" : "@input" 17 | } 18 | ] 19 | }, 20 | "overwriteIfExists" : true 21 | } 22 | } 23 | ], 24 | "buildVersion" : 1, 25 | "name" : "Edit Clip", 26 | "clientMinVersion" : 1, 27 | "summary" : "", 28 | "icon" : { 29 | "glyph" : "square.and.pencil", 30 | "color" : "#3FA1F8" 31 | }, 32 | "clientVersion" : 836 33 | } -------------------------------------------------------------------------------- /Actions/Installer.taioactions: -------------------------------------------------------------------------------- 1 | { 2 | "actions" : [ 3 | { 4 | "type" : "@ui.text-input", 5 | "parameters" : { 6 | "prompt" : { 7 | "value" : "Input URL" 8 | }, 9 | "keyboardType" : 0, 10 | "initialText" : { 11 | "value" : "" 12 | }, 13 | "singleLineText" : false 14 | } 15 | }, 16 | { 17 | "type" : "@text.encode", 18 | "parameters" : { 19 | "mode" : 0, 20 | "decode" : false, 21 | "text" : { 22 | "value" : "$", 23 | "tokens" : [ 24 | { 25 | "location" : 0, 26 | "value" : "@input" 27 | } 28 | ] 29 | }, 30 | "base64Options" : 0 31 | } 32 | }, 33 | { 34 | "type" : "@text", 35 | "parameters" : { 36 | "text" : { 37 | "value" : "taio:\/\/actions?action=import&url=$", 38 | "tokens" : [ 39 | { 40 | "location" : 33, 41 | "value" : "@input" 42 | } 43 | ] 44 | } 45 | } 46 | }, 47 | { 48 | "type" : "@util.open-url", 49 | "parameters" : { 50 | "url" : { 51 | "value" : "$", 52 | "tokens" : [ 53 | { 54 | "location" : 0, 55 | "value" : "@input" 56 | } 57 | ] 58 | }, 59 | "fullScreen" : false, 60 | "browser" : 0 61 | } 62 | } 63 | ], 64 | "buildVersion" : 1, 65 | "name" : "Installer", 66 | "clientMinVersion" : 1, 67 | "summary" : "", 68 | "icon" : { 69 | "glyph" : "tray.and.arrow.down", 70 | "color" : "#A777FF" 71 | }, 72 | "clientVersion" : 1202 73 | } -------------------------------------------------------------------------------- /Actions/Json Format.taioactions: -------------------------------------------------------------------------------- 1 | { 2 | "actions" : [ 3 | { 4 | "type" : "@comment", 5 | "parameters" : { 6 | "text" : { 7 | "value" : "EditorOnly", 8 | "tokens" : [ 9 | 10 | ] 11 | } 12 | } 13 | }, 14 | { 15 | "type" : "@flow.environment" 16 | }, 17 | { 18 | "type" : "@flow.if", 19 | "parameters" : { 20 | "blockIdentifier" : "8669DA7E-015B-4EC9-86D2-267D94A292FC", 21 | "condition" : 1, 22 | "rhs" : { 23 | "value" : "editor" 24 | }, 25 | "lhs" : { 26 | "value" : "$", 27 | "tokens" : [ 28 | { 29 | "location" : 0, 30 | "value" : "@input" 31 | } 32 | ] 33 | } 34 | } 35 | }, 36 | { 37 | "type" : "@flow.javascript", 38 | "parameters" : { 39 | "script" : { 40 | "value" : "$app.strings = {\n \"en\": {\n \"editorOnly\": \"Editor Only\"\n },\n \"zh-Hans\": {\n \"editorOnly\": \"仅在编辑器中可用\"\n }\n}\n$actions.resolve($l10n(\"editorOnly\"))\n" 41 | } 42 | } 43 | }, 44 | { 45 | "type" : "@ui.toast", 46 | "parameters" : { 47 | "style" : 0, 48 | "waitUntilDone" : false, 49 | "title" : { 50 | "value" : "$", 51 | "tokens" : [ 52 | { 53 | "location" : 0, 54 | "value" : "@input" 55 | } 56 | ] 57 | } 58 | } 59 | }, 60 | { 61 | "type" : "@flow.finish" 62 | }, 63 | { 64 | "type" : "@flow.else", 65 | "parameters" : { 66 | "blockIdentifier" : "8669DA7E-015B-4EC9-86D2-267D94A292FC" 67 | } 68 | }, 69 | { 70 | "type" : "@flow.endif", 71 | "parameters" : { 72 | "blockIdentifier" : "8669DA7E-015B-4EC9-86D2-267D94A292FC" 73 | } 74 | }, 75 | { 76 | "type" : "@comment", 77 | "parameters" : { 78 | "text" : { 79 | "value" : "GetTextFromFile", 80 | "tokens" : [ 81 | 82 | ] 83 | } 84 | } 85 | }, 86 | { 87 | "type" : "@flow.if", 88 | "parameters" : { 89 | "blockIdentifier" : "D64C424E-E7FA-4FE1-A4F5-1E98DB6E83F6", 90 | "condition" : 1, 91 | "rhs" : { 92 | "value" : "" 93 | }, 94 | "lhs" : { 95 | "value" : "$", 96 | "tokens" : [ 97 | { 98 | "location" : 0, 99 | "value" : "@editor.selection-text" 100 | } 101 | ] 102 | } 103 | } 104 | }, 105 | { 106 | "type" : "@text", 107 | "parameters" : { 108 | "text" : { 109 | "value" : "$", 110 | "tokens" : [ 111 | { 112 | "location" : 0, 113 | "value" : "@editor.selection-text" 114 | } 115 | ] 116 | } 117 | } 118 | }, 119 | { 120 | "type" : "@flow.else", 121 | "parameters" : { 122 | "blockIdentifier" : "D64C424E-E7FA-4FE1-A4F5-1E98DB6E83F6" 123 | } 124 | }, 125 | { 126 | "type" : "@text", 127 | "parameters" : { 128 | "text" : { 129 | "value" : "$", 130 | "tokens" : [ 131 | { 132 | "location" : 0, 133 | "value" : "@editor.full-text" 134 | } 135 | ] 136 | } 137 | } 138 | }, 139 | { 140 | "type" : "@flow.endif", 141 | "parameters" : { 142 | "blockIdentifier" : "D64C424E-E7FA-4FE1-A4F5-1E98DB6E83F6" 143 | } 144 | }, 145 | { 146 | "type" : "@flow.set-variable", 147 | "parameters" : { 148 | "value" : { 149 | "value" : "$", 150 | "tokens" : [ 151 | { 152 | "location" : 0, 153 | "value" : "@input" 154 | } 155 | ] 156 | }, 157 | "name" : { 158 | "value" : "oldContent" 159 | } 160 | } 161 | }, 162 | { 163 | "type" : "@flow.javascript", 164 | "parameters" : { 165 | "script" : { 166 | "value" : "\/\/ Get input\ntry {\n const text = JSON.parse($actions.inputValue)\n\n $actions.resolve(JSON.stringify(text, null, 4))\n} catch {\n $actions.reject(\"Not json content\");\n}\n\n\/\/ Exception handling:\n\/\/ $actions.reject(\"Error\");\n\/\/ $actions.finish();" 167 | } 168 | } 169 | }, 170 | { 171 | "type" : "@text.replace", 172 | "parameters" : { 173 | "mode" : 0, 174 | "pattern" : { 175 | "value" : "$", 176 | "tokens" : [ 177 | { 178 | "location" : 0, 179 | "value" : "oldContent" 180 | } 181 | ] 182 | }, 183 | "text" : { 184 | "value" : "$", 185 | "tokens" : [ 186 | { 187 | "location" : 0, 188 | "value" : "@editor.full-text" 189 | } 190 | ] 191 | }, 192 | "replacement" : { 193 | "value" : "$", 194 | "tokens" : [ 195 | { 196 | "location" : 0, 197 | "value" : "@input" 198 | } 199 | ] 200 | } 201 | } 202 | }, 203 | { 204 | "type" : "@editor.set-text", 205 | "parameters" : { 206 | "createIfNotExists" : false, 207 | "location" : 0, 208 | "filename" : { 209 | "value" : "$", 210 | "tokens" : [ 211 | { 212 | "location" : 0, 213 | "value" : "@editor.file-name" 214 | } 215 | ] 216 | }, 217 | "text" : { 218 | "value" : "$", 219 | "tokens" : [ 220 | { 221 | "location" : 0, 222 | "value" : "@input" 223 | } 224 | ] 225 | } 226 | } 227 | } 228 | ], 229 | "buildVersion" : 1, 230 | "name" : "Json Format", 231 | "clientMinVersion" : 1, 232 | "summary" : "", 233 | "icon" : { 234 | "glyph" : "wand.and.stars", 235 | "color" : "#FB6666" 236 | }, 237 | "clientVersion" : 1052 238 | } -------------------------------------------------------------------------------- /Actions/Open URL.taioactions: -------------------------------------------------------------------------------- 1 | { 2 | "actions" : [ 3 | { 4 | "type" : "@comment", 5 | "parameters" : { 6 | "text" : { 7 | "value" : "GetUrls", 8 | "tokens" : [ 9 | 10 | ] 11 | } 12 | } 13 | }, 14 | { 15 | "type" : "@flow.set-variable", 16 | "parameters" : { 17 | "value" : { 18 | "value" : "$", 19 | "tokens" : [ 20 | { 21 | "location" : 0, 22 | "value" : "@input" 23 | } 24 | ] 25 | }, 26 | "name" : { 27 | "value" : "input" 28 | } 29 | } 30 | }, 31 | { 32 | "type" : "@util.get-clipboard", 33 | "parameters" : { 34 | "mode" : 0 35 | } 36 | }, 37 | { 38 | "type" : "@flow.javascript", 39 | "parameters" : { 40 | "script" : { 41 | "value" : "let text = $actions.getVar(\"input\")\nif (text === \"\") text = $actions.inputValue\n\nfunction getUrls(text) {\n \/\/ 正则表达式用于匹配标准http和https链接,包括中文字符\r\n const httpRegex = \/https?:\\\/\\\/[\\w-]+(\\.[\\w-]+)*([\\p{Script=Han}\\w.,@?^=%&:\/~+#()\\-]*[\\w@?^=%&\/~+#()\\-])?\/giu\r\n \/\/ 正则表达式用于匹配iOS URL Scheme(假设scheme后面是:\/\/),包括中文字符\r\n const iosSchemeRegex = \/\\b\\w+:\\\/\\\/[\\w-]+(\\.[\\w-]+)*([\\p{Script=Han}\\w.,@?^=%&:\/~+#()\\-]*[\\w@?^=%&\/~+#()\\-])?\/giu\r\n\r\n \/\/ 使用正则表达式查找匹配项\r\n const httpUrls = text.match(httpRegex) || []\r\n const iosUrls = text.match(iosSchemeRegex) || []\r\n\r\n \/\/ 合并两个数组并去重\r\n const allUrls = [...new Set([...httpUrls, ...iosUrls])]\r\n\r\n return allUrls\r\n}\n\nconst urls = getUrls(text)\n$actions.resolve(urls.join(\"\\n\"))\n" 42 | } 43 | } 44 | }, 45 | { 46 | "type" : "@flow.set-variable", 47 | "parameters" : { 48 | "value" : { 49 | "value" : "$", 50 | "tokens" : [ 51 | { 52 | "location" : 0, 53 | "value" : "@input" 54 | } 55 | ] 56 | }, 57 | "name" : { 58 | "value" : "url" 59 | } 60 | } 61 | }, 62 | { 63 | "type" : "@flow.javascript", 64 | "parameters" : { 65 | "script" : { 66 | "value" : "const urlStr = $actions.inputValue?.trim() ?? \"\"\nif (urlStr.length === 0) {\n $actions.resolve(0)\n}\n\nconst urls = urlStr.split(\"\\n\") ?? []\n$actions.resolve(urls.length)\n" 67 | } 68 | } 69 | }, 70 | { 71 | "type" : "@flow.if", 72 | "parameters" : { 73 | "blockIdentifier" : "F6CD5801-2CBF-44A5-B563-A773B0B56B6A", 74 | "condition" : 0, 75 | "rhs" : { 76 | "value" : "0" 77 | }, 78 | "lhs" : { 79 | "value" : "$", 80 | "tokens" : [ 81 | { 82 | "location" : 0, 83 | "value" : "@input" 84 | } 85 | ] 86 | } 87 | } 88 | }, 89 | { 90 | "type" : "@comment", 91 | "parameters" : { 92 | "text" : { 93 | "value" : "NoUrlToast", 94 | "tokens" : [ 95 | 96 | ] 97 | } 98 | } 99 | }, 100 | { 101 | "type" : "@flow.javascript", 102 | "parameters" : { 103 | "script" : { 104 | "value" : "$app.strings = {\n \"en\": {\n \"noUrlToastTitle\": \"No URL detected\"\n },\n \"zh-Hans\": {\n \"noUrlToastTitle\": \"未匹配到 URL\"\n }\n}\n$actions.resolve($l10n(\"noUrlToastTitle\"))\n" 105 | } 106 | } 107 | }, 108 | { 109 | "type" : "@text", 110 | "parameters" : { 111 | "text" : { 112 | "value" : "$", 113 | "tokens" : [ 114 | { 115 | "location" : 0, 116 | "value" : "@input" 117 | } 118 | ] 119 | } 120 | } 121 | }, 122 | { 123 | "type" : "@ui.toast", 124 | "parameters" : { 125 | "style" : 0, 126 | "waitUntilDone" : false, 127 | "title" : { 128 | "value" : "$", 129 | "tokens" : [ 130 | { 131 | "location" : 0, 132 | "value" : "@input" 133 | } 134 | ] 135 | } 136 | } 137 | }, 138 | { 139 | "type" : "@flow.finish" 140 | }, 141 | { 142 | "type" : "@flow.else", 143 | "parameters" : { 144 | "blockIdentifier" : "F6CD5801-2CBF-44A5-B563-A773B0B56B6A" 145 | } 146 | }, 147 | { 148 | "type" : "@flow.if", 149 | "parameters" : { 150 | "blockIdentifier" : "D31658F9-61FB-462F-8A78-924FBCECCAD3", 151 | "condition" : 1, 152 | "rhs" : { 153 | "value" : "1" 154 | }, 155 | "lhs" : { 156 | "value" : "$", 157 | "tokens" : [ 158 | { 159 | "location" : 0, 160 | "value" : "@input" 161 | } 162 | ] 163 | } 164 | } 165 | }, 166 | { 167 | "type" : "@ui.menu", 168 | "parameters" : { 169 | "prompt" : { 170 | "value" : "" 171 | }, 172 | "selectAllByDefault" : false, 173 | "multiValue" : false, 174 | "lines" : { 175 | "value" : "$", 176 | "tokens" : [ 177 | { 178 | "location" : 0, 179 | "value" : "url" 180 | } 181 | ] 182 | } 183 | } 184 | }, 185 | { 186 | "type" : "@flow.set-variable", 187 | "parameters" : { 188 | "value" : { 189 | "value" : "$", 190 | "tokens" : [ 191 | { 192 | "location" : 0, 193 | "value" : "@input" 194 | } 195 | ] 196 | }, 197 | "name" : { 198 | "value" : "url" 199 | } 200 | } 201 | }, 202 | { 203 | "type" : "@flow.else", 204 | "parameters" : { 205 | "blockIdentifier" : "D31658F9-61FB-462F-8A78-924FBCECCAD3" 206 | } 207 | }, 208 | { 209 | "type" : "@flow.endif", 210 | "parameters" : { 211 | "blockIdentifier" : "D31658F9-61FB-462F-8A78-924FBCECCAD3" 212 | } 213 | }, 214 | { 215 | "type" : "@text.encode", 216 | "parameters" : { 217 | "mode" : 0, 218 | "decode" : false, 219 | "text" : { 220 | "value" : "$", 221 | "tokens" : [ 222 | { 223 | "location" : 0, 224 | "value" : "url" 225 | } 226 | ] 227 | }, 228 | "base64Options" : 0 229 | } 230 | }, 231 | { 232 | "type" : "@util.open-url", 233 | "parameters" : { 234 | "url" : { 235 | "value" : "$", 236 | "tokens" : [ 237 | { 238 | "location" : 0, 239 | "value" : "@input" 240 | } 241 | ] 242 | }, 243 | "fullScreen" : false, 244 | "browser" : 1 245 | } 246 | }, 247 | { 248 | "type" : "@flow.endif", 249 | "parameters" : { 250 | "blockIdentifier" : "F6CD5801-2CBF-44A5-B563-A773B0B56B6A" 251 | } 252 | } 253 | ], 254 | "buildVersion" : 1, 255 | "name" : "Open URL", 256 | "clientMinVersion" : 1, 257 | "summary" : "", 258 | "icon" : { 259 | "glyph" : "paperplane", 260 | "color" : "#10ADC0" 261 | }, 262 | "clientVersion" : 32 263 | } -------------------------------------------------------------------------------- /Actions/URL Decode.taioactions: -------------------------------------------------------------------------------- 1 | { 2 | "actions" : [ 3 | { 4 | "type" : "@comment", 5 | "parameters" : { 6 | "text" : { 7 | "value" : "EditorOnly", 8 | "tokens" : [ 9 | 10 | ] 11 | } 12 | } 13 | }, 14 | { 15 | "type" : "@flow.environment" 16 | }, 17 | { 18 | "type" : "@flow.if", 19 | "parameters" : { 20 | "blockIdentifier" : "8669DA7E-015B-4EC9-86D2-267D94A292FC", 21 | "condition" : 1, 22 | "rhs" : { 23 | "value" : "editor" 24 | }, 25 | "lhs" : { 26 | "value" : "$", 27 | "tokens" : [ 28 | { 29 | "location" : 0, 30 | "value" : "@input" 31 | } 32 | ] 33 | } 34 | } 35 | }, 36 | { 37 | "type" : "@flow.javascript", 38 | "parameters" : { 39 | "script" : { 40 | "value" : "$app.strings = {\n \"en\": {\n \"editorOnly\": \"Editor Only\"\n },\n \"zh-Hans\": {\n \"editorOnly\": \"仅在编辑器中可用\"\n }\n}\n$actions.resolve($l10n(\"editorOnly\"))\n" 41 | } 42 | } 43 | }, 44 | { 45 | "type" : "@ui.toast", 46 | "parameters" : { 47 | "style" : 0, 48 | "waitUntilDone" : false, 49 | "title" : { 50 | "value" : "$", 51 | "tokens" : [ 52 | { 53 | "location" : 0, 54 | "value" : "@input" 55 | } 56 | ] 57 | } 58 | } 59 | }, 60 | { 61 | "type" : "@flow.finish" 62 | }, 63 | { 64 | "type" : "@flow.else", 65 | "parameters" : { 66 | "blockIdentifier" : "8669DA7E-015B-4EC9-86D2-267D94A292FC" 67 | } 68 | }, 69 | { 70 | "type" : "@flow.endif", 71 | "parameters" : { 72 | "blockIdentifier" : "8669DA7E-015B-4EC9-86D2-267D94A292FC" 73 | } 74 | }, 75 | { 76 | "type" : "@comment", 77 | "parameters" : { 78 | "text" : { 79 | "value" : "GetTextFromFile", 80 | "tokens" : [ 81 | 82 | ] 83 | } 84 | } 85 | }, 86 | { 87 | "type" : "@flow.if", 88 | "parameters" : { 89 | "blockIdentifier" : "D64C424E-E7FA-4FE1-A4F5-1E98DB6E83F6", 90 | "condition" : 1, 91 | "rhs" : { 92 | "value" : "" 93 | }, 94 | "lhs" : { 95 | "value" : "$", 96 | "tokens" : [ 97 | { 98 | "location" : 0, 99 | "value" : "@editor.selection-text" 100 | } 101 | ] 102 | } 103 | } 104 | }, 105 | { 106 | "type" : "@text", 107 | "parameters" : { 108 | "text" : { 109 | "value" : "$", 110 | "tokens" : [ 111 | { 112 | "location" : 0, 113 | "value" : "@editor.selection-text" 114 | } 115 | ] 116 | } 117 | } 118 | }, 119 | { 120 | "type" : "@flow.else", 121 | "parameters" : { 122 | "blockIdentifier" : "D64C424E-E7FA-4FE1-A4F5-1E98DB6E83F6" 123 | } 124 | }, 125 | { 126 | "type" : "@text", 127 | "parameters" : { 128 | "text" : { 129 | "value" : "$", 130 | "tokens" : [ 131 | { 132 | "location" : 0, 133 | "value" : "@editor.full-text" 134 | } 135 | ] 136 | } 137 | } 138 | }, 139 | { 140 | "type" : "@flow.endif", 141 | "parameters" : { 142 | "blockIdentifier" : "D64C424E-E7FA-4FE1-A4F5-1E98DB6E83F6" 143 | } 144 | }, 145 | { 146 | "type" : "@flow.set-variable", 147 | "parameters" : { 148 | "value" : { 149 | "value" : "$", 150 | "tokens" : [ 151 | { 152 | "location" : 0, 153 | "value" : "@input" 154 | } 155 | ] 156 | }, 157 | "name" : { 158 | "value" : "origin" 159 | } 160 | } 161 | }, 162 | { 163 | "type" : "@flow.set-variable", 164 | "parameters" : { 165 | "value" : { 166 | "value" : "$", 167 | "tokens" : [ 168 | { 169 | "location" : 0, 170 | "value" : "@input" 171 | } 172 | ] 173 | }, 174 | "name" : { 175 | "value" : "content" 176 | } 177 | } 178 | }, 179 | { 180 | "type" : "@comment", 181 | "parameters" : { 182 | "text" : { 183 | "value" : "GetUrls", 184 | "tokens" : [ 185 | 186 | ] 187 | } 188 | } 189 | }, 190 | { 191 | "type" : "@flow.set-variable", 192 | "parameters" : { 193 | "value" : { 194 | "value" : "$", 195 | "tokens" : [ 196 | { 197 | "location" : 0, 198 | "value" : "@input" 199 | } 200 | ] 201 | }, 202 | "name" : { 203 | "value" : "input" 204 | } 205 | } 206 | }, 207 | { 208 | "type" : "@util.get-clipboard", 209 | "parameters" : { 210 | "mode" : 0 211 | } 212 | }, 213 | { 214 | "type" : "@flow.javascript", 215 | "parameters" : { 216 | "script" : { 217 | "value" : "let text = $actions.getVar(\"input\")\nif (text === \"\") text = $actions.inputValue\nconst regex = \/([a-zA-Z0-9]+:\\\/\\\/)([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([:0-9])*([\\\/\\w\\#\\.\\-\\?\\=\\&\\%\\u4e00-\\u9fa5])*\\s?\/ig\nconst urls = text.match(regex, text) ?? []\n\n$actions.resolve(urls.join(\"\\n\"))\n\n" 218 | } 219 | } 220 | }, 221 | { 222 | "type" : "@flow.if", 223 | "parameters" : { 224 | "blockIdentifier" : "B20225F6-2389-491F-A5B4-4AF9DA64F9C4", 225 | "condition" : 0, 226 | "rhs" : { 227 | "value" : "" 228 | }, 229 | "lhs" : { 230 | "value" : "$", 231 | "tokens" : [ 232 | { 233 | "location" : 0, 234 | "value" : "@input" 235 | } 236 | ] 237 | } 238 | } 239 | }, 240 | { 241 | "type" : "@comment", 242 | "parameters" : { 243 | "text" : { 244 | "value" : "NoUrlToast", 245 | "tokens" : [ 246 | 247 | ] 248 | } 249 | } 250 | }, 251 | { 252 | "type" : "@flow.javascript", 253 | "parameters" : { 254 | "script" : { 255 | "value" : "$app.strings = {\n \"en\": {\n \"noUrlToastTitle\": \"No URL detected\"\n },\n \"zh-Hans\": {\n \"noUrlToastTitle\": \"未匹配到 URL\"\n }\n}\n$actions.resolve($l10n(\"noUrlToastTitle\"))\n" 256 | } 257 | } 258 | }, 259 | { 260 | "type" : "@text", 261 | "parameters" : { 262 | "text" : { 263 | "value" : "$", 264 | "tokens" : [ 265 | { 266 | "location" : 0, 267 | "value" : "@input" 268 | } 269 | ] 270 | } 271 | } 272 | }, 273 | { 274 | "type" : "@ui.toast", 275 | "parameters" : { 276 | "style" : 0, 277 | "waitUntilDone" : false, 278 | "title" : { 279 | "value" : "$", 280 | "tokens" : [ 281 | { 282 | "location" : 0, 283 | "value" : "@input" 284 | } 285 | ] 286 | } 287 | } 288 | }, 289 | { 290 | "type" : "@flow.finish" 291 | }, 292 | { 293 | "type" : "@flow.finish" 294 | }, 295 | { 296 | "type" : "@flow.else", 297 | "parameters" : { 298 | "blockIdentifier" : "B20225F6-2389-491F-A5B4-4AF9DA64F9C4" 299 | } 300 | }, 301 | { 302 | "type" : "@flow.endif", 303 | "parameters" : { 304 | "blockIdentifier" : "B20225F6-2389-491F-A5B4-4AF9DA64F9C4" 305 | } 306 | }, 307 | { 308 | "type" : "@flow.foreach-begin", 309 | "parameters" : { 310 | "blockIdentifier" : "1126BFC5-EBE1-44FA-8862-BAFEC0C7C12F", 311 | "mode" : 0, 312 | "pattern" : { 313 | "value" : "" 314 | }, 315 | "reverse" : false, 316 | "text" : { 317 | "value" : "$", 318 | "tokens" : [ 319 | { 320 | "location" : 0, 321 | "value" : "@input" 322 | } 323 | ] 324 | }, 325 | "group" : 0 326 | } 327 | }, 328 | { 329 | "type" : "@flow.set-variable", 330 | "parameters" : { 331 | "value" : { 332 | "value" : "$", 333 | "tokens" : [ 334 | { 335 | "location" : 0, 336 | "value" : "@input" 337 | } 338 | ] 339 | }, 340 | "name" : { 341 | "value" : "url" 342 | } 343 | } 344 | }, 345 | { 346 | "type" : "@text.encode", 347 | "parameters" : { 348 | "mode" : 0, 349 | "decode" : true, 350 | "text" : { 351 | "value" : "$", 352 | "tokens" : [ 353 | { 354 | "location" : 0, 355 | "value" : "url" 356 | } 357 | ] 358 | }, 359 | "base64Options" : 0 360 | } 361 | }, 362 | { 363 | "type" : "@text.replace", 364 | "parameters" : { 365 | "mode" : 0, 366 | "pattern" : { 367 | "value" : "$", 368 | "tokens" : [ 369 | { 370 | "location" : 0, 371 | "value" : "url" 372 | } 373 | ] 374 | }, 375 | "text" : { 376 | "value" : "$", 377 | "tokens" : [ 378 | { 379 | "location" : 0, 380 | "value" : "content" 381 | } 382 | ] 383 | }, 384 | "replacement" : { 385 | "value" : "$", 386 | "tokens" : [ 387 | { 388 | "location" : 0, 389 | "value" : "@input" 390 | } 391 | ] 392 | } 393 | } 394 | }, 395 | { 396 | "type" : "@flow.set-variable", 397 | "parameters" : { 398 | "value" : { 399 | "value" : "$", 400 | "tokens" : [ 401 | { 402 | "location" : 0, 403 | "value" : "@input" 404 | } 405 | ] 406 | }, 407 | "name" : { 408 | "value" : "content" 409 | } 410 | } 411 | }, 412 | { 413 | "type" : "@flow.foreach-end", 414 | "parameters" : { 415 | "blockIdentifier" : "1126BFC5-EBE1-44FA-8862-BAFEC0C7C12F" 416 | } 417 | }, 418 | { 419 | "type" : "@ui.alert", 420 | "parameters" : { 421 | "showCancelButton" : true, 422 | "message" : { 423 | "value" : "" 424 | }, 425 | "title" : { 426 | "value" : "" 427 | }, 428 | "actions" : [ 429 | { 430 | "title" : { 431 | "value" : "Show Diff" 432 | }, 433 | "value" : { 434 | "value" : "0" 435 | } 436 | }, 437 | { 438 | "title" : { 439 | "value" : "Apply" 440 | }, 441 | "value" : { 442 | "value" : "1" 443 | } 444 | }, 445 | { 446 | "title" : { 447 | "value" : "" 448 | }, 449 | "value" : { 450 | "value" : "2" 451 | } 452 | }, 453 | { 454 | "title" : { 455 | "value" : "" 456 | }, 457 | "value" : { 458 | "value" : "3" 459 | } 460 | }, 461 | { 462 | "title" : { 463 | "value" : "" 464 | }, 465 | "value" : { 466 | "value" : "4" 467 | } 468 | }, 469 | { 470 | "title" : { 471 | "value" : "" 472 | }, 473 | "value" : { 474 | "value" : "5" 475 | } 476 | }, 477 | { 478 | "title" : { 479 | "value" : "" 480 | }, 481 | "value" : { 482 | "value" : "6" 483 | } 484 | } 485 | ] 486 | } 487 | }, 488 | { 489 | "type" : "@flow.if", 490 | "parameters" : { 491 | "blockIdentifier" : "BA296C3E-3C40-42C1-A913-7AE2525F85AF", 492 | "condition" : 0, 493 | "rhs" : { 494 | "value" : "0" 495 | }, 496 | "lhs" : { 497 | "value" : "$", 498 | "tokens" : [ 499 | { 500 | "location" : 0, 501 | "value" : "@input" 502 | } 503 | ] 504 | } 505 | } 506 | }, 507 | { 508 | "type" : "@ui.render-diff", 509 | "parameters" : { 510 | "fullScreen" : false, 511 | "rhs" : { 512 | "value" : "$", 513 | "tokens" : [ 514 | { 515 | "location" : 0, 516 | "value" : "content" 517 | } 518 | ] 519 | }, 520 | "lhs" : { 521 | "value" : "$", 522 | "tokens" : [ 523 | { 524 | "location" : 0, 525 | "value" : "origin" 526 | } 527 | ] 528 | } 529 | } 530 | }, 531 | { 532 | "type" : "@flow.restart" 533 | }, 534 | { 535 | "type" : "@flow.else", 536 | "parameters" : { 537 | "blockIdentifier" : "BA296C3E-3C40-42C1-A913-7AE2525F85AF" 538 | } 539 | }, 540 | { 541 | "type" : "@text.replace", 542 | "parameters" : { 543 | "mode" : 0, 544 | "pattern" : { 545 | "value" : "$", 546 | "tokens" : [ 547 | { 548 | "location" : 0, 549 | "value" : "origin" 550 | } 551 | ] 552 | }, 553 | "text" : { 554 | "value" : "$", 555 | "tokens" : [ 556 | { 557 | "location" : 0, 558 | "value" : "@editor.full-text" 559 | } 560 | ] 561 | }, 562 | "replacement" : { 563 | "value" : "$", 564 | "tokens" : [ 565 | { 566 | "location" : 0, 567 | "value" : "content" 568 | } 569 | ] 570 | } 571 | } 572 | }, 573 | { 574 | "type" : "@editor.set-text", 575 | "parameters" : { 576 | "createIfNotExists" : false, 577 | "location" : 0, 578 | "filename" : { 579 | "value" : "$", 580 | "tokens" : [ 581 | { 582 | "location" : 0, 583 | "value" : "@editor.file-name" 584 | } 585 | ] 586 | }, 587 | "text" : { 588 | "value" : "$", 589 | "tokens" : [ 590 | { 591 | "location" : 0, 592 | "value" : "@input" 593 | } 594 | ] 595 | } 596 | } 597 | }, 598 | { 599 | "type" : "@flow.endif", 600 | "parameters" : { 601 | "blockIdentifier" : "BA296C3E-3C40-42C1-A913-7AE2525F85AF" 602 | } 603 | } 604 | ], 605 | "buildVersion" : 1, 606 | "name" : "URL Decode", 607 | "clientMinVersion" : 1, 608 | "summary" : "", 609 | "icon" : { 610 | "glyph" : "link", 611 | "color" : "#A777FF" 612 | }, 613 | "clientVersion" : 1164 614 | } -------------------------------------------------------------------------------- /Actions/URL Encode.taioactions: -------------------------------------------------------------------------------- 1 | { 2 | "actions" : [ 3 | { 4 | "type" : "@comment", 5 | "parameters" : { 6 | "text" : { 7 | "value" : "EditorOnly", 8 | "tokens" : [ 9 | 10 | ] 11 | } 12 | } 13 | }, 14 | { 15 | "type" : "@flow.environment" 16 | }, 17 | { 18 | "type" : "@flow.if", 19 | "parameters" : { 20 | "blockIdentifier" : "8669DA7E-015B-4EC9-86D2-267D94A292FC", 21 | "condition" : 1, 22 | "rhs" : { 23 | "value" : "editor" 24 | }, 25 | "lhs" : { 26 | "value" : "$", 27 | "tokens" : [ 28 | { 29 | "location" : 0, 30 | "value" : "@input" 31 | } 32 | ] 33 | } 34 | } 35 | }, 36 | { 37 | "type" : "@flow.javascript", 38 | "parameters" : { 39 | "script" : { 40 | "value" : "$app.strings = {\n \"en\": {\n \"editorOnly\": \"Editor Only\"\n },\n \"zh-Hans\": {\n \"editorOnly\": \"仅在编辑器中可用\"\n }\n}\n$actions.resolve($l10n(\"editorOnly\"))\n" 41 | } 42 | } 43 | }, 44 | { 45 | "type" : "@ui.toast", 46 | "parameters" : { 47 | "style" : 0, 48 | "waitUntilDone" : false, 49 | "title" : { 50 | "value" : "$", 51 | "tokens" : [ 52 | { 53 | "location" : 0, 54 | "value" : "@input" 55 | } 56 | ] 57 | } 58 | } 59 | }, 60 | { 61 | "type" : "@flow.finish" 62 | }, 63 | { 64 | "type" : "@flow.else", 65 | "parameters" : { 66 | "blockIdentifier" : "8669DA7E-015B-4EC9-86D2-267D94A292FC" 67 | } 68 | }, 69 | { 70 | "type" : "@flow.endif", 71 | "parameters" : { 72 | "blockIdentifier" : "8669DA7E-015B-4EC9-86D2-267D94A292FC" 73 | } 74 | }, 75 | { 76 | "type" : "@comment", 77 | "parameters" : { 78 | "text" : { 79 | "value" : "GetTextFromFile", 80 | "tokens" : [ 81 | 82 | ] 83 | } 84 | } 85 | }, 86 | { 87 | "type" : "@flow.if", 88 | "parameters" : { 89 | "blockIdentifier" : "D64C424E-E7FA-4FE1-A4F5-1E98DB6E83F6", 90 | "condition" : 1, 91 | "rhs" : { 92 | "value" : "" 93 | }, 94 | "lhs" : { 95 | "value" : "$", 96 | "tokens" : [ 97 | { 98 | "location" : 0, 99 | "value" : "@editor.selection-text" 100 | } 101 | ] 102 | } 103 | } 104 | }, 105 | { 106 | "type" : "@text", 107 | "parameters" : { 108 | "text" : { 109 | "value" : "$", 110 | "tokens" : [ 111 | { 112 | "location" : 0, 113 | "value" : "@editor.selection-text" 114 | } 115 | ] 116 | } 117 | } 118 | }, 119 | { 120 | "type" : "@flow.else", 121 | "parameters" : { 122 | "blockIdentifier" : "D64C424E-E7FA-4FE1-A4F5-1E98DB6E83F6" 123 | } 124 | }, 125 | { 126 | "type" : "@text", 127 | "parameters" : { 128 | "text" : { 129 | "value" : "$", 130 | "tokens" : [ 131 | { 132 | "location" : 0, 133 | "value" : "@editor.full-text" 134 | } 135 | ] 136 | } 137 | } 138 | }, 139 | { 140 | "type" : "@flow.endif", 141 | "parameters" : { 142 | "blockIdentifier" : "D64C424E-E7FA-4FE1-A4F5-1E98DB6E83F6" 143 | } 144 | }, 145 | { 146 | "type" : "@flow.set-variable", 147 | "parameters" : { 148 | "value" : { 149 | "value" : "$", 150 | "tokens" : [ 151 | { 152 | "location" : 0, 153 | "value" : "@input" 154 | } 155 | ] 156 | }, 157 | "name" : { 158 | "value" : "origin" 159 | } 160 | } 161 | }, 162 | { 163 | "type" : "@flow.set-variable", 164 | "parameters" : { 165 | "value" : { 166 | "value" : "$", 167 | "tokens" : [ 168 | { 169 | "location" : 0, 170 | "value" : "@input" 171 | } 172 | ] 173 | }, 174 | "name" : { 175 | "value" : "content" 176 | } 177 | } 178 | }, 179 | { 180 | "type" : "@comment", 181 | "parameters" : { 182 | "text" : { 183 | "value" : "GetUrls", 184 | "tokens" : [ 185 | 186 | ] 187 | } 188 | } 189 | }, 190 | { 191 | "type" : "@flow.set-variable", 192 | "parameters" : { 193 | "value" : { 194 | "value" : "$", 195 | "tokens" : [ 196 | { 197 | "location" : 0, 198 | "value" : "@input" 199 | } 200 | ] 201 | }, 202 | "name" : { 203 | "value" : "input" 204 | } 205 | } 206 | }, 207 | { 208 | "type" : "@util.get-clipboard", 209 | "parameters" : { 210 | "mode" : 0 211 | } 212 | }, 213 | { 214 | "type" : "@flow.javascript", 215 | "parameters" : { 216 | "script" : { 217 | "value" : "let text = $actions.getVar(\"input\")\nif (text === \"\") text = $actions.inputValue\nconst regex = \/([a-zA-Z0-9]+:\\\/\\\/)([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([:0-9])*([\\\/\\w\\#\\.\\-\\?\\=\\&\\%\\u4e00-\\u9fa5])*\\s?\/ig\nconst urls = text.match(regex, text) ?? []\n\n$actions.resolve(urls.join(\"\\n\"))\n\n" 218 | } 219 | } 220 | }, 221 | { 222 | "type" : "@flow.if", 223 | "parameters" : { 224 | "blockIdentifier" : "AE083683-DAFF-46E0-B435-BB7C5F5046F7", 225 | "condition" : 0, 226 | "rhs" : { 227 | "value" : "" 228 | }, 229 | "lhs" : { 230 | "value" : "$", 231 | "tokens" : [ 232 | { 233 | "location" : 0, 234 | "value" : "@input" 235 | } 236 | ] 237 | } 238 | } 239 | }, 240 | { 241 | "type" : "@comment", 242 | "parameters" : { 243 | "text" : { 244 | "value" : "NoUrlToast", 245 | "tokens" : [ 246 | 247 | ] 248 | } 249 | } 250 | }, 251 | { 252 | "type" : "@flow.javascript", 253 | "parameters" : { 254 | "script" : { 255 | "value" : "$app.strings = {\n \"en\": {\n \"noUrlToastTitle\": \"No URL detected\"\n },\n \"zh-Hans\": {\n \"noUrlToastTitle\": \"未匹配到 URL\"\n }\n}\n$actions.resolve($l10n(\"noUrlToastTitle\"))\n" 256 | } 257 | } 258 | }, 259 | { 260 | "type" : "@text", 261 | "parameters" : { 262 | "text" : { 263 | "value" : "$", 264 | "tokens" : [ 265 | { 266 | "location" : 0, 267 | "value" : "@input" 268 | } 269 | ] 270 | } 271 | } 272 | }, 273 | { 274 | "type" : "@ui.toast", 275 | "parameters" : { 276 | "style" : 0, 277 | "waitUntilDone" : false, 278 | "title" : { 279 | "value" : "$", 280 | "tokens" : [ 281 | { 282 | "location" : 0, 283 | "value" : "@input" 284 | } 285 | ] 286 | } 287 | } 288 | }, 289 | { 290 | "type" : "@flow.finish" 291 | }, 292 | { 293 | "type" : "@flow.finish" 294 | }, 295 | { 296 | "type" : "@flow.else", 297 | "parameters" : { 298 | "blockIdentifier" : "AE083683-DAFF-46E0-B435-BB7C5F5046F7" 299 | } 300 | }, 301 | { 302 | "type" : "@flow.endif", 303 | "parameters" : { 304 | "blockIdentifier" : "AE083683-DAFF-46E0-B435-BB7C5F5046F7" 305 | } 306 | }, 307 | { 308 | "type" : "@flow.foreach-begin", 309 | "parameters" : { 310 | "blockIdentifier" : "8E4AFD3A-7408-4DEB-A639-4FC667F7DD6F", 311 | "mode" : 0, 312 | "pattern" : { 313 | "value" : "" 314 | }, 315 | "reverse" : false, 316 | "text" : { 317 | "value" : "$", 318 | "tokens" : [ 319 | { 320 | "location" : 0, 321 | "value" : "@input" 322 | } 323 | ] 324 | }, 325 | "group" : 0 326 | } 327 | }, 328 | { 329 | "type" : "@flow.set-variable", 330 | "parameters" : { 331 | "value" : { 332 | "value" : "$", 333 | "tokens" : [ 334 | { 335 | "location" : 0, 336 | "value" : "@input" 337 | } 338 | ] 339 | }, 340 | "name" : { 341 | "value" : "url" 342 | } 343 | } 344 | }, 345 | { 346 | "type" : "@text.encode", 347 | "parameters" : { 348 | "mode" : 0, 349 | "decode" : false, 350 | "text" : { 351 | "value" : "$", 352 | "tokens" : [ 353 | { 354 | "location" : 0, 355 | "value" : "url" 356 | } 357 | ] 358 | }, 359 | "base64Options" : 0 360 | } 361 | }, 362 | { 363 | "type" : "@text.replace", 364 | "parameters" : { 365 | "mode" : 0, 366 | "pattern" : { 367 | "value" : "$", 368 | "tokens" : [ 369 | { 370 | "location" : 0, 371 | "value" : "url" 372 | } 373 | ] 374 | }, 375 | "text" : { 376 | "value" : "$", 377 | "tokens" : [ 378 | { 379 | "location" : 0, 380 | "value" : "content" 381 | } 382 | ] 383 | }, 384 | "replacement" : { 385 | "value" : "$", 386 | "tokens" : [ 387 | { 388 | "location" : 0, 389 | "value" : "@input" 390 | } 391 | ] 392 | } 393 | } 394 | }, 395 | { 396 | "type" : "@flow.set-variable", 397 | "parameters" : { 398 | "value" : { 399 | "value" : "$", 400 | "tokens" : [ 401 | { 402 | "location" : 0, 403 | "value" : "@input" 404 | } 405 | ] 406 | }, 407 | "name" : { 408 | "value" : "content" 409 | } 410 | } 411 | }, 412 | { 413 | "type" : "@flow.foreach-end", 414 | "parameters" : { 415 | "blockIdentifier" : "8E4AFD3A-7408-4DEB-A639-4FC667F7DD6F" 416 | } 417 | }, 418 | { 419 | "type" : "@ui.alert", 420 | "parameters" : { 421 | "showCancelButton" : true, 422 | "message" : { 423 | "value" : "" 424 | }, 425 | "title" : { 426 | "value" : "" 427 | }, 428 | "actions" : [ 429 | { 430 | "title" : { 431 | "value" : "Show Diff" 432 | }, 433 | "value" : { 434 | "value" : "0" 435 | } 436 | }, 437 | { 438 | "title" : { 439 | "value" : "Apply" 440 | }, 441 | "value" : { 442 | "value" : "1" 443 | } 444 | }, 445 | { 446 | "title" : { 447 | "value" : "" 448 | }, 449 | "value" : { 450 | "value" : "2" 451 | } 452 | }, 453 | { 454 | "title" : { 455 | "value" : "" 456 | }, 457 | "value" : { 458 | "value" : "3" 459 | } 460 | }, 461 | { 462 | "title" : { 463 | "value" : "" 464 | }, 465 | "value" : { 466 | "value" : "4" 467 | } 468 | }, 469 | { 470 | "title" : { 471 | "value" : "" 472 | }, 473 | "value" : { 474 | "value" : "5" 475 | } 476 | }, 477 | { 478 | "title" : { 479 | "value" : "" 480 | }, 481 | "value" : { 482 | "value" : "6" 483 | } 484 | } 485 | ] 486 | } 487 | }, 488 | { 489 | "type" : "@flow.if", 490 | "parameters" : { 491 | "blockIdentifier" : "FE39E23C-5149-4EB0-AC9D-4F2EBAEC5D34", 492 | "condition" : 0, 493 | "rhs" : { 494 | "value" : "0" 495 | }, 496 | "lhs" : { 497 | "value" : "$", 498 | "tokens" : [ 499 | { 500 | "location" : 0, 501 | "value" : "@input" 502 | } 503 | ] 504 | } 505 | } 506 | }, 507 | { 508 | "type" : "@ui.render-diff", 509 | "parameters" : { 510 | "fullScreen" : false, 511 | "rhs" : { 512 | "value" : "$", 513 | "tokens" : [ 514 | { 515 | "location" : 0, 516 | "value" : "content" 517 | } 518 | ] 519 | }, 520 | "lhs" : { 521 | "value" : "$", 522 | "tokens" : [ 523 | { 524 | "location" : 0, 525 | "value" : "origin" 526 | } 527 | ] 528 | } 529 | } 530 | }, 531 | { 532 | "type" : "@flow.restart" 533 | }, 534 | { 535 | "type" : "@flow.else", 536 | "parameters" : { 537 | "blockIdentifier" : "FE39E23C-5149-4EB0-AC9D-4F2EBAEC5D34" 538 | } 539 | }, 540 | { 541 | "type" : "@text.replace", 542 | "parameters" : { 543 | "mode" : 0, 544 | "pattern" : { 545 | "value" : "$", 546 | "tokens" : [ 547 | { 548 | "location" : 0, 549 | "value" : "origin" 550 | } 551 | ] 552 | }, 553 | "text" : { 554 | "value" : "$", 555 | "tokens" : [ 556 | { 557 | "location" : 0, 558 | "value" : "@editor.full-text" 559 | } 560 | ] 561 | }, 562 | "replacement" : { 563 | "value" : "$", 564 | "tokens" : [ 565 | { 566 | "location" : 0, 567 | "value" : "content" 568 | } 569 | ] 570 | } 571 | } 572 | }, 573 | { 574 | "type" : "@editor.set-text", 575 | "parameters" : { 576 | "createIfNotExists" : false, 577 | "location" : 0, 578 | "filename" : { 579 | "value" : "$", 580 | "tokens" : [ 581 | { 582 | "location" : 0, 583 | "value" : "@editor.file-name" 584 | } 585 | ] 586 | }, 587 | "text" : { 588 | "value" : "$", 589 | "tokens" : [ 590 | { 591 | "location" : 0, 592 | "value" : "@input" 593 | } 594 | ] 595 | } 596 | } 597 | }, 598 | { 599 | "type" : "@flow.endif", 600 | "parameters" : { 601 | "blockIdentifier" : "FE39E23C-5149-4EB0-AC9D-4F2EBAEC5D34" 602 | } 603 | } 604 | ], 605 | "buildVersion" : 1, 606 | "name" : "URL Encode", 607 | "clientMinVersion" : 1, 608 | "summary" : "", 609 | "icon" : { 610 | "glyph" : "link", 611 | "color" : "#A777FF" 612 | }, 613 | "clientVersion" : 1164 614 | } -------------------------------------------------------------------------------- /Actions/b23clean.taioactions: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [ 3 | { 4 | "type": "@comment", 5 | "parameters": { 6 | "text": { 7 | "value": "b23.tv trace parameter cleanup" 8 | } 9 | } 10 | }, 11 | { 12 | "type": "@flow.javascript", 13 | "parameters": { 14 | "script": { 15 | "value": "(()=>{$app.strings={en:{COPY:\"Copy\",COPIED:\"Copied\",\"b23clean.converting\":\"Converting...\",\"b23clean.noUrl\":\"No link detected\",\"b23clean.noBiliUrl\":\"Not a bilibili link\",\"b23clean.success\":\"Converted to BV video link\"},\"zh-Hans\":{COPY:\"复制\",COPIED:\"已复制\",\"b23clean.converting\":\"正在转换...\",\"b23clean.noUrl\":\"未检测到链接\",\"b23clean.noBiliUrl\":\"不是 bilibili 链接\",\"b23clean.success\":\"已转换为 BV 视频链接\"}},$app.theme=\"auto\",$app.minSDKVer=\"2.19.0\",$app.minOSVer=\"14.0.0\",$app.idleTimerDisabled=!1,$app.keyboardToolbarEnabled=!0,$app.rotateDisabled=!1;class e{static #e=$objc(\"UIApplication\").$sharedApplication();static #t=$objc(\"UINotificationFeedbackGenerator\").$new();static feedbackSuccess(){e.#t.$notificationOccurred(0)}static feedbackError(){e.#t.$notificationOccurred(2)}static align={left:0,right:1,top:2,bottom:3};static textColor=$color(\"primaryText\");static linkColor=$color(\"systemLink\");static primaryViewBackgroundColor=$color(\"primarySurface\");static scrollViewBackgroundColor=$color(\"insetGroupedBackground\");static scrollViewList=[\"list\",\"matrix\"];static isLargeScreen=$device.isIpad||$device.isIpadPro;static get windowSize(){return $objc(\"UIWindow\").$keyWindow().jsValue().size}static NavigationBarNormalHeight=$objc(\"UINavigationController\").invoke(\"alloc.init\").$navigationBar().jsValue().frame.height;static NavigationBarLargeTitleHeight=$objc(\"UITabBarController\").invoke(\"alloc.init\").$tabBar().jsValue().frame.height+e.NavigationBarNormalHeight;static get isSplitScreenMode(){return e.isLargeScreen&&$device.info.screen.width!==e.windowSize.width}static get topSafeAreaInsets(){return e.#e?.$keyWindow()?.$safeAreaInsets()?.top??0}static get bottomSafeAreaInsets(){return e.#e?.$keyWindow()?.$safeAreaInsets()?.bottom??0}static get statusBarOrientation(){return e.#e.$statusBarOrientation()}static get consoleBarHeight(){if($app.isDebugging){let t=e.#e.$statusBarFrame().height+26;return $device.isIphoneX&&(t+=30),t}return 0}static get isHorizontal(){return 3===e.statusBarOrientation||4===e.statusBarOrientation}static loading(){let t=$ui.create(e.blurBox({cornerRadius:15},[{type:\"spinner\",props:{loading:!0,style:0},layout:(e,t)=>{e.size.equalTo(t.prev),e.center.equalTo(t.super)}}]));return{start:()=>{$ui.controller.view.insertAtIndex(t,0),t.layout((t,i)=>{t.center.equalTo(i.super);let a=Math.min(.6*Math.min(e.windowSize.width,e.windowSize.height),260);t.size.equalTo($size(a,a))}),t.moveToFront()},end:()=>{t.remove()}}}static defaultBackgroundColor(t){return e.scrollViewList.indexOf(t)>-1?e.scrollViewBackgroundColor:e.primaryViewBackgroundColor}static separatorLine(t={},i=e.align.bottom){return{type:\"canvas\",props:t,layout:(t,a)=>{void 0===a.prev?t.top.equalTo(a.super):i===e.align.bottom?t.top.equalTo(a.prev.bottom):t.top.equalTo(a.prev.top),t.height.equalTo(1/$device.info.screen.scale),t.left.right.inset(0)},events:{draw:(e,i)=>{i.strokeColor=t.bgcolor??$color(\"separatorColor\"),i.setLineWidth(1),i.moveToPoint(0,0),i.addLineToPoint(e.frame.width,0),i.strokePath()}}}}static blurBox(e={},t=[],i=$layout.fill){return{type:\"blur\",props:Object.assign({style:$blurStyle.thinMaterial},e),views:t,layout:i}}static getContentSize(t,i=\"A\",a=e.windowSize.width,o){let r={text:i,width:a,font:t};return void 0!==o&&(r.lineSpacing=o),$text.sizeThatFits(r)}static getSymbolSize(e,t){let i=(e=\"string\"==typeof e?$image(e):e).size.width/e.size.height;return e.size.width>e.size.height?$size(t,t/i):$size(t*i,t)}static push({views:e,statusBarStyle:t=0,title:i=\"\",navButtons:a=[{title:\"\"}],bgcolor:o=e[0]?.props?.bgcolor??\"primarySurface\",titleView:r,disappeared:s}={}){let n={statusBarStyle:t,navButtons:a,title:i,bgcolor:\"string\"==typeof o?$color(o):o};r&&(n.titleView=r),$ui.push({props:n,events:{disappeared:()=>{void 0!==s&&s()}},views:[{type:\"view\",views:e,layout:(e,t)=>{e.top.equalTo(t.super.safeArea),e.bottom.equalTo(t.super),e.left.right.equalTo(t.super.safeArea)}}]})}}class t{static type={info:void 0,success:\"checkmark\",warning:\"exclamationmark.triangle\",error:\"xmark.circle\"};static edges=40;static iconSize=100;static labelTopMargin=10;static defaultFont=$font(\"default\",26);width=Math.min(.6*e.windowSize.width,260);labelWidth=this.width-2*t.edges;id=$text.uuid;#i=\"\";font=t.defaultFont;type=t.type.info;labelLines=2;constructor(e,i=t.type.info,a=2,o=t.defaultFont){this.type=i,this.message=e,this.labelLines=a,this.font=o}get message(){return this.#i}set message(i){this.#i=i,this.fontHeight=e.getContentSize(this.font,this.message,this.labelWidth,this.labelLines).height,this.height=(this.hasIcon?t.labelTopMargin+t.iconSize:0)+this.fontHeight+2*t.edges}get hasIcon(){return void 0!==this.type}get blurBox(){let i=e.blurBox({id:this.id,cornerRadius:15,alpha:0},[{type:\"image\",props:{symbol:this.type,hidden:!this.hasIcon,tintColor:$color(\"lightGray\")},layout:(e,i)=>{e.top.inset(t.edges),e.size.equalTo(t.iconSize),e.centerX.equalTo(i.super)}},{type:\"label\",props:{font:this.font,text:this.message,align:$align.center,lines:this.labelLines,color:$color(\"lightGray\")},layout:(e,i)=>{e.bottom.equalTo(i.supper).offset(-t.edges),e.width.equalTo(this.labelWidth),e.height.equalTo(this.fontHeight),e.centerX.equalTo(i.super)}}]);return i.events={tapped:()=>{this.remove()}},i}show(){$ui.controller.view.insertAtIndex($ui.create(this.blurBox),0);let e=$(this.id);e.layout((e,t)=>{e.center.equalTo(t.super),e.size.equalTo($size(this.width,this.height))}),e.moveToFront(),$ui.animate({duration:.2,animation:()=>{e.alpha=1}})}remove(){let e=$(this.id);e&&$ui.animate({duration:.2,animation:()=>{e.alpha=0},completion:()=>{e.remove()}})}static toast({message:e,type:i=t.type.info,show:a=!0,displayTime:o=2,labelLines:r=2,font:s=t.defaultFont}){let n=new t(e,i,r,s);return a&&(n.show(),$delay(o,()=>{n.remove()})),n}static info(e,i={}){return t.toast(Object.assign({message:e,type:t.type.info},i))}static success(e,i={}){return t.toast(Object.assign({message:e,type:t.type.success},i))}static warning(e,i={}){return t.toast(Object.assign({message:e,type:t.type.warning},i))}static error(e,i={}){return t.toast(Object.assign({message:e,type:t.type.error},i))}}async function i(e){if(-1===e.indexOf(\"bilibili.com\")&&-1===e.indexOf(\"b23.tv\"))throw Error($l10n(\"b23clean.noBiliUrl\"));let t=e;e.indexOf(\"b23.tv\")>=0&&(t=(await $http.get(e)).response.url);let i=t.indexOf(\"?\");return i>-1&&(t=t.substring(0,i-1)),t}async function a(){let e=t.info($l10n(\"b23clean.converting\"),{show:!1});try{let a=(()=>{let e=[$actions.inputValue,$clipboard.text];for(let t=0;t1){let e=await $ui.menu({items:a});o=a[e.index]}if(-1===o.indexOf(\"bilibili.com\")&&-1===o.indexOf(\"b23.tv\"))throw Error($l10n(\"b23clean.noBiliUrl\"));e.show(),o=await i(o),e.remove(),await $ui.alert({title:$l10n(\"b23clean.success\"),message:o,actions:[{title:$l10n(\"OK\")},{title:$l10n(\"COPY\"),handler:()=>{$clipboard.text=o,t.success($l10n(\"COPIED\"))}}]})}catch(i){e.remove(),$delay(.5,()=>t.error(String(i)))}}({run:()=>{a().catch(e=>console.error(e))}}).run()})();" 16 | } 17 | } 18 | } 19 | ], 20 | "buildVersion": 1, 21 | "clientMinVersion": 1, 22 | "summary": "", 23 | "icon": { 24 | "glyph": "trash", 25 | "color": "#FF3300" 26 | }, 27 | "clientVersion": 592, 28 | "name": "b23clean" 29 | } -------------------------------------------------------------------------------- /Juice/README.md: -------------------------------------------------------------------------------- 1 | # Juice 2 | 3 | > 4 | 5 | Given HTML, Juice will inline your CSS properties into the style attribute. 6 | 7 | ## Install 8 | 9 | JSBox: 10 | 11 | - Juice.js: [Click to Install](jsbox://import?url=https%3A%2F%2Fraw.githubusercontent.com%2Fipuppet%2FTaioActions%2Fmain%2FJuice%2Fdist%2FJuice.js) 12 | 13 | Taio: 14 | 15 | - Juice: [Click to Install](taio://actions?action=import&url=https%3A%2F%2Fraw.githubusercontent.com%2Fipuppet%2FTaioActions%2Fmain%2FActions%2FJuice.taioactions) 16 | -------------------------------------------------------------------------------- /Juice/build.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs") 2 | const path = require("path") 3 | const process = require("child_process") 4 | 5 | const config = JSON.parse(fs.readFileSync(path.join(__dirname, "config.json"), "utf-8")) 6 | 7 | const outputName = config.info.name 8 | const distEntryPath = path.join(__dirname, `dist/${outputName}.js`) 9 | const entryFileContent = fs.readFileSync(path.join(__dirname, "main.js"), "utf-8") 10 | 11 | const entryFile = "main.build.js" 12 | const entryFilePath = path.join(__dirname, entryFile) 13 | 14 | function injectContent() { 15 | const stringsFolder = path.join(__dirname, "strings") 16 | const stringsFiles = fs.readdirSync(stringsFolder) 17 | const localizedText = {} 18 | stringsFiles.forEach(fileName => { 19 | if (path.extname(fileName) !== ".strings") { 20 | return 21 | } 22 | 23 | const locale = fileName.replace(".strings", "") 24 | localizedText[locale] = {} 25 | 26 | const filePath = path.join(stringsFolder, fileName) 27 | const content = fs.readFileSync(filePath, "utf-8") 28 | const lines = content.split(/\r?\n/) 29 | lines.forEach(line => { 30 | const match = /[\"'](.+)[\"'][ \n]*=[ \n]*[\"'](.+)[\"']/.exec(line) 31 | if (match) { 32 | localizedText[locale][match[1]] = match[2] 33 | } 34 | }) 35 | }) 36 | const stringsText = `$app.strings = ${JSON.stringify(localizedText)};` 37 | 38 | const configSettings = Object.keys(config.settings) 39 | .map(key => { 40 | const value = (() => { 41 | const value = config.settings[key] 42 | if (typeof value === "string") { 43 | return `"${value}"` 44 | } else { 45 | return value 46 | } 47 | })() 48 | return `$app.${key} = ${value};` 49 | }) 50 | .join("\n") 51 | 52 | const contents = [stringsText, configSettings, entryFileContent] 53 | 54 | fs.writeFileSync(entryFilePath, contents.join("\n\n")) 55 | } 56 | 57 | function buildTextActions() { 58 | const script = fs.readFileSync(distEntryPath, "utf-8") 59 | const template = path.join(__dirname, "template.json") 60 | const fileContent = fs.readFileSync(template, "utf-8") 61 | const textAction = JSON.parse(fileContent) 62 | 63 | textAction.name = config.info.name 64 | 65 | for (let i = 0; i < textAction.actions.length; i++) { 66 | if (textAction.actions[i].type === "@flow.javascript") { 67 | textAction.actions[i].parameters.script.value = script 68 | break 69 | } 70 | } 71 | const outputPath = path.join(__dirname, `dist/${outputName}.json`) 72 | fs.writeFileSync(outputPath, JSON.stringify(textAction, null, 4)) 73 | } 74 | 75 | function injectPackageJson(packageJson) { 76 | packageJson.jsbox = distEntryPath 77 | packageJson.targets = { 78 | jsbox: { 79 | source: entryFile, 80 | includeNodeModules: false, 81 | sourceMap: false, 82 | outputFormat: "global" 83 | } 84 | } 85 | 86 | return packageJson 87 | } 88 | 89 | async function build() { 90 | const packageJsonPath = path.join(__dirname, "package.json") 91 | const packageJsonContent = fs.readFileSync(packageJsonPath, "utf-8") 92 | 93 | const packageJson = injectPackageJson(JSON.parse(packageJsonContent)) 94 | fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson)) 95 | 96 | try { 97 | injectContent() 98 | const stdout = process.execSync(`parcel build`) 99 | console.log(stdout.toString()) 100 | buildTextActions() 101 | } catch (error) { 102 | if (error.stdout) { 103 | console.error(error.stdout.toString()) 104 | } else { 105 | console.error(error) 106 | } 107 | } finally { 108 | // 恢复文件内容 109 | fs.unlinkSync(entryFilePath) 110 | fs.writeFileSync(packageJsonPath, packageJsonContent) 111 | } 112 | } 113 | 114 | build() 115 | -------------------------------------------------------------------------------- /Juice/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "name": "Juice", 4 | "version": "0.0.1", 5 | "author": "ipuppet", 6 | "module": false 7 | }, 8 | "settings": { 9 | "theme": "auto", 10 | "minSDKVer": "2.19.0", 11 | "minOSVer": "13.0.0", 12 | "idleTimerDisabled": false, 13 | "keyboardToolbarEnabled": true, 14 | "rotateDisabled": false 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Juice/main.js: -------------------------------------------------------------------------------- 1 | // run app 2 | const app = require("./scripts/app") 3 | app.run() -------------------------------------------------------------------------------- /Juice/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "license": "MIT", 3 | "scripts": { 4 | "build": "node build.js" 5 | } 6 | } -------------------------------------------------------------------------------- /Juice/scripts/app.js: -------------------------------------------------------------------------------- 1 | const { UIKit, Kernel, Logger } = require("./lib/easy-jsbox") 2 | const juice = require("./lib/juice.min.js") 3 | 4 | class AppKernel extends Kernel { 5 | constructor() { 6 | super() 7 | this.logger = new Logger() 8 | this.juice = juice 9 | } 10 | } 11 | 12 | class AppUI { 13 | static renderMainUI() { 14 | const kernel = new AppKernel() 15 | kernel.useJsboxNav() 16 | const MainUI = require("./ui/main") 17 | const mainUI = new MainUI(kernel) 18 | kernel.setNavButtons(mainUI.getNavButtons()) 19 | kernel.UIRender(mainUI.getView()) 20 | } 21 | 22 | static renderUnsupported() { 23 | $intents.finish("不支持在此环境中运行") 24 | $ui.render({ 25 | views: [ 26 | { 27 | type: "label", 28 | props: { 29 | text: "不支持在此环境中运行", 30 | align: $align.center 31 | }, 32 | layout: $layout.fill 33 | } 34 | ] 35 | }) 36 | } 37 | 38 | static handleTaio() { 39 | try { 40 | const text = $actions.inputValue 41 | const result = juice(text) 42 | $actions.resolve(result) 43 | } catch (error) { 44 | $actions.reject(error) 45 | } 46 | } 47 | } 48 | 49 | module.exports = { 50 | run: () => { 51 | if (UIKit.isTaio) { 52 | AppUI.handleTaio() 53 | } else if ($app.env === $env.app) { 54 | AppUI.renderMainUI() 55 | } else { 56 | AppUI.renderUnsupported() 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Juice/scripts/lib/easy-jsbox.js: -------------------------------------------------------------------------------- 1 | var vt="1.4.4",q=class{title;handler;constructor({title:t=$l10n("OK"),disabled:e=!1,style:i=$alertActionType.default,handler:s=()=>{}}={}){this.title=t,this.disabled=e,this.style=i,this.handler=s}},at=class a{id=$text.uuid;title;message;actions;titleFont=$font("bold",20);messageFont=$font(14);actionButtonFontSize=16;actionButtonHighlight=$color($rgba(0,0,0,.2),$rgba(255,255,255,.2));actionButtonHeight=35;actionButtonBoderWidth=.5;actionButtonBorderColor=$color("#C9C9C9","#383838");boxWidth=250;textVerticalMargin=20;textHorizontalMargin=50;constructor({title:t="",message:e="",actions:i=[]}={}){this.title=t,this.message=e,this.actions=i,this.actions.length===0&&this.actions.push(new q),this.titleSize=h.getContentSize(this.titleFont,this.title,this.boxWidth-this.textHorizontalMargin*2),this.messageSize=h.getContentSize(this.messageFont,this.message,this.boxWidth-this.textHorizontalMargin*2)}textView(){return{type:"view",views:[{type:"label",props:{lines:0,font:this.titleFont,text:this.title,color:$color("tint"),align:$align.center},layout:(t,e)=>{t.centerX.equalTo(e.super),t.width.equalTo(this.boxWidth-this.textHorizontalMargin*2),t.height.equalTo(this.titleSize.height),t.top.equalTo(this.textVerticalMargin)}},{type:"label",props:{lines:0,font:this.messageFont,text:this.message,align:$align.center},layout:(t,e)=>{t.centerX.equalTo(e.super),t.width.equalTo(this.boxWidth-this.textHorizontalMargin*2),t.height.equalTo(this.messageSize.height),t.top.equalTo(e.prev.bottom)}}],layout:(t,e)=>{t.top.width.equalTo(e.super),t.height.equalTo(this.titleSize.height+this.messageSize.height+this.textVerticalMargin*2)}}}actionView(){let t=(e,i)=>{let s=l=>this.actions.length===2?l.y>=0&&l.x>=0&&l.y<=this.actionButtonHeight&&l.x<=this.boxWidth/2:l.y>=0&&l.x>=0&&l.y<=this.actionButtonHeight&&l.x<=this.boxWidth,o=async(l,c,p)=>{e.disabled||(l.bgcolor=$color("clear"),s(c)&&(typeof e.handler=="function"&&await e.handler({index:i,title:e.title}),this.dismiss()))},r=$color("tint"),n=$font(this.actionButtonFontSize);return e.disabled?r=$color("gray"):e.style===$alertActionType.destructive?r=$color("red"):e.style===$alertActionType.cancel&&(n=$font("bold",this.actionButtonFontSize)),{type:"label",props:{lines:1,text:e.title,align:$align.center,font:n,color:r,borderWidth:this.actionButtonBoderWidth,borderColor:this.actionButtonBorderColor,bgcolor:$color("clear")},events:{tapped:()=>{},touchesBegan:l=>{e.disabled||(l.bgcolor=this.actionButtonHighlight)},touchesEnded:o,touchesCancelled:o,touchesMoved:(l,c,p)=>{e.disabled||(s(c)?l.bgcolor=this.actionButtonHighlight:l.bgcolor=$color("clear"))}},layout:(l,c)=>{this.actions.length===2?c.prev?(l.left.equalTo(c.prev.right).offset(-this.actionButtonBoderWidth),l.width.equalTo(c.super).dividedBy(2).offset(this.actionButtonBoderWidth)):l.width.equalTo(c.super).dividedBy(2):(l.width.equalTo(c.super),c.prev&&l.top.equalTo(c.prev.bottom).offset(-this.actionButtonBoderWidth)),l.height.equalTo(this.actionButtonHeight)}}};return{type:"view",views:this.actions.map((e,i)=>t(e,i)),layout:(e,i)=>{e.left.equalTo(i.super).offset(-this.actionButtonBoderWidth),e.width.equalTo(i.super).offset(this.actionButtonBoderWidth*2),e.bottom.equalTo(i.super),e.top.equalTo(i.prev.bottom)}}}getView(){let t={type:"view",props:{id:this.id+"-box",smoothCorners:!0,cornerRadius:20,bgcolor:$color("#FFFFFF","#000000")},views:[this.textView(),this.actionView()],layout:(e,i)=>{e.center.equalTo(i.super.safeArea);let s=this.titleSize.height+this.messageSize.height+this.textVerticalMargin*2,o=this.actions.length>2?this.actions.length:1;s+=this.actionButtonHeight*o,s-=this.actionButtonBoderWidth*o;let r=this.boxWidth-this.actionButtonBoderWidth*2;e.size.equalTo($size(r,s))}};return{type:"view",props:{id:this.id,alpha:0,bgcolor:$rgba(0,0,0,.6)},views:[t],layout:$layout.fill}}present(){let t=$ui.create(this.getView());$ui.controller.view.hidden?$ui.controller.view.super.insertAtIndex(t,0):$ui.controller.view.insertAtIndex(t,0);let e=$(this.id);e.layout($layout.fill),e.moveToFront(),$ui.animate({duration:.3,animation:()=>{e.alpha=1}})}dismiss(){let t=$(this.id);$ui.animate({duration:.3,animation:()=>{t.alpha=0},completion:()=>{t.remove()}})}static fromJsbox(t){return new Promise((e,i)=>{new a({title:t.title,message:t.message,actions:t?.actions?.map(o=>(o.handler||(o.handler=r=>{e(r)}),new q(o)))}).present()})}},v=class{events={};setEvents(t){return Object.keys(t).forEach(e=>this.setEvent(e,t[e])),this}setEvent(t,e){return this.events[t]=e,this}appendEvent(t,e){let i=this.events[t];return typeof i=="function"?this.events[t]=(...s)=>{i(...s),e(...s)}:this.setEvent(t,e),this}callEvent(t,...e){typeof this.events[t]=="function"&&this.events[t](...e)}},nt=class{viewController;constructor(){this.edges=10,this.iconSize=25}setViewController(t){this.viewController=t}get menu(){return{items:[{title:$l10n("SHARE"),symbol:"square.and.arrow.up",handler:async(t,e)=>{let i=t.object(e).info.info;$share.sheet([$file.absolutePath(i.path)])}}]}}delete(t){$file.delete(t.path)}edit(t){let e=$file.read(t.path);if(e.info?.mimeType?.startsWith("image"))b.quickLookImage(e,t.path.substring(t.path.lastIndexOf("/")+1));else{let i=new b,s=$text.uuid;i.setView({type:"code",layout:$layout.fill,props:{id:s,lineNumbers:!0,theme:$device.isDarkMode?"atom-one-dark":"atom-one-light",text:e.string,insets:$insets(15,15,15,15)}}).addNavBar({title:t.file,popButton:{title:$l10n("CLOSE")},rightButtons:[{title:$l10n("SAVE"),tapped:()=>{$file.write({data:$data({string:$(s).text}),path:t.path}),$ui.success($l10n("SAVE_SUCCESS"))}}]}),i.init().present()}}getFiles(t=""){return $file.list(t).map(e=>{let i=t+"/"+e,s=$file.isDirectory(i);return{info:{info:{path:i,file:e,isDirectory:s}},icon:{symbol:s?"folder.fill":"doc"},name:{text:e},size:{text:s?"":"--"}}}).sort((e,i)=>{if(e.info.info.isDirectory!==i.info.info.isDirectory)return e.info.info.isDirectory?-1:1;if(e.info.info.isDirectory===i.info.info.isDirectory)return e.info.info.file.localeCompare(i.info.info.file)})}async loadFileSize(t){return t.map((e,i)=>{let s=e.info.info;if(!s.isDirectory)try{t[i].size.text=h.bytesToSize($file.read(s.path).info.size)}catch(o){t[i].size.text=o}}),t}get listTemplate(){return{props:{bgcolor:$color("clear")},views:[{props:{id:"info"}},{type:"image",props:{id:"icon"},layout:(t,e)=>{t.centerY.equalTo(e.super),t.left.inset(this.edges),t.size.equalTo(this.iconSize)}},{type:"view",views:[{type:"label",props:{id:"size",color:$color("secondaryText"),lines:1},layout:(t,e)=>{t.height.equalTo(e.super),t.right.inset(this.edges)}},{type:"label",props:{id:"name",lines:1},layout:(t,e)=>{t.height.left.equalTo(e.super),t.right.equalTo(e.prev.left).offset(-this.edges)}}],layout:(t,e)=>{t.height.right.equalTo(e.super),t.left.equalTo(e.prev.right).offset(this.edges)}}]}}#t(t){let e=t.lastIndexOf("/"),i=t.substring(e<0?0:e+1),s=this.getListView(t),o=async()=>{let r=$file.absolutePath(t);(await $ui.alert({title:"Path",message:r,actions:[{title:$l10n("COPY")},{title:$l10n("OK")}]})).index===0&&($clipboard.text=r,$ui.toast($l10n("COPIED")))};if(this.viewController){let r=new m;r.setView(s).navigationBarTitle(i),r.navigationBar.setLargeTitleDisplayMode(g.largeTitleDisplayModeNever),r.navigationBarItems.addRightButton({symbol:"info.circle",tapped:o}),this.viewController.push(r)}else h.push({title:i,views:[s],navButtons:[{symbol:"info.circle",handler:o}]})}getListView(t=""){return{type:"list",props:{menu:this.menu,bgcolor:h.primaryViewBackgroundColor,separatorInset:$insets(0,this.edges,0,0),data:[],template:this.listTemplate,actions:[{title:" "+$l10n("DELETE")+" ",color:$color("red"),handler:(e,i)=>{let s=e.object(i).info.info;h.deleteConfirm($l10n("FILE_MANAGER_DELETE_CONFIRM_MSG")+' "'+s.file+'" ?',()=>{this.delete(s),e.delete(i)})}}]},layout:$layout.fill,events:{ready:e=>{let i=this.getFiles(t);e.data=i,this.loadFileSize(i).then(s=>{e.data=s})},pulled:async e=>{let i=this.getFiles(t);e.data=i,e.data=await this.loadFileSize(i),$delay(.5,()=>{e.endRefreshing()})},didSelect:(e,i,s)=>{let o=s.info.info;o.isDirectory?this.#t(o.path):this.edit(o)}}}}push(t=""){this.#t(t)}},S=class a{basePath;constructor({basePath:t="storage"}={}){this.basePath=t,this.#t(this.basePath)}static join(...t){let e=t.length,i=t[0];if(e<2)return i;for(let s=0;ss&&(i=t.substring(s+1),t=t.substring(0,s+1))}return e&&this.#t(t),t+i}exists(t=""){return t=this.filePath(t,!1),!!$file.exists(t)}write(t="",e){return new Promise((i,s)=>{try{let o=this.writeSync(t,e);o?i(o):s(o)}catch(o){s(o)}})}writeSync(t="",e){if(!e)throw new A("data");return $file.write({data:e,path:this.filePath(t)})}read(t=""){return new Promise((e,i)=>{try{let s=this.readSync(t);s?e(s):i()}catch(s){i(s)}})}readSync(t=""){if(t=this.filePath(t),!$file.exists(t))throw new x(t);return $file.isDirectory(t)?$file.list(t):$file.read(t)}readAsJSON(t="",e=null){try{let i=this.readSync(t)?.string;return JSON.parse(i)}catch{return e}}static readFromRoot(t=""){return new Promise((e,i)=>{try{let s=a.readFromRootSync(t);s?e(s):i()}catch(s){i(s)}})}static readFromRootSync(t=""){if(!t)throw new A("path");if(!$file.exists(t))throw new x(t);return $file.isDirectory(t)?$file.list(t):$file.read(t)}static readFromRootAsJSON(t="",e=null){try{let i=a.readFromRootSync(t)?.string;return JSON.parse(i)}catch{return e}}delete(t=""){return $file.delete(this.filePath(t,!1))}copy(t,e){t=this.filePath(t),e=this.filePath(e),$file.copy({src:t,dst:e})}move(t,e){t=this.filePath(t),e=this.filePath(e),$file.move({src:t,dst:e})}},lt=class a{startTime=Date.now();isUseJsboxNav=!1;title=$addin?.current?.name;constructor(){$app.isDebugging&&(console.log("You are running EasyJsBox in debug mode."),$app.idleTimerDisabled=!0),H.init()}static isObject(t){return t!=null&&typeof t=="object"}static objectEqual(t,e){let i=Object.keys(t),s=Object.keys(e);if(i.length!==s.length)return!1;i.sort(),s.sort();for(let o=0;on?i[n]:0,c=isNaN(Number(l))?l.charCodeAt():Number(l),p=s.length>n?s[n]:0,f=isNaN(Number(p))?p.charCodeAt():Number(p);if(cf){r=1;break}}return r}useJsboxNav(){return this.isUseJsboxNav=!0,this}setTitle(t){this.isUseJsboxNav&&($ui.title=t),this.title=t}setNavButtons(t){this.navButtons=t}openInJsbox(){$app.openURL(`jsbox://run?name=${this.title}`)}UIRender(t={}){let e=$context.query;if(e.type==="alertFromKeyboard"){let i=JSON.parse($text.URLDecode(e.value));i.actions=[{title:$l10n("CANCEL")}],$ui.alert(i);return}try{t.props=Object.assign({title:this.title,navBarHidden:!this.isUseJsboxNav,navButtons:this.navButtons??[],statusBarStyle:0},t.props),t.events||(t.events={});let i=t.events.layoutSubviews;t.events.layoutSubviews=()=>{$app.notify({name:"interfaceOrientationEvent",object:{statusBarOrientation:h.statusBarOrientation,isHorizontal:h.isHorizontal}}),typeof i=="function"&&i()},$ui.render(t)}catch(i){this.print(i)}}KeyboardRender(t={}){t.id||(t.id=$text.uuid),$ui.render(),$delay(0,()=>{$ui.controller.view=$ui.create(t),$ui.controller.view.layout(t.layout)})}KeyboardRenderWithViewFunc(t){$ui.render(),$delay(0,()=>{$ui.controller.view=$ui.create({type:"view"}),$delay(0,async()=>{let e=await t();e.id||(e.id=$text.uuid),$ui.controller.view=$ui.create(e),$ui.controller.view.layout(e.layout)})})}async checkUpdate(){let t="dev",e=await $http.get(`https://raw.githubusercontent.com/ipuppet/EasyJsBox/${t}/src/version.js`);if(e.error)throw e.error;let i=e.data.match(/.*VERSION.+\"([0-9\.]+)\"/)[1];if(this.print(`easy-jsbox latest version: ${i}`),a.versionCompare(i,vt)>0){let s=await $http.get(`https://raw.githubusercontent.com/ipuppet/EasyJsBox/${t}/dist/easy-jsbox.js`);if(s.error)throw s.error;return s.data}return!1}},H=class{static l10n(t,e,i){if(typeof e=="string"){let o={};e.split(";").forEach(n=>{if(n=n.trim(),n!==""){let l=n.split("=");o[l[0].trim().slice(1,-1)]=l[1].trim().slice(1,-1)}}),e=o}let s=$app.strings;if(i)Object.assign(s[t],e);else for(let o in e)s[t][o]||(s[t][o]=e[o]);$app.strings=s}static set(t,e){this.l10n(t,e,!0)}static add(t,e){this.l10n(t,e,!1)}static init(){this.add("zh-Hans",{OK:"\u597D",DONE:"\u5B8C\u6210",CANCEL:"\u53D6\u6D88",CLEAR:"\u6E05\u9664",BACK:"\u8FD4\u56DE",ERROR:"\u53D1\u751F\u9519\u8BEF",SUCCESS:"\u6210\u529F",INVALID_VALUE:"\u975E\u6CD5\u53C2\u6570",CONFIRM_CHANGES:"\u6570\u636E\u5DF2\u53D8\u5316\uFF0C\u786E\u8BA4\u4FEE\u6539\uFF1F",SETTING:"\u8BBE\u7F6E",GENERAL:"\u4E00\u822C",ADVANCED:"\u9AD8\u7EA7",TIPS:"\u5C0F\u8D34\u58EB",COLOR:"\u989C\u8272",COPY:"\u590D\u5236",COPIED:"\u590D\u5236\u6210\u529F",JSBOX_ICON:"JSBox \u5185\u7F6E\u56FE\u6807",SF_SYMBOLS:"SF Symbols",IMAGE_BASE64:"\u56FE\u7247 / base64",PREVIEW:"\u9884\u89C8",SELECT_IMAGE_PHOTO:"\u4ECE\u76F8\u518C\u9009\u62E9\u56FE\u7247",SELECT_IMAGE_ICLOUD:"\u4ECE iCloud \u9009\u62E9\u56FE\u7247",CLEAR_IMAGE:"\u6E05\u9664\u56FE\u7247",NO_IMAGE:"\u65E0\u56FE\u7247",ABOUT:"\u5173\u4E8E",VERSION:"Version",AUTHOR:"\u4F5C\u8005",AT_BOTTOM:"\u5DF2\u7ECF\u5230\u5E95\u5566~"}),this.add("en",{OK:"OK",DONE:"Done",CANCEL:"Cancel",CLEAR:"Clear",BACK:"Back",ERROR:"Error",SUCCESS:"Success",INVALID_VALUE:"Invalid value",CONFIRM_CHANGES:"The data has changed, confirm the modification?",SETTING:"Setting",GENERAL:"General",ADVANCED:"Advanced",TIPS:"Tips",COLOR:"Color",COPY:"Copy",COPIED:"Copide",JSBOX_ICON:"JSBox in app icon",SF_SYMBOLS:"SF Symbols",IMAGE_BASE64:"Image / base64",PREVIEW:"Preview",SELECT_IMAGE_PHOTO:"Select From Photo",SELECT_IMAGE_ICLOUD:"Select From iCloud",CLEAR_IMAGE:"Clear Image",NO_IMAGE:"No Image",ABOUT:"About",VERSION:"Version",AUTHOR:"Author",AT_BOTTOM:"It's the end~"}),this.add("zh-Hans",{DELETE_CONFIRM_TITLE:"\u5220\u9664\u524D\u786E\u8BA4"}),this.add("en",{DELETE_CONFIRM_TITLE:"Delete Confirmation"}),this.add("zh-Hans",{FILE_MANAGER_DELETE_CONFIRM_MSG:"\u786E\u8BA4\u8981\u5220\u9664\u5417",DELETE:"\u5220\u9664",CANCEL:"\u53D6\u6D88",CLOSE:"\u5173\u95ED",SHARE:"\u5206\u4EAB",SAVE:"\u4FDD\u5B58",SAVE_SUCCESS:"\u4FDD\u5B58\u6210\u529F"}),this.add("en",{FILE_MANAGER_DELETE_CONFIRM_MSG:"Are you sure you want to delete",DELETE:"Delete",CANCEL:"Cancel",CLOSE:"Close",SHARE:"Share",SAVE:"Save",SAVE_SUCCESS:"Save Success"})}},V=class a{static level={info:"info",warn:"warn",error:"error"};writer;fsLevels=[a.level.error];printToFile(t){this.fsLevels=t}setWriter(t,e){this.writer=i=>{t.exists(e)&&(i=(t.readSync(e)?.string??"")+i),t.writeSync(e,$data({string:i}))}}format(t,e){return`${new Date().toUTCString()} [${e.toUpperCase()}] ${t} 2 | `}log(t,e){this.writer&&this.fsLevels.includes(e)&&this.writer(this.format(t,e)),$app.isDebugging&&console[e](t)}info(t){this.log(t,a.level.info)}warn(t){this.log(t,a.level.warn)}error(t){this.log(t,a.level.error)}},R=class{rightButtons=[];leftButtons=[];#t={};hasbutton=!1;isPinTitleView=!1;setTitleView(t){return this.titleView=t,this}pinTitleView(){return this.isPinTitleView=!0,this}setFixedFooterView(t){return this.fixedFooterView=t,this}setRightButtons(t){return t.forEach(e=>this.addRightButton(e)),this.hasbutton||(this.hasbutton=!0),this}setLeftButtons(t){return t.forEach(e=>this.addLeftButton(e)),this.hasbutton||(this.hasbutton=!0),this}addRightButton({id:t,symbol:e,title:i,tapped:s,menu:o,events:r,color:n}={}){let l=E.creat({id:t,symbol:e,title:i,tapped:s,menu:o,events:r,color:n,align:h.align.right});return this.rightButtons.push(l),this.#t[t??l.id]=l,this.hasbutton||(this.hasbutton=!0),this}addLeftButton({id:t,symbol:e,title:i,tapped:s,menu:o,events:r,color:n}={}){let l=E.creat({id:t,symbol:e,title:i,tapped:s,menu:o,events:r,color:n,align:h.align.left});return this.leftButtons.push(l),this.#t[t??l.id]=l,this.hasbutton||(this.hasbutton=!0),this}getButton(t){return this.#t[t]}getButtons(){return Object.values(this.#t)}addPopButton(t,e,i){return t||(t=$l10n("BACK")),this.popButtonView=e??{type:"button",props:{bgcolor:$color("clear"),symbol:"chevron.left",tintColor:h.linkColor,title:` ${t}`,titleColor:h.linkColor,font:$font("bold",16)},layout:(s,o)=>{s.left.equalTo(o.super.safeArea).offset(E.style.edges),s.centerY.equalTo(o.super.safeArea)},events:{tapped:()=>{$ui.pop(),typeof i=="function"&&i()}}},this}removePopButton(){return this.popButtonView=void 0,this}},ht=class{constructor(t){this.content=t}valueToJs(t){switch(t.tag){case"dict":return this.dictToJs(t);case"true":case"false":return t.tag==="true";case"integer":return t.number;case"key":case"string":return t.string;case"date":return new Date(t.string);case"array":return this.arrayToJs(t);default:return t.node}}arrayToJs(t){let e=[];return t.children().forEach(i=>{e.push(this.valueToJs(i))}),e}dictToJs(t){let e=[],i=[];return t.children().forEach(s=>{s.tag==="key"?e.push(this.valueToJs(s)):i.push(this.valueToJs(s))}),Object.fromEntries(e.map((s,o)=>[s,i[o]]))}getObject(){if(!this.content)return!1;let t=$xml.parse({string:this.content,mode:"xml"});return this.valueToJs(t.rootElement.firstChild({xPath:"//plist/dict"}))}static get(t){return new this(t).getObject()}},w=class a{static method={get:"GET",post:"POST",put:"PUT",delete:"DELETE",patch:"PATCH",head:"HEAD",options:"OPTIONS"};static errorType={http:0,network:1};cacheContainerKey=$addin?.current?.name+".request.cache";#t;#e=!1;#i=!1;cacheLife=1e3*60*60*24*30;#s=!1;timeout=5;logger;constructor(t){t instanceof V&&(this.logger=t)}get cache(){return $cache.get(this.cacheContainerKey)??{}}#o(t){this.#s&&this.logger instanceof V&&this.logger.info(t)}logRequest(){return this.#s=!0,this}disableLogRequest(){this.#s=!1}getCacheKey(t){return $text.MD5(t)}getCache(t,e=null){return this.cache[t]??e}setCache(t,e){if(!e)return;let i=this.cache;i[t]=e,$cache.set(this.cacheContainerKey,i)}removeCache(t){let e=this.cache;delete e[t],$cache.set(this.cacheContainerKey,e)}clearCache(){$cache.remove(this.cacheContainerKey)}clearNSURLCache(){this.#t||(this.#t=$objc("NSURLCache").$sharedURLCache()),this.#t.$removeAllCachedResponses()}enableCache(){return this.#e=!0,this}disableCache(){return this.#e=!1,this}ignoreCacheExp(){this.#i=!0}async request(t,e,i={},s={},o=this.cacheLife,r){let n,l=this.#e&&e===a.method.get;if(l){n=this.getCacheKey(t);let p=this.getCache(n);if(p&&(this.#i||p.exp>Date.now()))return this.#o("get data from cache: "+t),p.data}this.#o(`sending request [${e}]: ${t}`);let c=await $http.request(Object.assign({header:s,url:t,method:e,body:e===a.method.get?null:i,timeout:this.timeout},r));if(c.error)throw new O({type:a.errorType.network,message:c.error.localizedDescription,code:c.error.code});if(c?.response?.statusCode>=400){let p=c.data;throw typeof p=="object"&&(p=JSON.stringify(p)),new O({type:a.errorType.http,message:p,code:c.response.statusCode})}return l&&this.setCache(n,{exp:Date.now()+o,data:c}),c}},u=class a{static rowHeight=50;static edgeOffset=10;static iconSize=30;static iconDefaultColor="#00CC00";setting;#t;#e;#i;title;#s={};#o;constructor({setting:t,key:e,title:i,icon:s,value:o=null}={}){this.setting=t,this.key=e,this.title=$l10n(i),this.icon=s,this.default=o}get method(){return this.setting.method}set key(t){return this.#e=t??$text.uuid,this.#t=void 0,this}get key(){return this.#e}get id(){return this.#t||(this.#t=`setting-${$text.uuid}-${this.key}`),this.#t}set icon(t){return t?Array.isArray(t)||(t=[t,a.iconDefaultColor]):t=["square.grid.2x2.fill",a.iconDefaultColor],Array.isArray(t[0])||(t[0]=[t[0],t[0]]),t[1]?Array.isArray(t[1])||(t[1]=[t[1],t[1]]):t[1]=[a.iconDefaultColor,a.iconDefaultColor],this.#i=t,this}get icon(){return this.#i}get options(){return this.#s}set options(t){return this.#s=t??{},this}set(t){return typeof this.#o=="function"&&this.#o(t),this.setting.set(this.key,t)}onSet(t){return this.#o=t,this}get(t=this.default){return this.setting.getOriginal(this.key,t)}evalValues(t,e=[]){let i;return typeof t=="string"?t.startsWith("this.method")?i=new Function("method",`return ${t.replace("this.","")}()`)(this.method):i=new Function(`return {${t}}`)():typeof t=="function"?i=t():i=t??e,i}createLineLabel(){return{type:"view",views:[{type:"view",props:{bgcolor:$color(this.icon[1][0],this.icon[1][1]),cornerRadius:5,smoothCorners:!0},views:[{type:"image",props:{tintColor:$color("white"),image:$image(this.icon[0][0],this.icon[0][1])},layout:(t,e)=>{t.center.equalTo(e.super),t.size.equalTo(20)}}],layout:(t,e)=>{t.centerY.equalTo(e.super),t.size.equalTo(a.iconSize),t.left.inset(a.edgeOffset)}},{type:"label",props:{text:this.title,lines:1,align:$align.left},layout:(t,e)=>{t.centerY.equalTo(e.super),t.height.equalTo(e.super),t.left.equalTo(e.prev.right).offset(a.edgeOffset),t.width.greaterThanOrEqualTo(10)}}],layout:(t,e)=>{t.height.centerY.equalTo(e.super),t.left.inset(0)}}}getView(){}create(){return this.getView(this.options)}},b=class a{#t=()=>{};#e=()=>{};style=a.UIModalPresentationStyle.PageSheet;#i=!1;#s;#o;#r;static UIModalPresentationStyle={Automatic:-2,FullScreen:0,PageSheet:1,FormSheet:2,CurrentContext:3,Custom:4,OverFullScreen:5,OverCurrentContext:6,Popover:7,BlurOverFullScreen:8};navigationView;init(){this.initNavBar(),$define({type:"SheetViewController: UIViewController",events:{"viewWillDisappear:":e=>{typeof this.#o=="function"&&this.#o(e)},"viewDidDisappear:":e=>{typeof this.#r=="function"&&this.#r(e)}}}),this.sheetVC=$objc("SheetViewController").$new();let t=this.sheetVC.$view();return t.$addSubview($ui.create({type:"view"})),this.sheetVC.$setModalPresentationStyle(this.style),this.sheetVC.$setModalInPresentation(this.#i),this.#t=()=>{t.jsValue().add(this.navigationView?.getPage().definition??this.view),$ui.vc.ocValue().invoke("presentViewController:animated:completion:",this.sheetVC,!0,null)},this.#e=()=>this.sheetVC.invoke("dismissViewControllerAnimated:completion:",!0,null),this}initNavBar(){if(!this.#s)return;let{title:t="",popButton:e={title:$l10n("CLOSE")},rightButtons:i=[]}=this.#s;if(this.view===void 0)throw new W;this.navigationView=new m;let s=this.navigationView.navigationBar;s.setLargeTitleDisplayMode(g.largeTitleDisplayModeNever),s.navigationBarLargeTitleHeight-=s.navigationBarNormalHeight,s.navigationBarNormalHeight=h.PageSheetNavigationBarNormalHeight,s.navigationBarLargeTitleHeight+=s.navigationBarNormalHeight,this.style===a.UIModalPresentationStyle.FullScreen||this.style===a.UIModalPresentationStyle.OverFullScreen||this.style===a.UIModalPresentationStyle.BlurOverFullScreen?s.setTopSafeArea():s.removeTopSafeArea(),e.events=Object.assign({tapped:async()=>{typeof e.tapped=="function"&&await e.tapped(),this.dismiss()}},e.events??{}),this.navigationView.navigationBarItems.addLeftButton(e).setRightButtons(i),this.navigationView.setView(this.view).navigationBarTitle(t),this.view.props?.bgcolor&&this.navigationView?.getPage().setProp("bgcolor",this.view.props?.bgcolor)}preventDismiss(){return this.#i=!0,this}setStyle(t){return this.style=t,this}setView(t={}){if(typeof t!="object")throw new rt("view","object");return this.view=t,this}addNavBar(t){return this.#s=t,this}present(){this.#t()}dismiss(){this.#e()}willDismiss(t){return this.#o=t,this}didDismiss(t){return this.#r=t,this}static quickLookImage(t,e=$l10n("PREVIEW")){new a().setView({type:"view",views:[{type:"scroll",props:{zoomEnabled:!0,maxZoomScale:3},layout:$layout.fill,views:[{type:"image",props:{data:t},layout:$layout.fill}]}],layout:$layout.fill}).addNavBar({title:e,rightButtons:[{symbol:"square.and.arrow.up",tapped:()=>$share.sheet(t)}]}).init().present()}},ut=class{#t={};addTask(t,e=0){let i=$text.uuid;return this.#t[i]=$delay(e,async()=>{await t(),delete this.#t[i]}),i}cancelTask(t){this.#t[t].cancel()}clearTasks(){Object.values(this.#t).forEach(t=>t.cancel())}},ct=class a{static type={info:void 0,success:"checkmark",warning:"exclamationmark.triangle",error:"xmark.circle"};static edges=40;static iconSize=100;static labelTopMargin=10;static defaultFont=$font("default",26);width=Math.min(h.windowSize.width*.6,260);labelWidth=this.width-a.edges*2;id=$text.uuid;#t="";font=a.defaultFont;type=a.type.info;labelLines=2;constructor(t,e=a.type.info,i=2,s=a.defaultFont){this.type=e,this.message=t,this.labelLines=i,this.font=s}get message(){return this.#t}set message(t){this.#t=t,this.fontHeight=h.getContentSize(this.font,this.message,this.labelWidth,this.labelLines).height,this.height=(this.hasIcon?a.labelTopMargin+a.iconSize:0)+this.fontHeight+a.edges*2}get hasIcon(){return this.type!==void 0}get blurBox(){let t=h.blurBox({id:this.id,cornerRadius:15,alpha:0},[{type:"image",props:{symbol:this.type,hidden:!this.hasIcon,tintColor:$color("lightGray")},layout:(e,i)=>{e.top.inset(a.edges),e.size.equalTo(a.iconSize),e.centerX.equalTo(i.super)}},{type:"label",props:{font:this.font,text:this.message,align:$align.center,lines:this.labelLines,color:$color("lightGray")},layout:(e,i)=>{e.bottom.equalTo(i.supper).offset(-a.edges),e.width.equalTo(this.labelWidth),e.height.equalTo(this.fontHeight),e.centerX.equalTo(i.super)}}]);return t.events={tapped:()=>{this.remove()}},t}show(){let t=$ui.create(this.blurBox);$ui.controller.view.hidden?$ui.controller.view.super.insertAtIndex(t,0):$ui.controller.view.insertAtIndex(t,0);let e=$(this.id);e.layout((i,s)=>{i.center.equalTo(s.super),i.size.equalTo($size(this.width,this.height))}),e.moveToFront(),$ui.animate({duration:.2,animation:()=>{e.alpha=1}})}remove(){let t=$(this.id);t&&$ui.animate({duration:.2,animation:()=>{t.alpha=0},completion:()=>{t.remove()}})}static toast({message:t,type:e=a.type.info,show:i=!0,displayTime:s=2,labelLines:o=2,font:r=a.defaultFont}){let n=new a(t,e,o,r);return i&&(n.show(),$delay(s,()=>{n.remove()})),n}static info(t,e={}){return a.toast(Object.assign({message:t,type:a.type.info},e))}static success(t,e={}){return a.toast(Object.assign({message:t,type:a.type.success},e))}static warning(t,e={}){return a.toast(Object.assign({message:t,type:a.type.warning},e))}static error(t,e={}){return a.toast(Object.assign({message:t,type:a.type.error},e))}},h=class a{static#t=$objc("UIApplication").$sharedApplication();static#e=$objc("UINotificationFeedbackGenerator").$new();static feedbackSuccess(){a.#e.$notificationOccurred(0)}static feedbackError(){a.#e.$notificationOccurred(2)}static isTaio=$app.info.bundleID.includes("taio");static align={left:0,right:1,top:2,bottom:3};static textColor=$color("primaryText");static linkColor=$color("systemLink");static primaryViewBackgroundColor=$color("primarySurface");static scrollViewBackgroundColor=$color("insetGroupedBackground");static scrollViewList=["list","matrix"];static isLargeScreen=$device.isIpad||$device.isIpadPro;static get windowSize(){return $objc("UIWindow").$keyWindow().jsValue().size}static NavigationBarNormalHeight=$objc("UINavigationController").invoke("alloc.init").$navigationBar().jsValue().frame.height;static NavigationBarLargeTitleHeight=$objc("UITabBarController").invoke("alloc.init").$tabBar().jsValue().frame.height+a.NavigationBarNormalHeight;static PageSheetNavigationBarNormalHeight=56;static get isSplitScreenMode(){return a.isLargeScreen&&$device.info.screen.width!==a.windowSize.width}static get topSafeAreaInsets(){return a.isTaio?0:a.#t?.$keyWindow()?.$safeAreaInsets()?.top??0}static get bottomSafeAreaInsets(){return a.#t?.$keyWindow()?.$safeAreaInsets()?.bottom??0}static get statusBarOrientation(){return a.#t.$statusBarOrientation()}static get consoleBarHeight(){if($app.isDebugging){let t=a.#t.$statusBarFrame().height+26;return $device.isIphoneX&&(t+=30),t}return 0}static get isHorizontal(){return a.statusBarOrientation===3||a.statusBarOrientation===4}static loading(){let t=$ui.create(a.blurBox({cornerRadius:15},[{type:"spinner",props:{loading:!0,style:0},layout:(e,i)=>{e.size.equalTo(i.prev),e.center.equalTo(i.super)}}]));return{start:()=>{$ui.controller.view.insertAtIndex(t,0),t.layout((e,i)=>{e.center.equalTo(i.super);let s=Math.min(Math.min(a.windowSize.width,a.windowSize.height)*.6,260);e.size.equalTo($size(s,s))}),t.moveToFront()},end:()=>{t.remove()}}}static defaultBackgroundColor(t){return a.scrollViewList.indexOf(t)>-1?a.scrollViewBackgroundColor:a.primaryViewBackgroundColor}static separatorLine(t={},e=a.align.bottom){return{type:"canvas",props:t,layout:(i,s)=>{s.prev===void 0?i.top.equalTo(s.super):e===a.align.bottom?i.top.equalTo(s.prev.bottom):i.top.equalTo(s.prev.top),i.height.equalTo(1/$device.info.screen.scale),i.left.right.inset(0)},events:{draw:(i,s)=>{s.strokeColor=t.bgcolor??$color("separatorColor"),s.setLineWidth(1),s.moveToPoint(0,0),s.addLineToPoint(i.frame.width,0),s.strokePath()}}}}static blurBox(t={},e=[],i=$layout.fill){return{type:"blur",props:Object.assign({style:$blurStyle.thinMaterial},t),views:e,layout:i}}static getContentSize(t,e="A",i=a.windowSize.width,s=void 0){let o={text:e,width:i,font:t};return s!==void 0&&(o.lineSpacing=s),$text.sizeThatFits(o)}static getSymbolSize(t,e){t=typeof t=="string"?$image(t):t;let i=t.size.width/t.size.height;return t.size.width>t.size.height?$size(e,e/i):$size(e*i,e)}static push({views:t,statusBarStyle:e=0,title:i="",navButtons:s=[{title:""}],bgcolor:o=t[0]?.props?.bgcolor??"primarySurface",titleView:r=void 0,disappeared:n}={}){let l={statusBarStyle:e,navButtons:s,title:i,bgcolor:typeof o=="string"?$color(o):o};r&&(l.titleView=r),$ui.push({props:l,events:{disappeared:()=>{n!==void 0&&n()}},views:[{type:"view",views:t,layout:(c,p)=>{c.top.equalTo(p.super.safeArea),c.bottom.equalTo(p.super),c.left.right.equalTo(p.super.safeArea)}}]})}static compressImage(t,e=1280*720){let i=$imagekit.info(t);if(i.height*i.width>e){let s=e/(i.height*i.width);t=$imagekit.scaleBy(t,s)}return t}static deleteConfirm(t,e){$ui.alert({title:$l10n("DELETE_CONFIRM_TITLE"),message:t,actions:[{title:$l10n("DELETE"),style:$alertActionType.destructive,handler:()=>{e()}},{title:$l10n("CANCEL")}]})}static bytesToSize(t){if(t===0)return"0 B";let e=1024,i=["B","KB","MB","GB","TB","PB","EB","ZB","YB"],s=Math.floor(Math.log(t)/Math.log(e));return(t/Math.pow(e,s)).toPrecision(3)+" "+i[s]}},pt=class{#t;text="";interval;fullScreen=!1;#e=()=>{};constructor(){this.#t=$text.uuid}updateText(t){$(this.#t).text=t}setLoop(t){if(typeof t!="function")throw"loop must be a function";this.#e=t}done(){clearInterval(this.interval)}load(){$ui.render({props:{navBarHidden:this.fullScreen},views:[{type:"spinner",props:{loading:!0},layout:(t,e)=>{t.centerY.equalTo(e.super).offset(-15),t.width.equalTo(e.super)}},{type:"label",props:{id:this.#t,align:$align.center,text:""},layout:(t,e)=>{t.top.equalTo(e.prev.bottom).offset(10),t.left.right.equalTo(e.super)}}],layout:$layout.fill,events:{appeared:()=>{this.interval=setInterval(()=>{this.#e()},100)}}})}},d=class a{id=$text.uuid;type;props;views;events;layout;#t=void 0;#e=null;constructor({type:t="view",props:e={},views:i=[],events:s={},layout:o=$layout.fill}={}){this.type=t,this.props=e,this.views=i,this.events=s,this.layout=o,this.props.id?this.id=this.props.id:this.props.id=this.id}static create(t){return new this(t)}static createFromViews(t){return new this({views:t})}get scrollableView(){return this.scrollable?this.#e:null}set scrollableView(t){this.#e=t}get scrollable(){if(this.#t===void 0){if(this.#t=!1,h.scrollViewList.indexOf(this.type)>-1)this.scrollableView=this,this.#t=!0;else if(this.views.length>0){let t=e=>{if(!this.#t&&e?.length>0)for(let i=0;i-1){typeof e[i]!==a&&(e[i]=a.create(e[i])),this.scrollableView=e[i],this.#t=!0;return}else t(e[i].views)};t(this.views)}}return this.#t}set scrollable(t){throw new Error("[scrollable] is readonly prop.")}setProps(t){return Object.keys(t).forEach(e=>this.setProp(e,t[e])),this}setProp(t,e){return t==="id"&&(this.id=e),this.props[t]=e,this}setViews(t){return this.views=t,this.#t=void 0,this}setEvents(t){return Object.keys(t).forEach(e=>this.setEvent(e,t[e])),this}setEvent(t,e){return this.events[t]=e,this}eventMiddleware(t,e){let i=this.events[t];return this.events[t]=(...s)=>{typeof i=="function"&&e(i,...s)},this}assignEvent(t,e){let i=this.events[t];return this.events[t]=(...s)=>{typeof i=="function"&&i(...s),e(...s)},this}setLayout(t){return this.layout=t,this}getView(){return this}get definition(){return this.getView()}},A=class extends Error{constructor(t){super(`Parameter [${t}] is required.`),this.name="FileStorageParameterError"}},x=class extends Error{constructor(t){super(`File not found: ${t}`),this.name="FileStorageFileNotFoundError"}},O=class extends Error{constructor({message:t,code:e,type:i}={}){super(t),this.name="RequestError",this.code=e,this.type=i}},k=class extends Error{constructor(){super("Call loadConfig() first."),this.name="SettingLoadConfigError"}},j=class extends Error{constructor(){super("Attempted to assign to readonly property."),this.name="SettingReadonlyError"}},W=class extends Error{constructor(){super("Please call setView(view) first."),this.name="SheetViewUndefinedError"}},D=class extends Error{constructor(t,e){super(`The type of the parameter '${t}' must be '${e}'`),this.name="ValidationError"}},dt=class extends d{height=60;getView(){return this.type="view",this.setProp("bgcolor",h.primaryViewBackgroundColor),this.layout=(t,e)=>{t.left.right.bottom.equalTo(e.super),t.top.equalTo(e.super.safeAreaBottom).offset(-this.height)},this.views=[d.create({props:this.props,views:this.views,layout:(t,e)=>{t.left.right.top.equalTo(e.super),t.height.equalTo(this.height)}})],this}},gt=class extends d{titleStyle={font:$font("bold",21),height:30};#t;#e;templateIdByIndex(t){return this.props.template.views[t]?.props?.id===void 0&&(this.props.template.views[t].props===void 0&&(this.props.template.views[t].props={}),this.props.template.views[t].props.id=$text.uuid),this.props.template.views[t].props.id}get templateHiddenStatus(){if(!this.#e){this.#e={};for(let t=0;t{i.items=i.items.filter(s=>s?.__title?.hidden===!0),e.push(i)}),e}set data(t){this.props.data=this.rebuildData(t),$(this.id).data=this.props.data}#i(t){let e={...this.hiddenViews};return Object.assign(e,{__templateProps:{hidden:!0},__title:{hidden:!1,text:t,info:{title:!0}}}),e}rebuildData(t=[]){return t.map(e=>(e.items=e.items.map(i=>(Object.keys(i).forEach(s=>{i[s].hidden=this.templateHiddenStatus[s]??!1}),Object.keys(this.templateHiddenStatus).forEach(s=>{i[s]||(i[s]={}),i[s].hidden=this.templateHiddenStatus[s]}),i.__templateProps={hidden:!1},i.__title={hidden:!0},i)),e.title&&e.items.unshift(this.#i(e.title)),e))}rebuildTemplate(){let t={};this.props.template.props!==void 0&&(this.props.template.props.cornerRadius!==void 0&&(this.props.template.props.clipsToBounds=!1),t=Object.assign(this.props.template.props,{id:"__templateProps",hidden:!1}));let e=[{type:"view",props:t,layout:$layout.fill},{type:"label",props:{id:"__title",hidden:!0,font:this.titleStyle.font},layout:(i,s)=>{i.top.inset(-(this.titleStyle.height/4)*3),i.height.equalTo(this.titleStyle.height),i.width.equalTo(s.super.safeArea)}}].concat(this.props.template.views);this.props.template.views=e}insert(t,e=!0){return t.indexPath=this.indexPath(t.indexPath,e),$(this.id).insert(t)}delete(t,e=!0){return t=this.indexPath(t,e),$(this.id).delete(t)}object(t,e=!0){return t=this.indexPath(t,e),$(this.id).object(t)}cell(t,e=!0){return t=this.indexPath(t,e),$(this.id).cell(t)}indexPath(t,e){let i=e?1:0;return typeof t=="number"?t=$indexPath(0,t+i):t=$indexPath(t.section,t.row+i),t}getView(){return this.props.data=this.rebuildData(this.props.data),this.rebuildTemplate(),this.setEvent("itemSize",(t,e)=>{if(t.object(e)?.__title?.info?.title)return $size(Math.max($device.info.screen.width,$device.info.screen.height),0);let s=this.props.columns??2,o=this.props.spacing??15,r=this.props.itemWidth??this.props.itemSize?.width??(t.super.frame.width-o*(s+1))/s,n=this.props.itemHeight??this.props.itemSize?.height??100;return $size(r,n)}),this}},U=class extends d{controller={};setController(t){return this.controller=t,this}},E=class a extends d{static#t;edges=15;buttonEdges=this.edges/2;iconSize=24;fontSize=17;color=h.textColor;title;#e;#i;align=h.align.right;get symbol(){return typeof this.#e=="string"?this.#i==="icon"?$icon(this.#e,this.color):$image(this.#e):this.#e}set symbol(t){typeof this.#e=="string"?isNaN(t)?this.#i="image":this.#i="icon":String(t)==="[object BBFileIcon]"?this.#i="icon":this.#i="image",this.#e=t}get width(){if(this.title){let t=$text.sizeThatFits({text:this.title,width:h.windowSize.width,font:$font(this.fontSize)});return Math.ceil(t.width)+this.edges}return this.iconSize+this.edges}static get style(){return this.#t===void 0&&(this.#t=new a),this.#t}setEdges(t){return this.edges=t,this}setFontSize(t){return this.fontSize=t,$(this.id)&&($(this.id).font=$font(this.fontSize)),this}setColor(t=h.textColor){return this.color=t,$(this.id)&&($(this.id).titleColor=this.color,$(`icon-button-${this.id}`).titleColor=this.color,$(`icon-checkmark-${this.id}`).titleColor=this.color),this}setTitle(t){return this.title=t,$(this.id)&&($(this.id).title=this.title),this}setSymbol(t){return this.symbol=t,$(`icon-button-${this.id}`)&&(this.#i==="icon"?$(`icon-button-${this.id}`).icon=this.symbol:$(`icon-button-${this.id}`).image=this.symbol),this}setMenu(t){return this.menu=t,this}setAlign(t){return this.align=t,this}setLoading(t){t?($(this.id).hidden=!0,$("spinner-"+this.id).hidden=!1):($(this.id).hidden=!1,$("spinner-"+this.id).hidden=!0)}#s(){let t=$(`icon-button-${this.id}`),e=$(`icon-checkmark-${this.id}`);t.alpha=0,$(this.id).hidden=!1,$("spinner-"+this.id).hidden=!0,$ui.animate({duration:.6,animation:()=>{e.alpha=1},completion:()=>{$delay(.3,()=>$ui.animate({duration:.6,animation:()=>{e.alpha=0},completion:()=>{$ui.animate({duration:.4,animation:()=>{t.alpha=1},completion:()=>{t.alpha=1}})}}))}})}hide(){$(this.id+"-container").hidden=!0}show(){$(this.id+"-container").hidden=!1}getView(){let t=this.events.tapped;return this.events.tapped=e=>{t&&t({start:()=>this.setLoading(!0),done:()=>this.#s(),cancel:()=>this.setLoading(!1)},e)},{type:"view",props:{id:this.id+"-container",info:{align:this.align}},views:[{type:"button",props:Object.assign({id:this.id,bgcolor:$color("clear"),font:$font(this.fontSize),titleColor:this.color,contentEdgeInsets:$insets(0,0,0,0),titleEdgeInsets:$insets(0,0,0,0),imageEdgeInsets:$insets(0,0,0,0)},this.menu?{menu:this.menu}:{},this.title?{title:this.title}:{},this.props),views:[{type:"image",props:Object.assign({id:`icon-button-${this.id}`,hidden:this.symbol===void 0,tintColor:this.color},this.symbol?this.#i==="icon"?{icon:this.symbol}:{image:this.symbol}:{}),layout:(e,i)=>{this.symbol&&this.#i==="image"&&e.size.equalTo(h.getSymbolSize(this.symbol,this.iconSize)),e.center.equalTo(i.super)}},{type:"image",props:{id:`icon-checkmark-${this.id}`,alpha:0,tintColor:this.color,symbol:"checkmark"},layout:(e,i)=>{e.center.equalTo(i.super),e.size.equalTo(h.getSymbolSize("checkmark",this.iconSize))}}],events:this.events,layout:$layout.fill},{type:"spinner",props:{id:"spinner-"+this.id,loading:!0,hidden:!0},layout:$layout.fill}],layout:(e,i)=>{if(e.size.equalTo($size(this.width,h.NavigationBarNormalHeight)),e.centerY.equalTo(i.super),i.prev&&i.prev?.info?.align===this.align)this.align===h.align.right?e.right.equalTo(i.prev.left).offset(-this.buttonEdges):e.left.equalTo(i.prev.right).offset(this.buttonEdges);else{let s=this.edges/2;this.align===h.align.right?e.right.inset(s):e.left.inset(s)}}}}static creat({id:t,symbol:e,title:i,tapped:s,menu:o,events:r,color:n,align:l=h.align.right}={}){let c=new a;return c.setEvents(Object.assign({tapped:s},r)).setAlign(l).setSymbol(e).setTitle(i).setColor(n).setMenu(o),t&&c.setProp("id",t),c}},g=class a extends d{static largeTitleDisplayModeAutomatic=0;static largeTitleDisplayModeAlways=1;static largeTitleDisplayModeNever=2;navigationBarItems;title="";prefersLargeTitles=!0;largeTitleDisplayMode=a.largeTitleDisplayModeAutomatic;fontFamily="bold";largeTitleFontSize=34;largeTitleFontHeight=$text.sizeThatFits({text:"A",width:100,font:$font(this.fontFamily,this.largeTitleFontSize)}).height;navigationBarTitleFontSize=17;topSafeArea=!0;contentViewHeightOffset=0;navigationBarNormalHeight=h.NavigationBarNormalHeight;navigationBarLargeTitleHeight=h.NavigationBarLargeTitleHeight;setTopSafeArea(){return this.topSafeArea=!0,this}removeTopSafeArea(){return this.topSafeArea=!1,this}setLargeTitleDisplayMode(t){return this.largeTitleDisplayMode=t,this}setBackgroundColor(t){return this.backgroundColor=t,this}setTitle(t){return this.title=t,this}setPrefersLargeTitles(t){return this.prefersLargeTitles=t,this}setContentViewHeightOffset(t){return this.contentViewHeightOffset=t,this}getLargeTitleView(){return this.prefersLargeTitles&&this.largeTitleDisplayMode!==a.largeTitleDisplayModeNever?{type:"label",props:{id:this.id+"-large-title",text:this.title,textColor:h.textColor,align:$align.left,font:$font(this.fontFamily,this.largeTitleFontSize),line:1},layout:(t,e)=>{t.left.equalTo(e.super.safeArea).offset(15),t.height.equalTo(this.largeTitleFontHeight),t.top.equalTo(e.super.safeAreaTop).offset(this.navigationBarNormalHeight)}}:{props:{id:this.id+"-large-title"},layout:(t,e)=>{t.left.top.right.inset(0),t.bottom.equalTo(e.super.safeAreaTop).offset(this.navigationBarNormalHeight)}}}getNavigationBarView(){let t=(r,n)=>{let l=(y,B)=>{y.top.equalTo(B.super.safeAreaTop),y.bottom.equalTo(B.super.safeAreaTop).offset(this.navigationBarNormalHeight),n===h.align.left?y.left.equalTo(B.super.safeArea):y.right.equalTo(B.super.safeArea)};if(r&&!Array.isArray(r))return{type:"view",views:[r],layout:l};let c=0,p=[];r.forEach(y=>{c+=y.width,p.push(y.definition)});let f=r[0]?.edges??0;return c+=r.length>=2?f*2:f,r.length>0?{type:"view",views:p,info:{width:c},layout:(y,B)=>{l(y,B),y.width.equalTo(c)}}:{type:"view",layout:y=>y.size.equalTo(0)}},e=t(this.navigationBarItems.popButtonView??this.navigationBarItems.leftButtons,h.align.left),i=t(this.navigationBarItems.rightButtons,h.align.right),s=this.prefersLargeTitles,o=!this.prefersLargeTitles||this.largeTitleDisplayMode===a.largeTitleDisplayModeNever;return{type:"view",props:{id:this.id+"-navigation",bgcolor:$color("clear")},layout:(r,n)=>{r.left.top.right.inset(0),r.bottom.equalTo(n.super.safeAreaTop).offset(this.navigationBarNormalHeight)},views:[this.backgroundColor?{type:"view",props:{hidden:s,bgcolor:this.backgroundColor,id:this.id+"-background"},layout:$layout.fill}:h.blurBox({hidden:s,id:this.id+"-background"}),h.separatorLine({id:this.id+"-underline",alpha:s?0:1}),{type:"view",props:{alpha:0,bgcolor:$color("clear"),id:this.id+"-large-title-mask"},events:{ready:r=>{r.bgcolor=$(this.id+"-large-title")?.prev.bgcolor}},layout:$layout.fill},e,i,{type:"view",views:[{type:"label",props:{id:this.id+"-small-title",alpha:o?1:0,text:this.title,font:$font(this.fontFamily,this.navigationBarTitleFontSize),align:$align.center,bgcolor:$color("clear"),textColor:h.textColor},layout:(r,n)=>{r.edges.equalTo(n.super.safeArea);let l=h.getContentSize($font(this.fontFamily,this.navigationBarTitleFontSize),n.text).width,c=Math.max(e.info?.width??0,i.info?.width??0);h.windowSize.width-c*2>l&&r.centerX.equalTo(n.super.super)}}],layout:(r,n)=>{r.top.bottom.equalTo(n.super.safeArea),r.left.equalTo(n.prev.prev.right),r.right.equalTo(n.prev.left)}}]}}},G=class a extends v{static largeTitleViewSmallMode=0;static largeTitleViewLargeMode=1;navigationBar;updateSelector(){this.selector={navigation:$(this.navigationBar.id+"-navigation"),largeTitleView:$(this.navigationBar.id+"-large-title"),smallTitleView:$(this.navigationBar.id+"-small-title"),underlineView:this.navigationBar.navigationBarItems.isPinTitleView?$(this.navigationBar.id+"-title-view-underline"):$(this.navigationBar.id+"-underline"),largeTitleMaskView:$(this.navigationBar.id+"-large-title-mask"),backgroundView:$(this.navigationBar.id+"-background"),titleViewBackgroundView:$(this.navigationBar.id+"-title-view-background")}}toNormal(t=!0){this.updateSelector(),this.selector.backgroundView.hidden=!1,$ui.animate({duration:.2,animation:()=>{this.selector.underlineView.alpha=1,this.selector.smallTitleView.alpha=1,this.selector.largeTitleView.alpha=0}}),t&&this.navigationBar.navigationBarItems&&(this.navigationBar.largeTitleDisplayMode=g.largeTitleDisplayModeNever)}toLargeTitle(t=!0){this.updateSelector(),this.selector.backgroundView.hidden=!0,$ui.animate({duration:.2,animation:()=>{this.selector.underlineView.alpha=0,this.selector.smallTitleView.alpha=0,this.selector.largeTitleView.alpha=1}}),t&&this.navigationBar.navigationBarItems&&(this.navigationBar.largeTitleDisplayMode=g.largeTitleDisplayModeAlways)}#t(t){let e=t===a.largeTitleViewSmallMode;this.selector.largeTitleView.alpha=e?0:1,$ui.animate({duration:.2,animation:()=>{this.selector.smallTitleView.alpha=e?1:0}})}#e(t){if(this.selector.largeTitleView.updateLayout((i,s)=>{this.navigationBar.navigationBarNormalHeight-t>0?i.top.equalTo(s.super.safeAreaTop).offset(this.navigationBar.navigationBarNormalHeight-t):i.top.equalTo(s.super.safeAreaTop).offset(0)}),t>0)t>=this.navigationBar.navigationBarNormalHeight?this.#t(a.largeTitleViewSmallMode):this.#t(a.largeTitleViewLargeMode);else{this.#t(a.largeTitleViewLargeMode);let i=this.navigationBar.largeTitleFontSize-t*.04;i>40&&(i=40),this.selector.largeTitleView.font=$font(this.navigationBar.fontFamily,i)}}#i(t){let e=this.navigationBar.largeTitleDisplayMode===g.largeTitleDisplayModeNever?5:this.navigationBar.navigationBarNormalHeight,i=this.selector.titleViewBackgroundView!==void 0;if(t>e){this.selector.backgroundView.hidden=!1;let s=()=>{i&&this.navigationBar.navigationBarItems.isPinTitleView&&(this.selector.titleViewBackgroundView.alpha=1),this.selector.largeTitleMaskView.alpha=0,this.selector.underlineView.alpha=1};(t-e)/3>=1?s():$ui.animate({duration:.2,animation:()=>{s()}})}else this.selector.largeTitleMaskView.alpha=t>0?1:0,this.selector.underlineView.alpha=0,i&&(this.selector.titleViewBackgroundView.alpha=0),this.selector.backgroundView.hidden=!0}didScroll(t){if(!this.navigationBar.prefersLargeTitles)return;let e=this.navigationBar.largeTitleDisplayMode;if(e!==g.largeTitleDisplayModeAlways)if(this.updateSelector(),e===g.largeTitleDisplayModeAutomatic){if(!this.navigationBar.navigationBarItems?.isPinTitleView&&(this.navigationBar.navigationBarItems?.titleView?.controller.didScroll(t),t>0)){let i=this.navigationBar.navigationBarItems?.titleView?.height??0;t-=i,t<0&&(t=0)}this.#e(t),this.#i(t)}else e===g.largeTitleDisplayModeNever&&this.#i(t)}didEndDragging(t,e,i,s){if(!this.navigationBar.prefersLargeTitles)return;let o=this.navigationBar.largeTitleDisplayMode;if(o!==g.largeTitleDisplayModeAlways&&(this.updateSelector(),o===g.largeTitleDisplayModeAutomatic)){let r=0;this.navigationBar.navigationBarItems?.isPinTitleView||(this.navigationBar.navigationBarItems?.titleView?.controller.didEndDragging(t,e,i,s),r=this.navigationBar.navigationBarItems?.titleView?.height??0,t-=r),t>=0&&t<=this.navigationBar.largeTitleFontHeight&&i($point(0,t>=this.navigationBar.largeTitleFontHeight/2?this.navigationBar.navigationBarNormalHeight+r-s:r-s))}}},C=class extends D{constructor(t,e){super(t,e),this.name="NavigationViewTypeError"}},m=class extends v{page;navigationController=new G;navigationBar=new g;navigationBarItems=new R;constructor(){super(),this.navigationBar.navigationBarItems=this.navigationBarItems,this.navigationController.navigationBar=this.navigationBar}navigationBarTitle(t){return this.navigationBar.setTitle(t),this}setView(t){if(typeof t!="object")throw new C("view","object");return this.view=d.create(t),this}getTopOffset(){if(!(this.view instanceof d))throw new C("view","View");let t=this.view.scrollableView,e=$app.isDebugging?0:h.topSafeAreaInsets,i=this.navigationBar.largeTitleDisplayMode===g.largeTitleDisplayModeNever?this.navigationBar.navigationBarNormalHeight:this.navigationBar.navigationBarLargeTitleHeight,s=this.navigationBar.contentViewHeightOffset+i;if(this.navigationBarItems.titleView&&(s+=this.navigationBarItems.titleView.topOffset,s+=this.navigationBarItems.titleView.height,s+=this.navigationBarItems.titleView.bottomOffset),!this.view.scrollable||t.props.associateWithNavigationBar===!1){let o=s-this.navigationBar.contentViewHeightOffset;return(!h.isHorizontal||h.isLargeScreen)&&this.navigationBar.topSafeArea&&(o+=e),o}return t.props.stickyHeader&&(s-=i,s+=this.navigationBar.largeTitleFontHeight),s}getBottomOffset(){return this.navigationBarItems.fixedFooterView?.height??0}#t(){if(!(this.view instanceof d))throw new C("view","View");let t=this.view.scrollableView,e=$app.isDebugging?0:h.topSafeAreaInsets,i=this.getTopOffset();if(!this.view.scrollable||t.props.associateWithNavigationBar===!1){this.view.layout=(o,r)=>{o.left.right.equalTo(r.super.safeArea),o.bottom.equalTo(r.super),o.top.equalTo(i)};return}let s=this.navigationBarItems.isPinTitleView?this.navigationBarItems.titleView.height+this.navigationBarItems.titleView.bottomOffset+this.navigationBar.contentViewHeightOffset:0;if(t.props.indicatorInsets){let o=t.props.indicatorInsets;t.props.indicatorInsets=$insets(o.top+this.navigationBar.navigationBarNormalHeight+s,o.left,o.bottom+this.getBottomOffset(),o.right)}else t.props.indicatorInsets=$insets(this.navigationBar.navigationBarNormalHeight+s,0,this.navigationBarItems.fixedFooterView?.height??0,0);if(t.props.contentInset){let o=t.props.contentInset;t.props.contentInset=$insets(o.top+i+s,o.left,o.bottom+this.getBottomOffset(),o.right)}else t.props.contentInset=$insets(i+s,0,this.navigationBarItems.fixedFooterView?.height??0,0);t.props.contentOffset=$point(0,-i),t.layout=(o,r)=>{t.props.stickyHeader?o.top.equalTo(r.super.safeArea).offset(this.navigationBar.navigationBarNormalHeight):o.top.equalTo(r.super),o.left.right.equalTo(r.super.safeArea),o.bottom.equalTo(r.super)},t.assignEvent("didScroll",o=>{let r=o.contentOffset.y;(!h.isHorizontal||h.isLargeScreen)&&this.navigationBar.topSafeArea&&!t.props.stickyHeader&&(r+=e),r+=i,this.navigationController.didScroll(r)}).assignEvent("didEndDragging",(o,r)=>{let n=o.contentOffset.y,l=0;(!h.isHorizontal||h.isLargeScreen)&&this.navigationBar.topSafeArea&&!t.props.stickyHeader&&(n+=e,l=e),n+=i,l+=i,this.navigationController.didEndDragging(n,r,(...c)=>o.scrollToOffset(...c),l)}).assignEvent("didEndDecelerating",(...o)=>{o[0].tracking||t.events?.didEndDragging(...o)})}#e(){if(this.navigationBar.prefersLargeTitles){this.#t();let t={};if(this.navigationBarItems.titleView){let e=this.navigationBar.largeTitleDisplayMode===g.largeTitleDisplayModeNever?1:0;t=d.create({views:[this.navigationBar.backgroundColor?{type:"view",props:{alpha:e,bgcolor:this.navigationBar.backgroundColor,id:this.navigationBar.id+"-title-view-background"},layout:$layout.fill}:h.blurBox({alpha:e,id:this.navigationBar.id+"-title-view-background"}),h.separatorLine({id:this.navigationBar.id+"-title-view-underline",alpha:e}),this.navigationBarItems.titleView.definition],layout:(i,s)=>{i.top.equalTo(s.prev.bottom),i.width.equalTo(s.super),i.height.equalTo(this.navigationBarItems.titleView.topOffset+this.navigationBarItems.titleView.height+this.navigationBarItems.titleView.bottomOffset)}})}this.page=T.createFromViews([this.view,this.navigationBar.getLargeTitleView(),t,this.navigationBar.getNavigationBarView(),this.navigationBarItems.fixedFooterView?.definition??{}])}else this.page=T.createFromViews([this.view]);this.view.props?.bgcolor?this.page.setProp("bgcolor",this.view.props.bgcolor):this.page.setProp("bgcolor",h.defaultBackgroundColor(this.view.type))}getPage(){return this.page||this.#e(),this.page}},ft=class extends U{height=35;topOffset=15;bottomOffset=10;horizontalOffset=15;kbType=$kbType.search;placeholder=$l10n("SEARCH");inputEvents={};keyboardView;accessoryView;cancelButtonFont=$font(16);constructor(t){super(t),this.setController(new J),this.controller.setSearchBar(this)}get cancelButtonWidth(){return h.getContentSize(this.cancelButtonFont,$l10n("CANCEL")).width}setEvent(t,e){return this.inputEvents[t]=e,this}setPlaceholder(t){return this.placeholder=t,this}setKbType(t){return this.kbType=t,this}setKeyboardView(t){return this.keyboardView=t,this}setAccessoryView(t){return this.accessoryView=t,this}onBeginEditingAnimate(){$ui.animate({duration:.3,animation:()=>{let t=this.cancelButtonWidth;$(this.id+"-cancel-button").updateLayout((e,i)=>{e.left.equalTo(i.super.right).offset(-t)}),$(this.id+"-cancel-button").alpha=1,$(this.id+"-cancel-button").relayout(),$(this.id+"-input").updateLayout(e=>{e.right.inset(t+this.horizontalOffset/2)}),$(this.id+"-input").relayout()}})}onEndEditingAnimate(){$ui.animate({duration:.3,animation:()=>{$(this.id+"-cancel-button").updateLayout((t,e)=>{t.left.equalTo(e.super.right)}),$(this.id+"-cancel-button").alpha=0,$(this.id+"-cancel-button").relayout(),$(this.id+"-input").updateLayout($layout.fill),$(this.id+"-input").relayout()}})}cancel(){$(this.id+"-input").blur(),$(this.id+"-input").text="",this.onEndEditingAnimate(),this.controller.callEvent("onCancel")}getView(){return this.props={id:this.id,smoothCorners:!0,cornerRadius:6},this.views=[{type:"input",props:{id:this.id+"-input",type:this.kbType,bgcolor:$color("#EEF1F1","#212121"),placeholder:this.placeholder,keyboardView:this.keyboardView,accessoryView:this.accessoryView},layout:$layout.fill,events:Object.assign({didBeginEditing:t=>{this.onBeginEditingAnimate(),this.controller.callEvent("onBeginEditing",t.text)},didEndEditing:t=>{this.controller.callEvent("onEndEditing",t.text)},changed:t=>this.controller.callEvent("onChange",t.text),returned:t=>this.controller.callEvent("onReturn",t.text)},this.inputEvents)},{type:"button",props:{id:this.id+"-cancel-button",title:$l10n("CANCEL"),font:this.cancelButtonFont,titleColor:$color("tintColor"),bgcolor:$color("clear"),alpha:0,hidden:!1},events:{tapped:()=>this.cancel()},layout:(t,e)=>{t.height.equalTo(e.super),t.width.equalTo(this.cancelButtonWidth),t.left.equalTo(e.super.right)}}],this.layout=(t,e)=>{t.height.equalTo(this.height),t.top.equalTo(e.super.safeArea).offset(this.topOffset),t.left.equalTo(e.super.safeArea).offset(this.horizontalOffset),t.right.equalTo(e.super.safeArea).offset(-this.horizontalOffset)},this}},J=class extends v{setSearchBar(t){return this.searchBar=t,this}updateSelector(){this.selector={inputBox:$(this.searchBar.id),input:$(this.searchBar.id+"-input")}}hide(){this.updateSelector(),this.selector.inputBox.updateLayout(t=>{t.height.equalTo(0)})}show(){this.updateSelector(),this.selector.inputBox.updateLayout(t=>{t.height.equalTo(this.searchBar.height)})}didScroll(t){this.updateSelector();let e=this.searchBar.height-t;if(e=e>0?e>this.searchBar.height?this.searchBar.height:e:0,this.selector.inputBox.updateLayout(i=>{i.height.equalTo(e)}),t>0){let i=(this.searchBar.height/2-5-t)/10;this.selector.input.alpha=i}else this.selector.input.alpha=1}didEndDragging(t,e,i){this.updateSelector(),t>=0&&t<=this.searchBar.height&&i($point(0,t>=this.searchBar.height/2?this.searchBar.height:0))}},K=class extends v{#t=[];#e(t){t.callEvent("onPop"),this.callEvent("onPop",t),this.#t.pop()}push(t){let e=this.#t[this.#t.length-1];t.navigationBarItems.addPopButton(e?.navigationBar.title),this.#t.push(t),$ui.push({props:{statusBarStyle:0,navBarHidden:!0},events:{disappeared:()=>{this.#e(t)}},views:[t.getPage().definition],layout:$layout.fill})}},L=class extends u{get isArray(){return Array.isArray(this.default)}async tapped(){let t=this.isArray?this.default[1]:this.default;(await $ui.alert({title:this.title,message:t,actions:[{title:$l10n("COPY")},{title:$l10n("OK")}]})).index===0&&($clipboard.text=t,$ui.toast($l10n("COPIED")))}getView(){return{type:"view",props:{selectable:!0,info:{key:this.key}},views:[this.createLineLabel(),{type:"label",props:{text:this.isArray?this.default[0]:this.default,align:$align.right,textColor:$color("darkGray")},layout:(t,e)=>{t.centerY.equalTo(e.prev),t.right.inset(u.edgeOffset),t.width.equalTo(180)}}],layout:$layout.fill}}},Y=class extends u{getView(){return{type:"view",props:{id:this.id,selectable:!0},views:[this.createLineLabel(),{type:"switch",props:{on:this.get(),onColor:$color("#00CC00")},events:{changed:t=>{try{this.set(t.on)}catch(e){throw t.on=!t.on,e}}},layout:(t,e)=>{t.centerY.equalTo(e.prev),t.right.inset(u.edgeOffset)}}],layout:$layout.fill}}},X=class extends u{getView(){return{type:"view",props:{id:this.id,selectable:!0},views:[this.createLineLabel(),{type:"button",props:{symbol:"square.and.pencil",bgcolor:$color("clear"),tintColor:$color("primaryText")},events:{tapped:t=>{let e=$ui.popover({sourceView:t,sourceRect:t.bounds,directions:$popoverDirection.down,size:$size(320,150),views:[{type:"text",props:{id:`${this.id}-string`,align:$align.left,text:this.get()},layout:i=>{i.left.right.inset(10),i.top.inset(20),i.height.equalTo(90)}},{type:"button",props:{symbol:"checkmark",bgcolor:$color("clear"),titleEdgeInsets:10,contentEdgeInsets:0},layout:i=>{i.right.inset(10),i.bottom.inset(25),i.size.equalTo(30)},events:{tapped:()=>{this.set($(`${this.id}-string`).text),e.dismiss()}}}]})}},layout:(t,e)=>{t.centerY.equalTo(e.prev),t.right.inset(0),t.size.equalTo(50)}}],layout:$layout.fill}}},_=class extends u{with({min:t,max:e}={}){return this.options={min:t,max:e},this}getView({min:t,max:e}={}){let i=`${this.id}-label`;return{type:"view",props:{id:this.id,selectable:!0},views:[this.createLineLabel(),{type:"label",props:{id:i,text:this.get(),align:$align.left},layout:(s,o)=>{s.height.equalTo(o.super),s.right.inset(120)}},{type:"stepper",props:{min:t,max:e,value:this.get()},events:{changed:s=>{$(i).text=s.value;try{this.set(s.value)}catch(o){throw $(i).text=this.get(),o}}},layout:(s,o)=>{s.centerY.equalTo(o.prev),s.right.inset(u.edgeOffset)}}],layout:$layout.fill}}},z=class extends u{rightSymbol="chevron.right";buttonId=`${this.id}-button`;start(){$(this.buttonId).alpha=0,$(`${this.buttonId}-spinner`).alpha=1}cancel(){$(this.buttonId).alpha=1,$(`${this.buttonId}-spinner`).alpha=0}done(){$(`${this.buttonId}-spinner`).alpha=0;let t=$(this.buttonId);t.symbol="checkmark",$ui.animate({duration:.6,animation:()=>t.alpha=1,completion:()=>{$ui.animate({duration:.4,animation:()=>t.alpha=0,completion:()=>{t.symbol=this.rightSymbol,$ui.animate({duration:.4,animation:()=>t.alpha=1})}})}})}with({script:t}={}){return this.options={script:t},this}async tapped(){let t={start:()=>this.start(),cancel:()=>this.cancel(),done:()=>this.done()},{script:e}=this.options;typeof e=="function"?await e(t):e.startsWith("this.method")?await new Function("method","animate",`return async()=>{await ${e.replace("this.","")}(animate)}`)(this.method,t)():await new Function("animate",`return async()=>{${e}}`)(t)()}getView(){let t="chevron.right";return{type:"view",props:{id:this.id,selectable:!0,info:{key:this.key}},views:[this.createLineLabel(),{type:"view",views:[{type:"button",props:{id:this.buttonId,symbol:t,bgcolor:$color("clear"),tintColor:$color("secondaryText")},events:{tapped:()=>this.tapped()},layout:(e,i)=>{e.centerY.equalTo(i.super),e.right.inset(0),e.height.equalTo(i.super)}},{type:"spinner",props:{id:`${this.buttonId}-spinner`,loading:!0,alpha:0},layout:(e,i)=>{e.size.equalTo(15),e.centerY.equalTo(i.super),e.right.equalTo(i.prev)}}],layout:(e,i)=>{e.right.inset(u.edgeOffset),e.height.equalTo(u.rowHeight),e.width.equalTo(i.super)}}],layout:$layout.fill}}},Z=class extends u{with({items:t,values:e}={}){return Array.isArray(t)&&(t=t.map(i=>$l10n(i))),this.options={items:t,values:e},this}getView({items:t,values:e}={}){t=this.evalValues(t),e=this.evalValues(e);let i=t?.length>0&&e?.length===t?.length;return{type:"view",props:{id:this.id,selectable:!0},views:[this.createLineLabel(),{type:"tab",props:{items:t??[],index:i?e.indexOf(this.get()):this.get(),dynamicWidth:!0},layout:(s,o)=>{s.right.inset(u.edgeOffset),s.centerY.equalTo(o.prev)},events:{changed:s=>{i?this.set(e[s.index]):this.set(s.index)}}}],layout:$layout.fill}}},Q=class extends u{with({items:t,values:e,pullDown:i}={}){return Array.isArray(t)&&(t=t.map(s=>$l10n(s))),this.options={items:t,values:e,pullDown:i},this}getView({items:t,values:e,pullDown:i}={}){let s=`${this.id}-label`,o=this.evalValues(t),r=this.evalValues(e),n=o?.length>0&&r?.length===o?.length,l=(p,f)=>{if(n){let y=this.evalValues(e);this.set(y[f])}else this.set(f);$(s).title=p},c=()=>{i||$ui.menu({items:this.evalValues(t),handler:l})};return{type:"view",props:{id:this.id,selectable:!0},views:[this.createLineLabel(),{type:"view",views:[{type:"button",props:{menu:i?{pullDown:!0,asPrimary:!0,items:o.map((p,f)=>({title:p,handler:()=>l(p,f)}))}:void 0,title:n?o[r.indexOf(this.get())]:o[this.get()],titleColor:$color("secondaryText"),bgcolor:$color("clear"),id:s},events:{tapped:c},layout:(p,f)=>{p.right.inset(0),p.height.equalTo(f.super)}}],layout:(p,f)=>{p.right.inset(u.edgeOffset),p.height.equalTo(u.rowHeight),p.width.equalTo(f.super)}}],layout:$layout.fill}}},tt=class extends u{get(t=null){let e=super.get(t);return e?typeof e=="string"?$color(e):$rgba(e.red,e.green,e.blue,e.alpha):t}getView(){let t=`${this.id}-color`;return{type:"view",props:{id:this.id,selectable:!0},views:[this.createLineLabel(),{type:"view",views:[{type:"view",props:{id:t,bgcolor:this.get(),circular:!0,borderWidth:1,borderColor:$color("#e3e3e3")},layout:(e,i)=>{e.centerY.equalTo(i.super),e.right.inset(u.edgeOffset),e.size.equalTo(20)}},{type:"view",events:{tapped:async()=>{let e=await $picker.color({color:this.get()});this.set(e.components),$(t).bgcolor=$rgba(e.components.red,e.components.green,e.components.blue,e.components.alpha)}},layout:(e,i)=>{e.right.inset(0),e.height.width.equalTo(i.super.height)}}],layout:(e,i)=>{e.height.equalTo(u.rowHeight),e.width.equalTo(i.super)}}],layout:$layout.fill}}},et=class extends u{with({mode:t=2}={}){return this.options={mode:t},this}getView({mode:t=2}={}){let e=i=>{let s="";switch(typeof i=="number"&&(i=new Date(i)),t){case 0:s=i.toLocaleTimeString();break;case 1:s=i.toLocaleDateString();break;case 2:s=i.toLocaleString();break}return s};return{type:"view",props:{id:this.id,selectable:!0},views:[this.createLineLabel(),{type:"view",views:[{type:"label",props:{id:`${this.id}-label`,color:$color("secondaryText"),text:this.get()?e(this.get()):"None"},layout:(i,s)=>{i.right.inset(0),i.height.equalTo(s.super)}}],events:{tapped:async()=>{let i=this.get(),s=await $picker.date({props:{mode:t,date:i||Date.now()}});this.set(s.getTime()),$(`${this.id}-label`).text=e(s)}},layout:(i,s)=>{i.right.inset(u.edgeOffset),i.height.equalTo(u.rowHeight),i.width.equalTo(s.super)}}],layout:$layout.fill}}},N=class extends u{with({secure:t=!1,kbType:e=$kbType.default,saveFunc:i}={}){return this.options={secure:t,kbType:e,saveFunc:i},this}getView({secure:t=!1,kbType:e=$kbType.default,saveFunc:i}={}){i===void 0&&(i=o=>this.set(o));let s=this.id+"-input";return{type:"view",props:{id:this.id,selectable:!0},views:[this.createLineLabel(),{type:"input",props:{id:s,type:e,align:$align.right,bgcolor:$color("clear"),textColor:$color("secondaryText"),text:this.get(),font:$font(16),secure:t,accessoryView:h.blurBox({height:44},[h.separatorLine({},h.align.top),{type:"button",props:{title:$l10n("DONE"),bgcolor:$color("clear"),titleColor:$color("primaryText")},layout:(o,r)=>{o.right.inset(u.edgeOffset),o.centerY.equalTo(r.super)},events:{tapped:()=>{$(s).blur()}}},{type:"button",props:{title:$l10n("CANCEL"),bgcolor:$color("clear"),titleColor:$color("primaryText")},layout:(o,r)=>{o.left.inset(u.edgeOffset),o.centerY.equalTo(r.super)},events:{tapped:()=>{let o=$(s),r=this.get("");o.text!==r&&(o.text=r),o.blur()}}}])},layout:(o,r)=>{o.left.equalTo(r.prev.get("label").right).offset(u.edgeOffset),o.right.inset(u.edgeOffset),o.width.greaterThanOrEqualTo(50),o.height.equalTo(r.super),o.left.priority(10),o.width.priority(10)},events:{didBeginEditing:o=>{o.secure=!1,$app.autoKeyboardEnabled||($app.autoKeyboardEnabled=!0)},returned:o=>{o.blur()},didEndEditing:async o=>{let r=this.get("");i(o.text)||(o.text=r),t&&(o.secure=t)}}}],layout:$layout.fill}}},it=class extends u{getView(){return new N(this).getView({secure:!1,kbType:$kbType.decimal,saveFunc:t=>t===""||!(i=>/^[0-9]+.?[0-9]*$/.test(i))(t)?($ui.toast($l10n("INVALID_VALUE")),!1):this.set(Number(t))})}},st=class extends u{with({bgcolor:t="#000000"}={}){return this.options={bgcolor:t},this}getView({bgcolor:t="#000000"}={}){let e=`${this.id}-image`;return{type:"view",props:{id:this.id,selectable:!0},views:[this.createLineLabel(),{type:"view",views:[{type:"image",props:{cornerRadius:8,bgcolor:typeof t=="string"?$color(t):t,smoothCorners:!0},layout:(i,s)=>{i.right.inset(u.edgeOffset),i.centerY.equalTo(s.super),i.size.equalTo($size(30,30))}},{type:"image",props:{id:e,image:$image(this.get()),icon:$icon(this.get()?.slice(5,this.get().indexOf(".")),$color("#ffffff")),tintColor:$color("#ffffff")},layout:(i,s)=>{i.right.equalTo(s.prev).offset(-5),i.centerY.equalTo(s.super),i.size.equalTo($size(20,20))}}],events:{tapped:()=>{$ui.menu({items:[$l10n("JSBOX_ICON"),$l10n("SF_SYMBOLS"),$l10n("IMAGE_BASE64")],handler:async(i,s)=>{if(s===0){let o=await $ui.selectIcon();this.set(o),$(e).icon=$icon(o.slice(5,o.indexOf(".")),$color("#ffffff"))}else(s===1||s===2)&&$input.text({text:"",placeholder:i,handler:o=>{if(o===""){$ui.toast($l10n("INVALID_VALUE"));return}this.set(o),s===1?$(e).symbol=o:$(e).image=$image(o)}})}})}},layout:(i,s)=>{i.right.inset(0),i.height.equalTo(u.rowHeight),i.width.equalTo(s.super)}}],layout:$layout.fill}}},P=class extends u{with({view:t,navButtons:e=[]}={}){return this.options={view:t,navButtons:e},this}tapped(){let{view:t,navButtons:e}=this.options;return t=this.evalValues(t,{}),e=this.evalValues(e),e.length>0&&e.map(i=>{if(typeof i.tapped=="string"){let s=i.tapped;i.tapped=()=>{this.evalValues(s)}}return i.handler=i.tapped,i}),new Promise((i,s)=>{if(this.setting.isUseJsboxNav){let o={title:this.title,props:t.props??{},views:[t],disappeared:()=>i()};e.length>0&&(o.navButtons=e),h.push(o)}else{let o=new m;o.setView(t).navigationBarTitle(this.title),o.navigationBarItems.addPopButton(),o.navigationBar.setLargeTitleDisplayMode(g.largeTitleDisplayModeNever),this.setting.hasSectionTitle(t)&&o.navigationBar.setContentViewHeightOffset(-10),e.length>0&&o.navigationBarItems.setRightButtons(e),this.setting.viewController.setEvent("onPop",()=>i()),this.setting.viewController.push(o)}})}getView(){return{type:"view",props:{id:this.id,selectable:!0,info:{key:this.key}},views:[this.createLineLabel(),{type:"button",props:{symbol:"chevron.right",bgcolor:$color("clear"),tintColor:$color("secondaryText")},events:{tapped:()=>this.tapped()},layout:(t,e)=>{t.centerY.equalTo(e.super),t.right.inset(u.edgeOffset),t.height.equalTo(e.super)}}],layout:$layout.fill}}},M=class extends P{with({children:t}={}){return super.with({view:()=>this.setting.getListView(t,{},this.id)}),this.options.children=t,this}},ot=class extends u{getImagePath(t=!1){let e=$text.MD5(this.key)+".jpg";return t&&(e="compress."+e),this.setting.imagePath+e}getImage(t=!1){try{return this.setting.fileStorage.readSync(this.getImagePath(t))}catch(e){if(e instanceof x)return null;throw e}}get(t=null){return this.getImage(!1)??null}getView(){let t=`${this.id}-image`,e=$image("questionmark.square.dashed"),i=o=>async()=>{$(t).hidden=!0,$(`${t}-spinner`).hidden=!1,await $wait(.1);try{await o()}catch(r){$ui.alert({title:$l10n("ERROR"),message:String(r)})}await $wait(.1),$(`${t}-spinner`).hidden=!0,$(t).hidden=!1},s=[{title:$l10n("PREVIEW"),handler:i(()=>{let o=this.getImage(!1);o?b.quickLookImage(o):$ui.toast($l10n("NO_IMAGE"))})},{inline:!0,items:[{title:$l10n("SELECT_IMAGE_PHOTO"),handler:i(async()=>{let o=await $photo.pick({format:"data"});if(!o.status||!o.data){if(o?.error?.description!=="canceled")throw new Error(o?.error?.description);return}let r=h.compressImage(o.data.image);this.setting.fileStorage.write(this.getImagePath(!0),r.jpg(.8)),this.setting.fileStorage.write(this.getImagePath(),o.data),$(t).image=r,$ui.success($l10n("SUCCESS"))})},{title:$l10n("SELECT_IMAGE_ICLOUD"),handler:i(async()=>{let o=await $drive.open();if(!o)return;let r=h.compressImage(o.image);this.setting.fileStorage.write(this.getImagePath(!0),r.jpg(.8)),this.setting.fileStorage.write(this.getImagePath(),o),$(t).image=r,$ui.success($l10n("SUCCESS"))})}]},{title:$l10n("CLEAR_IMAGE"),destructive:!0,handler:i(()=>{this.setting.fileStorage.delete(this.getImagePath(!0)),this.setting.fileStorage.delete(this.getImagePath()),$(t).image=e,$ui.success($l10n("SUCCESS"))})}];return{type:"view",props:{id:this.id,selectable:!0},views:[this.createLineLabel(),{type:"view",views:[{type:"image",props:{id:t,image:this.getImage(!0)?.image??e},layout:(o,r)=>{o.right.inset(u.edgeOffset),o.centerY.equalTo(r.super),o.size.equalTo($size(30,30))}},{type:"spinner",props:{id:`${t}-spinner`,loading:!0,hidden:!0},layout:(o,r)=>{o.size.equalTo(r.prev),o.left.top.equalTo(r.prev)}},{type:"button",props:{menu:{pullDown:!0,asPrimary:!0,items:s},bgcolor:$color("clear")},layout:(o,r)=>{o.right.inset(u.edgeOffset),o.centerY.equalTo(r.super),o.size.equalTo($size(30,30))}}],layout:(o,r)=>{o.right.inset(0),o.height.equalTo(u.rowHeight),o.width.equalTo(r.super)}}],layout:$layout.fill}}},yt=class extends v{name;setting={};settingItems={};userData;fileStorage;logger;imagePath;viewController=new K;method={readme:()=>{let t=(()=>{let i=$device.info?.language?.startsWith("zh")?"README_CN.md":"README.md";try{return __README__[i]??__README__["README.md"]}catch{return $file.read(i)?.string??$file.read("README.md")?.string}})();new b().setView({type:"markdown",props:{content:t},layout:(i,s)=>{i.size.equalTo(s.super)}}).addNavBar({title:"README",popButton:{symbol:"x.circle"}}).init().present()}};#t=!1;#e=!1;#i;constructor(t={}){super(),typeof t.set=="function"&&typeof t.get=="function"?(this.set=t.set,this.getOriginal=t.get,this.setUserData(t.userData??{})):(this.fileStorage=t.fileStorage??new S,this.dataFile=t.dataFile??"setting.json"),t.structure?this.setStructure(t.structure):this.setStructurePath(t.structurePath??"setting.json"),this.logger=t.logger??new V,this.isUseJsboxNav=t.isUseJsboxNav??!1,this.imagePath=(t.name??"default")+".image/",this.setName(t.name??$text.uuid)}useJsboxNav(){return this.isUseJsboxNav=!0,this}#s(){if(!this.#e)throw new k}loader(t){let e=null;switch(t.type){case"info":e=new L(t);break;case"switch":e=new Y(t);break;case"string":e=new X(t);break;case"stepper":e=new _(t).with({min:t.min??1,max:t.max??12});break;case"script":e=new z(t).with({script:t.script??t.value});break;case"tab":e=new Z(t).with({items:t.items,values:t.values});break;case"menu":e=new Q(t).with({items:t.items,values:t.values,pullDown:t.pullDown??!1});break;case"color":e=new tt(t);break;case"date":e=new et(t).with({mode:t.mode});break;case"input":e=new N(t).with({secure:t.secure});break;case"number":e=new it(t);break;case"icon":e=new st(t).with({bgcolor:t.bgcolor});break;case"push":e=new P(t).with({view:t.view,navButtons:t.navButtons});break;case"child":e=new M(t).with({children:t.children});break;case"image":e=new ot(t);break;default:e=t,e.default=t.value,e.get=(...i)=>this.get(...i),e.set=(...i)=>this.set(...i)}return e}loadConfig(){this.#e=!1;let t=this.userData??this.fileStorage.readAsJSON(this.dataFile,{}),e=i=>{for(let s in i)for(let o in i[s].items){let r=i[s].items[o];r instanceof u||(i[s].items[o]=this.loader(r),r=i[s].items[o]),r.setting||(r.setting=this),this.settingItems[r.key]=r,r instanceof M?e(r.options.children):r instanceof z||r instanceof L||(r.key in t?this.setting[r.key]=t[r.key]:this.setting[r.key]=r.default)}};return e(this.structure),this.#e=!0,this}hasSectionTitle(t){return this.#s(),!!t[0]?.title}setUserData(t){return this.userData=t,this}setStructure(t){return this.structure=t,this.loadConfig()}setStructurePath(t){return this.structure||this.setStructure(S.readFromRootAsJSON(t)),this}setName(t){return this.name=t,this}setFooter(t){return this.footer=t,this}set footer(t){this.#i=t}get footer(){if(this.#i===void 0){let t=S.readFromRootAsJSON("config.json",{}).info??{};if(!t.version||!t.author)try{t=__INFO__}catch{}this.#i={},t.version&&t.author&&(this.#i={type:"view",props:{height:70},views:[{type:"label",props:{font:$font(14),text:`${$l10n("VERSION")} ${t.version} \u2665 ${t.author}`,textColor:$color({light:"#C0C0C0",dark:"#545454"}),align:$align.center},layout:e=>{e.left.right.inset(0),e.top.inset(10)}}]})}return this.#i}setReadonly(){return this.#t=!0,this}set(t,e){if(this.#t)throw new j;return this.#s(),this.setting[t]=e,this.fileStorage.write(this.dataFile,$data({string:JSON.stringify(this.setting)})),this.callEvent("onSet",t,e),!0}getOriginal(t,e=null){return this.#s(),Object.prototype.hasOwnProperty.call(this.setting,t)?this.setting[t]:e}getItem(t){return this.settingItems[t]}get(t,e=null){return this.#s(),this.getItem(t)?this.getItem(t).get(e):this.getOriginal(t,e)}#o(t){let e=[];for(let i in t){let s=[];for(let o in t[i].items){let r=t[i].items[o];r instanceof u&&s.push(r.create())}e.push({title:$l10n(t[i].title??""),rows:s})}return e}getListView(t=this.structure,e=this.footer,i=this.name){return{type:"list",props:{id:i,style:2,separatorInset:$insets(0,u.iconSize+u.edgeOffset*2,0,u.edgeOffset),footer:e,data:this.#o(t)},layout:$layout.fill,events:{rowHeight:(s,o)=>(s.object(o)?.props?.info??{}).rowHeight??u.rowHeight,didSelect:async(s,o,r)=>{s=s.ocValue();let n=this.getItem(r.props.info.key);if(typeof n?.tapped=="function"){s.$selectRowAtIndexPath_animated_scrollPosition(o.ocValue(),!1,0);try{await n.tapped()}catch(l){this.logger.error(l)}}s.$deselectRowAtIndexPath_animated(o,!0)}}}}getNavigationView(){let t=new m;return t.setView(this.getListView(this.structure)).navigationBarTitle($l10n("SETTING")),this.hasSectionTitle(this.structure)&&t.navigationBar.setContentViewHeightOffset(-10),t}getPage(){return this.getNavigationView().getPage()}},rt=class extends D{constructor(t,e){super(t,e),this.name="SheetViewTypeError"}},F=class extends d{constructor(t={}){super(t),this.setIcon(t.icon),this.setTitle(t.title),t.activeStatus!==void 0&&(this.activeStatus=t.activeStatus)}setIcon(t){return t instanceof Array?this.icon=t:this.icon=[t,t],this}setTitle(t){return this.title=t,this}active(){$(`${this.props.id}-icon`).image=$image(this.icon[1]),$(`${this.props.id}-icon`).tintColor=$color("systemLink"),$(`${this.props.id}-title`).textColor=$color("systemLink"),this.activeStatus=!0}inactive(){$(`${this.props.id}-icon`).image=$image(this.icon[0]),$(`${this.props.id}-icon`).tintColor=$color("lightGray"),$(`${this.props.id}-title`).textColor=$color("lightGray"),this.activeStatus=!1}getView(){return this.views=[{type:"image",props:{id:`${this.props.id}-icon`,image:$image(this.activeStatus?this.icon[1]:this.icon[0]),bgcolor:$color("clear"),tintColor:$color(this.activeStatus?"systemLink":"lightGray")},layout:(t,e)=>{t.centerX.equalTo(e.super);let i=I.tabBarHeight/2;t.size.equalTo(i),t.top.inset((I.tabBarHeight-i-13)/2)}},{type:"label",props:{id:`${this.props.id}-title`,text:this.title,font:$font(10),textColor:$color(this.activeStatus?"systemLink":"lightGray")},layout:(t,e)=>{t.centerX.equalTo(e.prev),t.top.equalTo(e.prev.bottom).offset(3)}}],this}},wt=class extends d{height=60;getView(){return this.type="view",this.setProp("bgcolor",this.props.bgcolor??h.primaryViewBackgroundColor),this.layout=(t,e)=>{t.left.right.bottom.equalTo(e.super),t.top.equalTo(e.super.safeAreaBottom).offset(-this.height-I.tabBarHeight)},this.views=[d.create({props:this.props,views:this.views,layout:(t,e)=>{t.left.right.top.equalTo(e.super),t.height.equalTo(this.height)}})],this}},I=class a extends v{static tabBarHeight=50;#t={};#e={};#i;#s;#o=$text.uuid;#r=$text.uuid;bottomSafeAreaInsets=$app.isDebugging?0:h.bottomSafeAreaInsets;get selected(){return this.#s}set selected(t){this.switchPageTo(t)}get contentOffset(){return a.tabBarHeight+(this.#i?.height??0)}setPages(t={}){return Object.keys(t).forEach(e=>this.setPage(e,t[e])),this}setPage(t,e){return this.#s===void 0&&(this.#s=t),e instanceof T?this.#t[t]=e:this.#t[t]=T.create(e),this.#s!==t&&(this.#t[t].activeStatus=!1),this}switchPageTo(t){if(this.#t[t]){if(this.#s===t)return;$ui.animate({duration:.4,animation:()=>{this.#e[t].active()}}),this.#e[this.#s].inactive(),this.#t[this.#s].hide(),this.#t[t].show(),this.callEvent("onChange",this.#s,t),this.#s=t,this.initBackground()}}hideBackground(t=!0){$(this.#r).hidden=!0,$ui.animate({duration:t?.2:1e-4,animation:()=>{$(this.#o).alpha=0}})}showBackground(t=!0){$(this.#r).hidden=!1,$ui.animate({duration:t?.2:1e-4,animation:()=>{$(this.#o).alpha=1}})}initBackground(){let t=this.#t[this.selected];t.scrollable&&$delay(0,()=>{let e=$(t.id).get(t.scrollableView.id),i=e.contentOffset.y;e.contentSize.height+this.bottomSafeAreaInsets-e.frame.height-i<=0?this.hideBackground(!1):this.showBackground(!1)})}setCells(t={}){return Object.keys(t).forEach(e=>this.setCell(e,t[e])),this}setCell(t,e){return this.#s===void 0&&(this.#s=t),e instanceof F||(e=new F({props:{info:{key:t}},icon:e.icon,title:e.title,activeStatus:this.#s===t})),this.#e[t]=e,this}setHeader(t){return this.#i=t,this}#a(){let t=[];return Object.values(this.#e).forEach(e=>{e.setEvent("tapped",i=>{let s=i.info.key;this.switchPageTo(s)}),t.push(e.getView())}),t}#n(){return Object.values(this.#t).map(t=>{if(t.scrollable){let e=t.scrollableView;if(e.props.indicatorInsets){let i=e.props.indicatorInsets;e.props.indicatorInsets=$insets(i.top,i.left,i.bottom+this.contentOffset,i.right)}else e.props.indicatorInsets=$insets(0,0,this.contentOffset,0);if(e.props.contentInset){let i=e.props.contentInset;e.props.contentInset=$insets(i.top,i.left,i.bottom+this.contentOffset,i.right)}else e.props.contentInset=$insets(0,0,this.contentOffset,0);typeof e.assignEvent=="function"&&e.assignEvent("didScroll",i=>{let s=i.contentOffset.y-this.contentOffset;i.contentSize.height+this.bottomSafeAreaInsets-i.frame.height-s<=1?this.hideBackground():this.showBackground()})}return t.definition})}generateView(){let t={type:"view",layout:(e,i)=>{e.centerX.equalTo(i.super),e.width.equalTo(i.super),e.top.equalTo(i.super.safeAreaBottom).offset(-a.tabBarHeight),e.bottom.equalTo(i.super)},views:[h.blurBox({id:this.#o}),{type:"stack",layout:$layout.fillSafeArea,props:{axis:$stackViewAxis.horizontal,distribution:$stackViewDistribution.fillEqually,spacing:0,stack:{views:this.#a()}}},h.separatorLine({id:this.#r},h.align.top)],events:{ready:()=>this.initBackground()}};return d.createFromViews(this.#n().concat(this.#i?.definition??[],t))}},T=class extends d{constructor(t={}){super(t),this.activeStatus=!0}show(){$(this.props.id).hidden=!1,this.activeStatus=!0}hide(){$(this.props.id).hidden=!0,this.activeStatus=!1}setHorizontalSafeArea(t){return this.horizontalSafeArea=t,this}#t(t,e){t.top.bottom.equalTo(e.super),this.horizontalSafeArea?t.left.right.equalTo(e.super.safeArea):t.left.right.equalTo(e.super)}getView(){return this.layout=this.#t,this.props.clipsToBounds=!0,this.props.hidden=!this.activeStatus,super.getView()}},$t=class extends w{#t;user;password;#e;namespace="JSBox.WebDAV";lockTokenCacheKey=this.namespace+".lockToken";get host(){return this.#t}set host(t){for(this.#t=t.trim();this.#t.endsWith("/");)this.#t=this.#t.substring(0,this.#t.length-1);this.#t.startsWith("http")||(this.#t="http://"+this.#t)}get basepath(){return this.#e}set basepath(t){for(this.#e=t.trim();this.#e.endsWith("/");)this.#e=this.#e.substring(0,this.#e.length-1);for(;this.#e.startsWith("/");)this.#e=this.#e.substring(1);this.#e="/"+this.#e}constructor({host:t,user:e,password:i,basepath:s=""}={}){super(),this.host=t,this.user=e,this.password=i,this.basepath=s}#i(t){return t=t.trim(),t=t.startsWith("/")?t:"/"+t,this.basepath+t}async request(t,e,i=null,s={}){return s=Object.assign({"Content-Type":"text/xml; charset=UTF-8",Authorization:"Basic "+$text.base64Encode(`${this.user}:${this.password}`)},s),await super.request(this.host+this.#i(t),e,i,s)}async allow(t){let e=await this.request(t,w.method.options);return(e.response.headers?.allow??e.response.headers?.Allow)?.split(",").map(s=>s.trim().toUpperCase())??[]}async propfind(t,e=[],i=0){Array.isArray(e)||(e=[e]);let o=`${e.map(n=>``).join()}`,r=await this.request(t,"PROPFIND",o,{Depth:i});return $xml.parse({string:r.data})}async propfindAll(t,e=0){let i='',s=await this.request(t,"PROPFIND",i,{Depth:e});return $xml.parse({string:s.data})}async ls(t,e=1){let i=await this.request(t,"PROPFIND",null,{Depth:e});return $xml.parse({string:i.data})}async exists(t){try{return(await this.allow(t)).includes(w.method.get)?await this.request(t,w.method.head):await this.ls(t,0),!0}catch(e){if(e?.code===404)return!1;throw e}}async mkdir(t){return await this.request(t,"MKCOL")}async get(t){return await this.request(t,w.method.get,null)}async put(t,e,{withLock:i=!0,waitInterval:s=2,maxTry:o=3}={}){let r={};for(;await this.isLocked(t);){if(--o<=0)throw new Error("Resource Locked");await $wait(s)}if(i)try{await this.lock(t),r.If=`(${this.#o(t)})`}catch(n){if(n.code!==404)throw n;i=!1}await this.request(t,w.method.put,e,r),i&&await this.unlock(t)}async delete(t){if(!t)throw new Error("path empty");return await this.request(t,w.method.delete)}#s(t,e){let i=$cache.get(this.lockTokenCacheKey)??{};i[t]=e,$cache.set(this.lockTokenCacheKey,i)}#o(t){return($cache.get(this.lockTokenCacheKey)??{})[t]}async isSupportLock(t){try{return!!(await this.propfind(t,"supportedlock")).rootElement.firstChild({xPath:"//D:response/D:propstat/D:prop/D:supportedlock/D:lockentry"}).firstChild({xPath:"//D:locktype/D:write"})}catch(e){if(e.code!==404)return!1;throw e}}async lock(t,{infinity:e=!1,timeout:i="Second-10"}={}){if(!await this.isSupportLock(t))throw new Error("Your WebDAV service does not support the `LOCK` method.");let o=`${this.namespace}`,r=await this.request(t,"LOCK",o,{Timeout:i,Depth:e?"infinity":0}),n=r.response.headers["lock-token"]??r.response.headers["Lock-Token"];return this.#s(t,n),$xml.parse({string:r.data})}async isLocked(t){try{let i=(await this.propfind(t,"lockdiscovery")).rootElement;if(!i.firstChild({xPath:"//D:response/D:propstat/D:status"}).string.includes("404")){let n=i.firstChild({xPath:"//D:response/D:propstat/D:prop/D:lockdiscovery"}).children()??[];for(let l=0;l { 17 | const text = $(this.contentTextId).text 18 | if (!text || text === "") { 19 | $ui.warning("Content is empty") 20 | return 21 | } 22 | try { 23 | const result = this.kernel.juice(text) 24 | $(this.resultTextId).text = result 25 | $ui.success("Done") 26 | } catch (error) { 27 | this.kernel.logger.error(error) 28 | } 29 | } 30 | }, 31 | { 32 | symbol: "doc.on.clipboard", 33 | title: $l10n("PASTE"), 34 | handler: () => { 35 | const text = $clipboard.text 36 | if (text && text !== "") { 37 | $(this.contentTextId).text = text 38 | } else { 39 | $ui.warning("Clipboard is empty") 40 | } 41 | } 42 | } 43 | ] 44 | } 45 | 46 | getView() { 47 | return { 48 | type: "view", 49 | props: {}, 50 | layout: $layout.fill, 51 | views: [ 52 | { 53 | type: "text", 54 | props: { 55 | id: this.contentTextId, 56 | cornerRadius: 10, 57 | smoothCorners: true, 58 | placeholder: "Content here", 59 | bgcolor: this.bgcolor 60 | }, 61 | layout: (make, view) => { 62 | make.top.left.right.equalTo(view.super.safeArea).inset(this.margin) 63 | make.height 64 | .equalTo(view.super.safeArea) 65 | .dividedBy(2) 66 | .offset(this.margin * 2 * -1) 67 | } 68 | }, 69 | { 70 | type: "text", 71 | props: { 72 | id: this.resultTextId, 73 | cornerRadius: 10, 74 | smoothCorners: true, 75 | editable: false, 76 | placeholder: "Result here", 77 | menu: { 78 | items: [ 79 | { 80 | symbol: "doc.on.clipboard", 81 | title: $l10n("COPY"), 82 | handler: () => { 83 | const text = $(this.resultTextId).text 84 | if (text && text !== "") { 85 | $clipboard.text = $(this.resultTextId).text 86 | $ui.success("Copied") 87 | } else { 88 | $ui.warning("Result is empty") 89 | } 90 | } 91 | } 92 | ] 93 | }, 94 | bgcolor: this.bgcolor 95 | }, 96 | layout: (make, view) => { 97 | make.bottom.left.right.equalTo(view.super.safeArea).inset(this.margin) 98 | make.top.equalTo(view.prev.bottom).offset(this.margin) 99 | } 100 | } 101 | ] 102 | } 103 | } 104 | } 105 | 106 | module.exports = MainUI 107 | -------------------------------------------------------------------------------- /Juice/strings/en.strings: -------------------------------------------------------------------------------- 1 | "ALERT_INFO" = "Alert"; 2 | "NONE" = "None"; 3 | "FAILED_TO_LOAD_VIEW" = "Faild to load view"; 4 | "VIEW_NOT_PROVIDED" = "The view is not provided"; 5 | "UNCATEGORIZED" = "Uncategorized"; 6 | 7 | "OK" = "OK"; 8 | "START" = "Start"; 9 | "CANCEL" = "Cancel"; 10 | 11 | "COPY" = "Copy"; -------------------------------------------------------------------------------- /Juice/strings/zh-Hans.strings: -------------------------------------------------------------------------------- 1 | "ALERT_INFO" = "提示"; 2 | "NONE" = "什么都没有"; 3 | "FAILED_TO_LOAD_VIEW" = "加载视图失败"; 4 | "VIEW_NOT_PROVIDED" = "未提供该视图"; 5 | "UNCATEGORIZED" = "未分类"; 6 | 7 | "OK" = "好"; 8 | "START" = "开始"; 9 | "CANCEL" = "取消"; 10 | 11 | "COPY" = "复制"; -------------------------------------------------------------------------------- /Juice/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [ 3 | { 4 | "type": "@comment", 5 | "parameters": { 6 | "text": { 7 | "value": "GitHub: https://github.com/ipuppet/Juice" 8 | } 9 | } 10 | }, 11 | { 12 | "type": "@flow.javascript", 13 | "parameters": { 14 | "script": { 15 | "value": "" 16 | } 17 | } 18 | } 19 | ], 20 | "buildVersion": 1, 21 | "clientMinVersion": 1, 22 | "clientVersion": 592, 23 | "icon": { 24 | "glyph": "arrow.2.circlepath.circle.fill", 25 | "color": "#FF6633" 26 | }, 27 | "summary": "Given HTML, Juice will inline your CSS properties into the style attribute." 28 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Samuel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Taio Actios 2 | 3 | 安装 Installer 后,可复制(长按)其他动作的链接到安装器进行安装。 4 | 5 | ## Installer 6 | 7 | > 通过 URL 安装动作 8 | 9 | 复制下方链接在 Safari 中打开: 10 | 11 | taio://actions?action=import&url=https%3A%2F%2Fraw.githubusercontent.com%2Fipuppet%2FTaioActions%2Fmain%2FActions%2FInstaller.taioactions 12 | 13 | ## b23clean 14 | 15 | > 清除 b23.tv 追踪参数 16 | 17 | [b23clean](https://raw.githubusercontent.com/ipuppet/TaioActions/main/Actions/b23clean.taioactions) 18 | 19 | ## Beautify 20 | 21 | > 美化 JS CSS HTML 22 | > 使用 [beautify-web/js-beautify](https://github.com/beautify-web/js-beautify) 实现 23 | 24 | [Beautify](https://raw.githubusercontent.com/ipuppet/TaioActions/main/Actions/Beautify.taioactions) 25 | 26 | ## Juice 27 | 28 | > 将 CSS 属性内联到 style 属性中 29 | > 使用 [Automattic/juice](https://github.com/Automattic/juice) 实现 30 | 31 | ### 使用方法 32 | 33 | 作为模块使用,请在您自己的动作中引用此动作。 34 | 35 | 输入 HTML 内容,返回内联 CSS 后的内容。 36 | 37 | [Juice](https://raw.githubusercontent.com/ipuppet/TaioActions/main/Actions/Juice.taioactions) 38 | 39 | ## Clean Clipboard 40 | 41 | > 清空当前剪切板 42 | 43 | [Clean Clipboard](https://raw.githubusercontent.com/ipuppet/TaioActions/main/Actions/Clean%20Clipboard.taioactions) 44 | 45 | ## Copy Content 46 | 47 | > 复制文件内容 48 | 49 | [Copy Content](https://raw.githubusercontent.com/ipuppet/TaioActions/main/Actions/Copy%20Content.taioactions) 50 | 51 | ## Edit Clip 52 | 53 | > 创建文件 `ClipEditor.md` 编辑选中的 Clip 54 | 55 | [Edit Clip](https://raw.githubusercontent.com/ipuppet/TaioActions/main/Actions/Edit%20Clip.taioactions) 56 | 57 | ## Json Format 58 | 59 | > 格式化 JSON 60 | 61 | [Json Format](https://raw.githubusercontent.com/ipuppet/TaioActions/main/Actions/Json%20Format.taioactions) 62 | 63 | ## Open URL 64 | 65 | > 打开链接,有多条时可手动指定 66 | 67 | [Open URL](https://raw.githubusercontent.com/ipuppet/TaioActions/main/Actions/Open%20URL.taioactions) 68 | 69 | ## URL Decode 70 | 71 | > 对选中文本或全文 URL 解码,并提供差异对比(仅在编辑器内可用) 72 | 73 | [URL Decode](https://raw.githubusercontent.com/ipuppet/TaioActions/main/Actions/URL%20Decode.taioactions) 74 | 75 | ## URL Encode 76 | 77 | > 对选中文本或全文 URL 编码,并提供差异对比(仅在编辑器内可用) 78 | 79 | [URL Encode](https://raw.githubusercontent.com/ipuppet/TaioActions/main/Actions/URL%20Encode.taioactions) 80 | -------------------------------------------------------------------------------- /b23clean/README.md: -------------------------------------------------------------------------------- 1 | # b23clean 2 | 3 | ## Install 4 | 5 | JSBox: 6 | 7 | - b23clean.js: [Click to Install](jsbox://import?url=https%3A%2F%2Fraw.githubusercontent.com%2Fipuppet%2FTaioActions%2Fmain%2Fb23clean%2Fdist%2Fb23clean.js) 8 | 9 | Taio: 10 | 11 | - b23clean: [Click to Install](taio://actions?action=import&url=https%3A%2F%2Fraw.githubusercontent.com%2Fipuppet%2FTaioActions%2Fmain%2FActions%2Fb23clean.taioactions) 12 | -------------------------------------------------------------------------------- /b23clean/build.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs") 2 | const path = require("path") 3 | const process = require("child_process") 4 | 5 | const config = JSON.parse(fs.readFileSync(path.join(__dirname, "config.json"), "utf-8")) 6 | 7 | const outputName = config.info.name 8 | const distEntryPath = path.join(__dirname, `dist/${outputName}.js`) 9 | const entryFileContent = fs.readFileSync(path.join(__dirname, "main.js"), "utf-8") 10 | 11 | const entryFile = "main.build.js" 12 | const entryFilePath = path.join(__dirname, entryFile) 13 | 14 | function injectContent() { 15 | const stringsFolder = path.join(__dirname, "strings") 16 | const stringsFiles = fs.readdirSync(stringsFolder) 17 | const localizedText = {} 18 | stringsFiles.forEach(fileName => { 19 | if (path.extname(fileName) !== ".strings") { 20 | return 21 | } 22 | 23 | const locale = fileName.replace(".strings", "") 24 | localizedText[locale] = {} 25 | 26 | const filePath = path.join(stringsFolder, fileName) 27 | const content = fs.readFileSync(filePath, "utf-8") 28 | const lines = content.split(/\r?\n/) 29 | lines.forEach(line => { 30 | const match = /[\"'](.+)[\"'][ \n]*=[ \n]*[\"'](.+)[\"']/.exec(line) 31 | if (match) { 32 | localizedText[locale][match[1]] = match[2] 33 | } 34 | }) 35 | }) 36 | const stringsText = `$app.strings = ${JSON.stringify(localizedText)};` 37 | 38 | const configSettings = Object.keys(config.settings) 39 | .map(key => { 40 | const value = (() => { 41 | const value = config.settings[key] 42 | if (typeof value === "string") { 43 | return `"${value}"` 44 | } else { 45 | return value 46 | } 47 | })() 48 | return `$app.${key} = ${value};` 49 | }) 50 | .join("\n") 51 | 52 | const contents = [stringsText, configSettings, entryFileContent] 53 | 54 | fs.writeFileSync(entryFilePath, contents.join("\n\n")) 55 | } 56 | 57 | function buildTextActions() { 58 | const script = fs.readFileSync(distEntryPath, "utf-8") 59 | const template = path.join(__dirname, "template.json") 60 | const fileContent = fs.readFileSync(template, "utf-8") 61 | const textAction = JSON.parse(fileContent) 62 | 63 | textAction.name = config.info.name 64 | 65 | for (let i = 0; i < textAction.actions.length; i++) { 66 | if (textAction.actions[i].type === "@flow.javascript") { 67 | textAction.actions[i].parameters.script.value = script 68 | break 69 | } 70 | } 71 | const outputPath = path.join(__dirname, `dist/${outputName}.json`) 72 | fs.writeFileSync(outputPath, JSON.stringify(textAction, null, 4)) 73 | } 74 | 75 | function injectPackageJson(packageJson) { 76 | packageJson.jsbox = distEntryPath 77 | packageJson.targets = { 78 | jsbox: { 79 | source: entryFile, 80 | includeNodeModules: false, 81 | sourceMap: false, 82 | outputFormat: "global" 83 | } 84 | } 85 | 86 | return packageJson 87 | } 88 | 89 | async function build() { 90 | const packageJsonPath = path.join(__dirname, "package.json") 91 | const packageJsonContent = fs.readFileSync(packageJsonPath, "utf-8") 92 | 93 | const packageJson = injectPackageJson(JSON.parse(packageJsonContent)) 94 | fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson)) 95 | 96 | try { 97 | injectContent() 98 | const stdout = process.execSync(`parcel build`) 99 | console.log(stdout.toString()) 100 | buildTextActions() 101 | } catch (error) { 102 | if (error.stdout) { 103 | console.error(error.stdout.toString()) 104 | } else { 105 | console.error(error) 106 | } 107 | } finally { 108 | // 恢复文件内容 109 | fs.unlinkSync(entryFilePath) 110 | fs.writeFileSync(packageJsonPath, packageJsonContent) 111 | } 112 | } 113 | 114 | build() 115 | -------------------------------------------------------------------------------- /b23clean/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "name": "b23clean", 4 | "version": "1.0.0", 5 | "author": "ipuppet", 6 | "module": false 7 | }, 8 | "settings": { 9 | "theme": "auto", 10 | "minSDKVer": "2.19.0", 11 | "minOSVer": "14.0.0", 12 | "idleTimerDisabled": false, 13 | "keyboardToolbarEnabled": true, 14 | "rotateDisabled": false 15 | } 16 | } -------------------------------------------------------------------------------- /b23clean/dist/b23clean.js: -------------------------------------------------------------------------------- 1 | (()=>{$app.strings={en:{COPY:"Copy",COPIED:"Copied","b23clean.converting":"Converting...","b23clean.noUrl":"No link detected","b23clean.noBiliUrl":"Not a bilibili link","b23clean.success":"Converted to BV video link"},"zh-Hans":{COPY:"复制",COPIED:"已复制","b23clean.converting":"正在转换...","b23clean.noUrl":"未检测到链接","b23clean.noBiliUrl":"不是 bilibili 链接","b23clean.success":"已转换为 BV 视频链接"}},$app.theme="auto",$app.minSDKVer="2.19.0",$app.minOSVer="14.0.0",$app.idleTimerDisabled=!1,$app.keyboardToolbarEnabled=!0,$app.rotateDisabled=!1;class e{static #e=$objc("UIApplication").$sharedApplication();static #t=$objc("UINotificationFeedbackGenerator").$new();static feedbackSuccess(){e.#t.$notificationOccurred(0)}static feedbackError(){e.#t.$notificationOccurred(2)}static align={left:0,right:1,top:2,bottom:3};static textColor=$color("primaryText");static linkColor=$color("systemLink");static primaryViewBackgroundColor=$color("primarySurface");static scrollViewBackgroundColor=$color("insetGroupedBackground");static scrollViewList=["list","matrix"];static isLargeScreen=$device.isIpad||$device.isIpadPro;static get windowSize(){return $objc("UIWindow").$keyWindow().jsValue().size}static NavigationBarNormalHeight=$objc("UINavigationController").invoke("alloc.init").$navigationBar().jsValue().frame.height;static NavigationBarLargeTitleHeight=$objc("UITabBarController").invoke("alloc.init").$tabBar().jsValue().frame.height+e.NavigationBarNormalHeight;static get isSplitScreenMode(){return e.isLargeScreen&&$device.info.screen.width!==e.windowSize.width}static get topSafeAreaInsets(){return e.#e?.$keyWindow()?.$safeAreaInsets()?.top??0}static get bottomSafeAreaInsets(){return e.#e?.$keyWindow()?.$safeAreaInsets()?.bottom??0}static get statusBarOrientation(){return e.#e.$statusBarOrientation()}static get consoleBarHeight(){if($app.isDebugging){let t=e.#e.$statusBarFrame().height+26;return $device.isIphoneX&&(t+=30),t}return 0}static get isHorizontal(){return 3===e.statusBarOrientation||4===e.statusBarOrientation}static loading(){let t=$ui.create(e.blurBox({cornerRadius:15},[{type:"spinner",props:{loading:!0,style:0},layout:(e,t)=>{e.size.equalTo(t.prev),e.center.equalTo(t.super)}}]));return{start:()=>{$ui.controller.view.insertAtIndex(t,0),t.layout((t,i)=>{t.center.equalTo(i.super);let a=Math.min(.6*Math.min(e.windowSize.width,e.windowSize.height),260);t.size.equalTo($size(a,a))}),t.moveToFront()},end:()=>{t.remove()}}}static defaultBackgroundColor(t){return e.scrollViewList.indexOf(t)>-1?e.scrollViewBackgroundColor:e.primaryViewBackgroundColor}static separatorLine(t={},i=e.align.bottom){return{type:"canvas",props:t,layout:(t,a)=>{void 0===a.prev?t.top.equalTo(a.super):i===e.align.bottom?t.top.equalTo(a.prev.bottom):t.top.equalTo(a.prev.top),t.height.equalTo(1/$device.info.screen.scale),t.left.right.inset(0)},events:{draw:(e,i)=>{i.strokeColor=t.bgcolor??$color("separatorColor"),i.setLineWidth(1),i.moveToPoint(0,0),i.addLineToPoint(e.frame.width,0),i.strokePath()}}}}static blurBox(e={},t=[],i=$layout.fill){return{type:"blur",props:Object.assign({style:$blurStyle.thinMaterial},e),views:t,layout:i}}static getContentSize(t,i="A",a=e.windowSize.width,o){let r={text:i,width:a,font:t};return void 0!==o&&(r.lineSpacing=o),$text.sizeThatFits(r)}static getSymbolSize(e,t){let i=(e="string"==typeof e?$image(e):e).size.width/e.size.height;return e.size.width>e.size.height?$size(t,t/i):$size(t*i,t)}static push({views:e,statusBarStyle:t=0,title:i="",navButtons:a=[{title:""}],bgcolor:o=e[0]?.props?.bgcolor??"primarySurface",titleView:r,disappeared:s}={}){let n={statusBarStyle:t,navButtons:a,title:i,bgcolor:"string"==typeof o?$color(o):o};r&&(n.titleView=r),$ui.push({props:n,events:{disappeared:()=>{void 0!==s&&s()}},views:[{type:"view",views:e,layout:(e,t)=>{e.top.equalTo(t.super.safeArea),e.bottom.equalTo(t.super),e.left.right.equalTo(t.super.safeArea)}}]})}}class t{static type={info:void 0,success:"checkmark",warning:"exclamationmark.triangle",error:"xmark.circle"};static edges=40;static iconSize=100;static labelTopMargin=10;static defaultFont=$font("default",26);width=Math.min(.6*e.windowSize.width,260);labelWidth=this.width-2*t.edges;id=$text.uuid;#i="";font=t.defaultFont;type=t.type.info;labelLines=2;constructor(e,i=t.type.info,a=2,o=t.defaultFont){this.type=i,this.message=e,this.labelLines=a,this.font=o}get message(){return this.#i}set message(i){this.#i=i,this.fontHeight=e.getContentSize(this.font,this.message,this.labelWidth,this.labelLines).height,this.height=(this.hasIcon?t.labelTopMargin+t.iconSize:0)+this.fontHeight+2*t.edges}get hasIcon(){return void 0!==this.type}get blurBox(){let i=e.blurBox({id:this.id,cornerRadius:15,alpha:0},[{type:"image",props:{symbol:this.type,hidden:!this.hasIcon,tintColor:$color("lightGray")},layout:(e,i)=>{e.top.inset(t.edges),e.size.equalTo(t.iconSize),e.centerX.equalTo(i.super)}},{type:"label",props:{font:this.font,text:this.message,align:$align.center,lines:this.labelLines,color:$color("lightGray")},layout:(e,i)=>{e.bottom.equalTo(i.supper).offset(-t.edges),e.width.equalTo(this.labelWidth),e.height.equalTo(this.fontHeight),e.centerX.equalTo(i.super)}}]);return i.events={tapped:()=>{this.remove()}},i}show(){$ui.controller.view.insertAtIndex($ui.create(this.blurBox),0);let e=$(this.id);e.layout((e,t)=>{e.center.equalTo(t.super),e.size.equalTo($size(this.width,this.height))}),e.moveToFront(),$ui.animate({duration:.2,animation:()=>{e.alpha=1}})}remove(){let e=$(this.id);e&&$ui.animate({duration:.2,animation:()=>{e.alpha=0},completion:()=>{e.remove()}})}static toast({message:e,type:i=t.type.info,show:a=!0,displayTime:o=2,labelLines:r=2,font:s=t.defaultFont}){let n=new t(e,i,r,s);return a&&(n.show(),$delay(o,()=>{n.remove()})),n}static info(e,i={}){return t.toast(Object.assign({message:e,type:t.type.info},i))}static success(e,i={}){return t.toast(Object.assign({message:e,type:t.type.success},i))}static warning(e,i={}){return t.toast(Object.assign({message:e,type:t.type.warning},i))}static error(e,i={}){return t.toast(Object.assign({message:e,type:t.type.error},i))}}async function i(e){if(-1===e.indexOf("bilibili.com")&&-1===e.indexOf("b23.tv"))throw Error($l10n("b23clean.noBiliUrl"));let t=e;e.indexOf("b23.tv")>=0&&(t=(await $http.get(e)).response.url);let i=t.indexOf("?");return i>-1&&(t=t.substring(0,i-1)),t}async function a(){let e=t.info($l10n("b23clean.converting"),{show:!1});try{let a=(()=>{let e=[$actions.inputValue,$clipboard.text];for(let t=0;t1){let e=await $ui.menu({items:a});o=a[e.index]}if(-1===o.indexOf("bilibili.com")&&-1===o.indexOf("b23.tv"))throw Error($l10n("b23clean.noBiliUrl"));e.show(),o=await i(o),e.remove(),await $ui.alert({title:$l10n("b23clean.success"),message:o,actions:[{title:$l10n("OK")},{title:$l10n("COPY"),handler:()=>{$clipboard.text=o,t.success($l10n("COPIED"))}}]})}catch(i){e.remove(),$delay(.5,()=>t.error(String(i)))}}({run:()=>{a().catch(e=>console.error(e))}}).run()})(); -------------------------------------------------------------------------------- /b23clean/dist/b23clean.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [ 3 | { 4 | "type": "@comment", 5 | "parameters": { 6 | "text": { 7 | "value": "b23.tv trace parameter cleanup" 8 | } 9 | } 10 | }, 11 | { 12 | "type": "@flow.javascript", 13 | "parameters": { 14 | "script": { 15 | "value": "(()=>{$app.strings={en:{COPY:\"Copy\",COPIED:\"Copied\",\"b23clean.converting\":\"Converting...\",\"b23clean.noUrl\":\"No link detected\",\"b23clean.noBiliUrl\":\"Not a bilibili link\",\"b23clean.success\":\"Converted to BV video link\"},\"zh-Hans\":{COPY:\"复制\",COPIED:\"已复制\",\"b23clean.converting\":\"正在转换...\",\"b23clean.noUrl\":\"未检测到链接\",\"b23clean.noBiliUrl\":\"不是 bilibili 链接\",\"b23clean.success\":\"已转换为 BV 视频链接\"}},$app.theme=\"auto\",$app.minSDKVer=\"2.19.0\",$app.minOSVer=\"14.0.0\",$app.idleTimerDisabled=!1,$app.keyboardToolbarEnabled=!0,$app.rotateDisabled=!1;class e{static #e=$objc(\"UIApplication\").$sharedApplication();static #t=$objc(\"UINotificationFeedbackGenerator\").$new();static feedbackSuccess(){e.#t.$notificationOccurred(0)}static feedbackError(){e.#t.$notificationOccurred(2)}static align={left:0,right:1,top:2,bottom:3};static textColor=$color(\"primaryText\");static linkColor=$color(\"systemLink\");static primaryViewBackgroundColor=$color(\"primarySurface\");static scrollViewBackgroundColor=$color(\"insetGroupedBackground\");static scrollViewList=[\"list\",\"matrix\"];static isLargeScreen=$device.isIpad||$device.isIpadPro;static get windowSize(){return $objc(\"UIWindow\").$keyWindow().jsValue().size}static NavigationBarNormalHeight=$objc(\"UINavigationController\").invoke(\"alloc.init\").$navigationBar().jsValue().frame.height;static NavigationBarLargeTitleHeight=$objc(\"UITabBarController\").invoke(\"alloc.init\").$tabBar().jsValue().frame.height+e.NavigationBarNormalHeight;static get isSplitScreenMode(){return e.isLargeScreen&&$device.info.screen.width!==e.windowSize.width}static get topSafeAreaInsets(){return e.#e?.$keyWindow()?.$safeAreaInsets()?.top??0}static get bottomSafeAreaInsets(){return e.#e?.$keyWindow()?.$safeAreaInsets()?.bottom??0}static get statusBarOrientation(){return e.#e.$statusBarOrientation()}static get consoleBarHeight(){if($app.isDebugging){let t=e.#e.$statusBarFrame().height+26;return $device.isIphoneX&&(t+=30),t}return 0}static get isHorizontal(){return 3===e.statusBarOrientation||4===e.statusBarOrientation}static loading(){let t=$ui.create(e.blurBox({cornerRadius:15},[{type:\"spinner\",props:{loading:!0,style:0},layout:(e,t)=>{e.size.equalTo(t.prev),e.center.equalTo(t.super)}}]));return{start:()=>{$ui.controller.view.insertAtIndex(t,0),t.layout((t,i)=>{t.center.equalTo(i.super);let a=Math.min(.6*Math.min(e.windowSize.width,e.windowSize.height),260);t.size.equalTo($size(a,a))}),t.moveToFront()},end:()=>{t.remove()}}}static defaultBackgroundColor(t){return e.scrollViewList.indexOf(t)>-1?e.scrollViewBackgroundColor:e.primaryViewBackgroundColor}static separatorLine(t={},i=e.align.bottom){return{type:\"canvas\",props:t,layout:(t,a)=>{void 0===a.prev?t.top.equalTo(a.super):i===e.align.bottom?t.top.equalTo(a.prev.bottom):t.top.equalTo(a.prev.top),t.height.equalTo(1/$device.info.screen.scale),t.left.right.inset(0)},events:{draw:(e,i)=>{i.strokeColor=t.bgcolor??$color(\"separatorColor\"),i.setLineWidth(1),i.moveToPoint(0,0),i.addLineToPoint(e.frame.width,0),i.strokePath()}}}}static blurBox(e={},t=[],i=$layout.fill){return{type:\"blur\",props:Object.assign({style:$blurStyle.thinMaterial},e),views:t,layout:i}}static getContentSize(t,i=\"A\",a=e.windowSize.width,o){let r={text:i,width:a,font:t};return void 0!==o&&(r.lineSpacing=o),$text.sizeThatFits(r)}static getSymbolSize(e,t){let i=(e=\"string\"==typeof e?$image(e):e).size.width/e.size.height;return e.size.width>e.size.height?$size(t,t/i):$size(t*i,t)}static push({views:e,statusBarStyle:t=0,title:i=\"\",navButtons:a=[{title:\"\"}],bgcolor:o=e[0]?.props?.bgcolor??\"primarySurface\",titleView:r,disappeared:s}={}){let n={statusBarStyle:t,navButtons:a,title:i,bgcolor:\"string\"==typeof o?$color(o):o};r&&(n.titleView=r),$ui.push({props:n,events:{disappeared:()=>{void 0!==s&&s()}},views:[{type:\"view\",views:e,layout:(e,t)=>{e.top.equalTo(t.super.safeArea),e.bottom.equalTo(t.super),e.left.right.equalTo(t.super.safeArea)}}]})}}class t{static type={info:void 0,success:\"checkmark\",warning:\"exclamationmark.triangle\",error:\"xmark.circle\"};static edges=40;static iconSize=100;static labelTopMargin=10;static defaultFont=$font(\"default\",26);width=Math.min(.6*e.windowSize.width,260);labelWidth=this.width-2*t.edges;id=$text.uuid;#i=\"\";font=t.defaultFont;type=t.type.info;labelLines=2;constructor(e,i=t.type.info,a=2,o=t.defaultFont){this.type=i,this.message=e,this.labelLines=a,this.font=o}get message(){return this.#i}set message(i){this.#i=i,this.fontHeight=e.getContentSize(this.font,this.message,this.labelWidth,this.labelLines).height,this.height=(this.hasIcon?t.labelTopMargin+t.iconSize:0)+this.fontHeight+2*t.edges}get hasIcon(){return void 0!==this.type}get blurBox(){let i=e.blurBox({id:this.id,cornerRadius:15,alpha:0},[{type:\"image\",props:{symbol:this.type,hidden:!this.hasIcon,tintColor:$color(\"lightGray\")},layout:(e,i)=>{e.top.inset(t.edges),e.size.equalTo(t.iconSize),e.centerX.equalTo(i.super)}},{type:\"label\",props:{font:this.font,text:this.message,align:$align.center,lines:this.labelLines,color:$color(\"lightGray\")},layout:(e,i)=>{e.bottom.equalTo(i.supper).offset(-t.edges),e.width.equalTo(this.labelWidth),e.height.equalTo(this.fontHeight),e.centerX.equalTo(i.super)}}]);return i.events={tapped:()=>{this.remove()}},i}show(){$ui.controller.view.insertAtIndex($ui.create(this.blurBox),0);let e=$(this.id);e.layout((e,t)=>{e.center.equalTo(t.super),e.size.equalTo($size(this.width,this.height))}),e.moveToFront(),$ui.animate({duration:.2,animation:()=>{e.alpha=1}})}remove(){let e=$(this.id);e&&$ui.animate({duration:.2,animation:()=>{e.alpha=0},completion:()=>{e.remove()}})}static toast({message:e,type:i=t.type.info,show:a=!0,displayTime:o=2,labelLines:r=2,font:s=t.defaultFont}){let n=new t(e,i,r,s);return a&&(n.show(),$delay(o,()=>{n.remove()})),n}static info(e,i={}){return t.toast(Object.assign({message:e,type:t.type.info},i))}static success(e,i={}){return t.toast(Object.assign({message:e,type:t.type.success},i))}static warning(e,i={}){return t.toast(Object.assign({message:e,type:t.type.warning},i))}static error(e,i={}){return t.toast(Object.assign({message:e,type:t.type.error},i))}}async function i(e){if(-1===e.indexOf(\"bilibili.com\")&&-1===e.indexOf(\"b23.tv\"))throw Error($l10n(\"b23clean.noBiliUrl\"));let t=e;e.indexOf(\"b23.tv\")>=0&&(t=(await $http.get(e)).response.url);let i=t.indexOf(\"?\");return i>-1&&(t=t.substring(0,i-1)),t}async function a(){let e=t.info($l10n(\"b23clean.converting\"),{show:!1});try{let a=(()=>{let e=[$actions.inputValue,$clipboard.text];for(let t=0;t1){let e=await $ui.menu({items:a});o=a[e.index]}if(-1===o.indexOf(\"bilibili.com\")&&-1===o.indexOf(\"b23.tv\"))throw Error($l10n(\"b23clean.noBiliUrl\"));e.show(),o=await i(o),e.remove(),await $ui.alert({title:$l10n(\"b23clean.success\"),message:o,actions:[{title:$l10n(\"OK\")},{title:$l10n(\"COPY\"),handler:()=>{$clipboard.text=o,t.success($l10n(\"COPIED\"))}}]})}catch(i){e.remove(),$delay(.5,()=>t.error(String(i)))}}({run:()=>{a().catch(e=>console.error(e))}}).run()})();" 16 | } 17 | } 18 | } 19 | ], 20 | "buildVersion": 1, 21 | "clientMinVersion": 1, 22 | "summary": "", 23 | "icon": { 24 | "glyph": "trash", 25 | "color": "#FF3300" 26 | }, 27 | "clientVersion": 592, 28 | "name": "b23clean" 29 | } -------------------------------------------------------------------------------- /b23clean/main.js: -------------------------------------------------------------------------------- 1 | // run app 2 | const app = require("./scripts/app") 3 | app.run() 4 | -------------------------------------------------------------------------------- /b23clean/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "license": "MIT", 3 | "scripts": { 4 | "build": "node build.js" 5 | } 6 | } -------------------------------------------------------------------------------- /b23clean/scripts/app.js: -------------------------------------------------------------------------------- 1 | const { Toast } = require("./libs/toast") 2 | 3 | function getUrls() { 4 | const input = (() => { 5 | const inputList = [$actions.inputValue, $clipboard.text] 6 | for (let i = 0; i < inputList.length; i++) { 7 | if (inputList[i] && inputList[i] !== "") { 8 | return inputList[i] 9 | } 10 | } 11 | return "" 12 | })() 13 | 14 | const regex = /(https?:\/\/)([\da-z\.-]+)\.([a-z\.]{2,6})([:0-9])*([\/\w\#\.\-\?\=\&])*\s?/gi 15 | return input.match(regex) ?? [] 16 | } 17 | 18 | async function cleanUrl(b23url) { 19 | if (b23url.indexOf("bilibili.com") === -1 && b23url.indexOf("b23.tv") === -1) { 20 | throw new Error($l10n("b23clean.noBiliUrl")) 21 | } 22 | 23 | let url = b23url 24 | if (b23url.indexOf("b23.tv") >= 0) { 25 | const resp = await $http.get(b23url) 26 | url = resp.response.url 27 | } 28 | 29 | const queryStart = url.indexOf("?") 30 | if (queryStart > -1) { 31 | url = url.substring(0, queryStart - 1) 32 | } 33 | 34 | return url 35 | } 36 | 37 | async function main() { 38 | const loading = Toast.info($l10n("b23clean.converting"), { show: false }) 39 | 40 | try { 41 | const b23url = getUrls() 42 | if (b23url.length === 0) { 43 | throw new Error($l10n("b23clean.noUrl")) 44 | } 45 | 46 | let url = b23url[0] 47 | if (b23url.length > 1) { 48 | const urlSelected = await $ui.menu({ 49 | items: b23url 50 | }) 51 | url = b23url[urlSelected.index] 52 | } 53 | 54 | if (url.indexOf("bilibili.com") === -1 && url.indexOf("b23.tv") === -1) { 55 | throw new Error($l10n("b23clean.noBiliUrl")) 56 | } 57 | 58 | loading.show() 59 | url = await cleanUrl(url) 60 | loading.remove() // $actions.resolve 会结束运行,不能用 finally 61 | 62 | await $ui.alert({ 63 | title: $l10n("b23clean.success"), 64 | message: url, 65 | actions: [ 66 | { title: $l10n("OK") }, 67 | { 68 | title: $l10n("COPY"), 69 | handler: () => { 70 | $clipboard.text = url 71 | Toast.success($l10n("COPIED")) 72 | } 73 | } 74 | ] 75 | }) 76 | } catch (error) { 77 | loading.remove() 78 | $delay(0.5, () => Toast.error(String(error))) 79 | } 80 | } 81 | 82 | module.exports = { 83 | run: () => { 84 | main().catch(error => console.error(error)) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /b23clean/scripts/libs/toast.js: -------------------------------------------------------------------------------- 1 | const { UIKit } = require("./ui-kit") 2 | 3 | class Toast { 4 | static type = { 5 | info: undefined, 6 | success: "checkmark", 7 | warning: "exclamationmark.triangle", 8 | error: "xmark.circle" 9 | } 10 | static edges = 40 11 | static iconSize = 100 12 | static labelTopMargin = 10 13 | static defaultFont = $font("default", 26) 14 | 15 | width = Math.min(UIKit.windowSize.width * 0.6, 260) 16 | labelWidth = this.width - Toast.edges * 2 17 | 18 | id = $text.uuid 19 | 20 | #message = "" 21 | font = Toast.defaultFont 22 | type = Toast.type.info 23 | labelLines = 2 24 | 25 | constructor(message, type = Toast.type.info, labelLines = 2, font = Toast.defaultFont) { 26 | // 先确定类型,用于高度计算 27 | this.type = type 28 | this.message = message 29 | this.labelLines = labelLines 30 | this.font = font 31 | } 32 | 33 | get message() { 34 | return this.#message 35 | } 36 | 37 | set message(message) { 38 | this.#message = message 39 | this.fontHeight = UIKit.getContentSize(this.font, this.message, this.labelWidth, this.labelLines).height 40 | this.height = (this.hasIcon ? Toast.labelTopMargin + Toast.iconSize : 0) + this.fontHeight + Toast.edges * 2 41 | } 42 | 43 | get hasIcon() { 44 | return this.type !== undefined 45 | } 46 | 47 | get blurBox() { 48 | const blurBox = UIKit.blurBox({ id: this.id, cornerRadius: 15, alpha: 0 }, [ 49 | { 50 | type: "image", 51 | props: { 52 | symbol: this.type, 53 | hidden: !this.hasIcon, 54 | tintColor: $color("lightGray") 55 | }, 56 | layout: (make, view) => { 57 | make.top.inset(Toast.edges) 58 | make.size.equalTo(Toast.iconSize) 59 | make.centerX.equalTo(view.super) 60 | } 61 | }, 62 | { 63 | type: "label", 64 | props: { 65 | font: this.font, 66 | text: this.message, 67 | align: $align.center, 68 | lines: this.labelLines, 69 | color: $color("lightGray") 70 | }, 71 | layout: (make, view) => { 72 | make.bottom.equalTo(view.supper).offset(-Toast.edges) 73 | make.width.equalTo(this.labelWidth) 74 | make.height.equalTo(this.fontHeight) 75 | make.centerX.equalTo(view.super) 76 | } 77 | } 78 | ]) 79 | blurBox.events = { 80 | tapped: () => { 81 | this.remove() 82 | } 83 | } 84 | 85 | return blurBox 86 | } 87 | 88 | show() { 89 | $ui.controller.view.insertAtIndex($ui.create(this.blurBox), 0) 90 | const toast = $(this.id) 91 | toast.layout((make, view) => { 92 | make.center.equalTo(view.super) 93 | make.size.equalTo($size(this.width, this.height)) 94 | }) 95 | toast.moveToFront() 96 | $ui.animate({ 97 | duration: 0.2, 98 | animation: () => { 99 | toast.alpha = 1 100 | } 101 | }) 102 | } 103 | 104 | remove() { 105 | const toast = $(this.id) 106 | if (!toast) return 107 | $ui.animate({ 108 | duration: 0.2, 109 | animation: () => { 110 | toast.alpha = 0 111 | }, 112 | completion: () => { 113 | toast.remove() 114 | } 115 | }) 116 | } 117 | 118 | static toast({ 119 | message, 120 | type = Toast.type.info, 121 | show = true, 122 | displayTime = 2, 123 | labelLines = 2, 124 | font = Toast.defaultFont 125 | }) { 126 | const toast = new Toast(message, type, labelLines, font) 127 | if (show) { 128 | toast.show() 129 | $delay(displayTime, () => { 130 | toast.remove() 131 | }) 132 | } 133 | 134 | return toast 135 | } 136 | static info(message, opts = {}) { 137 | return Toast.toast(Object.assign({ message, type: Toast.type.info }, opts)) 138 | } 139 | static success(message, opts = {}) { 140 | return Toast.toast(Object.assign({ message, type: Toast.type.success }, opts)) 141 | } 142 | static warning(message, opts = {}) { 143 | return Toast.toast(Object.assign({ message, type: Toast.type.warning }, opts)) 144 | } 145 | static error(message, opts = {}) { 146 | return Toast.toast(Object.assign({ message, type: Toast.type.error }, opts)) 147 | } 148 | } 149 | 150 | module.exports = { Toast } 151 | -------------------------------------------------------------------------------- /b23clean/scripts/libs/ui-kit.js: -------------------------------------------------------------------------------- 1 | class UIKit { 2 | static #sharedApplication = $objc("UIApplication").$sharedApplication() 3 | static #feedbackGenerator = $objc("UINotificationFeedbackGenerator").$new() 4 | 5 | static feedbackSuccess() { 6 | UIKit.#feedbackGenerator.$notificationOccurred(0) 7 | } 8 | static feedbackError() { 9 | UIKit.#feedbackGenerator.$notificationOccurred(2) 10 | } 11 | 12 | /** 13 | * 对齐方式 14 | */ 15 | static align = { left: 0, right: 1, top: 2, bottom: 3 } 16 | 17 | /** 18 | * 默认文本颜色 19 | */ 20 | static textColor = $color("primaryText") 21 | 22 | /** 23 | * 默认链接颜色 24 | */ 25 | static linkColor = $color("systemLink") 26 | static primaryViewBackgroundColor = $color("primarySurface") 27 | static scrollViewBackgroundColor = $color("insetGroupedBackground") 28 | 29 | /** 30 | * 可滚动视图列表 31 | * @type {string[]} 32 | */ 33 | static scrollViewList = ["list", "matrix"] 34 | 35 | /** 36 | * 是否属于大屏设备 37 | * @type {boolean} 38 | */ 39 | static isLargeScreen = $device.isIpad || $device.isIpadPro 40 | 41 | /** 42 | * 获取Window大小 43 | */ 44 | static get windowSize() { 45 | return $objc("UIWindow").$keyWindow().jsValue().size 46 | } 47 | 48 | static NavigationBarNormalHeight = $objc("UINavigationController").invoke("alloc.init").$navigationBar().jsValue() 49 | .frame.height 50 | static NavigationBarLargeTitleHeight = 51 | $objc("UITabBarController").invoke("alloc.init").$tabBar().jsValue().frame.height + 52 | UIKit.NavigationBarNormalHeight 53 | 54 | /** 55 | * 判断是否是分屏模式 56 | * @type {boolean} 57 | */ 58 | static get isSplitScreenMode() { 59 | return UIKit.isLargeScreen && $device.info.screen.width !== UIKit.windowSize.width 60 | } 61 | 62 | static get topSafeAreaInsets() { 63 | return UIKit.#sharedApplication?.$keyWindow()?.$safeAreaInsets()?.top ?? 0 64 | } 65 | 66 | static get bottomSafeAreaInsets() { 67 | return UIKit.#sharedApplication?.$keyWindow()?.$safeAreaInsets()?.bottom ?? 0 68 | } 69 | 70 | static get statusBarOrientation() { 71 | return UIKit.#sharedApplication.$statusBarOrientation() 72 | } 73 | 74 | /** 75 | * 调试模式控制台高度 76 | * @type {number} 77 | */ 78 | static get consoleBarHeight() { 79 | if ($app.isDebugging) { 80 | let height = UIKit.#sharedApplication.$statusBarFrame().height + 26 81 | if ($device.isIphoneX) { 82 | height += 30 83 | } 84 | return height 85 | } 86 | return 0 87 | } 88 | 89 | static get isHorizontal() { 90 | return UIKit.statusBarOrientation === 3 || UIKit.statusBarOrientation === 4 91 | } 92 | 93 | static loading() { 94 | const loading = $ui.create( 95 | UIKit.blurBox( 96 | { 97 | cornerRadius: 15 98 | }, 99 | [ 100 | { 101 | type: "spinner", 102 | props: { 103 | loading: true, 104 | style: 0 105 | }, 106 | layout: (make, view) => { 107 | make.size.equalTo(view.prev) 108 | make.center.equalTo(view.super) 109 | } 110 | } 111 | ] 112 | ) 113 | ) 114 | 115 | return { 116 | start: () => { 117 | $ui.controller.view.insertAtIndex(loading, 0) 118 | loading.layout((make, view) => { 119 | make.center.equalTo(view.super) 120 | const size = Math.min(Math.min(UIKit.windowSize.width, UIKit.windowSize.height) * 0.6, 260) 121 | make.size.equalTo($size(size, size)) 122 | }) 123 | loading.moveToFront() 124 | }, 125 | end: () => { 126 | loading.remove() 127 | } 128 | } 129 | } 130 | 131 | static defaultBackgroundColor(type) { 132 | return UIKit.scrollViewList.indexOf(type) > -1 133 | ? UIKit.scrollViewBackgroundColor 134 | : UIKit.primaryViewBackgroundColor 135 | } 136 | 137 | static separatorLine(props = {}, align = UIKit.align.bottom) { 138 | return { 139 | // canvas 140 | type: "canvas", 141 | props: props, 142 | layout: (make, view) => { 143 | if (view.prev === undefined) { 144 | make.top.equalTo(view.super) 145 | } else if (align === UIKit.align.bottom) { 146 | make.top.equalTo(view.prev.bottom) 147 | } else { 148 | make.top.equalTo(view.prev.top) 149 | } 150 | make.height.equalTo(1 / $device.info.screen.scale) 151 | make.left.right.inset(0) 152 | }, 153 | events: { 154 | draw: (view, ctx) => { 155 | ctx.strokeColor = props.bgcolor ?? $color("separatorColor") 156 | ctx.setLineWidth(1) 157 | ctx.moveToPoint(0, 0) 158 | ctx.addLineToPoint(view.frame.width, 0) 159 | ctx.strokePath() 160 | } 161 | } 162 | } 163 | } 164 | 165 | static blurBox(props = {}, views = [], layout = $layout.fill) { 166 | return { 167 | type: "blur", 168 | props: Object.assign( 169 | { 170 | style: $blurStyle.thinMaterial 171 | }, 172 | props 173 | ), 174 | views, 175 | layout 176 | } 177 | } 178 | 179 | /** 180 | * 计算文本尺寸 181 | * @param {$font} font 182 | * @param {string} content 183 | * @returns 184 | */ 185 | static getContentSize(font, content = "A", width = UIKit.windowSize.width, lineSpacing = undefined) { 186 | const options = { 187 | text: content, 188 | width, 189 | font: font 190 | } 191 | if (lineSpacing !== undefined) { 192 | options.lineSpacing = lineSpacing 193 | } 194 | return $text.sizeThatFits(options) 195 | } 196 | 197 | static getSymbolSize(symbol, size) { 198 | symbol = typeof symbol === "string" ? $image(symbol) : symbol 199 | const scale = symbol.size.width / symbol.size.height 200 | if (symbol.size.width > symbol.size.height) { 201 | return $size(size, size / scale) 202 | } else { 203 | return $size(size * scale, size) 204 | } 205 | } 206 | 207 | /** 208 | * 建议仅在使用 JSBox nav 时使用,便于统一风格 209 | */ 210 | static push({ 211 | views, 212 | statusBarStyle = 0, 213 | title = "", 214 | navButtons = [{ title: "" }], 215 | bgcolor = views[0]?.props?.bgcolor ?? "primarySurface", 216 | titleView = undefined, 217 | disappeared 218 | } = {}) { 219 | const props = { 220 | statusBarStyle, 221 | navButtons, 222 | title, 223 | bgcolor: typeof bgcolor === "string" ? $color(bgcolor) : bgcolor 224 | } 225 | if (titleView) { 226 | props.titleView = titleView 227 | } 228 | $ui.push({ 229 | props, 230 | events: { 231 | disappeared: () => { 232 | if (disappeared !== undefined) disappeared() 233 | } 234 | }, 235 | views: [ 236 | { 237 | type: "view", 238 | views: views, 239 | layout: (make, view) => { 240 | make.top.equalTo(view.super.safeArea) 241 | make.bottom.equalTo(view.super) 242 | make.left.right.equalTo(view.super.safeArea) 243 | } 244 | } 245 | ] 246 | }) 247 | } 248 | } 249 | 250 | module.exports = { 251 | UIKit 252 | } 253 | -------------------------------------------------------------------------------- /b23clean/strings/en.strings: -------------------------------------------------------------------------------- 1 | "COPY" = "Copy"; 2 | "COPIED" = "Copied"; 3 | 4 | "b23clean.converting" = "Converting..."; 5 | "b23clean.noUrl" = "No link detected"; 6 | "b23clean.noBiliUrl" = "Not a bilibili link"; 7 | "b23clean.success" = "Converted to BV video link"; -------------------------------------------------------------------------------- /b23clean/strings/zh-Hans.strings: -------------------------------------------------------------------------------- 1 | "COPY" = "复制"; 2 | "COPIED" = "已复制"; 3 | 4 | "b23clean.converting" = "正在转换..."; 5 | "b23clean.noUrl" = "未检测到链接"; 6 | "b23clean.noBiliUrl" = "不是 bilibili 链接"; 7 | "b23clean.success" = "已转换为 BV 视频链接"; -------------------------------------------------------------------------------- /b23clean/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [ 3 | { 4 | "type": "@comment", 5 | "parameters": { 6 | "text": { 7 | "value": "b23.tv trace parameter cleanup" 8 | } 9 | } 10 | }, 11 | { 12 | "type": "@flow.javascript", 13 | "parameters": { 14 | "script": { 15 | "value": "" 16 | } 17 | } 18 | } 19 | ], 20 | "buildVersion": 1, 21 | "clientMinVersion": 1, 22 | "summary": "", 23 | "icon": { 24 | "glyph": "trash", 25 | "color": "#FF3300" 26 | }, 27 | "clientVersion": 592 28 | } --------------------------------------------------------------------------------