Code snippets:Miscellaneous
From MDC
This page contains small, self-explanatory code snippets.
[edit] Saving a web page to a local file
Although the following code does not prompt the user for a filename, you can do so using the file picker component.
var file = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
file.initWithPath("C:\\filename.html");
var wbp = Components.classes['@mozilla.org/embedding/browser/nsWebBrowserPersist;1']
.createInstance(Components.interfaces.nsIWebBrowserPersist);
wbp.saveDocument(content.document, file, null, null, null, null);
[edit] Operating system detection
// Returns "WINNT" on Windows Vista, XP, 2000, and NT systems;
// "Linux" on GNU/Linux; and "Darwin" on Mac OS X.
var osString = Components.classes["@mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULRuntime).OS;
In cases when nsIXULRuntime is not available (older SeaMonkey versions), you can use nsIHttpProtocolHandler.oscpu or navigator.oscpu:
Components.classes["@mozilla.org/network/protocol;1?name=http"]
.getService(Components.interfaces.nsIHttpProtocolHandler).oscpu;
[edit] Detecting the host application and version
var info = Components.classes["@mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULAppInfo);
// Get the name of the application running us
info.name; // Returns "Firefox" for Firefox
info.version; // Returns "2.0.0.1" for Firefox version 2.0.0.1
[edit] Retrieving the version of an extension as specified in the extension's install.rdf
var em = Components.classes["@mozilla.org/extensions/manager;1"]
.getService(Components.interfaces.nsIExtensionManager);
// Change extension-guid@example.org to the GUID of the extension whose version
// you want to retrieve, e.g. foxyproxy@eric.h.jung for FoxyProxy
var addon = em.getItemForID("extension-guid@example.org");
var version = addon.version;
[edit] Copying from an input stream to an output stream
// istream is a nsIInputStream and ostream is a nsIOutputStream
// the output stream needs to be buffered to work.
var bostream = Components.classes["@mozilla.org/network/buffered-output-stream;1"]
.createInstance(Components.interfaces.nsIBufferedOutputStream);
bostream.init(ostream, 0x8000);
// make a stream pump and a stream listener to read from the input stream for us
var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"]
.createInstance(Components.interfaces.nsIInputStreamPump);
pump.init(istream, -1, -1, 0, 0, true);
/* we need our own observer to know when to close the file */
var observer = {
onStartRequest: function(aRequest, aContext) {},
onStopRequest: function(aRequest, aContext, aStatusCode) {
bostream.close();
}
};
// make a simple stream listener to do the writing to output stream for us
var listener = Components.classes["@mozilla.org/network/simple-stream-listener;1"]
.createInstance(Components.interfaces.nsISimpleStreamListener);
listener.init(bostream, observer);
// start the copying
pump.asyncRead(listener, null);
[edit] Restarting Firefox/Thunderbird/SuiteRunner
- For Firefox 3 see <code>onWizardFinish around here: http://mxr.mozilla.org/seamonkey/source/toolkit/mozapps/update/content/updates.js#1639
- For Firefox 2 see around here: http://mxr.mozilla.org/mozilla1.8/source/toolkit/mozapps/update/content/updates.js#1631
bug 338039 tracks improving this situation by providing a simple method to restart the application.
[edit] Simulating mouse and key Events
nsIDOMWindowUtils interface contains some helpful methods to simulate mouse and key events.
New in Firefox 3 / Gecko 1.9
var req = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
var utils = req.getInterface(Components.interfaces.nsIDOMWindowUtils);
utils.sendMouseEvent("mousedown", 10, 10, 0, 1, 0);
utils.sendMouseEvent("mouseup", 10, 10, 0, 1, 0);
[edit] Poor man's obfuscation
This code is meant as a trivial way to protect somewhat sensitive data (ex: an extension's password stored in a preference) from casual discovery. At glance it looks like gibberish, but it's easily breakable. For storing passwords, this document explains use of nsIPasswordManager.
function encrypt(val) {
num_out = "";
if(val == ""){
return "";
}else {
str_in = escape(val);
for(i = 0; i < str_in.length; i++) {
num_out += str_in.charCodeAt(i) - 23;
}
return unescape(num_out);
}
}
function decrypt(val) {
str_out = "";
if(val == ""){
return "";
}else {
num_out = val;
for(i = 0; i < num_out.length; i += 2) {
num_in = parseInt(num_out.substr(i,[2])) + 23;
num_in = unescape('%' + num_in.toString(16));
str_out += num_in;
}
return str_out;
}
}
[edit] Detecting mouse wheel events
When scrolling the mouse wheel on an element, the DOMMouseScroll event fires. event.detail contains the number of lines to scroll. This event is Mozilla-only; other browsers may support window.onmousewheel.
<div id="scrollArea" style="overflow: scroll; height: 6em; width: 10em;">
This is the scrolling area.
This is the scrolling area.
This is the scrolling area.
This is the scrolling area.
This is the scrolling area.
This is the scrolling area.
This is the scrolling area.
This is the scrolling area.
This is the scrolling area.
This is the scrolling area.
This is the scrolling area.
This is the scrolling area.
</div>
<script type="text/javascript">
var elm = document.getElementById("scrollArea");
elm.addEventListener("DOMMouseScroll", function scroll(event){
//event.detail is positive for a downward scroll, negative for an upward scroll
alert("scrolling " + event.detail + " lines");
}, false);
</script>
If you do not receive a DOMMouseScroll event while holding any of the modifier keys (Ctrl,Shift,Alt,Meta) you should check the mousewheel.withcontrolkey.action and related preferences. The meaning of the action preference is shown in the following table
| mousewheel.withXXXkey.action | Result |
| 0 | Scroll by lines. If set, you will receive DOMMouseScroll events. |
| 1 | Scroll by page. |
| 2 | Move around in the history. If set, you will not receive DOMMouseScroll events. |
| 3 | Change text size. If set, you will not receive DOMMouseScroll events. |
You can listen to mouse wheel click events just like normal click events. When the mouse wheel is clicked, event.button will be equal to 2.
[edit] Inserting text at the cursor
function insertText(element, snippet)
{
var selectionEnd = element.selectionStart + snippet.length;
var currentValue = element.value;
var beforeText = currentValue.substring(0, element.selectionStart);
var afterText = currentValue.substring(element.selectionEnd, currentValue.length);
element.value = beforeText + snippet + afterText;
element.focus();
//put the cursor after the inserted text
element.setSelectionRange(selectionEnd, selectionEnd);
}
insertText(document.getElementById("example"), "the text to be inserted");
[edit] Getting the currently selected text
From browser.xul overlay context:
var selectedText = document.commandDispatcher.focusedWindow.getSelection().toString();
See also [1]
[edit] Disabling JavaScript programmatically
// Disable JS in the currently active tab from the context of browser.xul getBrowser().docShell.allowJavascript = false;
If this isn't your browser, you should save the value and restore it when finished. If you wish to block selected scripts based on their URI, implement nsIContentPolicy.
[edit] Discovering which element in the loaded document has focus
// focussedControl stores the focussed field, or null if there is none.
// This excludes textareas for simplicity, but onPageLoad() can easily be
// modified to cycle through textareas as well. Further enhancements would include
// handling for fields dynamically added to the page (e.g., by page javascript).
var focussedControl;
window.addEventListener("load", function(e) { onWindowLoad(e); }, false);
function onWindowLoad() {
addEventListener("load", onPageLoad, true);
}
function onPageLoad() {
pageDoc = document.commandDispatcher.focusedWindow.document;
var inputList = pageDoc.getElementsByTagName('input');
for (var i=1; i<inputList.length; i++) {
inputList.item(i).
addEventListener("focus", function(e) {onFocusInput(e);}, false);
inputList.item(i).
addEventListener("blur", function(e) {onBlurInput(e);}, false);
}
}
function onFocusInput(focusEvent) {
focussedControl = focusEvent.originalTarget;
}
function onBlurInput(blurEvent) {
focussedControl = null;
}
[edit] Receiving notification before an extension is disabled and/or uninstalled
xulplanet entry on global notifications
- notification: "em-action-requested"
- aData: "item-disabled"
- aSubject is an nsIUpdateItem instance.
This notification is broadcast when the user disables the extension, but before it's actually disabled. The user can cancel his action before the restart, in which case the extension won't be disabled. Some people suggested setting a flag when receiving this notification (and unsetting it if the user canceled the action) and only doing the clean up at the shutdown. The downside is that your code won't run if Firefox shuts down improperly.
You should filter on the item ID to only handle the actions on your extension.
[edit] Using string bundles from JavaScript
Assuming the extension has myext.properties with name/value pairs such as:
invalid.url=The speficied URL, %S, is invalid. That was attempt number %S.
These properties can be accessed from JavaScript in the following manner:
var common = {
_bundle: Components.classes["@mozilla.org/intl/stringbundle;1"]
.getService(Components.interfaces.nsIStringBundleService)
.createBundle("chrome://myext/locale/myext.properties"),
getLocalizedMessage: function(msg, args) {
return this._bundle.GetStringFromName(msg, args);
}
};
alert(common.getLocalizedMessage("invalid.url", "http://bad/url/", "3"));
Another similar alternative (using both GetStringFromName and formatStringFromName), is:
var fcBundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
.getService(Components.interfaces.nsIStringBundleService)
.createBundle("chrome://myext/locale/myext.properties");
function getStr(msg, args){ //get localised message
if (typeof args == "object"){
return fcBundle.formatStringFromName(msg,args,args.length);
}else return fcBundle.GetStringFromName(msg);
}
/* Usage */
alert(getStr("invalid.url",[ "http://bad/url/", "3"])); //for message with paramenters
alert(getStr("invalid.url")); //for message without parameters