OC kbin-mod-options; Mod options made easy

kbin-mod-options

Description

The purpose of this script is to allow mods to more easily implement settings.

Functionality

Header

kmoAddHeader(<modName>, <{author: 'name', version: 'versionNumber', license: 'licenseType', url: 'modUrl'}>);
  • modName - required
  • info object - optional

Example

const settingHeader = kmoAddHeader(
    'kbin-mod-options examples',
    {
        author: 'Ori',
        version: '0.1',
        license: 'MIT',
        url: 'https://github.com/Oricul'
    }
);

Header Example

Toggle Switch

kmoAddToggle(<headerChildDiv>, <settingLabel>, <settingValue>, <settingDescription>);
  • headerChildDiv - required
  • settingLabel - required
  • settingValue - required
  • settingDescription - optional

Example

// Create toggle switch
const settingEnabled = kmoAddToggle(
    settingHeader,
    'Enabled',
    true,
    'Turns this mod on or off.'
);
// Listen for toggle
settingEnabled.addEventListener("click", () => {
    // Log enabled state to console.
    console.log( kmoGetToggle(settingEnabled) );
});

Toggle Switch Example

Drop-Down

kmoAddDropDown(<headerChildDiv>, <settingLabel>, <[{name: 'friendlyName', value: 'backendValue'},{name: 'friendlyNameTwo', value: 'backendValueTwo'}]>, <currentSetting>, <settingDescription>);
  • headerChildDiv - required
  • settingLabel - required
  • options array - required
  • name/value in options array - required
  • currentSetting - required
  • settingDescription - optional

Example

// Create drop down
const font = kmoAddDropDown(
    settingHeader,
    'Font',
    [
        {
            name: 'Arial',
            value: 'font-arial'
        },{
            name: 'Consolas',
            value: 'font-consolas'
        }
    ],
    'font-consolas',
    'Choose a font for kbin.'
);
// Listen for drop down change
font.addEventListener("change", () => {
    // Log drop down selection to console.
    console.log( kmoGetDropDown(font) );
});

Drop-Down Example

Button

kmoAddButton(<headerChildDiv>, <settingLabel>, <buttonLabel>, <settingDescription>);
  • headerChildDiv - required
  • settingLabel - required
  • buttonLabel - required
  • settingDescription - optional

Example

// Create button const
const resetButton = kmoAddButton(
    settingHeader,
    'Default Settings',
    'Reset',
    'Resets settings to defaults.'
);
// Listen for button press.
resetButton.addEventListener("click", () => {
    // Log press to console.
    console.log( 'button pressed!' );
});

Button Example

Color Dropper

kmoAddColorDropper(<headerChildDiv>, <settingLabel>, <currentColor>, <settingDescription>);
  • headerChildDiv - required
  • settingLabel - required
  • currentColor - required
  • settingDescription - optional

Example

// Create color dropper const
const primaryColor = kmoAddColorDropper(
    settingHeader,
    'Primary Color',
    '#0ff',
    'Select primary theme color'
);
// Listen for new color change
primaryColor.addEventListener("change", () => {
    // Log color selection out to console.
    console.log( primaryColor.value );
});

Color Dropper Example

Usage

Simply add kbin-mod-options to your script's requires.

// @require    https://github.com/Oricul/kbin-scripts/raw/main/kbin-mod-options.js

Example

// ==UserScript==
// @name         kbin-mod-options-dev
// @namespace    https://github.com/Oricul
// @version      0.1
// @description  Attempt at standardizing mod options.
// @author       0rito
// @license      MIT
// @match        https://kbin.social/*
// @match        https://kbin.sh/*
// @icon         https://kbin.social/favicon.svg
// @grant        none
// @require      file://H:/GoogleDrive/Personal/Documents/GitHub/kbin-scripts/kbin-mod-options.js
// ==/UserScript==

