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.
5 cr.define('print_preview', function() {
9 * Draggable control for setting a page margin.
10 * @param {!print_preview.ticket_items.CustomMargins.Orientation} orientation
11 * Orientation of the margin control that determines where the margin
12 * textbox will be placed.
14 * @extends {print_preview.Component}
16 function MarginControl(orientation) {
17 print_preview.Component.call(this);
20 * Determines where the margin textbox will be placed.
21 * @type {!print_preview.ticket_items.CustomMargins.Orientation}
24 this.orientation_ = orientation;
27 * Position of the margin control in points.
31 this.positionInPts_ = 0;
34 * Page size of the document to print.
35 * @type {!print_preview.Size}
38 this.pageSize_ = new print_preview.Size(0, 0);
41 * Amount to scale pixel values by to convert to pixel space.
45 this.scaleTransform_ = 1;
48 * Amount to translate values in pixel space.
49 * @type {!print_preview.Coordinate2d}
52 this.translateTransform_ = new print_preview.Coordinate2d(0, 0);
55 * Position of the margin control when dragging starts.
56 * @type {print_preview.Coordinate2d}
59 this.marginStartPositionInPixels_ = null;
62 * Position of the mouse when the dragging starts.
63 * @type {print_preview.Coordinate2d}
66 this.mouseStartPositionInPixels_ = null;
69 * Processing timeout for the textbox.
73 this.textTimeout_ = null;
76 * Value of the textbox when the timeout was started.
80 this.preTimeoutValue_ = null;
83 * Textbox used to display and receive the value of the margin.
84 * @type {HTMLInputElement}
90 * Element of the margin control line.
94 this.marginLineEl_ = null;
97 * Whether this margin control's textbox has keyboard focus.
101 this.isFocused_ = false;
104 * Whether the margin control is in an error state.
108 this.isInError_ = false;
112 * Event types dispatched by the margin control.
115 MarginControl.EventType = {
116 // Dispatched when the margin control starts dragging.
117 DRAG_START: 'print_preview.MarginControl.DRAG_START',
119 // Dispatched when the text in the margin control's textbox changes.
120 TEXT_CHANGE: 'print_preview.MarginControl.TEXT_CHANGE'
124 * CSS classes used by this component.
128 MarginControl.Classes_ = {
129 TOP: 'margin-control-top',
130 RIGHT: 'margin-control-right',
131 BOTTOM: 'margin-control-bottom',
132 LEFT: 'margin-control-left',
133 TEXTBOX: 'margin-control-textbox',
135 INVISIBLE: 'invisible',
136 DISABLED: 'margin-control-disabled',
137 DRAGGING: 'margin-control-dragging',
138 LINE: 'margin-control-line'
142 * Map from orientation to CSS class name.
144 * !print_preview.ticket_items.CustomMargins.Orientation,
145 * !MarginControl.Classes_>}
148 MarginControl.OrientationToClass_ = {};
149 MarginControl.OrientationToClass_[
150 print_preview.ticket_items.CustomMargins.Orientation.TOP] =
151 MarginControl.Classes_.TOP;
152 MarginControl.OrientationToClass_[
153 print_preview.ticket_items.CustomMargins.Orientation.RIGHT] =
154 MarginControl.Classes_.RIGHT;
155 MarginControl.OrientationToClass_[
156 print_preview.ticket_items.CustomMargins.Orientation.BOTTOM] =
157 MarginControl.Classes_.BOTTOM;
158 MarginControl.OrientationToClass_[
159 print_preview.ticket_items.CustomMargins.Orientation.LEFT] =
160 MarginControl.Classes_.LEFT;
163 * Radius of the margin control in pixels. Padding of control + 1 for border.
168 MarginControl.RADIUS_ = 9;
171 * Timeout after a text change after which the text in the textbox is saved to
172 * the print ticket. Value in milliseconds.
177 MarginControl.TEXTBOX_TIMEOUT_ = 1000;
179 MarginControl.prototype = {
180 __proto__: print_preview.Component.prototype,
182 /** @return {boolean} Whether this margin control is in focus. */
183 getIsFocused: function() {
184 return this.isFocused_;
188 * @return {!print_preview.ticket_items.CustomMargins.Orientation}
189 * Orientation of the margin control.
191 getOrientation: function() {
192 return this.orientation_;
196 * @param {number} scaleTransform New scale transform of the margin control.
198 setScaleTransform: function(scaleTransform) {
199 this.scaleTransform_ = scaleTransform;
201 this.setPositionInPts(this.positionInPts_);
205 * @param {!print_preview.Coordinate2d} translateTransform New translate
206 * transform of the margin control.
208 setTranslateTransform: function(translateTransform) {
209 this.translateTransform_ = translateTransform;
211 this.setPositionInPts(this.positionInPts_);
215 * @param {!print_preview.Size} pageSize New size of the document's pages.
217 setPageSize: function(pageSize) {
218 this.pageSize_ = pageSize;
219 this.setPositionInPts(this.positionInPts_);
222 /** @param {boolean} isVisible Whether the margin control is visible. */
223 setIsVisible: function(isVisible) {
225 this.getElement().classList.remove(MarginControl.Classes_.INVISIBLE);
227 this.getElement().classList.add(MarginControl.Classes_.INVISIBLE);
231 /** @return {boolean} Whether the margin control is in an error state. */
232 getIsInError: function() {
233 return this.isInError_;
237 * @param {boolean} isInError Whether the margin control is in an error
240 setIsInError: function(isInError) {
241 this.isInError_ = isInError;
243 this.textbox_.classList.add(MarginControl.Classes_.INVALID);
245 this.textbox_.classList.remove(MarginControl.Classes_.INVALID);
249 /** @param {boolean} isEnabled Whether to enable the margin control. */
250 setIsEnabled: function(isEnabled) {
251 this.textbox_.disabled = !isEnabled;
253 this.getElement().classList.remove(MarginControl.Classes_.DISABLED);
255 this.getElement().classList.add(MarginControl.Classes_.DISABLED);
259 /** @return {number} Current position of the margin control in points. */
260 getPositionInPts: function() {
261 return this.positionInPts_;
265 * @param {number} posInPts New position of the margin control in points.
267 setPositionInPts: function(posInPts) {
268 this.positionInPts_ = posInPts;
269 var orientationEnum =
270 print_preview.ticket_items.CustomMargins.Orientation;
271 var x = this.translateTransform_.x;
272 var y = this.translateTransform_.y;
273 var width = null, height = null;
274 if (this.orientation_ == orientationEnum.TOP) {
275 y = this.scaleTransform_ * posInPts + this.translateTransform_.y -
276 MarginControl.RADIUS_;
277 width = this.scaleTransform_ * this.pageSize_.width;
278 } else if (this.orientation_ == orientationEnum.RIGHT) {
279 x = this.scaleTransform_ * (this.pageSize_.width - posInPts) +
280 this.translateTransform_.x - MarginControl.RADIUS_;
281 height = this.scaleTransform_ * this.pageSize_.height;
282 } else if (this.orientation_ == orientationEnum.BOTTOM) {
283 y = this.scaleTransform_ * (this.pageSize_.height - posInPts) +
284 this.translateTransform_.y - MarginControl.RADIUS_;
285 width = this.scaleTransform_ * this.pageSize_.width;
287 x = this.scaleTransform_ * posInPts + this.translateTransform_.x -
288 MarginControl.RADIUS_;
289 height = this.scaleTransform_ * this.pageSize_.height;
291 this.getElement().style.left = Math.round(x) + 'px';
292 this.getElement().style.top = Math.round(y) + 'px';
294 this.getElement().style.width = Math.round(width) + 'px';
296 if (height != null) {
297 this.getElement().style.height = Math.round(height) + 'px';
301 /** @return {string} The value in the margin control's textbox. */
302 getTextboxValue: function() {
303 return this.textbox_.value;
306 /** @param {string} value New value of the margin control's textbox. */
307 setTextboxValue: function(value) {
308 if (this.textbox_.value != value) {
309 this.textbox_.value = value;
314 * Converts a value in pixels to points.
315 * @param {number} Pixel value to convert.
316 * @return {number} Given value expressed in points.
318 convertPixelsToPts: function(pixels) {
320 var orientationEnum =
321 print_preview.ticket_items.CustomMargins.Orientation;
322 if (this.orientation_ == orientationEnum.TOP) {
323 pts = pixels - this.translateTransform_.y + MarginControl.RADIUS_;
324 pts /= this.scaleTransform_;
325 } else if (this.orientation_ == orientationEnum.RIGHT) {
326 pts = pixels - this.translateTransform_.x + MarginControl.RADIUS_;
327 pts /= this.scaleTransform_;
328 pts = this.pageSize_.width - pts;
329 } else if (this.orientation_ == orientationEnum.BOTTOM) {
330 pts = pixels - this.translateTransform_.y + MarginControl.RADIUS_;
331 pts /= this.scaleTransform_;
332 pts = this.pageSize_.height - pts;
334 pts = pixels - this.translateTransform_.x + MarginControl.RADIUS_;
335 pts /= this.scaleTransform_;
341 * Translates the position of the margin control relative to the mouse
342 * position in pixels.
343 * @param {!print_preview.Coordinate2d} mousePosition New position of
345 * @return {!print_preview.Coordinate2d} New position of the margin control.
347 translateMouseToPositionInPixels: function(mousePosition) {
348 return new print_preview.Coordinate2d(
349 mousePosition.x - this.mouseStartPositionInPixels_.x +
350 this.marginStartPositionInPixels_.x,
351 mousePosition.y - this.mouseStartPositionInPixels_.y +
352 this.marginStartPositionInPixels_.y);
356 createDom: function() {
357 this.setElementInternal(this.cloneTemplateInternal(
358 'margin-control-template'));
359 this.getElement().classList.add(MarginControl.OrientationToClass_[
361 this.textbox_ = this.getElement().getElementsByClassName(
362 MarginControl.Classes_.TEXTBOX)[0];
363 this.marginLineEl_ = this.getElement().getElementsByClassName(
364 MarginControl.Classes_.LINE)[0];
368 enterDocument: function() {
369 print_preview.Component.prototype.enterDocument.call(this);
371 this.getElement(), 'mousedown', this.onMouseDown_.bind(this));
373 this.textbox_, 'keydown', this.onTextboxKeyDown_.bind(this));
375 this.textbox_, 'focus', this.setIsFocused_.bind(this, true));
376 this.tracker.add(this.textbox_, 'blur', this.onTexboxBlur_.bind(this));
380 exitDocument: function() {
381 print_preview.Component.prototype.exitDocument.call(this);
382 this.textbox_ = null;
383 this.marginLineEl_ = null;
387 * @param {boolean} isFocused Whether the margin control is in focus.
390 setIsFocused_: function(isFocused) {
391 this.isFocused_ = isFocused;
395 * Called whenever a mousedown event occurs on the component.
396 * @param {MouseEvent} event The event that occured.
399 onMouseDown_: function(event) {
400 if (!this.textbox_.disabled &&
402 (event.target == this.getElement() ||
403 event.target == this.marginLineEl_)) {
404 this.mouseStartPositionInPixels_ =
405 new print_preview.Coordinate2d(event.x, event.y);
406 this.marginStartPositionInPixels_ = new print_preview.Coordinate2d(
407 this.getElement().offsetLeft, this.getElement().offsetTop);
408 this.setIsInError(false);
409 cr.dispatchSimpleEvent(this, MarginControl.EventType.DRAG_START);
414 * Called when a key down event occurs on the textbox. Dispatches a
415 * TEXT_CHANGE event if the "Enter" key was pressed.
416 * @param {Event} event Contains the key that was pressed.
419 onTextboxKeyDown_: function(event) {
420 if (this.textTimeout_) {
421 clearTimeout(this.textTimeout_);
422 this.textTimeout_ = null;
424 if (event.keyIdentifier == 'Enter') {
425 this.preTimeoutValue_ = null;
426 cr.dispatchSimpleEvent(this, MarginControl.EventType.TEXT_CHANGE);
428 if (this.preTimeoutValue_ == null) {
429 this.preTimeoutValue_ = this.textbox_.value;
431 this.textTimeout_ = setTimeout(
432 this.onTextboxTimeout_.bind(this), MarginControl.TEXTBOX_TIMEOUT_);
437 * Called after a timeout after the text in the textbox has changed. Saves
438 * the textbox's value to the print ticket.
441 onTextboxTimeout_: function() {
442 this.textTimeout_ = null;
443 if (this.textbox_.value != this.preTimeoutValue_) {
444 cr.dispatchSimpleEvent(this, MarginControl.EventType.TEXT_CHANGE);
446 this.preTimeoutValue_ = null;
450 * Called when the textbox loses focus. Dispatches a TEXT_CHANGE event.
452 onTexboxBlur_: function() {
453 if (this.textTimeout_) {
454 clearTimeout(this.textTimeout_);
455 this.textTimeout_ = null;
456 this.preTimeoutValue_ = null;
458 this.setIsFocused_(false);
459 cr.dispatchSimpleEvent(this, MarginControl.EventType.TEXT_CHANGE);
465 MarginControl: MarginControl