forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			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(["nsIMenuBuilder"]),
 | 
						|
 | 
						|
  currentNode: null,
 | 
						|
  root: null,
 | 
						|
  items: {},
 | 
						|
  nestedStack: [],
 | 
						|
 | 
						|
  toJSONString() {
 | 
						|
    return JSON.stringify(this.root);
 | 
						|
  },
 | 
						|
 | 
						|
  openContainer(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(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() {
 | 
						|
    if (!("children" in this.currentNode)) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    this.currentNode.children.push({ type: "separator" });
 | 
						|
  },
 | 
						|
 | 
						|
  undoAddSeparator() {
 | 
						|
    if (!("children" in this.currentNode)) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    let children = this.currentNode.children;
 | 
						|
    if (children.length && children[children.length - 1].type == "separator") {
 | 
						|
      children.pop();
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  closeContainer() {
 | 
						|
    this.currentNode = this.nestedStack.length
 | 
						|
      ? this.nestedStack.pop()
 | 
						|
      : this.root;
 | 
						|
  },
 | 
						|
 | 
						|
  click(id) {
 | 
						|
    let item = this.items[id];
 | 
						|
    if (item) {
 | 
						|
      item.click();
 | 
						|
    }
 | 
						|
  },
 | 
						|
};
 | 
						|
 | 
						|
var EXPORTED_SYMBOLS = ["HTMLMenuBuilder"];
 |