adnan kamili
adnan kamili

Reputation: 9485

keydown event not working in bootstrapped Firefox addon

I am new to extension development. I am trying to trigger an action on a keydown event in my bootstrapped Firefox extension, but it doesn't seem to work. Am I missing something?

Here is my bootstrap.js code:

Cu.import("resource://gre/modules/Services.jsm");

function watchWindows(callback) {

    function watcher(window) {
    try {

      let {documentElement} = window.document;
      if (documentElement.getAttribute("windowtype") == "navigator:browser")
        callback(window);
    }
    catch(ex) {}
    }


     function runOnLoad(window) {

    window.addEventListener("load", function runOnce() {
      window.removeEventListener("load", runOnce, false);
      watcher(window);
    }, false);
  }

  // Add functionality to existing windows
  let windows = Services.wm.getEnumerator(null);
  while (windows.hasMoreElements()) {
    // Only run the watcher immediately if the window is completely loaded
    let window = windows.getNext();
    if (window.document.readyState == "complete")
      watcher(window);
    // Wait for the window to load before continuing
    else
      runOnLoad(window);
  }

  // Watch for new browser windows opening then wait for it to load
  function windowWatcher(subject, topic) {
    if (topic == "domwindowopened")
      runOnLoad(subject);
  }
  Services.ww.registerNotification(windowWatcher);

  // Make sure to stop watching for windows if we're unloading
  unload(function() Services.ww.unregisterNotification(windowWatcher));
}

/**
* Save callbacks to run when unloading. Optionally scope the callback to a
* container, e.g., window. Provide a way to run all the callbacks.
*
* @usage unload(): Run all callbacks and release them.
*
* @usage unload(callback): Add a callback to run on unload.
* @param [function] callback: 0-parameter function to call on unload.
* @return [function]: A 0-parameter function that undoes adding the callback.
*
* @usage unload(callback, container) Add a scoped callback to run on unload.
* @param [function] callback: 0-parameter function to call on unload.
* @param [node] container: Remove the callback when this container unloads.
* @return [function]: A 0-parameter function that undoes adding the callback.
*/
function unload(callback, container) {
  // Initialize the array of unloaders on the first usage
  let unloaders = unload.unloaders;
  if (unloaders == null)
    unloaders = unload.unloaders = [];

  // Calling with no arguments runs all the unloader callbacks
  if (callback == null) {
    unloaders.slice().forEach(function(unloader) unloader());
    unloaders.length = 0;
    return;
  }

  // The callback is bound to the lifetime of the container if we have one
  if (container != null) {
    // Remove the unloader when the container unloads
    container.addEventListener("unload", removeUnloader, false);

    // Wrap the callback to additionally remove the unload listener
    let origCallback = callback;
    callback = function() {
      container.removeEventListener("unload", removeUnloader, false);
      origCallback();
    }
  }

  // Wrap the callback in a function that ignores failures
  function unloader() {
    try {
      callback();
    }
    catch(ex) {}
  }
  unloaders.push(unloader);

  // Provide a way to remove the unloader
  function removeUnloader() {
    let index = unloaders.indexOf(unloader);
    if (index != -1)
      unloaders.splice(index, 1);
  }
  return removeUnloader;
}

/* library */

const Utils = (function() {

    const sbService = Cc['@mozilla.org/intl/stringbundle;1']
                         .getService(Ci.nsIStringBundleService);
    const windowMediator = Cc['@mozilla.org/appshell/window-mediator;1']
                              .getService(Ci.nsIWindowMediator);


    let setAttrs = function(widget, attrs) {
        for (let [key, value] in Iterator(attrs)) {
            widget.setAttribute(key, value);
        }
    };

    let getMostRecentWindow = function(winType) {
        return windowMediator.getMostRecentWindow(winType);
    };

    let exports = {
        setAttrs: setAttrs,
        getMostRecentWindow: getMostRecentWindow,
    };
    return exports;
})();



