Adding Events and Commands

Event handlers

Just like with HTML, most JavaScript code execution is triggered by event handlers attached to DOM elements. The most commonly used event is the onload event, which is used in overlays and other windows to detect when the window has loaded and then run initialization code:

就像使用HTML,最JavaScript代码的执行被附加到DOM元素的事件处理程序启动。最常用的事件是onload事件,这是用来在覆盖和其他窗口来检测窗口加载并运行初始化代码:

// rest of overlay code goes here.
window.addEventListener(
  "load", function() { XulSchoolChrome.BrowserOverlay.init(); }, false);

You can do something similar with the onunload event, to do any cleanup you may need.

你可以做的onunload事件类似的东西,做你所需要的任何清理。

Please read Appendix A for recommendations on how to use the load event to initialize your add-on without having a negative performance impact on Firefox.
请参阅附录A有关如何使用load事件来初始化加载,而不必在Firefox负面性能影响的建议。

Another way to attach event handlers, just like HTML, is to place the handler in the XUL code:

另一种附加事件处理程序,就像HTML,是将处理程序中的XUL代码:

<overlay id="xulschoolhello-browser-overlay"
  onload="XulSchoolChrome.BrowserOverlay.init();"
  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

We prefer the first method because it keeps a better separation of content and behavior. Also, note that the addEventListener method receives the event name without the "on" prefix, while element attributes do have the prefix. There's a long list of events you can listen to, and which you use depend on the situation. Elements only implement the events that are relevant to them, but there are several events that are implemented for most elements. These are some notable events you should keep in mind:

我们倾向于第一种方法,因为它保留了较好的分离的内容和行为。此外,请注意addEventListener方法接收事件名称没有“on”前缀,而元素的 属性是有前缀。有活动,你可以听一个长长的清单,并使用视乎情况而定。元素只实现那些与他们相关的事件,但也有被实现为大多数元素的几个事件。这些都是一 些著名的事件,你应该记住:

  • oncommand. This is one of the most important and commonly used events in XUL. It's very useful because it represents the most common action for input controls such as menu items, buttons and checkboxes. For a button, it represents the action of the user clicking on it, or focusing it with the keyboard and then pressing the ENTER key. It's an abstraction of the main way to interact with a control element.
  • oncommand. 这是在XUL最重要和最常用的事件之一。这是非常有用的,因为它代表了输入控件,如菜单项,按钮和复选框中最常见的动作。对于一个按钮,它代表用户点击就可以了作用,还是注重它的键盘,然后按ENTER键。它的主要方式有控制元件进行交互的抽象。
  • onselect. Fired when the selection in a tree or listbox changes.
  • onselect. 发射时的选择在树上或列表框的变化。
  • onclick. Triggered when the user clicks on the element, including right clicks. You shouldn't normally use this event to trigger actions on input controls such as buttons. Use oncommand instead.
  • onclick. 当用户单击该元素上,包括右点击触发。通常你不应该使用这个事件来触发输入控件,如按钮的动作。使用按需代替。
  • onfocus and onblur. Used when an element receives or loses focus when the user is navigating with the keyboard. You can combine these with -moz-user-focus to add custom focus behavior to elements that normally wouldn't have it.
  • onfocusonblur. 当一个元素是获得还是失去,当用户浏览带有键盘焦点使用。你可以用-moz-user-focus结合这些来添加自定义焦点的行为,通常不会有它的元素。
  • Drag and drop. Drag and drop operations involve several events. Since drag and drop is a complicated thing to manage, there are some high level wrappers that facilitate working with it. Also keep in mind that there are 2 drag and drop APIs, the newest (and preferred) one introduced in Firefox 3.5.
  • Drag and drop.  拖放操作涉及多个事件。由于拖放是一个复杂的事情来管理,也有一些高层次的包装,以促进与它一起工作。同时请记住,有2拖放的API,最新的(和首选)一名在Firefox 3.5中引入。

Event handlers can take an event argument, which is an Event object that holds information on the event. You can get information on key modifiers (in case the user was holding a modifier key like Alt while performing the event), screen coordinates for mouse events, and most importantly, the target element for the event. For example:

事件处理程序可以把一个事件的说法,这是保存在事件信息的Event对象。你可以在关键修饰符的信息(如果用户正拿着像是Alt修饰键,同时执行的情况下),屏幕坐标的鼠标事件,最重要的是,该事件的目标元素。例如:

<button label="&xulschoolhello.defaultGreeting.label;"
  oncommand="XulSchoolChrome.BrowserOverlay.changeGreeting(event);" />

Then on the Javascript code you would have something like this:

changeGreeting : function(aEvent) {
  // more stuff
  aEvent.target.setAttribute("label", someNewGreeting);
}

The target in this example is the button element, so clicking on it will change its text. The advantage of using the event argument is that the method is not dependent of the specific button, so it can also be used for other elements.

For more advanced event handling, you should read about Event Propagation. In a nutshell, events propagate from the root of the DOM tree all the way down to the target element and then all the way up back to the root, in the capture and bubble phases, respectively. You can capture and cancel events during any of these phases, provided that they aren't canceled before they reach the point where you intended to capture them. The addEventListener method allows you to control the phase where you want to handle an event, with the last argument of the function.

