Wanikani Open Framework [developer thread]

Hi, I have a pretty minor issue with something I can’t seem to get to work regarding the WKOF. Maybe the problem is on my end or a question on it was posed before but I couldn’t find anything.

I made a settings menu with multiple color pickers and a button to reset these colors back. I reset the colors by changing a wkof.settings[scriptId].colors endpoint in the settings object. This works and the colors reset but it does not show the change immediately in the settings interface inside the color pickers themself; they stay in the color they were. Only when you save the settings and open them again do the color pickers actually have the correct color. I thought though this change was supposed to be triggered by the on_change function which is passed to the on_click function of a button element and I do call it but that does not do anything.

Images

I changed the colors:


I reset them with the button and see the changes outside the settings menu instantly:

I have to reopen the settings menu to see the color changes there too:

The relevant excerpt out of the documentation:

If this is somehow intended or something I did wrong, please tell me. Thanks!

1 Like

I think for the Heatmap Settings (I have a generate colors button) I just ended up changing the UI directly by accessing the DOM

1 Like

Ah, okay. So then there probably is no way to do it via wkof currently. Thank you!

1 Like

From the documentation:

“A refresh occurs […] whenever your script calls .refresh() on your dialog object, such as after you have programmatically modified a setting in wkof.settings[script_id].”

So, I think you can call dialog.refresh() from within your on_change function. Just be aware, though, that it will refresh all settings from the values in wkof.settings[script_id], which may not be what you want in this case.

2 Likes

Thank you! This works perfectly for me because I save all settings on change in wkof.settings[script_id] already (even though it’s probably not a good practice) so the other settings aren’t affected by this. I totally didn’t see that refresh function.

1 Like

Ah, I also have an Apply button and maybe that’s why I ended up modifying the DOM

1 Like

I would be nice if I can see which script failed to fetch data fast enough. I don’t think I can see that in the console, and sometimes the dialog just stays visible for minutes.

1 Like

Hey guys, I don’t use WKOF but I do have to work with scripts using it under the hood, so please excuse my ignorance here. I did try to brush up with the code and documentation.

I am aware I can do

 wkof.ready('ItemData').then(() => {
     console.log('ITEM DATA MODULE READY!');
 });

But what I really need, is a way to subscribe to ItemData and listen for any downloads that have finished that were triggered by another userscript. Is this possible? Maybe there is an event I am missing?

This is primarily for when WKOF is first installed or initial download of subjects, assignments, etc . . .

Thanks!

Hmm… wkof doesn’t have anything built in for monitoring what other scripts are doing (at least, not without the other script providing a signal to let you know).

Can you tell me more about what you’re trying to achieve (not ‘how’, but what the end goal is)? get_items() first loads any previously fetched data from the indexeddb cache, then calls the WK server (but not more than once per minute) to see if any new items have been added to that particular endpoint since the last time the cache was updated. So, as you can see, it’s sort of complicated as to exactly when new data has been fetched from the WK server, versus just a “no new data” response.

Can you tell me more about what you’re trying to achieve

The scenario: My script inserts custom / non-WaniKani items into WKOF’s database.

On every page load, it first checks to see if the wkof.file_cache database exists, then checks to see if any custom items need to be inserted. This ensures compatibility with scripts, in this case specifically Reorder Omega that utilizes get_items().

However, say the wkof.file_cache database does not exist yet or is empty. If I understand correctly, Reorder Omega initializes a download of subjects, assignments, ... through the ItemData module.

So essentially, is it possible: to be notified that ItemData is creating the initial wkof.file_cache database, insert my dummy data, then have Reorder Omega continue loading. Maybe ItemData fires an event when it’s initializing the database, and I can subscribe to that before ItemData tells Reorder Omega that the state is ready?


My first idea was to just go ahead and create & pre-populate the database if it does not exist, but there’s the limitation with indexeddb that you cannot change the structure of the database once it exists ( for that version ). So I have to wait until ItemData itsef initalizes the database.

I don’t think it’s relevant, but here is my sync() function

