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 * Creates a PageSettings object. This object encapsulates all settings and | |
10 * logic related to page selection. | |
11 * @constructor | |
12 */ | |
13 function PageSettings() { | |
14 this.allPagesRadioButton_ = $('all-pages'); | |
15 this.selectedPagesRadioButton_ = $('print-pages'); | |
16 this.selectedPagesTextfield_ = $('individual-pages'); | |
17 this.selectedPagesHint_ = $('individual-pages-hint'); | |
18 | |
19 // Timer id of |this.selectedPagesTextfield|. It is used to reset the timer | |
20 // whenever needed. | |
21 this.timerId_; | |
22 | |
23 // Contains the previously selected pages (pages requested by last | |
24 // preview request). It is used in | |
25 // |this.onSelectedPagesMayHaveChanged_()| to make sure that a new preview | |
26 // is not requested more often than necessary. | |
27 this.previouslySelectedPages_ = []; | |
28 | |
29 // The total page count of the previewed document regardless of which pages | |
30 // the user has selected. | |
31 this.totalPageCount_ = undefined; | |
32 this.addEventListeners_(); | |
33 } | |
34 | |
35 cr.addSingletonGetter(PageSettings); | |
36 | |
37 PageSettings.prototype = { | |
38 /** | |
39 * The text that is currently in |this.selectedPagesTextfield|. | |
40 * @type {string} | |
41 */ | |
42 get selectedPagesText() { | |
43 return this.selectedPagesTextfield_.value; | |
44 }, | |
45 | |
46 /** | |
47 * The radio button corresponding to "all pages selected". | |
48 * @type {HTMLInputElement} | |
49 */ | |
50 get allPagesRadioButton() { | |
51 return this.allPagesRadioButton_; | |
52 }, | |
53 | |
54 /** | |
55 * The radio button corresponding to "specific pages selected". | |
56 * @type {HTMLInputElement} | |
57 */ | |
58 get selectedPagesRadioButton() { | |
59 return this.selectedPagesRadioButton_; | |
60 }, | |
61 | |
62 /** | |
63 * The textfield containing page ranges as specified by the user. | |
64 * @type {HTMLInputElement} | |
65 */ | |
66 get selectedPagesTextfield() { | |
67 return this.selectedPagesTextfield_; | |
68 }, | |
69 | |
70 /** | |
71 * The span element containing the hint shown to the user when page | |
72 * selection is not valid. | |
73 * @type {HTMLElement} | |
74 */ | |
75 get selectedPagesHint() { | |
76 return this.selectedPagesHint_; | |
77 }, | |
78 | |
79 /** | |
80 * The total page count of the previewed document regardless of which pages | |
81 * the user has selected. If the total count is not known this value must | |
82 * be undefined. | |
83 * @type {number} | |
84 */ | |
85 get totalPageCount() { | |
86 return this.totalPageCount_; | |
87 }, | |
88 | |
89 /** | |
90 * @param {number} count The number to assing to |this.totalPageCount_|. | |
91 */ | |
92 set totalPageCount(count) { | |
93 this.totalPageCount_ = count; | |
94 }, | |
95 | |
96 /** | |
97 * Returns the selected pages in ascending order without any duplicates. | |
98 * | |
99 * @return {Array.<number>} The selected pages. | |
100 */ | |
101 get selectedPagesSet() { | |
102 var selectedPagesText = this.selectedPagesText; | |
103 | |
104 if (this.allPagesRadioButton.checked || selectedPagesText.length == 0) | |
105 selectedPagesText = '1-' + this.totalPageCount_; | |
106 | |
107 var pageList = pageRangeTextToPageList(selectedPagesText, | |
108 this.totalPageCount_); | |
109 return pageListToPageSet(pageList); | |
110 }, | |
111 | |
112 /** | |
113 * Returns the previously selected pages in ascending order without any | |
114 * duplicates. | |
115 * | |
116 * @return {Array.<number>} The previously selected pages. | |
117 */ | |
118 get previouslySelectedPages() { | |
119 return this.previouslySelectedPages_; | |
120 }, | |
121 | |
122 /** | |
123 * Returns an array of objects describing the selected page ranges. See | |
124 * documentation of pageSetToPageRanges() for more details. | |
125 * @return {Array.<{from: number, to: number}>} An array of page range | |
126 * objects. | |
127 */ | |
128 get selectedPageRanges() { | |
129 return pageSetToPageRanges(this.selectedPagesSet); | |
130 }, | |
131 | |
132 /** | |
133 * Invalidates |this.totalPageCount_| to indicate that the total number of | |
134 * pages is not known. | |
135 * @private | |
136 */ | |
137 invalidateTotalPageCount_: function() { | |
138 this.totalPageCount_ = undefined; | |
139 }, | |
140 | |
141 /** | |
142 * Invlidates |this.previouslySelectedPages_| to indicate that this value | |
143 * does no longer apply. | |
144 * @private | |
145 */ | |
146 invalidatePreviouslySelectedPages_: function() { | |
147 this.previouslySelectedPages_.length = 0; | |
148 }, | |
149 | |
150 /** | |
151 * Resets all the state variables of this object and hides | |
152 * |this.selectedPagesHint|. | |
153 */ | |
154 resetState: function() { | |
155 this.selectedPagesTextfield.classList.remove('invalid'); | |
156 fadeOutElement(this.selectedPagesHint_); | |
157 this.invalidateTotalPageCount_(); | |
158 this.invalidatePreviouslySelectedPages_(); | |
159 }, | |
160 | |
161 /** | |
162 * Updates |this.totalPageCount_| and |this.previouslySelectedPages_|, | |
163 * only if they have been previously invalidated. | |
164 * @param {number} newTotalPageCount The new total page count. | |
165 */ | |
166 updateState: function(newTotalPageCount) { | |
167 if (!this.totalPageCount_) | |
168 this.totalPageCount_ = newTotalPageCount; | |
169 | |
170 if (this.previouslySelectedPages_.length == 0) { | |
171 for (var i = 0; i < this.totalPageCount_; i++) | |
172 this.previouslySelectedPages_.push(i + 1); | |
173 } | |
174 | |
175 if (!this.isPageSelectionValid()) | |
176 this.onSelectedPagesTextfieldChanged(); | |
177 }, | |
178 | |
179 /** | |
180 * Updates |this.previouslySelectedPages_| with the currently selected | |
181 * pages. | |
182 */ | |
183 updatePageSelection: function() { | |
184 this.previouslySelectedPages_ = this.selectedPagesSet; | |
185 }, | |
186 | |
187 /** | |
188 * @private | |
189 * @return {boolean} true if currently selected pages differ from | |
190 * |this.previouslySelectesPages_|. | |
191 */ | |
192 hasPageSelectionChanged_: function() { | |
193 return !areArraysEqual(this.previouslySelectedPages_, | |
194 this.selectedPagesSet); | |
195 }, | |
196 | |
197 /** | |
198 * Checks if the page selection has changed and is valid. | |
199 * @return {boolean} true if the page selection is changed and is valid. | |
200 */ | |
201 hasPageSelectionChangedAndIsValid: function() { | |
202 return this.isPageSelectionValid() && this.hasPageSelectionChanged_(); | |
203 }, | |
204 | |
205 /** | |
206 * Validates the contents of |this.selectedPagesTextfield|. | |
207 * | |
208 * @return {boolean} true if the text is valid. | |
209 */ | |
210 isPageSelectionValid: function() { | |
211 if (this.allPagesRadioButton_.checked || | |
212 this.selectedPagesText.length == 0) { | |
213 return true; | |
214 } | |
215 return isPageRangeTextValid(this.selectedPagesText, this.totalPageCount_); | |
216 }, | |
217 | |
218 /** | |
219 * Checks all page selection related settings and requests a new print | |
220 * previw if needed. | |
221 * @return {boolean} true if a new preview was requested. | |
222 */ | |
223 requestPrintPreviewIfNeeded: function() { | |
224 if (this.hasPageSelectionChangedAndIsValid()) { | |
225 this.updatePageSelection(); | |
226 requestPrintPreview(); | |
227 return true; | |
228 } | |
229 if (!this.isPageSelectionValid()) | |
230 this.onSelectedPagesTextfieldChanged(); | |
231 return false; | |
232 }, | |
233 | |
234 /** | |
235 * Validates the selected pages and updates the hint accordingly. | |
236 * @private | |
237 */ | |
238 validateSelectedPages_: function() { | |
239 if (this.isPageSelectionValid()) { | |
240 this.selectedPagesTextfield.classList.remove('invalid'); | |
241 fadeOutElement(this.selectedPagesHint_); | |
242 this.selectedPagesHint.setAttribute('aria-hidden', 'true'); | |
243 } else { | |
244 this.selectedPagesTextfield.classList.add('invalid'); | |
245 this.selectedPagesHint.classList.remove('suggestion'); | |
246 this.selectedPagesHint.setAttribute('aria-hidden', 'false'); | |
247 this.selectedPagesHint.innerHTML = | |
248 localStrings.getStringF('pageRangeInstruction', | |
249 localStrings.getString( | |
250 'examplePageRangeText')); | |
251 fadeInElement(this.selectedPagesHint); | |
252 } | |
253 }, | |
254 | |
255 /** | |
256 * Executes whenever a blur event occurs on |this.selectedPagesTextfield| | |
257 * or when the timer expires. It takes care of | |
258 * 1) showing/hiding warnings/suggestions | |
259 * 2) updating print button/summary | |
260 */ | |
261 onSelectedPagesTextfieldChanged: function() { | |
262 this.validateSelectedPages_(); | |
263 cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY); | |
264 cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON); | |
265 }, | |
266 | |
267 /** | |
268 * When the user stops typing in |this.selectedPagesTextfield| or clicks on | |
269 * |allPagesRadioButton|, a new print preview is requested, only if | |
270 * 1) The input is compeletely valid (it can be parsed in its entirety). | |
271 * 2) The newly selected pages differ from |this.previouslySelectedPages_|. | |
272 * @private | |
273 */ | |
274 onSelectedPagesMayHaveChanged_: function() { | |
275 if (this.selectedPagesRadioButton_.checked) | |
276 this.onSelectedPagesTextfieldChanged(); | |
277 | |
278 // Toggling between "all pages"/"some pages" radio buttons while having an | |
279 // invalid entry in the page selection textfield still requires updating | |
280 // the print summary and print button. | |
281 if (!this.isPageSelectionValid() || !this.hasPageSelectionChanged_()) { | |
282 cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY); | |
283 cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON); | |
284 return; | |
285 } | |
286 requestPrintPreview(); | |
287 }, | |
288 | |
289 /** | |
290 * Whenever |this.selectedPagesTextfield| gains focus we add a timer to | |
291 * detect when the user stops typing in order to update the print preview. | |
292 * @private | |
293 */ | |
294 addTimerToSelectedPagesTextfield_: function() { | |
295 this.timerId_ = window.setTimeout( | |
296 this.onSelectedPagesMayHaveChanged_.bind(this), 1000); | |
297 }, | |
298 | |
299 /** | |
300 * As the user types in |this.selectedPagesTextfield|, we need to reset | |
301 * this timer, since the page ranges are still being edited. | |
302 * @private | |
303 */ | |
304 resetSelectedPagesTextfieldTimer_: function() { | |
305 clearTimeout(this.timerId_); | |
306 this.addTimerToSelectedPagesTextfield_(); | |
307 }, | |
308 | |
309 /** | |
310 * Handles the blur event of |this.selectedPagesTextfield|. Un-checks | |
311 * |this.selectedPagesRadioButton| if the input field is empty. | |
312 * @private | |
313 */ | |
314 onSelectedPagesTextfieldBlur_: function() { | |
315 clearTimeout(this.timerId_); | |
316 if (!this.selectedPagesText.length) { | |
317 this.allPagesRadioButton_.checked = true; | |
318 this.validateSelectedPages_(); | |
319 } | |
320 this.onSelectedPagesMayHaveChanged_(); | |
321 }, | |
322 | |
323 /** | |
324 * Gives focus to |this.selectedPagesTextfield| when | |
325 * |this.selectedPagesRadioButton| is clicked. | |
326 * @private | |
327 */ | |
328 onSelectedPagesRadioButtonChecked_: function() { | |
329 this.selectedPagesTextfield_.focus(); | |
330 }, | |
331 | |
332 /** | |
333 * Listener executing when an input event occurs in | |
334 * |this.selectedPagesTextfield|. Ensures that | |
335 * |this.selectedPagesTextfield| is non-empty before checking | |
336 * |this.selectedPagesRadioButton|. | |
337 * @private | |
338 */ | |
339 onSelectedPagesTextfieldInput_: function() { | |
340 if (this.selectedPagesText.length) | |
341 this.selectedPagesRadioButton.checked = true; | |
342 this.resetSelectedPagesTextfieldTimer_(); | |
343 }, | |
344 | |
345 /** | |
346 * Listener executing whenever a keyup events occurs in the pages textfield. | |
347 * @param {!KeyboardEvent} e The event that triggered this listener. | |
348 * @private | |
349 */ | |
350 onKeyUp_: function(e) { | |
351 if (e.keyIdentifier == 'Enter') | |
352 printHeader.onPrintRequested(); | |
353 }, | |
354 | |
355 /** | |
356 * Adding listeners to all pages related controls. The listeners take care | |
357 * of altering their behavior depending on |hasPendingPreviewRequest|. | |
358 * @private | |
359 */ | |
360 addEventListeners_: function() { | |
361 this.allPagesRadioButton.onclick = | |
362 this.onSelectedPagesMayHaveChanged_.bind(this); | |
363 this.selectedPagesRadioButton.onclick = | |
364 this.onSelectedPagesMayHaveChanged_.bind(this); | |
365 this.selectedPagesTextfield.oninput = | |
366 this.onSelectedPagesTextfieldInput_.bind(this); | |
367 this.selectedPagesTextfield.onfocus = | |
368 this.addTimerToSelectedPagesTextfield_.bind(this); | |
369 this.selectedPagesTextfield.onblur = | |
370 this.onSelectedPagesTextfieldBlur_.bind(this); | |
371 this.selectedPagesTextfield.onkeyup = this.onKeyUp_.bind(this); | |
372 } | |
373 }; | |
374 | |
375 return { | |
376 PageSettings: PageSettings | |
377 }; | |
378 }); | |
OLD | NEW |