OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview Legacy supervised user creation flow screen. | 6 * @fileoverview Legacy supervised user creation flow screen. |
7 */ | 7 */ |
8 | 8 |
9 login.createScreen('SupervisedUserCreationScreen', | 9 login.createScreen( |
10 'supervised-user-creation', function() { | 10 'SupervisedUserCreationScreen', 'supervised-user-creation', function() { |
11 var MAX_NAME_LENGTH = 50; | 11 var MAX_NAME_LENGTH = 50; |
12 var UserImagesGrid = options.UserImagesGrid; | 12 var UserImagesGrid = options.UserImagesGrid; |
13 var ButtonImages = UserImagesGrid.ButtonImages; | 13 var ButtonImages = UserImagesGrid.ButtonImages; |
14 | 14 |
15 var ManagerPod = cr.ui.define(function() { | 15 var ManagerPod = cr.ui.define(function() { |
16 var node = $('supervised-user-creation-manager-template').cloneNode(true); | 16 var node = |
17 node.removeAttribute('id'); | 17 $('supervised-user-creation-manager-template').cloneNode(true); |
18 node.removeAttribute('hidden'); | 18 node.removeAttribute('id'); |
19 return node; | 19 node.removeAttribute('hidden'); |
20 }); | 20 return node; |
21 | 21 }); |
22 ManagerPod.userImageSalt_ = {}; | 22 |
23 | 23 ManagerPod.userImageSalt_ = {}; |
24 /** | 24 |
25 * UI element for displaying single account in list of possible managers for | 25 /** |
26 * new supervised user. | 26 * UI element for displaying single account in list of possible managers |
27 * @type {Object} | 27 * for new supervised user. |
28 */ | 28 * @type {Object} |
29 ManagerPod.prototype = { | 29 */ |
30 __proto__: HTMLDivElement.prototype, | 30 ManagerPod.prototype = { |
31 | 31 __proto__: HTMLDivElement.prototype, |
32 /** @override */ | 32 |
33 decorate: function() { | 33 /** @override */ |
34 // Mousedown has to be used instead of click to be able to prevent 'focus' | 34 decorate: function() { |
35 // event later. | 35 // Mousedown has to be used instead of click to be able to prevent |
36 this.addEventListener('mousedown', | 36 // 'focus' event later. |
37 this.handleMouseDown_.bind(this)); | 37 this.addEventListener('mousedown', this.handleMouseDown_.bind(this)); |
38 var screen = $('supervised-user-creation'); | 38 var screen = $('supervised-user-creation'); |
39 var managerPod = this; | 39 var managerPod = this; |
40 var managerPodList = screen.managerList_; | 40 var managerPodList = screen.managerList_; |
41 var hideManagerPasswordError = function(element) { | 41 var hideManagerPasswordError = function(element) { |
42 managerPod.passwordElement.classList.remove('password-error'); | 42 managerPod.passwordElement.classList.remove('password-error'); |
43 $('bubble').hide(); | 43 $('bubble').hide(); |
| 44 }; |
| 45 |
| 46 screen.configureTextInput( |
| 47 this.passwordElement, |
| 48 screen.updateNextButtonForManager_.bind(screen), |
| 49 screen.validIfNotEmpty_.bind(screen), function(element) { |
| 50 screen.getScreenButton('next').focus(); |
| 51 }, hideManagerPasswordError); |
| 52 |
| 53 this.passwordElement.addEventListener('keydown', function(e) { |
| 54 switch (e.key) { |
| 55 case 'ArrowUp': |
| 56 managerPodList.selectNextPod(-1); |
| 57 e.stopPropagation(); |
| 58 break; |
| 59 case 'ArrowDown': |
| 60 managerPodList.selectNextPod(+1); |
| 61 e.stopPropagation(); |
| 62 break; |
| 63 } |
| 64 }); |
| 65 }, |
| 66 |
| 67 /** |
| 68 * Updates UI elements from user data. |
| 69 */ |
| 70 update: function() { |
| 71 this.imageElement.src = 'chrome://userimage/' + this.user.username + |
| 72 '?id=' + ManagerPod.userImageSalt_[this.user.username]; |
| 73 |
| 74 this.nameElement.textContent = this.user.displayName; |
| 75 this.emailElement.textContent = this.user.emailAddress; |
| 76 }, |
| 77 |
| 78 showPasswordError: function() { |
| 79 this.passwordElement.classList.add('password-error'); |
| 80 $('bubble').showTextForElement( |
| 81 this.passwordElement, |
| 82 loadTimeData.getString( |
| 83 'createSupervisedUserWrongManagerPasswordText'), |
| 84 cr.ui.Bubble.Attachment.BOTTOM, 24, 4); |
| 85 }, |
| 86 |
| 87 /** |
| 88 * Brings focus to password field. |
| 89 */ |
| 90 focusInput: function() { |
| 91 this.passwordElement.focus(); |
| 92 }, |
| 93 |
| 94 /** |
| 95 * Gets image element. |
| 96 * @type {!HTMLImageElement} |
| 97 */ |
| 98 get imageElement() { |
| 99 return this.querySelector('.supervised-user-creation-manager-image'); |
| 100 }, |
| 101 |
| 102 /** |
| 103 * Gets name element. |
| 104 * @type {!HTMLDivElement} |
| 105 */ |
| 106 get nameElement() { |
| 107 return this.querySelector('.supervised-user-creation-manager-name'); |
| 108 }, |
| 109 |
| 110 /** |
| 111 * Gets e-mail element. |
| 112 * @type {!HTMLDivElement} |
| 113 */ |
| 114 get emailElement() { |
| 115 return this.querySelector('.supervised-user-creation-manager-email'); |
| 116 }, |
| 117 |
| 118 /** |
| 119 * Gets password element. |
| 120 * @type {!HTMLDivElement} |
| 121 */ |
| 122 get passwordElement() { |
| 123 return this.querySelector( |
| 124 '.supervised-user-creation-manager-password'); |
| 125 }, |
| 126 |
| 127 /** |
| 128 * Gets password enclosing block. |
| 129 * @type {!HTMLDivElement} |
| 130 */ |
| 131 get passwordBlock() { |
| 132 return this.querySelector('.password-block'); |
| 133 }, |
| 134 |
| 135 /** @override */ |
| 136 handleMouseDown_: function(e) { |
| 137 this.parentNode.selectPod(this); |
| 138 // Prevent default so that we don't trigger 'focus' event. |
| 139 e.preventDefault(); |
| 140 }, |
| 141 |
| 142 /** |
| 143 * The user that this pod represents. |
| 144 * @type {!Object} |
| 145 */ |
| 146 user_: undefined, |
| 147 get user() { |
| 148 return this.user_; |
| 149 }, |
| 150 set user(userDict) { |
| 151 this.user_ = userDict; |
| 152 this.update(); |
| 153 }, |
44 }; | 154 }; |
45 | 155 |
46 screen.configureTextInput( | 156 var ManagerPodList = cr.ui.define('div'); |
47 this.passwordElement, | 157 |
48 screen.updateNextButtonForManager_.bind(screen), | 158 /** |
49 screen.validIfNotEmpty_.bind(screen), | 159 * UI element for selecting manager account for new supervised user. |
50 function(element) { | 160 * @type {Object} |
51 screen.getScreenButton('next').focus(); | 161 */ |
52 }, | 162 ManagerPodList.prototype = { |
53 hideManagerPasswordError); | 163 __proto__: HTMLDivElement.prototype, |
54 | 164 |
55 this.passwordElement.addEventListener('keydown', function(e) { | 165 selectedPod_: null, |
56 switch (e.key) { | 166 |
57 case 'ArrowUp': | 167 /** @override */ |
58 managerPodList.selectNextPod(-1); | 168 decorate: function() {}, |
59 e.stopPropagation(); | 169 |
60 break; | 170 /** |
61 case 'ArrowDown': | 171 * Returns all the pods in this pod list. |
62 managerPodList.selectNextPod(+1); | 172 * @type {NodeList} |
63 e.stopPropagation(); | 173 */ |
64 break; | 174 get pods() { |
65 } | 175 return this.children; |
66 }); | 176 }, |
67 }, | 177 |
68 | 178 addPod: function(manager) { |
69 /** | 179 var managerPod = new ManagerPod({user: manager}); |
70 * Updates UI elements from user data. | 180 this.appendChild(managerPod); |
71 */ | 181 managerPod.update(); |
72 update: function() { | 182 }, |
73 this.imageElement.src = 'chrome://userimage/' + this.user.username + | 183 |
74 '?id=' + ManagerPod.userImageSalt_[this.user.username]; | 184 clearPods: function() { |
75 | 185 this.innerHTML = ''; |
76 this.nameElement.textContent = this.user.displayName; | 186 this.selectedPod_ = null; |
77 this.emailElement.textContent = this.user.emailAddress; | 187 }, |
78 }, | 188 |
79 | 189 selectPod: function(podToSelect) { |
80 showPasswordError: function() { | 190 if ((this.selectedPod_ == podToSelect) && !!podToSelect) { |
81 this.passwordElement.classList.add('password-error'); | 191 podToSelect.focusInput(); |
82 $('bubble').showTextForElement( | 192 return; |
83 this.passwordElement, | 193 } |
84 loadTimeData.getString( | 194 this.selectedPod_ = podToSelect; |
85 'createSupervisedUserWrongManagerPasswordText'), | 195 for (var i = 0, pod; pod = this.pods[i]; ++i) { |
86 cr.ui.Bubble.Attachment.BOTTOM, | 196 if (pod != podToSelect) { |
87 24, 4); | 197 pod.classList.remove('focused'); |
88 }, | 198 pod.passwordElement.value = ''; |
89 | 199 pod.passwordBlock.hidden = true; |
90 /** | 200 } |
91 * Brings focus to password field. | 201 } |
92 */ | 202 if (!podToSelect) |
93 focusInput: function() { | 203 return; |
94 this.passwordElement.focus(); | 204 podToSelect.classList.add('focused'); |
95 }, | 205 podToSelect.passwordBlock.hidden = false; |
96 | 206 podToSelect.passwordElement.value = ''; |
97 /** | 207 podToSelect.focusInput(); |
98 * Gets image element. | 208 chrome.send( |
99 * @type {!HTMLImageElement} | 209 'managerSelectedOnSupervisedUserCreationFlow', |
100 */ | 210 [podToSelect.user.username]); |
101 get imageElement() { | 211 }, |
102 return this.querySelector('.supervised-user-creation-manager-image'); | 212 |
103 }, | 213 /** |
104 | 214 * Select pod next to currently selected one in given |direction|. |
105 /** | 215 * @param {integer} direction - +1 for selecting pod below current, -1 f
or |
106 * Gets name element. | 216 * selecting pod above current. |
107 * @type {!HTMLDivElement} | 217 * @type {boolean} returns if selected pod has changed. |
108 */ | 218 */ |
109 get nameElement() { | 219 selectNextPod: function(direction) { |
110 return this.querySelector('.supervised-user-creation-manager-name'); | 220 if (!this.selectedPod_) |
111 }, | 221 return false; |
112 | 222 var index = -1; |
113 /** | 223 for (var i = 0, pod; pod = this.pods[i]; ++i) { |
114 * Gets e-mail element. | 224 if (pod == this.selectedPod_) { |
115 * @type {!HTMLDivElement} | 225 index = i; |
116 */ | 226 break; |
117 get emailElement() { | 227 } |
118 return this.querySelector('.supervised-user-creation-manager-email'); | 228 } |
119 }, | 229 if (-1 == index) |
120 | 230 return false; |
121 /** | 231 index = index + direction; |
122 * Gets password element. | 232 if (index < 0 || index >= this.pods.length) |
123 * @type {!HTMLDivElement} | 233 return false; |
124 */ | 234 this.selectPod(this.pods[index]); |
125 get passwordElement() { | |
126 return this.querySelector('.supervised-user-creation-manager-password'); | |
127 }, | |
128 | |
129 /** | |
130 * Gets password enclosing block. | |
131 * @type {!HTMLDivElement} | |
132 */ | |
133 get passwordBlock() { | |
134 return this.querySelector('.password-block'); | |
135 }, | |
136 | |
137 /** @override */ | |
138 handleMouseDown_: function(e) { | |
139 this.parentNode.selectPod(this); | |
140 // Prevent default so that we don't trigger 'focus' event. | |
141 e.preventDefault(); | |
142 }, | |
143 | |
144 /** | |
145 * The user that this pod represents. | |
146 * @type {!Object} | |
147 */ | |
148 user_: undefined, | |
149 get user() { | |
150 return this.user_; | |
151 }, | |
152 set user(userDict) { | |
153 this.user_ = userDict; | |
154 this.update(); | |
155 }, | |
156 }; | |
157 | |
158 var ManagerPodList = cr.ui.define('div'); | |
159 | |
160 /** | |
161 * UI element for selecting manager account for new supervised user. | |
162 * @type {Object} | |
163 */ | |
164 ManagerPodList.prototype = { | |
165 __proto__: HTMLDivElement.prototype, | |
166 | |
167 selectedPod_: null, | |
168 | |
169 /** @override */ | |
170 decorate: function() { | |
171 }, | |
172 | |
173 /** | |
174 * Returns all the pods in this pod list. | |
175 * @type {NodeList} | |
176 */ | |
177 get pods() { | |
178 return this.children; | |
179 }, | |
180 | |
181 addPod: function(manager) { | |
182 var managerPod = new ManagerPod({user: manager}); | |
183 this.appendChild(managerPod); | |
184 managerPod.update(); | |
185 }, | |
186 | |
187 clearPods: function() { | |
188 this.innerHTML = ''; | |
189 this.selectedPod_ = null; | |
190 }, | |
191 | |
192 selectPod: function(podToSelect) { | |
193 if ((this.selectedPod_ == podToSelect) && !!podToSelect) { | |
194 podToSelect.focusInput(); | |
195 return; | |
196 } | |
197 this.selectedPod_ = podToSelect; | |
198 for (var i = 0, pod; pod = this.pods[i]; ++i) { | |
199 if (pod != podToSelect) { | |
200 pod.classList.remove('focused'); | |
201 pod.passwordElement.value = ''; | |
202 pod.passwordBlock.hidden = true; | |
203 } | |
204 } | |
205 if (!podToSelect) | |
206 return; | |
207 podToSelect.classList.add('focused'); | |
208 podToSelect.passwordBlock.hidden = false; | |
209 podToSelect.passwordElement.value = ''; | |
210 podToSelect.focusInput(); | |
211 chrome.send('managerSelectedOnSupervisedUserCreationFlow', | |
212 [podToSelect.user.username]); | |
213 }, | |
214 | |
215 /** | |
216 * Select pod next to currently selected one in given |direction|. | |
217 * @param {integer} direction - +1 for selecting pod below current, -1 for | |
218 * selecting pod above current. | |
219 * @type {boolean} returns if selected pod has changed. | |
220 */ | |
221 selectNextPod: function(direction) { | |
222 if (!this.selectedPod_) | |
223 return false; | |
224 var index = -1; | |
225 for (var i = 0, pod; pod = this.pods[i]; ++i) { | |
226 if (pod == this.selectedPod_) { | |
227 index = i; | |
228 break; | |
229 } | |
230 } | |
231 if (-1 == index) | |
232 return false; | |
233 index = index + direction; | |
234 if (index < 0 || index >= this.pods.length) | |
235 return false; | |
236 this.selectPod(this.pods[index]); | |
237 return true; | |
238 } | |
239 }; | |
240 | |
241 var ImportPod = cr.ui.define(function() { | |
242 var node = $('supervised-user-creation-import-template').cloneNode(true); | |
243 node.removeAttribute('id'); | |
244 node.removeAttribute('hidden'); | |
245 return node; | |
246 }); | |
247 | |
248 /** | |
249 * UI element for displaying single supervised user in list of possible users | |
250 * for importing existing users. | |
251 * @type {Object} | |
252 */ | |
253 ImportPod.prototype = { | |
254 __proto__: HTMLDivElement.prototype, | |
255 | |
256 /** @override */ | |
257 decorate: function() { | |
258 // Mousedown has to be used instead of click to be able to prevent 'focus' | |
259 // event later. | |
260 this.addEventListener('mousedown', this.handleMouseDown_.bind(this)); | |
261 var screen = $('supervised-user-creation'); | |
262 var importList = screen.importList_; | |
263 }, | |
264 | |
265 /** | |
266 * Updates UI elements from user data. | |
267 */ | |
268 update: function() { | |
269 this.imageElement.src = this.user.avatarurl; | |
270 this.nameElement.textContent = this.user.name; | |
271 if (this.user.exists) { | |
272 if (this.user.conflict == 'imported') { | |
273 this.nameElement.textContent = | |
274 loadTimeData.getStringF('importUserExists', this.user.name); | |
275 } else { | |
276 this.nameElement.textContent = | |
277 loadTimeData.getStringF('importUsernameExists', this.user.name); | |
278 } | |
279 } | |
280 this.classList.toggle('imported', this.user.exists); | |
281 }, | |
282 | |
283 /** | |
284 * Gets image element. | |
285 * @type {!HTMLImageElement} | |
286 */ | |
287 get imageElement() { | |
288 return this.querySelector('.import-pod-image'); | |
289 }, | |
290 | |
291 /** | |
292 * Gets name element. | |
293 * @type {!HTMLDivElement} | |
294 */ | |
295 get nameElement() { | |
296 return this.querySelector('.import-pod-name'); | |
297 }, | |
298 | |
299 /** @override */ | |
300 handleMouseDown_: function(e) { | |
301 this.parentNode.selectPod(this); | |
302 // Prevent default so that we don't trigger 'focus' event. | |
303 e.preventDefault(); | |
304 }, | |
305 | |
306 /** | |
307 * The user that this pod represents. | |
308 * @type {Object} | |
309 */ | |
310 user_: undefined, | |
311 | |
312 get user() { | |
313 return this.user_; | |
314 }, | |
315 | |
316 set user(userDict) { | |
317 this.user_ = userDict; | |
318 this.update(); | |
319 }, | |
320 }; | |
321 | |
322 var ImportPodList = cr.ui.define('div'); | |
323 | |
324 /** | |
325 * UI element for selecting existing supervised user for import. | |
326 * @type {Object} | |
327 */ | |
328 ImportPodList.prototype = { | |
329 __proto__: HTMLDivElement.prototype, | |
330 | |
331 selectedPod_: null, | |
332 | |
333 /** @override */ | |
334 decorate: function() { | |
335 this.setAttribute('tabIndex', 0); | |
336 this.classList.add('nofocus'); | |
337 var importList = this; | |
338 var screen = $('supervised-user-creation'); | |
339 | |
340 this.addEventListener('focus', function(e) { | |
341 if (importList.selectedPod_ == null) { | |
342 if (importList.pods.length > 0) | |
343 importList.selectPod(importList.pods[0]); | |
344 } | |
345 }); | |
346 | |
347 this.addEventListener('keydown', function(e) { | |
348 switch (e.key) { | |
349 case 'ArrowUp': | |
350 importList.selectNextPod(-1); | |
351 e.stopPropagation(); | |
352 break; | |
353 case 'Enter': | |
354 if (importList.selectedPod_ != null) | |
355 screen.importSupervisedUser_(); | |
356 e.stopPropagation(); | |
357 break; | |
358 case 'ArrowDown': | |
359 importList.selectNextPod(+1); | |
360 e.stopPropagation(); | |
361 break; | |
362 } | |
363 }); | |
364 }, | |
365 | |
366 /** | |
367 * Returns all the pods in this pod list. | |
368 * @type {NodeList} | |
369 */ | |
370 get pods() { | |
371 return this.children; | |
372 }, | |
373 | |
374 /** | |
375 * Returns selected pod. | |
376 * @type {Node} | |
377 */ | |
378 get selectedPod() { | |
379 return this.selectedPod_; | |
380 }, | |
381 | |
382 addPod: function(user) { | |
383 var importPod = new ImportPod({user: user}); | |
384 this.appendChild(importPod); | |
385 importPod.update(); | |
386 }, | |
387 | |
388 clearPods: function() { | |
389 this.innerHTML = ''; | |
390 this.selectedPod_ = null; | |
391 }, | |
392 | |
393 scrollIntoView: function(pod) { | |
394 scroller = this.parentNode; | |
395 var itemHeight = pod.getBoundingClientRect().height; | |
396 var scrollTop = scroller.scrollTop; | |
397 var top = pod.offsetTop - scroller.offsetTop; | |
398 var clientHeight = scroller.clientHeight; | |
399 | |
400 var self = scroller; | |
401 | |
402 // Function to adjust the tops of viewport and row. | |
403 function scrollToAdjustTop() { | |
404 self.scrollTop = top; | |
405 return true; | |
406 } | |
407 // Function to adjust the bottoms of viewport and row. | |
408 function scrollToAdjustBottom() { | |
409 var cs = getComputedStyle(self); | |
410 var paddingY = parseInt(cs.paddingTop, 10) + | |
411 parseInt(cs.paddingBottom, 10); | |
412 | |
413 if (top + itemHeight > scrollTop + clientHeight - paddingY) { | |
414 self.scrollTop = top + itemHeight - clientHeight + paddingY; | |
415 return true; | 235 return true; |
416 } | 236 } |
417 return false; | |
418 } | |
419 | |
420 // Check if the entire of given indexed row can be shown in the viewport. | |
421 if (itemHeight <= clientHeight) { | |
422 if (top < scrollTop) | |
423 return scrollToAdjustTop(); | |
424 if (scrollTop + clientHeight < top + itemHeight) | |
425 return scrollToAdjustBottom(); | |
426 } else { | |
427 if (scrollTop < top) | |
428 return scrollToAdjustTop(); | |
429 if (top + itemHeight < scrollTop + clientHeight) | |
430 return scrollToAdjustBottom(); | |
431 } | |
432 return false; | |
433 }, | |
434 | |
435 /** | |
436 * @param {Element} podToSelect - pod to select, can be null. | |
437 */ | |
438 selectPod: function(podToSelect) { | |
439 if ((this.selectedPod_ == podToSelect) && !!podToSelect) { | |
440 return; | |
441 } | |
442 this.selectedPod_ = podToSelect; | |
443 for (var i = 0; i < this.pods.length; i++) { | |
444 var pod = this.pods[i]; | |
445 if (pod != podToSelect) | |
446 pod.classList.remove('focused'); | |
447 } | |
448 if (!podToSelect) | |
449 return; | |
450 podToSelect.classList.add('focused'); | |
451 podToSelect.focus(); | |
452 var screen = $('supervised-user-creation'); | |
453 if (!this.selectedPod_) { | |
454 screen.getScreenButton('import').disabled = true; | |
455 } else { | |
456 screen.getScreenButton('import').disabled = | |
457 this.selectedPod_.user.exists; | |
458 if (!this.selectedPod_.user.exists) { | |
459 chrome.send('userSelectedForImportInSupervisedUserCreationFlow', | |
460 [podToSelect.user.id]); | |
461 } | |
462 } | |
463 }, | |
464 | |
465 selectNextPod: function(direction) { | |
466 if (!this.selectedPod_) | |
467 return false; | |
468 var index = -1; | |
469 for (var i = 0, pod; pod = this.pods[i]; ++i) { | |
470 if (pod == this.selectedPod_) { | |
471 index = i; | |
472 break; | |
473 } | |
474 } | |
475 if (-1 == index) | |
476 return false; | |
477 index = index + direction; | |
478 if (index < 0 || index >= this.pods.length) | |
479 return false; | |
480 this.selectPod(this.pods[index]); | |
481 return true; | |
482 }, | |
483 | |
484 selectUser: function(user_id) { | |
485 for (var i = 0, pod; pod = this.pods[i]; ++i) { | |
486 if (pod.user.id == user_id) { | |
487 this.selectPod(pod); | |
488 this.scrollIntoView(pod); | |
489 break; | |
490 } | |
491 } | |
492 }, | |
493 }; | |
494 | |
495 return { | |
496 EXTERNAL_API: [ | |
497 'loadManagers', | |
498 'setCameraPresent', | |
499 'setDefaultImages', | |
500 'setExistingSupervisedUsers', | |
501 'showErrorPage', | |
502 'showIntroPage', | |
503 'showManagerPage', | |
504 'showManagerPasswordError', | |
505 'showPage', | |
506 'showPasswordError', | |
507 'showProgress', | |
508 'showStatusError', | |
509 'showTutorialPage', | |
510 'showUsernamePage', | |
511 'supervisedUserNameError', | |
512 'supervisedUserNameOk', | |
513 'supervisedUserSuggestImport', | |
514 ], | |
515 | |
516 lastVerifiedName_: null, | |
517 lastIncorrectUserName_: null, | |
518 managerList_: null, | |
519 importList_: null, | |
520 | |
521 currentPage_: null, | |
522 imagesRequested_: false, | |
523 | |
524 // Contains data that can be auto-shared with handler. | |
525 context_: {}, | |
526 | |
527 /** @override */ | |
528 decorate: function() { | |
529 this.managerList_ = new ManagerPodList(); | |
530 $('supervised-user-creation-managers-pane').appendChild( | |
531 this.managerList_); | |
532 | |
533 this.importList_ = new ImportPodList(); | |
534 $('supervised-user-creation-import-pane').appendChild(this.importList_); | |
535 | |
536 var userNameField = $('supervised-user-creation-name'); | |
537 var passwordField = $('supervised-user-creation-password'); | |
538 var password2Field = $('supervised-user-creation-password-confirm'); | |
539 | |
540 var creationScreen = this; | |
541 | |
542 var hideUserPasswordError = function(element) { | |
543 $('bubble').hide(); | |
544 $('supervised-user-creation-password').classList.remove( | |
545 'password-error'); | |
546 }; | 237 }; |
547 | 238 |
548 this.configureTextInput(userNameField, | 239 var ImportPod = cr.ui.define(function() { |
549 this.checkUserName_.bind(this), | 240 var node = |
550 this.validIfNotEmpty_.bind(this), | 241 $('supervised-user-creation-import-template').cloneNode(true); |
551 function(element) { | 242 node.removeAttribute('id'); |
552 passwordField.focus(); | 243 node.removeAttribute('hidden'); |
553 }, | 244 return node; |
554 this.clearUserNameError_.bind(this)); | |
555 this.configureTextInput(passwordField, | |
556 this.updateNextButtonForUser_.bind(this), | |
557 this.validIfNotEmpty_.bind(this), | |
558 function(element) { | |
559 password2Field.focus(); | |
560 }, | |
561 hideUserPasswordError); | |
562 this.configureTextInput(password2Field, | |
563 this.updateNextButtonForUser_.bind(this), | |
564 this.validIfNotEmpty_.bind(this), | |
565 function(element) { | |
566 creationScreen.getScreenButton('next').focus(); | |
567 }, | |
568 hideUserPasswordError); | |
569 | |
570 this.getScreenButton('error').addEventListener('click', function(e) { | |
571 creationScreen.handleErrorButtonPressed_(); | |
572 e.stopPropagation(); | |
573 }); | 245 }); |
574 | 246 |
575 /* | 247 /** |
576 TODO(antrim) : this is an explicit code duplications with UserImageScreen. | 248 * UI element for displaying single supervised user in list of possible |
577 It should be removed by issue 251179. | 249 * users for importing existing users. |
578 */ | 250 * @type {Object} |
579 var imageGrid = this.getScreenElement('image-grid'); | 251 */ |
580 UserImagesGrid.decorate(imageGrid); | 252 ImportPod.prototype = { |
581 | 253 __proto__: HTMLDivElement.prototype, |
582 // Preview image will track the selected item's URL. | 254 |
583 var previewElement = this.getScreenElement('image-preview'); | 255 /** @override */ |
584 previewElement.oncontextmenu = function(e) { e.preventDefault(); }; | 256 decorate: function() { |
585 | 257 // Mousedown has to be used instead of click to be able to prevent |
586 imageGrid.previewElement = previewElement; | 258 // 'focus' event later. |
587 imageGrid.selectionType = 'default'; | 259 this.addEventListener('mousedown', this.handleMouseDown_.bind(this)); |
588 imageGrid.flipPhotoElement = this.getScreenElement('flip-photo'); | 260 var screen = $('supervised-user-creation'); |
589 | 261 var importList = screen.importList_; |
590 imageGrid.addEventListener('activate', | 262 }, |
591 this.handleActivate_.bind(this)); | 263 |
592 imageGrid.addEventListener('select', | 264 /** |
593 this.handleSelect_.bind(this)); | 265 * Updates UI elements from user data. |
594 imageGrid.addEventListener('phototaken', | 266 */ |
595 this.handlePhotoTaken_.bind(this)); | 267 update: function() { |
596 imageGrid.addEventListener('photoupdated', | 268 this.imageElement.src = this.user.avatarurl; |
597 this.handlePhotoUpdated_.bind(this)); | 269 this.nameElement.textContent = this.user.name; |
598 // Set the title for camera item in the grid. | 270 if (this.user.exists) { |
599 imageGrid.setCameraTitles( | 271 if (this.user.conflict == 'imported') { |
600 loadTimeData.getString('takePhoto'), | 272 this.nameElement.textContent = |
601 loadTimeData.getString('photoFromCamera')); | 273 loadTimeData.getStringF('importUserExists', this.user.name); |
602 | 274 } else { |
603 this.getScreenElement('take-photo').addEventListener( | 275 this.nameElement.textContent = loadTimeData.getStringF( |
604 'click', this.handleTakePhoto_.bind(this)); | 276 'importUsernameExists', this.user.name); |
605 this.getScreenElement('discard-photo').addEventListener( | 277 } |
606 'click', this.handleDiscardPhoto_.bind(this)); | 278 } |
607 | 279 this.classList.toggle('imported', this.user.exists); |
608 // Toggle 'animation' class for the duration of WebKit transition. | 280 }, |
609 this.getScreenElement('flip-photo').addEventListener( | 281 |
610 'click', this.handleFlipPhoto_.bind(this)); | 282 /** |
611 this.getScreenElement('image-stream-crop').addEventListener( | 283 * Gets image element. |
612 'transitionend', function(e) { | 284 * @type {!HTMLImageElement} |
613 previewElement.classList.remove('animation'); | 285 */ |
| 286 get imageElement() { |
| 287 return this.querySelector('.import-pod-image'); |
| 288 }, |
| 289 |
| 290 /** |
| 291 * Gets name element. |
| 292 * @type {!HTMLDivElement} |
| 293 */ |
| 294 get nameElement() { |
| 295 return this.querySelector('.import-pod-name'); |
| 296 }, |
| 297 |
| 298 /** @override */ |
| 299 handleMouseDown_: function(e) { |
| 300 this.parentNode.selectPod(this); |
| 301 // Prevent default so that we don't trigger 'focus' event. |
| 302 e.preventDefault(); |
| 303 }, |
| 304 |
| 305 /** |
| 306 * The user that this pod represents. |
| 307 * @type {Object} |
| 308 */ |
| 309 user_: undefined, |
| 310 |
| 311 get user() { |
| 312 return this.user_; |
| 313 }, |
| 314 |
| 315 set user(userDict) { |
| 316 this.user_ = userDict; |
| 317 this.update(); |
| 318 }, |
| 319 }; |
| 320 |
| 321 var ImportPodList = cr.ui.define('div'); |
| 322 |
| 323 /** |
| 324 * UI element for selecting existing supervised user for import. |
| 325 * @type {Object} |
| 326 */ |
| 327 ImportPodList.prototype = { |
| 328 __proto__: HTMLDivElement.prototype, |
| 329 |
| 330 selectedPod_: null, |
| 331 |
| 332 /** @override */ |
| 333 decorate: function() { |
| 334 this.setAttribute('tabIndex', 0); |
| 335 this.classList.add('nofocus'); |
| 336 var importList = this; |
| 337 var screen = $('supervised-user-creation'); |
| 338 |
| 339 this.addEventListener('focus', function(e) { |
| 340 if (importList.selectedPod_ == null) { |
| 341 if (importList.pods.length > 0) |
| 342 importList.selectPod(importList.pods[0]); |
| 343 } |
614 }); | 344 }); |
615 this.getScreenElement('image-preview-img').addEventListener( | 345 |
616 'transitionend', function(e) { | 346 this.addEventListener('keydown', function(e) { |
617 previewElement.classList.remove('animation'); | 347 switch (e.key) { |
| 348 case 'ArrowUp': |
| 349 importList.selectNextPod(-1); |
| 350 e.stopPropagation(); |
| 351 break; |
| 352 case 'Enter': |
| 353 if (importList.selectedPod_ != null) |
| 354 screen.importSupervisedUser_(); |
| 355 e.stopPropagation(); |
| 356 break; |
| 357 case 'ArrowDown': |
| 358 importList.selectNextPod(+1); |
| 359 e.stopPropagation(); |
| 360 break; |
| 361 } |
618 }); | 362 }); |
619 | 363 }, |
620 $('supervised-user-creation-navigation').addEventListener('close', | 364 |
621 this.cancel.bind(this)); | 365 /** |
622 }, | 366 * Returns all the pods in this pod list. |
623 | 367 * @type {NodeList} |
624 buttonIds: [], | 368 */ |
625 | 369 get pods() { |
626 /** | 370 return this.children; |
627 * Creates button for adding to controls. | 371 }, |
628 * @param {string} buttonId -- id for button, have to be unique within | 372 |
629 * screen. Actual id will be prefixed with screen name and appended with | 373 /** |
630 * '-button'. Use getScreenButton(buttonId) to find it later. | 374 * Returns selected pod. |
631 * @param {string} i18nPrefix -- screen prefix for i18n values. | 375 * @type {Node} |
632 * @param {function} callback -- will be called on button press with | 376 */ |
633 * buttonId parameter. | 377 get selectedPod() { |
634 * @param {array} pages -- list of pages where this button should be | 378 return this.selectedPod_; |
635 * displayed. | 379 }, |
636 * @param {array} classes -- list of additional CSS classes for button. | 380 |
637 */ | 381 addPod: function(user) { |
638 makeButton: function(buttonId, i18nPrefix, callback, pages, classes) { | 382 var importPod = new ImportPod({user: user}); |
639 var capitalizedId = buttonId.charAt(0).toUpperCase() + buttonId.slice(1); | 383 this.appendChild(importPod); |
640 this.buttonIds.push(buttonId); | 384 importPod.update(); |
641 var result = this.ownerDocument.createElement('button'); | 385 }, |
642 result.id = this.name() + '-' + buttonId + '-button'; | 386 |
643 result.classList.add('screen-control-button'); | 387 clearPods: function() { |
644 for (var i = 0; i < classes.length; i++) { | 388 this.innerHTML = ''; |
645 result.classList.add(classes[i]); | 389 this.selectedPod_ = null; |
646 } | 390 }, |
647 result.textContent = loadTimeData. | 391 |
648 getString(i18nPrefix + capitalizedId + 'ButtonTitle'); | 392 scrollIntoView: function(pod) { |
649 result.addEventListener('click', function(e) { | 393 scroller = this.parentNode; |
650 callback(buttonId); | 394 var itemHeight = pod.getBoundingClientRect().height; |
651 e.stopPropagation(); | 395 var scrollTop = scroller.scrollTop; |
652 }); | 396 var top = pod.offsetTop - scroller.offsetTop; |
653 result.pages = pages; | 397 var clientHeight = scroller.clientHeight; |
654 return result; | 398 |
655 }, | 399 var self = scroller; |
656 | 400 |
657 /** | 401 // Function to adjust the tops of viewport and row. |
658 * Simple validator for |configureTextInput|. | 402 function scrollToAdjustTop() { |
659 * Element is considered valid if it has any text. | 403 self.scrollTop = top; |
660 * @param {Element} element - element to be validated. | 404 return true; |
661 * @return {boolean} - true, if element has any text. | 405 } |
662 */ | 406 // Function to adjust the bottoms of viewport and row. |
663 validIfNotEmpty_: function(element) { | 407 function scrollToAdjustBottom() { |
664 return (element.value.length > 0); | 408 var cs = getComputedStyle(self); |
665 }, | 409 var paddingY = |
666 | 410 parseInt(cs.paddingTop, 10) + parseInt(cs.paddingBottom, 10); |
667 /** | 411 |
668 * Configure text-input |element|. | 412 if (top + itemHeight > scrollTop + clientHeight - paddingY) { |
669 * @param {Element} element - element to be configured. | 413 self.scrollTop = top + itemHeight - clientHeight + paddingY; |
670 * @param {function(element)} inputChangeListener - function that will be | 414 return true; |
671 * called upon any button press/release. | 415 } |
672 * @param {function(element)} validator - function that will be called when | 416 return false; |
673 * Enter is pressed. If it returns |true| then advance to next element. | 417 } |
674 * @param {function(element)} moveFocus - function that will determine next | 418 |
675 * element and move focus to it. | 419 // Check if the entire of given indexed row can be shown in the |
676 * @param {function(element)} errorHider - function that is called upon | 420 // viewport. |
677 * every button press, so that any associated error can be hidden. | 421 if (itemHeight <= clientHeight) { |
678 */ | 422 if (top < scrollTop) |
679 configureTextInput: function(element, | 423 return scrollToAdjustTop(); |
680 inputChangeListener, | 424 if (scrollTop + clientHeight < top + itemHeight) |
681 validator, | 425 return scrollToAdjustBottom(); |
682 moveFocus, | |
683 errorHider) { | |
684 element.addEventListener('keydown', function(e) { | |
685 if (e.key == 'Enter') { | |
686 var dataValid = true; | |
687 if (validator) | |
688 dataValid = validator(element); | |
689 if (!dataValid) { | |
690 element.focus(); | |
691 } else { | 426 } else { |
692 if (moveFocus) | 427 if (scrollTop < top) |
693 moveFocus(element); | 428 return scrollToAdjustTop(); |
694 } | 429 if (top + itemHeight < scrollTop + clientHeight) |
695 e.stopPropagation(); | 430 return scrollToAdjustBottom(); |
696 return; | 431 } |
697 } | 432 return false; |
698 if (errorHider) | 433 }, |
699 errorHider(element); | 434 |
700 if (inputChangeListener) | 435 /** |
701 inputChangeListener(element); | 436 * @param {Element} podToSelect - pod to select, can be null. |
702 }); | 437 */ |
703 element.addEventListener('keyup', function(e) { | 438 selectPod: function(podToSelect) { |
704 if (inputChangeListener) | 439 if ((this.selectedPod_ == podToSelect) && !!podToSelect) { |
705 inputChangeListener(element); | 440 return; |
706 }); | 441 } |
707 }, | 442 this.selectedPod_ = podToSelect; |
708 | 443 for (var i = 0; i < this.pods.length; i++) { |
709 /** | 444 var pod = this.pods[i]; |
710 * Makes element from template. | 445 if (pod != podToSelect) |
711 * @param {string} templateId -- template will be looked up within screen | 446 pod.classList.remove('focused'); |
712 * by class with name "template-<templateId>". | 447 } |
713 * @param {string} elementId -- id for result, uinque within screen. Actual | 448 if (!podToSelect) |
714 * id will be prefixed with screen name. Use getScreenElement(id) to find | 449 return; |
715 * it later. | 450 podToSelect.classList.add('focused'); |
716 */ | 451 podToSelect.focus(); |
717 makeFromTemplate: function(templateId, elementId) { | 452 var screen = $('supervised-user-creation'); |
718 var templateClassName = 'template-' + templateId; | 453 if (!this.selectedPod_) { |
719 var templateNode = this.querySelector('.' + templateClassName); | 454 screen.getScreenButton('import').disabled = true; |
720 var screenPrefix = this.name() + '-'; | 455 } else { |
721 var result = templateNode.cloneNode(true); | 456 screen.getScreenButton('import').disabled = |
722 result.classList.remove(templateClassName); | 457 this.selectedPod_.user.exists; |
723 result.id = screenPrefix + elementId; | 458 if (!this.selectedPod_.user.exists) { |
724 return result; | 459 chrome.send( |
725 }, | 460 'userSelectedForImportInSupervisedUserCreationFlow', |
726 | 461 [podToSelect.user.id]); |
727 /** | 462 } |
728 * @param {string} buttonId -- id of button to be found, | 463 } |
729 * @return {Element} button created by makeButton with given buttonId. | 464 }, |
730 */ | 465 |
731 getScreenButton: function(buttonId) { | 466 selectNextPod: function(direction) { |
732 var fullId = this.name() + '-' + buttonId + '-button'; | 467 if (!this.selectedPod_) |
733 return this.getScreenElement(buttonId + '-button'); | 468 return false; |
734 }, | 469 var index = -1; |
735 | 470 for (var i = 0, pod; pod = this.pods[i]; ++i) { |
736 /** | 471 if (pod == this.selectedPod_) { |
737 * @param {string} elementId -- id of element to be found, | 472 index = i; |
738 * @return {Element} button created by makeFromTemplate with elementId. | 473 break; |
739 */ | 474 } |
740 getScreenElement: function(elementId) { | 475 } |
741 var fullId = this.name() + '-' + elementId; | 476 if (-1 == index) |
742 return $(fullId); | 477 return false; |
743 }, | 478 index = index + direction; |
744 | 479 if (index < 0 || index >= this.pods.length) |
745 /** | 480 return false; |
746 * Screen controls. | 481 this.selectPod(this.pods[index]); |
747 * @type {!Array} Array of Buttons. | 482 return true; |
748 */ | 483 }, |
749 get buttons() { | 484 |
750 var links = this.ownerDocument.createElement('div'); | 485 selectUser: function(user_id) { |
751 var buttons = this.ownerDocument.createElement('div'); | 486 for (var i = 0, pod; pod = this.pods[i]; ++i) { |
752 links.classList.add('controls-links'); | 487 if (pod.user.id == user_id) { |
753 buttons.classList.add('controls-buttons'); | 488 this.selectPod(pod); |
754 | 489 this.scrollIntoView(pod); |
755 var importLink = this.makeFromTemplate('import-supervised-user-link', | 490 break; |
756 'import-link'); | 491 } |
757 importLink.hidden = true; | 492 } |
758 links.appendChild(importLink); | 493 }, |
759 | 494 }; |
760 var linkElement = importLink.querySelector('.signin-link'); | 495 |
761 linkElement.addEventListener('click', | 496 return { |
762 this.importLinkPressed_.bind(this)); | 497 EXTERNAL_API: [ |
763 | 498 'loadManagers', |
764 var createLink = this.makeFromTemplate('create-supervised-user-link', | 499 'setCameraPresent', |
765 'create-link'); | 500 'setDefaultImages', |
766 createLink.hidden = true; | 501 'setExistingSupervisedUsers', |
767 links.appendChild(createLink); | 502 'showErrorPage', |
768 | 503 'showIntroPage', |
769 var status = this.makeFromTemplate('status-container', 'status'); | 504 'showManagerPage', |
770 buttons.appendChild(status); | 505 'showManagerPasswordError', |
771 | 506 'showPage', |
772 linkElement = createLink.querySelector('.signin-link'); | 507 'showPasswordError', |
773 linkElement.addEventListener('click', | 508 'showProgress', |
774 this.createLinkPressed_.bind(this)); | 509 'showStatusError', |
775 | 510 'showTutorialPage', |
776 buttons.appendChild(this.makeButton( | 511 'showUsernamePage', |
777 'start', | 512 'supervisedUserNameError', |
778 'supervisedUserCreationFlow', | 513 'supervisedUserNameOk', |
779 this.startButtonPressed_.bind(this), | 514 'supervisedUserSuggestImport', |
780 ['intro'], | 515 ], |
781 ['custom-appearance', 'button-fancy', 'button-blue'])); | 516 |
782 | 517 lastVerifiedName_: null, |
783 buttons.appendChild(this.makeButton( | 518 lastIncorrectUserName_: null, |
784 'prev', | 519 managerList_: null, |
785 'supervisedUserCreationFlow', | 520 importList_: null, |
786 this.prevButtonPressed_.bind(this), | 521 |
787 ['manager'], | 522 currentPage_: null, |
788 [])); | 523 imagesRequested_: false, |
789 | 524 |
790 buttons.appendChild(this.makeButton( | 525 // Contains data that can be auto-shared with handler. |
791 'next', | 526 context_: {}, |
792 'supervisedUserCreationFlow', | 527 |
793 this.nextButtonPressed_.bind(this), | 528 /** @override */ |
794 ['manager', 'username'], | 529 decorate: function() { |
795 [])); | 530 this.managerList_ = new ManagerPodList(); |
796 | 531 $('supervised-user-creation-managers-pane') |
797 buttons.appendChild(this.makeButton( | 532 .appendChild(this.managerList_); |
798 'import', | 533 |
799 'supervisedUserCreationFlow', | 534 this.importList_ = new ImportPodList(); |
800 this.importButtonPressed_.bind(this), | 535 $('supervised-user-creation-import-pane') |
801 ['import', 'import-password'], | 536 .appendChild(this.importList_); |
802 [])); | 537 |
803 | 538 var userNameField = $('supervised-user-creation-name'); |
804 buttons.appendChild(this.makeButton( | 539 var passwordField = $('supervised-user-creation-password'); |
805 'gotit', | 540 var password2Field = $('supervised-user-creation-password-confirm'); |
806 'supervisedUserCreationFlow', | 541 |
807 this.gotItButtonPressed_.bind(this), | 542 var creationScreen = this; |
808 ['created'], | 543 |
809 ['custom-appearance', 'button-fancy', 'button-blue'])); | 544 var hideUserPasswordError = function(element) { |
810 return [links, buttons]; | 545 $('bubble').hide(); |
811 }, | 546 $('supervised-user-creation-password') |
812 | 547 .classList.remove('password-error'); |
813 /** | 548 }; |
814 * Does sanity check and calls backend with current user name/password pair | 549 |
815 * to authenticate manager. May result in showManagerPasswordError. | 550 this.configureTextInput( |
816 * @private | 551 userNameField, this.checkUserName_.bind(this), |
817 */ | 552 this.validIfNotEmpty_.bind(this), function(element) { |
818 validateAndLogInAsManager_: function() { | 553 passwordField.focus(); |
819 var selectedPod = this.managerList_.selectedPod_; | 554 }, this.clearUserNameError_.bind(this)); |
820 if (null == selectedPod) | 555 this.configureTextInput( |
821 return; | 556 passwordField, this.updateNextButtonForUser_.bind(this), |
822 | 557 this.validIfNotEmpty_.bind(this), function(element) { |
823 var managerId = selectedPod.user.username; | 558 password2Field.focus(); |
824 var managerDisplayId = selectedPod.user.emailAddress; | 559 }, hideUserPasswordError); |
825 var managerPassword = selectedPod.passwordElement.value; | 560 this.configureTextInput( |
826 if (managerPassword.length == 0) | 561 password2Field, this.updateNextButtonForUser_.bind(this), |
827 return; | 562 this.validIfNotEmpty_.bind(this), function(element) { |
828 if (this.disabled) | 563 creationScreen.getScreenButton('next').focus(); |
829 return; | 564 }, hideUserPasswordError); |
830 this.disabled = true; | 565 |
831 this.context_.managerId = managerId; | 566 this.getScreenButton('error').addEventListener('click', function(e) { |
832 this.context_.managerDisplayId = managerDisplayId; | 567 creationScreen.handleErrorButtonPressed_(); |
833 this.context_.managerName = selectedPod.user.displayName; | 568 e.stopPropagation(); |
834 chrome.send('authenticateManagerInSupervisedUserCreationFlow', | 569 }); |
835 [managerId, managerPassword]); | 570 |
836 }, | 571 /* |
837 | 572 TODO(antrim) : this is an explicit code duplications with |
838 /** | 573 UserImageScreen. It should be removed by issue 251179. |
839 * Does sanity check and calls backend with user display name/password pair | 574 */ |
840 * to create a user. | 575 var imageGrid = this.getScreenElement('image-grid'); |
841 * @private | 576 UserImagesGrid.decorate(imageGrid); |
842 */ | 577 |
843 validateAndCreateSupervisedUser_: function() { | 578 // Preview image will track the selected item's URL. |
844 var firstPassword = $('supervised-user-creation-password').value; | 579 var previewElement = this.getScreenElement('image-preview'); |
845 var secondPassword = | 580 previewElement.oncontextmenu = function(e) { |
846 $('supervised-user-creation-password-confirm').value; | 581 e.preventDefault(); |
847 var userName = $('supervised-user-creation-name').value; | 582 }; |
848 if (firstPassword != secondPassword) { | 583 |
849 this.showPasswordError(loadTimeData.getString( | 584 imageGrid.previewElement = previewElement; |
850 'createSupervisedUserPasswordMismatchError')); | 585 imageGrid.selectionType = 'default'; |
851 return; | 586 imageGrid.flipPhotoElement = this.getScreenElement('flip-photo'); |
852 } | 587 |
853 if (this.disabled) | 588 imageGrid.addEventListener( |
854 return; | 589 'activate', this.handleActivate_.bind(this)); |
855 this.disabled = true; | 590 imageGrid.addEventListener('select', this.handleSelect_.bind(this)); |
856 | 591 imageGrid.addEventListener( |
857 this.context_.supervisedName = userName; | 592 'phototaken', this.handlePhotoTaken_.bind(this)); |
858 chrome.send('specifySupervisedUserCreationFlowUserData', | 593 imageGrid.addEventListener( |
859 [userName, firstPassword]); | 594 'photoupdated', this.handlePhotoUpdated_.bind(this)); |
860 }, | 595 // Set the title for camera item in the grid. |
861 | 596 imageGrid.setCameraTitles( |
862 /** | 597 loadTimeData.getString('takePhoto'), |
863 * Does sanity check and calls backend with selected existing supervised | 598 loadTimeData.getString('photoFromCamera')); |
864 * user id to import user. | 599 |
865 * @private | 600 this.getScreenElement('take-photo') |
866 */ | 601 .addEventListener('click', this.handleTakePhoto_.bind(this)); |
867 importSupervisedUser_: function() { | 602 this.getScreenElement('discard-photo') |
868 if (this.disabled) | 603 .addEventListener('click', this.handleDiscardPhoto_.bind(this)); |
869 return; | 604 |
870 if (this.currentPage_ == 'import-password') { | 605 // Toggle 'animation' class for the duration of WebKit transition. |
871 var firstPassword = this.getScreenElement('password').value; | 606 this.getScreenElement('flip-photo') |
872 var secondPassword = this.getScreenElement('password-confirm').value; | 607 .addEventListener('click', this.handleFlipPhoto_.bind(this)); |
873 if (firstPassword != secondPassword) { | 608 this.getScreenElement('image-stream-crop') |
874 this.showPasswordError(loadTimeData.getString( | 609 .addEventListener('transitionend', function(e) { |
875 'createSupervisedUserPasswordMismatchError')); | 610 previewElement.classList.remove('animation'); |
876 return; | 611 }); |
877 } | 612 this.getScreenElement('image-preview-img') |
878 var userId = this.context_.importUserId; | 613 .addEventListener('transitionend', function(e) { |
879 this.disabled = true; | 614 previewElement.classList.remove('animation'); |
880 chrome.send('importSupervisedUserWithPassword', | 615 }); |
881 [userId, firstPassword]); | 616 |
882 return; | 617 $('supervised-user-creation-navigation') |
883 } else { | 618 .addEventListener('close', this.cancel.bind(this)); |
884 var selectedPod = this.importList_.selectedPod_; | 619 }, |
885 if (!selectedPod) | 620 |
886 return; | 621 buttonIds: [], |
887 var user = selectedPod.user; | 622 |
888 var userId = user.id; | 623 /** |
889 | 624 * Creates button for adding to controls. |
890 this.context_.importUserId = userId; | 625 * @param {string} buttonId -- id for button, have to be unique within |
891 this.context_.supervisedName = user.name; | 626 * screen. Actual id will be prefixed with screen name and appended |
892 this.context_.selectedImageUrl = user.avatarurl; | 627 * with |
893 if (!user.needPassword) { | 628 * '-button'. Use getScreenButton(buttonId) to find it later. |
| 629 * @param {string} i18nPrefix -- screen prefix for i18n values. |
| 630 * @param {function} callback -- will be called on button press with |
| 631 * buttonId parameter. |
| 632 * @param {array} pages -- list of pages where this button should be |
| 633 * displayed. |
| 634 * @param {array} classes -- list of additional CSS classes for button. |
| 635 */ |
| 636 makeButton: function(buttonId, i18nPrefix, callback, pages, classes) { |
| 637 var capitalizedId = |
| 638 buttonId.charAt(0).toUpperCase() + buttonId.slice(1); |
| 639 this.buttonIds.push(buttonId); |
| 640 var result = this.ownerDocument.createElement('button'); |
| 641 result.id = this.name() + '-' + buttonId + '-button'; |
| 642 result.classList.add('screen-control-button'); |
| 643 for (var i = 0; i < classes.length; i++) { |
| 644 result.classList.add(classes[i]); |
| 645 } |
| 646 result.textContent = loadTimeData.getString( |
| 647 i18nPrefix + capitalizedId + 'ButtonTitle'); |
| 648 result.addEventListener('click', function(e) { |
| 649 callback(buttonId); |
| 650 e.stopPropagation(); |
| 651 }); |
| 652 result.pages = pages; |
| 653 return result; |
| 654 }, |
| 655 |
| 656 /** |
| 657 * Simple validator for |configureTextInput|. |
| 658 * Element is considered valid if it has any text. |
| 659 * @param {Element} element - element to be validated. |
| 660 * @return {boolean} - true, if element has any text. |
| 661 */ |
| 662 validIfNotEmpty_: function(element) { |
| 663 return (element.value.length > 0); |
| 664 }, |
| 665 |
| 666 /** |
| 667 * Configure text-input |element|. |
| 668 * @param {Element} element - element to be configured. |
| 669 * @param {function(element)} inputChangeListener - function that will b
e |
| 670 * called upon any button press/release. |
| 671 * @param {function(element)} validator - function that will be called w
hen |
| 672 * Enter is pressed. If it returns |true| then advance to next |
| 673 * element. |
| 674 * @param {function(element)} moveFocus - function that will determine n
ext |
| 675 * element and move focus to it. |
| 676 * @param {function(element)} errorHider - function that is called upon |
| 677 * every button press, so that any associated error can be hidden. |
| 678 */ |
| 679 configureTextInput: function( |
| 680 element, inputChangeListener, validator, moveFocus, errorHider) { |
| 681 element.addEventListener('keydown', function(e) { |
| 682 if (e.key == 'Enter') { |
| 683 var dataValid = true; |
| 684 if (validator) |
| 685 dataValid = validator(element); |
| 686 if (!dataValid) { |
| 687 element.focus(); |
| 688 } else { |
| 689 if (moveFocus) |
| 690 moveFocus(element); |
| 691 } |
| 692 e.stopPropagation(); |
| 693 return; |
| 694 } |
| 695 if (errorHider) |
| 696 errorHider(element); |
| 697 if (inputChangeListener) |
| 698 inputChangeListener(element); |
| 699 }); |
| 700 element.addEventListener('keyup', function(e) { |
| 701 if (inputChangeListener) |
| 702 inputChangeListener(element); |
| 703 }); |
| 704 }, |
| 705 |
| 706 /** |
| 707 * Makes element from template. |
| 708 * @param {string} templateId -- template will be looked up within scree
n |
| 709 * by class with name "template-<templateId>". |
| 710 * @param {string} elementId -- id for result, uinque within screen. Act
ual |
| 711 * id will be prefixed with screen name. Use getScreenElement(id) to |
| 712 * find it later. |
| 713 */ |
| 714 makeFromTemplate: function(templateId, elementId) { |
| 715 var templateClassName = 'template-' + templateId; |
| 716 var templateNode = this.querySelector('.' + templateClassName); |
| 717 var screenPrefix = this.name() + '-'; |
| 718 var result = templateNode.cloneNode(true); |
| 719 result.classList.remove(templateClassName); |
| 720 result.id = screenPrefix + elementId; |
| 721 return result; |
| 722 }, |
| 723 |
| 724 /** |
| 725 * @param {string} buttonId -- id of button to be found, |
| 726 * @return {Element} button created by makeButton with given buttonId. |
| 727 */ |
| 728 getScreenButton: function(buttonId) { |
| 729 var fullId = this.name() + '-' + buttonId + '-button'; |
| 730 return this.getScreenElement(buttonId + '-button'); |
| 731 }, |
| 732 |
| 733 /** |
| 734 * @param {string} elementId -- id of element to be found, |
| 735 * @return {Element} button created by makeFromTemplate with elementId. |
| 736 */ |
| 737 getScreenElement: function(elementId) { |
| 738 var fullId = this.name() + '-' + elementId; |
| 739 return $(fullId); |
| 740 }, |
| 741 |
| 742 /** |
| 743 * Screen controls. |
| 744 * @type {!Array} Array of Buttons. |
| 745 */ |
| 746 get buttons() { |
| 747 var links = this.ownerDocument.createElement('div'); |
| 748 var buttons = this.ownerDocument.createElement('div'); |
| 749 links.classList.add('controls-links'); |
| 750 buttons.classList.add('controls-buttons'); |
| 751 |
| 752 var importLink = this.makeFromTemplate( |
| 753 'import-supervised-user-link', 'import-link'); |
| 754 importLink.hidden = true; |
| 755 links.appendChild(importLink); |
| 756 |
| 757 var linkElement = importLink.querySelector('.signin-link'); |
| 758 linkElement.addEventListener( |
| 759 'click', this.importLinkPressed_.bind(this)); |
| 760 |
| 761 var createLink = this.makeFromTemplate( |
| 762 'create-supervised-user-link', 'create-link'); |
| 763 createLink.hidden = true; |
| 764 links.appendChild(createLink); |
| 765 |
| 766 var status = this.makeFromTemplate('status-container', 'status'); |
| 767 buttons.appendChild(status); |
| 768 |
| 769 linkElement = createLink.querySelector('.signin-link'); |
| 770 linkElement.addEventListener( |
| 771 'click', this.createLinkPressed_.bind(this)); |
| 772 |
| 773 buttons.appendChild(this.makeButton( |
| 774 'start', 'supervisedUserCreationFlow', |
| 775 this.startButtonPressed_.bind(this), ['intro'], |
| 776 ['custom-appearance', 'button-fancy', 'button-blue'])); |
| 777 |
| 778 buttons.appendChild(this.makeButton( |
| 779 'prev', 'supervisedUserCreationFlow', |
| 780 this.prevButtonPressed_.bind(this), ['manager'], [])); |
| 781 |
| 782 buttons.appendChild(this.makeButton( |
| 783 'next', 'supervisedUserCreationFlow', |
| 784 this.nextButtonPressed_.bind(this), ['manager', 'username'], [])); |
| 785 |
| 786 buttons.appendChild(this.makeButton( |
| 787 'import', 'supervisedUserCreationFlow', |
| 788 this.importButtonPressed_.bind(this), |
| 789 ['import', 'import-password'], [])); |
| 790 |
| 791 buttons.appendChild(this.makeButton( |
| 792 'gotit', 'supervisedUserCreationFlow', |
| 793 this.gotItButtonPressed_.bind(this), ['created'], |
| 794 ['custom-appearance', 'button-fancy', 'button-blue'])); |
| 795 return [links, buttons]; |
| 796 }, |
| 797 |
| 798 /** |
| 799 * Does sanity check and calls backend with current user name/password |
| 800 * pair to authenticate manager. May result in showManagerPasswordError. |
| 801 * @private |
| 802 */ |
| 803 validateAndLogInAsManager_: function() { |
| 804 var selectedPod = this.managerList_.selectedPod_; |
| 805 if (null == selectedPod) |
| 806 return; |
| 807 |
| 808 var managerId = selectedPod.user.username; |
| 809 var managerDisplayId = selectedPod.user.emailAddress; |
| 810 var managerPassword = selectedPod.passwordElement.value; |
| 811 if (managerPassword.length == 0) |
| 812 return; |
| 813 if (this.disabled) |
| 814 return; |
894 this.disabled = true; | 815 this.disabled = true; |
895 chrome.send('importSupervisedUser', [userId]); | 816 this.context_.managerId = managerId; |
896 } else { | 817 this.context_.managerDisplayId = managerDisplayId; |
897 this.setVisiblePage_('import-password'); | 818 this.context_.managerName = selectedPod.user.displayName; |
898 } | 819 chrome.send( |
899 } | 820 'authenticateManagerInSupervisedUserCreationFlow', |
900 }, | 821 [managerId, managerPassword]); |
901 | 822 }, |
902 /** | 823 |
903 * Calls backend part to check if current user name is valid/not taken. | 824 /** |
904 * Results in a call to either supervisedUserNameOk or | 825 * Does sanity check and calls backend with user display name/password |
905 * supervisedUserNameError. | 826 * pair to create a user. |
906 * @private | 827 * @private |
907 */ | 828 */ |
908 checkUserName_: function() { | 829 validateAndCreateSupervisedUser_: function() { |
909 var userName = this.getScreenElement('name').value; | 830 var firstPassword = $('supervised-user-creation-password').value; |
910 | 831 var secondPassword = |
911 // Avoid flickering | 832 $('supervised-user-creation-password-confirm').value; |
912 if (userName == this.lastIncorrectUserName_ || | 833 var userName = $('supervised-user-creation-name').value; |
913 userName == this.lastVerifiedName_) { | 834 if (firstPassword != secondPassword) { |
914 return; | 835 this.showPasswordError(loadTimeData.getString( |
915 } | 836 'createSupervisedUserPasswordMismatchError')); |
916 if (userName.length > 0) { | 837 return; |
917 chrome.send('checkSupervisedUserName', [userName]); | 838 } |
918 } else { | 839 if (this.disabled) |
919 this.nameErrorVisible = false; | 840 return; |
920 this.lastVerifiedName_ = null; | 841 this.disabled = true; |
921 this.lastIncorrectUserName_ = null; | 842 |
922 this.updateNextButtonForUser_(); | 843 this.context_.supervisedName = userName; |
923 } | 844 chrome.send( |
924 }, | 845 'specifySupervisedUserCreationFlowUserData', |
925 | 846 [userName, firstPassword]); |
926 /** | 847 }, |
927 * Called by backend part in case of successful name validation. | 848 |
928 * @param {string} name - name that was validated. | 849 /** |
929 */ | 850 * Does sanity check and calls backend with selected existing supervised |
930 supervisedUserNameOk: function(name) { | 851 * user id to import user. |
931 this.lastVerifiedName_ = name; | 852 * @private |
932 this.lastIncorrectUserName_ = null; | 853 */ |
933 if ($('supervised-user-creation-name').value == name) | 854 importSupervisedUser_: function() { |
934 this.clearUserNameError_(); | 855 if (this.disabled) |
935 this.updateNextButtonForUser_(); | 856 return; |
936 }, | 857 if (this.currentPage_ == 'import-password') { |
937 | 858 var firstPassword = this.getScreenElement('password').value; |
938 /** | 859 var secondPassword = |
939 * Called by backend part in case of name validation failure. | 860 this.getScreenElement('password-confirm').value; |
940 * @param {string} name - name that was validated. | 861 if (firstPassword != secondPassword) { |
941 * @param {string} errorText - reason why this name is invalid. | 862 this.showPasswordError(loadTimeData.getString( |
942 */ | 863 'createSupervisedUserPasswordMismatchError')); |
943 supervisedUserNameError: function(name, errorText) { | 864 return; |
944 this.disabled = false; | 865 } |
945 this.lastIncorrectUserName_ = name; | 866 var userId = this.context_.importUserId; |
946 this.lastVerifiedName_ = null; | 867 this.disabled = true; |
947 | 868 chrome.send( |
948 var userNameField = $('supervised-user-creation-name'); | 869 'importSupervisedUserWithPassword', [userId, firstPassword]); |
949 if (userNameField.value == this.lastIncorrectUserName_) { | 870 return; |
950 this.nameErrorVisible = true; | 871 } else { |
951 $('bubble').showTextForElement( | 872 var selectedPod = this.importList_.selectedPod_; |
952 $('supervised-user-creation-name'), | 873 if (!selectedPod) |
953 errorText, | 874 return; |
954 cr.ui.Bubble.Attachment.RIGHT, | 875 var user = selectedPod.user; |
955 12, 4); | 876 var userId = user.id; |
956 this.setButtonDisabledStatus('next', true); | 877 |
957 } | 878 this.context_.importUserId = userId; |
958 }, | 879 this.context_.supervisedName = user.name; |
959 | 880 this.context_.selectedImageUrl = user.avatarurl; |
960 supervisedUserSuggestImport: function(name, user_id) { | 881 if (!user.needPassword) { |
961 this.disabled = false; | 882 this.disabled = true; |
962 this.lastIncorrectUserName_ = name; | 883 chrome.send('importSupervisedUser', [userId]); |
963 this.lastVerifiedName_ = null; | 884 } else { |
964 | 885 this.setVisiblePage_('import-password'); |
965 var userNameField = $('supervised-user-creation-name'); | 886 } |
966 var creationScreen = this; | 887 } |
967 | 888 }, |
968 if (userNameField.value == this.lastIncorrectUserName_) { | 889 |
969 this.nameErrorVisible = true; | 890 /** |
970 var link = this.ownerDocument.createElement('div'); | 891 * Calls backend part to check if current user name is valid/not taken. |
971 link.innerHTML = loadTimeData.getStringF( | 892 * Results in a call to either supervisedUserNameOk or |
972 'importBubbleText', | 893 * supervisedUserNameError. |
973 '<a class="signin-link" href="#">', | 894 * @private |
974 name, | 895 */ |
975 '</a>'); | 896 checkUserName_: function() { |
976 link.querySelector('.signin-link').addEventListener('click', | 897 var userName = this.getScreenElement('name').value; |
977 function(e) { | 898 |
978 creationScreen.handleSuggestImport_(user_id); | 899 // Avoid flickering |
979 e.stopPropagation(); | 900 if (userName == this.lastIncorrectUserName_ || |
980 }); | 901 userName == this.lastVerifiedName_) { |
981 $('bubble').showContentForElement( | 902 return; |
982 $('supervised-user-creation-name'), | 903 } |
983 cr.ui.Bubble.Attachment.RIGHT, | 904 if (userName.length > 0) { |
984 link, | 905 chrome.send('checkSupervisedUserName', [userName]); |
985 12, 4); | 906 } else { |
986 this.setButtonDisabledStatus('next', true); | 907 this.nameErrorVisible = false; |
987 } | 908 this.lastVerifiedName_ = null; |
988 }, | 909 this.lastIncorrectUserName_ = null; |
989 | 910 this.updateNextButtonForUser_(); |
990 /** | 911 } |
991 * Clears user name error, if name is no more guaranteed to be invalid. | 912 }, |
992 * @private | 913 |
993 */ | 914 /** |
994 clearUserNameError_: function() { | 915 * Called by backend part in case of successful name validation. |
995 // Avoid flickering | 916 * @param {string} name - name that was validated. |
996 if ($('supervised-user-creation-name').value == | 917 */ |
| 918 supervisedUserNameOk: function(name) { |
| 919 this.lastVerifiedName_ = name; |
| 920 this.lastIncorrectUserName_ = null; |
| 921 if ($('supervised-user-creation-name').value == name) |
| 922 this.clearUserNameError_(); |
| 923 this.updateNextButtonForUser_(); |
| 924 }, |
| 925 |
| 926 /** |
| 927 * Called by backend part in case of name validation failure. |
| 928 * @param {string} name - name that was validated. |
| 929 * @param {string} errorText - reason why this name is invalid. |
| 930 */ |
| 931 supervisedUserNameError: function(name, errorText) { |
| 932 this.disabled = false; |
| 933 this.lastIncorrectUserName_ = name; |
| 934 this.lastVerifiedName_ = null; |
| 935 |
| 936 var userNameField = $('supervised-user-creation-name'); |
| 937 if (userNameField.value == this.lastIncorrectUserName_) { |
| 938 this.nameErrorVisible = true; |
| 939 $('bubble').showTextForElement( |
| 940 $('supervised-user-creation-name'), errorText, |
| 941 cr.ui.Bubble.Attachment.RIGHT, 12, 4); |
| 942 this.setButtonDisabledStatus('next', true); |
| 943 } |
| 944 }, |
| 945 |
| 946 supervisedUserSuggestImport: function(name, user_id) { |
| 947 this.disabled = false; |
| 948 this.lastIncorrectUserName_ = name; |
| 949 this.lastVerifiedName_ = null; |
| 950 |
| 951 var userNameField = $('supervised-user-creation-name'); |
| 952 var creationScreen = this; |
| 953 |
| 954 if (userNameField.value == this.lastIncorrectUserName_) { |
| 955 this.nameErrorVisible = true; |
| 956 var link = this.ownerDocument.createElement('div'); |
| 957 link.innerHTML = loadTimeData.getStringF( |
| 958 'importBubbleText', '<a class="signin-link" href="#">', name, |
| 959 '</a>'); |
| 960 link.querySelector('.signin-link') |
| 961 .addEventListener('click', function(e) { |
| 962 creationScreen.handleSuggestImport_(user_id); |
| 963 e.stopPropagation(); |
| 964 }); |
| 965 $('bubble').showContentForElement( |
| 966 $('supervised-user-creation-name'), |
| 967 cr.ui.Bubble.Attachment.RIGHT, link, 12, 4); |
| 968 this.setButtonDisabledStatus('next', true); |
| 969 } |
| 970 }, |
| 971 |
| 972 /** |
| 973 * Clears user name error, if name is no more guaranteed to be invalid. |
| 974 * @private |
| 975 */ |
| 976 clearUserNameError_: function() { |
| 977 // Avoid flickering |
| 978 if ($('supervised-user-creation-name').value == |
997 this.lastIncorrectUserName_) { | 979 this.lastIncorrectUserName_) { |
998 return; | 980 return; |
999 } | 981 } |
1000 this.nameErrorVisible = false; | 982 this.nameErrorVisible = false; |
1001 }, | 983 }, |
1002 | 984 |
1003 /** | 985 /** |
1004 * Called by backend part in case of password validation failure. | 986 * Called by backend part in case of password validation failure. |
1005 * @param {string} errorText - reason why this password is invalid. | 987 * @param {string} errorText - reason why this password is invalid. |
1006 */ | 988 */ |
1007 showPasswordError: function(errorText) { | 989 showPasswordError: function(errorText) { |
1008 $('bubble').showTextForElement( | 990 $('bubble').showTextForElement( |
1009 $('supervised-user-creation-password'), | 991 $('supervised-user-creation-password'), errorText, |
1010 errorText, | 992 cr.ui.Bubble.Attachment.RIGHT, 12, 4); |
1011 cr.ui.Bubble.Attachment.RIGHT, | 993 $('supervised-user-creation-password') |
1012 12, 4); | 994 .classList.add('password-error'); |
1013 $('supervised-user-creation-password').classList.add('password-error'); | 995 $('supervised-user-creation-password').focus(); |
1014 $('supervised-user-creation-password').focus(); | 996 this.disabled = false; |
1015 this.disabled = false; | 997 this.setButtonDisabledStatus('next', true); |
1016 this.setButtonDisabledStatus('next', true); | 998 }, |
1017 }, | 999 |
1018 | 1000 /** |
1019 /** | 1001 * True if user name error should be displayed. |
1020 * True if user name error should be displayed. | 1002 * @type {boolean} |
1021 * @type {boolean} | 1003 */ |
1022 */ | 1004 set nameErrorVisible(value) { |
1023 set nameErrorVisible(value) { | 1005 $('supervised-user-creation-name') |
1024 $('supervised-user-creation-name'). | 1006 .classList.toggle('duplicate-name', value); |
1025 classList.toggle('duplicate-name', value); | 1007 if (!value) |
1026 if (!value) | 1008 $('bubble').hide(); |
1027 $('bubble').hide(); | 1009 }, |
1028 }, | 1010 |
1029 | 1011 /** |
1030 /** | 1012 * Updates state of Continue button after minimal checks. |
1031 * Updates state of Continue button after minimal checks. | 1013 * @return {boolean} true, if form seems to be valid. |
1032 * @return {boolean} true, if form seems to be valid. | 1014 * @private |
1033 * @private | 1015 */ |
1034 */ | 1016 updateNextButtonForManager_: function() { |
1035 updateNextButtonForManager_: function() { | 1017 var selectedPod = this.managerList_.selectedPod_; |
1036 var selectedPod = this.managerList_.selectedPod_; | 1018 canProceed = null != selectedPod && |
1037 canProceed = null != selectedPod && | 1019 selectedPod.passwordElement.value.length > 0; |
1038 selectedPod.passwordElement.value.length > 0; | 1020 |
1039 | 1021 this.setButtonDisabledStatus('next', !canProceed); |
1040 this.setButtonDisabledStatus('next', !canProceed); | 1022 return canProceed; |
1041 return canProceed; | 1023 }, |
1042 }, | 1024 |
1043 | 1025 /** |
1044 /** | 1026 * Updates state of Continue button after minimal checks. |
1045 * Updates state of Continue button after minimal checks. | 1027 * @return {boolean} true, if form seems to be valid. |
1046 * @return {boolean} true, if form seems to be valid. | 1028 * @private |
1047 * @private | 1029 */ |
1048 */ | 1030 updateNextButtonForUser_: function() { |
1049 updateNextButtonForUser_: function() { | 1031 var firstPassword = this.getScreenElement('password').value; |
1050 var firstPassword = this.getScreenElement('password').value; | 1032 var secondPassword = this.getScreenElement('password-confirm').value; |
1051 var secondPassword = this.getScreenElement('password-confirm').value; | 1033 var userName = this.getScreenElement('name').value; |
1052 var userName = this.getScreenElement('name').value; | 1034 |
1053 | 1035 var passwordOk = (firstPassword.length > 0) && |
1054 var passwordOk = (firstPassword.length > 0) && | 1036 (firstPassword.length == secondPassword.length); |
1055 (firstPassword.length == secondPassword.length); | 1037 |
1056 | 1038 if (this.currentPage_ == 'import-password') { |
1057 if (this.currentPage_ == 'import-password') { | 1039 this.setButtonDisabledStatus('import', !passwordOk); |
1058 this.setButtonDisabledStatus('import', !passwordOk); | 1040 return passwordOk; |
1059 return passwordOk; | 1041 } |
1060 } | 1042 var imageGrid = this.getScreenElement('image-grid'); |
1061 var imageGrid = this.getScreenElement('image-grid'); | 1043 var imageChosen = |
1062 var imageChosen = !(imageGrid.selectionType == 'camera' && | 1044 !(imageGrid.selectionType == 'camera' && imageGrid.cameraLive); |
1063 imageGrid.cameraLive); | 1045 var canProceed = passwordOk && (userName.length > 0) && |
1064 var canProceed = | 1046 this.lastVerifiedName_ && (userName == this.lastVerifiedName_) && |
1065 passwordOk && | 1047 imageChosen; |
1066 (userName.length > 0) && | 1048 |
1067 this.lastVerifiedName_ && | 1049 this.setButtonDisabledStatus('next', !canProceed); |
1068 (userName == this.lastVerifiedName_) && | 1050 return canProceed; |
1069 imageChosen; | 1051 }, |
1070 | 1052 |
1071 this.setButtonDisabledStatus('next', !canProceed); | 1053 showSelectedManagerPasswordError_: function() { |
1072 return canProceed; | 1054 var selectedPod = this.managerList_.selectedPod_; |
1073 }, | 1055 selectedPod.showPasswordError(); |
1074 | 1056 selectedPod.passwordElement.value = ''; |
1075 showSelectedManagerPasswordError_: function() { | 1057 selectedPod.focusInput(); |
1076 var selectedPod = this.managerList_.selectedPod_; | 1058 this.updateNextButtonForManager_(); |
1077 selectedPod.showPasswordError(); | 1059 }, |
1078 selectedPod.passwordElement.value = ''; | 1060 |
1079 selectedPod.focusInput(); | 1061 /** |
1080 this.updateNextButtonForManager_(); | 1062 * Enables one particular subpage and hides the rest. |
1081 }, | 1063 * @param {string} visiblePage - name of subpage. |
1082 | 1064 * @private |
1083 /** | 1065 */ |
1084 * Enables one particular subpage and hides the rest. | 1066 setVisiblePage_: function(visiblePage) { |
1085 * @param {string} visiblePage - name of subpage. | 1067 this.disabled = false; |
1086 * @private | 1068 this.updateText_(); |
1087 */ | 1069 $('bubble').hide(); |
1088 setVisiblePage_: function(visiblePage) { | 1070 if (!this.imagesRequested_) { |
1089 this.disabled = false; | 1071 chrome.send('supervisedUserGetImages'); |
1090 this.updateText_(); | 1072 this.imagesRequested_ = true; |
1091 $('bubble').hide(); | 1073 } |
1092 if (!this.imagesRequested_) { | 1074 var pageNames = |
1093 chrome.send('supervisedUserGetImages'); | 1075 ['intro', 'manager', 'username', 'import', 'created', 'error']; |
1094 this.imagesRequested_ = true; | 1076 var pageButtons = { |
1095 } | 1077 'intro': 'start', |
1096 var pageNames = ['intro', | 1078 'error': 'error', |
1097 'manager', | 1079 'import': 'import', |
1098 'username', | 1080 'import-password': 'import', |
1099 'import', | 1081 'created': 'gotit' |
1100 'created', | 1082 }; |
1101 'error']; | 1083 this.hideStatus_(); |
1102 var pageButtons = {'intro' : 'start', | 1084 var pageToDisplay = visiblePage; |
1103 'error' : 'error', | 1085 if (visiblePage == 'import-password') |
1104 'import' : 'import', | 1086 pageToDisplay = 'username'; |
1105 'import-password' : 'import', | 1087 |
1106 'created' : 'gotit'}; | 1088 for (i in pageNames) { |
1107 this.hideStatus_(); | 1089 var pageName = pageNames[i]; |
1108 var pageToDisplay = visiblePage; | 1090 var page = $('supervised-user-creation-' + pageName); |
1109 if (visiblePage == 'import-password') | 1091 page.hidden = (pageName != pageToDisplay); |
1110 pageToDisplay = 'username'; | 1092 if (pageName == pageToDisplay) |
1111 | 1093 $('step-logo').hidden = page.classList.contains('step-no-logo'); |
1112 for (i in pageNames) { | 1094 } |
1113 var pageName = pageNames[i]; | 1095 |
1114 var page = $('supervised-user-creation-' + pageName); | 1096 for (i in this.buttonIds) { |
1115 page.hidden = (pageName != pageToDisplay); | 1097 var button = this.getScreenButton(this.buttonIds[i]); |
1116 if (pageName == pageToDisplay) | 1098 button.hidden = button.pages.indexOf(visiblePage) < 0; |
1117 $('step-logo').hidden = page.classList.contains('step-no-logo'); | 1099 button.disabled = false; |
1118 } | 1100 } |
1119 | 1101 |
1120 for (i in this.buttonIds) { | 1102 this.getScreenElement('import-link').hidden = true; |
1121 var button = this.getScreenButton(this.buttonIds[i]); | 1103 this.getScreenElement('create-link').hidden = true; |
1122 button.hidden = button.pages.indexOf(visiblePage) < 0; | 1104 |
1123 button.disabled = false; | 1105 if (pageButtons[visiblePage]) |
1124 } | 1106 this.getScreenButton(pageButtons[visiblePage]).focus(); |
1125 | 1107 |
1126 this.getScreenElement('import-link').hidden = true; | 1108 this.currentPage_ = visiblePage; |
1127 this.getScreenElement('create-link').hidden = true; | 1109 |
1128 | 1110 if (visiblePage == 'manager' || visiblePage == 'intro') { |
1129 if (pageButtons[visiblePage]) | 1111 $('supervised-user-creation-password') |
1130 this.getScreenButton(pageButtons[visiblePage]).focus(); | 1112 .classList.remove('password-error'); |
1131 | 1113 if (this.managerList_.pods.length > 0) |
1132 this.currentPage_ = visiblePage; | 1114 this.managerList_.selectPod(this.managerList_.pods[0]); |
1133 | 1115 $('login-header-bar').updateUI_(); |
1134 if (visiblePage == 'manager' || visiblePage == 'intro') { | 1116 } |
1135 $('supervised-user-creation-password').classList.remove( | 1117 |
1136 'password-error'); | 1118 if (visiblePage == 'username' || visiblePage == 'import-password') { |
1137 if (this.managerList_.pods.length > 0) | 1119 var elements = this.getScreenElement(pageToDisplay) |
1138 this.managerList_.selectPod(this.managerList_.pods[0]); | 1120 .querySelectorAll('.hide-on-import'); |
1139 $('login-header-bar').updateUI_(); | 1121 for (var i = 0; i < elements.length; i++) { |
1140 } | 1122 elements[i].classList.toggle( |
1141 | 1123 'hidden-on-import', visiblePage == 'import-password'); |
1142 if (visiblePage == 'username' || visiblePage == 'import-password') { | 1124 } |
1143 var elements = this.getScreenElement(pageToDisplay). | 1125 } |
1144 querySelectorAll('.hide-on-import'); | 1126 if (visiblePage == 'username') { |
1145 for (var i = 0; i < elements.length; i++) { | 1127 var imageGrid = this.getScreenElement('image-grid'); |
1146 elements[i].classList.toggle('hidden-on-import', | 1128 // select some image. |
1147 visiblePage == 'import-password'); | 1129 var selected = this.imagesData_[Math.floor( |
1148 } | 1130 Math.random() * this.imagesData_.length)]; |
1149 } | 1131 this.context_.selectedImageUrl = selected.url; |
1150 if (visiblePage == 'username') { | 1132 imageGrid.selectedItemUrl = selected.url; |
1151 var imageGrid = this.getScreenElement('image-grid'); | 1133 chrome.send('supervisedUserSelectImage', [selected.url, 'default']); |
1152 // select some image. | 1134 this.getScreenElement('image-grid').redraw(); |
1153 var selected = this.imagesData_[ | 1135 this.checkUserName_(); |
1154 Math.floor(Math.random() * this.imagesData_.length)]; | 1136 this.updateNextButtonForUser_(); |
1155 this.context_.selectedImageUrl = selected.url; | 1137 this.getScreenElement('name').focus(); |
1156 imageGrid.selectedItemUrl = selected.url; | 1138 this.getScreenElement('import-link').hidden = |
1157 chrome.send('supervisedUserSelectImage', | 1139 this.importList_.pods.length == 0; |
1158 [selected.url, 'default']); | 1140 } else if (visiblePage == 'import-password') { |
1159 this.getScreenElement('image-grid').redraw(); | 1141 var imageGrid = this.getScreenElement('image-grid'); |
1160 this.checkUserName_(); | 1142 var selected; |
1161 this.updateNextButtonForUser_(); | 1143 if ('selectedImageUrl' in this.context_) { |
1162 this.getScreenElement('name').focus(); | 1144 selected = this.context_.selectedImageUrl; |
1163 this.getScreenElement('import-link').hidden = | 1145 } else { |
1164 this.importList_.pods.length == 0; | 1146 // select some image. |
1165 } else if (visiblePage == 'import-password') { | 1147 selected = |
1166 var imageGrid = this.getScreenElement('image-grid'); | 1148 this.imagesData_[Math.floor( |
1167 var selected; | 1149 Math.random() * this.imagesData_.length)] |
1168 if ('selectedImageUrl' in this.context_) { | 1150 .url; |
1169 selected = this.context_.selectedImageUrl; | 1151 chrome.send('supervisedUserSelectImage', [selected, 'default']); |
1170 } else { | 1152 } |
1171 // select some image. | 1153 imageGrid.selectedItemUrl = selected; |
1172 selected = this.imagesData_[ | 1154 this.getScreenElement('image-grid').redraw(); |
1173 Math.floor(Math.random() * this.imagesData_.length)].url; | 1155 |
1174 chrome.send('supervisedUserSelectImage', | 1156 this.updateNextButtonForUser_(); |
1175 [selected, 'default']); | 1157 |
1176 } | 1158 this.getScreenElement('password').focus(); |
1177 imageGrid.selectedItemUrl = selected; | 1159 this.getScreenElement('import-link').hidden = true; |
1178 this.getScreenElement('image-grid').redraw(); | 1160 } else { |
1179 | 1161 this.getScreenElement('image-grid').stopCamera(); |
1180 this.updateNextButtonForUser_(); | 1162 } |
1181 | 1163 if (visiblePage == 'import') { |
1182 this.getScreenElement('password').focus(); | 1164 this.getScreenElement('create-link').hidden = false; |
1183 this.getScreenElement('import-link').hidden = true; | 1165 this.getScreenButton('import').disabled = |
1184 } else { | 1166 !this.importList_.selectedPod_ || |
1185 this.getScreenElement('image-grid').stopCamera(); | 1167 this.importList_.selectedPod_.user.exists; |
1186 } | 1168 } |
1187 if (visiblePage == 'import') { | 1169 $('supervised-user-creation-navigation').closeVisible = |
1188 this.getScreenElement('create-link').hidden = false; | 1170 (visiblePage != 'created'); |
1189 this.getScreenButton('import').disabled = | 1171 |
1190 !this.importList_.selectedPod_ || | 1172 chrome.send('currentSupervisedUserPage', [this.currentPage_]); |
1191 this.importList_.selectedPod_.user.exists; | 1173 }, |
1192 } | 1174 |
1193 $('supervised-user-creation-navigation').closeVisible = | 1175 setButtonDisabledStatus: function(buttonName, status) { |
1194 (visiblePage != 'created'); | 1176 var button = $('supervised-user-creation-' + buttonName + '-button'); |
1195 | 1177 button.disabled = status; |
1196 chrome.send('currentSupervisedUserPage', [this.currentPage_]); | 1178 }, |
1197 }, | 1179 |
1198 | 1180 gotItButtonPressed_: function() { |
1199 setButtonDisabledStatus: function(buttonName, status) { | 1181 chrome.send('finishLocalSupervisedUserCreation'); |
1200 var button = $('supervised-user-creation-' + buttonName + '-button'); | 1182 }, |
1201 button.disabled = status; | 1183 |
1202 }, | 1184 handleErrorButtonPressed_: function() { |
1203 | 1185 chrome.send('abortLocalSupervisedUserCreation'); |
1204 gotItButtonPressed_: function() { | 1186 }, |
1205 chrome.send('finishLocalSupervisedUserCreation'); | 1187 |
1206 }, | 1188 startButtonPressed_: function() { |
1207 | 1189 this.setVisiblePage_('manager'); |
1208 handleErrorButtonPressed_: function() { | 1190 this.setButtonDisabledStatus('next', true); |
1209 chrome.send('abortLocalSupervisedUserCreation'); | 1191 }, |
1210 }, | 1192 |
1211 | 1193 nextButtonPressed_: function() { |
1212 startButtonPressed_: function() { | 1194 if (this.currentPage_ == 'manager') { |
1213 this.setVisiblePage_('manager'); | 1195 this.validateAndLogInAsManager_(); |
1214 this.setButtonDisabledStatus('next', true); | 1196 return; |
1215 }, | 1197 } |
1216 | 1198 if (this.currentPage_ == 'username') { |
1217 nextButtonPressed_: function() { | 1199 this.validateAndCreateSupervisedUser_(); |
1218 if (this.currentPage_ == 'manager') { | 1200 } |
1219 this.validateAndLogInAsManager_(); | 1201 }, |
1220 return; | 1202 |
1221 } | 1203 importButtonPressed_: function() { |
1222 if (this.currentPage_ == 'username') { | 1204 this.importSupervisedUser_(); |
1223 this.validateAndCreateSupervisedUser_(); | 1205 }, |
1224 } | 1206 |
1225 }, | 1207 importLinkPressed_: function() { |
1226 | 1208 this.setVisiblePage_('import'); |
1227 importButtonPressed_: function() { | 1209 }, |
1228 this.importSupervisedUser_(); | 1210 |
1229 }, | 1211 handleSuggestImport_: function(user_id) { |
1230 | 1212 this.setVisiblePage_('import'); |
1231 importLinkPressed_: function() { | 1213 this.importList_.selectUser(user_id); |
1232 this.setVisiblePage_('import'); | 1214 }, |
1233 }, | 1215 |
1234 | 1216 createLinkPressed_: function() { |
1235 handleSuggestImport_: function(user_id) { | 1217 this.setVisiblePage_('username'); |
1236 this.setVisiblePage_('import'); | 1218 this.lastIncorrectUserName_ = null; |
1237 this.importList_.selectUser(user_id); | 1219 this.lastVerifiedName_ = null; |
1238 }, | 1220 this.checkUserName_(); |
1239 | 1221 }, |
1240 createLinkPressed_: function() { | 1222 |
1241 this.setVisiblePage_('username'); | 1223 prevButtonPressed_: function() { |
1242 this.lastIncorrectUserName_ = null; | 1224 this.setVisiblePage_('intro'); |
1243 this.lastVerifiedName_ = null; | 1225 }, |
1244 this.checkUserName_(); | 1226 |
1245 }, | 1227 showProgress: function(text) { |
1246 | 1228 var status = this.getScreenElement('status'); |
1247 prevButtonPressed_: function() { | 1229 var statusText = status.querySelector('.id-text'); |
1248 this.setVisiblePage_('intro'); | 1230 statusText.textContent = text; |
1249 }, | 1231 statusText.classList.remove('error'); |
1250 | 1232 status.querySelector('.id-spinner').hidden = false; |
1251 showProgress: function(text) { | 1233 status.hidden = false; |
1252 var status = this.getScreenElement('status'); | 1234 this.getScreenElement('import-link').hidden = true; |
1253 var statusText = status.querySelector('.id-text'); | 1235 this.getScreenElement('create-link').hidden = true; |
1254 statusText.textContent = text; | 1236 }, |
1255 statusText.classList.remove('error'); | 1237 |
1256 status.querySelector('.id-spinner').hidden = false; | 1238 showStatusError: function(text) { |
1257 status.hidden = false; | 1239 var status = this.getScreenElement('status'); |
1258 this.getScreenElement('import-link').hidden = true; | 1240 var statusText = status.querySelector('.id-text'); |
1259 this.getScreenElement('create-link').hidden = true; | 1241 statusText.textContent = text; |
1260 }, | 1242 statusText.classList.add('error'); |
1261 | 1243 status.querySelector('.id-spinner').hidden = true; |
1262 showStatusError: function(text) { | 1244 status.hidden = false; |
1263 var status = this.getScreenElement('status'); | 1245 this.getScreenElement('import-link').hidden = true; |
1264 var statusText = status.querySelector('.id-text'); | 1246 this.getScreenElement('create-link').hidden = true; |
1265 statusText.textContent = text; | 1247 }, |
1266 statusText.classList.add('error'); | 1248 |
1267 status.querySelector('.id-spinner').hidden = true; | 1249 hideStatus_: function() { |
1268 status.hidden = false; | 1250 var status = this.getScreenElement('status'); |
1269 this.getScreenElement('import-link').hidden = true; | 1251 status.hidden = true; |
1270 this.getScreenElement('create-link').hidden = true; | 1252 }, |
1271 }, | 1253 |
1272 | 1254 /** |
1273 hideStatus_: function() { | 1255 * Updates state of login header so that necessary buttons are |
1274 var status = this.getScreenElement('status'); | 1256 * displayed. |
1275 status.hidden = true; | 1257 */ |
1276 }, | 1258 onBeforeShow: function(data) { |
1277 | 1259 $('login-header-bar').signinUIState = |
1278 /** | 1260 SIGNIN_UI_STATE.SUPERVISED_USER_CREATION_FLOW; |
1279 * Updates state of login header so that necessary buttons are displayed. | 1261 if (data['managers']) { |
1280 */ | 1262 this.loadManagers(data['managers']); |
1281 onBeforeShow: function(data) { | 1263 } |
1282 $('login-header-bar').signinUIState = | 1264 var imageGrid = this.getScreenElement('image-grid'); |
1283 SIGNIN_UI_STATE.SUPERVISED_USER_CREATION_FLOW; | 1265 imageGrid.updateAndFocus(); |
1284 if (data['managers']) { | 1266 }, |
1285 this.loadManagers(data['managers']); | 1267 |
1286 } | 1268 /** |
1287 var imageGrid = this.getScreenElement('image-grid'); | 1269 * Update state of login header so that necessary buttons are displayed. |
1288 imageGrid.updateAndFocus(); | 1270 */ |
1289 }, | 1271 onBeforeHide: function() { |
1290 | 1272 $('login-header-bar').signinUIState = SIGNIN_UI_STATE.HIDDEN; |
1291 /** | 1273 this.getScreenElement('image-grid').stopCamera(); |
1292 * Update state of login header so that necessary buttons are displayed. | 1274 }, |
1293 */ | 1275 |
1294 onBeforeHide: function() { | 1276 /** |
1295 $('login-header-bar').signinUIState = SIGNIN_UI_STATE.HIDDEN; | 1277 * Returns a control which should receive an initial focus. |
1296 this.getScreenElement('image-grid').stopCamera(); | 1278 */ |
1297 }, | 1279 get defaultControl() { |
1298 | 1280 return $('supervised-user-creation-name'); |
1299 /** | 1281 }, |
1300 * Returns a control which should receive an initial focus. | 1282 |
1301 */ | 1283 /** |
1302 get defaultControl() { | 1284 * True if the the screen is disabled (handles no user interaction). |
1303 return $('supervised-user-creation-name'); | 1285 * @type {boolean} |
1304 }, | 1286 */ |
1305 | 1287 disabled_: false, |
1306 /** | 1288 |
1307 * True if the the screen is disabled (handles no user interaction). | 1289 get disabled() { |
1308 * @type {boolean} | 1290 return this.disabled_; |
1309 */ | 1291 }, |
1310 disabled_: false, | 1292 |
1311 | 1293 set disabled(value) { |
1312 get disabled() { | 1294 this.disabled_ = value; |
1313 return this.disabled_; | 1295 var controls = this.querySelectorAll('button,input'); |
1314 }, | 1296 for (var i = 0, control; control = controls[i]; ++i) { |
1315 | 1297 control.disabled = value; |
1316 set disabled(value) { | 1298 } |
1317 this.disabled_ = value; | 1299 $('login-header-bar').disabled = value; |
1318 var controls = this.querySelectorAll('button,input'); | 1300 }, |
1319 for (var i = 0, control; control = controls[i]; ++i) { | 1301 |
1320 control.disabled = value; | 1302 /** |
1321 } | 1303 * Called by backend part to propagate list of possible managers. |
1322 $('login-header-bar').disabled = value; | 1304 * @param {Array} userList - list of users that can be managers. |
1323 }, | 1305 */ |
1324 | 1306 loadManagers: function(userList) { |
1325 /** | 1307 $('supervised-user-creation-managers-block').hidden = false; |
1326 * Called by backend part to propagate list of possible managers. | 1308 this.managerList_.clearPods(); |
1327 * @param {Array} userList - list of users that can be managers. | 1309 for (var i = 0; i < userList.length; ++i) |
1328 */ | 1310 this.managerList_.addPod(userList[i]); |
1329 loadManagers: function(userList) { | 1311 if (userList.length > 0) |
1330 $('supervised-user-creation-managers-block').hidden = false; | 1312 this.managerList_.selectPod(this.managerList_.pods[0]); |
1331 this.managerList_.clearPods(); | 1313 }, |
1332 for (var i = 0; i < userList.length; ++i) | 1314 |
1333 this.managerList_.addPod(userList[i]); | 1315 /** |
1334 if (userList.length > 0) | 1316 * Cancels user creation and drops to user screen (either sign). |
1335 this.managerList_.selectPod(this.managerList_.pods[0]); | 1317 */ |
1336 }, | 1318 cancel: function() { |
1337 | 1319 var notSignedInPages = ['intro', 'manager']; |
1338 /** | 1320 var postCreationPages = ['created']; |
1339 * Cancels user creation and drops to user screen (either sign). | 1321 if (notSignedInPages.indexOf(this.currentPage_) >= 0) { |
1340 */ | 1322 chrome.send('hideLocalSupervisedUserCreation'); |
1341 cancel: function() { | 1323 |
1342 var notSignedInPages = ['intro', 'manager']; | 1324 // Make sure no manager password is kept: |
1343 var postCreationPages = ['created']; | 1325 this.managerList_.clearPods(); |
1344 if (notSignedInPages.indexOf(this.currentPage_) >= 0) { | 1326 |
1345 chrome.send('hideLocalSupervisedUserCreation'); | 1327 Oobe.showUserPods(); |
1346 | 1328 return; |
1347 // Make sure no manager password is kept: | 1329 } |
1348 this.managerList_.clearPods(); | 1330 if (postCreationPages.indexOf(this.currentPage_) >= 0) { |
1349 | 1331 chrome.send('finishLocalSupervisedUserCreation'); |
1350 Oobe.showUserPods(); | 1332 return; |
1351 return; | 1333 } |
1352 } | 1334 chrome.send('abortLocalSupervisedUserCreation'); |
1353 if (postCreationPages.indexOf(this.currentPage_) >= 0) { | 1335 }, |
1354 chrome.send('finishLocalSupervisedUserCreation'); | 1336 |
1355 return; | 1337 updateText_: function() { |
1356 } | 1338 var managerDisplayId = this.context_.managerDisplayId; |
1357 chrome.send('abortLocalSupervisedUserCreation'); | 1339 this.updateElementText_( |
1358 }, | 1340 'intro-alternate-text', 'createSupervisedUserIntroAlternateText'); |
1359 | 1341 this.updateElementText_( |
1360 updateText_: function() { | 1342 'created-text-1', 'createSupervisedUserCreatedText1', |
1361 var managerDisplayId = this.context_.managerDisplayId; | 1343 this.context_.supervisedName); |
1362 this.updateElementText_('intro-alternate-text', | 1344 // TODO(antrim): Move wrapping with strong in grd file, and eliminate |
1363 'createSupervisedUserIntroAlternateText'); | 1345 // this |
1364 this.updateElementText_('created-text-1', | 1346 // call. |
1365 'createSupervisedUserCreatedText1', | 1347 this.updateElementText_( |
1366 this.context_.supervisedName); | 1348 'created-text-2', 'createSupervisedUserCreatedText2', |
1367 // TODO(antrim): Move wrapping with strong in grd file, and eliminate this | 1349 this.wrapStrong(loadTimeData.getString('managementURL')), |
1368 //call. | 1350 this.context_.supervisedName); |
1369 this.updateElementText_('created-text-2', | 1351 this.updateElementText_( |
1370 'createSupervisedUserCreatedText2', | 1352 'created-text-3', 'createSupervisedUserCreatedText3', |
1371 this.wrapStrong( | 1353 managerDisplayId); |
1372 loadTimeData.getString('managementURL')), | 1354 this.updateElementText_( |
1373 this.context_.supervisedName); | 1355 'name-explanation', 'createSupervisedUserNameExplanation', |
1374 this.updateElementText_('created-text-3', | 1356 managerDisplayId); |
1375 'createSupervisedUserCreatedText3', | 1357 }, |
1376 managerDisplayId); | 1358 |
1377 this.updateElementText_('name-explanation', | 1359 wrapStrong: function(original) { |
1378 'createSupervisedUserNameExplanation', | 1360 if (original == undefined) |
1379 managerDisplayId); | 1361 return original; |
1380 }, | 1362 return '<strong>' + original + '</strong>'; |
1381 | 1363 }, |
1382 wrapStrong: function(original) { | 1364 |
1383 if (original == undefined) | 1365 updateElementText_: function(localId, templateName) { |
1384 return original; | 1366 var args = Array.prototype.slice.call(arguments); |
1385 return '<strong>' + original + '</strong>'; | 1367 args.shift(); |
1386 }, | 1368 this.getScreenElement(localId).innerHTML = |
1387 | 1369 loadTimeData.getStringF.apply(loadTimeData, args); |
1388 updateElementText_: function(localId, templateName) { | 1370 }, |
1389 var args = Array.prototype.slice.call(arguments); | 1371 |
1390 args.shift(); | 1372 showIntroPage: function() { |
1391 this.getScreenElement(localId).innerHTML = | 1373 $('supervised-user-creation-password').value = ''; |
1392 loadTimeData.getStringF.apply(loadTimeData, args); | 1374 $('supervised-user-creation-password-confirm').value = ''; |
1393 }, | 1375 $('supervised-user-creation-name').value = ''; |
1394 | 1376 |
1395 showIntroPage: function() { | 1377 this.lastVerifiedName_ = null; |
1396 $('supervised-user-creation-password').value = ''; | 1378 this.lastIncorrectUserName_ = null; |
1397 $('supervised-user-creation-password-confirm').value = ''; | 1379 this.passwordErrorVisible = false; |
1398 $('supervised-user-creation-name').value = ''; | 1380 $('supervised-user-creation-password') |
1399 | 1381 .classList.remove('password-error'); |
1400 this.lastVerifiedName_ = null; | 1382 this.nameErrorVisible = false; |
1401 this.lastIncorrectUserName_ = null; | 1383 |
1402 this.passwordErrorVisible = false; | 1384 this.setVisiblePage_('intro'); |
1403 $('supervised-user-creation-password').classList.remove('password-error'); | 1385 }, |
1404 this.nameErrorVisible = false; | 1386 |
1405 | 1387 showManagerPage: function() { |
1406 this.setVisiblePage_('intro'); | 1388 this.setVisiblePage_('manager'); |
1407 }, | 1389 }, |
1408 | 1390 |
1409 showManagerPage: function() { | 1391 showUsernamePage: function() { |
1410 this.setVisiblePage_('manager'); | 1392 this.setVisiblePage_('username'); |
1411 }, | 1393 }, |
1412 | 1394 |
1413 showUsernamePage: function() { | 1395 showTutorialPage: function() { |
1414 this.setVisiblePage_('username'); | 1396 this.setVisiblePage_('created'); |
1415 }, | 1397 }, |
1416 | 1398 |
1417 showTutorialPage: function() { | 1399 showPage: function(page) { |
1418 this.setVisiblePage_('created'); | 1400 this.setVisiblePage_(page); |
1419 }, | 1401 }, |
1420 | 1402 |
1421 showPage: function(page) { | 1403 showErrorPage: function(errorTitle, errorText, errorButtonText) { |
1422 this.setVisiblePage_(page); | 1404 this.disabled = false; |
1423 }, | 1405 $('supervised-user-creation-error-title').innerHTML = errorTitle; |
1424 | 1406 $('supervised-user-creation-error-text').innerHTML = errorText; |
1425 showErrorPage: function(errorTitle, errorText, errorButtonText) { | 1407 $('supervised-user-creation-error-button').textContent = |
1426 this.disabled = false; | 1408 errorButtonText; |
1427 $('supervised-user-creation-error-title').innerHTML = errorTitle; | 1409 this.setVisiblePage_('error'); |
1428 $('supervised-user-creation-error-text').innerHTML = errorText; | 1410 }, |
1429 $('supervised-user-creation-error-button').textContent = errorButtonText; | 1411 |
1430 this.setVisiblePage_('error'); | 1412 showManagerPasswordError: function() { |
1431 }, | 1413 this.disabled = false; |
1432 | 1414 this.showSelectedManagerPasswordError_(); |
1433 showManagerPasswordError: function() { | 1415 }, |
1434 this.disabled = false; | 1416 |
1435 this.showSelectedManagerPasswordError_(); | 1417 /* |
1436 }, | 1418 TODO(antrim) : this is an explicit code duplications with |
1437 | 1419 UserImageScreen. It should be removed by issue 251179. |
1438 /* | 1420 */ |
1439 TODO(antrim) : this is an explicit code duplications with UserImageScreen. | 1421 /** |
1440 It should be removed by issue 251179. | 1422 * Currently selected user image index (take photo button is with zero |
1441 */ | 1423 * index). |
1442 /** | 1424 * @type {number} |
1443 * Currently selected user image index (take photo button is with zero | 1425 */ |
1444 * index). | 1426 selectedUserImage_: -1, |
1445 * @type {number} | 1427 imagesData: [], |
1446 */ | 1428 |
1447 selectedUserImage_: -1, | 1429 setDefaultImages: function(imagesData) { |
1448 imagesData: [], | 1430 var imageGrid = this.getScreenElement('image-grid'); |
1449 | 1431 imageGrid.setDefaultImages(imagesData); |
1450 setDefaultImages: function(imagesData) { | 1432 this.imagesData_ = imagesData; |
1451 var imageGrid = this.getScreenElement('image-grid'); | 1433 }, |
1452 imageGrid.setDefaultImages(imagesData); | 1434 |
1453 this.imagesData_ = imagesData; | 1435 |
1454 }, | 1436 handleActivate_: function() { |
1455 | 1437 var imageGrid = this.getScreenElement('image-grid'); |
1456 | 1438 if (imageGrid.selectedItemUrl == ButtonImages.TAKE_PHOTO) { |
1457 handleActivate_: function() { | 1439 this.handleTakePhoto_(); |
1458 var imageGrid = this.getScreenElement('image-grid'); | 1440 return; |
1459 if (imageGrid.selectedItemUrl == ButtonImages.TAKE_PHOTO) { | 1441 } |
1460 this.handleTakePhoto_(); | 1442 this.nextButtonPressed_(); |
1461 return; | 1443 }, |
1462 } | 1444 |
1463 this.nextButtonPressed_(); | 1445 /** |
1464 }, | 1446 * Handles selection change. |
1465 | 1447 * @param {Event} e Selection change event. |
1466 /** | 1448 * @private |
1467 * Handles selection change. | 1449 */ |
1468 * @param {Event} e Selection change event. | 1450 handleSelect_: function(e) { |
1469 * @private | 1451 var imageGrid = this.getScreenElement('image-grid'); |
1470 */ | 1452 this.updateNextButtonForUser_(); |
1471 handleSelect_: function(e) { | 1453 |
1472 var imageGrid = this.getScreenElement('image-grid'); | 1454 $('supervised-user-creation-flip-photo').tabIndex = |
1473 this.updateNextButtonForUser_(); | 1455 (imageGrid.selectionType == 'camera') ? 0 : -1; |
1474 | 1456 if (imageGrid.cameraLive || imageGrid.selectionType != 'camera') |
1475 $('supervised-user-creation-flip-photo').tabIndex = | 1457 imageGrid.previewElement.classList.remove('phototaken'); |
1476 (imageGrid.selectionType == 'camera') ? 0 : -1; | 1458 else |
1477 if (imageGrid.cameraLive || imageGrid.selectionType != 'camera') | 1459 imageGrid.previewElement.classList.add('phototaken'); |
1478 imageGrid.previewElement.classList.remove('phototaken'); | 1460 |
1479 else | 1461 if (!imageGrid.cameraLive || imageGrid.selectionType != 'camera') { |
1480 imageGrid.previewElement.classList.add('phototaken'); | 1462 this.context_.selectedImageUrl = imageGrid.selectedItemUrl; |
1481 | 1463 chrome.send( |
1482 if (!imageGrid.cameraLive || imageGrid.selectionType != 'camera') { | 1464 'supervisedUserSelectImage', |
1483 this.context_.selectedImageUrl = imageGrid.selectedItemUrl; | 1465 [imageGrid.selectedItemUrl, imageGrid.selectionType]); |
1484 chrome.send('supervisedUserSelectImage', | 1466 } |
1485 [imageGrid.selectedItemUrl, imageGrid.selectionType]); | 1467 // Start/stop camera on (de)selection. |
1486 } | 1468 if (!imageGrid.inProgramSelection && |
1487 // Start/stop camera on (de)selection. | 1469 imageGrid.selectionType != e.oldSelectionType) { |
1488 if (!imageGrid.inProgramSelection && | 1470 if (imageGrid.selectionType == 'camera') { |
1489 imageGrid.selectionType != e.oldSelectionType) { | 1471 // Programmatic selection of camera item is done in |
1490 if (imageGrid.selectionType == 'camera') { | 1472 // startCamera callback where streaming is started by itself. |
1491 // Programmatic selection of camera item is done in | 1473 imageGrid.startCamera(function() { |
1492 // startCamera callback where streaming is started by itself. | |
1493 imageGrid.startCamera( | |
1494 function() { | |
1495 // Start capture if camera is still the selected item. | 1474 // Start capture if camera is still the selected item. |
1496 $('supervised-user-creation-image-preview-img').classList. | 1475 $('supervised-user-creation-image-preview-img') |
1497 toggle('animated-transform', true); | 1476 .classList.toggle('animated-transform', true); |
1498 return imageGrid.selectedItem == imageGrid.cameraImage; | 1477 return imageGrid.selectedItem == imageGrid.cameraImage; |
1499 }); | 1478 }); |
1500 } else { | 1479 } else { |
1501 $('supervised-user-creation-image-preview-img').classList.toggle( | 1480 $('supervised-user-creation-image-preview-img') |
1502 'animated-transform', false); | 1481 .classList.toggle('animated-transform', false); |
1503 imageGrid.stopCamera(); | 1482 imageGrid.stopCamera(); |
1504 } | 1483 } |
1505 } | 1484 } |
1506 }, | 1485 }, |
1507 | 1486 |
1508 /** | 1487 /** |
1509 * Handle camera-photo flip. | 1488 * Handle camera-photo flip. |
1510 */ | 1489 */ |
1511 handleFlipPhoto_: function() { | 1490 handleFlipPhoto_: function() { |
1512 var imageGrid = this.getScreenElement('image-grid'); | 1491 var imageGrid = this.getScreenElement('image-grid'); |
1513 imageGrid.previewElement.classList.add('animation'); | 1492 imageGrid.previewElement.classList.add('animation'); |
1514 imageGrid.flipPhoto = !imageGrid.flipPhoto; | 1493 imageGrid.flipPhoto = !imageGrid.flipPhoto; |
1515 var flipMessageId = imageGrid.flipPhoto ? | 1494 var flipMessageId = imageGrid.flipPhoto ? |
1516 'photoFlippedAccessibleText' : 'photoFlippedBackAccessibleText'; | 1495 'photoFlippedAccessibleText' : |
1517 announceAccessibleMessage(loadTimeData.getString(flipMessageId)); | 1496 'photoFlippedBackAccessibleText'; |
1518 }, | 1497 announceAccessibleMessage(loadTimeData.getString(flipMessageId)); |
1519 | 1498 }, |
1520 /** | 1499 |
1521 * Handle photo capture from the live camera stream. | 1500 /** |
1522 */ | 1501 * Handle photo capture from the live camera stream. |
1523 handleTakePhoto_: function(e) { | 1502 */ |
1524 this.getScreenElement('image-grid').takePhoto(); | 1503 handleTakePhoto_: function(e) { |
1525 chrome.send('supervisedUserTakePhoto'); | 1504 this.getScreenElement('image-grid').takePhoto(); |
1526 }, | 1505 chrome.send('supervisedUserTakePhoto'); |
1527 | 1506 }, |
1528 handlePhotoTaken_: function(e) { | 1507 |
1529 chrome.send('supervisedUserPhotoTaken', [e.dataURL]); | 1508 handlePhotoTaken_: function(e) { |
1530 announceAccessibleMessage( | 1509 chrome.send('supervisedUserPhotoTaken', [e.dataURL]); |
1531 loadTimeData.getString('photoCaptureAccessibleText')); | 1510 announceAccessibleMessage( |
1532 }, | 1511 loadTimeData.getString('photoCaptureAccessibleText')); |
1533 | 1512 }, |
1534 /** | 1513 |
1535 * Handle photo updated event. | 1514 /** |
1536 * @param {Event} e Event with 'dataURL' property containing a data URL. | 1515 * Handle photo updated event. |
1537 */ | 1516 * @param {Event} e Event with 'dataURL' property containing a data URL. |
1538 handlePhotoUpdated_: function(e) { | 1517 */ |
1539 chrome.send('supervisedUserPhotoTaken', [e.dataURL]); | 1518 handlePhotoUpdated_: function(e) { |
1540 }, | 1519 chrome.send('supervisedUserPhotoTaken', [e.dataURL]); |
1541 | 1520 }, |
1542 /** | 1521 |
1543 * Handle discarding the captured photo. | 1522 /** |
1544 */ | 1523 * Handle discarding the captured photo. |
1545 handleDiscardPhoto_: function(e) { | 1524 */ |
1546 var imageGrid = this.getScreenElement('image-grid'); | 1525 handleDiscardPhoto_: function(e) { |
1547 imageGrid.discardPhoto(); | 1526 var imageGrid = this.getScreenElement('image-grid'); |
1548 chrome.send('supervisedUserDiscardPhoto'); | 1527 imageGrid.discardPhoto(); |
1549 announceAccessibleMessage( | 1528 chrome.send('supervisedUserDiscardPhoto'); |
1550 loadTimeData.getString('photoDiscardAccessibleText')); | 1529 announceAccessibleMessage( |
1551 }, | 1530 loadTimeData.getString('photoDiscardAccessibleText')); |
1552 | 1531 }, |
1553 setCameraPresent: function(present) { | 1532 |
1554 this.getScreenElement('image-grid').cameraPresent = present; | 1533 setCameraPresent: function(present) { |
1555 }, | 1534 this.getScreenElement('image-grid').cameraPresent = present; |
1556 | 1535 }, |
1557 setExistingSupervisedUsers: function(users) { | 1536 |
1558 var selectedUser = null; | 1537 setExistingSupervisedUsers: function(users) { |
1559 // Store selected user | 1538 var selectedUser = null; |
1560 if (this.importList_.selectedPod) | 1539 // Store selected user |
1561 selectedUser = this.importList_.selectedPod.user.id; | 1540 if (this.importList_.selectedPod) |
1562 | 1541 selectedUser = this.importList_.selectedPod.user.id; |
1563 var userList = users; | 1542 |
1564 userList.sort(function(a, b) { | 1543 var userList = users; |
1565 // Put existing users last. | 1544 userList.sort(function(a, b) { |
1566 if (a.exists != b.exists) | 1545 // Put existing users last. |
1567 return a.exists ? 1 : -1; | 1546 if (a.exists != b.exists) |
1568 // Sort rest by name. | 1547 return a.exists ? 1 : -1; |
1569 return a.name.localeCompare(b.name, [], {sensitivity: 'base'}); | 1548 // Sort rest by name. |
1570 }); | 1549 return a.name.localeCompare(b.name, [], {sensitivity: 'base'}); |
1571 | 1550 }); |
1572 this.importList_.clearPods(); | 1551 |
1573 var selectedIndex = -1; | 1552 this.importList_.clearPods(); |
1574 for (var i = 0; i < userList.length; ++i) { | 1553 var selectedIndex = -1; |
1575 this.importList_.addPod(userList[i]); | 1554 for (var i = 0; i < userList.length; ++i) { |
1576 if (selectedUser == userList[i].id) | 1555 this.importList_.addPod(userList[i]); |
1577 selectedIndex = i; | 1556 if (selectedUser == userList[i].id) |
1578 } | 1557 selectedIndex = i; |
1579 | 1558 } |
1580 if (userList.length == 1) | 1559 |
1581 this.importList_.selectPod(this.importList_.pods[0]); | 1560 if (userList.length == 1) |
1582 | 1561 this.importList_.selectPod(this.importList_.pods[0]); |
1583 if (selectedIndex >= 0) | 1562 |
1584 this.importList_.selectPod(this.importList_.pods[selectedIndex]); | 1563 if (selectedIndex >= 0) |
1585 | 1564 this.importList_.selectPod(this.importList_.pods[selectedIndex]); |
1586 if (this.currentPage_ == 'username') | 1565 |
1587 this.getScreenElement('import-link').hidden = (userList.length == 0); | 1566 if (this.currentPage_ == 'username') |
1588 }, | 1567 this.getScreenElement('import-link').hidden = |
1589 }; | 1568 (userList.length == 0); |
1590 }); | 1569 }, |
1591 | 1570 }; |
| 1571 }); |
OLD | NEW |