sync()
async function sync({ decks, syncRequiredAsOf }) {

        // WARNING: indexedDB.databases() does not work on firefox
        let databases = (await indexedDB.databases()).map(db => db.name);
        if (Array.from(databases).indexOf('wkof.file_cache') === -1) return;

        const db = await idb.openDB('wkof.file_cache', 1, {});
        const tx = db.transaction('files', 'readwrite');
        const store = tx.objectStore('files');
        const wpData = await store.get('waniplus');

        // no need to sync if it's up-to-date
        if (wpData && new Date(wpData.lastWkofSync).getTime() >= syncRequiredAsOf) return;

        console.log('WaniPlus: Syncing with WKOF cache.');

        const wkofSubjects = await store.get('Apiv2.subjects');
        const wkofAssignments = await store.get('Apiv2.assignments');
        const wkofStatistics = await store.get('Apiv2.review_statistics');

        decks.forEach(deck => {
            deck.items.forEach(item => {
                let subject = generateSubject(item, deck.id)
                wkofSubjects.content.data[subject.id] = subject;

                if (item.assignments.length > 0) {
                    let assignment = generateAssignment(item);
                    let statistics = generateReviewStatistic(item);
                    wkofAssignments.content.data[assignment.id] = assignment;
                    wkofStatistics.content.data[statistics.id] = statistics;
                }
            });
        });

        store.put({ name: 'Apiv2.subjects', content: wkofSubjects.content });
        store.put({ name: 'Apiv2.assignments', content: wkofAssignments.content });
        store.put({ name: 'Apiv2.review_statistics', content: wkofStatistics.content });
        store.put({ name: 'waniplus', lastWkofSync: new Date().toISOString() });

        db.close();
    }

In that case, when you detect that the cache hasn’t been populated yet, I’d recommend just calling get_items() yourself with each of the endpoints you need to support.

if (!is_filecache_populated()) {
  wkof.ItemData
    .get_items("subjects, assignments, review_statistics")
    .then(add_nonWK_items);
}

It’ll only have to do it once, so there’s really no downside that I can see.

(The above is pseudocode, so is_filecache_populated() isn’t an existing function)

4 Likes

I feel stupid, this is such a simple solution haha.

Thanks!

2 Likes

Being neck-deep in a complex problem tends to make you think of complex solutions. That’s when you’ve gotta let your “lazy” skill kick in and tell you, “There’s gotta be a simpler way!”.

I was halfway to writing up a complex solution for you when my ‘lazy’ kicked in :slight_smile:

3 Likes

Hi guys. My WK open framework script started bugging today. When I do reviews, the % count does not move and all my answers, right or wrong, are grey rather than green or red. Basically, it breaks the reviews and I can’t finish them. I use Macaque on Safari on the iPad. I switched all other scripts off and it turns out WK open frame work is the one causing this issue. Let me know if anyone else has the same issue, and if it is fixable. Thanks!

Anyone else seeing a bug where the gear icon in lessons disappears after the first Turbo navigation? It’s making it near-impossible to implement a setting for my Lesson Filter script.

I see someone else noticed this with Omega: [Userscript] Reorder Omega - #789 by Beyond_Sleepy

@rfindley Do you think you’ll have time to look into this?

1 Like

Turbo usually overwrites the <body> tag upon navigation, which is why the menu disappears, and currently wkof doesn’t make any assumptions about the lifetime of Menu links. I’m open to adding some sort of Menu persistance, but I haven’t seen enough use-cases yet to devise a good plan for how that should work.

So should I just re-add my menu item after each turbo navigation then?

Yeah, that’s what I’d recommend for now. During the process of implementing that in your script, if you think there’s a good and somewhat universal way of implementing something in wkof, I’d welcome the input.

Is it not as simple as just capturing every turbo before render event and adding the menu items that have already been registered? Since it’s a single page load you can track which have been registered locally (which I’m sure you’re already doing to some extent) and then just add them to the new body each time. Other than making sure to prevent duplicates it seems simple on the surface, so I’m curious if you know of some gotchas that I’m not considering.

Possibly. I’m not very familiar with the events on the Lessons page since the Turbo update. The only work I’ve done there is to update the wkof Menu module for the new DOM structure. The Menu module doesn’t actually do anything with the Turbo events there currently, and the Core of wkof only has a half-baked idea for handling Turbo events that I tried with one script during development, and have recommended that others not use it yet.

I mean… I’m familiar with Turbo events in general, but I haven’t looked at how and when WK is updating the Lessons page yet.

1 Like