OC kbin-megamod: proposal and proof of concept for integrated collection of kbin scripts with toggle menu

Recently I had been thinking about using localstorage to elaborate a settings menu that could be used to toggle various scripts that persist browser sessions and would make the process of script management less fiddly and prone to collisions for end-users.

Then @Perry made a subscriptions panel using precisely this sort of logic (a modal leveraging localstorage), so I had a turnkey logic ready to go, and gratefully made use of his modal implementation. Thank you!

kbin-megamod exposes a modal that covers the screen and could be used to fit a large amount of checkboxes (toggles) for different scripts, or any fancy menu-like styling. The idea is that by integrating scripts into a suite, users do not have to manage numerous disparate scripts, updates, and the potential for collisions between them, because they would be tested and integrated a priori into the suite and served from a unified endpoint.

An icon at the top right of the navbar to trigger the modal

The "Megamod Settings" panel exposes a series of toggles that trigger different scripts. This can cover the screen and could fit a large amount of scripts. Tabs or columns could be added as well.

The masthead of the script defines a series of includes (@require) that call a list of scripts sourced from the /mods directory of the same repository. For maintanability purposes, each "feature" integrated into the megamod should be an atomic script sourced here. The calling script itself only manages the menu and storage of settings. For security reasons, scripts should be peer reviewed and audited by contributors and served from a single location, reducing the likelihood of a remote script being changed to execute malicious code, or simply to introduce breaking changes. When the megamod is loaded, @require scripts are fetched and saved in local cache. (Note: when testing, if you wish to update the local cache, bump the version number of the megamod script to force a redownload.)

The business logic follows:

Three arrays and one object are declared and initialized. The first array contains a list of human-readable "labels" for each option in the menu:

/*human readable mod label*/
     const mmLabels = [
            "Add mail icon",
            "Add subs to navbar",
            "Label OP",
            "Profile dropdown",
        ];

The second array contains a human-readable list of descriptions for what each feature does.

    /*human readable mod desc*/
    const mmDescs = [
            "Add mail link to usernames if on kbin.social",
            "Add magazine subscriptions to navbar",
            "Add 'OP' label to thread author",
            "Convert profile page links to dropdown",
            ];

The third array contains the identifiers for the functions, and is used when populating DOM elements with a unique classname. These must be unique.

    /*function identifier, can be same as function name*/
    const mmFuncs = [
        "addMail",
        "initMags",
        "labelOp",
        "dropdownEntry"
        ];

Finally, an object maps these classnames to the actual function entrypoint in the cached script. This is merely used as a workaround for interpolating the classname variables returned from the event listener in order to call the cached function, as explained in the section after this. The entry point name need not be the same as the function identifier (classname) above, but must be unique to prevent collisions. For simplicity, I used entry points with the same name, but they could be anything, such as myEntryPoint.

The entry point logic in the target script must parse an incoming boolean and either enable or disable the logic accordingly. In the case of disabling, this means the script must tear down or hide any DOM elements previously created.

     /*object used for interpolation of function names*/
    /*key MUST be same as mmFuncs array*/
    /*value MUST be literal entry point in the target script, will be passed boolean*/
    /*literal func name need not be identical to key*/
      const funcObj = {
       addMail: addMail,
       initMags: initMags,
       labelOp: labelOp,
       dropdownEntry: dropdownEntry
       };

The toggle logic. The method argument is the name from the mmFuncs array that is returned when the event listener triggers on a checkbox. This is then used as a key in the funcObj and interpolated to the value (the actual script entry point) and a boolean argument is passed.

function applySettings(method) {
        const settings = getSettings();
        if (settings[method] == true) {
            funcObj[method](true);
        } else {
             funcObj[method](false);
        }
    }

The toggle logic in the destination script's entry point may look something like this:

function initMags(toggle){
    if (toggle === false) {
        $('.subs-nav').remove();
    } else {
        createMags();
    }
}