(function() {
    'use strict';

    // Section header - kmoAddHeader(<modName>, {author: 'name', version: 'versionNumber', license: 'licenseType', url: 'modUrl'});
    // modName - required, author - optional, version - optional, license - optional, url - optional
    const settingHeader = kmoAddHeader(
        'kbin-mod-options examples',
        {
            author: 'Ori',
            version: '0.1',
            license: 'MIT',
            url: 'https://github.com/Oricul'
        }
    );
    // Toggle switch - kmoAddToggle(<settingLabel>, <settingValue>, <settingDescription>);
    // settingLabel - required, settingValue - required, settingDescription - optional
    const settingOne = kmoAddToggle(
        settingHeader,
        'Enabled',
        true,
        'Turn this mod on or off.'
    );
    // Listener for toggle switch - kmoGetToggle(<toggleSwitchVar>);
    // toggleSwitchVar - required
    settingOne.addEventListener("click", () => {
            console.log(kmoGetToggle(settingOne));
    });
    // Dropdown Menu - kmoAddDropDown(<settingLabel>, [{name: 'name', value: 'value'},{name: 'name2', value: 'value2'}], <currentSetting>, <settingDescription>);
    // settingLabel - required, name & value - required, currentSetting - required, settingDescription - optional
    const settingTwo = kmoAddDropDown(
        settingHeader,
        'Font',
        [
            {
                name: 'Arial',
                value: 'font-arial'
            },{
                name: 'Consolas',
                value: 'font-consolas'
            }
        ],
        'font-consolas',
        'Choose a site-wide font.');
    // Listener for dropdown menu - kmoGetDropDown(<dropDownVar>);
    // dropDownVar - required
    settingTwo.addEventListener("change", () => {
        console.log(kmoGetDropDown(settingTwo));
    });
    // Button - kmoAddButton(<settingLabel>, <buttonLabel>, <settingDescription>);
    // settingLabel - required, buttonLabel - required, settingDescription - optional
    const settingThree = kmoAddButton(
        settingHeader,
        'Default Settings',
        'Reset',
        'Resets settings to defaults.'
    );
    // Listener example for buttons.
    settingThree.addEventListener("click", () => {
        console.log('button pressed');
    });
    // Color Dropper - kmoAddColorDropper(<settingLabel>, <currentColor>, <settingDescription>);
    // settingLabel - required, currentColor - required, settingDescription - optional
    const settingFour = kmoAddColorDropper(
        settingHeader,
        'Primary Color',
        '#0ff',
        'Select primary color for style.'
    );
    // Listener example for color dropper.
    settingFour.addEventListener("change", () => {
        console.log(settingFour.value);
    });
})();
Ori,

Update: In preparation for Kbin/kbin-core#666 which makes some changes to the classes and CSS of the options menu, I've gone ahead and updated included CSS with specific declarations for things that KMO is using. Please let me know if you catch any bugs, but the only change from a user-perspective should be a slight style-shift.

As always, you can review the changes here.

0rito,
0rito avatar

Version 0.2.3 released.

Slight styling changes, including menu expansion animation.

0rito,
0rito avatar

Version 0.2.2 released.

I noticed that KUP (Kbin Usability Pack) 0.2.1 by @Perry added some settings refactoring that hides the old .settings-list instead of updating in place. This unfortunately has a side-effect of causing script's settings that are slower, or wait on DOM to load, to be hidden instead of displayed with their new refactor.

In order to prevent this issue in the future, I've updated to create our own DIV and simply append it to the .section DIV instead. Without KUP, you'll notice no difference in how settings are displayed from version 0.2.1, but if you're using KUP, it currently puts your options section at the top of the new section created by KUP. I imagine this will change if KUP moves to prepend instead of append. In my view, mod options should have always been last in any settings list solution, so I do hope that change is made at the very least.

Perry, (edited )
Perry avatar

And you're absolutely right! For some reason that I can't remember now, that wasn't included at release, but it should definitely wait for everything to load before mutating the settings. I've thrown together a fix that should make it actually wait for the document to load and an additional 100ms before running.

I'll probably have a release out later this evening.

Edit: I've also added a Compatibility Mode option to make KUP play nicer with other scripts that customise the settings panel. It will simply append the new settings to the end of the panel. I've attached an image of how it looks like.

Edit: I've released KUP 0.2.2 with the aforementioned fixes. https://kbin.social/m/kbinStyles/t/105421/Kbin-Usability-Pack-0-2-2-Now-with-settings. I've also made sure to add any enabled KUP setting as a class to the body of the document (e.g. "KUP-setting-settingsCompatibilityMode") as well as "KUP-injected" when KUP is installed. I've also added the object document.KUP that additionally serves as a carrier of future KUP endpoints (or to just check if KUP is installed).

