git @ Cat's Eye Technologies Canvas-Feedback / master src / yoob / preset-manager.js
master

Tree @master (Download .tar.gz)

preset-manager.js @masterraw · history · blame

/*
 * This file is part of yoob.js version 0.13
 * Available from https://github.com/catseye/yoob.js/
 * This file is in the public domain.  See http://unlicense.org/ for details.
 */
if (window.yoob === undefined) yoob = {};

/*
 * An object for managing a set of "presets" -- which, for an esolang,
 * might be example programs; for an emulator, might be ROM images;
 * for a control panel, may be pre-selected combinations of settings;
 * and so forth.
 *
 * Mostly intended to be connected to a yoob.Controller -- but need not be.
 */
yoob.PresetManager = function() {
    /*
     * The single argument is a dictionary (object) where the keys are:
     *
     *    selectElem: (required) the <select> DOM element that will be
     *        populated with the available example programs.  Selecting one
     *        will cause the .select() method of this manager to be called.
     *        it will also call .onselect if that method is present.
     *
     *    setPreset: (optional) a callback which will be called whenever
     *        a new preset is selected.  If this is not given, an individual
     *        callback must be supplied with each preset as it is added.
     */
    this.init = function(cfg) {
        this.selectElem = cfg.selectElem;
        if (cfg.setPreset) {
            this.setPreset = cfg.setPreset;
        }
        this.clear();
        var $this = this;
        this.selectElem.onchange = function() {
            $this._select(this.options[this.selectedIndex].value);
        }
        return this;
    };

    /*
     * Removes all options from the selectElem, and their associated data.
     */
    this.clear = function() {
        this.reactTo = {};
        while (this.selectElem.firstChild) {
            this.selectElem.removeChild(this.selectElem.firstChild);
        }
        this.add('(select one...)', function() {});
        return this;
    };

    /*
     * Adds a preset to this PresetManager.  When it is selected,
     * the given callback will be called, being passed the id as the
     * first argument.  If no callback is provided, the default callback,
     * configured with setPreset in the init() configuration, will be used.
     */
    this.add = function(id, callback) {
        var opt = document.createElement("option");
        opt.text = id;
        opt.value = id;
        this.selectElem.options.add(opt);
        var $this = this;
        this.reactTo[id] = callback || this.setPreset;
        return this;
    };

    this.setPreset = function(id) {
        throw new Error("No default setPreset callback configured");
    };

    /*
     * Called by the selectElem's onchange event.  For sanity, you should
     * probably not call this yourself.
     */
    this._select = function(id) {
        this.reactTo[id](id);
        if (this.onselect) {
            this.onselect(id);
        }
    };

    /*
     * Call this to programmatically select an item.  This will change
     * the selected option in the selectElem and trigger the appropriate
     * callback in this PresetManager.
     */
    this.select = function(id) {
        var i = 0;
        var opt = this.selectElem.options[i];
        while (opt) {
            if (opt.value === id) {
                this.selectElem.selectedIndex = i;
                this._select(id);
                return this;
            }
            i++;
            opt = this.selectElem.options[i];
        }
        // if not found, select the "(select one...)" option
        this.selectElem.selectedIndex = 0;
        return this;
    };

    /*
     * When called, every DOM element in the document with the given
     * class will be considered a preset, and the manager
     * will be populated with these.  Generally the CSS for the class
     * will have `display: none` and the elements will be <div>s.
     *
     * callback is as described for the .add() method.
     */
    this.populateFromClass = function(className, callback) {
        var elements = document.getElementsByClassName(className);
        for (var i = 0; i < elements.length; i++) {
            var e = elements[i];
            this.add(e.id, callback);
        }
        return this;
    };

    /*
     * When called with a yoob.SourceManager and an array of
     * 2-element arrays of a name and a source text, this preset
     * manager will be populated with each source text as a
     * named preset.  A callback to load the source text with
     * the SourceManager will be automatically supplied.
     */
    this.populateFromPairs = function(sourceManager, pairs) {
        function makeCallback(sourceText) {
            return function(id) {
                sourceManager.loadSource(sourceText);
            }
        }

        for (var i = 0; i < pairs.length; i++) {
            this.add(pairs[i][0], makeCallback(pairs[i][1]));
        }
        this.select(pairs[0][0]);
        return this;
    };
};