I believe this could be a way forward for curating a collection of scripts, or to use the language from the repository, a "megamod" collection of "mods." It should give end-users a more straightforward means of configuring their experience without having to collect and install disparate scripts, which may be difficult for some. (Of course, power users can continue to pick and choose from standalone scripts if they wish.)

Integrating a new feature is as simple as adding four lines to megamod.user.js

  • The feature label in the first array (mmLabels)
  • The feature description in the second array (mmDescs)
  • The classname in the third array (mmFuncs)
  • The entry point mapping in the final object (funcObj)

That means you only need to write two human-readable sentence fragments and two names, add the script to the /mods directory, and the script will be integrated in the modal. All of the business logic of the called feature is then handled by the cached script. Ensure that the script handles setup and teardown correctly when it is toggled and that the entry points are defined correctly. Also, don't forget to add jQuery to the @requires if necessary and any @grants or other remote content to the masthead of the megamod.user.js so that they are passed through.

Going forward, we should look into externalizing this into a manifest and preparing the arrays/objects programmatically, rather than inline.

I would like to ask for your contributions and suggestions. Below I am including callouts to users I saw had posted scripts here recently (from the first few pages). If you wish to integrate your script, please make a PR. Sorry if I missed anyone. The main area that will require some testing will be ensuring that the scripts "play nicely" with each other and that there is no reduplication of efforts or collisions. I believe most scripts are being MIT licensed, so they could be integrated anyway with proper attribution, but obviously having the script authors integrate their own code would be preferable.

The main thing you would have to refactor is add some teardown logic to your script so that when toggled to the off state, it reverts all of its changes and restores the elements to their prior state.

@raltsm4k, @minnieo, @blobcat, @artillect, @0rito, @SirPsychoMantis, @CodingAndCoffee

Postscript: as for the megamod script itself, I have not thoroughly cleaned everything yet. I have not fully integrated the "add dropdown" functionality from my other script, but merely added it as the last checkbox for testing purposes, so the cosmetic teardown is not working correctly when disabling it. Otherwise, the other toggles are working correctly and act as a minimum viable prototype. You can test enabling/disabling these features and should see the effects live.

Lastly, in case you are wondering, "won't these features be added to kbin upstream eventually?" If you are already a script author, I think you know the answer to this, but to clarify for other interested parties: there will always be a need for third-party modifications on any site, no matter how mature, as users may have wildly different needs. Changing things on the client-side is non-invasive and can be prototyped easily, as well as takes the strain on upstream developers off of UI concerns and lets them focus on more important issues. Finally, client-side scripts could also serve as a reference for designs used in production code, so these efforts are not wasted.

McBinary,
McBinary avatar

I'm not a dev of any sort, but I will say that I have been waiting for the spiritual successor of RES to show up here - and I think this is it.
'One [script] to rule them all sort' of thing.

I am using several of y'all's script already and it gets sort of cumbersome opening up each script individually to check if there has been a new version released.

For what it's worth from a user perspective - I like the idea of there being just a button or a drop down shade to enable specific scripts. Obscuring them in the Profile > Settings page makes them hard to find for new users and doesn't exactly allow you to refresh the page to see them in action since none of them are applied to the profile page.

Harlan_Cloverseed,
Harlan_Cloverseed avatar

I will use this when it’s easy and functional

shazbot,

Our people will contact your people when it is ready

RodPhoto,
RodPhoto avatar

What an excellent idea and implementation (as far as I can understand it). It makes so much sense to put everyone's efforts into a "suite" and create a super customizable user experience. I can't wait to try this and I hope all of you talented peeps get on board with it.

artillect,
artillect avatar

This is awesome! I was working on something similar, but you beat me to the punch! This is probably a better way to handle it than how I had planned, with each script adding itself to the settings (although I think that would be nice to have as an alternate method, so scripts not in the megamod can still have access to a nice config menu).