let ResponseManager = (function() {

    const obsService = Cc['@mozilla.org/observer-service;1']
                          .getService(Ci.nsIObserverService);

    const RESPONSE_TOPIC = 'http-on-examine-response';

    let observers = [];

    let addObserver = function(observer) {
        try {
            obsService.addObserver(observer, RESPONSE_TOPIC, false);
        } catch(error) {
            trace(error);
        }
        observers.push(observers);
    };

    let removeObserver = function(observer) {
        try {
            obsService.removeObserver(observer, RESPONSE_TOPIC, false);
        } catch(error) {
            trace(error);
        }
    };

    let destory = function() {
        for (let observer of observers) {
            removeObserver(observer);
        }
        observers = null;
    };

    let exports = {
        addObserver: addObserver,
        removeObserver: removeObserver,
        destory: destory,
    };
    return exports;
})();

/* main */

let ReDisposition = function() {

    let respObserver;

    respObserver = {

        observing: false,

        observe: function(subject, topic, data) {
            try {
                let channel = subject.QueryInterface(Ci.nsIHttpChannel);
                this.override(channel);
            } catch(error) {
                trace(error);
            }
        },

        start: function() {
            if (!this.observing) {
                ResponseManager.addObserver(this);
                this.observing = true;
            }
        },
        stop: function() {
            if (this.observing) {
                ResponseManager.removeObserver(this);
                this.observing = false;
            }
        },
        refresh: function() {
            this.start();
        },

        re: /^\s*attachment/i,

        re2: /^\s*text/i,

        override: function(channel) {

            if(disablePlugin)
            {
               try {
               let contentHeader;
               contentHeader = channel.getResponseHeader('Content-Type');
               if (this.re2.test(contentHeader)) 
               return;
               channel.setResponseHeader('Content-Disposition', "attachment", false);
               return;
               }
                catch(error) {
                return;
                }       
            }

            // check if have header
            let header;
            try {
                header = channel.getResponseHeader('Content-Disposition');
            } catch(error) {
                return;
            }

            // override to inline
            if (this.re.test(header)) {
                channel.setResponseHeader('Content-Disposition', header.replace(this.re, "inline"), false);
                return;
            }

        }
    };



    let initialize = function() {

        respObserver.refresh();
    };
    let destory = function() {

        respObserver.stop();
    };

    let exports = {
        initialize: initialize,
        destory: destory,
    }
    return exports;

};

/* bootstrap entry points */

let reDisposition;
var disablePlugin = false;
let install = function(data, reason) {};
let uninstall = function(data, reason) {};

let startup = function(data, reason) {

    reDisposition = ReDisposition();
    reDisposition.initialize();
    function onwindow(window) {
        function onkeydown(e) {
            if (e.keyCode == 70)
            {
            disablePlugin = true;
            }
            else
            {
            disablePlugin = false;
            }

        }
        function onkeyup(e) {

            disablePlugin = false;

        }
        // Bootstrapped add-ons need to clean up after themselves!
        function onunload() {
            window.removeEventListener("keydown", onkeypress);
            window.removeEventListener("keyup", onkeypress);
        }
        window.addEventListener("keydown", onkeydown);
        window.addEventListener("keyup", onkeyup);
        unload(onunload, window);
    }
    watchWindows(onwindow);


};

let shutdown = function(data, reason) {
    reDisposition.destory();
};

Upvotes: 3

Views: 522

Answers (1)

nmaier
nmaier

Reputation: 33212

There is no window in a bootstrap.js scope. bootstrap.js is essentially a standalone code module (that is running in a Sandbox, but that's just an implementation detail). It will run only once per application, not once per window.

When developing bootstrapped add-ons, you have to enumerate existing and watch for new windows yourself and "attach" to them as needed. See e.g. the watchWindows boilerplate.

Here is an example. It assumes you're using the watchWindows boilerplate:

function startup(data, reason) {
    // Callback function called for each browser window (browser.xul)
    function onwindow(window) {
        function onkeydown(e) {
            // XXX: Your code here.
        }
        // Bootstrapped add-ons need to clean up after themselves!
        function onunload() {
            window.removeEventListener("keydown", onkeypress);
        }
        window.addEventListener("keydown", onkeydown);
        unload(onunload, window);
    }

    // Will also fire for existing windows once and upon each new window.
    watchWindows(onwindow);
}

Developing bootstrapped add-ons isn't really something I'd recommend when you're new to Firefox add-ons, XUL/XPCOM and the mozilla platform in general. You probably should check out XUL overlay-based add-ons or the Add-on SDK.

Upvotes: 3

Related Questions