forked from mirrors/gecko-dev
		
	 61c60113b7
			
		
	
	
		61c60113b7
		
	
	
	
	
		
			
			Differential Revision: https://phabricator.services.mozilla.com/D18463 --HG-- rename : dom/html/htmlMenuBuilder.js => dom/html/HTMLMenuBuilder.jsm extra : source : 1e75ce91029b4eb030071e9802cd0bdbad59b9cf
		
			
				
	
	
		
			132 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			132 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| // This component is used to build the menus for the HTML contextmenu attribute.
 | |
| 
 | |
| // A global value that is used to identify each menu item. It is
 | |
| // incremented with each one that is found.
 | |
| var gGeneratedId = 1;
 | |
| 
 | |
| function HTMLMenuBuilder() {
 | |
|   this.currentNode = null;
 | |
|   this.root = null;
 | |
|   this.items = {};
 | |
|   this.nestedStack = [];
 | |
| };
 | |
| 
 | |
| // Building is done in two steps:
 | |
| // The first generates a hierarchical JS object that contains the menu structure.
 | |
| // This object is returned by toJSONString.
 | |
| //
 | |
| // The second step can take this structure and generate a XUL menu hierarchy or
 | |
| // other UI from this object. The default UI is done in PageMenu.jsm.
 | |
| //
 | |
| // When a multi-process browser is used, the first step is performed by the child
 | |
| // process and the second step is performed by the parent process.
 | |
| 
 | |
| HTMLMenuBuilder.prototype =
 | |
| {
 | |
|   classID:        Components.ID("{51c65f5d-0de5-4edc-9058-60e50cef77f8}"),
 | |
|   QueryInterface: ChromeUtils.generateQI([Ci.nsIMenuBuilder]),
 | |
| 
 | |
|   currentNode: null,
 | |
|   root: null,
 | |
|   items: {},
 | |
|   nestedStack: [],
 | |
| 
 | |
|   toJSONString: function() {
 | |
|     return JSON.stringify(this.root);
 | |
|   },
 | |
| 
 | |
|   openContainer: function(aLabel) {
 | |
|     if (!this.currentNode) {
 | |
|       this.root = {
 | |
|         type: "menu",
 | |
|         children: []
 | |
|       };
 | |
|       this.currentNode = this.root;
 | |
|     }
 | |
|     else {
 | |
|       let parent = this.currentNode;
 | |
|       this.currentNode = {
 | |
|         type: "menu",
 | |
|         label: aLabel,
 | |
|         children: []
 | |
|       };
 | |
|       parent.children.push(this.currentNode);
 | |
|       this.nestedStack.push(parent);
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   addItemFor: function(aElement, aCanLoadIcon) {
 | |
|     // Since we no longer type check this at the IDL level, make sure we've got
 | |
|     // the right element type here.
 | |
|     if (ChromeUtils.getClassName(aElement) !== "HTMLMenuItemElement") {
 | |
|       return;
 | |
|     }
 | |
|     if (!("children" in this.currentNode)) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     let item = {
 | |
|       type: "menuitem",
 | |
|       label: aElement.label
 | |
|     };
 | |
| 
 | |
|     let elementType = aElement.type;
 | |
|     if (elementType == "checkbox" || elementType == "radio") {
 | |
|       item.checkbox = true;
 | |
| 
 | |
|       if (aElement.checked) {
 | |
|         item.checked = true;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     let icon = aElement.icon;
 | |
|     if (icon.length > 0 && aCanLoadIcon) {
 | |
|       item.icon = icon;
 | |
|     }
 | |
| 
 | |
|     if (aElement.disabled) {
 | |
|       item.disabled = true;
 | |
|     }
 | |
| 
 | |
|     item.id = gGeneratedId++;
 | |
|     this.currentNode.children.push(item);
 | |
| 
 | |
|     this.items[item.id] = aElement;
 | |
|   },
 | |
| 
 | |
|   addSeparator: function() {
 | |
|     if (!("children" in this.currentNode)) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     this.currentNode.children.push({ type: "separator"});
 | |
|   },
 | |
| 
 | |
|   undoAddSeparator: function() {
 | |
|     if (!("children" in this.currentNode)) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     let children = this.currentNode.children;
 | |
|     if (children.length && children[children.length - 1].type == "separator") {
 | |
|       children.pop();
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   closeContainer: function() {
 | |
|     this.currentNode = this.nestedStack.length ? this.nestedStack.pop() : this.root;
 | |
|   },
 | |
| 
 | |
|   click: function(id) {
 | |
|     let item = this.items[id];
 | |
|     if (item) {
 | |
|       item.click();
 | |
|     }
 | |
|   }
 | |
| };
 | |
| 
 | |
| var EXPORTED_SYMBOLS = ["HTMLMenuBuilder"];
 |