OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 cr.define('print_preview', function() { |
| 6 'use strict'; |
| 7 |
| 8 /** |
| 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. |
| 13 * @constructor |
| 14 * @extends {print_preview.Component} |
| 15 */ |
| 16 function MarginControl(orientation) { |
| 17 print_preview.Component.call(this); |
| 18 |
| 19 /** |
| 20 * Determines where the margin textbox will be placed. |
| 21 * @type {print_preview.ticket_items.CustomMargins.Orientation} |
| 22 * @private |
| 23 */ |
| 24 this.orientation_ = orientation; |
| 25 |
| 26 /** |
| 27 * Position of the margin control in points. |
| 28 * @type {number} |
| 29 * @private |
| 30 */ |
| 31 this.positionInPts_ = 0; |
| 32 |
| 33 /** |
| 34 * Page size of the document to print. |
| 35 * @type {!print_preview.Size} |
| 36 * @private |
| 37 */ |
| 38 this.pageSize_ = new print_preview.Size(0, 0); |
| 39 |
| 40 /** |
| 41 * Amount to scale pixel values by to convert to pixel space. |
| 42 * @type {number} |
| 43 * @private |
| 44 */ |
| 45 this.scaleTransform_ = 1; |
| 46 |
| 47 /** |
| 48 * Amount to translate values in pixel space. |
| 49 * @type {!print_preview.Coordinate2d} |
| 50 * @private |
| 51 */ |
| 52 this.translateTransform_ = new print_preview.Coordinate2d(0, 0); |
| 53 |
| 54 /** |
| 55 * Position of the margin control when dragging starts. |
| 56 * @type {print_preview.Coordinate2d} |
| 57 * @private |
| 58 */ |
| 59 this.marginStartPositionInPixels_ = null; |
| 60 |
| 61 /** |
| 62 * Position of the mouse when the dragging starts. |
| 63 * @type {print_preview.Coordinate2d} |
| 64 * @private |
| 65 */ |
| 66 this.mouseStartPositionInPixels_ = null; |
| 67 |
| 68 /** |
| 69 * Processing timeout for the textbox. |
| 70 * @type {Object} |
| 71 * @private |
| 72 */ |
| 73 this.textTimeout_ = null; |
| 74 |
| 75 /** |
| 76 * Value of the textbox when the timeout was started. |
| 77 * @type {?string} |
| 78 * @private |
| 79 */ |
| 80 this.preTimeoutValue_ = null; |
| 81 |
| 82 /** |
| 83 * Textbox used to display and receive the value of the margin. |
| 84 * @type {HTMLInputElement} |
| 85 * @private |
| 86 */ |
| 87 this.textbox_ = null; |
| 88 |
| 89 /** |
| 90 * Element of the margin control line. |
| 91 * @type {HTMLElement} |
| 92 * @private |
| 93 */ |
| 94 this.marginLineEl_ = null; |
| 95 |
| 96 /** |
| 97 * Whether this margin control's textbox has keyboard focus. |
| 98 * @type {boolean} |
| 99 * @private |
| 100 */ |
| 101 this.isFocused_ = false; |
| 102 |
| 103 /** |
| 104 * Whether the margin control is in an error state. |
| 105 * @type {boolean} |
| 106 * @private |
| 107 */ |
| 108 this.isInError_ = false; |
| 109 }; |
| 110 |
| 111 /** |
| 112 * Event types dispatched by the margin control. |
| 113 * @enum {string} |
| 114 */ |
| 115 MarginControl.EventType = { |
| 116 // Dispatched when the margin control starts dragging. |
| 117 DRAG_START: 'print_preview.MarginControl.DRAG_START', |
| 118 |
| 119 // Dispatched when the text in the margin control's textbox changes. |
| 120 TEXT_CHANGE: 'print_preview.MarginControl.TEXT_CHANGE' |
| 121 }; |
| 122 |
| 123 /** |
| 124 * CSS classes used by this component. |
| 125 * @enum {string} |
| 126 * @private |
| 127 */ |
| 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', |
| 134 INVALID: 'invalid', |
| 135 INVISIBLE: 'invisible', |
| 136 DISABLED: 'margin-control-disabled', |
| 137 DRAGGING: 'margin-control-dragging', |
| 138 LINE: 'margin-control-line' |
| 139 }; |
| 140 |
| 141 /** |
| 142 * Map from orientation to CSS class name. |
| 143 * @type {object.< |
| 144 * print_preview.ticket_items.CustomMargins.Orientation, |
| 145 * MarginControl.Classes_>} |
| 146 * @private |
| 147 */ |
| 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; |
| 161 |
| 162 /** |
| 163 * Radius of the margin control in pixels. Padding of control + 1 for border. |
| 164 * @type {number} |
| 165 * @const |
| 166 * @private |
| 167 */ |
| 168 MarginControl.RADIUS_ = 9; |
| 169 |
| 170 /** |
| 171 * Timeout after a text change after which the text in the textbox is saved to |
| 172 * the print ticket. Value in milliseconds. |
| 173 * @type {number} |
| 174 * @const |
| 175 * @private |
| 176 */ |
| 177 MarginControl.TEXTBOX_TIMEOUT_ = 1000; |
| 178 |
| 179 MarginControl.prototype = { |
| 180 __proto__: print_preview.Component.prototype, |
| 181 |
| 182 /** @return {boolean} Whether this margin control is in focus. */ |
| 183 getIsFocused: function() { |
| 184 return this.isFocused_; |
| 185 }, |
| 186 |
| 187 /** |
| 188 * @return {print_preview.ticket_items.CustomMargins.Orientation} |
| 189 * Orientation of the margin control. |
| 190 */ |
| 191 getOrientation: function() { |
| 192 return this.orientation_; |
| 193 }, |
| 194 |
| 195 /** |
| 196 * @param {number} scaleTransform New scale transform of the margin control. |
| 197 */ |
| 198 setScaleTransform: function(scaleTransform) { |
| 199 this.scaleTransform_ = scaleTransform; |
| 200 // Reset position |
| 201 this.setPositionInPts(this.positionInPts_); |
| 202 }, |
| 203 |
| 204 /** |
| 205 * @param {!print_preview.Coordinate2d} translateTransform New translate |
| 206 * transform of the margin control. |
| 207 */ |
| 208 setTranslateTransform: function(translateTransform) { |
| 209 this.translateTransform_ = translateTransform; |
| 210 // Reset position |
| 211 this.setPositionInPts(this.positionInPts_); |
| 212 }, |
| 213 |
| 214 /** |
| 215 * @param {!print_preview.Size} pageSize New size of the document's pages. |
| 216 */ |
| 217 setPageSize: function(pageSize) { |
| 218 this.pageSize_ = pageSize; |
| 219 this.setPositionInPts(this.positionInPts_); |
| 220 }, |
| 221 |
| 222 /** @param {boolean} isVisible Whether the margin control is visible. */ |
| 223 setIsVisible: function(isVisible) { |
| 224 if (isVisible) { |
| 225 this.getElement().classList.remove(MarginControl.Classes_.INVISIBLE); |
| 226 } else { |
| 227 this.getElement().classList.add(MarginControl.Classes_.INVISIBLE); |
| 228 } |
| 229 }, |
| 230 |
| 231 /** @return {boolean} Whether the margin control is in an error state. */ |
| 232 getIsInError: function() { |
| 233 return this.isInError_; |
| 234 }, |
| 235 |
| 236 /** |
| 237 * @param {boolean} isInError Whether the margin control is in an error |
| 238 * state. |
| 239 */ |
| 240 setIsInError: function(isInError) { |
| 241 this.isInError_ = isInError; |
| 242 if (isInError) { |
| 243 this.textbox_.classList.add(MarginControl.Classes_.INVALID); |
| 244 } else { |
| 245 this.textbox_.classList.remove(MarginControl.Classes_.INVALID); |
| 246 } |
| 247 }, |
| 248 |
| 249 /** @param {boolean} isEnabled Whether to enable the margin control. */ |
| 250 setIsEnabled: function(isEnabled) { |
| 251 this.textbox_.disabled = !isEnabled; |
| 252 if (isEnabled) { |
| 253 this.getElement().classList.remove(MarginControl.Classes_.DISABLED); |
| 254 } else { |
| 255 this.getElement().classList.add(MarginControl.Classes_.DISABLED); |
| 256 } |
| 257 }, |
| 258 |
| 259 /** @return {number} Current position of the margin control in points. */ |
| 260 getPositionInPts: function() { |
| 261 return this.positionInPts_; |
| 262 }, |
| 263 |
| 264 /** |
| 265 * @param {number} posInPts New position of the margin control in points. |
| 266 */ |
| 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; |
| 286 } else { |
| 287 x = this.scaleTransform_ * posInPts + this.translateTransform_.x - |
| 288 MarginControl.RADIUS_; |
| 289 height = this.scaleTransform_ * this.pageSize_.height; |
| 290 } |
| 291 this.getElement().style.left = Math.round(x) + 'px'; |
| 292 this.getElement().style.top = Math.round(y) + 'px'; |
| 293 if (width != null) { |
| 294 this.getElement().style.width = Math.round(width) + 'px'; |
| 295 } |
| 296 if (height != null) { |
| 297 this.getElement().style.height = Math.round(height) + 'px'; |
| 298 } |
| 299 }, |
| 300 |
| 301 /** @return {string} The value in the margin control's textbox. */ |
| 302 getTextboxValue: function() { |
| 303 return this.textbox_.value; |
| 304 }, |
| 305 |
| 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; |
| 310 } |
| 311 }, |
| 312 |
| 313 /** |
| 314 * Converts a value in pixels to points. |
| 315 * @param {number} Pixel value to convert. |
| 316 * @return {number} Given value expressed in points. |
| 317 */ |
| 318 convertPixelsToPts: function(pixels) { |
| 319 var pts; |
| 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; |
| 333 } else { |
| 334 pts = pixels - this.translateTransform_.x + MarginControl.RADIUS_; |
| 335 pts /= this.scaleTransform_; |
| 336 } |
| 337 return pts; |
| 338 }, |
| 339 |
| 340 /** |
| 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 |
| 344 * the mouse. |
| 345 * @return {!print_preview.Coordinate2d} New position of the margin control. |
| 346 */ |
| 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); |
| 353 }, |
| 354 |
| 355 /** @override */ |
| 356 createDom: function() { |
| 357 this.setElementInternal(this.cloneTemplateInternal( |
| 358 'margin-control-template')); |
| 359 this.getElement().classList.add(MarginControl.OrientationToClass_[ |
| 360 this.orientation_]); |
| 361 this.textbox_ = this.getElement().getElementsByClassName( |
| 362 MarginControl.Classes_.TEXTBOX)[0]; |
| 363 this.marginLineEl_ = this.getElement().getElementsByClassName( |
| 364 MarginControl.Classes_.LINE)[0]; |
| 365 }, |
| 366 |
| 367 /** @override */ |
| 368 enterDocument: function() { |
| 369 print_preview.Component.prototype.enterDocument.call(this); |
| 370 this.tracker.add( |
| 371 this.getElement(), 'mousedown', this.onMouseDown_.bind(this)); |
| 372 this.tracker.add( |
| 373 this.textbox_, 'keydown', this.onTextboxKeyDown_.bind(this)); |
| 374 this.tracker.add( |
| 375 this.textbox_, 'focus', this.setIsFocused_.bind(this, true)); |
| 376 this.tracker.add(this.textbox_, 'blur', this.onTexboxBlur_.bind(this)); |
| 377 }, |
| 378 |
| 379 /** @override */ |
| 380 exitDocument: function() { |
| 381 print_preview.Component.prototype.exitDocument.call(this); |
| 382 this.textbox_ = null; |
| 383 this.marginLineEl_ = null; |
| 384 }, |
| 385 |
| 386 /** |
| 387 * @param {boolean} isFocused Whether the margin control is in focus. |
| 388 * @private |
| 389 */ |
| 390 setIsFocused_: function(isFocused) { |
| 391 this.isFocused_ = isFocused; |
| 392 }, |
| 393 |
| 394 /** |
| 395 * Called whenever a mousedown event occurs on the component. |
| 396 * @param {MouseEvent} event The event that occured. |
| 397 * @private |
| 398 */ |
| 399 onMouseDown_: function(event) { |
| 400 if (!this.textbox_.disabled && |
| 401 event.button == 0 && |
| 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); |
| 410 } |
| 411 }, |
| 412 |
| 413 /** |
| 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. |
| 417 * @private |
| 418 */ |
| 419 onTextboxKeyDown_: function(event) { |
| 420 if (this.textTimeout_) { |
| 421 clearTimeout(this.textTimeout_); |
| 422 this.textTimeout_ = null; |
| 423 } |
| 424 if (event.keyIdentifier == 'Enter') { |
| 425 this.preTimeoutValue_ = null; |
| 426 cr.dispatchSimpleEvent(this, MarginControl.EventType.TEXT_CHANGE); |
| 427 } else { |
| 428 if (this.preTimeoutValue_ == null) { |
| 429 this.preTimeoutValue_ = this.textbox_.value; |
| 430 } |
| 431 this.textTimeout_ = setTimeout( |
| 432 this.onTextboxTimeout_.bind(this), MarginControl.TEXTBOX_TIMEOUT_); |
| 433 } |
| 434 }, |
| 435 |
| 436 /** |
| 437 * Called after a timeout after the text in the textbox has changed. Saves |
| 438 * the textbox's value to the print ticket. |
| 439 * @private |
| 440 */ |
| 441 onTextboxTimeout_: function() { |
| 442 this.textTimeout_ = null; |
| 443 if (this.textbox_.value != this.preTimeoutValue_) { |
| 444 cr.dispatchSimpleEvent(this, MarginControl.EventType.TEXT_CHANGE); |
| 445 } |
| 446 this.preTimeoutValue_ = null; |
| 447 }, |
| 448 |
| 449 /** |
| 450 * Called when the textbox loses focus. Dispatches a TEXT_CHANGE event. |
| 451 */ |
| 452 onTexboxBlur_: function() { |
| 453 if (this.textTimeout_) { |
| 454 clearTimeout(this.textTimeout_); |
| 455 this.textTimeout_ = null; |
| 456 this.preTimeoutValue_ = null; |
| 457 } |
| 458 this.setIsFocused_(false); |
| 459 cr.dispatchSimpleEvent(this, MarginControl.EventType.TEXT_CHANGE); |
| 460 } |
| 461 }; |
| 462 |
| 463 // Export |
| 464 return { |
| 465 MarginControl: MarginControl |
| 466 }; |
| 467 }); |
OLD | NEW |