wishingking / GM_createMenu

// ==UserScript==
// @namespace     https://openuserjs.org/users/wishingking
// @exclude       *

// ==UserLibrary==
// @name          GM_createMenu
// @description   GM_createMenu, A library, support batch add, for you to solve batch add and switch menu trouble.
// @copyright     2020, wishingking (https://openuserjs.org/users/wishingking)
// @license MIT
// @version       0.1.10

// ==/UserScript==

// ==/UserLibrary==

// ==OpenUserJS==
// @author wishingking
// ==/OpenUserJS==

/**
  *
  * When you write a plug-in, you suddenly find that you need a switch button or need to batch add menu. What should I do? Call the underlying API to implement? It may not be too much trouble, and after deleting the menu, the new menu will change its position up and down. In short, dig the pit slowly. Well, there is a GM_createMenu library packaged today, which perfectly solves the problem of adding switch menu and batch adding menu. OK, have a good time!
  * 
  * The following permissions must be granted
  * //@grant GM_registerMenuCommand
  * //@grant GM_unregisterMenuCommand
  * //@grant GM_setValue If you want to remember the menu switch status, you need to turn it on
  * //@grant GM_getValue If you want to remember the menu switch status, you need to turn it on
  */
  var GM_createMenu = {
        list : [], //menu lists
        ids : {}, //menu ids
        storage : false,
        isSwitch:function(item){
            return item && item.on && item.off;
        },
        //stored menus
        store : function(data){
            GM_setValue("__GM_createMenu_list", data||this.list);
        },
        //get stored menus
        getStore : function(key){
            return GM_getValue(key||"__GM_createMenu_list");
        },
        mergeList : function(list, store){
            if(!store || store.length===0) return list;
            //array map
            var storeMap = {};
            for(var i in store){
                var itemstore = store[i];
                if(!itemstore || typeof itemstore !== "object") continue;
                var itemstorename = itemstore["name"] || (itemstore["on"]["name"] + itemstore["off"]["name"]);
                storeMap[itemstorename] = itemstore;
            }

            //merge array
            for(var n in list){
                var item = list[n];
                if(!item || typeof item !== "object") continue;
                var itemname = item["name"] || (item["on"]["name"] + item["off"]["name"]);
                var storeitem = storeMap[itemname];
                if(this.isSwitch(storeitem)){
                    item.curr = storeitem.curr;
                    item.uncurr = storeitem.uncurr;
                    item.on.default = storeitem.on.default;
                    item.off.default = storeitem.off.default;
                    list[n] = item;
                }
            }
            return list;
        },
        //create menu,from contains page, menu
        create : function(option, from){
            var _this = this;
            if(_this.list.length===0) return;
            from = from || 'page';
            if(typeof option !== 'undefined' && typeof option.storage !== 'undefined'){
                _this.storage = option.storage;
            }
            //delete old menu
            for(var i in _this.ids){
               GM_unregisterMenuCommand(_this.ids[i]);
            }
            //merge data
            var list = _this.list;
            if(_this.storage){
                list = _this.mergeList(list, _this.getStore());
            } else {
                if(GM_setValue) _this.store([]);
            }
            //begin create menu
            list.forEach(function(item, i){
                if(!item || typeof item !== "object") return true;
                var currMenu = _this.isSwitch(item) ? item[item.curr] : item;
                _this.ids[currMenu.name] = GM_registerMenuCommand(currMenu.name, function(){
                    //call user callback
                    currMenu.callback();

                    if(_this.isSwitch(item)){
                        //Reverse switch
                        item[item.curr].default = false;
                        item[item.uncurr].default = true;
                        var item_curr = item.curr;
                        item.curr=item.uncurr;
                        item.uncurr=item_curr;

                        if(_this.storage){
                            _this.store();
                        }

                        _this.create(option, 'menu');
                    }

                }, currMenu.accessKey||null);
                if(item.load && from === 'page') item.load(item.uncurr||null);
            });
        },
        //Add menu configuration
        add:function(conf){
            //Compatible array configuration
            if(Object.prototype.toString.call(conf) === "[object Array]"){
                for(var i in conf){
                    this.add(conf[i]);
                }
                return this;
            }
            //switch menu
            if(conf.on && conf.off){
                //check configuration
                if((!conf.on.name||!conf.off.name) && typeof conf === 'object'){
                    alert("GM_createMenu Item name is need.");
                    return this;
                }
                if(!conf.on.callback){
                    conf.on.callback = function(){};
                }
                if(!conf.off.callback){
                    conf.off.callback = function(){};
                }
                if(conf.off.default){
                    conf.curr="off"
                    conf.uncurr="on"
                    conf.on.default=false;
                    conf.off.default=true;
                }
                else if(conf.on.default){
                    conf.curr="on"
                    conf.uncurr="off";
                    conf.on.default=true;
                    conf.off.default=false;
                }
                else{
                    conf.curr="on"
                    conf.uncurr="off";
                    conf.on.default=true;
                    conf.off.default=false;
                }
            } else {
                //common menu
                //check configuration
                if(!conf.name && typeof conf === 'object'){
                    alert("GM_createMenu Item name is need.");
                    return this;
                }
            }

            this.list.push(conf);
            return this;
        },
    };

/** Demoļ¼š

GM_createMenu.add([
    //switch menu
    {
        load : function(menuStatus){
            if(menuStatus==="on") alert("loaded");
        },
        on : {
            default : true,
            name : "Open",
            callback : function(){
                alert("I'm Open.");
            }
        },
        off : {
            name : "Close",
            callback : function(){
                alert("I'm Close.");
            }
        }
    },
    {
        on : {
            name : "Edit",
            accessKey: 'E',
            callback : function(){
                alert("I am editing");
            }
        },
        off : {
            default : true,
            name : "Exit Edit",
            accessKey: 'X',
            callback : function(){
                alert("I'm exit.");
            }
        }
    },
    //common menu
    {
        name : "Common menu 1",
        callback : function(){
            alert("I'm Common menu 1");
        }
    },
    {
        name : "Common menu 2",
        callback : function(){
            alert("I am Common menu 2");
        },
        load : function(){
            alert("loaded common menu2");
        }
    }
]);
GM_createMenu.create({storage:true});

Or:

GM_createMenu.add({
    on : {
        default : true,
        name : "Open",
        callback : function(){
            alert("I'm Open.");
        }
    },
    off : {
        name : "Close",
        callback : function(){
            alert("I'm Close.");
        }
    }
});
GM_createMenu.add({
    on : {
        name : "Edit",
        accessKey: 'E',
        callback : function(){
            alert("I am editing");
        }
    },
    off : {
        default : true,
        name : "Exit Edit",
        accessKey: 'X',
        callback : function(){
            alert("I'm exit.");
        }
    }
});
GM_createMenu.create();
*/