Prevent the closing of a tab with firefox addon sd

2019-05-27 04:03发布

I am looking for a way to prevent the closing of a tab using the firefox addon sdk.

Is there a way to achieve that?

2条回答
萌系小妹纸
2楼-- · 2019-05-27 04:15

This does the trick. Can copy paste this to scratchpad and run (with environment > browser of course)

adapted from here: https://gist.github.com/Noitidart/9406437 which is from: https://gist.github.com/Noitidart/51b62b356b3a21010a4d

it uses the onbeforeunload thing and attaches it to all top windows on load of tabs, and also on open of tabs with event listener of TabOpen

when you want to undo the changes this made, run windowListener.unregister() i gave commented out example at bottom of window. but if you run unregister from scratchpad make sure you blank out the stuff at top first otherwise it wont unregister what was registered on the PREVIOUS run, it will just unregister what it registerd on the current run.

not tailored for addon-sdk, but you can drop this into your addon sdk but at top you have to add like var {Cu, Ci} = require('chrome'); Cu.import('resource://gre/modules/Services.jsm');

this code does modify the text of the warning modal.

it doesnt check if some other onbeforeunload is already registered, its an ez check you should add that in. if need help let me know.

try {
    windowListener.unregister();
} catch (ignore) {}

var ignoreFrames = true;

function beforeUnloader(e) {
    //console.log('beforeUnload e:', e); //http://i.imgur.com/AbUn20J.png
    var DOMWindow = e.target.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
                                                     .getInterface(Ci.nsIWebNavigation)
                                                     .QueryInterface(Ci.nsIDocShellTreeItem)
                                                     .rootTreeItem
                                                     .QueryInterface(Ci.nsIInterfaceRequestor)
                                                     .getInterface(Ci.nsIDOMWindow);
    DOMWindow.setTimeout(function() {
        try {
            if (DOMWindow.gBrowser) {
                var linkedBrowser = DOMWindow.gBrowser.getBrowserForDocument(e.target);
            } else {
                var linkedBrowser = DOMWindow.document;
            }
            var modal = linkedBrowser.parentNode.querySelector('tabmodalprompt');
            var warnTxtNode = modal.ownerDocument.getAnonymousElementByAttribute(modal, 'anonid', 'info.body').firstChild;
            warnTxtNode.textContent = 'rawr';
        } catch (ex) {
            console.warn('excpetion occured when trying to modify warn text, ex:', ex);
        }
    }, 10);
    return 'dummy text so it shows unloader'; //see third bullet here: https://developer.mozilla.org/en-US/docs/WindowEventHandlers.onbeforeunload it says "Note that in Firefox 4 and later the returned string is not displayed to the user. Instead, Firefox displays the string "This page is asking you to confirm that you want to leave - data you have entered may not be saved." See bug 588292."
};

function addInjections(theDoc) {
    theDoc.defaultView.onbeforeunload = beforeUnloader;
}

function removeInjections(theDoc, skipChecks) {
  theDoc.defaultView.onbeforeunload = null;
}

function tabopened(e) {
    //console.info('tabopened: e:', e); //http://i.imgur.com/Re0Wmfn.png
    addInjections(e.target.linkedBrowser.contentDocument);
}

function listenPageLoad(event) {
    var win = event.originalTarget.defaultView;
    var doc = win.document;
    Cu.reportError('page loaded loc = ' + doc.location);
    if (win.frameElement) {
        //its a frame
        Cu.reportError('its a frame');
        if (ignoreFrames) {
            return;//dont want to watch frames
        }
    }
    addInjections(doc);
}