0rito,
0rito avatar

Just took a look. With the previous version of kmo, it does in fact work when compatibility mode is enabled. I think that's probably the best solution to hope for without slowing down your own enhancements to the point of being a visual hindrance. Thanks for taking a look.

I just need to up my visual appearance game now. Your dropdown appearance and effect is much more visually appealing and while my implementation is meant to make mod options more accessible for would-be devs, it would be ideal to make it visually appealing as well.

0rito,
0rito avatar

Version 0.2 released.

It is a breaking change, but I do believe it is better to get it out quickly before any known adoption. The major change is to add collapsibility. This change does require your header to be passed as the first argument to each 'Add' function. Example code has been updated, but the gist of it is to store your header in a variable and update your add calls to reference the variable in the first argument position.

artillect,
artillect avatar

@shazbot and I (mostly shazbot) have been working on something that's pretty similar, it isn't ready for the public yet, but it's almost there (there's a big pull request that we're working on finishing now). I'd love it if you join us so we can pool our efforts together! A unified settings menu is definitely something that we need for the community, and it'd be great if we could all work together on a single one so it can be perfect :)

0rito,
0rito avatar

Yep, I've looked at it, used it a bit. I feel as though the two projects are distinct enough that they could co-exist. Whereas megamod is a mod manager where you can toggle on/off, it becomes a burden for script writers to maintain two separate sets of options for their scripts - one for megamod and one for a standalone version.

In contrast, this script isn't intended to be installed as a userscript. Instead, it's to supplement other developers userscripts. A userscript that is setup to work with megamod could still utilize this script and simply lightens the load on the developer.

My reasoning is that I agree with @JohnEdwa and, subsequently, @SirPsychoMantis - at least partially. It makes sense for options to be standardized in one place, in this case the options menu. I also believe that if megamod does go mainstream, it's mod manager should be separate.

Hope that makes sense. ( っ- ‸ - c)

artillect,
artillect avatar

The megamod is also going to have configuration options for each script, that's something shazbot is working on right now, but I do see your point about them coexisting.

I totally get why you wanna put everything in one place, but personally I think it'll get too cluttered with a lot of scripts adding their settings to the sidebar. Hence the separate settings menu that fills the screen.

I'm excited to see where you go with this!

0rito,
0rito avatar

Might be a little less cluttered visibly if settings sections were collapsed vertically to start. Might be something I look at tomorrow.

artillect,
artillect avatar

I bet that'd work well! If you're not opposed to using jquery, jquery-ui's accordion widget would make that pretty easy to do

shazbot,

I haven't picked this apart yet, but I am thinking about how we can blend these two approaches and perhaps utilize your logic in the megamod script, at least insofar as creating the input fields requested. I agree that it's a burden on authors to maintain two versions. I always assumed from the start that we would need to do some integration ("porting") on the megamod end if we choose to add in scripts. I don't think it's reasonable or necessary to track down every mod author and force them to push PRs into the repo solely for the purposes of adding a few LOC to add a toggle. However, basic interopability is obviously desirable and simplifies the process, but I'm not fundamentally against fragmentation, either.

Current logic is:

Recipient script "requests" the population of certain menu options by defining these a priori in the JSON manifest. E.g., I want a select field with these values, a, b, and c. Megamod builds up its menus based on these fields and when their state is changed, updates a locally cached object with the values for those parameters, calling the entry point function in the recipient script with these values. Megamod itself doesn't parse any of these values, merely hands them back to the recipient script.

We have no control right now over how a script author chooses to write their entry point function. Some agreed-upon standard would be nice to have, but might not be possible. The other issue is that megamod does not intentionally try to stay in lock-step with remote scripts by sourcing them verbatim. The analogy is that megamod is more like a stable "distro" with manually whitelisted "packages" that are included after auditing and necessary changes are made. So megamod's versions might be slightly behind the bleeding-edge version, and it's the responsibility of megamod's maintainers to audit and update them as necessary. If a user wants access to bleeding-edge versions of any script without integration, they can use the *monkey extension's discovery panel to find and install remote scripts matching the TLD.

@artillect

  • 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