If I'm understanding this correctly, it seems like you should be able to add multiple config options per script, which is great (but I think it might be a bit hacky)! It'd be awesome if you could add headers to help separate the options into sections, and add more option types like text, sliders, and radio buttons. Having more config types would be awesome for other configuration purposes. I also think that the current method of adding config options is a bit clunky and will definitely get unwieldy as the number of mods grows, maybe a function like addOption(mmLabel, mmDesc, mmFunc, funcObj) would work well.

I'm gonna start messing with this and getting my scripts set up to work with it, I'll throw together a pull request once I've gotten some of them working

shazbot,

I added some boilerplate code to add semantic tabs at the top to jump to different categories. Currently these don't do anything, but it should help visualize it.

shazbot, (edited )

This is awesome! I was working on something similar, but you beat me to the punch! This is probably a better way to handle it than how I had planned, with each script adding itself to the settings (although I think that would be nice to have as an alternate method, so scripts not in the megamod can still have access to a nice config menu).

Yes, in theory you could shoot the moon here and offer a selection of things like syntax highlighting themes, styles, icon packs, or whatever other content you wanted to "sideload," but probably best to get a solid MVP going before doing anything fancy. Just added preliminary support for @0rito's syntax highlighting script, so the next logical step on that one would be letting you pick your preferred theme from a dropdown. I'm not 100% sure on how the includes called from other scripts bubble through to the top script, but would be nice if we could externalize those includes into a separate file so that you don't have an insanely long masthead with all of the remote resources. (Although that is not terrible, I suppose.) I was also thinking about whether we could have a standalone JSON manifest containing the stringwise resources, and sourcing that at the start to instantiate the arrays etc.

If I'm understanding this correctly, it seems like you should be able to add multiple config options per script,

Currently we just listen for a boolean event change and toggle state, but could parse other parameters as well.

It'd be awesome if you could add headers to help separate the options into sections, and add more option types like text, sliders, and radio buttons. Having more config types would be awesome for other configuration purposes.

Yes, I envisioned something like that, perhaps a series of tabs at the top for different semantic categories, or at least columns, HRs, and groupings. Since the type of input fields needed by different scripts varies, it might be good to define a basic (but not overengineered) templating method for setting up the GUI elements needed when adding the mod, rather than hardcoding the whole GUI ahead of time. For example, a handful of categories like "radio", "picker", "textarea" and passing that as an argument alongside the addOption function. This would necessitate encapsulating the script calling logic better so that everything is namespaced correctly and setting an option within a given script's "area" of the GUI will call the right script with those arguments. But the nice thing here is that the calling logic is dumb and just emits some state for the destination script to ingest, so the destination script just needs to parse these inputs and doesn't have to be integrated into the GUI logic at all.

I think the best step for now would be cramming as many scripts in here as possible to bootstrap it and test for possible conflicts, then think about how to visually organize those, but could have the conversation about GUI in parallel.

I also think that the current method of adding config options is a bit clunky and will definitely get unwieldy as the number of mods grows

Definitely agree with that, it needs to be streamlined.

I'm gonna start messing with this and getting my scripts set up to work with it, I'll throw together a pull request once I've gotten some of them working

Thank you!

JohnEdwa,
JohnEdwa avatar

I still think the proper place for userscript settings is in the sidebar with the built in settings as is done by the Kbin enhancement script - we already have the site preferences split into two places (sidebar and profile settings page), adding a third one to hunt through feels unnecessarily complicated.
At the very least, the icon/link to open them should live there.

shazbot, (edited )

I see, thank you for the criticism. I hadn't used that one before. Don't you think this unnecessarily buries the link? What if the user has disabled sidebars altogether or this settings menu changes upstream? Wouldn't it be better to decouple the link from this area? In any event, this is more about a framework for integrally managing mods; the physical location of widgets could always be changed.

JohnEdwa,
JohnEdwa avatar

