1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
9 * Class that keeps track of current burn process state.
10 * @param {Object} strings Localized state strings.
13 function State(strings) {
14 this.setStrings(strings);
15 this.changeState(State.StatesEnum.DEVICE_NONE);
23 cssState: 'device-detected-none',
26 cssState: 'device-detected-usb warning',
29 cssState: 'device-detected-sd warning',
32 cssState: 'device-detected-mul warning',
35 cssState: 'warning-no-conf',
37 ERROR_DEVICE_TOO_SMALL: {
38 cssState: 'warning-no-conf',
41 cssState: 'progress progress-canceble',
44 cssState: 'progress progress-canceble',
59 * Sets the state strings.
60 * @param {Object} strings Localized state strings.
62 setStrings: function(strings) {
63 State.StatesEnum.DEVICE_NONE.statusText =
64 strings.getString('statusDevicesNone');
65 State.StatesEnum.DEVICE_NONE.warningText =
66 strings.getString('warningDevicesNone');
67 State.StatesEnum.DEVICE_USB.statusText =
68 strings.getString('statusDeviceUSB');
69 State.StatesEnum.DEVICE_SD.statusText = strings.getString('statusDeviceSD');
70 State.StatesEnum.DEVICE_MUL.statusText =
71 strings.getString('statusDevicesMultiple');
72 State.StatesEnum.ERROR_NO_NETWORK.statusText =
73 strings.getString('statusNoConnection');
74 State.StatesEnum.ERROR_NO_NETWORK.warningText =
75 strings.getString('warningNoConnection');
76 State.StatesEnum.ERROR_DEVICE_TOO_SMALL.statusText =
77 strings.getString('statusNoSpace');
78 State.StatesEnum.PROGRESS_DOWNLOAD.statusText =
79 strings.getString('statusDownloading');
80 State.StatesEnum.PROGRESS_UNZIP.statusText =
81 strings.getString('statusUnzip');
82 State.StatesEnum.PROGRESS_BURN.statusText = strings.getString('statusBurn');
83 State.StatesEnum.FAIL.statusText = strings.getString('statusError');
84 State.StatesEnum.SUCCESS.statusText = strings.getString('statusSuccess');
85 State.StatesEnum.SUCCESS.warningText = strings.getString('warningSuccess');
89 * Changes the current state to new state.
90 * @param {Object} newState Specifies the new state object.
92 changeState: function(newState) {
93 if (newState == this.state)
95 this.state = newState;
97 $('main-content').className = this.state.cssState;
99 $('status-text').textContent = this.state.statusText;
101 if (newState.warningText)
102 $('warning-text').textContent = this.state.warningText;
104 if (this.isInitialState() && this.state != State.StatesEnum.DEVICE_NONE) {
105 $('warning-button').textContent = localStrings.getString('confirmButton');
106 } else if (this.state == State.StatesEnum.FAIL) {
107 $('warning-button').textContent =
108 localStrings.getString('retryButton');
113 * Reset to initial state.
114 * @param {Array} devices Array of device information.
116 gotoInitialState: function(devices) {
117 if (devices.length == 0) {
118 this.changeState(State.StatesEnum.DEVICE_NONE);
119 } else if (devices.length == 1) {
120 // If a device type is not specified for some reason, we should
121 // default to display a USB device.
122 var initialState = State.StatesEnum.DEVICE_USB;
123 if (devices[0].type == 'sd')
124 initialState = State.StatesEnum.DEVICE_SD;
125 this.changeState(initialState);
127 this.changeState(State.StatesEnum.DEVICE_MUL);
132 * Returns true if the device is in initial state.
133 * @return {boolean} True if the device is in initial state else false.
135 isInitialState: function() {
136 return this.state == State.StatesEnum.DEVICE_NONE ||
137 this.state == State.StatesEnum.DEVICE_USB ||
138 this.state == State.StatesEnum.DEVICE_SD ||
139 this.state == State.StatesEnum.DEVICE_MUL;
143 * Returns true if device state matches the given state name.
144 * @param {string} stateName Given state name.
145 * @return {boolean} True if the device state matches the given state name.
147 equals: function(stateName) {
148 return this.state == stateName;
153 * Class that keeps track of available devices.
156 function DeviceSelection() {
157 this.selectedDevice = undefined;
161 DeviceSelection.prototype = {
163 * Shows the currently selected device.
165 showDeviceSelection: function() {
166 if (this.devices.length == 0) {
167 this.selectedDevice = undefined;
169 this.selectDevice(this.devices[0].devicePath);
174 * Handles device selected event.
175 * @param {string} label Device label.
176 * @param {string} filePath File path.
177 * @param {string} devicePath Selected device path.
179 onDeviceSelected: function(label, filePath, devicePath) {
180 $('warning-button').onclick =
181 browserBridge.sendBurnImageMessage.bind(browserBridge, filePath,
184 this.selectedDevice = devicePath;
186 $('warning-text').textContent =
187 localStrings.getStringF('warningDevices', label);
191 * Selects the specified device based on the specified path.
192 * @param {string} path Device path.
194 selectDevice: function(path) {
195 var element = $('radio-' + path);
196 element.checked = true;
197 element.onclick.apply(element);
201 * Creates a new device element.
202 * @param {Object} device Specifies new device information.
203 * @return {HTMLLIElement} New device element.
205 createNewDeviceElement: function(device) {
206 var element = document.createElement('li');
207 var radioButton = document.createElement('input');
208 radioButton.type = 'radio';
209 radioButton.name = 'device';
210 radioButton.value = device.label;
211 radioButton.id = 'radio-' + device.devicePath;
212 radioButton.className = 'float-start';
213 var deviceLabelText = document.createElement('p');
214 deviceLabelText.textContent = device.label;
215 deviceLabelText.className = 'select-option float-start';
216 var newLine = document.createElement('div');
217 newLine.className = 'new-line';
218 element.appendChild(radioButton);
219 element.appendChild(deviceLabelText);
220 element.appendChild(newLine);
221 element.id = 'select-' + device.devicePath;
222 element.className = 'selection-element';
223 radioButton.onclick = this.onDeviceSelected.bind(this,
224 device.label, device.filePath, device.devicePath);
229 * Updates the list of selected devices.
230 * @param {Array} devices List of devices.
232 devicesUpdated: function(newDevices) {
233 this.devices = newDevices;
234 var selectListDOM = $('device-selection');
235 selectListDOM.innerHTML = '';
236 if (this.devices.length > 0) {
237 for (var i = 0; i < this.devices.length; i++) {
238 var element = this.createNewDeviceElement(this.devices[i]);
239 selectListDOM.appendChild(element);
241 this.selectDevice(this.devices[0].devicePath);
243 this.selectedDevice = undefined;
248 * Handles device added event.
249 * @param {Object} device Device information.
250 * @param {boolean} allowSelect True to update the selected device info.
252 deviceAdded: function(device, allowSelect) {
253 this.devices.push(device);
254 var selectListDOM = $('device-selection');
255 selectListDOM.appendChild(this.createNewDeviceElement(device));
256 if (allowSelect && this.devices.length == 1)
257 this.selectDevice(device.devicePath);
261 * Handles device removed event.
262 * @param {string} devicePath Device path to be removed.
263 * @param {boolean} allowSelect True to update the selected device info.
265 deviceRemoved: function(devicePath, allowSelect) {
266 device = this.findDevice(devicePath);
269 this.devices.splice(this.devices.indexOf(device), 1);
271 // Remove device selection element from DOM.
272 var deviceSelectElement = $('select-' + devicePath);
273 deviceSelectElement.parentNode.removeChild(deviceSelectElement);
275 // Update selected device element.
277 if (this.devices.length > 0) {
278 if (this.selectedDevice == devicePath)
279 this.selectDevice(this.devices[0].devicePath);
281 this.selectedDevice = undefined;
287 * Finds device with given device path property.
288 * @param {string} devicePath Device path of device to find.
289 * @return {Object} Matching device information or undefined if not found.
291 findDevice: function(devicePath) {
292 for (var i = 0; i < this.devices.length; ++i) {
293 if (this.devices[i].devicePath == devicePath) {
294 return this.devices[i];
302 * Class that handles communication with chrome.
305 function BrowserBridge() {
306 this.currentState = new State(localStrings);
307 this.deviceSelection = new DeviceSelection();
308 // We will use these often so it makes sence making them class members to
309 // avoid frequent document.getElementById calls.
310 this.progressElement = $('progress-div');
311 this.progressText = $('progress-text');
312 this.progressTimeLeftText = $('pending-time');
315 BrowserBridge.prototype = {
316 sendCancelMessage: function() {
317 chrome.send('cancelBurnImage');
320 sendGetDevicesMessage: function() {
321 chrome.send('getDevices');
324 sendWebuiInitializedMessage: function() {
325 chrome.send('webuiInitialized');
329 * Sends the burn image message to c++ code.
330 * @param {string} filePath Specifies the file path.
331 * @param {string} devicePath Specifies the device path.
333 sendBurnImageMessage: function(filePath, devicePath) {
334 chrome.send('burnImage', [devicePath, filePath]);
337 reportSuccess: function() {
338 this.currentState.changeState(State.StatesEnum.SUCCESS);
342 * Update the device state to report a failure and display an error message to
344 * @param {string} errorMessage Specifies the warning text message.
346 reportFail: function(errorMessage) {
347 this.currentState.changeState(State.StatesEnum.FAIL);
348 $('warning-text').textContent = errorMessage;
349 $('warning-button').onclick = this.onBurnRetry.bind(this);
353 * Handles device added event.
354 * @param {Object} device Device information.
356 deviceAdded: function(device) {
357 var inInitialState = this.currentState.isInitialState();
358 this.deviceSelection.deviceAdded(device, inInitialState);
360 this.currentState.gotoInitialState(this.deviceSelection.devices);
364 * Handles device removed event.
365 * @param {string} devicePath Device path to be removed.
367 deviceRemoved: function(devicePath) {
368 var inInitialState = this.currentState.isInitialState();
369 this.deviceSelection.deviceRemoved(devicePath, inInitialState);
371 this.currentState.gotoInitialState(this.deviceSelection.devices);
375 * Gets device callbacks and update the current state.
376 * @param {Array} devices List of devices.
378 getDevicesCallback: function(devices) {
379 this.deviceSelection.devicesUpdated(devices);
380 this.currentState.gotoInitialState(this.deviceSelection.devices);
381 this.sendWebuiInitializedMessage();
385 * Updates the progress information based on the signal received.
386 * @param {Object} updateSignal Specifies the signal information.
388 updateProgress: function(updateSignal) {
389 if (updateSignal.progressType == 'download' &&
390 !this.currentState.equals(State.StatesEnum.PROGRESS_DOWNLOAD)) {
391 this.currentState.changeState(State.StatesEnum.PROGRESS_DOWNLOAD);
392 } else if (updateSignal.progressType == 'unzip' &&
393 !this.currentState.equals(State.StatesEnum.PROGRESS_UNZIP)) {
394 this.currentState.changeState(State.StatesEnum.PROGRESS_UNZIP);
395 } else if (updateSignal.progressType == 'burn' &&
396 !this.currentState.equals(State.StatesEnum.PROGRESS_BURN)) {
397 this.currentState.changeState(State.StatesEnum.PROGRESS_BURN);
400 if (!(updateSignal.amountTotal > 0)) {
401 this.progressElement.removeAttribute('value');
403 this.progressElement.value = updateSignal.amountFinished;
404 this.progressElement.max = updateSignal.amountTotal;
407 this.progressText.textContent = updateSignal.progressText;
408 this.progressTimeLeftText.textContent = updateSignal.timeLeftText;
411 reportNoNetwork: function() {
412 this.currentState.changeState(State.StatesEnum.ERROR_NO_NETWORK);
415 reportNetworkDetected: function() {
416 if (this.currentState.equals(State.StatesEnum.ERROR_NO_NETWORK)) {
417 this.deviceSelection.showDeviceSelection();
418 this.currentState.gotoInitialState(this.deviceSelection.devices);
423 * Updates the current state to report device too small error.
424 * @param {number} deviceSize Received device size.
426 reportDeviceTooSmall: function(deviceSize) {
427 this.currentState.changeState(State.StatesEnum.ERROR_DEVICE_TOO_SMALL);
428 $('warning-text').textContent =
429 localStrings.getStringF('warningNoSpace', deviceSize);
433 * Processes click on 'Retry' button in FAIL state.
435 onBurnRetry: function() {
436 this.deviceSelection.showDeviceSelection();
437 this.currentState.gotoInitialState(this.deviceSelection.devices);
441 document.addEventListener('DOMContentLoaded', function() {
442 localStrings = new LocalStrings();
443 browserBridge = new BrowserBridge();
445 jstProcess(new JsEvalContext(templateData), $('more-info-link'));
447 $('cancel-button').onclick =
448 browserBridge.sendCancelMessage.bind(browserBridge);
449 browserBridge.sendGetDevicesMessage();