// Copyright 2008 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS-IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /** * @fileoverview A dimension picker control. A dimension picker allows the * user to visually select a row and column count. * * @author robbyw@google.com (Robby Walker) * @see ../demos/dimensionpicker.html * @see ../demos/dimensionpicker_rtl.html */ goog.provide('goog.ui.DimensionPicker'); goog.require('goog.events.EventType'); goog.require('goog.events.KeyCodes'); goog.require('goog.math.Size'); goog.require('goog.ui.Component'); goog.require('goog.ui.Control'); goog.require('goog.ui.DimensionPickerRenderer'); goog.require('goog.ui.registry'); /** * A dimension picker allows the user to visually select a row and column * count using their mouse and keyboard. * * The currently selected dimension is controlled by an ACTION event. Event * listeners may retrieve the selected item using the * {@link #getValue} method. * * @param {goog.ui.DimensionPickerRenderer=} opt_renderer Renderer used to * render or decorate the palette; defaults to * {@link goog.ui.DimensionPickerRenderer}. * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper, used for * document interaction. * @constructor * @extends {goog.ui.Control} * @final */ goog.ui.DimensionPicker = function(opt_renderer, opt_domHelper) { goog.ui.Control.call( this, null, opt_renderer || goog.ui.DimensionPickerRenderer.getInstance(), opt_domHelper); this.size_ = new goog.math.Size(this.minColumns, this.minRows); }; goog.inherits(goog.ui.DimensionPicker, goog.ui.Control); /** * Minimum number of columns to show in the grid. * @type {number} */ goog.ui.DimensionPicker.prototype.minColumns = 5; /** * Minimum number of rows to show in the grid. * @type {number} */ goog.ui.DimensionPicker.prototype.minRows = 5; /** * Maximum number of columns to show in the grid. * @type {number} */ goog.ui.DimensionPicker.prototype.maxColumns = 20; /** * Maximum number of rows to show in the grid. * @type {number} */ goog.ui.DimensionPicker.prototype.maxRows = 20; /** * Palette dimensions (columns x rows). * @type {goog.math.Size} * @private */ goog.ui.DimensionPicker.prototype.size_; /** * Currently highlighted row count. * @type {number} * @private */ goog.ui.DimensionPicker.prototype.highlightedRows_ = 1; /** * Currently highlighted column count. * @type {number} * @private */ goog.ui.DimensionPicker.prototype.highlightedColumns_ = 1; /** @override */ goog.ui.DimensionPicker.prototype.enterDocument = function() { goog.ui.DimensionPicker.superClass_.enterDocument.call(this); var handler = this.getHandler(); handler .listen( this.getRenderer().getMouseMoveElement(this), goog.events.EventType.MOUSEMOVE, this.handleMouseMove) .listen( this.getDomHelper().getWindow(), goog.events.EventType.RESIZE, this.handleWindowResize); var parent = this.getParent(); if (parent) { handler.listen(parent, goog.ui.Component.EventType.SHOW, this.handleShow_); } }; /** @override */ goog.ui.DimensionPicker.prototype.exitDocument = function() { goog.ui.DimensionPicker.superClass_.exitDocument.call(this); var handler = this.getHandler(); handler .unlisten( this.getRenderer().getMouseMoveElement(this), goog.events.EventType.MOUSEMOVE, this.handleMouseMove) .unlisten( this.getDomHelper().getWindow(), goog.events.EventType.RESIZE, this.handleWindowResize); var parent = this.getParent(); if (parent) { handler.unlisten( parent, goog.ui.Component.EventType.SHOW, this.handleShow_); } }; /** * Resets the highlighted size when the picker is shown. * @private */ goog.ui.DimensionPicker.prototype.handleShow_ = function() { if (this.isVisible()) { this.setValue(1, 1); } }; /** @override */ goog.ui.DimensionPicker.prototype.disposeInternal = function() { goog.ui.DimensionPicker.superClass_.disposeInternal.call(this); delete this.size_; }; // Palette event handling. /** * Handles mousemove events. Determines which palette size was moused over and * highlights it. * @param {goog.events.BrowserEvent} e Mouse event to handle. * @protected */ goog.ui.DimensionPicker.prototype.handleMouseMove = function(e) { var highlightedSizeX = this.getRenderer().getGridOffsetX( this, this.isRightToLeft() ? /** @type {!HTMLElement} */ (e.target).offsetWidth - e.offsetX : e.offsetX); var highlightedSizeY = this.getRenderer().getGridOffsetY(this, e.offsetY); this.setValue(highlightedSizeX, highlightedSizeY); }; /** * Handles window resize events. Ensures no scrollbars are introduced by the * renderer's mouse catcher. * @param {goog.events.Event} e Resize event to handle. * @protected */ goog.ui.DimensionPicker.prototype.handleWindowResize = function(e) { this.getRenderer().positionMouseCatcher(this); }; /** * Handle key events if supported, so the user can use the keyboard to * manipulate the highlighted rows and columns. * @param {goog.events.KeyEvent} e The key event object. * @return {boolean} Whether the key event was handled. * @override */ goog.ui.DimensionPicker.prototype.handleKeyEvent = function(e) { var rows = this.highlightedRows_; var columns = this.highlightedColumns_; switch (e.keyCode) { case goog.events.KeyCodes.DOWN: rows++; break; case goog.events.KeyCodes.UP: rows--; break; case goog.events.KeyCodes.LEFT: if (this.isRightToLeft()) { columns++; } else { if (columns == 1) { // Delegate to parent. return false; } else { columns--; } } break; case goog.events.KeyCodes.RIGHT: if (this.isRightToLeft()) { if (columns == 1) { // Delegate to parent. return false; } else { columns--; } } else { columns++; } break; default: return goog.ui.DimensionPicker.superClass_.handleKeyEvent.call(this, e); } this.setValue(columns, rows); return true; }; // Palette management. /** * @return {goog.math.Size} Current table size shown (columns x rows). */ goog.ui.DimensionPicker.prototype.getSize = function() { return this.size_; }; /** * @return {!goog.math.Size} size The currently highlighted dimensions. */ goog.ui.DimensionPicker.prototype.getValue = function() { return new goog.math.Size(this.highlightedColumns_, this.highlightedRows_); }; /** * Sets the currently highlighted dimensions. If the dimensions are not valid * (not between 1 and the maximum number of columns/rows to show), they will * be changed to the closest valid value. * @param {(number|!goog.math.Size)} columns The number of columns to highlight, * or a goog.math.Size object containing both. * @param {number=} opt_rows The number of rows to highlight. Can be * omitted when columns is a good.math.Size object. */ goog.ui.DimensionPicker.prototype.setValue = function(columns, opt_rows) { if (!goog.isDef(opt_rows)) { columns = /** @type {!goog.math.Size} */ (columns); opt_rows = columns.height; columns = columns.width; } else { columns = /** @type {number} */ (columns); } // Ensure that the row and column values are within the minimum value (1) and // maxmimum values. columns = Math.max(1, columns); opt_rows = Math.max(1, opt_rows); columns = Math.min(this.maxColumns, columns); opt_rows = Math.min(this.maxRows, opt_rows); if (this.highlightedColumns_ != columns || this.highlightedRows_ != opt_rows) { var renderer = this.getRenderer(); // Show one more row/column than highlighted so the user understands the // palette can grow. this.size_.width = Math.max(Math.min(columns + 1, this.maxColumns), this.minColumns); this.size_.height = Math.max(Math.min(opt_rows + 1, this.maxRows), this.minRows); renderer.updateSize(this, this.getElement()); this.highlightedColumns_ = columns; this.highlightedRows_ = opt_rows; renderer.setHighlightedSize(this, columns, opt_rows); } }; /** * Register this control so it can be created from markup */ goog.ui.registry.setDecoratorByClassName( goog.ui.DimensionPickerRenderer.CSS_CLASS, function() { return new goog.ui.DimensionPicker(); });