dimensionpicker.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // Copyright 2008 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 dimension picker control. A dimension picker allows the
  16. * user to visually select a row and column count.
  17. *
  18. * @author robbyw@google.com (Robby Walker)
  19. * @see ../demos/dimensionpicker.html
  20. * @see ../demos/dimensionpicker_rtl.html
  21. */
  22. goog.provide('goog.ui.DimensionPicker');
  23. goog.require('goog.events.EventType');
  24. goog.require('goog.events.KeyCodes');
  25. goog.require('goog.math.Size');
  26. goog.require('goog.ui.Component');
  27. goog.require('goog.ui.Control');
  28. goog.require('goog.ui.DimensionPickerRenderer');
  29. goog.require('goog.ui.registry');
  30. /**
  31. * A dimension picker allows the user to visually select a row and column
  32. * count using their mouse and keyboard.
  33. *
  34. * The currently selected dimension is controlled by an ACTION event. Event
  35. * listeners may retrieve the selected item using the
  36. * {@link #getValue} method.
  37. *
  38. * @param {goog.ui.DimensionPickerRenderer=} opt_renderer Renderer used to
  39. * render or decorate the palette; defaults to
  40. * {@link goog.ui.DimensionPickerRenderer}.
  41. * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper, used for
  42. * document interaction.
  43. * @constructor
  44. * @extends {goog.ui.Control}
  45. * @final
  46. */
  47. goog.ui.DimensionPicker = function(opt_renderer, opt_domHelper) {
  48. goog.ui.Control.call(
  49. this, null, opt_renderer || goog.ui.DimensionPickerRenderer.getInstance(),
  50. opt_domHelper);
  51. this.size_ = new goog.math.Size(this.minColumns, this.minRows);
  52. };
  53. goog.inherits(goog.ui.DimensionPicker, goog.ui.Control);
  54. /**
  55. * Minimum number of columns to show in the grid.
  56. * @type {number}
  57. */
  58. goog.ui.DimensionPicker.prototype.minColumns = 5;
  59. /**
  60. * Minimum number of rows to show in the grid.
  61. * @type {number}
  62. */
  63. goog.ui.DimensionPicker.prototype.minRows = 5;
  64. /**
  65. * Maximum number of columns to show in the grid.
  66. * @type {number}
  67. */
  68. goog.ui.DimensionPicker.prototype.maxColumns = 20;
  69. /**
  70. * Maximum number of rows to show in the grid.
  71. * @type {number}
  72. */
  73. goog.ui.DimensionPicker.prototype.maxRows = 20;
  74. /**
  75. * Palette dimensions (columns x rows).
  76. * @type {goog.math.Size}
  77. * @private
  78. */
  79. goog.ui.DimensionPicker.prototype.size_;
  80. /**
  81. * Currently highlighted row count.
  82. * @type {number}
  83. * @private
  84. */
  85. goog.ui.DimensionPicker.prototype.highlightedRows_ = 1;
  86. /**
  87. * Currently highlighted column count.
  88. * @type {number}
  89. * @private
  90. */
  91. goog.ui.DimensionPicker.prototype.highlightedColumns_ = 1;
  92. /** @override */
  93. goog.ui.DimensionPicker.prototype.enterDocument = function() {
  94. goog.ui.DimensionPicker.superClass_.enterDocument.call(this);
  95. var handler = this.getHandler();
  96. handler
  97. .listen(
  98. this.getRenderer().getMouseMoveElement(this),
  99. goog.events.EventType.MOUSEMOVE, this.handleMouseMove)
  100. .listen(
  101. this.getDomHelper().getWindow(), goog.events.EventType.RESIZE,
  102. this.handleWindowResize);
  103. var parent = this.getParent();
  104. if (parent) {
  105. handler.listen(parent, goog.ui.Component.EventType.SHOW, this.handleShow_);
  106. }
  107. };
  108. /** @override */
  109. goog.ui.DimensionPicker.prototype.exitDocument = function() {
  110. goog.ui.DimensionPicker.superClass_.exitDocument.call(this);
  111. var handler = this.getHandler();
  112. handler
  113. .unlisten(
  114. this.getRenderer().getMouseMoveElement(this),
  115. goog.events.EventType.MOUSEMOVE, this.handleMouseMove)
  116. .unlisten(
  117. this.getDomHelper().getWindow(), goog.events.EventType.RESIZE,
  118. this.handleWindowResize);
  119. var parent = this.getParent();
  120. if (parent) {
  121. handler.unlisten(
  122. parent, goog.ui.Component.EventType.SHOW, this.handleShow_);
  123. }
  124. };
  125. /**
  126. * Resets the highlighted size when the picker is shown.
  127. * @private
  128. */
  129. goog.ui.DimensionPicker.prototype.handleShow_ = function() {
  130. if (this.isVisible()) {
  131. this.setValue(1, 1);
  132. }
  133. };
  134. /** @override */
  135. goog.ui.DimensionPicker.prototype.disposeInternal = function() {
  136. goog.ui.DimensionPicker.superClass_.disposeInternal.call(this);
  137. delete this.size_;
  138. };
  139. // Palette event handling.
  140. /**
  141. * Handles mousemove events. Determines which palette size was moused over and
  142. * highlights it.
  143. * @param {goog.events.BrowserEvent} e Mouse event to handle.
  144. * @protected
  145. */
  146. goog.ui.DimensionPicker.prototype.handleMouseMove = function(e) {
  147. var highlightedSizeX = this.getRenderer().getGridOffsetX(
  148. this, this.isRightToLeft() ?
  149. /** @type {!HTMLElement} */ (e.target).offsetWidth - e.offsetX :
  150. e.offsetX);
  151. var highlightedSizeY = this.getRenderer().getGridOffsetY(this, e.offsetY);
  152. this.setValue(highlightedSizeX, highlightedSizeY);
  153. };
  154. /**
  155. * Handles window resize events. Ensures no scrollbars are introduced by the
  156. * renderer's mouse catcher.
  157. * @param {goog.events.Event} e Resize event to handle.
  158. * @protected
  159. */
  160. goog.ui.DimensionPicker.prototype.handleWindowResize = function(e) {
  161. this.getRenderer().positionMouseCatcher(this);
  162. };
  163. /**
  164. * Handle key events if supported, so the user can use the keyboard to
  165. * manipulate the highlighted rows and columns.
  166. * @param {goog.events.KeyEvent} e The key event object.
  167. * @return {boolean} Whether the key event was handled.
  168. * @override
  169. */
  170. goog.ui.DimensionPicker.prototype.handleKeyEvent = function(e) {
  171. var rows = this.highlightedRows_;
  172. var columns = this.highlightedColumns_;
  173. switch (e.keyCode) {
  174. case goog.events.KeyCodes.DOWN:
  175. rows++;
  176. break;
  177. case goog.events.KeyCodes.UP:
  178. rows--;
  179. break;
  180. case goog.events.KeyCodes.LEFT:
  181. if (this.isRightToLeft()) {
  182. columns++;
  183. } else {
  184. if (columns == 1) {
  185. // Delegate to parent.
  186. return false;
  187. } else {
  188. columns--;
  189. }
  190. }
  191. break;
  192. case goog.events.KeyCodes.RIGHT:
  193. if (this.isRightToLeft()) {
  194. if (columns == 1) {
  195. // Delegate to parent.
  196. return false;
  197. } else {
  198. columns--;
  199. }
  200. } else {
  201. columns++;
  202. }
  203. break;
  204. default:
  205. return goog.ui.DimensionPicker.superClass_.handleKeyEvent.call(this, e);
  206. }
  207. this.setValue(columns, rows);
  208. return true;
  209. };
  210. // Palette management.
  211. /**
  212. * @return {goog.math.Size} Current table size shown (columns x rows).
  213. */
  214. goog.ui.DimensionPicker.prototype.getSize = function() {
  215. return this.size_;
  216. };
  217. /**
  218. * @return {!goog.math.Size} size The currently highlighted dimensions.
  219. */
  220. goog.ui.DimensionPicker.prototype.getValue = function() {
  221. return new goog.math.Size(this.highlightedColumns_, this.highlightedRows_);
  222. };
  223. /**
  224. * Sets the currently highlighted dimensions. If the dimensions are not valid
  225. * (not between 1 and the maximum number of columns/rows to show), they will
  226. * be changed to the closest valid value.
  227. * @param {(number|!goog.math.Size)} columns The number of columns to highlight,
  228. * or a goog.math.Size object containing both.
  229. * @param {number=} opt_rows The number of rows to highlight. Can be
  230. * omitted when columns is a good.math.Size object.
  231. */
  232. goog.ui.DimensionPicker.prototype.setValue = function(columns, opt_rows) {
  233. if (!goog.isDef(opt_rows)) {
  234. columns = /** @type {!goog.math.Size} */ (columns);
  235. opt_rows = columns.height;
  236. columns = columns.width;
  237. } else {
  238. columns = /** @type {number} */ (columns);
  239. }
  240. // Ensure that the row and column values are within the minimum value (1) and
  241. // maxmimum values.
  242. columns = Math.max(1, columns);
  243. opt_rows = Math.max(1, opt_rows);
  244. columns = Math.min(this.maxColumns, columns);
  245. opt_rows = Math.min(this.maxRows, opt_rows);
  246. if (this.highlightedColumns_ != columns ||
  247. this.highlightedRows_ != opt_rows) {
  248. var renderer = this.getRenderer();
  249. // Show one more row/column than highlighted so the user understands the
  250. // palette can grow.
  251. this.size_.width =
  252. Math.max(Math.min(columns + 1, this.maxColumns), this.minColumns);
  253. this.size_.height =
  254. Math.max(Math.min(opt_rows + 1, this.maxRows), this.minRows);
  255. renderer.updateSize(this, this.getElement());
  256. this.highlightedColumns_ = columns;
  257. this.highlightedRows_ = opt_rows;
  258. renderer.setHighlightedSize(this, columns, opt_rows);
  259. }
  260. };
  261. /**
  262. * Register this control so it can be created from markup
  263. */
  264. goog.ui.registry.setDecoratorByClassName(
  265. goog.ui.DimensionPickerRenderer.CSS_CLASS,
  266. function() { return new goog.ui.DimensionPicker(); });