/*start - windowlistener*/
var windowListener = {
    //DO NOT EDIT HERE
    onOpenWindow: function (aXULWindow) {
        // Wait for the window to finish loading
        let aDOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
        aDOMWindow.addEventListener("load", function () {
            aDOMWindow.removeEventListener("load", arguments.callee, false);
            windowListener.loadIntoWindow(aDOMWindow, aXULWindow);
        }, false);
    },
    onCloseWindow: function (aXULWindow) {},
    onWindowTitleChange: function (aXULWindow, aNewTitle) {},
    register: function () {
        // Load into any existing windows
        let XULWindows = Services.wm.getXULWindowEnumerator(null);
        while (XULWindows.hasMoreElements()) {
            let aXULWindow = XULWindows.getNext();
            let aDOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
            windowListener.loadIntoWindow(aDOMWindow, aXULWindow);
        }
        // Listen to new windows
        Services.wm.addListener(windowListener);
    },
    unregister: function () {
        // Unload from any existing windows
        let XULWindows = Services.wm.getXULWindowEnumerator(null);
        while (XULWindows.hasMoreElements()) {
            let aXULWindow = XULWindows.getNext();
            let aDOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
            windowListener.unloadFromWindow(aDOMWindow, aXULWindow);
        }
        //Stop listening so future added windows dont get this attached
        Services.wm.removeListener(windowListener);
    },
    //END - DO NOT EDIT HERE
    loadIntoWindow: function (aDOMWindow, aXULWindow) {
        if (!aDOMWindow) {
            return;
        }
        if (aDOMWindow.gBrowser) {
            aDOMWindow.gBrowser.addEventListener('DOMContentLoaded', listenPageLoad, false);
            if (aDOMWindow.gBrowser.tabContainer) {
                //has tabContainer
                aDOMWindow.gBrowser.tabContainer.addEventListener("TabOpen", tabopened, false);
                //start - go through all tabs in this window we just added to
                var tabs = aDOMWindow.gBrowser.tabContainer.childNodes;
                for (var i = 0; i < tabs.length; i++) {
                    Cu.reportError('DOING tab: ' + i);
                    var tabBrowser = tabs[i].linkedBrowser;
                    var win = tabBrowser.contentWindow;
                    loadIntoContentWindowAndItsFrames(win);
                }
                //end - go through all tabs in this window we just added to
            } else {
                //does not have tabContainer
                var win = aDOMWindow.gBrowser.contentWindow;
                loadIntoContentWindowAndItsFrames(win);
            }
        } else {
            //window does not have gBrowser
        }
    },
    unloadFromWindow: function (aDOMWindow, aXULWindow) {
        if (!aDOMWindow) {
            return;
        }
        if (aDOMWindow.gBrowser) {
            aDOMWindow.gBrowser.removeEventListener('DOMContentLoaded', listenPageLoad, false);
            if (aDOMWindow.gBrowser.tabContainer) {
                //has tabContainer
                aDOMWindow.gBrowser.tabContainer.removeEventListener("TabOpen", tabopened, false);
                //start - go through all tabs in this window we just added to
                var tabs = aDOMWindow.gBrowser.tabContainer.childNodes;
                for (var i = 0; i < tabs.length; i++) {
                    Cu.reportError('DOING tab: ' + i);
                    var tabBrowser = tabs[i].linkedBrowser;
                    var win = tabBrowser.contentWindow;
                    unloadFromContentWindowAndItsFrames(win);
                }
                //end - go through all tabs in this window we just added to
            } else {
                //does not have tabContainer
                var win = aDOMWindow.gBrowser.contentWindow;
                unloadFromContentWindowAndItsFrames(win);
            }
        } else {
            //window does not have gBrowser
        }
    }
};
/*end - windowlistener*/

function loadIntoContentWindowAndItsFrames(theWin) {
    var frames = theWin.frames;
    var winArr = [theWin];
    for (var j = 0; j < frames.length; j++) {
        winArr.push(frames[j].window);
    }
    Cu.reportError('# of frames in tab: ' + frames.length);
    for (var j = 0; j < winArr.length; j++) {
        if (j == 0) {
            Cu.reportError('**checking win: ' + j + ' location = ' + winArr[j].document.location);
        } else {
            Cu.reportError('**checking frame win: ' + j + ' location = ' + winArr[j].document.location);
        }
        var doc = winArr[j].document;
        //START - edit below here
        addInjections(doc);
        if (ignoreFrames) {
            break;
        }
        //END - edit above here
    }
}

function unloadFromContentWindowAndItsFrames(theWin) {
    var frames = theWin.frames;
    var winArr = [theWin];
    for (var j = 0; j < frames.length; j++) {
        winArr.push(frames[j].window);
    }
    Cu.reportError('# of frames in tab: ' + frames.length);
    for (var j = 0; j < winArr.length; j++) {
        if (j == 0) {
            Cu.reportError('**checking win: ' + j + ' location = ' + winArr[j].document.location);
        } else {
            Cu.reportError('**checking frame win: ' + j + ' location = ' + winArr[j].document.location);
        }
        var doc = winArr[j].document;
        //START - edit below here
        removeInjections(doc);
        if (ignoreFrames) {
            break;
        }
        //END - edit above here
    }
}

windowListener.register();
查看更多
你好瞎i
3楼-- · 2019-05-27 04:26

Ok man here is what you want. The previous version was to see if i could get onbeforeunload to trigger only when tab closed, but i couldnt figure that out.

Here's how to do it: We override the removeTab function. Following the guidlines here: MDN :: Overriding/Extending/Amending existing functions - Alternative: Replace + Function.apply()

  // Keep a reference to the original function.
  var _original = gBrowser.removeTab;

  // Override a function.
  gBrowser.removeTab = function() {
    // Execute some action before the original function call.
    if (window.myAddonIsInstalled = true) {
        var closeit = confirm('are you sure you want to close the tab?')

        // Execute original function.
        if (closeit) {
            var rv = _original.apply(gBrowser, arguments);
        }

        // return the original result
        return rv;
    } else {
        var rv = _original.apply(gBrowser, arguments);
        // return the original result
        return rv;
    }
  };

on uninstall of your addon make sure to set the global property of window.myAddonIsInstalled to false. As that is the recommended way to disable your functionality per that article.

查看更多
登录 后发表回答