| 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 |