In general, you should avoid adding event handlers in the capturing phase, or canceling events. This can lead to unexpected behavior for the user since most events have a default behavior associated to them.

Custom events

This is a very powerful tool that you should know, even if it isn't that frequently used. The DOM createEvent function allows you to create custom events that you can dispatch and capture.

Custom events serve as a good communication mechanism, specially when dealing with a somewhat common problem: communication between window XUL and web page content. It isn't hard for XUL code to control the content on pages being loaded or displayed, as we will see later on, but it can be hard for your extension XUL code to receive information from pages in a secure manner. This is because it would be very insecure to have a website JS controlling the behavior of Firefox and running JavaScript code with chrome privileges.

Suppose your extension interacts with pages from a website, and you want some actions on this site to trigger actions in your extension. One way to solve this is to have the actions on the site to generate a custom event that can be easily recognized by your extension. You can capture the events in the XUL  overlay, since they'll bubble all the way up:

// in the overlay code.
document.addEventListener(
  "XSHelloGreetingEvent", function(aEvent) { /* do stuff*/ }, false);

Be careful when doing this! You should at least validate the URL of the page that is generating the custom event, so that you know that it's coming from the right place. You should also avoid this kind of events to trigger actions that could be destructive to the user's data, because a malicious site could try to trigger these events and cause damage. There's a reason for the division between remote content and local chrome, so make sure you respect it.

There's a section further ahead on Intercepting Page Loads which complements this section very well. This should give you a solid foundation to handle interaction between web content and XUL.  Additional information on custom events and how they can be used to effect communication between web content and XUL can be found in the Interaction between privileged and non-privileged pages code snippets, which describe and provide examples of this sort of communication.

Broadcasters

Keeping a consistent UI is another important aspect of extension behavior. Maybe your extension needs to disable or enable a series of controls when the user logs in or out of a service, or when Firefox detects it's online or offline. It's common that you need to change several elements at the same time, and this can be difficult to manage through JavaScript. The broadcaster element can help you out in these cases.

First you need to add a broadcaster element to your XUL code, as a child of a broadcasterset element.

<broadcasterset id="xulschoolhello-broadcasterset">
  <broadcaster id="xulschoolhello-online-broadcaster" />
</broadcasterset>

These elements are completely invisible, so you can put them anywhere. It is recommended that you have them at the top of the XUL code, along with script declarations and other invisible elements with as popupset and commandset.

Then you need to identify which of your XUL elements will be linked to this broadcaster, using the observes attribute:

<menuitem id="xulschoolhello-hello-menu-item"
  label="&xulschoolhello.hello.label;"
  accesskey="&xulschoolhello.helloItem.accesskey;"
  observes="xulschoolhello-online-broadcaster"
  oncommand="XULSchoolChrome.BrowserOverlay.sayHello(event);" />

The attribute value is set to be the id of the broadcaster element, indicating that this element will observe all attribute changes that happen in the broadcaster. You can have as many elements as you want observing a broadcaster.

With that set, all you need to do now is set or remove attributes in the broadcaster using JavaScript. All nodes observing it will automatically have those attribute values set or removed as well. You can override pre-existing values, such as the label attribute value in the example.

let onlineBroadcaster = document.getElementById("xulschoolhello-online-broadcaster");

onlineBroadcaster.setAttribute("label", "Something");

You can also have finer-grained control to this behavior by adding the observes element as a child to your observer node. This allows you to choose which attributes you want it to observe.

Broadcasters allow you to easily maintain consistency among numerous elements without having to add much code. They also save you the trouble of having to know if a given element is present in the DOM or not. For example, if you have a customizable toolbar, you can't be sure if a given button is present or not, so it's easier to use a broadcaster. This way you only need to set values to the broadcaster instead of having to check if the button is there or not.

Commands

The command element is a specialized type of broadcaster, meant to be used with the oncommand event. This is the recommended way of centralizing common UI behavior in Firefox and extensions. Commands are heavily used in Firefox, as a quick look into the DOM Inspector should show.

Their behavior is identical as broadcaster elements, but they should be used when oncommand is one of the shared attributes. Our menu example is in fact better suited for a command.

<commandset id="xulschoolhello-commandset">
  <command id="xulschoolhello-hello-command"
    oncommand="XULSchoolChrome.BrowserOverlay.sayHello(event);" />
  <!-- More commands. -->
</commandset>
<!-- More code here... -->
<menuitem id="xulschoolhello-hello-menu-item"
  label="&xulschoolhello.hello.label;"
  accesskey="&xulschoolhello.helloItem.accesskey;"
  command="xulschoolhello-hello-command" />

Commands allow you to keep your JavaScript calls in a single place, avoiding code repetition and possible bugs. Your UI can easily scale this way. You can create an extension that adds toolbar buttons, statusbar buttons and menu items, all with equivalent behavior, and without having to repeat lots of XUL code in the process. Commands and broadcasters also facilitate working with complex form windows and dialogs. You should always keep them in mind when adding the event-driven code for your extension.

This tutorial was kindly donated to Mozilla by Appcoast.

文档标签和贡献者

 此页面的贡献者: ziyunfei, mponeto
 最后编辑者: ziyunfei,