GMCommonAPI.js

GM Common API (GMC) is a simple library designed for easily adding Greasemonkey 4 compatibilty to existing userscripts

目前為 2017-10-25 提交的版本,檢視 最新版本

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.gf.qytechs.cn/scripts/34527/226135/GMCommonAPIjs.js

// GMC - GM Common Library. A "Synchronious API" compatible with both the new/upcoming Greasemonkey 4 WebExtension
// and all the other common userscript managers.
// A fast and easy way to add Greasemonkey 4 WebExtension compatibility for (some) existing "synchronious" userscripts.

var GMC = GMC || {

    /*
     *  GMC.info
     *
     *  Maps to GM_info or GM.info object.
     *  Grants:
     *  GM.info
     *  GM_info
     */
    info: (typeof GM_info === 'object' ? GM_info : (typeof GM === 'object' && typeof GM.info === 'object' ? GM.info : null) ),


    /*
     *  GMC.registerMenuCommand(caption, commandFunc, accessKey)
     *
     *  Currently the GM4 API is missing GM.registerMenuCommand, but luckily Firefox supports HTML5 context menus, which
     *  are created by this method when supported (Currently only supported in Firefox). AccessKey is currently ignored
     *  in context menus.
     *  Grants:
     *  GM.info
     *  GM_info
     *  GM_registerMenuCommand
     *  GM.registerMenuCommand (Optional for possible future support. Currently not supported)
     */
    registerMenuCommand: function(caption, commandFunc, accessKey) {
        if (typeof GM_registerMenuCommand === 'function') {
            // Supported by most userscript extensions, but currently NOT in the upcoming Greasemonkey 4 WebExtension and it's new asynchronous API!
            GM_registerMenuCommand(caption, commandFunc, accessKey);
        } else if (typeof GM === 'object' && typeof GM.registerMenuCommand === 'function') {
            // Will probably NOT be implemented in the upcoming Greasemonkey 4 WebExtension, but if?...
            GM.registerMenuCommand(caption, commandFunc, accessKey);
        }
        if (GMC.contextMenuSupported()) {
            // Setup HTML5 contextmenu on page - Currently only supported in Firefox...
            let menuElem = null;
            if (document.body.getAttribute('contextmenu')) {
                // If existing context menu on body, don't replace but use it...
                menuElem = document.querySelector('menu#'+document.body.getAttribute('contextmenu'));
            }
            if (!menuElem) {
                // if not already exist, create the "top menu container"
                menuElem = document.createElement("menu");
                menuElem.setAttribute('type', 'context');
                menuElem.id = 'gmcmenu';
                document.body.appendChild(menuElem);
            }
            document.body.setAttribute('contextmenu', menuElem.id);
            let scriptMenu = document.querySelector('menu#menu'+GMC.getScriptIdentifier());
            if (!scriptMenu) {
                // if not already exist, create "menu container" for current userscript
                scriptMenu = document.createElement("menu");
                scriptMenu.setAttribute('label', GMC.getScriptName());
                scriptMenu.id = 'menu'+GMC.getScriptIdentifier();
                menuElem.appendChild(scriptMenu);
            }
            // create menu item
            let menuItem = document.createElement("menuitem");
            menuItem.setAttribute('label', caption);
            scriptMenu.appendChild(menuItem);
            menuItem.addEventListener('click',commandFunc, false);
        }
    },


    /*
     *  GMC.setValue(name, value)
     *
     *  When supported, this points to GM_setValue which stores values in a userscript specific database. Otherwise
     *  the HTML5 Web Storage is used, which is a domain(+protocol) specific database in the browser.
     *  IMPORTANT: If your userscript is a "single-domain" type, the difference in storage type is probably not a
     *  problem, but for "multiple-domain userscripts" GMC.setValue() might not be a satisfying solution.
     *  To prevent mistakenly overwriting or reading other clientscript's values when using Web Storage, a prefix based
     *  on userscript namespace and scriptname is added to name used in Web Storage.
     *  Grants:
     *  GM.info
     *  GM_setValue
     */
    setValue: function(name, value) {
        if (typeof GM_setValue === 'function') {
            GM_setValue(name, value);
        } else {
            GMC.setLocalStorageValue(name, value);
        }
    },


    /*
     *  GMC.getValue(name, defvalue)
     *
     *  Get the values stored using GMC.setValue(). When supported via GM_getValue and otherwise from HTML5 Web Storage.
     *  Grants:
     *  GM.info
     *  GM_getValue
     */
    getValue: function(name, defvalue) { // getLocalStorageValue: function(name, defvalue) {
        if (typeof GM_getValue === 'function') {
            return GM_getValue(name, defvalue);
        } else {
            return GMC.getLocalStorageValue(name, defvalue);
        }
    },


    /*
     *  GMC.deleteValue(name)
     *
     *  Deletes a value stored using GMC.setValue(). When supported via GM_deleteValue and otherwise from HTML5 Web Storage.
     *  Grants:
     *  GM.info
     *  GM_deleteValue
     */
    deleteValue: function(name) {
        if (typeof GM_deleteValue === 'function') {
            GM_deleteValue(name);
        } else {
            GMC.deleteLocalStorageValue(name);
        }
    },


    /*
     *  GMC.setLocalStorageValue(name, value)
     *
     *  Save value in HTML5 Web Storage (window.localStorage), which is a domain(+protocol) specific database in the browser.
     *  To prevent mistakenly overwriting or reading other clientscript's values when using Web Storage, a prefix based
     *  on userscript namespace and scriptname is added to the name used in Web Storage.
     *  Grants:
     *  GM.info
     *  GM_info
     */
    setLocalStorageValue: function(name, value) {
        localStorage.setItem(GMC.getScriptIdentifier() + '_' + name, value);
    },


    /*
     *  GMC.getLocalStorageValue(name, defvalue)
     *
     *  Get a value that was stored using GMC.setLocalStorageValue().
     *  Grants:
     *  GM.info
     *  GM_info
     */
    getLocalStorageValue: function(name, defvalue) {
        if ((GMC.getScriptIdentifier()+'_'+name) in localStorage) {
            return localStorage.getItem(GMC.getScriptIdentifier()+'_'+name);
        } else {
            return defvalue;
        }
    },


    /*
     *  GMC.deleteLocalStorageValue(name)
     *
     *  Deletes a value that was stored using GMC.setLocalStorageValue().
     *  Grants:
     *  GM.info
     *  GM_info
     */
    deleteLocalStorageValue: function(name) {
        localStorage.removeItem(GMC.getScriptIdentifier() + '_' + name);
    },


    /*
     *  GMC.setSessionStorageValue(name, value)
     *
     *  Similar to setLocalStorageValue(), but setSessionStorageValue() only stores for the current session.
     *  Grants:
     *  GM.info
     *  GM_info
     */
    setSessionStorageValue: function(name, value) {
        sessionStorage.setItem(GMC.getScriptIdentifier() + '_' + name, value);
    },


    /*
     *  GMC.getSessionStorageValue(name, defvalue)
     *
     *  Get a value that was stored using GMC.setSessionStorageValue().
     *  Grants:
     *  GM.info
     *  GM_info
     */
    getSessionStorageValue: function(name, defvalue) {
        if ((GMC.getScriptIdentifier()+'_'+name) in localStorage) {
            return sessionStorage.getItem(GMC.getScriptIdentifier()+'_'+name);
        } else {
            return defvalue;
        }
    },


    /*
     *  GMC.deleteSessionStorageValue(name)
     *
     *  Deletes a value that was stored using GMC.setSessionStorageValue().
     *  Grants:
     *  GM.info
     *  GM_info
     */
    deleteSessionStorageValue: function(name) {
        sessionStorage.removeItem(GMC.getScriptIdentifier() + '_' + name);
    },


    /*
     *  GMC.log(message)
     *
     *  Write a log-line to console. Uses GM_log if supported, otherwise directly via window.console.log().
     *  Grants:
     *  GM_log
     */
    log: function(message) {
        if(typeof GM_log === 'function') {
            GM_log(message);
        } else if (window.console) {
            window.console.log(GMC.getScriptNamespace() + GMC.getScriptName() + ' : ' + message);
        }
    },


    /*
     *  GMC.setClipboard(text)
     *
     *  Sets content of the clipboard by using either GM.setClipboard or GM_setClipboard.
     *  Grants:
     *  GM.setClipboard
     *  GM_setClipboard
     */
    setClipboard: (typeof GM_setClipboard === 'function' ? GM_setClipboard : (typeof GM === 'object' && typeof GM.setClipboard === 'function' ? GM.setClipboard : null)),


    /*
     *  GMC.addStyle(style)
     *
     *  Adds style in a an element in html header.
     *  Grants:
     *  GM_addStyle (Optional. Will be used when available, but this method should normally also work without)
     */
    addStyle: function(style) {
        if (typeof GM_addStyle === 'function') {
            return GM_addStyle(style);
        }
        let head = document.getElementsByTagName('head')[0];
        if (head) {
            let styleElem = document.createElement('style');
            styleElem.setAttribute('type', 'text/css');
            styleElem.textContent = style;
            head.appendChild(styleElem);
            return styleElem;
        }
        return null;
    },


    /*
     *  GMC.openInTab(url)
     *
     *  Opens url in a new tab (or window). If GM_openInTab ain't supported window.open is used instead. In most
     *  browsers/configurations this will open as a tab anyway (but no guarantee).
     *  Grants:
     *  GM_openInTab
     */
    openInTab: function(url) {
        if (typeof GM_openInTab === 'function') {
            return GM_openInTab(url);
        }
        return window.open(url);
    },



    getScriptName: function() {
        if (typeof GMC.info.script.name === 'string' && GMC.info.script.name.trim().length > 0) {
            return GMC.info.script.name.trim();
        } else {
            return 'Userscript';
        }
    },
    getScriptNamespace: function() {
        if (typeof GMC.info.script.namespace === 'string') {
            return GMC.info.script.namespace.trim();
        } else {
            return '';
        }
    },
    getScriptIdentifier: function() { // A "safe" identifier without any special characters
        if (typeof GMC.info === 'object' && typeof GMC.info.script === 'object') {
            return 'gmc' + GMC.getScriptNamespace().replace(/[^\w]+/g,'x') + GMC.getScriptName().replace(/[^\w]+/g,'x');
        } else {
            alert('Error: Script Namespace or Name not found (Missing @grant for GM_info/GM.info?)');
        }
    },
    contextMenuSupported: function() { // Argh, it's a bit ugly, maybe not 100% accurate (and maybe unnecessary), but...
        let oMenu = document.createElement("menu");
        return (oMenu.type !== "undefined"); // type="list|context|toolbar" if supported ?
    },




    // IN DEVELOPMENT


    // HTML5 Web Notifications ?
    //notification: (typeof GM_notification === 'function' ? GM_notification : (typeof GM === 'object' && typeof GM.notification === 'function' ? GM.notification : null)),


    listValues: function() {
        if (typeof GM_listValues === 'function') {
            return GM_listValues();
        } else {
            return GMC.listLocalStorageValues();
        }
    },
    listLocalStorageValues: function() {
        alert('Sorry, listLocalStorageValues() not yet implemented...');
        // String areay of Names (not including value)
        // https://medium.com/@ramsunvtech/onfocus-html5-storage-apis-b45d92aa424b
        // https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
    },
    getResourceURL: function(resourceName) {
        if (typeof GM_getResourceURL === 'function') {
            return GM_getResourceURL(resourceName);
        } else if (typeof GMC.info === 'object') {
            if (typeof GMC.info.script === 'object' && typeof GMC.info.script.resources === 'object' && typeof GMC.info.script.resources[resourceName] === 'object' && GMC.info.script.resources[resourceName].url) {
                return GMC.info.script.resources[resourceName].url;
            } else if (GMC.info.scriptMetaStr) {
                // Parse metadata block to find the original "remote url" instead:
                let ptrn = new RegExp('^\\s*\\/\\/\\s*@resource\\s+([^\\s]+)\\s+([^\\s]+)\\s*$','im');
                let a = GMC.info.scriptMetaStr.match(ptrn);
                if (a) {
                    return a[2];
                }
            }
            alert('Error: Cannot find url of resource=' + resourceName + ' in GMC.info object');
        } else {
            alert('Error: Cannot lookup resourceURL (Missing @grant for GM_info/GM.info or GM_getResourceURL?)');
        }
    },

    // INTERNAL or EXPERIMENTAL
    showChangelog: function(log) {
        alert('log: ' + log);
    },
    showAbout: function(log, paypalId) {
        alert('about');
    },
    isProbablyGreasemonkey3X: function() { // Running on Greasemonkey Legacy version?
        // if not Firefox => return false;
        if (typeof GM_info === 'object' && typeof GM_info.script === 'object') {
            return (typeof GM_info.script.author === 'undefined' && typeof GM_info.version === 'string' && GM_info.version.substring(0,2) === '3.');
        } else if (typeof GM === 'object') {
            return false;
        }
        return true;
    },
    inspect: function(obj) {
        var output='';
        for (var property in obj) {
            output+=property+': ' + typeof obj[property] + ((typeof obj[property] === 'string' || typeof obj[property] === 'boolean' || typeof obj[property] === 'number') ? ' = ' + obj[property] : '') + '\n'; //+window.app.yui[obj]+'; ';
        }
        alert(output);
    }
};

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址