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 3 // found in the LICENSE file. 4 5 cr.define('nfcDebug', function() { 6 'use strict'; 7 8 function NfcDebugUI() { 9 this.adapterData_ = {}; 10 this.peerData_ = {}; 11 this.tagData_ = {}; 12 } 13 14 NfcDebugUI.prototype = { 15 setAdapterData: function(data) { 16 this.adapterData_ = data; 17 }, 18 19 setPeerData: function(data) { 20 this.peerData_ = data; 21 }, 22 23 setTagData: function(data) { 24 this.tagData_ = data; 25 }, 26 27 /** 28 * Powers the NFC adapter ON or OFF. 29 */ 30 toggleAdapterPower: function() { 31 chrome.send('setAdapterPower', [!this.adapterData_.powered]); 32 }, 33 34 /** 35 * Tells the NFC adapter to start or stop polling. 36 */ 37 toggleAdapterPolling: function() { 38 chrome.send('setAdapterPolling', [!this.adapterData_.polling]); 39 }, 40 41 /** 42 * Notifies the UI that the user made an NDEF type selection and the 43 * appropriate form should be displayed. 44 */ 45 recordTypeChanged: function() { 46 this.updateRecordFormContents(); 47 }, 48 49 /** 50 * Creates a table element and populates it for each record contained 51 * in the given list of records and adds them as a child of the given 52 * DOMElement. This method will replace the contents of the given element 53 * with the tables. 54 * 55 * @param {DOMElement} div The container that the records should be rendered 56 * to. 57 * @param {Array} records List of NDEF record data. 58 */ 59 renderRecords: function(div, records) { 60 div.textContent = ''; 61 if (records.length == 0) { 62 return; 63 } 64 var self = this; 65 records.forEach(function(record) { 66 var recordDiv = document.createElement('div'); 67 recordDiv.setAttribute('class', 'record-div'); 68 for (var key in record) { 69 if (!record.hasOwnProperty(key)) 70 continue; 71 72 var rowDiv = document.createElement('div'); 73 rowDiv.setAttribute('class', 'record-key-value-div'); 74 75 var keyElement, valueElement; 76 if (key == 'titles') { 77 keyElement = document.createElement('div'); 78 keyElement.setAttribute('class', 'record-key-div'); 79 keyElement.appendChild(document.createTextNode(key)); 80 valueElement = document.createElement('div'); 81 valueElement.setAttribute('class', 'record-value-div'); 82 self.renderRecords(valueElement, record[key]); 83 } else { 84 keyElement = document.createElement('span'); 85 keyElement.setAttribute('class', 'record-key-span'); 86 keyElement.appendChild(document.createTextNode(key)); 87 valueElement = document.createElement('span'); 88 valueElement.setAttribute('class', 'record-value-span'); 89 valueElement.appendChild(document.createTextNode(record[key])); 90 } 91 rowDiv.appendChild(keyElement); 92 rowDiv.appendChild(valueElement); 93 recordDiv.appendChild(rowDiv); 94 } 95 div.appendChild(recordDiv); 96 if (records[records.length - 1] !== record) 97 div.appendChild(document.createElement('hr')); 98 }); 99 }, 100 101 /** 102 * Updates which record type form is displayed based on the currently 103 * selected type. 104 */ 105 updateRecordFormContents: function() { 106 var recordTypeMenu = $('record-type-menu'); 107 var selectedType = 108 recordTypeMenu.options[recordTypeMenu.selectedIndex].value; 109 this.updateRecordFormContentsFromType(selectedType); 110 }, 111 112 /** 113 * Updates which record type form is displayed based on the passed in 114 * type string. 115 * 116 * @param {string} type The record type. 117 */ 118 updateRecordFormContentsFromType: function(type) { 119 $('text-form').hidden = (type != 'text'); 120 $('uri-form').hidden = (type != 'uri'); 121 $('smart-poster-form').hidden = (type != 'smart-poster'); 122 }, 123 124 /** 125 * Tries to push or write the record to the remote tag or device based on 126 * the contents of the record form fields. 127 */ 128 submitRecordForm: function() { 129 var recordTypeMenu = $('record-type-menu'); 130 var selectedType = 131 recordTypeMenu.options[recordTypeMenu.selectedIndex].value; 132 var recordData = {}; 133 if (selectedType == 'text') { 134 recordData.type = 'TEXT'; 135 if ($('text-form-text').value) 136 recordData.text = $('text-form-text').value; 137 if ($('text-form-encoding').value) 138 recordData.encoding = $('text-form-encoding').value; 139 if ($('text-form-language-code').value) 140 recordData.languageCode = $('text-form-language-code').value; 141 } else if (selectedType == 'uri') { 142 recordData.type = 'URI'; 143 if ($('uri-form-uri').value) 144 recordData.uri = $('uri-form-uri').value; 145 if ($('uri-form-mime-type').value) 146 recordData.mimeType = $('uri-form-mime-type').value; 147 if ($('uri-form-target-size').value) { 148 var targetSize = $('uri-form-target-size').value; 149 targetSize = parseFloat(targetSize); 150 recordData.targetSize = isNaN(targetSize) ? 0.0 : targetSize; 151 } 152 } else if (selectedType == 'smart-poster') { 153 recordData.type = 'SMART_POSTER'; 154 if ($('smart-poster-form-uri').value) 155 recordData.uri = $('smart-poster-form-uri').value; 156 if ($('smart-poster-form-mime-type').value) 157 recordData.mimeType = $('smart-poster-form-mime-type').value; 158 if ($('smart-poster-form-target-size').value) { 159 var targetSize = $('smart-poster-form-target-size').value; 160 targetSize = parseFloat(targetSize); 161 recordData.targetSize = isNaN(targetSize) ? 0.0 : targetSize; 162 } 163 var title = {}; 164 if ($('smart-poster-form-title-text').value) 165 title.text = $('smart-poster-form-title-text').value; 166 if ($('smart-poster-form-title-encoding').value) 167 title.encoding = $('smart-poster-form-title-encoding').value; 168 if ($('smart-poster-form-title-language-code').value) 169 title.languageCode = 170 $('smart-poster-form-title-language-code').value; 171 if (Object.keys(title).length != 0) 172 recordData.titles = [title]; 173 } 174 chrome.send('submitRecordForm', [recordData]); 175 }, 176 177 /** 178 * Given a dictionary |data|, builds a table where each row contains the 179 * a key and its value. The resulting table is then added as the sole child 180 * of |div|. |data| contains information about an adapter, tag, or peer and 181 * this method creates a table for display, thus the value of some keys 182 * will be processed. 183 * 184 * @param {DOMElement} div The container that the table should be rendered 185 * to. 186 * @param {dictionary} data Data to generate the table from. 187 */ 188 createTableFromData: function(div, data) { 189 div.textContent = ''; 190 var table = document.createElement('table'); 191 table.classList.add('parameters-table'); 192 for (var key in data) { 193 var row = document.createElement('tr'); 194 var col = document.createElement('td'); 195 col.textContent = key; 196 row.appendChild(col); 197 198 col = document.createElement('td'); 199 var value = data[key]; 200 if (key == 'records') 201 value = value.length; 202 else if (key == 'supportedTechnologies') 203 value = value.join(', '); 204 col.textContent = value; 205 row.appendChild(col); 206 table.appendChild(row); 207 } 208 div.appendChild(table); 209 }, 210 }; 211 212 cr.addSingletonGetter(NfcDebugUI); 213 214 /** 215 * Initializes the page after the content has loaded. 216 */ 217 NfcDebugUI.initialize = function() { 218 $('nfc-adapter-info').hidden = true; 219 $('adapter-toggles').hidden = true; 220 $('nfc-adapter-info').classList.add('transition-out'); 221 $('ndef-record-form').classList.add('transition-out'); 222 $('nfc-peer-info').classList.add('transition-out'); 223 $('nfc-tag-info').classList.add('transition-out'); 224 $('power-toggle').onclick = function() { 225 NfcDebugUI.getInstance().toggleAdapterPower(); 226 }; 227 $('poll-toggle').onclick = function() { 228 NfcDebugUI.getInstance().toggleAdapterPolling(); 229 }; 230 $('record-type-menu').onchange = function() { 231 NfcDebugUI.getInstance().recordTypeChanged(); 232 }; 233 $('record-form-submit-button').onclick = function() { 234 NfcDebugUI.getInstance().submitRecordForm(); 235 }; 236 $('record-form-submit-button').hidden = true; 237 NfcDebugUI.getInstance().updateRecordFormContents(); 238 chrome.send('initialize'); 239 }; 240 241 /** 242 * Updates the UI based on the NFC availability on the current platform. 243 * 244 * @param {bool} available If true, NFC is supported on the current platform. 245 */ 246 NfcDebugUI.onNfcAvailabilityDetermined = function(available) { 247 $('nfc-not-supported').hidden = available; 248 }; 249 250 /** 251 * Notifies the UI that information about the NFC adapter has been received. 252 * 253 * @param {dictionary} data Properties of the NFC adapter. 254 */ 255 NfcDebugUI.onNfcAdapterInfoChanged = function(data) { 256 NfcDebugUI.getInstance().setAdapterData(data); 257 258 $('nfc-adapter-info').hidden = false; 259 NfcDebugUI.getInstance().createTableFromData($('adapter-parameters'), data); 260 261 $('nfc-adapter-info').classList.toggle('transition-out', !data.present); 262 $('nfc-adapter-info').classList.toggle('transition-in', data.present); 263 $('ndef-record-form').classList.toggle('transition-out', !data.present); 264 $('ndef-record-form').classList.toggle('transition-in', data.present); 265 266 $('adapter-toggles').hidden = !data.present; 267 $('ndef-record-form').hidden = !data.present; 268 269 $('power-toggle').textContent = loadTimeData.getString( 270 data.powered ? 'adapterPowerOffText' : 'adapterPowerOnText'); 271 $('poll-toggle').textContent = loadTimeData.getString( 272 data.polling ? 'adapterStopPollText' : 'adapterStartPollText'); 273 }; 274 275 /** 276 * Notifies the UI that information about an NFC peer has been received. 277 * 278 * @param {dictionary} data Properties of the NFC peer device. 279 */ 280 NfcDebugUI.onNfcPeerDeviceInfoChanged = function(data) { 281 NfcDebugUI.getInstance().setPeerData(data); 282 283 if (Object.keys(data).length == 0) { 284 $('nfc-peer-info').classList.add('transition-out'); 285 $('nfc-peer-info').classList.remove('transition-in'); 286 $('record-form-submit-button').hidden = true; 287 return; 288 } 289 290 $('nfc-peer-info').classList.remove('transition-out'); 291 $('nfc-peer-info').classList.add('transition-in'); 292 293 NfcDebugUI.getInstance().createTableFromData($('peer-parameters'), data); 294 295 $('record-form-submit-button').hidden = false; 296 $('record-form-submit-button').textContent = 297 loadTimeData.getString('ndefFormPushButtonText'); 298 299 if (data.records.length == 0) { 300 $('peer-records-entry').hidden = true; 301 return; 302 } 303 304 $('peer-records-entry').hidden = false; 305 NfcDebugUI.getInstance().renderRecords($('peer-records-container'), 306 data.records); 307 }; 308 309 /** 310 * Notifies the UI that information about an NFC tag has been received. 311 * 312 * @param {dictionary} data Properties of the NFC tag. 313 */ 314 NfcDebugUI.onNfcTagInfoChanged = function(data) { 315 NfcDebugUI.getInstance().setTagData(data); 316 317 if (Object.keys(data).length == 0) { 318 $('nfc-tag-info').classList.add('transition-out'); 319 $('nfc-tag-info').classList.remove('transition-in'); 320 $('record-form-submit-button').hidden = true; 321 return; 322 } 323 324 $('nfc-tag-info').classList.remove('transition-out'); 325 $('nfc-tag-info').classList.add('transition-in'); 326 327 NfcDebugUI.getInstance().createTableFromData($('tag-parameters'), data); 328 329 $('record-form-submit-button').hidden = false; 330 $('record-form-submit-button').textContent = 331 loadTimeData.getString('ndefFormWriteButtonText'); 332 333 if (data.records.length == 0) { 334 $('tag-records-entry').hidden = true; 335 return; 336 } 337 338 $('tag-records-entry').hidden = false; 339 NfcDebugUI.getInstance().renderRecords($('tag-records-container'), 340 data.records); 341 }; 342 343 /** 344 * Notifies the UI that a call to "setAdapterPower" failed. Displays an 345 * alert. 346 */ 347 NfcDebugUI.onSetAdapterPowerFailed = function() { 348 alert(loadTimeData.getString('errorFailedToSetPowerText')); 349 }; 350 351 /** 352 * Notifies the UI that a call to "setAdapterPolling" failed. Displays an 353 * alert. 354 */ 355 NfcDebugUI.onSetAdapterPollingFailed = function() { 356 alert(loadTimeData.getString('errorFailedToSetPollingText')); 357 }; 358 359 /** 360 * Notifies the UI that an error occurred while submitting an NDEF record 361 * form. 362 * @param {string} errorMessage An error message, describing the failure. 363 */ 364 NfcDebugUI.onSubmitRecordFormFailed = function(errorMessage) { 365 alert(loadTimeData.getString('errorFailedToSubmitPrefixText') + 366 ' ' + errorMessage); 367 }; 368 369 // Export 370 return { 371 NfcDebugUI: NfcDebugUI 372 }; 373 }); 374 375 document.addEventListener('DOMContentLoaded', nfcDebug.NfcDebugUI.initialize); 376