pinokiod 3.9.2 → 3.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/:w +1247 -0
- package/package.json +1 -1
- package/server/public/style.css +4 -0
- package/server/views/app.ejs +15 -11
- package/server/views/index.ejs +38 -34
package/:w
ADDED
|
@@ -0,0 +1,1247 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<title>Pinokio</title>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
|
6
|
+
<link href="/xterm.min.css" rel="stylesheet" />
|
|
7
|
+
<link href="/css/fontawesome.min.css" rel="stylesheet">
|
|
8
|
+
<link href="/css/solid.min.css" rel="stylesheet">
|
|
9
|
+
<link href="/css/regular.min.css" rel="stylesheet">
|
|
10
|
+
<link href="/css/brands.min.css" rel="stylesheet">
|
|
11
|
+
<link href="/markdown.css" rel="stylesheet"/>
|
|
12
|
+
<link href="/noty.css" rel="stylesheet"/>
|
|
13
|
+
<link href="/filepond.min.css" rel="stylesheet" />
|
|
14
|
+
<link href="/filepond-plugin-image-preview.min.css" rel="stylesheet" />
|
|
15
|
+
<link href="/filepond-plugin-image-edit.min.css" rel="stylesheet" />
|
|
16
|
+
<link href="/style.css" rel="stylesheet"/>
|
|
17
|
+
<% if (agent === "electron") { %>
|
|
18
|
+
<link href="/electron.css" rel="stylesheet"/>
|
|
19
|
+
<% } %>
|
|
20
|
+
<style>
|
|
21
|
+
.line2 {
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
background: rgba(0,0,100,0.04);
|
|
26
|
+
}
|
|
27
|
+
.line2 a {
|
|
28
|
+
text-decoration: none;
|
|
29
|
+
color: black;
|
|
30
|
+
}
|
|
31
|
+
.status {
|
|
32
|
+
padding: 10px;
|
|
33
|
+
margin: 10px;
|
|
34
|
+
border-radius: 10px;
|
|
35
|
+
}
|
|
36
|
+
.status.offline {
|
|
37
|
+
background: silver;
|
|
38
|
+
}
|
|
39
|
+
.status.online {
|
|
40
|
+
background: yellowgreen;
|
|
41
|
+
}
|
|
42
|
+
.switch {
|
|
43
|
+
padding: 10px;
|
|
44
|
+
margin: 10px 0;
|
|
45
|
+
}
|
|
46
|
+
.switch[data-online=true] {
|
|
47
|
+
color: yellowgreen;
|
|
48
|
+
}
|
|
49
|
+
.button {
|
|
50
|
+
padding: 10px;
|
|
51
|
+
}
|
|
52
|
+
.on, .off {
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
}
|
|
56
|
+
header .runner {
|
|
57
|
+
padding: 10px 0 0;
|
|
58
|
+
}
|
|
59
|
+
.proxy {
|
|
60
|
+
padding: 0 10px;
|
|
61
|
+
text-align: right;
|
|
62
|
+
}
|
|
63
|
+
.proxy a {
|
|
64
|
+
text-decoration: none;
|
|
65
|
+
display: inline-block;
|
|
66
|
+
padding: 5px 10px;
|
|
67
|
+
border-radius: 2px;
|
|
68
|
+
background: black;
|
|
69
|
+
color: white;
|
|
70
|
+
}
|
|
71
|
+
.browser-options-btns {
|
|
72
|
+
display: flex;
|
|
73
|
+
padding-top: 5px;
|
|
74
|
+
}
|
|
75
|
+
.browser-options-row {
|
|
76
|
+
/*
|
|
77
|
+
border-top: 1px solid rgba(0,0,0,0.1);
|
|
78
|
+
border-bottom: 1px solid rgba(0,0,0,0.1);
|
|
79
|
+
*/
|
|
80
|
+
display: flex;
|
|
81
|
+
padding: 10px;
|
|
82
|
+
align-items: flex-start;
|
|
83
|
+
}
|
|
84
|
+
.browser-options-row h3 {
|
|
85
|
+
margin: 0;
|
|
86
|
+
font-size: 14px;
|
|
87
|
+
margin-bottom: 3px;
|
|
88
|
+
}
|
|
89
|
+
.browser-options-row .btn.disabled {
|
|
90
|
+
opacity: 0.7;
|
|
91
|
+
}
|
|
92
|
+
.browser-options-row .btn {
|
|
93
|
+
font-weight: bold;
|
|
94
|
+
width: 100px;
|
|
95
|
+
text-align: center;
|
|
96
|
+
display: block;
|
|
97
|
+
margin-right: 10px;
|
|
98
|
+
flex-shrink: 0;
|
|
99
|
+
padding: 5px;
|
|
100
|
+
}
|
|
101
|
+
.badge {
|
|
102
|
+
font-size: 12px;
|
|
103
|
+
padding: 5px 10px;
|
|
104
|
+
background: rgba(0,0,100,0.1);
|
|
105
|
+
border-radius: 5px;
|
|
106
|
+
display: inline-block;
|
|
107
|
+
margin-top: 5px;
|
|
108
|
+
}
|
|
109
|
+
a.badge {
|
|
110
|
+
color: royalblue;
|
|
111
|
+
text-decoration: none;
|
|
112
|
+
cursor: pointer;
|
|
113
|
+
}
|
|
114
|
+
.badge a {
|
|
115
|
+
color: royalblue;
|
|
116
|
+
text-decoration: none;
|
|
117
|
+
}
|
|
118
|
+
body.dark .btn {
|
|
119
|
+
color: white;
|
|
120
|
+
border: 1px solid rgba(255,255,255,0.3);
|
|
121
|
+
}
|
|
122
|
+
body.dark .badge {
|
|
123
|
+
background: rgba(255,255,255,0.1);
|
|
124
|
+
}
|
|
125
|
+
/*
|
|
126
|
+
body.dark .browser-options-row {
|
|
127
|
+
border-top: 1px solid rgba(255,255,255,0.05);
|
|
128
|
+
border-bottom: 1px solid rgba(255,255,255,0.05);
|
|
129
|
+
}
|
|
130
|
+
*/
|
|
131
|
+
.context-menu-wrapper {
|
|
132
|
+
padding: 2px 0;
|
|
133
|
+
background: rgba(0,0,0,0.9);
|
|
134
|
+
}
|
|
135
|
+
.context-menu {
|
|
136
|
+
/*
|
|
137
|
+
max-height: 10000px;
|
|
138
|
+
overflow: hidden;
|
|
139
|
+
transition: max-height 1s ease-in-out;
|
|
140
|
+
*/
|
|
141
|
+
display: flex;
|
|
142
|
+
}
|
|
143
|
+
.context-menu .btn:hover {
|
|
144
|
+
color: cornflowerblue !important;
|
|
145
|
+
}
|
|
146
|
+
.context-menu .btn {
|
|
147
|
+
background: none !important;
|
|
148
|
+
border: none !important;
|
|
149
|
+
display: block;
|
|
150
|
+
width: 80px;
|
|
151
|
+
padding: 6px 10px !important;
|
|
152
|
+
text-align: left;
|
|
153
|
+
}
|
|
154
|
+
.context-menu.collapsed {
|
|
155
|
+
/*
|
|
156
|
+
max-height: 0;
|
|
157
|
+
*/
|
|
158
|
+
display: none;
|
|
159
|
+
}
|
|
160
|
+
body.dark .open-menu {
|
|
161
|
+
background: black !important;
|
|
162
|
+
color: white !important;
|
|
163
|
+
}
|
|
164
|
+
.open-menu {
|
|
165
|
+
width: 80px;
|
|
166
|
+
border-radius: 0 !important;
|
|
167
|
+
background: white !important;
|
|
168
|
+
color: black !important;
|
|
169
|
+
border: 1px solid rgba(0, 0, 0, 0.3);
|
|
170
|
+
}
|
|
171
|
+
.open-menu.selected {
|
|
172
|
+
border: none !important;
|
|
173
|
+
/*
|
|
174
|
+
background: none !important;
|
|
175
|
+
*/
|
|
176
|
+
}
|
|
177
|
+
.open-menu.selected span {
|
|
178
|
+
display: none;
|
|
179
|
+
}
|
|
180
|
+
@media only screen and (max-width: 480px) {
|
|
181
|
+
.btn2 {
|
|
182
|
+
padding: 5px;
|
|
183
|
+
font-size: 11px;
|
|
184
|
+
}
|
|
185
|
+
.nav-btns {
|
|
186
|
+
flex-grow: 1;
|
|
187
|
+
justify-content: center;
|
|
188
|
+
padding: 0;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
</style>
|
|
192
|
+
<script src="/hotkeys.min.js"></script>
|
|
193
|
+
<script src="/sweetalert2.js"></script>
|
|
194
|
+
<script src="/noty.js"></script>
|
|
195
|
+
<script src="/notyq.js"></script>
|
|
196
|
+
<script src="/xterm.js"></script>
|
|
197
|
+
<script src="/xterm-addon-fit.js"></script>
|
|
198
|
+
<script src="/xterm-addon-web-links.js"></script>
|
|
199
|
+
<script src="/xterm-theme.js"></script>
|
|
200
|
+
<script src="/Socket.js"></script>
|
|
201
|
+
<script src="/install.js"></script>
|
|
202
|
+
<script src="/common.js"></script>
|
|
203
|
+
<script src="/opener.js"></script>
|
|
204
|
+
<script src="/nav.js"></script>
|
|
205
|
+
<script src="/fuse.js"></script>
|
|
206
|
+
<script src="/report.js"></script>
|
|
207
|
+
<script src="/filepond-plugin-file-validate-type.min.js"></script>
|
|
208
|
+
<script src="/filepond-plugin-image-exif-orientation.min.js"></script>
|
|
209
|
+
<script src="/filepond-plugin-image-preview.min.js"></script>
|
|
210
|
+
<script src="/filepond-plugin-image-edit.min.js"></script>
|
|
211
|
+
<script src="/filepond-plugin-image-crop.min.js"></script>
|
|
212
|
+
<script src="/filepond-plugin-image-resize.min.js"></script>
|
|
213
|
+
<script src="/filepond-plugin-image-transform.min.js"></script>
|
|
214
|
+
<script src="/filepond.min.js"></script>
|
|
215
|
+
<script src="/fscreator.js"></script>
|
|
216
|
+
<script src="/fseditor.js"></script>
|
|
217
|
+
</head>
|
|
218
|
+
<body class='<%=theme%>'>
|
|
219
|
+
<% if (error) { %>
|
|
220
|
+
<nav class='error-message'>
|
|
221
|
+
<div><%=error%></div>
|
|
222
|
+
<div class='flexible'></div>
|
|
223
|
+
<a class='btn' target="_blank" href="<%=install%>">Download</a>
|
|
224
|
+
</nav>
|
|
225
|
+
<% } %>
|
|
226
|
+
<!--
|
|
227
|
+
<header class='grabbable'>
|
|
228
|
+
-->
|
|
229
|
+
<header class='navheader grabbable'>
|
|
230
|
+
<h1>
|
|
231
|
+
<% if (ishome) { %>
|
|
232
|
+
<a class='home' href="/"><i class="fa-solid fa-house"></i></a>
|
|
233
|
+
<button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
|
|
234
|
+
<button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
|
|
235
|
+
<a class='btn2 create-new' id='create-new-folder'><div><i class='fa-solid fa-plus'></i></div><div>New</div></a>
|
|
236
|
+
<!--
|
|
237
|
+
<a href="/new" class='btn2'><div><i class='fa-solid fa-folder-plus'></i></div><div>Create</div></a>
|
|
238
|
+
-->
|
|
239
|
+
<a class='btn2' id='explore' href="/?mode=explore"><div><i class="fa-solid fa-globe"></i></div><div>Discover</div></a>
|
|
240
|
+
<a href="/network" class='btn2'><div><i class="fa-solid fa-wifi"></i></div><div>Network</div></a>
|
|
241
|
+
<a href="/connect" class='btn2'><div><i class="fa-solid fa-circle-user"></i></div><div>Connect</div></a>
|
|
242
|
+
<!--
|
|
243
|
+
<button id='newfolder' class='btn2'><div><i class="fa-solid fa-folder-plus"></i></div><div>New Folder</div></button>
|
|
244
|
+
-->
|
|
245
|
+
<% } %>
|
|
246
|
+
<% paths.forEach((path) => { %>
|
|
247
|
+
<% if (path.action) { %>
|
|
248
|
+
<a class='path nav-button' id="<%=path.id%>" onclick="<%=path.action%>"><%-path.name%></a>
|
|
249
|
+
<% } else if (path.path) { %>
|
|
250
|
+
<a class='path' href="<%=path.path%>"><%-path.name%></a>
|
|
251
|
+
<% } %>
|
|
252
|
+
<% }) %>
|
|
253
|
+
<form class='search'>
|
|
254
|
+
<% if (display.includes("form")) { %>
|
|
255
|
+
<input type='search' class="flexible" placeholder='Filter downloaded apps'>
|
|
256
|
+
<% } else { %>
|
|
257
|
+
<% } %>
|
|
258
|
+
</form>
|
|
259
|
+
<% if (ishome) { %>
|
|
260
|
+
<div class='nav-btns'>
|
|
261
|
+
<a class='btn2' href="<%=portal%>" target="_blank"><div><i class="fa-solid fa-question"></i></div><div>Help</div></a>
|
|
262
|
+
<% if (agent === "electron") { %>
|
|
263
|
+
<a class='btn2' data-filepath="<%=filepath%>"><div><i class="fa-regular fa-folder-open"></i></div><div>Files</div></a>
|
|
264
|
+
<% } %>
|
|
265
|
+
<button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
|
|
266
|
+
<a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
|
|
267
|
+
<a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
|
|
268
|
+
<% if (agent === "electron") { %>
|
|
269
|
+
<a href="/" target="_blank" class='btn2' features="browser"><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
|
|
270
|
+
<% } else { %>
|
|
271
|
+
<a href="/" target="_blank" class='btn2'><div><i class="fa-solid fa-square-up-right"></i></div><div>Open</div></a>
|
|
272
|
+
<% } %>
|
|
273
|
+
<button id='new-window' title='open a new window' class='btn2'><div><i class="fa-solid fa-plus"></i></div><div>Window</div></button>
|
|
274
|
+
</div>
|
|
275
|
+
<% } %>
|
|
276
|
+
</h1>
|
|
277
|
+
<% if (!ishome) { %>
|
|
278
|
+
<div class='runner'>
|
|
279
|
+
<button class='btn' id='open-fs' data-filepath="<%=filepath%>"><i class="fa-solid fa-eye"></i> View Folder</button>
|
|
280
|
+
</div>
|
|
281
|
+
<% } %>
|
|
282
|
+
<% if (display.includes("dependencies") && config) { %>
|
|
283
|
+
<div class='dependencies'>
|
|
284
|
+
<h2>Prerequisites</h2>
|
|
285
|
+
<div class='item'>Download and install the following dependencies first</div>
|
|
286
|
+
<div class='requirements'>
|
|
287
|
+
<% config.dependencies.forEach((dep) => { %>
|
|
288
|
+
<% if (dep.downloaded) { %>
|
|
289
|
+
<div class='item'><i class="fa-solid fa-check"></i> <a class='downloaded' href="<%=dep.downloaded%>" target="_blank"><%=dep.uri%></a><div class='flexible'></div></div>
|
|
290
|
+
<% } else { %>
|
|
291
|
+
<div class='item'><a class='btn' href="/?mode=download&uri=<%=dep.uri%>" target="_blank"><i class="fa-solid fa-download"></i> Download</a> <%=dep.uri%><div class='flexible'></div></div>
|
|
292
|
+
<% } %>
|
|
293
|
+
<% }) %>
|
|
294
|
+
</div>
|
|
295
|
+
</div>
|
|
296
|
+
<% } %>
|
|
297
|
+
</header>
|
|
298
|
+
<main>
|
|
299
|
+
<div id='terminal' class='hidden'></div>
|
|
300
|
+
<div class='container'>
|
|
301
|
+
<% if (ishome) { %>
|
|
302
|
+
<% if (running.length === 0 && notRunning.length === 0) { %>
|
|
303
|
+
<% } else { %>
|
|
304
|
+
<% if (false) { %>
|
|
305
|
+
<div class='browser-options'>
|
|
306
|
+
<% if (agent === "electron") { %>
|
|
307
|
+
<div class='browser-options-row'>
|
|
308
|
+
<% if (agent === "electron") { %>
|
|
309
|
+
<a href="/" target="_blank" class='btn' features="browser"><div><i class="fa-solid fa-square-up-right"></i> Open</div></a>
|
|
310
|
+
<% } else { %>
|
|
311
|
+
<a href="/" target="_blank" class='btn'><div><i class="fa-solid fa-square-up-right"></i> Open</div></a>
|
|
312
|
+
<% } %>
|
|
313
|
+
<div class='flexible'>
|
|
314
|
+
<h3><i class="fa-solid fa-bolt"></i> Instant Launch</h3>
|
|
315
|
+
<div>(Experimental) Directly open pinokio apps from your favorite browser address bar at localhost. If an app you're trying to use is already running, it will instantly load. If it's not, the app will first launch and then load the website.</div>
|
|
316
|
+
</div>
|
|
317
|
+
</div>
|
|
318
|
+
<% } %>
|
|
319
|
+
<div class='browser-options-row'>
|
|
320
|
+
<a href="/network" class='btn'><div><i class="fa-solid fa-gauge"></i> Configure</div></a>
|
|
321
|
+
<div class='flexible'>
|
|
322
|
+
<h3><i class="fa-solid fa-wifi"></i> Local Sharing</h3>
|
|
323
|
+
<div>Serve Pinokio, installed apps, and even external apps (example: Ollama) to any device on the same network.</div>
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
<div class='browser-options-row hidden'>
|
|
327
|
+
<% if (cloudflare_pub) { %>
|
|
328
|
+
<a id='cloudflare-stop' class='btn'><div><i class="fa-solid fa-stop"></i> Stop</div></a>
|
|
329
|
+
<div class='flexible'>
|
|
330
|
+
<h3>Public Share</h3>
|
|
331
|
+
<div>Open up your Pinokio server to the open internet (anyone with the URL can access)</div>
|
|
332
|
+
<span class='badge'><i class="fa-solid fa-circle-notch fa-spin"></i> Running at <a href="<%=cloudflare_pub%>" target="_blank" features="browser"><%=cloudflare_pub%></a></span>
|
|
333
|
+
<a id='cloudflare-qr' class='badge'><i class="fa-solid fa-qrcode"></i> Scan QR Code</a>
|
|
334
|
+
</div>
|
|
335
|
+
<% } else { %>
|
|
336
|
+
<a id='cloudflare' class='btn'><div><i class="fa-solid fa-play"></i> Start</div></a>
|
|
337
|
+
<a id='cloudflare-starting' class='btn disabled hidden'><div><i class="fa-solid fa-circle-notch fa-spin"></i> Starting</div></a>
|
|
338
|
+
<div class='flexible'>
|
|
339
|
+
<h3>Public Share</h3>
|
|
340
|
+
<div>Open up your Pinokio server to the open internet (anyone with the URL can access)</div>
|
|
341
|
+
</div>
|
|
342
|
+
<% } %>
|
|
343
|
+
</div>
|
|
344
|
+
</div>
|
|
345
|
+
<% } %>
|
|
346
|
+
<% } %>
|
|
347
|
+
<% if (running.length > 0) { %>
|
|
348
|
+
<div class='running-apps'>
|
|
349
|
+
<!--
|
|
350
|
+
<div class='header-label'>Running</div>
|
|
351
|
+
-->
|
|
352
|
+
<% running.forEach((item) => { %>
|
|
353
|
+
<a href="<%=item.browser_url%>" data-description="<%=item.description%>" data-index="<%=item.index%>" data-name="<%=item.name%>" data-title="<%=item.name%>" data-uri="<%=item.uri%>" data-icon="<%=item.icon%>" data-path="<%=item.path%>" data-iconpath="<%=item.iconpath ? item.iconpath : ''%>" class='line align-top'>
|
|
354
|
+
<h3>
|
|
355
|
+
<div class='item-icon'>
|
|
356
|
+
<% if (item.icon) { %>
|
|
357
|
+
<img src="<%=item.icon%>">
|
|
358
|
+
<% } else { %>
|
|
359
|
+
<% if (theme === 'dark') { %>
|
|
360
|
+
<img src="/pinokio-white.png">
|
|
361
|
+
<% } else { %>
|
|
362
|
+
<img src="/pinokio-black.png">
|
|
363
|
+
<% } %>
|
|
364
|
+
<% } %>
|
|
365
|
+
</div>
|
|
366
|
+
<div class='col'>
|
|
367
|
+
<div class='uri'><i class="fa-regular fa-folder"></i><%=item.url%></div>
|
|
368
|
+
<div class='title'><%=item.name%></div>
|
|
369
|
+
<div class='description'><%=item.description%></div>
|
|
370
|
+
<div class='menu-btns'>
|
|
371
|
+
<div>
|
|
372
|
+
<button class='btn open-menu'>
|
|
373
|
+
<i class="fa-solid fa-bars"></i><span> Menu</span>
|
|
374
|
+
</button>
|
|
375
|
+
<div class='context-menu collapsed'>
|
|
376
|
+
<div class='context-menu-wrapper'>
|
|
377
|
+
<button class='btn browse' data-src="<%=item.browser_url%>/browse">
|
|
378
|
+
<i class='fa-regular fa-folder-open'></i> View
|
|
379
|
+
</button>
|
|
380
|
+
<button class='btn copy-menu' data-src="<%=item.browser_url%>/browse">
|
|
381
|
+
<i class='fa-solid fa-copy'></i> Copy
|
|
382
|
+
</button>
|
|
383
|
+
</div>
|
|
384
|
+
</div>
|
|
385
|
+
</div>
|
|
386
|
+
<div class='flexible'></div>
|
|
387
|
+
<% if (item.running_scripts) { %>
|
|
388
|
+
<% item.running_scripts.forEach((s) => { %>
|
|
389
|
+
<button class='btn shutdown' data-src="<%=s.path%>">
|
|
390
|
+
<i class="fa-solid fa-stop"></i> Stop <%=s.name%>
|
|
391
|
+
<i class='fa-solid fa-spin fa-circle-notch'></i>
|
|
392
|
+
</button>
|
|
393
|
+
<% }) %>
|
|
394
|
+
<% } %>
|
|
395
|
+
</div>
|
|
396
|
+
<% if (item.shortcuts && item.shortcuts.length > 0) { %>
|
|
397
|
+
<div class='btns'>
|
|
398
|
+
<% item.shortcuts.forEach((btn) => { %>
|
|
399
|
+
<% if (btn.btn) { %>
|
|
400
|
+
<button data-action="<%=btn.action ? JSON.stringify(btn.action) : ''%>" class='btn menu-btn'><%-btn.btn%></button>
|
|
401
|
+
<% } %>
|
|
402
|
+
<% }) %>
|
|
403
|
+
</div>
|
|
404
|
+
<% } %>
|
|
405
|
+
</div>
|
|
406
|
+
<!--
|
|
407
|
+
<div class='spinner'>
|
|
408
|
+
<i class="fa-solid fa-chevron-right"></i>
|
|
409
|
+
</div>
|
|
410
|
+
-->
|
|
411
|
+
</h3>
|
|
412
|
+
</a>
|
|
413
|
+
<% }) %>
|
|
414
|
+
</div>
|
|
415
|
+
<% } %>
|
|
416
|
+
<% if (notRunning.length > 0) { %>
|
|
417
|
+
<div class='not-running-apps'>
|
|
418
|
+
<!--
|
|
419
|
+
<div class='header-label'>Not Running</div>
|
|
420
|
+
-->
|
|
421
|
+
<% notRunning.forEach((item) => { %>
|
|
422
|
+
<a href="<%=item.browser_url%>" data-description="<%=item.description%>" data-index="<%=item.index%>" data-name="<%=item.name%>" data-title="<%=item.name%>" data-uri="<%=item.uri%>" data-icon="<%=item.icon%>" data-path="<%=item.path%>" data-iconpath="<%=item.iconpath ? item.iconpath : ''%>" class='line align-top'>
|
|
423
|
+
<h3>
|
|
424
|
+
<div class='item-icon'>
|
|
425
|
+
<% if (item.icon) { %>
|
|
426
|
+
<img src="<%=item.icon%>">
|
|
427
|
+
<% } else { %>
|
|
428
|
+
<% if (theme === 'dark') { %>
|
|
429
|
+
<img src="/pinokio-white.png">
|
|
430
|
+
<% } else { %>
|
|
431
|
+
<img src="/pinokio-black.png">
|
|
432
|
+
<% } %>
|
|
433
|
+
<% } %>
|
|
434
|
+
</div>
|
|
435
|
+
<div class='col'>
|
|
436
|
+
<div class='uri'><i class="fa-regular fa-folder"></i><%=item.url%></div>
|
|
437
|
+
<div class='title'><%=item.name%></div>
|
|
438
|
+
<div class='description'><%=item.description%></div>
|
|
439
|
+
<div class='menu-btns'>
|
|
440
|
+
<button class='btn open-menu'>
|
|
441
|
+
<i class="fa-solid fa-bars"></i><span> Menu</span>
|
|
442
|
+
</button>
|
|
443
|
+
<div class='context-menu collapsed'>
|
|
444
|
+
<div class='context-menu-wrapper'>
|
|
445
|
+
<button class='btn browse' data-src="<%=item.browser_url%>/browse">
|
|
446
|
+
<i class='fa-regular fa-folder-open'></i> View
|
|
447
|
+
</button>
|
|
448
|
+
<button class='btn copy-menu' data-src="<%=item.browser_url%>/browse">
|
|
449
|
+
<i class='fa-solid fa-copy'></i> Copy
|
|
450
|
+
</button>
|
|
451
|
+
<button class='btn move-menu' data-src="<%=item.browser_url%>/browse">
|
|
452
|
+
<i class="fa-solid fa-pencil"></i> Move
|
|
453
|
+
</button>
|
|
454
|
+
<button class='btn edit-menu' data-src="<%=item.browser_url%>/browse">
|
|
455
|
+
<i class='fa-solid fa-pen-to-square'></i> Edit
|
|
456
|
+
</button>
|
|
457
|
+
<button class='btn del' data-src="<%=item.url%>">
|
|
458
|
+
<i class="fa-solid fa-trash-can"></i> Delete
|
|
459
|
+
</button>
|
|
460
|
+
</div>
|
|
461
|
+
</div>
|
|
462
|
+
</div>
|
|
463
|
+
<div class='fiexible'></div>
|
|
464
|
+
<% if (item.shortcuts && item.shortcuts.length > 0) { %>
|
|
465
|
+
<div class='btns'>
|
|
466
|
+
<% item.shortcuts.forEach((btn) => { %>
|
|
467
|
+
<% if (btn.btn) { %>
|
|
468
|
+
<button data-action="<%=btn.action ? JSON.stringify(btn.action) : ''%>" class='btn menu-btn'><%-btn.btn%></button>
|
|
469
|
+
<% } %>
|
|
470
|
+
<% }) %>
|
|
471
|
+
</div>
|
|
472
|
+
<% } %>
|
|
473
|
+
</div>
|
|
474
|
+
<!--
|
|
475
|
+
<div class='spinner'>
|
|
476
|
+
<i class="fa-solid fa-chevron-right"></i>
|
|
477
|
+
</div>
|
|
478
|
+
-->
|
|
479
|
+
</h3>
|
|
480
|
+
</a>
|
|
481
|
+
<% }) %>
|
|
482
|
+
</div>
|
|
483
|
+
<% } %>
|
|
484
|
+
<% if (running.length === 0 && notRunning.length === 0) { %>
|
|
485
|
+
<div class='placeholder'>
|
|
486
|
+
<h1>Welcome.</h1>
|
|
487
|
+
<br>
|
|
488
|
+
<div>Get started by installing some Pinokio scripts.</div>
|
|
489
|
+
<a href="/?mode=explore" class='btn'><i class="fa-solid fa-globe"></i> Visit Discover Page</a>
|
|
490
|
+
</div>
|
|
491
|
+
<% } %>
|
|
492
|
+
<% } else { %>
|
|
493
|
+
<% items.forEach((item, index) => { %>
|
|
494
|
+
<a data-description="<%=item.description%>" data-index="<%=index%>" data-name="<%=item.name%>" data-uri="<%=item.uri%>" class='line thick' href="<%=item.url%>">
|
|
495
|
+
<h3>
|
|
496
|
+
<% if (item.icon) { %>
|
|
497
|
+
<i class="<%=item.icon%>"></i>
|
|
498
|
+
<% } else { %>
|
|
499
|
+
<i class="fa-regular fa-folder"></i>
|
|
500
|
+
<% } %>
|
|
501
|
+
<%=item.name%>
|
|
502
|
+
</h3>
|
|
503
|
+
<div class='description'><%=item.description%></div>
|
|
504
|
+
</a>
|
|
505
|
+
<% }) %>
|
|
506
|
+
<% } %>
|
|
507
|
+
<% if (readme) { %>
|
|
508
|
+
<div class='readme markdown-body'>
|
|
509
|
+
<div class='content'><%-readme%></div>
|
|
510
|
+
</div>
|
|
511
|
+
<% } %>
|
|
512
|
+
<% if (display.includes("onboarding")) { %>
|
|
513
|
+
<!--
|
|
514
|
+
<div class='container'>
|
|
515
|
+
<div class='content'>
|
|
516
|
+
<h2>Quickstart</h2>
|
|
517
|
+
<div>Install llama</div>
|
|
518
|
+
<br>
|
|
519
|
+
<button class='btn' id='llama'>Install</button>
|
|
520
|
+
</div>
|
|
521
|
+
</div>
|
|
522
|
+
-->
|
|
523
|
+
<% } %>
|
|
524
|
+
</div>
|
|
525
|
+
</main>
|
|
526
|
+
<script>
|
|
527
|
+
let paths = location.pathname.split("/").filter(x=>x)
|
|
528
|
+
var term
|
|
529
|
+
const n = new N()
|
|
530
|
+
let socket = new Socket()
|
|
531
|
+
const pull = async () => {
|
|
532
|
+
if (!term) {
|
|
533
|
+
<% if (theme === "dark") { %>
|
|
534
|
+
term = await createTerm(xtermTheme.FrontEndDelight)
|
|
535
|
+
<% } else { %>
|
|
536
|
+
term = await createTerm(xtermTheme.Tomorrow)
|
|
537
|
+
<% } %>
|
|
538
|
+
}
|
|
539
|
+
socket.close()
|
|
540
|
+
await new Promise((resolve, reject) => {
|
|
541
|
+
let cwd
|
|
542
|
+
let chunks = location.pathname.split("/").filter((x) => { return x })
|
|
543
|
+
if (chunks.length > 0) {
|
|
544
|
+
//cwd = chunks.slice(1).join("/")
|
|
545
|
+
cwd = "~/" + chunks.join("/")
|
|
546
|
+
} else {
|
|
547
|
+
cwd = "."
|
|
548
|
+
}
|
|
549
|
+
socket.run({
|
|
550
|
+
method: "shell.run",
|
|
551
|
+
params: {
|
|
552
|
+
message: `git pull`,
|
|
553
|
+
// path: "<%=uri%>",//cwd
|
|
554
|
+
path: cwd
|
|
555
|
+
}
|
|
556
|
+
}, (packet) => {
|
|
557
|
+
if (packet.type === 'stream') {
|
|
558
|
+
term.write(packet.data.raw)
|
|
559
|
+
} else if (packet.type === "result") {
|
|
560
|
+
resolve()
|
|
561
|
+
} else if (packet.type === "error") {
|
|
562
|
+
n.Noty({
|
|
563
|
+
text: packet.data
|
|
564
|
+
})
|
|
565
|
+
}
|
|
566
|
+
})
|
|
567
|
+
})
|
|
568
|
+
<% if (config && config.update) { %>
|
|
569
|
+
n.Noty({
|
|
570
|
+
text: "Success! An update script exists. Click to visit and run the update script!",
|
|
571
|
+
type: "success",
|
|
572
|
+
callbacks: {
|
|
573
|
+
onClose: () => {
|
|
574
|
+
location.href = "<%=config.update%>"
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
})
|
|
578
|
+
<% } else { %>
|
|
579
|
+
n.Noty({
|
|
580
|
+
text: "Success! Click to refresh.",
|
|
581
|
+
type: "success",
|
|
582
|
+
callbacks: {
|
|
583
|
+
onClose: () => {
|
|
584
|
+
location.href = location.href
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
})
|
|
588
|
+
<% } %>
|
|
589
|
+
}
|
|
590
|
+
<% if (display.includes("onboarding")) { %>
|
|
591
|
+
//document.querySelector("#llama").addEventListener("click", async (e) => {
|
|
592
|
+
// if (!term) term = createTerm()
|
|
593
|
+
// await install("llama", "https://github.com/malfunctionize/lla", term, socket)
|
|
594
|
+
//})
|
|
595
|
+
<% } %>
|
|
596
|
+
<% if (display.includes("form")) { %>
|
|
597
|
+
let list = []
|
|
598
|
+
document.querySelectorAll(".line").forEach((el, index) => {
|
|
599
|
+
list.push({
|
|
600
|
+
index: parseInt(el.getAttribute("data-index")),
|
|
601
|
+
name: el.getAttribute("data-name"),
|
|
602
|
+
description: el.getAttribute("data-description"),
|
|
603
|
+
uri: el.getAttribute("data-uri")
|
|
604
|
+
})
|
|
605
|
+
})
|
|
606
|
+
const search = (items, value) => {
|
|
607
|
+
let filtered = []
|
|
608
|
+
for(let i=0; i<items.length; i++) {
|
|
609
|
+
let item = items[i]
|
|
610
|
+
let re = new RegExp(value, "i")
|
|
611
|
+
if (re.test(item.name)) {
|
|
612
|
+
filtered.push({ item })
|
|
613
|
+
} else if (re.test(item.description)) {
|
|
614
|
+
filtered.push({ item })
|
|
615
|
+
} else if (re.test(item.uri)) {
|
|
616
|
+
filtered.push({ item })
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
return filtered
|
|
620
|
+
}
|
|
621
|
+
//const fuse = new Fuse(list, {
|
|
622
|
+
// threshold: 0.3,
|
|
623
|
+
// keys: [{
|
|
624
|
+
// name: "name",
|
|
625
|
+
// weight: 5,
|
|
626
|
+
// }, {
|
|
627
|
+
// name: "description",
|
|
628
|
+
// weight: 1,
|
|
629
|
+
// }],
|
|
630
|
+
// includeScore: true,
|
|
631
|
+
// includeMatches: true
|
|
632
|
+
//})
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
let selectedIndex = -1
|
|
636
|
+
let selectedBtnIndex = 0
|
|
637
|
+
let filteredCount = list.length
|
|
638
|
+
let filteredBtnsCount = 0
|
|
639
|
+
|
|
640
|
+
const renderSearch = () => {
|
|
641
|
+
let target = document.querySelector("form input[type=search]")
|
|
642
|
+
let result
|
|
643
|
+
if (target.value.trim().length === 0) {
|
|
644
|
+
result = list.map((i, index) => {
|
|
645
|
+
return { item: i }
|
|
646
|
+
})
|
|
647
|
+
} else {
|
|
648
|
+
result = search(list, target.value)
|
|
649
|
+
}
|
|
650
|
+
let all = document.querySelectorAll(".line")
|
|
651
|
+
for(let el of all) {
|
|
652
|
+
el.classList.add("hidden")
|
|
653
|
+
el.classList.remove("selected")
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
filteredCount = result.length
|
|
657
|
+
for(let i=0; i<result.length; i++) {
|
|
658
|
+
let selector = result[i]
|
|
659
|
+
//let el = document.querySelector(".line[data-name='" + selector.item.name + "']")
|
|
660
|
+
let el = document.querySelector(".line[data-index='" + selector.item.index + "']")
|
|
661
|
+
el.classList.remove("hidden")
|
|
662
|
+
if (i === selectedIndex) {
|
|
663
|
+
el.classList.add("selected")
|
|
664
|
+
let btns = el.querySelectorAll(".btns a")
|
|
665
|
+
filteredBtnsCount = btns.length
|
|
666
|
+
btns.forEach((_el, j) => {
|
|
667
|
+
if (selectedBtnIndex === j) {
|
|
668
|
+
_el.classList.add("selected")
|
|
669
|
+
} else {
|
|
670
|
+
_el.classList.remove("selected")
|
|
671
|
+
}
|
|
672
|
+
})
|
|
673
|
+
} else {
|
|
674
|
+
el.classList.remove("selected")
|
|
675
|
+
let btns = el.querySelectorAll(".btns a")
|
|
676
|
+
btns.forEach((_el, j) => {
|
|
677
|
+
_el.classList.remove("selected")
|
|
678
|
+
})
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
renderSearch()
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
document.querySelector("form input[type=search]").addEventListener("input", (e) => {
|
|
688
|
+
selectedIndex = 0
|
|
689
|
+
selectedBtnIndex = 0
|
|
690
|
+
renderSearch()
|
|
691
|
+
/*
|
|
692
|
+
if (e.target.value.trim().length === 0) {
|
|
693
|
+
let all = document.querySelectorAll(".line")
|
|
694
|
+
for(let el of all) {
|
|
695
|
+
el.classList.remove("hidden")
|
|
696
|
+
}
|
|
697
|
+
} else {
|
|
698
|
+
let all = document.querySelectorAll(".line")
|
|
699
|
+
for(let el of all) {
|
|
700
|
+
el.classList.add("hidden")
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
//let result = fuse.search(e.target.value)
|
|
704
|
+
let result = search(list, e.target.value)
|
|
705
|
+
// result.sort((x, y) => {
|
|
706
|
+
// return y.score - x.score
|
|
707
|
+
// })
|
|
708
|
+
let i = 0
|
|
709
|
+
//for(let selector of result) {
|
|
710
|
+
for(let i=0; i<result.length; i++) {
|
|
711
|
+
let selector = result[i]
|
|
712
|
+
let el = document.querySelector(".line[data-name='" + selector.item.name + "']")
|
|
713
|
+
el.classList.remove("hidden")
|
|
714
|
+
if (i === 0) {
|
|
715
|
+
el.classList.add("selected")
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
*/
|
|
720
|
+
})
|
|
721
|
+
document.querySelector("form input[type=search]").focus()
|
|
722
|
+
<% } %>
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
// if (el) {
|
|
726
|
+
// let url = el.getAttribute("data-url")
|
|
727
|
+
// if (url) {
|
|
728
|
+
// let target = el.getAttribute("data-target")
|
|
729
|
+
// if (target && target.length > 0) {
|
|
730
|
+
// let agent = el.getAttribute("data-agent")
|
|
731
|
+
// if (agent && agent.length > 0) {
|
|
732
|
+
// window.open(url, target, agent)
|
|
733
|
+
// } else {
|
|
734
|
+
// window.open(url, target)
|
|
735
|
+
// }
|
|
736
|
+
// } else {
|
|
737
|
+
// location.href = url
|
|
738
|
+
// }
|
|
739
|
+
// }
|
|
740
|
+
// }
|
|
741
|
+
//document.querySelector(".runner").addEventListener("click", async (e) => {
|
|
742
|
+
// let el = e.target.closest(".btn")
|
|
743
|
+
// if (!el) {
|
|
744
|
+
// if (el.classList.contains("btn")) {
|
|
745
|
+
// el = e.target
|
|
746
|
+
// }
|
|
747
|
+
// }
|
|
748
|
+
//
|
|
749
|
+
// if (el) {
|
|
750
|
+
// let url = el.getAttribute("data-url")
|
|
751
|
+
// if (url) {
|
|
752
|
+
// let target = el.getAttribute("data-target")
|
|
753
|
+
// if (target && target.length > 0) {
|
|
754
|
+
// let agent = el.getAttribute("data-agent")
|
|
755
|
+
// if (agent && agent.length > 0) {
|
|
756
|
+
// window.open(url, target, agent)
|
|
757
|
+
// } else {
|
|
758
|
+
// window.open(url, target)
|
|
759
|
+
// }
|
|
760
|
+
// } else {
|
|
761
|
+
// location.href = url
|
|
762
|
+
// }
|
|
763
|
+
// }
|
|
764
|
+
// }
|
|
765
|
+
//})
|
|
766
|
+
<% if (display.includes("install")) { %>
|
|
767
|
+
document.querySelector("#install").addEventListener("click", async (e) => {
|
|
768
|
+
location.href = e.target.getAttribute("data-url")
|
|
769
|
+
})
|
|
770
|
+
<% } %>
|
|
771
|
+
//Reporter()
|
|
772
|
+
/*
|
|
773
|
+
<% if (display.includes("dependencies")) { %>
|
|
774
|
+
document.querySelector(".requirements").addEventListener("click", (e) => {
|
|
775
|
+
e.preventDefault()
|
|
776
|
+
e.stopPropagation()
|
|
777
|
+
let el = e.target.closest(".opener")
|
|
778
|
+
if (!el) {
|
|
779
|
+
if (e.target.classList.contains("opener")) {
|
|
780
|
+
el = e.target
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
if (el) {
|
|
784
|
+
window.open(el.getAttribute("data-href"), "_blank", "app")
|
|
785
|
+
}
|
|
786
|
+
})
|
|
787
|
+
<% } %>
|
|
788
|
+
*/
|
|
789
|
+
let params = new URLSearchParams(location.search)
|
|
790
|
+
let selected = params.get("selected")
|
|
791
|
+
if (selected) {
|
|
792
|
+
document.querySelector("form input[type=search]").value = selected
|
|
793
|
+
document.querySelector("form input[type=search]").dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));
|
|
794
|
+
}
|
|
795
|
+
if (document.querySelector("form input[type=search]")) {
|
|
796
|
+
document.querySelector("form input[type=search]").addEventListener("input", (e) => {
|
|
797
|
+
let p
|
|
798
|
+
if (e.target.value && e.target.value.trim().length > 0) {
|
|
799
|
+
p = location.pathname + "?selected=" + e.target.value
|
|
800
|
+
} else {
|
|
801
|
+
p = location.pathname
|
|
802
|
+
}
|
|
803
|
+
window.history.pushState({ path: p }, '', p);
|
|
804
|
+
})
|
|
805
|
+
}
|
|
806
|
+
<% if (ishome) { %>
|
|
807
|
+
// if launch_complete is true => already finished launching so no need to refresh
|
|
808
|
+
// if launch_complete is false => not finished launching. wait until it's complete, and then refresh
|
|
809
|
+
// autolaunch display update
|
|
810
|
+
<% if (!launch_complete) { %>
|
|
811
|
+
let interval = setInterval(async () => {
|
|
812
|
+
let res = await fetch("/pinokio/info").then((res) => {
|
|
813
|
+
return res.json()
|
|
814
|
+
})
|
|
815
|
+
if (res.launch_complete) {
|
|
816
|
+
console.log("launched")
|
|
817
|
+
clearInterval(interval)
|
|
818
|
+
location.href = location.href
|
|
819
|
+
} else {
|
|
820
|
+
console.log("not yet launched")
|
|
821
|
+
}
|
|
822
|
+
}, 1000)
|
|
823
|
+
<% } %>
|
|
824
|
+
document.addEventListener("keydown", (e) => {
|
|
825
|
+
e = e || window.event;
|
|
826
|
+
if (e.key === "ArrowUp") {
|
|
827
|
+
console.log("up arrow pressed");
|
|
828
|
+
selectedIndex = Math.max(selectedIndex-1, 0)
|
|
829
|
+
selectedBtnIndex = 0
|
|
830
|
+
renderSearch()
|
|
831
|
+
let selected = document.querySelector(".line.selected")
|
|
832
|
+
selected.scrollIntoView(false)
|
|
833
|
+
//
|
|
834
|
+
} else if (e.key === "ArrowDown") {
|
|
835
|
+
console.log("before selectedIndex", selectedIndex)
|
|
836
|
+
selectedIndex = Math.min(filteredCount-1, selectedIndex+1)
|
|
837
|
+
selectedBtnIndex = 0
|
|
838
|
+
console.log("after selectedIndex", selectedIndex)
|
|
839
|
+
renderSearch()
|
|
840
|
+
console.log("down arrow pressed");
|
|
841
|
+
let selected = document.querySelector(".line.selected")
|
|
842
|
+
selected.scrollIntoView(false)
|
|
843
|
+
} else if (e.key === "ArrowLeft") {
|
|
844
|
+
selectedBtnIndex = Math.max(selectedBtnIndex-1, 0)
|
|
845
|
+
console.log("left arrow pressed");
|
|
846
|
+
console.log("selectedBtnIndex", selectedBtnIndex)
|
|
847
|
+
renderSearch()
|
|
848
|
+
} else if (e.key === "ArrowRight") {
|
|
849
|
+
console.log("right arrow pressed");
|
|
850
|
+
selectedBtnIndex = Math.min(filteredBtnsCount-1, selectedBtnIndex+1)
|
|
851
|
+
console.log("selectedBtnIndex", selectedBtnIndex)
|
|
852
|
+
renderSearch()
|
|
853
|
+
} else if (e.key === "Enter") {
|
|
854
|
+
//let selected = document.querySelector(".line.selected:not(.hidden) .btns a.selected")
|
|
855
|
+
//let selected = document.querySelector(".line.selected:not(.hidden) .title a")
|
|
856
|
+
let selected = document.querySelector(".line.selected:not(.hidden)")
|
|
857
|
+
console.log("selected", selected)
|
|
858
|
+
if (selected) {
|
|
859
|
+
e.preventDefault()
|
|
860
|
+
e.stopPropagation()
|
|
861
|
+
selected.click()
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
});
|
|
865
|
+
document.addEventListener("click", async (e) => {
|
|
866
|
+
if (e.target.classList.contains("shutdown")) {
|
|
867
|
+
target = e.target
|
|
868
|
+
} else {
|
|
869
|
+
target = e.target.closest(".shutdown")
|
|
870
|
+
}
|
|
871
|
+
if (target) {
|
|
872
|
+
e.preventDefault()
|
|
873
|
+
e.stopPropagation()
|
|
874
|
+
let src = target.getAttribute("data-src")
|
|
875
|
+
console.log("src", src)
|
|
876
|
+
|
|
877
|
+
socket.run({
|
|
878
|
+
method: "kernel.api.stop",
|
|
879
|
+
params: {
|
|
880
|
+
uri: "~/" + src
|
|
881
|
+
}
|
|
882
|
+
}, (packet) => {
|
|
883
|
+
console.log("packet", packet)
|
|
884
|
+
if (packet.type === "result") {
|
|
885
|
+
socket.close()
|
|
886
|
+
target.querySelector("i.fa-stop").className = "fa-solid fa-check"
|
|
887
|
+
target.querySelector("i.fa-spin").classList.add("hidden")
|
|
888
|
+
n.Noty({
|
|
889
|
+
text: `stopped ${src}`,
|
|
890
|
+
silent: true
|
|
891
|
+
})
|
|
892
|
+
setTimeout(() => {
|
|
893
|
+
location.href = location.href
|
|
894
|
+
}, 500)
|
|
895
|
+
}
|
|
896
|
+
})
|
|
897
|
+
|
|
898
|
+
return
|
|
899
|
+
}
|
|
900
|
+
if (e.target.classList.contains("open-menu")) {
|
|
901
|
+
target = e.target
|
|
902
|
+
} else {
|
|
903
|
+
target = e.target.closest(".open-menu")
|
|
904
|
+
}
|
|
905
|
+
if (target) {
|
|
906
|
+
e.preventDefault()
|
|
907
|
+
e.stopPropagation()
|
|
908
|
+
let contextMenu = target.closest(".col").querySelector(".context-menu").classList.toggle("collapsed")
|
|
909
|
+
target.classList.toggle("selected")
|
|
910
|
+
return
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
if (e.target.classList.contains("move-menu")) {
|
|
914
|
+
target = e.target
|
|
915
|
+
} else {
|
|
916
|
+
target = e.target.closest(".move-menu")
|
|
917
|
+
}
|
|
918
|
+
if (target) {
|
|
919
|
+
e.preventDefault()
|
|
920
|
+
e.stopPropagation()
|
|
921
|
+
let line = target.closest(".line")
|
|
922
|
+
let title = line.getAttribute("data-title")
|
|
923
|
+
let icon = line.getAttribute("data-icon")
|
|
924
|
+
let iconpath = line.getAttribute("data-iconpath")
|
|
925
|
+
let path = line.getAttribute("data-path")
|
|
926
|
+
let description = line.getAttribute("data-description")
|
|
927
|
+
await FSEditor({
|
|
928
|
+
title,
|
|
929
|
+
description,
|
|
930
|
+
old_path: path,
|
|
931
|
+
icon,
|
|
932
|
+
iconpath,
|
|
933
|
+
move: true,
|
|
934
|
+
edit: true,
|
|
935
|
+
redirect: (new_path) => {
|
|
936
|
+
return location.href
|
|
937
|
+
}
|
|
938
|
+
})
|
|
939
|
+
return
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
if (e.target.classList.contains("copy-menu")) {
|
|
943
|
+
target = e.target
|
|
944
|
+
} else {
|
|
945
|
+
target = e.target.closest(".copy-menu")
|
|
946
|
+
}
|
|
947
|
+
if (target) {
|
|
948
|
+
e.preventDefault()
|
|
949
|
+
e.stopPropagation()
|
|
950
|
+
let line = target.closest(".line")
|
|
951
|
+
let title = line.getAttribute("data-title")
|
|
952
|
+
let icon = line.getAttribute("data-icon")
|
|
953
|
+
let iconpath = line.getAttribute("data-iconpath")
|
|
954
|
+
let path = line.getAttribute("data-path")
|
|
955
|
+
let description = line.getAttribute("data-description")
|
|
956
|
+
await FSEditor({
|
|
957
|
+
title,
|
|
958
|
+
description,
|
|
959
|
+
old_path: path,
|
|
960
|
+
icon,
|
|
961
|
+
iconpath,
|
|
962
|
+
copy: true,
|
|
963
|
+
edit: true,
|
|
964
|
+
redirect: (new_path) => {
|
|
965
|
+
return location.href
|
|
966
|
+
}
|
|
967
|
+
})
|
|
968
|
+
return
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
if (e.target.classList.contains("edit-menu")) {
|
|
972
|
+
target = e.target
|
|
973
|
+
} else {
|
|
974
|
+
target = e.target.closest(".edit-menu")
|
|
975
|
+
}
|
|
976
|
+
if (target) {
|
|
977
|
+
e.preventDefault()
|
|
978
|
+
e.stopPropagation()
|
|
979
|
+
let line = target.closest(".line")
|
|
980
|
+
let title = line.getAttribute("data-title")
|
|
981
|
+
let icon = line.getAttribute("data-icon")
|
|
982
|
+
let iconpath = line.getAttribute("data-iconpath")
|
|
983
|
+
let path = line.getAttribute("data-path")
|
|
984
|
+
let description = line.getAttribute("data-description")
|
|
985
|
+
await FSEditor({
|
|
986
|
+
title,
|
|
987
|
+
description,
|
|
988
|
+
old_path: path,
|
|
989
|
+
icon,
|
|
990
|
+
iconpath,
|
|
991
|
+
edit: true,
|
|
992
|
+
redirect: (new_path) => {
|
|
993
|
+
return location.href
|
|
994
|
+
}
|
|
995
|
+
})
|
|
996
|
+
return
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
if (e.target.classList.contains("browse")) {
|
|
1003
|
+
target = e.target
|
|
1004
|
+
} else {
|
|
1005
|
+
target = e.target.closest(".browse")
|
|
1006
|
+
}
|
|
1007
|
+
if (target) {
|
|
1008
|
+
e.preventDefault()
|
|
1009
|
+
e.stopPropagation()
|
|
1010
|
+
let src = target.getAttribute("data-src")
|
|
1011
|
+
location.href = src
|
|
1012
|
+
return
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
|
|
1016
|
+
// delete
|
|
1017
|
+
if (e.target.classList.contains("del")) {
|
|
1018
|
+
target = e.target
|
|
1019
|
+
} else {
|
|
1020
|
+
target = e.target.closest(".del")
|
|
1021
|
+
}
|
|
1022
|
+
if (target) {
|
|
1023
|
+
e.preventDefault()
|
|
1024
|
+
e.stopPropagation()
|
|
1025
|
+
let confirmed = confirm("Are you sure you want to delete the folder? All files in the folder will be gone.")
|
|
1026
|
+
if (confirmed) {
|
|
1027
|
+
let itemEl = target.closest(".line[data-uri]")
|
|
1028
|
+
let name = itemEl.getAttribute("data-uri")
|
|
1029
|
+
console.log("delete", name)
|
|
1030
|
+
Swal.fire({
|
|
1031
|
+
html: '<i class="fa-solid fa-circle-notch fa-spin"></i> Deleting',
|
|
1032
|
+
customClass: {
|
|
1033
|
+
container: "loader-container",
|
|
1034
|
+
popup: "loader-popup",
|
|
1035
|
+
htmlContainer: "loader-dialog",
|
|
1036
|
+
footer: "hidden",
|
|
1037
|
+
actions: "hidden"
|
|
1038
|
+
}
|
|
1039
|
+
});
|
|
1040
|
+
let res = await fetch("/pinokio/delete", {
|
|
1041
|
+
method: "post",
|
|
1042
|
+
headers: {
|
|
1043
|
+
"Content-Type": "application/json"
|
|
1044
|
+
},
|
|
1045
|
+
body: JSON.stringify({ name })
|
|
1046
|
+
}).then((res) => {
|
|
1047
|
+
return res.json()
|
|
1048
|
+
})
|
|
1049
|
+
console.log("res", res)
|
|
1050
|
+
Swal.close()
|
|
1051
|
+
if (res) {
|
|
1052
|
+
if (res.success) {
|
|
1053
|
+
location.href = "/"
|
|
1054
|
+
} else if (res.error) {
|
|
1055
|
+
alert(res.error)
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
} else {
|
|
1059
|
+
}
|
|
1060
|
+
return
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
|
|
1064
|
+
|
|
1065
|
+
if (document.querySelector(".container")) {
|
|
1066
|
+
document.querySelector(".container").addEventListener("click", async (e) => {
|
|
1067
|
+
//let el = e.target.closest(".menu-btn")
|
|
1068
|
+
//if (!el) {
|
|
1069
|
+
// if (el.classList.contains("menu-btn")) {
|
|
1070
|
+
// el = e.target
|
|
1071
|
+
// }
|
|
1072
|
+
//}
|
|
1073
|
+
|
|
1074
|
+
let el
|
|
1075
|
+
if (e.target.classList.contains("menu-btn")) {
|
|
1076
|
+
el = e.target
|
|
1077
|
+
} else {
|
|
1078
|
+
if (e.target.closest(".menu-btn")) {
|
|
1079
|
+
el = e.target
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
console.log("EL", el)
|
|
1084
|
+
|
|
1085
|
+
if (el) {
|
|
1086
|
+
e.preventDefault()
|
|
1087
|
+
e.stopPropagation()
|
|
1088
|
+
let actionStr = el.getAttribute("data-action")
|
|
1089
|
+
if (actionStr) {
|
|
1090
|
+
let action = JSON.parse(actionStr)
|
|
1091
|
+
console.log("action", action)
|
|
1092
|
+
if (action.method === "stop" && action.uri) {
|
|
1093
|
+
socket.run({
|
|
1094
|
+
method: "kernel.api.stop",
|
|
1095
|
+
params: {
|
|
1096
|
+
uri: action.uri//"~" + location.pathname
|
|
1097
|
+
}
|
|
1098
|
+
}, (packet) => {
|
|
1099
|
+
console.log("packet", packet)
|
|
1100
|
+
if (packet.type === "result") {
|
|
1101
|
+
socket.close()
|
|
1102
|
+
location.href = location.href
|
|
1103
|
+
}
|
|
1104
|
+
})
|
|
1105
|
+
return
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
}
|
|
1110
|
+
})
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
/*
|
|
1117
|
+
target = (e.target.classList.contains(".btn") ? e.target : e.target.closest(".btn"))
|
|
1118
|
+
if (target) {
|
|
1119
|
+
target.classList.add("clicked")
|
|
1120
|
+
document.querySelectorAll(".line .btns .btn").forEach((e) => {
|
|
1121
|
+
e.classList.remove("selected")
|
|
1122
|
+
})
|
|
1123
|
+
target.classList.add("selected")
|
|
1124
|
+
target.closest(".line").classList.add("selected")
|
|
1125
|
+
return
|
|
1126
|
+
}
|
|
1127
|
+
*/
|
|
1128
|
+
|
|
1129
|
+
|
|
1130
|
+
})
|
|
1131
|
+
<% if (proxy) { %>
|
|
1132
|
+
if (document.querySelector("#wifi-qr")) {
|
|
1133
|
+
document.querySelector("#wifi-qr").addEventListener("click", async (e) => {
|
|
1134
|
+
await Swal.fire({
|
|
1135
|
+
title: "Local Share",
|
|
1136
|
+
customClass: {
|
|
1137
|
+
popup: "min-popup",
|
|
1138
|
+
title: "min-title"
|
|
1139
|
+
},
|
|
1140
|
+
showConfirmButton: false,
|
|
1141
|
+
html: `<div class='min-modal'>
|
|
1142
|
+
<div>Access Pinokio from</div>
|
|
1143
|
+
<div>any local network device</div>
|
|
1144
|
+
<div><img src="<%=qr%>"></div>
|
|
1145
|
+
<a href="<%=proxy.proxy%>" target="_blank"><%=proxy.proxy%></a>
|
|
1146
|
+
</div>`
|
|
1147
|
+
})
|
|
1148
|
+
})
|
|
1149
|
+
}
|
|
1150
|
+
if (document.querySelector("#wifi-stop")) {
|
|
1151
|
+
document.querySelector("#wifi-stop").addEventListener("click", async (e) => {
|
|
1152
|
+
let res = await fetch("/unpublish", {
|
|
1153
|
+
method: "post",
|
|
1154
|
+
headers: {
|
|
1155
|
+
"Content-Type": "application/json"
|
|
1156
|
+
},
|
|
1157
|
+
body: JSON.stringify({
|
|
1158
|
+
type: "local"
|
|
1159
|
+
})
|
|
1160
|
+
}).then((res) => {
|
|
1161
|
+
return res.json()
|
|
1162
|
+
})
|
|
1163
|
+
console.log(res)
|
|
1164
|
+
location.href = location.href
|
|
1165
|
+
})
|
|
1166
|
+
}
|
|
1167
|
+
<% } %>
|
|
1168
|
+
<% if (cloudflare_pub) { %>
|
|
1169
|
+
if (document.querySelector("#cloudflare-qr")) {
|
|
1170
|
+
document.querySelector("#cloudflare-qr").addEventListener("click", async (e) => {
|
|
1171
|
+
await Swal.fire({
|
|
1172
|
+
title: "Public Share",
|
|
1173
|
+
customClass: {
|
|
1174
|
+
popup: "min-popup",
|
|
1175
|
+
title: "min-title"
|
|
1176
|
+
},
|
|
1177
|
+
showConfirmButton: false,
|
|
1178
|
+
html: `<div class='min-modal'>
|
|
1179
|
+
<div>Access Pinokio from anywhere</div>
|
|
1180
|
+
<div>(powered by cloudflare tunnel)</div>
|
|
1181
|
+
<div><img src="<%=qr_cloudflare%>"></div>
|
|
1182
|
+
<a href="<%=cloudflare_pub%>" target="_blank"><%=cloudflare_pub%></a>
|
|
1183
|
+
</div>`
|
|
1184
|
+
})
|
|
1185
|
+
})
|
|
1186
|
+
}
|
|
1187
|
+
if (document.querySelector("#cloudflare-stop")) {
|
|
1188
|
+
document.querySelector("#cloudflare-stop").addEventListener("click", async (e) => {
|
|
1189
|
+
let res = await fetch("/unpublish", {
|
|
1190
|
+
method: "post",
|
|
1191
|
+
headers: {
|
|
1192
|
+
"Content-Type": "application/json"
|
|
1193
|
+
},
|
|
1194
|
+
body: JSON.stringify({
|
|
1195
|
+
type: "cloudflare"
|
|
1196
|
+
})
|
|
1197
|
+
}).then((res) => {
|
|
1198
|
+
return res.json()
|
|
1199
|
+
})
|
|
1200
|
+
console.log(res)
|
|
1201
|
+
location.href = location.href
|
|
1202
|
+
})
|
|
1203
|
+
}
|
|
1204
|
+
<% } %>
|
|
1205
|
+
if (document.querySelector("#wifi")) {
|
|
1206
|
+
document.querySelector("#wifi").addEventListener("click", async (e) => {
|
|
1207
|
+
document.querySelector("#wifi").classList.add("hidden")
|
|
1208
|
+
document.querySelector("#wifi-starting").classList.remove("hidden")
|
|
1209
|
+
let res = await fetch("/publish", {
|
|
1210
|
+
method: "post",
|
|
1211
|
+
headers: {
|
|
1212
|
+
"Content-Type": "application/json"
|
|
1213
|
+
},
|
|
1214
|
+
body: JSON.stringify({
|
|
1215
|
+
type: "local"
|
|
1216
|
+
})
|
|
1217
|
+
}).then((res) => {
|
|
1218
|
+
return res.json()
|
|
1219
|
+
})
|
|
1220
|
+
console.log(res)
|
|
1221
|
+
location.href = location.href
|
|
1222
|
+
})
|
|
1223
|
+
}
|
|
1224
|
+
if (document.querySelector("#cloudflare")) {
|
|
1225
|
+
document.querySelector("#cloudflare").addEventListener("click", async (e) => {
|
|
1226
|
+
document.querySelector("#cloudflare").classList.add("hidden")
|
|
1227
|
+
document.querySelector("#cloudflare-starting").classList.remove("hidden")
|
|
1228
|
+
let res = await fetch("/publish", {
|
|
1229
|
+
method: "post",
|
|
1230
|
+
headers: {
|
|
1231
|
+
"Content-Type": "application/json"
|
|
1232
|
+
},
|
|
1233
|
+
body: JSON.stringify({
|
|
1234
|
+
type: "cloudflare"
|
|
1235
|
+
})
|
|
1236
|
+
}).then((res) => {
|
|
1237
|
+
return res.json()
|
|
1238
|
+
})
|
|
1239
|
+
console.log(res)
|
|
1240
|
+
location.href = location.href
|
|
1241
|
+
})
|
|
1242
|
+
}
|
|
1243
|
+
<% } %>
|
|
1244
|
+
|
|
1245
|
+
</script>
|
|
1246
|
+
</body>
|
|
1247
|
+
</html>
|