##// END OF EJS Templates
Update markup a bit
naryl -
r68:b533adc9 default
parent child Browse files
Show More
@@ -1,523 +1,522 b''
1 1
2 2 (in-package txt2web.api)
3 3
4 4 ;;; API deals with DOM manipulation and some bookkeeping for the
5 5 ;;; intrinsics, namely variables
6 6 ;;; API is an implementation detail and has no QSP documentation. It
7 7 ;;; doesn't call intrinsics
8 8
9 9 ;;; Utils
10 10
11 11 (defun make-act-html (title img)
12 12 (+ "<a class='qsp-act' href='" (href-call call-act title) "' onmouseover='" (inline-call select-act title) "'>"
13 13 (if img (+ "<img src='" img "'>") "")
14 14 title
15 15 "</a>"))
16 16
17 17 (defun make-menu-item-html (num title img loc)
18 18 (+ "<a href='" (href-call finish-menu loc) "'>"
19 19 (if img (+ "<img src='" img "'>") "")
20 20 title
21 21 "</a>"))
22 22
23 23 (defun make-obj (title img selected)
24 (+ "<li onclick='" (inline-call select-obj title img) "'>"
25 "<a class='qsp-obj" (if selected " qsp-obj-selected" "") "'>"
24 (+ "<li onclick='" (inline-call select-obj title img)
25 "' class='qsp-obj" (if selected " selected" "") "'>"
26 26 (if img (+ "<img src='" img "'>") "")
27 27 title
28 "</a>"))
28 "</li>"))
29 29
30 30 (defun make-menu-delimiter ()
31 31 "<hr>")
32 32
33 33 (defun copy-obj (obj)
34 34 (chain *j-s-o-n (parse (chain *j-s-o-n (stringify obj)))))
35 35
36 36 (defun report-error (text)
37 37 (alert text))
38 38
39 39 (defun start-sleeping ()
40 40 (chain (by-id "qsp") class-list (add "disable")))
41 41
42 42 (defun finish-sleeping ()
43 43 (chain (by-id "qsp") class-list (remove "disable")))
44 44
45 45 (defun sleep (msec)
46 46 (with-sleep (resume)
47 47 (set-timeout resume msec)))
48 48
49 49 (defun init-dom ()
50 50 ;; Save/load buttons
51 51 (let ((btn (by-id "qsp-btn-save")))
52 52 (setf (@ btn onclick) savegame)
53 53 (setf (@ btn href) "#"))
54 54 (let ((btn (by-id "qsp-btn-open")))
55 55 (setf (@ btn onclick) opengame)
56 56 (setf (@ btn href) "#"))
57 57 ;; Close image on click
58 58 (setf (@ (by-id "qsp-image-container") onclick)
59 59 show-image)
60 60 ;; Enter in input field
61 61 (setf (@ (get-frame :input) onkeyup)
62 62 on-input-key)
63 63 ;; Close the dropdown on any click
64 64 (setf (@ window onclick)
65 65 (lambda (event)
66 66 (setf (@ window mouse)
67 67 (list (@ event page-x)
68 68 (@ event page-y)))
69 69 (finish-menu nil))))
70 70
71 71 (defun init-globals (game-name)
72 72 (chain *object (assign *globals (getprop *default-globals game-name))))
73 73
74 74 (defun call-serv-loc (var-name &rest args)
75 75 (let ((loc-name (get-global var-name 0)))
76 76 (when loc-name
77 77 (let ((loc (getprop *locs (chain loc-name (to-upper-case)))))
78 78 (when loc
79 79 (call-loc loc-name args))))))
80 80
81 81 (defun filename-game (filename)
82 82 (let ((game-name (chain filename (match "(.*/)?([^.]+)(\\.[a-zA-Z]+)?") 2))))
83 83 (getprop *games game-name))
84 84
85 85 (defun run-game (name)
86 86 (let ((game (filename-game name)))
87 87 (setf *main-game name)
88 88 ;; Replace locations with the new game's
89 89 (setf *locs game)
90 90 (funcall (getprop game
91 91 (chain *object (keys game) 0))
92 92 (list))))
93 93
94 94 ;;; Misc
95 95
96 96 (defun newline (key)
97 97 (append-id (key-to-id key) "<br>" t))
98 98
99 99 (defun clear-id (id)
100 100 (setf (inner-html (by-id id)) ""))
101 101
102 102 (defun escape-html (text)
103 103 (chain text
104 104 (replace (regex "/&/g") "&amp;")
105 105 (replace (regex "/</g") "&lt;")
106 106 (replace (regex "/>/g") "&gt;")
107 107 (replace (regex "/\"/g") "&quot;")
108 108 (replace (regex "/'/g") "&apos;")))
109 109
110 110 (defun prepare-contents (s &optional force-html)
111 111 (setf s (chain s (to-string)))
112 112 (if (or force-html (get-global "USEHTML" 0))
113 113 s
114 114 (escape-html s)))
115 115
116 116 (defun get-id (id &optional force-html)
117 117 (inner-html (by-id id)))
118 118
119 119 (defun set-id (id contents &optional force-html)
120 120 (setf (inner-html (by-id id)) (prepare-contents contents force-html)))
121 121
122 122 (defun append-id (id contents &optional force-html)
123 123 (when contents
124 124 (incf (inner-html (by-id id)) (prepare-contents contents force-html))))
125 125
126 126 (defun on-input-key (ev)
127 127 (when (= 13 (@ ev key-code))
128 128 (chain ev (prevent-default))
129 129 (call-serv-loc "$USERCOM")))
130 130
131 131 ;;; Function calls
132 132
133 133 (defun init-args (args)
134 134 (dotimes (i 10)
135 135 (set-global "ARGS" i 0)
136 136 (set-global "$ARGS" i "")
137 137 (when (and args (< i (length args)))
138 138 (let ((arg (elt args i)))
139 139 (if (numberp arg)
140 140 (set-global "ARGS" i arg)
141 141 (set-global "$ARGS" i arg))))))
142 142
143 143 (defun get-result ()
144 144 (or (get-global "$RESULT" 0)
145 145 (get-global "RESULT" 0)))
146 146
147 147 (defun call-loc (name args)
148 148 (setf name (chain name (to-upper-case)))
149 149 (with-frame
150 150 (with-call-args args t
151 151 (funcall (getprop *locs name)))))
152 152
153 153 (defun call-act (title)
154 154 (with-frame
155 155 (funcall (getprop *acts title :act)))
156 156 (void))
157 157
158 158 ;;; Text windows
159 159
160 160 (defun key-to-id (key)
161 161 (case key
162 162 (:all "qsp")
163 163 (:main "qsp-main")
164 164 (:stat "qsp-stat")
165 165 (:objs "qsp-objs")
166 166 (:acts "qsp-acts")
167 167 (:input "qsp-input")
168 168 (:image "qsp-image")
169 169 (:dropdown "qsp-dropdown")
170 170 (t (report-error "Internal error!"))))
171 171
172 172 (defun get-frame (key)
173 173 (by-id (key-to-id key)))
174 174
175 175 (defun add-text (key text)
176 176 (append-id (key-to-id key) text))
177 177
178 178 (defun get-text (key)
179 179 (get-id (key-to-id key)))
180 180
181 181 (defun clear-text (key)
182 182 (clear-id (key-to-id key)))
183 183
184 184 (defun enable-frame (key enable)
185 185 (let ((obj (get-frame key)))
186 186 (setf (@ obj style display) (if enable "block" "none"))
187 187 (void)))
188 188
189 189 ;;; Actions
190 190
191 191 (defun add-act (title img act)
192 192 (setf (getprop *acts title)
193 193 (create :title title :img img :act act :selected nil))
194 194 (update-acts))
195 195
196 196 (defun del-act (title)
197 197 (delete (getprop *acts title))
198 198 (update-acts))
199 199
200 200 (defun clear-act ()
201 201 (setf *acts (create))
202 202 (update-acts))
203 203
204 204 (defun update-acts ()
205 205 (clear-id "qsp-acts")
206 206 (let ((elt (by-id "qsp-acts")))
207 207 (for-in (title *acts)
208 208 (let ((obj (getprop *acts title)))
209 209 (incf (inner-html elt) (make-act-html title (getprop obj :img)))))))
210 210
211 211 (defun select-act (title)
212 212 (loop :for (k v) :of *acts
213 213 :do (setf (getprop v :selected) nil))
214 214 (setf (getprop *acts title :selected) t)
215 215 (call-serv-loc "$ONACTSEL"))
216 216
217 217 ;;; Variables
218 218
219 219 (defun new-var (slot &rest indexes)
220 220 (let ((v (list)))
221 221 (dolist (index indexes)
222 222 (setf (elt v index) (if (eq #\$ (elt slot 0)) "" 0)))
223 223 (setf (@ v :indexes) (create))
224 224 v))
225 225
226 226 (defun set-str-element (slot index value)
227 227 (if (has index (getprop slot :indexes))
228 228 (setf (elt slot (getprop slot :indexes index))
229 229 value)
230 230 (progn
231 231 (chain slot (push value))
232 232 (setf (getprop slot :indexes index)
233 233 (1- (length slot)))))
234 234 (void))
235 235
236 236 (defun set-any-element (slot index value)
237 237 (cond ((null index)
238 238 (chain (elt slot) (push value)))
239 239 ((numberp index)
240 240 (setf (elt slot index) value))
241 241 ((stringp index)
242 242 (set-str-element slot index value))
243 243 (t (report-error "INTERNAL ERROR")))
244 244 (void))
245 245
246 246 (defun set-serv-var (name index value)
247 247 (let ((slot (getprop *globals name)))
248 248 (set-any-element slot index value))
249 249 (funcall (getprop serv-vars name :body) value index)
250 250 (void))
251 251
252 252 (defun get-element (slot index)
253 253 (if (numberp index)
254 254 (elt slot index)
255 255 (elt slot (getprop slot :indexes index))))
256 256
257 257 (defun set-global (name index value)
258 258 (set-any-element (getprop *globals name) index value))
259 259
260 260 (defun get-global (name index)
261 261 (get-element (getprop *globals name) index))
262 262
263 263 (defun kill-var (&optional name index)
264 264 (cond (name
265 265 (setf name (chain name (to-upper-case)))
266 266 (cond ((and index (not (= 0 index)))
267 267 (chain (getprop *globals name) (kill index)))
268 268 (t
269 269 (setf (getprop *globals name) (list))
270 270 (setf (getprop *globals name "indexes") (create)))))
271 271 (t
272 272 (setf *globals (create))
273 273 (init-globals *main-game)))
274 274 (void))
275 275
276 276 (defun array-size (name)
277 277 (@ (var-ref name) :values length))
278 278
279 279 ;;; Locals
280 280
281 281 (defun push-local-frame ()
282 282 (chain *locals (push (create)))
283 283 (void))
284 284
285 285 (defun pop-local-frame ()
286 286 (chain *locals (pop))
287 287 (void))
288 288
289 289 (defun current-local-frame ()
290 290 (elt *locals (1- (length *locals))))
291 291
292 292 ;;; Objects
293 293
294 294 (defun select-obj (title img)
295 295 (loop :for (k v) :of *objs
296 296 :do (setf (getprop v :selected) nil))
297 297 (setf (getprop *objs title :selected) t)
298 298 (call-serv-loc "$ONOBJSEL" title img))
299 299
300 300 (defun update-objs ()
301 (clear-id "qsp-objs")
301 302 (let ((elt (by-id "qsp-objs")))
302 (setf (inner-html elt) "<ul>")
303 303 (loop :for (name obj) :of *objs
304 304 :do (incf (inner-html elt)
305 (make-obj name (@ obj :img) (@ obj :selected))))
306 (incf (inner-html elt) "</ul>")))
305 (make-obj name (@ obj :img) (@ obj :selected))))))
307 306
308 307 ;;; Menu
309 308
310 309 (defun open-menu (menu-data)
311 310 (let ((elt (get-frame :dropdown))
312 311 (i 0))
313 312 (loop :for item :in menu-data
314 313 :do (incf i)
315 314 :do (incf (inner-html elt)
316 315 (if (eq item :delimiter)
317 316 (make-menu-delimiter i)
318 317 (make-menu-item-html i
319 318 (@ item :text)
320 319 (@ item :icon)
321 320 (@ item :loc)))))
322 321 (let ((mouse (@ window mouse)))
323 322 (setf (@ elt style left) (+ (elt mouse 0) "px"))
324 323 (setf (@ elt style top) (+ (elt mouse 1) "px"))
325 324 ;; Make sure it's inside the viewport
326 325 (when (> (@ document body inner-width)
327 326 (+ (elt mouse 0) (@ elt inner-width)))
328 327 (incf (@ elt style left) (@ elt inner-width)))
329 328 (when (> (@ document body inner-height)
330 329 (+ (elt mouse 0) (@ elt inner-height)))
331 330 (incf (@ elt style top) (@ elt inner-height))))
332 331 (setf (@ elt style display) "block")))
333 332
334 333 (defun finish-menu (loc)
335 334 (when *menu-resume
336 335 (let ((elt (get-frame :dropdown)))
337 336 (setf (inner-html elt) "")
338 337 (setf (@ elt style display) "none")
339 338 (funcall *menu-resume)
340 339 (setf *menu-resume nil))
341 340 (when loc
342 341 (call-loc loc)))
343 342 (void))
344 343
345 344 (defun menu (menu-data)
346 345 (with-sleep (resume)
347 346 (open-menu menu-data)
348 347 (setf *menu-resume resume))
349 348 (void))
350 349
351 350 ;;; Content
352 351
353 352 (defun clean-audio ()
354 353 (loop :for k :in (chain *object (keys *playing))
355 354 :for v := (getprop *playing k)
356 355 :do (when (@ v ended)
357 356 (delete (@ *playing k)))))
358 357
359 358 (defun show-image (path)
360 359 (let ((img (get-frame :image)))
361 360 (cond (path
362 361 (setf (@ img src) path)
363 362 (setf (@ img style display) "flex"))
364 363 (t
365 364 (setf (@ img src) "")
366 365 (setf (@ img style display) "hidden")))))
367 366
368 367 (defun rgb-string (rgb)
369 368 (let ((red (ps::>> rgb 16))
370 369 (green (logand (ps::>> rgb 8) 255))
371 370 (blue (logand rgb 255)))
372 371 (flet ((rgb-to-hex (comp)
373 372 (let ((hex (chain (*number comp) (to-string 16))))
374 373 (if (< (length hex) 2)
375 374 (+ "0" hex)
376 375 hex))))
377 376 (+ "#" (rgb-to-hex red) (rgb-to-hex green) (rgb-to-hex blue)))))
378 377
379 378 (defun store-obj (key obj)
380 379 (store-str key (btoa (encode-u-r-i-component (chain *j-s-o-n (stringify obj)))))
381 380 (void))
382 381 (defun store-str (key str)
383 382 (chain local-storage (set-item (+ "qsp_" key) str))
384 383 (void))
385 384
386 385 (defun load-obj (key)
387 386 (chain *j-s-o-n (parse (encode-u-r-i-component (atob (load-str key))))))
388 387 (defun load-str (key)
389 388 (chain local-storage (get-item (+ "qsp_" key))))
390 389
391 390 ;;; Saves
392 391
393 392 (defun slot-savegame (slot comment)
394 393 (let ((saves (load-obj "saves")))
395 394 (setf (@ saves slot) comment)
396 395 (store-obj saves))
397 396 (store-str slot (state-to-base64))
398 397 (void))
399 398
400 399 (defun slot-loadgame (slot)
401 400 (base64-to-state (load-str slot))
402 401 (void))
403 402
404 403 (defun slot-deletegame (slot)
405 404 (let ((saves (load-obj "saves")))
406 405 (setf (@ saves slot) undefined)
407 406 (store-obj saves))
408 407 (store-str slot undefined)
409 408 (void))
410 409
411 410 (defun slot-listgames ()
412 411 (load-obj "saves"))
413 412
414 413 (defun opengame ()
415 414 (let ((element (chain document (create-element :input))))
416 415 (chain element (set-attribute :type :file))
417 416 (chain element (set-attribute :id :qsp-opengame))
418 417 (chain element (set-attribute :tabindex -1))
419 418 (chain element (set-attribute "aria-hidden" t))
420 419 (setf (@ element style display) :block)
421 420 (setf (@ element style visibility) :hidden)
422 421 (setf (@ element style position) :fixed)
423 422 (setf (@ element onchange)
424 423 (lambda (event)
425 424 (let* ((file (@ event target files 0))
426 425 (reader (new (*file-reader))))
427 426 (setf (@ reader onload)
428 427 (lambda (ev)
429 428 (block nil
430 429 (let ((target (@ ev current-target)))
431 430 (unless (@ target result)
432 431 (return))
433 432 (base64-to-state (@ target result))
434 433 (unstash-state)))))
435 434 (chain reader (read-as-text file)))))
436 435 (chain document body (append-child element))
437 436 (chain element (click))
438 437 (chain document body (remove-child element))))
439 438
440 439 (defun savegame ()
441 440 (let ((element (chain document (create-element :a))))
442 441 (chain element (set-attribute :href (+ "data:text/plain;charset=utf-8," (state-to-base64))))
443 442 (chain element (set-attribute :download "savegame.sav"))
444 443 (setf (@ element style display) :none)
445 444 (chain document body (append-child element))
446 445 (chain element (click))
447 446 (chain document body (remove-child element))))
448 447
449 448 (defun stash-state (args)
450 449 (call-serv-loc "$ONGSAVE")
451 450 (setf *state-stash
452 451 (chain *j-s-o-n (stringify
453 452 (create :vars *globals
454 453 :objs *objs
455 454 :loc-args args
456 455 :msecs (- (chain *date (now)) *started-at)
457 456 :timer-interval *timer-interval
458 457 :main-html (inner-html
459 458 (get-frame :main))
460 459 :stat-html (inner-html
461 460 (get-frame :stat))
462 461 :next-location *current-location))))
463 462 (void))
464 463
465 464 (defun unstash-state ()
466 465 (let ((data (chain *j-s-o-n (parse *state-stash))))
467 466 (clear-act)
468 467 (setf *globals (@ data :vars))
469 468 (loop :for k :in (chain *object (keys *globals))
470 469 :do (chain *object (set-prototype-of (getprop *globals k)
471 470 (@ *var prototype))))
472 471 (setf *started-at (- (chain *date (now)) (@ data :msecs)))
473 472 (setf *objs (@ data :objs))
474 473 (setf *current-location (@ data :next-location))
475 474 (setf (inner-html (get-frame :main))
476 475 (@ data :main-html))
477 476 (setf (inner-html (get-frame :stat))
478 477 (@ data :stat-html))
479 478 (update-objs)
480 479 (set-timer (@ data :timer-interval))
481 480 (call-serv-loc "$ONGLOAD")
482 481 (call-loc *current-location (@ data :loc-args))
483 482 (void)))
484 483
485 484 (defun state-to-base64 ()
486 485 (btoa (encode-u-r-i-component *state-stash)))
487 486
488 487 (defun base64-to-state (data)
489 488 (setf *state-stash (decode-u-r-i-component (atob data))))
490 489
491 490 ;;; Timers
492 491
493 492 (defun set-timer (interval)
494 493 (setf *timer-interval interval)
495 494 (clear-interval *timer-obj)
496 495 (setf *timer-obj
497 496 (set-interval
498 497 (lambda ()
499 498 (call-serv-loc "$COUNTER"))
500 499 interval)))
501 500
502 501 ;;; Special variables
503 502
504 503 (defvar serv-vars (create))
505 504
506 505 (define-serv-var $backimage (path)
507 506 (setf (@ (get-frame :main) style background-image) path))
508 507
509 508 (define-serv-var bcolor (color)
510 509 (setf (@ (get-frame :all) style background-color) (rgb-string color)))
511 510
512 511 (define-serv-var fcolor (color)
513 512 (setf (@ (get-frame :all) style color) (rgb-string color)))
514 513
515 514 (define-serv-var lcolor (color)
516 515 (setf (@ (get-frame :style) inner-text)
517 516 (+ "a { color: " (rgb-string color) ";}")))
518 517
519 518 (define-serv-var fsize (size)
520 519 (setf (@ (get-frame :all) style font-size) size))
521 520
522 521 (define-serv-var $fname (font-name)
523 522 (setf (@ (get-frame :all) style font-family) (+ font-name ",serif")))
General Comments 0
You need to be logged in to leave comments. Login now