OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 * Javascript for local_discovery.html, served from chrome://devices/ | 6 * Javascript for local_discovery.html, served from chrome://devices/ |
7 * This is used to show discoverable devices near the user. | 7 * This is used to show discoverable devices near the user as well as |
| 8 * cloud devices registered to them. |
8 * | 9 * |
9 * The simple object defined in this javascript file listens for | 10 * The object defined in this javascript file listens for callbacks from the |
10 * callbacks from the C++ code saying that a new device is available. | 11 * C++ code saying that a new device is available as well as manages the UI for |
| 12 * registering a device on the local network. |
11 */ | 13 */ |
12 | 14 |
13 | 15 |
14 <include src="../uber/uber_utils.js" /> | 16 <include src="../uber/uber_utils.js" /> |
15 | 17 |
16 cr.define('local_discovery', function() { | 18 cr.define('local_discovery', function() { |
17 'use strict'; | 19 'use strict'; |
18 | 20 |
19 /** | 21 /** |
| 22 * Prefix for printer management page URLs, relative to base cloud print URL. |
| 23 * @type {string} |
| 24 */ |
| 25 var PRINTER_MANAGEMENT_PAGE_PREFIX = '#printer/id/'; |
| 26 |
| 27 /** |
20 * Map of service names to corresponding service objects. | 28 * Map of service names to corresponding service objects. |
21 * @type {Object.<string,Service>} | 29 * @type {Object.<string,Service>} |
22 */ | 30 */ |
23 var devices = {}; | 31 var devices = {}; |
24 | 32 |
25 | |
26 /** | 33 /** |
27 * Object that represents a device in the device list. | 34 * Object that represents a device in the device list. |
28 * @param {Object} info Information about the device. | 35 * @param {Object} info Information about the device. |
29 * @constructor | 36 * @constructor |
30 */ | 37 */ |
31 function Device(info) { | 38 function Device(info) { |
32 this.info = info; | 39 this.info = info; |
33 this.domElement = null; | 40 this.domElement = null; |
34 } | 41 } |
35 | 42 |
36 Device.prototype = { | 43 Device.prototype = { |
37 /** | 44 /** |
38 * Update the device. | 45 * Update the device. |
39 * @param {Object} info New information about the device. | 46 * @param {Object} info New information about the device. |
40 */ | 47 */ |
41 updateDevice: function(info) { | 48 updateDevice: function(info) { |
42 if (this.domElement && info.is_mine != this.info.is_mine) { | |
43 this.deviceContainer(this.info.is_mine).removeChild(this.domElement); | |
44 this.deviceContainer(info.is_mine).appendChild(this.domElement); | |
45 } | |
46 this.info = info; | 49 this.info = info; |
47 this.renderDevice(); | 50 this.renderDevice(); |
48 }, | 51 }, |
49 | 52 |
50 /** | 53 /** |
51 * Delete the device. | 54 * Delete the device. |
52 */ | 55 */ |
53 removeDevice: function() { | 56 removeDevice: function() { |
54 this.deviceContainer(this.info.is_mine).removeChild(this.domElement); | 57 this.deviceContainer().removeChild(this.domElement); |
55 }, | 58 }, |
56 | 59 |
57 /** | 60 /** |
58 * Render the device to the device list. | 61 * Render the device to the device list. |
59 */ | 62 */ |
60 renderDevice: function() { | 63 renderDevice: function() { |
61 if (this.domElement) { | 64 if (this.domElement) { |
62 clearElement(this.domElement); | 65 clearElement(this.domElement); |
63 } else { | 66 } else { |
64 this.domElement = document.createElement('div'); | 67 this.domElement = document.createElement('div'); |
65 this.deviceContainer(this.info.is_mine).appendChild(this.domElement); | 68 this.deviceContainer().appendChild(this.domElement); |
66 } | 69 } |
67 | 70 |
68 this.domElement.classList.add('device'); | 71 fillDeviceDescription(this.domElement, this.info.human_readable_name, |
69 this.domElement.classList.add('printer-active'); | 72 this.info.description, |
70 | 73 loadTimeData.getString('serviceRegister'), |
71 var deviceInfo = document.createElement('div'); | 74 this.register.bind(this)); |
72 deviceInfo.className = 'device-info'; | |
73 this.domElement.appendChild(deviceInfo); | |
74 | |
75 var deviceName = document.createElement('h3'); | |
76 deviceName.className = 'device-name'; | |
77 deviceName.textContent = this.info.human_readable_name; | |
78 deviceInfo.appendChild(deviceName); | |
79 | |
80 var deviceDescription = document.createElement('div'); | |
81 deviceDescription.className = 'device-description'; | |
82 deviceDescription.textContent = this.info.description; | |
83 deviceInfo.appendChild(deviceDescription); | |
84 | |
85 var buttonContainer = document.createElement('div'); | |
86 buttonContainer.className = 'button-container'; | |
87 this.domElement.appendChild(buttonContainer); | |
88 | |
89 var button = document.createElement('button'); | |
90 button.textContent = loadTimeData.getString('serviceRegister'); | |
91 | |
92 if (this.info.registered) { | |
93 button.disabled = 'disabled'; | |
94 } else { | |
95 button.addEventListener( | |
96 'click', | |
97 sendRegisterDevice.bind(null, this.info.service_name)); | |
98 } | |
99 | |
100 buttonContainer.appendChild(button); | |
101 }, | 75 }, |
102 | 76 |
103 /** | 77 /** |
104 * Return the correct container for the device. | 78 * Return the correct container for the device. |
105 * @param {boolean} is_mine Whether or not the device is in the 'Registered' | 79 * @param {boolean} is_mine Whether or not the device is in the 'Registered' |
106 * section. | 80 * section. |
107 */ | 81 */ |
108 deviceContainer: function(is_mine) { | 82 deviceContainer: function() { |
109 if (is_mine) return $('registered-devices'); | 83 return $('register-device-list'); |
110 return $('unregistered-devices'); | 84 }, |
| 85 /** |
| 86 * Register the device. |
| 87 */ |
| 88 register: function() { |
| 89 chrome.send('registerDevice', [this.info.service_name]); |
| 90 setRegisterPage('register-page-adding1'); |
111 } | 91 } |
112 }; | 92 }; |
113 | 93 |
114 /** | 94 /** |
115 * Appends a row to the output table listing the new device. | 95 * Returns a textual representation of the number of printers on the network. |
116 * @param {string} name Name of the device. | 96 * @return {string} Number of printers on the network as localized string. |
117 * @param {string} info Additional info of the device, if empty device need to | |
118 * be deleted. | |
119 */ | 97 */ |
120 function onDeviceUpdate(name, info) { | 98 function generateNumberPrintersAvailableText(numberPrinters) { |
121 if (info) { | 99 if (numberPrinters == 0) { |
122 if (devices.hasOwnProperty(name)) { | 100 return loadTimeData.getString('printersOnNetworkZero'); |
123 devices[name].updateDevice(info); | 101 } else if (numberPrinters == 1) { |
124 } else { | 102 return loadTimeData.getString('printersOnNetworkOne'); |
125 devices[name] = new Device(info); | |
126 devices[name].renderDevice(); | |
127 } | |
128 } else { | 103 } else { |
129 devices[name].removeDevice(); | 104 return loadTimeData.getStringF('printersOnNetworkMultiple', |
130 delete devices[name]; | 105 numberPrinters); |
131 } | 106 } |
132 } | 107 } |
133 | 108 |
134 /** | 109 /** |
| 110 * Fill device element with the description of a device. |
| 111 * @param {HTMLElement} device_dom_element Element to be filled. |
| 112 * @param {string} name Name of device. |
| 113 * @param {string} description Description of device. |
| 114 * @param {string} button_text Text to appear on button. |
| 115 * @param {function()} button_action Action for button. |
| 116 */ |
| 117 function fillDeviceDescription(device_dom_element, |
| 118 name, |
| 119 description, |
| 120 button_text, |
| 121 button_action) { |
| 122 device_dom_element.classList.add('device'); |
| 123 |
| 124 var deviceInfo = document.createElement('div'); |
| 125 deviceInfo.className = 'device-info'; |
| 126 device_dom_element.appendChild(deviceInfo); |
| 127 |
| 128 var deviceName = document.createElement('h3'); |
| 129 deviceName.className = 'device-name'; |
| 130 deviceName.textContent = name; |
| 131 deviceInfo.appendChild(deviceName); |
| 132 |
| 133 var deviceDescription = document.createElement('div'); |
| 134 deviceDescription.className = 'device-subline'; |
| 135 deviceDescription.textContent = description; |
| 136 deviceInfo.appendChild(deviceDescription); |
| 137 |
| 138 var button = document.createElement('button'); |
| 139 button.textContent = button_text; |
| 140 button.addEventListener('click', button_action); |
| 141 device_dom_element.appendChild(button); |
| 142 } |
| 143 |
| 144 /** |
135 * Hide the register overlay. | 145 * Hide the register overlay. |
136 */ | 146 */ |
137 function showRegisterOverlay() { | 147 function showRegisterOverlay() { |
138 $('register-overlay').classList.add('showing'); | 148 $('register-overlay').classList.add('showing'); |
139 $('overlay').hidden = false; | 149 $('overlay').hidden = false; |
140 uber.invokeMethodOnParent('beginInterceptingEvents'); | 150 uber.invokeMethodOnParent('beginInterceptingEvents'); |
| 151 setRegisterPage('register-page-choose'); |
141 } | 152 } |
142 | 153 |
143 /** | 154 /** |
144 * Show the register overlay. | 155 * Show the register overlay. |
145 */ | 156 */ |
146 function hideRegisterOverlay() { | 157 function hideRegisterOverlay() { |
147 $('register-overlay').classList.remove('showing'); | 158 $('register-overlay').classList.remove('showing'); |
148 $('overlay').hidden = true; | 159 $('overlay').hidden = true; |
149 uber.invokeMethodOnParent('stopInterceptingEvents'); | 160 uber.invokeMethodOnParent('stopInterceptingEvents'); |
150 chrome.send('cancelRegistration'); | 161 chrome.send('cancelRegistration'); |
151 } | 162 } |
152 | 163 |
153 /** | 164 /** |
154 * Clear a DOM element of all children. | 165 * Clear a DOM element of all children. |
155 * @param {HTMLElement} element DOM element to clear. | 166 * @param {HTMLElement} element DOM element to clear. |
156 */ | 167 */ |
157 function clearElement(element) { | 168 function clearElement(element) { |
158 while (element.firstChild) { | 169 while (element.firstChild) { |
159 element.removeChild(element.firstChild); | 170 element.removeChild(element.firstChild); |
160 } | 171 } |
161 } | 172 } |
162 | 173 |
163 /** | 174 /** |
164 * Register a device. | |
165 * @param {string} device The device to register. | |
166 */ | |
167 function sendRegisterDevice(device) { | |
168 chrome.send('registerDevice', [device]); | |
169 } | |
170 | |
171 /** | |
172 * Announce that a registration failed. | 175 * Announce that a registration failed. |
173 */ | 176 */ |
174 function registrationFailed() { | 177 function onRegistrationFailed() { |
175 setRegisterPage('register-page-error'); | 178 setRegisterPage('register-page-error'); |
176 } | 179 } |
177 | 180 |
178 /** | 181 /** |
179 * Update UI to reflect that registration has been confirmed on the printer. | 182 * Update UI to reflect that registration has been confirmed on the printer. |
180 */ | 183 */ |
181 function registrationConfirmedOnPrinter() { | 184 function onRegistrationConfirmedOnPrinter() { |
182 setRegisterPage('register-page-adding2'); | 185 setRegisterPage('register-page-adding2'); |
183 } | 186 } |
184 | 187 |
185 /** | 188 /** |
186 * Announce that a registration succeeeded. | 189 * Update device unregistered device list, and update related strings to |
| 190 * reflect the number of devices available to register. |
| 191 * @param {string} name Name of the device. |
| 192 * @param {string} info Additional info of the device or null if the device |
| 193 * has been removed. |
187 */ | 194 */ |
188 function registrationSuccess() { | 195 function onUnregisteredDeviceUpdate(name, info) { |
189 hideRegisterOverlay(); | 196 if (info) { |
| 197 if (devices.hasOwnProperty(name)) { |
| 198 devices[name].updateDevice(info); |
| 199 } else { |
| 200 devices[name] = new Device(info); |
| 201 devices[name].renderDevice(); |
| 202 } |
| 203 } else { |
| 204 if (devices.hasOwnProperty(name)) { |
| 205 devices[name].removeDevice(); |
| 206 delete devices[name]; |
| 207 } |
| 208 } |
| 209 |
| 210 var numberPrinters = $('register-device-list').children.length; |
| 211 $('printer-num').textContent = generateNumberPrintersAvailableText( |
| 212 numberPrinters); |
| 213 |
| 214 if (numberPrinters == 0) { |
| 215 $('register-message').textContent = loadTimeData.getString( |
| 216 'noPrintersOnNetworkExplanation'); |
| 217 } else { |
| 218 $('register-message').textContent = loadTimeData.getString( |
| 219 'registerConfirmMessage'); |
| 220 } |
190 } | 221 } |
191 | 222 |
192 /** | 223 /** |
| 224 * Handle a list of cloud devices available to the user globally. |
| 225 * @param {Array.<Object>} devices_list List of devices. |
| 226 */ |
| 227 function onCloudDeviceListAvailable(devices_list) { |
| 228 var devicesListLength = devices_list.length; |
| 229 var devicesContainer = $('cloud-devices'); |
| 230 |
| 231 clearElement(devicesContainer); |
| 232 $('cloud-devices-loading').hidden = true; |
| 233 |
| 234 for (var i = 0; i < devicesListLength; i++) { |
| 235 var devicesDomElement = document.createElement('div'); |
| 236 devicesContainer.appendChild(devicesDomElement); |
| 237 |
| 238 var description; |
| 239 if (devices_list[i].description == '') { |
| 240 description = loadTimeData.getString('noDescription'); |
| 241 } else { |
| 242 description = devices_list[i].description; |
| 243 } |
| 244 |
| 245 fillDeviceDescription(devicesDomElement, devices_list[i].display_name, |
| 246 description, 'Manage' /*Localize*/, |
| 247 manageCloudDevice.bind(null, devices_list[i].id)); |
| 248 } |
| 249 } |
| 250 |
| 251 |
| 252 /** |
| 253 * Announce that a registration succeeeded. |
| 254 */ |
| 255 function onRegistrationSuccess() { |
| 256 hideRegisterOverlay(); |
| 257 requestPrinterList(); |
| 258 } |
| 259 |
| 260 /** |
193 * Update visibility status for page. | 261 * Update visibility status for page. |
194 */ | 262 */ |
195 function updateVisibility() { | 263 function updateVisibility() { |
196 chrome.send('isVisible', [!document.webkitHidden]); | 264 chrome.send('isVisible', [!document.webkitHidden]); |
197 } | 265 } |
198 | 266 |
199 /** | 267 /** |
200 * Set the page that the register wizard is on. | 268 * Set the page that the register wizard is on. |
201 * @param {string} page_id ID string for page. | 269 * @param {string} page_id ID string for page. |
202 */ | 270 */ |
203 function setRegisterPage(page_id) { | 271 function setRegisterPage(page_id) { |
204 var pages = $('register-overlay').querySelectorAll('.register-page'); | 272 var pages = $('register-overlay').querySelectorAll('.register-page'); |
205 var pagesLength = pages.length; | 273 var pagesLength = pages.length; |
206 for (var i = 0; i < pagesLength; i++) { | 274 for (var i = 0; i < pagesLength; i++) { |
207 pages[i].hidden = true; | 275 pages[i].hidden = true; |
208 } | 276 } |
209 | 277 |
210 $(page_id).hidden = false; | 278 $(page_id).hidden = false; |
211 } | 279 } |
212 | 280 |
213 /** | 281 /** |
214 * Request a user account from a list. | 282 * Request the printer list. |
215 * @param {Array} users Array of (index, username) tuples. Username may be | |
216 * displayed to the user; index must be passed opaquely to the UI handler. | |
217 */ | 283 */ |
218 function requestUser(users, printerName) { | 284 function requestPrinterList() { |
219 clearElement($('register-user-list')); | 285 clearElement($('cloud-devices')); |
220 | 286 $('cloud-devices-loading').hidden = false; |
221 var usersLength = users.length; | 287 chrome.send('requestPrinterList'); |
222 for (var i = 0; i < usersLength; i++) { | |
223 var userIndex = users[i][0]; | |
224 var userName = users[i][1]; | |
225 | |
226 var option = document.createElement('option'); | |
227 option.textContent = userName; | |
228 option.userData = { userIndex: userIndex, userName: userName }; | |
229 $('register-user-list').appendChild(option); | |
230 } | |
231 | |
232 showRegisterOverlay(); | |
233 setRegisterPage('register-page-choose'); | |
234 $('register-message').textContent = | |
235 loadTimeData.getStringF('registerConfirmMessage', printerName); | |
236 } | 288 } |
237 | 289 |
238 /** | 290 /** |
239 * Send user selection and begin registration. | 291 * Go to management page for a cloud device. |
| 292 * @param {string} device_id ID of device. |
240 */ | 293 */ |
241 function beginRegistration() { | 294 function manageCloudDevice(device_id) { |
242 var userList = $('register-user-list'); | 295 chrome.send('openCloudPrintURL', |
243 var selectedOption = userList.options[userList.selectedIndex]; | 296 [PRINTER_MANAGEMENT_PAGE_PREFIX + device_id]); |
244 var userData = selectedOption.userData; | |
245 chrome.send('chooseUser', [userData.userIndex, userData.userName]); | |
246 setRegisterPage('register-page-adding1'); | |
247 } | 297 } |
248 | 298 |
| 299 |
249 document.addEventListener('DOMContentLoaded', function() { | 300 document.addEventListener('DOMContentLoaded', function() { |
250 uber.onContentFrameLoaded(); | 301 uber.onContentFrameLoaded(); |
251 | 302 |
252 cr.ui.overlay.setupOverlay($('overlay')); | 303 cr.ui.overlay.setupOverlay($('overlay')); |
253 cr.ui.overlay.globalInitialization(); | 304 cr.ui.overlay.globalInitialization(); |
254 $('overlay').addEventListener('cancelOverlay', hideRegisterOverlay); | 305 $('overlay').addEventListener('cancelOverlay', hideRegisterOverlay); |
255 | 306 |
256 var cancelButtons = document.querySelectorAll('.register-cancel'); | 307 var cancelButtons = document.querySelectorAll('.register-cancel'); |
257 var cancelButtonsLength = cancelButtons.length; | 308 var cancelButtonsLength = cancelButtons.length; |
258 for (var i = 0; i < cancelButtonsLength; i++) { | 309 for (var i = 0; i < cancelButtonsLength; i++) { |
259 cancelButtons[i].addEventListener('click', hideRegisterOverlay); | 310 cancelButtons[i].addEventListener('click', hideRegisterOverlay); |
260 } | 311 } |
261 | 312 |
262 $('register-error-exit').addEventListener('click', hideRegisterOverlay); | 313 $('register-error-exit').addEventListener('click', hideRegisterOverlay); |
263 | 314 |
264 $('register-confirmation-continue').addEventListener( | 315 $('add-printers-button').addEventListener('click', |
265 'click', beginRegistration); | 316 showRegisterOverlay); |
266 | 317 |
267 updateVisibility(); | 318 updateVisibility(); |
268 document.addEventListener('webkitvisibilitychange', updateVisibility, | 319 document.addEventListener('webkitvisibilitychange', updateVisibility, |
269 false); | 320 false); |
270 | 321 |
271 var title = loadTimeData.getString('devicesTitle'); | 322 var title = loadTimeData.getString('devicesTitle'); |
272 uber.invokeMethodOnParent('setTitle', {title: title}); | 323 uber.invokeMethodOnParent('setTitle', {title: title}); |
273 | 324 |
274 chrome.send('start'); | 325 chrome.send('start'); |
| 326 requestPrinterList(); |
275 }); | 327 }); |
276 | 328 |
277 return { | 329 return { |
278 registrationSuccess: registrationSuccess, | 330 onRegistrationSuccess: onRegistrationSuccess, |
279 registrationFailed: registrationFailed, | 331 onRegistrationFailed: onRegistrationFailed, |
280 onDeviceUpdate: onDeviceUpdate, | 332 onUnregisteredDeviceUpdate: onUnregisteredDeviceUpdate, |
281 requestUser: requestUser, | 333 onRegistrationConfirmedOnPrinter: onRegistrationConfirmedOnPrinter, |
282 registrationConfirmedOnPrinter: registrationConfirmedOnPrinter | 334 onCloudDeviceListAvailable: onCloudDeviceListAvailable |
283 }; | 335 }; |
284 }); | 336 }); |
OLD | NEW |