Hacking Firefox - part 37 pps

10 74 0
Hacking Firefox - part 37 pps

Đang tải... (xem toàn văn)

Thông tin tài liệu

362 Part VI — Creating Extensions and Themes Figure 17-24 shows the dialog we have created. F IGURE 17-24: A simple dialog Let’s look at our dialog code more closely: Ⅲ The dialog element specifies that our XUL document is in fact a dialog. ■ The title attribute specifies the dialog title. ■ The buttons attribute specifies the comma-separated list of buttons that will appear in the dialog. In our case, we want two buttons: OK and Cancel. Notice that we specified only the wanted buttons and didn’t have to create the button ele- ments. The buttons are created automatically, and their position and appearance are determined by the user’s operating system conventions. ■ The ondialogaccept and ondialogcancel attributes define functions that will be called when the user presses OK and Cancel, respectively. Ⅲ The script element defines our JavaScript code. Notice that while all our examples until now demonstrated the use of external JavaScript files, you can have your scripts embedded directly in the XUL document. Ⅲ A single label element is used to display a line of text. Obviously, real dialogs often have more complex user interfaces. Once our dialog implementation is ready, we can add it to our chrome package. Let’s name our dialog file testDialog.xul and add it to the siteleds package. We can now open it using the window.openDialog method like so: window.openDialog(“chrome://siteleds/content/testDialog.xul”, “_blank”, “chrome”); The first parameter specifies the URL of the dialog XUL file; the second, the name of the dialog. The third parameter specifies some optional flags — the chrome flag means that the document is a chrome window and doesn’t need to be wrapped by a browser component, like an HTML document, for example. You can specify the modal flag to make the opened dialog modal. Preferences and Persistent Information The preferences mechanism allows the browser to store user modifiable application settings. For example, when a user changes the browser’s home page in the Options dialog, the new value is saved as a user preference. 25_596500 ch17.qxd 6/30/05 3:14 PM Page 362 363 Chapter 17 — Creating Extensions The preference name is typically a dot-delimited list of words. For example, the home page user preference is browser.startup.homepage. You can see each word in the preference name as a branch. For example, all browsing-related preferences are located under the browser main branch, all the preferences that are related to the browser startup are located under the startup subbranch of the browser branch, and so on.This way, all the user preferences can be viewed as a tree (see Figure 17-25). When a new component or an extension creates its own preferences, it should give them a unique main branch name to avoid conflicts. For example, our sample extension might save and use a preference named siteleds.monitor.url. There is a convenient user interface for examining, modifying, and creating preferences. You can open it by typing about:config in your browser address bar. There are three main preference data types: string, integer, and Boolean. Also, each preference can have two optional values: default and current. When the user modifies the default preference value or creates a new preference, the new value is saved as a current value and is highlighted in bold in about:config. When the system tries to retrieve a preference value, it does the following: 1. Checks whether the preference has a current value and, if so, returns it. 2. If there is no current value, it checks whether there is a default value and, if there is, returns it. 3. If neither current nor default value can be found, an exception is thrown. If you are trying to retrieve a preference of a specific type, and a preference having a different type is found, an exception is thrown. For example, if you are trying to retrieve the string value of the user home page preference (browser.startup.homepage ) and a Boolean value is found instead, the call will throw an exception. There are several XPCOM components and interfaces for working with preferences. You can specify the preference names using these interfaces in two ways. You can obtain an interface to the root branch and specify the full preference names (such as browser.startup. homepage ). Alternatively, you can get an interface to a specific subbranch, which will allow you to omit that branch prefix from the preference names. For example, if you are working with the browser branch, you can use the startup.homepage string to access the browser .startup.homepage preference. Here’s how to get an interface to the root branch: var prefs = Components.classes[“@mozilla.org/preferences-service;1”]. getService(Components.interfaces.nsIPrefBranch); After we have the root branch, we can access a preference by specifying its full name: var homePage = prefs.getCharPref(“browser.startup.homepage”); If we want to work with a specific subbranch, we can use the getBranch method of the nsIPrefService interface: var prefs = Components.classes[“@mozilla.org/preferences-service;1”]. getService(Components.interfaces.nsIPrefService); var prefsBranch = prefs.getBranch(“browser.”); 25_596500 ch17.qxd 6/30/05 3:14 PM Page 363 F IGURE 17-25: Some of the preferences viewed as a tree foreground-color background-color page homepage period url root browser siteleds monitor startup display 25_596500 ch17.qxd 6/30/05 3:14 PM Page 364 365 Chapter 17 — Creating Extensions Now we can omit the browser prefix from all the preference names: var homePage = prefsBranch.getCharPref(“startup.homepage”); To modify a preference or create a new one, you can use one of the setCharPref, setBoolPref, or setIntPref methods (for string, Boolean, and integer preferences, respectively). For example, the following changes the user’s home page preference ( prefsBranch should contain a reference to the browser branch): prefsBranch.setCharPref(“startup.homepage”, “http://www.iosart.com/firefox/”); To retrieve a preference value, you can use one of the getCharPref, getBoolPref,or getIntPref methods. As mentioned earlier, the methods that retrieve preference values can throw exceptions if the preference is not found or has the wrong type. You can use the prefHasUserValue and getPrefType methods of the nsIPrefBranch interface to make sure that the preference exists and has the expected type or you can wrap your preference retrieval calls in try/catch JavaScript blocks. A related Mozilla mechanism allows saving the state of XUL elements across browser sessions. For example, a dialog can remember its size, so if the user resizes it, the correct size will be retained even after the browser is restarted. One way to accomplish this is to manually save the current state of the various elements as user preferences. Mozilla has a persistence mechanism that greatly simplifies this task. The following will make the size of a dialog persistent: <dialog xmlns=”http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul” id=”test-dialog” title=”Test Dialog” buttons=”accept,cancel” ondialogaccept=”return dialogOK();” ondialogcancel=”return dialogCancel();” width=”400” height=”200” persist=”width height”> We have added a new persist attribute to our dialog element and specified a space- delimited list of element attributes that we want to be saved. Now, each time these attributes change (the dialog is resized), their new values are saved by the browser. Next time the dialog is displayed, the width and height attributes will receive the saved values, rather than the initial ones. You can use the data persistence mechanism on any XUL element that has an id attribute. The mechanism is typically used to save element visibility, position, size, and so on, but you can make any attribute persistent, and any number of element attributes can be saved using this technique. Localized Strings in JavaScript As mentioned in the previous sections, all the strings that are displayed to the user should be defined in a separate string table file, which will allow easy translation of the user interface. You saw how this can be accomplished in XUL files using XML entities and DTD files. 25_596500 ch17.qxd 6/30/05 3:14 PM Page 365 366 Part VI — Creating Extensions and Themes Often, element labels and other displayed strings aren’t static; they can change during the pro- gram execution. For example, a status bar can display many different messages, and the text of these messages is typically set by a JavaScript code. A mechanism similar to XML entities is needed so the messages and strings that originate in JavaScript can be easily localized. JavaScript isn’t an XML language. Unlike XUL, it cannot use XML entities to specify string variables. Mozilla has an additional mechanism called property files that allows having variable localizable strings in JavaScript. Let’s extend our SiteLeds example to include this mechanism. First, we define a property file that is located in the same directory as our siteledsOverlay.dtd file and contains all the UI strings that need to be accessed from JavaScript. The contents of the siteledsOverlay.properties file are as follows: pageModified=The monitored page was modified. pageError=There was an error retrieving the monitored page. Now we include the property file we have created in our XUL document ( siteledsOverlay.xul) using a stringbundle element: . . . <!DOCTYPE overlay SYSTEM “chrome://siteleds/locale/siteledsOverlay.dtd”> <overlay id=”siteleds-overlay” xmlns=”http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul”> <script type=”application/x-javascript” src=”chrome://siteleds/content/siteledsOverlay.js”/> <stringbundle id=”siteleds-strings” src=”chrome://siteleds/locale/siteledsOverlay.properties”/> . . . Finally, we can get a specific string from our JavaScript code by finding the stringbundle element and calling its getString method: var stringBundle = document.getElementById(“siteleds-strings”); var pageErrorString = stringBundle.getString(“pageError”); alert(pageErrorString); To translate the user interface, you will need to translate all the DTD and property files. Firefox Customization Options This section shows some additional examples of how Firefox can be customized and enhanced using the extensions mechanism. Adding Main Menu and Context Menu Entries An extension can add menu entries to the main Firefox menu and to the context menu of the browser content area (the place where the web pages are displayed). 25_596500 ch17.qxd 6/30/05 3:14 PM Page 366 367 Chapter 17 — Creating Extensions First, let’s add a new menu entry to the browser Tools menu using a dynamic overlay. With the help of the DOM Inspector, we can find out that the id of the Firefox Tools menupopup element is menu_ToolsPopup. We can add the following to our overlay: <menupopup id=”menu_ToolsPopup”> <menuitem id=”my-menu-item” label=”My Menu Item” accesskey=”y” insertbefore=”menu_preferences” oncommand=”alert(‘Testing 1 2 3’);”/> </menupopup> The new menu item is shown in Figure 17-26. F IGURE 17-26: The new menu item You can control the exact position of the new menu item in the overlaid menu by specifying insertafter, insertbefore, or the position attributes of the new element. You can add menu items to the context area menu by overlaying the contentAreaContextMenu element: <menupopup id=”contentAreaContextMenu”> <menuitem id=”my-context-menu-item” label=”My Context Menu Item” accesskey=”y” oncommand=”alert(‘Context Testing 1 2 3’);”/> </menupopup> 25_596500 ch17.qxd 6/30/05 3:14 PM Page 367 368 Part VI — Creating Extensions and Themes You can dynamically determine whether to make your new menu item visible: 1. Add an initialization function that will be called when the Firefox window is loaded along with your overlay: window.addEventListener(“load”, initMyOverlay, false); 2. In the initialization function, attach a popupshowing event handler to the contentAreaContextMenu menu: function initMyOverlay() { var contextMenu = document.getElementById(“contentAreaContextMenu”); contextMenu.addEventListener(“popupshowing”, myContextPopupshowing, false); } This handler will be called every time the context menu is about to become visible. 3. In the myContextPopupshowing handler, test some condition and set the visibility of your menu item accordingly: function myContextPopupshowing() { var contextMenuItem = document.getElementById(“my-context-menu-item”); if (contextMenuItem) { contextMenuItem.hidden = !gContextMenu.isTextSelected; } } The preceding code shows our new menu item in the context menu only if some text is selected on the web page. As you can see, we first find our menu item using the DOM getElementById method. We then determine whether some text is selected by exam- ining the isTextSelected property of the global gContextMenu object and hide our menu item if no text is selected. The gContextMenu object has several useful methods and properties that can help you determine whether your menu item is appro- priate for a given context. Some examples follow: ■ target: The element on which the user clicked to open the context menu. ■ isTextSelected: Determines whether there is some text selected on the web page. ■ onLink, onTextInput, onImage, onTextInput: Allow you to determine the type of element that the context menu was opened on. ■ linkText(), linkURL(): If onLink is true, provides additional information about the link element that the context menu was opened on. Adding Keyboard Shortcuts In XUL, shortcut keys are defined using the key element. Several key elements are typically grouped in a keyset element. The Firefox keyboard shortcuts are defined in a keyset ele- ment that has an id of mainKeyset. You can overlay this element to create additional key- board shortcuts. For example, you can add the following to your dynamic overlay: 25_596500 ch17.qxd 6/30/05 3:14 PM Page 368 369 Chapter 17 — Creating Extensions <keyset id=”mainKeyset”> <key id=”my-key-test” key=”T” modifiers=”accel,shift” oncommand=”alert(‘Testing 1 2 3’);”/> </keyset> When the user presses Ctrl+Shift+T (Cmd+Shift+T on Macintosh), the oncommand script is executed. See the key element documentation for further details on specifying shortcuts in Mozilla. When adding new global shortcut keys, you should verify that your keys aren’t conflicting with the existing shortcuts, defined either in Firefox itself or in other popular extensions. It is always a good idea to implement some functionality in your extension that will let the user reconfigure the default extension shortcut keys. In addition, similar to text strings, it is recommended to define shortcut keys as XML entities rather than directly in the XUL file. Shortcut keys often correspond to the name of the action (for example, Ctrl+S for Save). If the extension is translated into another language, the default short- cuts may no longer make sense. If the shortcuts are specified inside a DTD file along with the other strings, they can be easily modified to correspond to the translated name of the action. Adding Toolbars and Toolbar Buttons A toolbar is created using the toolbar XUL element. All Firefox toolbars are located inside a single toolbox element. The id of this element is navigator-toolbox, and by overlaying it, we can add a custom browser toolbar, as demonstrated in the following example: <toolbox id=”navigator-toolbox”> <toolbar id=”my-test-toolbar” class=”chromeclass-toolbar” toolbarname=”My Test Toolbar” accesskey=”T” context=”toolbar-context-menu” hidden=”false” persist=”hidden”> <toolbarbutton id=”my-toolbar-button-1” tooltiptext=”First Button” label=”Button 1” oncommand=”alert(‘Testing Button 1’);”/> <toolbarbutton id=”my-toolbar-button-2” tooltiptext=”Second Button” label=”Button 2” oncommand=”alert(‘Testing Button 2’);”/> </toolbar> </toolbox> Let’s take a closer look at what we have done: Ⅲ We created a toolbox element with navigator-toolbox id in our overlay. The specified id attribute ensures that this toolbox will overlay the main Firefox toolbox and our toolbar will be added to the browser. 25_596500 ch17.qxd 6/30/05 3:14 PM Page 369 370 Part VI — Creating Extensions and Themes Ⅲ The toolbar element defines our new toolbar. Let’s examine its attributes: ■ class: The chromeclass-toolbar class specifies that the XUL element should be styled as a standard Firefox toolbar. ■ toolbarname: The name of the toolbar as it appears in the View ➪ Toolbars menu. ■ accesskey: The keyboard key that can be used to trigger the toolbar visibility in the Toolbars menu.The specified letter will be underlined, similar to other menu keyboard shortcuts. ■ context: The id of the context menu that appears when the user right-clicks over the toolbar. You can create your own custom menu or specify toolbar- context-menu , which is the id of the default Firefox context menu that allows toggling the visibility of the various toolbars. ■ hidden: The value of false specifies that the toolbar is initially visible. ■ persist: By setting this attribute to hidden, we are instructing the browser to remember the visibility state of our toolbar across sessions. Ⅲ Inside the toolbar element, we have defined a couple of toolbar buttons. As we men- tioned earlier, the toolbarbutton element is similar to a regular button but typically has a different style. In addition to toolbar buttons, we can place any elements on our toolbar (checkboxes, text boxes, drop-down lists, and so on). Figure 17-27 shows our new toolbar. F IGURE 17-27: A simple toolbar If you want to add a single toolbar button rather than a complete toolbar, you must use a slightly different technique. In Firefox, the user can customize a toolbar by choosing View ➪ Toolbars ➪ Customize and dragging the wanted toolbar buttons and other elements from the toolbar palette to the target location. By adding our toolbar button to the customization palette, we can allow the user to later add this button to one of the toolbars. It is possible to add a toolbar button directly to one of the browser toolbars, rather than to the customization palette, but this requires a somewhat more complex technique. 25_596500 ch17.qxd 6/30/05 3:14 PM Page 370 371 Chapter 17 — Creating Extensions To add our toolbarbutton to the customization palette, we need to overlay the Firefox main toolbarpalette element, which has an id of BrowserToolbarPalette: <toolbarpalette id=”BrowserToolbarPalette”> <toolbarbutton id=”my-toolbar-button-3” class=”toolbarbutton-1” tooltiptext=”Third Button” label=”Button 3” oncommand=”alert(‘Testing Button 3’);”/> </toolbarpalette> We have set the class of our toolbarbutton element to toolbarbutton-1. This ensures that the button will be displayed correctly in both Icons and Text toolbar modes. We now want to specify an icon for our toolbarbutton. Because toolbars can have two sizes, big and small, we will have to define two icons for our toolbar button. The big icon is 24 × 24 pixels, and the small one is 16 × 16 pixels. Let’s look at the style sheet that defines the toolbar button icon: #my-toolbar-button-3 { list-style-image: url(“chrome://my-extension/skin/button_3_large.png”); } toolbar[iconsize=”small”] #my-toolbar-button-3 { list-style-image: url(“chrome://my-extension/skin/button_3_small.png”); } As you can see, the iconsize attribute of the parent toolbar element determines whether the small or the large icons are displayed. Changing the Appearance of Web Pages An extension can modify the appearance of web pages that are loaded into the browser content area. You can define an event handler function that will be called each time a new web page is loaded. In this function, you can examine and modify the DOM structure of the loaded page. This is accomplished with the following steps: 1. Add an initialization function that will be called when the Firefox window is loaded along with your overlay: window.addEventListener(“load”, initMyOverlay, false); 2. In the initialization function, find the browser content element using its id ( appconten) and attach a load event handler to it: function initMyOverlay() { var appContent = document.getElementById(“appcontent”); appContent.addEventListener(“load”, myNewWebPageLoaded, true); } 25_596500 ch17.qxd 6/30/05 3:14 PM Page 371 . icon: #my-toolbar-button-3 { list-style-image: url(“chrome://my-extension/skin/button_3_large.png”); } toolbar[iconsize=”small”] #my-toolbar-button-3 { list-style-image: url(“chrome://my-extension/skin/button_3_small.png”); } As. persist=”hidden”> <toolbarbutton id=”my-toolbar-button-1” tooltiptext=”First Button” label=”Button 1” oncommand=”alert(‘Testing Button 1’);”/> <toolbarbutton id=”my-toolbar-button-2” tooltiptext=”Second. example: <toolbox id=”navigator-toolbox”> <toolbar id=”my-test-toolbar” class=”chromeclass-toolbar” toolbarname=”My Test Toolbar” accesskey=”T” context=”toolbar-context-menu” hidden=”false”

Ngày đăng: 04/07/2014, 17:20

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan