selectionmenubutton.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // Copyright 2009 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview A customized MenuButton for selection of items among lists.
  16. * Menu contains 'select all' and 'select none' MenuItems for selecting all and
  17. * no items by default. Other MenuItems can be added by user.
  18. *
  19. * The checkbox content fires the action events associated with the 'select all'
  20. * and 'select none' menu items.
  21. *
  22. * @see ../demos/selectionmenubutton.html
  23. */
  24. goog.provide('goog.ui.SelectionMenuButton');
  25. goog.provide('goog.ui.SelectionMenuButton.SelectionState');
  26. goog.require('goog.dom.InputType');
  27. goog.require('goog.dom.TagName');
  28. goog.require('goog.events.EventType');
  29. goog.require('goog.style');
  30. goog.require('goog.ui.Component');
  31. goog.require('goog.ui.MenuButton');
  32. goog.require('goog.ui.MenuItem');
  33. goog.require('goog.ui.registry');
  34. /**
  35. * A selection menu button control. Extends {@link goog.ui.MenuButton}.
  36. * Menu contains 'select all' and 'select none' MenuItems for selecting all and
  37. * no items by default. Other MenuItems can be added by user.
  38. *
  39. * The checkbox content fires the action events associated with the 'select all'
  40. * and 'select none' menu items.
  41. *
  42. * @param {goog.ui.ButtonRenderer=} opt_renderer Renderer used to render or
  43. * decorate the menu button; defaults to {@link goog.ui.MenuButtonRenderer}.
  44. * @param {goog.ui.MenuItemRenderer=} opt_itemRenderer Optional menu item
  45. * renderer.
  46. * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper, used for
  47. * document interaction.
  48. * @constructor
  49. * @extends {goog.ui.MenuButton}
  50. */
  51. goog.ui.SelectionMenuButton = function(
  52. opt_renderer, opt_itemRenderer, opt_domHelper) {
  53. goog.ui.MenuButton.call(this, null, null, opt_renderer, opt_domHelper);
  54. this.initialItemRenderer_ = opt_itemRenderer || null;
  55. };
  56. goog.inherits(goog.ui.SelectionMenuButton, goog.ui.MenuButton);
  57. goog.tagUnsealableClass(goog.ui.SelectionMenuButton);
  58. /**
  59. * Constants for menu action types.
  60. * @enum {number}
  61. */
  62. goog.ui.SelectionMenuButton.SelectionState = {
  63. ALL: 0,
  64. SOME: 1,
  65. NONE: 2
  66. };
  67. /**
  68. * Select button state
  69. * @type {goog.ui.SelectionMenuButton.SelectionState}
  70. * @protected
  71. */
  72. goog.ui.SelectionMenuButton.prototype.selectionState =
  73. goog.ui.SelectionMenuButton.SelectionState.NONE;
  74. /**
  75. * Item renderer used for the first 2 items, 'select all' and 'select none'.
  76. * @type {goog.ui.MenuItemRenderer}
  77. * @private
  78. */
  79. goog.ui.SelectionMenuButton.prototype.initialItemRenderer_;
  80. /**
  81. * Enables button and embedded checkbox.
  82. * @param {boolean} enable Whether to enable or disable the button.
  83. * @override
  84. */
  85. goog.ui.SelectionMenuButton.prototype.setEnabled = function(enable) {
  86. goog.ui.SelectionMenuButton.base(this, 'setEnabled', enable);
  87. this.setCheckboxEnabled(enable);
  88. };
  89. /**
  90. * Enables the embedded checkbox.
  91. * @param {boolean} enable Whether to enable or disable the checkbox.
  92. * @protected
  93. */
  94. goog.ui.SelectionMenuButton.prototype.setCheckboxEnabled = function(enable) {
  95. this.getCheckboxElement().disabled = !enable;
  96. };
  97. /** @override */
  98. goog.ui.SelectionMenuButton.prototype.handleMouseDown = function(e) {
  99. if (!this.getDomHelper().contains(
  100. this.getCheckboxElement(),
  101. /** @type {Element} */ (e.target))) {
  102. goog.ui.SelectionMenuButton.superClass_.handleMouseDown.call(this, e);
  103. }
  104. };
  105. /**
  106. * Gets the checkbox element. Needed because if decorating html, getContent()
  107. * may include and comment/text elements in addition to the input element.
  108. * @return {Element} Checkbox.
  109. * @protected
  110. */
  111. goog.ui.SelectionMenuButton.prototype.getCheckboxElement = function() {
  112. var elements = this.getDomHelper().getElementsByTagNameAndClass(
  113. goog.dom.TagName.INPUT,
  114. goog.getCssName('goog-selectionmenubutton-checkbox'),
  115. this.getContentElement());
  116. return elements[0];
  117. };
  118. /**
  119. * Checkbox click handler.
  120. * @param {goog.events.BrowserEvent} e Checkbox click event.
  121. * @protected
  122. */
  123. goog.ui.SelectionMenuButton.prototype.handleCheckboxClick = function(e) {
  124. if (this.selectionState == goog.ui.SelectionMenuButton.SelectionState.NONE) {
  125. this.setSelectionState(goog.ui.SelectionMenuButton.SelectionState.ALL);
  126. if (this.getItemAt(0)) {
  127. this.getItemAt(0).dispatchEvent( // 'All' item
  128. goog.ui.Component.EventType.ACTION);
  129. }
  130. } else {
  131. this.setSelectionState(goog.ui.SelectionMenuButton.SelectionState.NONE);
  132. if (this.getItemAt(1)) {
  133. this.getItemAt(1).dispatchEvent( // 'None' item
  134. goog.ui.Component.EventType.ACTION);
  135. }
  136. }
  137. };
  138. /**
  139. * Menu action handler to update checkbox checked state.
  140. * @param {goog.events.Event} e Menu action event.
  141. * @private
  142. */
  143. goog.ui.SelectionMenuButton.prototype.handleMenuAction_ = function(e) {
  144. if (e.target.getModel() == goog.ui.SelectionMenuButton.SelectionState.ALL) {
  145. this.setSelectionState(goog.ui.SelectionMenuButton.SelectionState.ALL);
  146. } else {
  147. this.setSelectionState(goog.ui.SelectionMenuButton.SelectionState.NONE);
  148. }
  149. };
  150. /**
  151. * Set up events related to the menu items.
  152. * @private
  153. */
  154. goog.ui.SelectionMenuButton.prototype.addMenuEvent_ = function() {
  155. if (this.getItemAt(0) && this.getItemAt(1)) {
  156. this.getHandler().listen(
  157. this.getMenu(), goog.ui.Component.EventType.ACTION,
  158. this.handleMenuAction_);
  159. this.getItemAt(0).setModel(goog.ui.SelectionMenuButton.SelectionState.ALL);
  160. this.getItemAt(1).setModel(goog.ui.SelectionMenuButton.SelectionState.NONE);
  161. }
  162. };
  163. /**
  164. * Set up events related to the checkbox.
  165. * @protected
  166. */
  167. goog.ui.SelectionMenuButton.prototype.addCheckboxEvent = function() {
  168. this.getHandler().listen(
  169. this.getCheckboxElement(), goog.events.EventType.CLICK,
  170. this.handleCheckboxClick);
  171. };
  172. /**
  173. * Adds the checkbox to the button, and adds 2 items to the menu corresponding
  174. * to 'select all' and 'select none'.
  175. * @override
  176. * @protected
  177. */
  178. goog.ui.SelectionMenuButton.prototype.createDom = function() {
  179. goog.ui.SelectionMenuButton.superClass_.createDom.call(this);
  180. this.createCheckbox();
  181. /** @desc Text for 'All' button, used to select all items in a list. */
  182. var MSG_SELECTIONMENUITEM_ALL = goog.getMsg('All');
  183. /** @desc Text for 'None' button, used to unselect all items in a list. */
  184. var MSG_SELECTIONMENUITEM_NONE = goog.getMsg('None');
  185. var itemAll = new goog.ui.MenuItem(
  186. MSG_SELECTIONMENUITEM_ALL, null, this.getDomHelper(),
  187. this.initialItemRenderer_);
  188. var itemNone = new goog.ui.MenuItem(
  189. MSG_SELECTIONMENUITEM_NONE, null, this.getDomHelper(),
  190. this.initialItemRenderer_);
  191. this.addItem(itemAll);
  192. this.addItem(itemNone);
  193. this.addCheckboxEvent();
  194. this.addMenuEvent_();
  195. };
  196. /**
  197. * Creates and adds the checkbox to the button.
  198. * @protected
  199. */
  200. goog.ui.SelectionMenuButton.prototype.createCheckbox = function() {
  201. var checkbox = this.getDomHelper().createElement(goog.dom.TagName.INPUT);
  202. checkbox.type = goog.dom.InputType.CHECKBOX;
  203. checkbox.className = goog.getCssName('goog-selectionmenubutton-checkbox');
  204. this.setContent(checkbox);
  205. };
  206. /** @override */
  207. goog.ui.SelectionMenuButton.prototype.decorateInternal = function(element) {
  208. goog.ui.SelectionMenuButton.superClass_.decorateInternal.call(this, element);
  209. this.addCheckboxEvent();
  210. this.addMenuEvent_();
  211. };
  212. /** @override */
  213. goog.ui.SelectionMenuButton.prototype.setMenu = function(menu) {
  214. goog.ui.SelectionMenuButton.superClass_.setMenu.call(this, menu);
  215. this.addMenuEvent_();
  216. };
  217. /**
  218. * Set selection state and update checkbox.
  219. * @param {goog.ui.SelectionMenuButton.SelectionState} state Selection state.
  220. */
  221. goog.ui.SelectionMenuButton.prototype.setSelectionState = function(state) {
  222. if (this.selectionState != state) {
  223. var checkbox = this.getCheckboxElement();
  224. if (state == goog.ui.SelectionMenuButton.SelectionState.ALL) {
  225. checkbox.checked = true;
  226. goog.style.setOpacity(checkbox, 1);
  227. } else if (state == goog.ui.SelectionMenuButton.SelectionState.SOME) {
  228. checkbox.checked = true;
  229. // TODO(user): Get UX help to style this
  230. goog.style.setOpacity(checkbox, 0.5);
  231. } else { // NONE
  232. checkbox.checked = false;
  233. goog.style.setOpacity(checkbox, 1);
  234. }
  235. this.selectionState = state;
  236. }
  237. };
  238. /**
  239. * Get selection state.
  240. * @return {goog.ui.SelectionMenuButton.SelectionState} Selection state.
  241. */
  242. goog.ui.SelectionMenuButton.prototype.getSelectionState = function() {
  243. return this.selectionState;
  244. };
  245. // Register a decorator factory function for goog.ui.SelectionMenuButton.
  246. goog.ui.registry.setDecoratorByClassName(
  247. goog.getCssName('goog-selectionmenubutton-button'),
  248. function() { return new goog.ui.SelectionMenuButton(); });