frisch's UserScript Extender

Extends the document with a new namespace for user script crosswide functions to utilize. Has no use alone but can be accessed by other scripts using document.fExt

目前為 2016-11-16 提交的版本,檢視 最新版本

// ==UserScript==
// @name         frisch's UserScript Extender
// @namespace    http://null.frisch-live.de/
// @version      0.57
// @description  Extends the document with a new namespace for user script crosswide functions to utilize. Has no use alone but can be accessed by other scripts using document.fExt
// @author       frisch
// @include      *
// @require      http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js
// @grant        GM_setClipboard
// ==/UserScript==
if(document.fExt === undefined) {
    console.log("Initializing frisch's UserScript Extender...");

    // Initialization
    fExt = {};
    fExt.jq = $;
    // Overwrites the contains expression to be case-insensitive
    fExt.jq.expr[':'].contains = function(a, i, m) {
        return fExt.jq(a).text().toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
    };
    fExt.settings = {
        minShowTime: 3000, // in milliseconds
        maxShowTime: 9000, // in milliseconds
        position: "BottomRight", // Position for the popup menu: TopRight, TopLeft, BottomRight, BottomLeft
        animationType: "fade", // Animation for the popup menu: slide, fade, none
        animationSpeed: 500,
        customContextMenu: true,
        hideContextMenuOnLeave: true, // automatically fades out the custom context menu when it loses focus, otherwhise only hides when you click somewhere
        progressType: "progressbar", //Possible values: hourglass, progressbar
        toleranceX: 20, // pixels as tolerance for the context menu, adjust the position slightly
        toleranceY: 20, // pixels as tolerance for the context menu, adjust the position slightly
    };
    fExt.popupQueue = [];
    fExt.popping = false;

    var hourGlass0 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAhkICgkAYfvBAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAKpJREFUSMetlcEOwyAMQ+39/z97h0nrOkjihPZAAYlXVPALcPgQgE7WEzhA8LODKYLfZoTg7dVGcOm0ENx2bQTDgYVgOiwRLCdSBK2pEEHAB6wI2pvaIgj0AReC87SpOtbXEz5Ivq97Zrs/UWvsO8eovTnci6RYPs5VVu6vKkyqFZjFWZ5FI6EYOkiEIlNIgdLUUOJGqmpK+U/rGpSFn8KiYWHiA8X1NM14AxEBKx1JZtGVAAAAAElFTkSuQmCC";
    var hourGlass25 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAhkICgR+0Id8AAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAKhJREFUSMetlUkOxCAMBLv4/589h5koG3hjckgAydVtR8bS5oMk24lH+iKsoSx+3zqC++tA1C1cAQ0LT0AewXSZRrDcpBC42xBBeOAiSB0tEUh5wBtB2tQUgVQHnAj63WbRbx3/uA8cfbv3bLWIlxJQT+FQDy4LInUFLkYUHl1ZI6PuIciGrxIZidxdF+TV5y6GH05YC2rqbxc0p8JjsFi/k7aH62436wPGSjUSU11z+AAAAABJRU5ErkJggg==";
    var hourGlass50 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAhkICTqUnMkUAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAKpJREFUSMe1lMsOgzAMBHfy///sHopEQsGv0BxAMtpZJ8ErbS4k2Y4e6YuwhrM43nUE66OKmJVM9SRiNWb5lkBc+r4ACi08AZIteAAfQVhwEaRKjwikPOAXQbqpWwRSHXAi6E+bRdc63sgDx9/Wma0e4nQE1LdwyAlmjMhdQRcjkkeRRcbd62L48jhvRuzupx7lPHIizTo/IC35Taxbdwxoy6d7tb8NY2Z9AJxfMxVU9/UgAAAAAElFTkSuQmCC";
    var hourGlass75 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAhkICTPtQHGwAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAK1JREFUSMetlUkSgzAMBKf5/5/FIUnFG9ZiOEAVaHqE8Qjp8ECSneiRPggrOIvvNY+gP2URrZLmfhDRG9M9CyCGvgeAi2DSMNVsECwULOoeECzrWVptW4gANi1EATOCcFNLBFIe8EdQT5t5O+t6Yx5s/K3PbHYRmyUg/wo/dycgeO5yurh8+b4LEkkIhsly342k3Bkolt89FOQPQ9Vqe5iifJhxVk/S8c/1NM26AScHLxnJI48dAAAAAElFTkSuQmCC";
    var hourGlass100 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAhkICSxgSHxFAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAKpJREFUSMetlUsShDAIBem5/52ZxbhIIhA+40Kr9L0GCSEiwwsR0YkfkR9CG5GF51lHsN+qiNXJ8j6J2AOzfUsgjrwPwBXBy8NLEyAwHBg6B4GpxwxlIHDUONkeCFwtbr0WBIGSoOQPglBHuOiaUl0Ql876/GMejH6BhL1ZRM0pSdqLjaT5fCnYk5tJa+tG0X4ZKFrvHhp2Z6hqr4dp2o8xof2dND5cp7tZvgvYKh27llJDAAAAAElFTkSuQmCC";

    var pbar0 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AkTCSsaEe8UvgAAALZJREFUSMfdll0OxCAIhAfDjfT+J5Az0adumo1FUXSTnacmVj8ZflpSVQAAEaGlnPPnWUTg1X0+v73wBFjro/C0AvGIIwAj0bF1yHNjD+KKqAWZsam1h98gMwDrYrya7BF7Tes8kJGLpRMQACBVBREpNkpVKeGQvhuWIqtQRHQ5R16FgXrDNQzUs/aYdf9X3nR/akspZqJnh2yt9UflPfPj4Sl59vTCSl/xzii29ZHlSIoaMb31C3teW2ty8diEAAAAAElFTkSuQmCC";
    var pbar25 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AkTCSsrQDEUhAAAALZJREFUSMfdlssNxCAMRMfIHUH/FcQ1zZ6yyoEYzG+lnVMkAg+PP4mQBACICGrKOX+fzQxR3efr2wtPgLfeC08zkIh0BaAnOvUOeW5sQUIR1SAjNtX26BtkBOBdTGeT3WOva10E0nOxdAICAEISIkJsFElJOCTtqCIZrUIz43SOoloGag3XZaCWtces+7/ylvtTW0pxEz06ZK/r+lF5j/x4REpeI70w01e6M4ptfeQ5klaNmNb6B29WW2uHr2HMAAAAAElFTkSuQmCC";
    var pbar50 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AkTCSs7XYYE4AAAALVJREFUSMfdlssNxCAMRMfIHZn+Kwg1zZ6yyoEYzG+lnVMkAg+PP4mQBACICGoys+9zKQVR3efr2wtPgLfeC08zkIh0BaAnOvUOeW5sQUIR1SAjNtX26BtkBOBdTGeT3WOva10E0nOxdAICAEISIkJsFElJOKThHJmZdNjL6RxFtQzUGq7LQK3qO2bd/5W33J/anLOb6NEhe13Xj8p75McjUvIa6YWZvtKdUWzrI8+RtGrEtNY/mktYa4XsqhcAAAAASUVORK5CYII=";
    var pbar75 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AkTCSwJ2hDDpwAAAK1JREFUSMftllEOAyEIRAfDjfD+J9AzsV/bbBpFQWuTpvNlgvJwNCipKgCAiNCSiLzGtVZ4defn3oQnwIrPwtMKxCPeAZjZHVtJngtHENeOWpCITa013INEAFZhvHrYM/aa1nkgM4WlExAAIFUFESk+KFWlhEPinclEhN7s1eUz8uoPCuv3rjfdT23O2ewC0SZbSvnSZYh8PDydnXuBnZDtLcgqNp2AuEAjW0fxC+YyVWuwau4lAAAAAElFTkSuQmCC";
    var pbar100 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AkTCTAYVte+CAAAAKJJREFUSMftllEOxCAIRAfDjfT+J9AzzX510w+loLabbDpfJigPR4MKSQCAiKCnnPN33FpDVEd+HU04A6y4F55WIBHpDoBnd2olOS+8goR21IPM2NRboyPIDMAqTFcP22OvaV0E4iksPQEBACEJESFuFElJeEgv6AX9MUiOp7aUYnaB2SZba/2RdTMfj0hn11FgJ2T5mfAAbrl1liNpRxJP/APHYkptRNVvhwAAAABJRU5ErkJggg==";

    var loader0, loader25, loader50, loader75, loader100;

    switch(fExt.settings.progressType){
        case "progressbar":
            loader0 = pbar0;
            loader25 = pbar25;
            loader50 = pbar50;
            loader75 = pbar75;
            loader100 = pbar100;
            break;
        case "hourglass":
            loader0 = hourGlass0;
            loader25 = hourGlass25;
            loader50 = hourGlass50;
            loader75 = hourGlass75;
            loader100 = hourGlass100;
            break;
        default:
            loader0 = hourGlass0;
            loader25 = hourGlass25;
            loader50 = hourGlass50;
            loader75 = hourGlass75;
            loader100 = hourGlass100;
            break;
    }

    // Custom Elements
    fExt.fExtPopup = $('<div id="fExtPopup" class="fExtElement" style="display:none; position:fixed; width:auto; height:auto; background-color:#545454; padding:10px; border-color:white; border-style:groove; color:white; z-index:2147483647; text-align:center; font-size:12px;"></div>');
    $("body").append(fExt.fExtPopup);

    fExt.fExtMessage = $('<div id="fExtMessage" class="fExtElement" style="display:none; position:fixed; width:auto; height:auto; background-color:#545454; padding:25px; border-color:white; border-style:groove; color:white; z-index:2147483647; text-align:center; font-size:large; padding:20px;"></div>');
    fExt.fExtMessageText = $('<span style="display: inline-block;"></span>');
    fExt.fExtMessageText.appendTo(fExt.fExtMessage);
    fExt.fExtMessage.appendTo("body");

    // Functions
    fExt.setLoading = function(percentage){
        if(percentage >= 100){
            $("link[rel='icon']").attr("href", loader100);
            $("link[rel='shortcut icon']").attr("href", loader100);

            setTimeout(function(){ fExt.setLoading(-1); },fExt.settings.minShowTime);
        }
        else if(percentage >= 75){
            $("link[rel='icon']").attr("href", loader75);
            $("link[rel='shortcut icon']").attr("href", loader75);
        }
        else if(percentage >= 50){
            $("link[rel='icon']").attr("href", loader50);
            $("link[rel='shortcut icon']").attr("href", loader50);
        }
        else if(percentage >= 25){
            $("link[rel='icon']").attr("href", loader25);
            $("link[rel='shortcut icon']").attr("href", loader25);
        }
        else if(percentage >= 0){
            $("link[rel='icon']").attr("href", loader0);
            $("link[rel='shortcut icon']").attr("href", loader0);
        }
        else {
            $("link[rel='icon']").attr("href", siteFavIconHref);
            $("link[rel='shortcut icon']").attr("href", siteFavIconHref);
        }
    };

    fExt.enqueuePopup = function(msg) {
        fExt.popupQueue.push(msg);
    };

    fExt.dequeuePopup = function() {
        var rv;
        if(fExt.popupQueue.length > 0){
            rv = fExt.popupQueue[0];
            fExt.popupQueue.splice(0, 1);
        }
        return rv;
    };

    fExt.createStyle = function(newClass) {
        $( "<style>" + newClass + "</style>" ).appendTo("head");
    };

    fExt.center = function (element,w) {
        if(w !== undefined)
            element.width(w);

        element.css("position", "fixed")
            .css("top", (($(window).height() - $(element).outerHeight()) / 2) + "px")
            .css("left", (($(window).width() - $(element).outerWidth()) / 2) + "px");
    };

    fExt.popup = function(msg) {
        if(msg !== undefined){
            if(fExt.popping){
                fExt.enqueuePopup(msg);
                return;
            }
            fExt.popping = true;
            fExt.fExtPopup.text(msg);

            fExt.show(fExt.fExtPopup);

            var showTime = msg.length * 50;

            if(showTime < fExt.settings.minShowTime)
                showTime = fExt.settings.minShowTime;
            else if(showTime > fExt.settings.maxShowTime)
                shotTime = fExt.settings.maxShowTime;

            setTimeout(function(){
                fExt.hide(fExt.fExtPopup);
                setTimeout(function(){
                    fExt.fExtPopup.text('');
                    fExt.popping = false;
                    fExt.popup(fExt.dequeuePopup());
                },fExt.settings.animationSpeed);
            },showTime);
        }
    };

    fExt.clipboard = function(action, text) {
        var clipboardCopy, retVal;
        action = action.toLowerCase();

        clipboardCopy = document.createElement('textarea');
        var jqClipboardCopy = $(clipboardCopy);
        document.body.appendChild(clipboardCopy);
        clipboardCopy.value = text;
        clipboardCopy.select();

        var msg;
        try {
            var successful = document.execCommand(action);
            if(successful)
                msg = action + " successful";
            else
                msg = "Could not perform Clipboard-Action " + action;

            if(clipboardCopy.value.length <= 50)
                msg += " (" + clipboardCopy.value + ")";

            document.fExt.popup(msg);
        }
        catch (err) {
            document.fExt.popup("Error on Clipboard-Action " + action +": " + err);
        }

        if(clipboardCopy)
            clipboardCopy.remove();
    };

    fExt.message = function(msg) {
        if(msg !== undefined && msg.length > 0){
            fExt.fExtMessageText.text(msg);

            if(!fExt.fExtMessage.is(":visible"))
                fExt.show(fExt.fExtMessage);

            fExt.center($("div#fExtMessage"));
        }
        else {
            fExt.hide(fExt.fExtMessage);
            setTimeout(function(){
                fExt.fExtMessageText.text('');
            },fExt.settings.animationSpeed);
        }
    };

    fExt.rotate = function(element, rotation) {
        var jqEl = $(element);
        var degree = jqEl.data('rotation');

        if (!degree)
            degree = 0;

        degree += rotation;

        jqEl.css('-webkit-transform','rotate(' + degree + 'deg)');
        jqEl.data('rotation',degree);
    };

    fExt.zoom = function(element, zoom){
        var jqEl = $(element);
        var zValue = parseFloat(jqEl.css('zoom'));
        var zAdd = parseFloat(zoom) / 100;

        if(!zValue)
            zValue = 1.0;

        var zNew = zValue + zAdd;
        jqEl.css('zoom', zNew);
    };

    fExt.zoomIn = function(element, zoom){
        fExt.zoom(element, zoom);
    };

    fExt.zoomOut = function(element, zoom){
        fExt.zoom(element, zoom * -1);
    };

    switch(fExt.settings.animationType) {
        case "fade":
            fExt.show = function(element, speed) {
                if(speed === undefined)
                    speed = fExt.settings.animationSpeed;
                $(element).fadeIn(speed);
            };
            fExt.hide = function(element, speed) {
                if(speed === undefined)
                    speed = fExt.settings.animationSpeed;
                $(element).fadeOut(speed);
            };
            break;
        case "slide":
            fExt.show = function(element, speed) {
                if(speed === undefined)
                    speed = fExt.settings.animationSpeed;
                $(element).slideDown(speed);
            };
            fExt.hide = function(element, speed) {
                if(speed === undefined)
                    speed = fExt.settings.animationSpeed;
                $(element).slideUp(speed);
            };
            break;
            //case "none":
        default:
            fExt.show = function(element, speed) {
                if(speed === undefined)
                    speed = fExt.settings.animationSpeed;
                $(element).show(speed);
            };
            fExt.hide = function(element, speed) {
                if(speed === undefined)
                    speed = fExt.settings.animationSpeed;
                $(element).hide(speed);
            };
            break;
    }

    switch(fExt.settings.position) {
        case "TopRight":
            fExt.fExtPopup.attr("style", fExt.fExtPopup.attr("style") + "top:50px; right:50px;");
            break;
        case "TopLeft":
            fExt.fExtPopup.attr("style", fExt.fExtPopup.attr("style") + "top:50px; left:50px;");
            break;
        case "BottomRight":
            fExt.fExtPopup.attr("style", fExt.fExtPopup.attr("style") + "bottom:50px; right:50px;");
            break;
        case "BottomLeft":
            fExt.fExtPopup.attr("style", fExt.fExtPopup.attr("style") + "bottom:50px; left:50px;");
            break;
        default:
            break;
    }

    var siteFavIcon = $("link[rel='icon']");
    if(siteFavIcon === undefined) {
        $("head").append('<link id="favIcon" rel="icon" href="');
        siteFavIcon = $("link[rel='icon']");
    }
    else {
        siteFavIcon.attr("id","favIcon");
    }
    var siteFavIconHref = siteFavIcon.attr("href");

    fExt.getSelection = function() {
        return window.getSelection().toString();
    };

    fExt.getSource = function(element) {
        var retVal;

        var jqTarget = $(element);
        var ucTagName = element.tagName.toUpperCase();

        switch(ucTagName) {
            case "IMG":
                retVal = element.src;
                break;
            case "A":
                retVal = element.href;
                break;
            case "VIDEO":
                var videoSource = jqTarget.find("source");
                retVal = (videoSource !== undefined) ? videoSource.get(0).src : undefined;
                break;
            case "INPUT":
                return jqTarget.val();
            default:
                jqTarget = $(element).closest("a");
                if(jqTarget.length > 0)
                    retVal = jqTarget.attr("href");
                break;
        }

        if(retVal) {
            if(!retVal.match("http.*")) {
                retVal = window.location.origin + retVal;
            }
        }
        else {
            retVal = $(element).text();
        }

        return retVal;
    };

    fExt.createStyle(".fExtLoader { background:url('" + loader50 + "')  #EFF7FF no-repeat top center; }");

    // ContextMenu
    fExt.ctxMenu = [];

    fExt.createStyle("#fExtContextMenu,#fExtContextMenu * { text-align: left !important; text-decoration: none !important; z-index: 2147483647 !important; color: #fff; }");
    fExt.createStyle("#fExtContextMenu { position: fixed;}");
    fExt.createStyle("#fExtContextMenu,.ctxSubList { font-size: 14px; background-color: #263238; width: 300px; height: auto; padding: 0;}");
    fExt.createStyle("#fExtContextMenu a,#fExtContextMenu hr,#fExtContextMenu li { width: 100%;}");
    fExt.createStyle("#fExtContextMenu .ctxElement { float: left; clear: left;}");
    fExt.createStyle("#fExtContextMenu li>a,#fExtContextMenu li>div,.ctxSubList li>a,.ctxSubList li>div { padding: 8px;}");
    fExt.createStyle("#fExtContextMenu li hr { margin: 0; border-style: solid; border-color: #666; border-width: 1px 0 0 0;}");
    fExt.createStyle("#fExtContextMenu li.ctxSub { cursor: default; font-weight: bold;}");
    fExt.createStyle("#fExtContextMenu li.ctxSub * { cursor: pointer; font-weight: normal;}");
    fExt.createStyle("#fExtContextMenu li { list-style-type: none; margin: 0 !important;}");
    fExt.createStyle("#fExtContextMenu li.ctxSub:hover>div.ctxSubLabel,");
    fExt.createStyle("#fExtContextMenu li.ctxSub:hover>div.ctxArrow {}");
    fExt.createStyle("#fExtContextMenu li.ctxItem { padding-left: 5px;}");
    fExt.createStyle("#fExtContextMenu li.ctxItem { border: none; position: relative; box-sizing: border-box; transition: all 250ms ease; }");
    fExt.createStyle("#fExtContextMenu li.ctxItem:hover { background: #3a7999; color: #3a7999; box-shadow: inset 0 0 0 3px #3a7999; }");
    fExt.createStyle("#fExtContextMenu li.ctxSub.disabled div.ctxSubLabel:hover,");
    fExt.createStyle("#fExtContextMenu li.ctxItem.disabled:hover a,#fExtContextMenu li.disabled div.ctxSubLabel,#fExtContextMenu li.disabled a { opacity: 0.70; font-style: italic; padding-left: 7px !important;}");
    fExt.createStyle("#fExtContextMenu li.ctxSeparator { display: inline-block;}");
    fExt.createStyle("#fExtContextMenu li.ctxSub div.ctxSubLabel { padding-left: 10px !important; float: left; clear: left;}");
    fExt.createStyle("#fExtContextMenu li.ctxSub div.ctxArrow { float: right; clear: right;}");
    fExt.createStyle("#fExtContextMenu li.ctxSub ul.ctxSubList { position: absolute; height: auto;}");

    fExt.ctxMenu.uniqueID = 1;
    fExt.ctxMenu.allItems = [];
    fExt.ctxMenu.actor = undefined;
    fExt.ctxMenu.html = $('<ul id="fExtContextMenu" class="ctxElement" style="display: none;"></ul>');
    fExt.ctxMenu.html.appendTo("body");

    ctxCtor = function(ret) {
        ret.ItemText = function(value){
            if(value === undefined)
                return this.item.text();

            this.item.text(value);
        };
        ret.Attribute = function(attribute, value){
            if(value === undefined)
                return this.item.attr(attribute);
            else
                this.item.attr(attribute, value);
        };
        ret.Toggle = function(enabled){
            if(enabled === true || (enabled === undefined && this.hasClass("disabled")))
                this.removeClass("disabled");
            else
                this.addClass("disabled");
        };
        ret.IsDisabled = function(){
            return this.hasClass("disabled");
        };
        ret.ID = function() {
            return this.data("Item-ID");
        };
    };

    fExt.ctxMenu.addItem = function(label, action, sub){
        var ret = $('<li class="ctxItem ctxElement"></li>');
        var retObj = $('<a href="#" class="ctxElement"></a>');
        retObj.appendTo(ret);
        ret.item = retObj;

        if(sub === undefined)
            ret.appendTo(fExt.ctxMenu.html);
        else
            ret.appendTo(sub.find("ul:first"));

        ctxCtor(ret);

        ret.Action = undefined;
        ret.Attribute("action", action);
        ret.ItemText(label);
        fExt.ctxMenu.assignID(ret);
        return ret;
    };

    fExt.ctxMenu.addSub = function(label, orientation, sub){
        var ret = $('<li class="ctxElement ctxSub"><div class="ctxElement ctxArrow">&gt;</div><ul class="ctxElement ctxSubList" style="display: none"></ul></li>');
        var item = $('<div class="ctxElement ctxSubLabel">' + label + ' </div>');
        item.appendTo(ret);

        ctxCtor(ret);

        var parentMenu = fExt.ctxMenu.html;
        if(sub !== undefined)
            parentMenu = $(sub).find("ul:first");
        else
            parentMenu = fExt.ctxMenu.html;

        if(orientation === 'bottom' || orientation === undefined || $(parentMenu).children().length === 0) {
            ret.appendTo(parentMenu);
        }
        else {
            ret.insertBefore($(parentMenu).children("li:first"));
        }

        return ret;
    };

    fExt.ctxMenu.addSeparator = function(sub){
        var ret = $('<li class="ctxElement ctxSeparator"><hr/></li>');

        if(sub === undefined)
            ret.appendTo(fExt.ctxMenu.html);
        else
            ret.appendTo(sub.find("ul:first"));

        return ret;
    };

    fExt.ctxMenu.assignID = function(item){
        if(item.ID() !== undefined)
            console.log("Item already has an ID: " + item.ID());

        item.data("Item-ID", fExt.ctxMenu.uniqueID);
        fExt.ctxMenu.uniqueID++;
        fExt.ctxMenu.allItems.push(item);
    };

    fExt.ctxMenu.getItem = function(id) {
        if(id !== undefined) {
            for(i = 0;i < fExt.ctxMenu.allItems.length; i++){
                var item = fExt.ctxMenu.allItems[i];
                if(id === item.ID())
                    return item;
            }
        }

        return undefined;
    };

    $("#fExtContextMenu").on("click", "li", function( event ) {
        var sender = fExt.ctxMenu.getItem($(this).data("Item-ID"));
        if(sender === undefined || sender.Action === undefined)
            return true;

        event.preventDefault();
        if(!sender.IsDisabled())
            sender.Action(event, sender, fExt.ctxMenu.actor);

        fExt.hide(fExt.ctxMenu.html);
        return false;
    });

    $("#fExtContextMenu").on("mouseenter", "li.ctxSub", function(event){
        var sub = $(this);
        var subOffs = sub.offset();
        var ul = sub.children("ul.ctxSubList:first");

        if(ul.children("li.ctxItem").length === 0)
            return;

        fExt.show(ul, 0);

        var height = ul.height();
        var width = ul.width();
        var y = subOffs.top;
        var x = subOffs.left + sub.width();
        if ((x + width) >= window.screen.availWidth)
            x = subOffs.left - ul.width();
        if ((y + height + 100 - window.scrollY) >= window.screen.availHeight)
            y = y - height;

        if ((y - window.scrollY) < 0)
            y = window.scrollY;
        if ((x  - window.scrollX) < 0)
            x = window.scrollX;

        ul.offset({ top: y, left: x});
    });
    $("#fExtContextMenu").on("mouseleave", "li.ctxSub", function(event){
        var ul = $(this).children("ul.ctxSubList:first");
        fExt.hide(ul);
    });
    $("#fExtContextMenu").on("mouseenter", "li.ctxSub", function(event){
        var ul = $(this).children("ul.ctxSubList:first");
        ul.stop();
        if($(this).find("li.ctxItem").length > 0)
            ul.show(0);
    });

    fExt.customContextMenuHandler = function (event){
        event.preventDefault();

        fExt.ctxMenu.actor = $(event.target);

        var y = event.clientY - fExt.settings.toleranceY,
            x = event.clientX - fExt.settings.toleranceX;
        if ((x + fExt.ctxMenu.html.width()) >= window.screen.availWidth)
            x = x - fExt.ctxMenu.html.width() + (fExt.settings.toleranceX * 1.5);
        if ((y + fExt.ctxMenu.html.height() + 100) >= window.screen.availHeight)
            y = y - fExt.ctxMenu.html.height() + (fExt.settings.toleranceY * 1.5);

        if (y < 0)
            y = 0;
        if (x < 0)
            x = 0;

        fExt.ctxMenu.html.css({
            top: y,
            left: x
        });

        $("#fExtContextMenu").trigger("fExtContextMenuOpening", [fExt.ctxMenu.actor]);

        fExt.show(fExt.ctxMenu.html, 0);

        return false;
    };

    $("#fExtContextMenu").on("fExtContextMenuOpening", function(event, actor){
    });

    if(fExt.settings.hideContextMenuOnLeave) {
        $("#fExtContextMenu").mouseleave(function(){
            fExt.hide(fExt.ctxMenu.html);
        });
        $("#fExtContextMenu").mouseenter(function(){
            fExt.ctxMenu.html.stop();
            fExt.ctxMenu.html.show(0);
        });
    }
    else {
        $("body").click(function(e){
            if(!$(this).hasClass("ctxElement") && fExt.ctxMenu.html.is(":visible"))
                fExt.hide(fExt.ctxMenu.html,0);
        });
    }

    $(document).on('contextmenu', function(event){
        if(fExt.settings.customContextMenu) {
            if(!$(event.target).hasClass("ctxElement"))
                fExt.customContextMenuHandler(event);
            else
                fExt.ctxMenu.html.hide();
        }
    });

    $(document).on('keyup', function(event){
        if((event.which === 17 && event.altKey) || (event.which === 18 && event.ctrlKey)) {
            fExt.settings.customContextMenu = !fExt.settings.customContextMenu;
            fExt.popup("Context-Menu has been toggled " + (fExt.settings.customContextMenu ? "on" : "off"));
        }
    });

    // Finalize
    document.fExt = fExt;

    fExt.fExtPopup.click(function(e){
        fExt.popupQueue = [];
        fExt.hide($(this));
    });

    fExt.fExtMessage.click(function(e){
        fExt.hide($(this));
    });

    console.log("frisch's UserScript Extender initialized!");
}

QingJ © 2025

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