• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5cr.define('cr.ui', function() {
6  /** @const */ var Command = cr.ui.Command;
7
8  /**
9   * Creates a new menu item element.
10   * @param {Object=} opt_propertyBag Optional properties.
11   * @constructor
12   * @extends {HTMLDivElement}
13   */
14  var MenuItem = cr.ui.define('div');
15
16  /**
17   * Creates a new menu separator element.
18   * @return {cr.ui.MenuItem} The new separator element.
19   */
20  MenuItem.createSeparator = function() {
21    var el = cr.doc.createElement('hr');
22    MenuItem.decorate(el);
23    return el;
24  };
25
26  MenuItem.prototype = {
27    __proto__: HTMLButtonElement.prototype,
28
29    /**
30     * Initializes the menu item.
31     */
32    decorate: function() {
33      var commandId;
34      if ((commandId = this.getAttribute('command')))
35        this.command = commandId;
36
37      this.addEventListener('mouseup', this.handleMouseUp_);
38
39      // Adding the 'custom-appearance' class prevents widgets.css from changing
40      // the appearance of this element.
41      this.classList.add('custom-appearance');
42    },
43
44    /**
45     * The command associated with this menu item. If this is set to a string
46     * of the form "#element-id" then the element is looked up in the document
47     * of the command.
48     * @type {cr.ui.Command}
49     */
50    command_: null,
51    get command() {
52      return this.command_;
53    },
54    set command(command) {
55      if (this.command_) {
56        this.command_.removeEventListener('labelChange', this);
57        this.command_.removeEventListener('disabledChange', this);
58        this.command_.removeEventListener('hiddenChange', this);
59        this.command_.removeEventListener('checkedChange', this);
60      }
61
62      if (typeof command == 'string' && command[0] == '#') {
63        command = this.ownerDocument.getElementById(command.slice(1));
64        cr.ui.decorate(command, Command);
65      }
66
67      this.command_ = command;
68      if (command) {
69        if (command.id)
70          this.setAttribute('command', '#' + command.id);
71
72        this.label = command.label;
73        this.disabled = command.disabled;
74        this.hidden = command.hidden;
75
76        this.command_.addEventListener('labelChange', this);
77        this.command_.addEventListener('disabledChange', this);
78        this.command_.addEventListener('hiddenChange', this);
79        this.command_.addEventListener('checkedChange', this);
80      }
81    },
82
83    /**
84     * The text label.
85     * @type {string}
86     */
87    get label() {
88      return this.textContent;
89    },
90    set label(label) {
91      this.textContent = label;
92    },
93
94    /**
95     * @return {boolean} Whether the menu item is a separator.
96     */
97    isSeparator: function() {
98      return this.tagName == 'HR';
99    },
100
101    /**
102     * Handles mouseup events. This dispatches an active event and if there
103     * is an assiciated command then that is executed.
104     * @param {Event} The mouseup event object.
105     * @private
106     */
107    handleMouseUp_: function(e) {
108      if (!this.disabled && !this.isSeparator() && this.selected) {
109        // Dispatch command event followed by executing the command object.
110        if (cr.dispatchSimpleEvent(this, 'activate', true, true)) {
111          var command = this.command;
112          if (command)
113            command.execute();
114        }
115      }
116    },
117
118    /**
119     * Handles changes to the associated command.
120     * @param {Event} e The event object.
121     */
122    handleEvent: function(e) {
123      switch (e.type) {
124        case 'disabledChange':
125          this.disabled = this.command.disabled;
126          break;
127        case 'hiddenChange':
128          this.hidden = this.command.hidden;
129          break;
130        case 'labelChange':
131          this.label = this.command.label;
132          break;
133        case 'checkedChange':
134          this.checked = this.command.checked;
135          break;
136      }
137    }
138  };
139
140  /**
141   * Whether the menu item is disabled or not.
142   * @type {boolean}
143   */
144  cr.defineProperty(MenuItem, 'disabled', cr.PropertyKind.BOOL_ATTR);
145
146  /**
147   * Whether the menu item is hidden or not.
148   * @type {boolean}
149   */
150  cr.defineProperty(MenuItem, 'hidden', cr.PropertyKind.BOOL_ATTR);
151
152  /**
153   * Whether the menu item is selected or not.
154   * @type {boolean}
155   */
156  cr.defineProperty(MenuItem, 'selected', cr.PropertyKind.BOOL_ATTR);
157
158  /**
159   * Whether the menu item is checked or not.
160   * @type {boolean}
161   */
162  cr.defineProperty(MenuItem, 'checked', cr.PropertyKind.BOOL_ATTR);
163
164  // Export
165  return {
166    MenuItem: MenuItem
167  };
168});
169