erkyrath / glkote Goto Github PK
View Code? Open in Web Editor NEWA Javascript display library for IF interfaces
Home Page: http://eblong.com/zarf/glk/glkote.html
License: MIT License
A Javascript display library for IF interfaces
Home Page: http://eblong.com/zarf/glk/glkote.html
License: MIT License
https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/
GlkOte should warn in Safari that files will be deleted after 7 days.
Ideally the save dialog should offer you the ability to download the savefile immediately too. Of course it doesn't have the file when the dialog is put up... so maybe set a variable/callback that pops up another dialog once glk_close_stream is called.
Open https://eblong.com/zarf/glk/glkote/sample-demo.html on iOS, and type "help."
Actual: The keyboard closes. You then have to tap on the input line to open it again. (In games that include a page break, there may be no >
prompt at all, requiring the user to guess where to tap on the screen.)
Expected: The keyboard should remain on screen when you type a command.
When I set up the glkote HTML structure, I didn't use white-space: pre-wrap
because it was 2008. Instead I used
in the minimal number of places to preserve output spacing.
I didn't use
for trailing spaces at the end of a line. This was a compromise -- a lot of games print trailing spaces on paragraphs, due to sloppy coding. If I change those to special characters, I'm making copy-and-paste significantly fuglier in a fairly common case.
However, Dannii points out that Jigsaw uses meaningful trailing space when displaying the jigsaw pieces.
Obvious options:
normal
style.See notes at erkyrath/quixe#20 .
Sometimes the gridcharheight seems to be calculated wrong, with the result that the bottom row of a grid window is invisible. A rearrange event will result in the correct gridcharheight being calculated.
Video: https://youtu.be/GAGTW8BiOtE
Currently, every module in the Glk JS ecosystem is a global object (window.GlkOte, window.Dialog, window.Quixe, etc). We would like to support the possibility of more than one. It should be possible to create instances of each and start them running, with each one talking only to its peers.
This was one of the issues mentioned when talking about ES modules (#39). However, I want to address this separately and first.
The plan is as follows:
Every module will define a JS class (e.g. GlkOteClass). (Recall that JS classes are just functions that you instantiate by writing new GlkOteClass()
.)
For backwards compatibility, each module will define an instance of its class (GlkOte). If you load the module.js in the old-fashioned way, you will wind up with window.GlkOteClass and window.GlkOte. A page can go ahead using window.GlkOte just as before. However, you can create more instances as needed.
An instance must be inited by calling its init() method. You may pass in associated module instances if you want:
GlkOte.init({ Dialog: new DialogClass() });
If you don't, the instance will create its own module instances where needed.
Each class has two new methods:
For example, GlkOte.getlibrary('Dialog')
will return the Dialog instance being used by that GlkOte instance. Glk.getlibrary('GlkOte')
will return the GlkOte being used by that Glk API instance. And so on.
When implementing higher-level modules, it's generally cleaner to fetch low-level modules using getlibrary()
rather than trying to cache a reference at init()
time. (Init order is a pain in the butt.)
The timer
event is not documented in the "Accepting User Events" section.
Apropos #48
iOS native IF interpreters (including, at least, Frotz and iosglk) have a feature in common: they have a header bar at the top of the screen with a keyboard button on it. When you click the keyboard button, the keyboard opens; when you click it again, the keyboard dismisses.
That button is especially important on the web, because it's easy to accidentally dismiss the keyboard by tapping anywhere on the screen except on the input line. When you do that, the only way to bring the keyboard back is to guess where the input line is and tap there.
Plus, sometimes you want to dismiss the keyboard (to see more text on the screen), and then easily bring it back again.
I think glkote (or Parchment??) should offer a header bar like this. The bar should include the title of the game and a keyboard button. (And maybe someday it should include text styling options: font, size, light/dark theme, etc.)
Unlike RemGlk, GlkApi can't handle an incomplete metrics definition, producing NaNs in glk_window_get_size
(and probably other functions). It should ideally support incomplete metrics (such as just providing a width and height), giving reasonable defaults for the other properties.
In dialog.js, if you hit Edit, the list of data files isn't always properly ordered. It's supposed to be Saves, Transcripts, Data but I've seen categories listed twice.
This turned up after running externalfile.ulx and then Advent.ulx.
This should give good compression. Better than the current "write out numbers in ASCII" plan.
Because it's basically stdio. See erkyrath/lectrote#107.
Lectrote is only slightly better in this sense: it uses an HTML renderer, so it can tell VoiceOver about individual paragraphs. When you type a command, you remain focused on the command area, and you have to navigate backward through the text to find the new text and read that. But at least on Lectrote it is possible to navigate paragraph by paragraph. (Lectrote does mark the transcript window as a live region, but macOS VoiceOver doesn't appear to notice.)
I wonder if all that would need to be done to improve this would be to stop GlkOte from manually focusing the input element (with an option, the current code is probably best for non screenreader users.)
(And return true on gestalt_GraphicsCharInput.)
Once this works, we can allow RemGlk to support it and test the feature end-to-end.
There's no need to use jQuery map/each/etc functions, and it just makes debugging so much harder (as the debugger will step through all the layers of jQuery code.)
A small horizontal line in the margin is traditional.
Apparently it breaks on older IE.
http://eblong.com/zarf/glulx/quixe/quixe/play-remote.html?story=stories/Advent.ulx.js
Swipe right until you reach the end. "Greater than. Text field. Is editing. Insertion point at start."
Expected: The keyboard should open
Actual: The keyboard doesn't open. Tapping/double-tapping makes no difference.
I'm pretty sure this was working in iOS 9 when I tested it in July, but it's broken now in iOS 10.1.1.
So I've run into a problem with my new project: Calling glkapi.js's glk_request_line_event doesn't work for arrays which haven't been passed to make_arg_array, and there doesn't seem to be an easy way to pass them to make_arg_array because neither it nor ArgInt/ArgChar are exposed on GiDispa. (We mustn't have ever tested ZVM with GiDispa or it wouldn't have worked.)
I see two options: expose those functions, or make retain_array not throw if it doesn't work. But I don't really understand the purpose of the system, so I don't know which option to take.
The spec says
void glk_request_line_event(winid_t win, char *buf, glui32 maxlen, glui32 initlen);
But glkapi.js has
function glk_request_line_event(win, buf, initlen)
(glk_request_line_event_uni is also missing maxlen.)
Where is maxlen? How are we meant to call it?
This is how I'm currently trying: https://github.com/curiousdannii/ifvms.js/blob/e8fd78e377/src/zvm/io.js#L314
Towards the bottom of glk_window_close
it tries to set box = content_box;
, but there is no content_box
in the file.
This must mean that that branch is never run. And so the whole keydamage_flag
stuff is unncessary?
It should give more storage capacity than localStorage.
We'll still want to fall back to localStorage if IndexedDB isn't available.
If the localStorage is full then the browser will throw, but dialog.js is not catching the errors.
Reported here: http://www.intfiction.org/forum/viewtopic.php?f=7&t=21040&start=20#p117664
Issue for tracking progress.
Code: https://github.com/curiousdannii/glkote/tree/stylehints2
Glkote automatically focuses the primary <input>
element on first load, but this doesn't actually open the on-screen keyboard on iOS Safari.
Worse, it does kinda sorta "pseudo-focus" the <input>
element, such that my PR #51 doesn't show the "Tap here to type" hint, because it thinks that the <input>
element is "already focused." (It is the document.activeElement
in that case.) 😒
Believe it or not, I think the best thing is actually not to focus the <input>
tag on first load on touchscreen devices, and to instead rely on my PR #51 "Tap here to type" to get folks into the game. (Or perhaps make tapping anywhere activate the on-screen keyboard, but only the first tap on first load…?)
So a couple of years ago, I tried out how an async GlkOte API might work. I'd like to revisit this as an option for GlkOte itself rather than pursuing it as a fork.
So the main issue is that it's just not possible to synchronously access the filesystem on some systems which I'd be interested in bringing GlkOte to, namely cloud file hosting services like Dropbox and Google Drive, as well as mobile apps using Cordova, and even IndexedDB in the browser. But it would also give the opportunity to make the JS API simpler: rather than having the user set up callbacks and then a handler that has to distinguish whether it's a Glk even or a special event and then call the callback func, which now has a different context than the original function, an async API would let you simply call the one function you want, and get back the result in the same function context, just like the C API! So if you call glk_select
you'll get back a Glk event and nothing else (ideally without even needing to call Glk.update
- that should be handled internally), if you call glk_fileref_create_by_prompt
you'll get back the file result without needing to worry about handling arrange events that might have occurred, etc.
The main disadvantage is that this would be a major breaking change, not just to how GlkOte is used, but it could require substantial changes to the end applications, Quixe etc. But I'd be willing to make those changes if we went forward in this direction.
So previously I guessed that too many Glk functions would need to be async. Partly this was because I thought that the glk_get_
functions might be able to pull data from the filesystem as it went. For something like Dropbox that's just not going to be feasible. Instead the Dialog system should be simplified to say that files to be read just need to be read and buffered in their entirety. (Files being written could perhaps still be periodically flushed, as feedback from that wouldn't need to be received back immediately.) So the functions I think would need to be made async would be:
Possibly these:
I had originally included some window functions as I thought it would be better to not just assume that new windows can always be opened. I'd also included the sound channel functions, because who knows, they might need to be async? We could reconsider them later. It may be possible to shift them to async without an addition breaking change, or that could be GlkOte version 4.
I've been brainstorming about how I would like to implement autosaving in ZVM, and if the memory and stack start as typed arrays then it would make sense to keep them that way. What if an autosave file was a Quetzal file with an extra chunk of JSON data for the remaining VM properties, either stored as ASCII or as UTF-16 if necessary. (Not UTF-8 to simplify processing - although that would really be up to the VM.)
I'm raising this here because it would need a change to the Dialog libraries.
When Quixe changes to using typed arrays you may want to change the format as well. Though the 100MB+ blorbs are mostly media, and the VM's RAM would still fit in a JS Array so the current format would work.
A (repeating) timer interval should be added to the JSON API, so that RemGlk can request timer events.
Many years ago I sent a PR for node support (#18). I think I've come up with a better plan now.
So the main problem with how the various components are organised at present is that the references to the other components are hardcoded using globals. I think it's much better if each component is a factory function rather than a singleton, so that the framework that uses GlkOte can construct the components in the order it wants, and pass in the references to the other components dynamically.
So like my old PR, I'd like to keep that aspect of it. The differences from the old PR would be:
It should be possible to do this with literally no other changes required for classic Quixe usage, but to then give Parchment/Lectrote/etc the flexible to use the components as they need.
GlkApi's gli_get_line doesn't add a NULL byte.
Also, just to check my understanding of the spec, if it reads a line break, that line break should be copied to the buffer and then a NULL, not replaced by the NULL, right?
Go to https://eblong.com/zarf/glk/glkote/sample-demo.html on iOS. Click the input line to open the keyboard.
Actual: When the keyboard is open, the status bar ("The Kitchen") scrolls out of view.
Expected: The status bar should appear floating at the top of the visual viewport.
I don't know which is preferred, but they should be consistent.
glkapi.js
still says:
/* Style hints are not supported. We will use the new style system. */
At least six years later, the new style system has yet to manifest. :) In the meantime it would be really nice if quixe could use the old style system. (And perhaps add a couple more user styles to glk to tide us over in the meantime?)
On an iPod Touch 7th Generation simulator, the <input>
line is a teeny tiny 1px-wide sliver on the right edge of the screen. Even with my PR #51, the <input>
is nearly impossible to tap on, as the "Tap here to type" hint disappears off the right edge of the screen.
In dialog.js, transcripts are displayed using <div>
with class DiaDisplayText. This sadly fails on Firefox, due to a long-standing bug -- linebreaks are lost when copying text in the browser, because CSS is ignored.
( https://bugzilla.mozilla.org/show_bug.cgi?id=116083 )
I think we can get around this by using a <pre>
element and restyling it back to the way we want. (font-family:inherit, at least.)
Noted in this thread: https://intfiction.org/t/release-along-with-parchment-interpreter/61411/20
Testing in https://eblong.com/zarf/glulx/quixe/quixe/play-remote.html?story=stories/Advent.ulx.js : If the input focus is off the input line, hitting a normal key (e.g. space bar) refocuses and enters the key. Does escape do the same? Yes in Safari, no in Chrome.
Same problem with the delete key, now that I check.
This becomes noticeable in keystroke input. (Type HELP
for example.) Hitting escape should quit the help menu, but this breaks in Chrome if the input focus has come loose. It's a little shaky even in Safari, where you may have to hit escape twice.
The truncation tests in unicasetest.inf fail if glk_buffer_canon_normalize_uni is passed a Uint32Array. Possibly the other functions would fail under the right circumstances, so I'm going to pass normal arrays to all of them just to be safe.
(I know GlkApi wasn't written to be used with TypedArrays, so it's a testament to its quality that everything else up until this point has worked!)
GlkOte and GlkApi both depend on GiLoad, but purely for its Blorb functions. I think it would make more sense for those to be found in this repository, so that there aren't any external dependencies, and so Quixe isn't required for other VMs. It could be called "Blorb", but would also need to support the JSON external resources system.
https://github.com/curiousdannii/parchment/tree/glkote-test
I've rejigged Parchment to use the code from the master branch of glkote. You'll need to ensure your checkout has retrieved all the submodules, but you won't need to run any build step. It will need to run from a webserver (not just a "file:" URL).
So TADS creates a two line text buffer status window, and something must be up with the measurements because it keeps trying to scroll and putting up the More indicator.
In two places variables called fref
are used without declaring them first, which causes an error to be thrown in strict mode:
glk_fileref_create_temp
Line 4896 in dd0c77d
glk_fileref_create_by_name
Line 4904 in dd0c77d
I don't think they need to be global variables so they could just be changed to var fref
?
It would in theory be possible to detect whether the window arrangement has a typical single text-buffer, and if so to do some shenanigans to move the scroll bar to the side of the page. Maybe the <div>
dimensions would be stretched to the page limits, and an inner div (or padding?) was used to limit the width of the window. If GlkOte was ever changed to use the flex box system it might be simpler?
Low priority, and rather hacky, but raising this issue so that the idea isn't forgotten.
If the input element isn't focused (by clicking elsewhere in the window) the arrow keys aren't captured as character events.
Possibly this is by design (to allow you to scroll windows). If so could some heuristics be added so that the ineffectual key presses still get captured?
An option to fling every input and output at an AJAX handler, so the server can save user transcripts.
Actually, use JSON (in the GlkOte standard form).
This imitates what IFComp currently does, but better. (Take a look at that to make sure I'm not missing any features. Game ID?)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.