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 * Textbox used to display and receive the value of the margin.
77 * @type {HTMLInputElement}
83 * Element of the margin control line.
87 this.marginLineEl_
= null;
90 * Whether this margin control's textbox has keyboard focus.
94 this.isFocused_
= false;
97 * Whether the margin control is in an error state.
101 this.isInError_
= false;
105 * Event types dispatched by the margin control.
108 MarginControl
.EventType
= {
109 // Dispatched when the margin control starts dragging.
110 DRAG_START
: 'print_preview.MarginControl.DRAG_START',
112 // Dispatched when the text in the margin control's textbox changes.
113 TEXT_CHANGE
: 'print_preview.MarginControl.TEXT_CHANGE'
117 * CSS classes used by this component.
121 MarginControl
.Classes_
= {
122 TEXTBOX
: 'margin-control-textbox',
123 DRAGGING
: 'margin-control-dragging',
124 LINE
: 'margin-control-line'
128 * Radius of the margin control in pixels. Padding of control + 1 for border.
133 MarginControl
.RADIUS_
= 9;
136 * Timeout after a text change after which the text in the textbox is saved to
137 * the print ticket. Value in milliseconds.
142 MarginControl
.TEXTBOX_TIMEOUT_
= 1000;
144 MarginControl
.prototype = {
145 __proto__
: print_preview
.Component
.prototype,
147 /** @return {boolean} Whether this margin control is in focus. */
148 getIsFocused: function() {
149 return this.isFocused_
;
153 * @return {!print_preview.ticket_items.CustomMargins.Orientation}
154 * Orientation of the margin control.
156 getOrientation: function() {
157 return this.orientation_
;
161 * @param {number} scaleTransform New scale transform of the margin control.
163 setScaleTransform: function(scaleTransform
) {
164 this.scaleTransform_
= scaleTransform
;
166 this.setPositionInPts(this.positionInPts_
);
170 * @param {!print_preview.Coordinate2d} translateTransform New translate
171 * transform of the margin control.
173 setTranslateTransform: function(translateTransform
) {
174 this.translateTransform_
= translateTransform
;
176 this.setPositionInPts(this.positionInPts_
);
180 * @param {!print_preview.Size} pageSize New size of the document's pages.
182 setPageSize: function(pageSize
) {
183 this.pageSize_
= pageSize
;
184 this.setPositionInPts(this.positionInPts_
);
187 /** @param {boolean} isVisible Whether the margin control is visible. */
188 setIsVisible: function(isVisible
) {
189 this.getElement().classList
.toggle('invisible', !isVisible
);
192 /** @return {boolean} Whether the margin control is in an error state. */
193 getIsInError: function() {
194 return this.isInError_
;
198 * @param {boolean} isInError Whether the margin control is in an error
201 setIsInError: function(isInError
) {
202 this.isInError_
= isInError
;
203 this.textbox_
.classList
.toggle('invalid', isInError
);
206 /** @param {boolean} isEnabled Whether to enable the margin control. */
207 setIsEnabled: function(isEnabled
) {
208 this.textbox_
.disabled
= !isEnabled
;
209 this.getElement().classList
.toggle('margin-control-disabled', !isEnabled
);
212 /** @return {number} Current position of the margin control in points. */
213 getPositionInPts: function() {
214 return this.positionInPts_
;
218 * @param {number} posInPts New position of the margin control in points.
220 setPositionInPts: function(posInPts
) {
221 this.positionInPts_
= posInPts
;
222 var orientationEnum
=
223 print_preview
.ticket_items
.CustomMargins
.Orientation
;
224 var x
= this.translateTransform_
.x
;
225 var y
= this.translateTransform_
.y
;
226 var width
= null, height
= null;
227 if (this.orientation_
== orientationEnum
.TOP
) {
228 y
= this.scaleTransform_
* posInPts
+ this.translateTransform_
.y
-
229 MarginControl
.RADIUS_
;
230 width
= this.scaleTransform_
* this.pageSize_
.width
;
231 } else if (this.orientation_
== orientationEnum
.RIGHT
) {
232 x
= this.scaleTransform_
* (this.pageSize_
.width
- posInPts
) +
233 this.translateTransform_
.x
- MarginControl
.RADIUS_
;
234 height
= this.scaleTransform_
* this.pageSize_
.height
;
235 } else if (this.orientation_
== orientationEnum
.BOTTOM
) {
236 y
= this.scaleTransform_
* (this.pageSize_
.height
- posInPts
) +
237 this.translateTransform_
.y
- MarginControl
.RADIUS_
;
238 width
= this.scaleTransform_
* this.pageSize_
.width
;
240 x
= this.scaleTransform_
* posInPts
+ this.translateTransform_
.x
-
241 MarginControl
.RADIUS_
;
242 height
= this.scaleTransform_
* this.pageSize_
.height
;
244 this.getElement().style
.left
= Math
.round(x
) + 'px';
245 this.getElement().style
.top
= Math
.round(y
) + 'px';
247 this.getElement().style
.width
= Math
.round(width
) + 'px';
249 if (height
!= null) {
250 this.getElement().style
.height
= Math
.round(height
) + 'px';
254 /** @return {string} The value in the margin control's textbox. */
255 getTextboxValue: function() {
256 return this.textbox_
.value
;
259 /** @param {string} value New value of the margin control's textbox. */
260 setTextboxValue: function(value
) {
261 if (this.textbox_
.value
!= value
) {
262 this.textbox_
.value
= value
;
267 * Converts a value in pixels to points.
268 * @param {number} pixels Pixel value to convert.
269 * @return {number} Given value expressed in points.
271 convertPixelsToPts: function(pixels
) {
273 var orientationEnum
=
274 print_preview
.ticket_items
.CustomMargins
.Orientation
;
275 if (this.orientation_
== orientationEnum
.TOP
) {
276 pts
= pixels
- this.translateTransform_
.y
+ MarginControl
.RADIUS_
;
277 pts
/= this.scaleTransform_
;
278 } else if (this.orientation_
== orientationEnum
.RIGHT
) {
279 pts
= pixels
- this.translateTransform_
.x
+ MarginControl
.RADIUS_
;
280 pts
/= this.scaleTransform_
;
281 pts
= this.pageSize_
.width
- pts
;
282 } else if (this.orientation_
== orientationEnum
.BOTTOM
) {
283 pts
= pixels
- this.translateTransform_
.y
+ MarginControl
.RADIUS_
;
284 pts
/= this.scaleTransform_
;
285 pts
= this.pageSize_
.height
- pts
;
287 pts
= pixels
- this.translateTransform_
.x
+ MarginControl
.RADIUS_
;
288 pts
/= this.scaleTransform_
;
294 * Translates the position of the margin control relative to the mouse
295 * position in pixels.
296 * @param {!print_preview.Coordinate2d} mousePosition New position of
298 * @return {!print_preview.Coordinate2d} New position of the margin control.
300 translateMouseToPositionInPixels: function(mousePosition
) {
301 return new print_preview
.Coordinate2d(
302 mousePosition
.x
- this.mouseStartPositionInPixels_
.x
+
303 this.marginStartPositionInPixels_
.x
,
304 mousePosition
.y
- this.mouseStartPositionInPixels_
.y
+
305 this.marginStartPositionInPixels_
.y
);
309 createDom: function() {
310 this.setElementInternal(this.cloneTemplateInternal(
311 'margin-control-template'));
312 this.getElement().classList
.add('margin-control-' + this.orientation_
);
313 this.textbox_
= this.getElement().getElementsByClassName(
314 MarginControl
.Classes_
.TEXTBOX
)[0];
315 this.textbox_
.setAttribute(
316 'aria-label', loadTimeData
.getString(this.orientation_
));
317 this.marginLineEl_
= this.getElement().getElementsByClassName(
318 MarginControl
.Classes_
.LINE
)[0];
322 enterDocument: function() {
323 print_preview
.Component
.prototype.enterDocument
.call(this);
325 this.getElement(), 'mousedown', this.onMouseDown_
.bind(this));
328 'webkitTransitionEnd',
329 this.onWebkitTransitionEnd_
.bind(this));
331 this.textbox_
, 'input', this.onTextboxInput_
.bind(this));
333 this.textbox_
, 'keydown', this.onTextboxKeyDown_
.bind(this));
335 this.textbox_
, 'focus', this.setIsFocused_
.bind(this, true));
336 this.tracker
.add(this.textbox_
, 'blur', this.onTexboxBlur_
.bind(this));
340 exitDocument: function() {
341 print_preview
.Component
.prototype.exitDocument
.call(this);
342 this.textbox_
= null;
343 this.marginLineEl_
= null;
347 * @param {boolean} isFocused Whether the margin control is in focus.
350 setIsFocused_: function(isFocused
) {
351 this.isFocused_
= isFocused
;
355 * Called whenever a mousedown event occurs on the component.
356 * @param {MouseEvent} event The event that occured.
359 onMouseDown_: function(event
) {
360 if (!this.textbox_
.disabled
&&
362 (event
.target
== this.getElement() ||
363 event
.target
== this.marginLineEl_
)) {
364 this.mouseStartPositionInPixels_
=
365 new print_preview
.Coordinate2d(event
.x
, event
.y
);
366 this.marginStartPositionInPixels_
= new print_preview
.Coordinate2d(
367 this.getElement().offsetLeft
, this.getElement().offsetTop
);
368 this.setIsInError(false);
369 cr
.dispatchSimpleEvent(this, MarginControl
.EventType
.DRAG_START
);
374 * Called when opacity CSS transition ends.
377 onWebkitTransitionEnd_: function(event
) {
378 if (event
.propertyName
!= 'opacity')
380 var elStyle
= window
.getComputedStyle(this.getElement());
381 var opacity
= parseInt(elStyle
.getPropertyValue('opacity'), 10);
382 this.textbox_
.setAttribute('aria-hidden', opacity
== 0);
386 * Called when textbox content changes. Starts text change timeout.
389 onTextboxInput_: function(event
) {
390 if (this.textTimeout_
) {
391 clearTimeout(this.textTimeout_
);
392 this.textTimeout_
= null;
394 this.textTimeout_
= setTimeout(
395 this.onTextboxTimeout_
.bind(this), MarginControl
.TEXTBOX_TIMEOUT_
);
399 * Called when a key down event occurs on the textbox. Dispatches a
400 * TEXT_CHANGE event if the "Enter" key was pressed.
401 * @param {Event} event Contains the key that was pressed.
404 onTextboxKeyDown_: function(event
) {
405 if (this.textTimeout_
) {
406 clearTimeout(this.textTimeout_
);
407 this.textTimeout_
= null;
409 if (event
.keyCode
== 13 /*enter*/) {
410 cr
.dispatchSimpleEvent(this, MarginControl
.EventType
.TEXT_CHANGE
);
415 * Called after a timeout after the text in the textbox has changed. Saves
416 * the textbox's value to the print ticket.
419 onTextboxTimeout_: function() {
420 this.textTimeout_
= null;
421 cr
.dispatchSimpleEvent(this, MarginControl
.EventType
.TEXT_CHANGE
);
425 * Called when the textbox loses focus. Dispatches a TEXT_CHANGE event.
427 onTexboxBlur_: function() {
428 if (this.textTimeout_
) {
429 clearTimeout(this.textTimeout_
);
430 this.textTimeout_
= null;
432 this.setIsFocused_(false);
433 cr
.dispatchSimpleEvent(this, MarginControl
.EventType
.TEXT_CHANGE
);
439 MarginControl
: MarginControl