You can't remove the sidebar normally, so it would have to be a custom userscript, and doing that would also remove the Magazine information box, subscribe and block buttons, list of moderators and thread info. Maybe a script that allows it to be collapsed when not needed could be useful but I don't see anyone just ripping it out completely.

But mainly thing is about keeping relevant settings grouped together. Lets say you add "Show thumbnails on left" option, it won't do anything unless the sidebar Threads -> Show Thumbnails is turned on first, so the logical place for that custom option would be in that same place. Same for any theme stuff, or anything to do with the top bar - the rest of the options are already in the sidebar.
So maybe the correct answer is actually more fragmentation where the framework would allow adding the option either to the new floating window if it's something major with a bunch of customization, or have it embedded into the already existing sidebar settings if it's better suited to be there? I dunno.

0rito,
0rito avatar

And here I am putting together a simple script to allow collapsing of those pesky sidebars, lol! However, doesn't RES also handle settings in a similar was as is here? I think they open a new page entirely now, but it's still a dedicated button, no? At the very least it would be familiar to users of RES.

JohnEdwa,
JohnEdwa avatar

Yes, although RES does do it like that because there is no second place for Reddit settings - the RES settings button is right next to the Reddit preferences link. On Kbin that settings link is already tucked in the dropdown you get when hovering your name and the settings you'd find there on Reddit (https://old.reddit.com/prefs/) like thumbnails, media previews, autoplay and so on in Kbin live in the sidebar instead.

shazbot,

You do you, boo. If needed, you could refer to kbin-css for how I hid sidebars there. I believe RES does work that way, yes.

shazbot,

I'm of two minds about it. On the one hand, the options may be semantically related, like you said. On the other hand, intermingling "official" options with third-party options somewhat obfuscates which ones are hacks/experimental and which ones are vanilla, so intentionally separating them cordons them off from each other.

My other thought was that the sidebar settings are more likely to be the "set it and forget it" top-level type, while a debug modal might include more frequently-used tweaks that the user reaches for on a regular basis. (Not saying the ones added into the existing POC are such, just thinking ahead. Such as filters and the like.)

Another thing is that (in theory), third-party options could supersede sidebar options, so you don't necessarily need to flip a toggle in the sidebar if a third-party script enforces the same check (e.g. user wants thumbnails, we better enable thumbnails first regardless of what the sidebar says). This may be trending towards bad design, however; depends on what we consider the responsibility of a third-party script to be (brute force or not).

I tend to agree with you that in cases like these, the ¿Por qué no los dos? school of thought works well. You could simply expose a link to the widget in both the navbar and sidebar or let the user set where they want it. I think it might be a bit messy to have all those options inline in the sidebar (might get rather long), but maybe an icon in the sidebar opening a sub-menu or opening this modal? There are a million ways to implement this, could be nested tabs or whatever. My gut instinct tells me the settings sidebar is going to get its own dedicated page in the future, but I may be wrong.

RodPhoto,
RodPhoto avatar

I'm just one user, but for what it's worth, I would rather have my "mod" options separate from the sites's settings, it makes it clear which ones are "official" and which ones are on my end. RES did it this way and I think it worked well. I'm not saying RES is any sort of model to follow, but it's been developed for a long time so there is precedent that others had the same idea.

  • All
  • Subscribed
  • Moderated
  • Favorites
  • kbinStyles
  • ngwrru68w68
  • rosin
  • GTA5RPClips
  • osvaldo12
  • love
  • Youngstown
  • slotface
  • khanakhh
  • everett
  • kavyap
  • mdbf
  • DreamBathrooms
  • thenastyranch
  • magazineikmin
  • anitta
  • InstantRegret
  • normalnudes
  • tacticalgear
  • cubers
  • ethstaker
  • modclub
  • cisconetworking
  • Durango
  • provamag3
  • tester
  • Leos
  • megavids
  • JUstTest
  • All magazines