// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. cr.define('print_preview', function() { 'use strict'; /** * Draggable control for setting a page margin. * @param {!print_preview.ticket_items.CustomMargins.Orientation} orientation * Orientation of the margin control that determines where the margin * textbox will be placed. * @constructor * @extends {print_preview.Component} */ function MarginControl(orientation) { print_preview.Component.call(this); /** * Determines where the margin textbox will be placed. * @type {!print_preview.ticket_items.CustomMargins.Orientation} * @private */ this.orientation_ = orientation; /** * Position of the margin control in points. * @type {number} * @private */ this.positionInPts_ = 0; /** * Page size of the document to print. * @type {!print_preview.Size} * @private */ this.pageSize_ = new print_preview.Size(0, 0); /** * Amount to scale pixel values by to convert to pixel space. * @type {number} * @private */ this.scaleTransform_ = 1; /** * Amount to translate values in pixel space. * @type {!print_preview.Coordinate2d} * @private */ this.translateTransform_ = new print_preview.Coordinate2d(0, 0); /** * Position of the margin control when dragging starts. * @type {print_preview.Coordinate2d} * @private */ this.marginStartPositionInPixels_ = null; /** * Position of the mouse when the dragging starts. * @type {print_preview.Coordinate2d} * @private */ this.mouseStartPositionInPixels_ = null; /** * Processing timeout for the textbox. * @type {?number} * @private */ this.textTimeout_ = null; /** * Value of the textbox when the timeout was started. * @type {?string} * @private */ this.preTimeoutValue_ = null; /** * Textbox used to display and receive the value of the margin. * @type {HTMLInputElement} * @private */ this.textbox_ = null; /** * Element of the margin control line. * @type {HTMLElement} * @private */ this.marginLineEl_ = null; /** * Whether this margin control's textbox has keyboard focus. * @type {boolean} * @private */ this.isFocused_ = false; /** * Whether the margin control is in an error state. * @type {boolean} * @private */ this.isInError_ = false; }; /** * Event types dispatched by the margin control. * @enum {string} */ MarginControl.EventType = { // Dispatched when the margin control starts dragging. DRAG_START: 'print_preview.MarginControl.DRAG_START', // Dispatched when the text in the margin control's textbox changes. TEXT_CHANGE: 'print_preview.MarginControl.TEXT_CHANGE' }; /** * CSS classes used by this component. * @enum {string} * @private */ MarginControl.Classes_ = { TOP: 'margin-control-top', RIGHT: 'margin-control-right', BOTTOM: 'margin-control-bottom', LEFT: 'margin-control-left', TEXTBOX: 'margin-control-textbox', INVALID: 'invalid', INVISIBLE: 'invisible', DISABLED: 'margin-control-disabled', DRAGGING: 'margin-control-dragging', LINE: 'margin-control-line' }; /** * Map from orientation to CSS class name. * @type {!Object.< * !print_preview.ticket_items.CustomMargins.Orientation, * !MarginControl.Classes_>} * @private */ MarginControl.OrientationToClass_ = {}; MarginControl.OrientationToClass_[ print_preview.ticket_items.CustomMargins.Orientation.TOP] = MarginControl.Classes_.TOP; MarginControl.OrientationToClass_[ print_preview.ticket_items.CustomMargins.Orientation.RIGHT] = MarginControl.Classes_.RIGHT; MarginControl.OrientationToClass_[ print_preview.ticket_items.CustomMargins.Orientation.BOTTOM] = MarginControl.Classes_.BOTTOM; MarginControl.OrientationToClass_[ print_preview.ticket_items.CustomMargins.Orientation.LEFT] = MarginControl.Classes_.LEFT; /** * Radius of the margin control in pixels. Padding of control + 1 for border. * @type {number} * @const * @private */ MarginControl.RADIUS_ = 9; /** * Timeout after a text change after which the text in the textbox is saved to * the print ticket. Value in milliseconds. * @type {number} * @const * @private */ MarginControl.TEXTBOX_TIMEOUT_ = 1000; MarginControl.prototype = { __proto__: print_preview.Component.prototype, /** @return {boolean} Whether this margin control is in focus. */ getIsFocused: function() { return this.isFocused_; }, /** * @return {!print_preview.ticket_items.CustomMargins.Orientation} * Orientation of the margin control. */ getOrientation: function() { return this.orientation_; }, /** * @param {number} scaleTransform New scale transform of the margin control. */ setScaleTransform: function(scaleTransform) { this.scaleTransform_ = scaleTransform; // Reset position this.setPositionInPts(this.positionInPts_); }, /** * @param {!print_preview.Coordinate2d} translateTransform New translate * transform of the margin control. */ setTranslateTransform: function(translateTransform) { this.translateTransform_ = translateTransform; // Reset position this.setPositionInPts(this.positionInPts_); }, /** * @param {!print_preview.Size} pageSize New size of the document's pages. */ setPageSize: function(pageSize) { this.pageSize_ = pageSize; this.setPositionInPts(this.positionInPts_); }, /** @param {boolean} isVisible Whether the margin control is visible. */ setIsVisible: function(isVisible) { if (isVisible) { this.getElement().classList.remove(MarginControl.Classes_.INVISIBLE); } else { this.getElement().classList.add(MarginControl.Classes_.INVISIBLE); } }, /** @return {boolean} Whether the margin control is in an error state. */ getIsInError: function() { return this.isInError_; }, /** * @param {boolean} isInError Whether the margin control is in an error * state. */ setIsInError: function(isInError) { this.isInError_ = isInError; if (isInError) { this.textbox_.classList.add(MarginControl.Classes_.INVALID); } else { this.textbox_.classList.remove(MarginControl.Classes_.INVALID); } }, /** @param {boolean} isEnabled Whether to enable the margin control. */ setIsEnabled: function(isEnabled) { this.textbox_.disabled = !isEnabled; if (isEnabled) { this.getElement().classList.remove(MarginControl.Classes_.DISABLED); } else { this.getElement().classList.add(MarginControl.Classes_.DISABLED); } }, /** @return {number} Current position of the margin control in points. */ getPositionInPts: function() { return this.positionInPts_; }, /** * @param {number} posInPts New position of the margin control in points. */ setPositionInPts: function(posInPts) { this.positionInPts_ = posInPts; var orientationEnum = print_preview.ticket_items.CustomMargins.Orientation; var x = this.translateTransform_.x; var y = this.translateTransform_.y; var width = null, height = null; if (this.orientation_ == orientationEnum.TOP) { y = this.scaleTransform_ * posInPts + this.translateTransform_.y - MarginControl.RADIUS_; width = this.scaleTransform_ * this.pageSize_.width; } else if (this.orientation_ == orientationEnum.RIGHT) { x = this.scaleTransform_ * (this.pageSize_.width - posInPts) + this.translateTransform_.x - MarginControl.RADIUS_; height = this.scaleTransform_ * this.pageSize_.height; } else if (this.orientation_ == orientationEnum.BOTTOM) { y = this.scaleTransform_ * (this.pageSize_.height - posInPts) + this.translateTransform_.y - MarginControl.RADIUS_; width = this.scaleTransform_ * this.pageSize_.width; } else { x = this.scaleTransform_ * posInPts + this.translateTransform_.x - MarginControl.RADIUS_; height = this.scaleTransform_ * this.pageSize_.height; } this.getElement().style.left = Math.round(x) + 'px'; this.getElement().style.top = Math.round(y) + 'px'; if (width != null) { this.getElement().style.width = Math.round(width) + 'px'; } if (height != null) { this.getElement().style.height = Math.round(height) + 'px'; } }, /** @return {string} The value in the margin control's textbox. */ getTextboxValue: function() { return this.textbox_.value; }, /** @param {string} value New value of the margin control's textbox. */ setTextboxValue: function(value) { if (this.textbox_.value != value) { this.textbox_.value = value; } }, /** * Converts a value in pixels to points. * @param {number} Pixel value to convert. * @return {number} Given value expressed in points. */ convertPixelsToPts: function(pixels) { var pts; var orientationEnum = print_preview.ticket_items.CustomMargins.Orientation; if (this.orientation_ == orientationEnum.TOP) { pts = pixels - this.translateTransform_.y + MarginControl.RADIUS_; pts /= this.scaleTransform_; } else if (this.orientation_ == orientationEnum.RIGHT) { pts = pixels - this.translateTransform_.x + MarginControl.RADIUS_; pts /= this.scaleTransform_; pts = this.pageSize_.width - pts; } else if (this.orientation_ == orientationEnum.BOTTOM) { pts = pixels - this.translateTransform_.y + MarginControl.RADIUS_; pts /= this.scaleTransform_; pts = this.pageSize_.height - pts; } else { pts = pixels - this.translateTransform_.x + MarginControl.RADIUS_; pts /= this.scaleTransform_; } return pts; }, /** * Translates the position of the margin control relative to the mouse * position in pixels. * @param {!print_preview.Coordinate2d} mousePosition New position of * the mouse. * @return {!print_preview.Coordinate2d} New position of the margin control. */ translateMouseToPositionInPixels: function(mousePosition) { return new print_preview.Coordinate2d( mousePosition.x - this.mouseStartPositionInPixels_.x + this.marginStartPositionInPixels_.x, mousePosition.y - this.mouseStartPositionInPixels_.y + this.marginStartPositionInPixels_.y); }, /** @override */ createDom: function() { this.setElementInternal(this.cloneTemplateInternal( 'margin-control-template')); this.getElement().classList.add(MarginControl.OrientationToClass_[ this.orientation_]); this.textbox_ = this.getElement().getElementsByClassName( MarginControl.Classes_.TEXTBOX)[0]; this.marginLineEl_ = this.getElement().getElementsByClassName( MarginControl.Classes_.LINE)[0]; }, /** @override */ enterDocument: function() { print_preview.Component.prototype.enterDocument.call(this); this.tracker.add( this.getElement(), 'mousedown', this.onMouseDown_.bind(this)); this.tracker.add( this.textbox_, 'keydown', this.onTextboxKeyDown_.bind(this)); this.tracker.add( this.textbox_, 'focus', this.setIsFocused_.bind(this, true)); this.tracker.add(this.textbox_, 'blur', this.onTexboxBlur_.bind(this)); }, /** @override */ exitDocument: function() { print_preview.Component.prototype.exitDocument.call(this); this.textbox_ = null; this.marginLineEl_ = null; }, /** * @param {boolean} isFocused Whether the margin control is in focus. * @private */ setIsFocused_: function(isFocused) { this.isFocused_ = isFocused; }, /** * Called whenever a mousedown event occurs on the component. * @param {MouseEvent} event The event that occured. * @private */ onMouseDown_: function(event) { if (!this.textbox_.disabled && event.button == 0 && (event.target == this.getElement() || event.target == this.marginLineEl_)) { this.mouseStartPositionInPixels_ = new print_preview.Coordinate2d(event.x, event.y); this.marginStartPositionInPixels_ = new print_preview.Coordinate2d( this.getElement().offsetLeft, this.getElement().offsetTop); this.setIsInError(false); cr.dispatchSimpleEvent(this, MarginControl.EventType.DRAG_START); } }, /** * Called when a key down event occurs on the textbox. Dispatches a * TEXT_CHANGE event if the "Enter" key was pressed. * @param {Event} event Contains the key that was pressed. * @private */ onTextboxKeyDown_: function(event) { if (this.textTimeout_) { clearTimeout(this.textTimeout_); this.textTimeout_ = null; } if (event.keyIdentifier == 'Enter') { this.preTimeoutValue_ = null; cr.dispatchSimpleEvent(this, MarginControl.EventType.TEXT_CHANGE); } else { if (this.preTimeoutValue_ == null) { this.preTimeoutValue_ = this.textbox_.value; } this.textTimeout_ = setTimeout( this.onTextboxTimeout_.bind(this), MarginControl.TEXTBOX_TIMEOUT_); } }, /** * Called after a timeout after the text in the textbox has changed. Saves * the textbox's value to the print ticket. * @private */ onTextboxTimeout_: function() { this.textTimeout_ = null; if (this.textbox_.value != this.preTimeoutValue_) { cr.dispatchSimpleEvent(this, MarginControl.EventType.TEXT_CHANGE); } this.preTimeoutValue_ = null; }, /** * Called when the textbox loses focus. Dispatches a TEXT_CHANGE event. */ onTexboxBlur_: function() { if (this.textTimeout_) { clearTimeout(this.textTimeout_); this.textTimeout_ = null; this.preTimeoutValue_ = null; } this.setIsFocused_(false); cr.dispatchSimpleEvent(this, MarginControl.EventType.TEXT_CHANGE); } }; // Export return { MarginControl: MarginControl }; });