Confirmed users
764
edits
m (→Use Cases) |
(Updated after talking with Myk) |
||
Line 54: | Line 54: | ||
==== add ==== | ==== add ==== | ||
<tt>add( | <tt>add(menuitem)</tt> | ||
Adds an item to the context menu. The position at which the item is inserted is at the discretion of Jetpack. | Adds an item to the context menu. The position at which the item is inserted is at the discretion of Jetpack. | ||
; menuitem: The menuitem to add. See [[#Creating New Menuitems]]. | |||
; menuitem: The menuitem to add. See [[# | |||
==== insertBefore ==== | ==== insertBefore ==== | ||
<tt>insertBefore( | <span style="background-color: #fcc;"><em>This part of the proposal is under review.</em></span> | ||
<tt>insertBefore(target, menuitem)</tt> | |||
Inserts a new item before an existing one. If the target item does not exist, this function silently fails, and the context menu not modified. | Inserts a new item before an existing one. If the target item does not exist, this function silently fails, and the context menu not modified. | ||
; target: A value describing the existing item before which to insert the new item. See [[#Specifying Existing Menuitems]]. | ; target: A value describing the existing item before which to insert the new item. See [[#Specifying Existing Menuitems]]. | ||
; menuitem: The menuitem to add. See [[# | ; menuitem: The menuitem to add. See [[#Creating New Menuitems]]. | ||
==== remove ==== | ==== remove ==== | ||
Line 75: | Line 75: | ||
<tt>remove(item)</tt> | <tt>remove(item)</tt> | ||
Permanently removes an item previously added to the context menu. This method should not be used to temporarily remove | Permanently removes an item previously added to the context menu. This method should not be used to temporarily remove an item under particular contexts; for that, set an appropriate context when creating the item. See [[#Specifying Contexts]]. | ||
; item: A menuitem that was previously created and added to the menu. See [[# | ; item: A menuitem that was previously created and added to the menu. See [[#Creating New Menuitems]]. | ||
==== replace ==== | ==== replace ==== | ||
<tt>replace( | <span style="background-color: #fcc;"><em>This part of the proposal is under review.</em></span> | ||
<tt>replace(target, menuitem)</tt> | |||
Replaces an existing item in the context menu. If the target item does not exist, this function silently fails, and the context menu is not modified. | Replaces an existing item in the context menu. If the target item does not exist, this function silently fails, and the context menu is not modified. | ||
; target: A value describing the existing item to replace. See [[#Specifying Existing Menuitems]]. | ; target: A value describing the existing item to replace. See [[#Specifying Existing Menuitems]]. | ||
; menuitem: The menuitem to add. See [[# | ; menuitem: The menuitem to add. See [[#Creating New Menuitems]]. | ||
=== Specifying Contexts === | === Specifying Contexts === | ||
Items should be added to the context menu, as its name implies, only when some particular context arises. Context can be related to page content or the page itself, but it should never be external to the page. (See [[#Non-Use Cases]] for examples.) | |||
Contexts may be specified with any of the following types: | Contexts may be specified with any of the following types: | ||
Line 103: | Line 102: | ||
; function: An arbitrary predicate. The context arises when the function returns true. The function is called with no arguments. | ; function: An arbitrary predicate. The context arises when the function returns true. The function is called with no arguments. | ||
=== | Instead of requiring consumers to manually add and remove items when particular contexts arise, this proposal introduces the notion that items are bound to one or more contexts, much as event listeners are bound to events. This binding occurs through an item's <tt>context</tt> property. When the context menu is invoked, all of the items bound to the context giving rise to the menu are added to the menu. If no items are bound to the context, no items are added to the menu. | ||
The <tt>context</tt> property is a collection, similar to event listener collections common throught Jetpack's various APIs. A single context may be bound by assigning one of the above types to the <tt>context</tt> property either on construction or after: | |||
<pre class="brush:js;toolbar:false;"> | |||
var item = new contextMenu.Item({ context: "img" }); | |||
item.context = "img"; | |||
</pre> | |||
New menuitems are created using | Multiple contexts may be bound by assigning an array of contexts either on construction or after: | ||
<pre class="brush:js;toolbar:false;"> | |||
var item = new contextMenu.Item({ context: ["img", "a[href]"] }); | |||
item.context = ["img", "a[href]"]; | |||
</pre> | |||
Contexts may also be bound by calling the collection's <tt>add</tt> method, which takes a single context or array of contexts: | |||
<pre class="brush:js;toolbar:false;"> | |||
item.context.add("img"); | |||
item.context.add(["img", "a[href]"]); | |||
</pre> | |||
Finally, contexts may be unbound by calling the collection's <tt>remove</tt> method, which takes a single context or array of contexts : | |||
<pre class="brush:js;toolbar:false;"> | |||
item.context.remove("img"); | |||
item.context.remove(["img", "a[href]"]); | |||
</pre> | |||
When an item is bound to more than one context, it is added to menus arising from any of those contexts. | |||
=== Creating New Menuitems === | |||
New menuitems are created using one of the constructors exported by the module, <tt>Item</tt>, <tt>Menu</tt>, and <tt>Separator</tt>. | |||
==== Item ==== | ==== Item ==== | ||
Line 111: | Line 142: | ||
<tt>Item(options)</tt> | <tt>Item(options)</tt> | ||
The <tt>Item</tt> constructor creates new menuitems. | The <tt>Item</tt> constructor creates new, simple menuitems. | ||
; options: An object that defines | ; options: An object that defines the following properties: | ||
<blockquote> | <blockquote> | ||
; | ; context: If the item is added to the top-level context menu, this specifies the context under which the item will appear. See [[#Specifying Contexts]]. This property is ignored if the item is contained in a submenu. | ||
; data: An optional, arbitrary string that the extension may associate with the menuitem. | |||
; | ; icon: The URL of an icon to display in the menuitem. Optional. Note that some environments, [https://bugzilla.mozilla.org/show_bug.cgi?id=527253 notably Gnome 2.28], do not support menuitem icons either by default or at all. | ||
; | ; label: The label of the menuitem, a string. | ||
; | ; onCommand: An optional function that will be called when the menuitem is clicked. It is called as <tt>onCommand(contextObj, data)</tt>. <tt>contextObj</tt> is an object describing the context in which the menu was invoked. See [[#Context Descriptions]]. <tt>data</tt> is the <tt>data</tt> property of the item that was selected or <tt>undefined</tt> if the selected item has no data. | ||
</blockquote> | </blockquote> | ||
==== Menu ==== | |||
<tt>Menu(options)</tt> | |||
The <tt>Menu</tt> constructor creates items that expand into submenus. | |||
; icon: The URL of an icon to display in the menuitem. Note that some environments, [https://bugzilla.mozilla.org/show_bug.cgi?id=527253 notably Gnome 2.28], do not support menuitem icons either by default or at all. | ; options: An object that defines the following properties: | ||
<blockquote> | |||
; context: If the item is added to the top-level context menu, this specifies the context under which the item will appear. See [[#Specifying Contexts]]. This property is ignored if the item is contained in a submenu. | |||
; icon: The URL of an icon to display in the menuitem. Optional. Note that some environments, [https://bugzilla.mozilla.org/show_bug.cgi?id=527253 notably Gnome 2.28], do not support menuitem icons either by default or at all. | |||
; items: An array of menuitems. The submenu will contain them. | |||
; label: The label of the menuitem, a string. | ; label: The label of the menuitem, a string. | ||
; | ; onCommand: An optional function that will be called when any of the item's descendents is clicked. (The commands of descendants are invoked first, in a bottom-up, bubbling manner.) It is called as <tt>onCommand(contextObj, data)</tt>. <tt>contextObj</tt> is an object describing the context in which the menu was invoked. See [[#Context Descriptions]]. <tt>data</tt> is the <tt>data</tt> property of the item that was selected or <tt>undefined</tt> if the selected item has no data. | ||
</blockquote> | </blockquote> | ||
Line 145: | Line 188: | ||
The <tt>Separator</tt> constructor creates menu separators. It takes no arguments. | The <tt>Separator</tt> constructor creates menu separators. It takes no arguments. | ||
=== Specifying | === Specifying Existing Menuitems === | ||
<span style="background-color: #fcc;"><em>This part of the proposal is under review.</em></span> | |||
Items that are part of the context menu by default are identified by case-sensitive IDs. These IDs are strings. | |||
=== | TODO: Table of IDs, making up our own where XUL IDs don't exist, are inconsistent, or are ugly. What to do about non-Firefox apps? | ||
=== Context Descriptions === | |||
It would be useful if menuitem commands had a way of examining the context in which they are invoked. For example, a command that downloads images needs to know the URL of the image that the user right-clicked when she opened the context menu. | |||
When a menuitem's command is called, it is passed an object describing the context in which the context menu was invoked. This object has the following properties: | |||
<blockquote> | <blockquote> | ||
; | ; node: The node the user clicked to invoke the menu. | ||
</ | ; document: The document containing <tt>node</tt>, i.e., <tt>node.ownerDocument</tt>. | ||
; window: The window containing <tt>document</tt>, i.e., <tt>node.ownerDocument.defaultView</tt>. | |||
</blockquote> | |||
=== Example Usage === | === Example Usage === | ||
Line 173: | Line 218: | ||
// Add "Edit Image" on images. | // Add "Edit Image" on images. | ||
var imgCssSelector = "img"; | |||
var editImageItem = new contextMenu.Item({ | var editImageItem = new contextMenu.Item({ | ||
label: "Edit Image", | label: "Edit Image", | ||
onCommand: function (context) { | onCommand: function (context) { | ||
editImage(context.node.src); | editImage(context.node.src); | ||
} | }, | ||
context: imgCssSelector | |||
}); | }); | ||
contextMenu.add(editImageItem); | |||
contextMenu.add( | |||
// Replace the "Search" menuitem with a menu that searches Google or | // Replace the "Search" menuitem with a menu that searches Google or | ||
// Wikipedia when there is selected text. | // Wikipedia when there is selected text. | ||
var | // | ||
// NOTE: The API used by this example is under review. | |||
var selection = require("selection"); | |||
function selectionExists() { | |||
return !!selection.text; | |||
} | |||
var searchMenu = new contextMenu.Menu({ | |||
label: "Search", | |||
onCommand: function (context, data) { | |||
context.window.location.href = data + selection.text; | |||
}, | |||
context: selectionExists, | |||
items: [ | items: [ | ||
new contextMenu.Item({ | new contextMenu.Item({ | ||
Line 196: | Line 253: | ||
] | ] | ||
}); | }); | ||
contextMenu.replace("context-searchselect", searchMenu); | |||
contextMenu.replace( | |||
// Add "Edit Page Source" when the menu is invoked on a | // Add "Edit Page Source" when the menu is invoked on a | ||
Line 215: | Line 261: | ||
onCommand: function (context) { | onCommand: function (context) { | ||
editSource(context.document.URL); | editSource(context.document.URL); | ||
} | }, | ||
context: null | |||
}); | }); | ||
contextMenu.add( | contextMenu.add(pageSourceItem); | ||
// Add "Edit Page Images" when the page contains at least one image. | // Add "Edit Page Images" when the page contains at least one image. | ||
function pageHasImages(context) { | |||
return !!context.document.querySelector("img"); | |||
} | |||
var editImagesItem = new contextMenu.Item({ | var editImagesItem = new contextMenu.Item({ | ||
label: "Edit Page Images", | label: "Edit Page Images", | ||
Line 225: | Line 275: | ||
var imgNodes = context.document.querySelectorAll("img"); | var imgNodes = context.document.querySelectorAll("img"); | ||
editImages(imgNodes); | editImages(imgNodes); | ||
} | }, | ||
context: pageHasImages | |||
}); | }); | ||
contextMenu.add(editImagesItem); | |||
contextMenu.add( | |||
</pre> | </pre> | ||
=== Issues === | === Issues === | ||
* [[# | * [[#Creating New Menuitems|Icons]]: Icon URLs should be able to point to resources in the XPI. How? |