| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 var harness = { | 5 var harness = { |
| 6 /** | 6 /** |
| 7 * Kick off the test harness. | 7 * Kick off the test harness. |
| 8 * | 8 * |
| 9 * Called by harness.html after the dom has been parsed. | 9 * Called by harness.html after the dom has been parsed. |
| 10 */ | 10 */ |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 console.log('Created/found', dir.fullPath); | 36 console.log('Created/found', dir.fullPath); |
| 37 createRoots(roots); | 37 createRoots(roots); |
| 38 }, | 38 }, |
| 39 function(err) { | 39 function(err) { |
| 40 console.log('Error creating ' + root + ':' + err.toString()); | 40 console.log('Error creating ' + root + ':' + err.toString()); |
| 41 createRoots(roots); | 41 createRoots(roots); |
| 42 }); | 42 }); |
| 43 } | 43 } |
| 44 | 44 |
| 45 function loadUI() { | 45 function loadUI() { |
| 46 var iframe = document.getElementById('dialog'); | 46 harness.iframe.src = 'main.html' + document.location.search; |
| 47 iframe.setAttribute('src', 'main.html' + document.location.search); | |
| 48 } | 47 } |
| 49 | 48 |
| 50 window.webkitStorageInfo.requestQuota( | 49 window.webkitStorageInfo.requestQuota( |
| 51 window.PERSISTENT, | 50 window.PERSISTENT, |
| 52 1024*1024*1024, // 1 Gig should be enough for everybody:) | 51 1024 * 1024 * 1024, // 1 Gig should be enough for everybody:) |
| 53 function(grantedBytes) { | 52 function(grantedBytes) { |
| 54 window.webkitRequestFileSystem( | 53 window.webkitRequestFileSystem( |
| 55 window.PERSISTENT, | 54 window.PERSISTENT, |
| 56 grantedBytes, | 55 grantedBytes, |
| 57 onFilesystem, | 56 onFilesystem, |
| 58 util.flog('Error initializing filesystem')); | 57 util.flog('Error initializing filesystem')); |
| 59 }, | 58 }, |
| 60 util.flog('Error requesting filesystem quota')); | 59 util.flog('Error requesting filesystem quota')); |
| 61 | 60 |
| 62 var paramstr = decodeURIComponent(document.location.search.substr(1)); | 61 var paramstr = decodeURIComponent(document.location.search.substr(1)); |
| 63 this.params = paramstr ? JSON.parse(paramstr) : {}; | 62 this.params = paramstr ? JSON.parse(paramstr) : {}; |
| 64 | 63 |
| 65 var input = document.getElementById('default-path'); | 64 var input = document.querySelector('#default-path'); |
| 66 input.value = this.params.defaultPath || ''; | 65 input.value = this.params.defaultPath || ''; |
| 67 input.addEventListener('keyup', this.onInputKeyUp.bind(this)); | 66 input.addEventListener('keyup', this.onInputKeyUp.bind(this)); |
| 68 }, | 67 }, |
| 69 | 68 |
| 70 onInputKeyUp: function(event) { | 69 onInputKeyUp: function(event) { |
| 71 if (event.keyCode != 13) | 70 if (event.keyCode != 13) |
| 72 return; | 71 return; |
| 73 | 72 |
| 74 this.changePath(); | 73 this.changePath(); |
| 75 }, | 74 }, |
| 76 | 75 |
| 77 changePath: function() { | 76 changePath: function() { |
| 78 var input = document.getElementById('default-path'); | 77 var input = document.querySelector('#default-path'); |
| 79 this.changeParam('defaultPath', input.value); | 78 this.changeParam('defaultPath', input.value); |
| 80 }, | 79 }, |
| 81 | 80 |
| 82 changeParam: function(name, value) { | 81 changeParam: function(name, value) { |
| 83 this.params[name] = value; | 82 this.params[name] = value; |
| 84 document.location.href = '?' + JSON.stringify(this.params); | 83 document.location.href = '?' + JSON.stringify(this.params); |
| 85 }, | 84 }, |
| 86 | 85 |
| 87 /** | 86 /** |
| 88 * 'Reset Fileystem' button click handler. | 87 * 'Reset Filesystem' button click handler. |
| 89 */ | 88 */ |
| 90 onClearClick: function() { | 89 onClearClick: function() { |
| 91 util.forEachDirEntry(this.filesystem.root, function(dirEntry) { | 90 harness.resetFilesystem(this.filesystem, harness.init); |
| 91 }, |
| 92 |
| 93 resetFilesystem: function(filesystem, opt_callback) { |
| 94 util.forEachDirEntry(filesystem.root, function(dirEntry) { |
| 92 if (!dirEntry) { | 95 if (!dirEntry) { |
| 93 console.log('Filesystem reset.'); | 96 console.log('Filesystem reset.'); |
| 94 harness.init(); | 97 if (opt_callback) opt_callback(); |
| 95 return; | 98 return; |
| 96 } | 99 } |
| 97 util.removeFileOrDirectory( | 100 util.removeFileOrDirectory( |
| 98 dirEntry, | 101 dirEntry, |
| 99 util.flog('Removed ' + dirEntry.name), | 102 util.flog('Removed ' + dirEntry.name), |
| 100 util.flog('Error deleting ' + dirEntry.name)); | 103 util.flog('Error deleting ' + dirEntry.name)); |
| 101 }); | 104 }); |
| 102 }, | 105 }, |
| 103 | 106 |
| 104 /** | 107 /** |
| 108 * 'Auto-populate' button click handler. |
| 109 */ |
| 110 onPopulateClick: function() { |
| 111 harness.importWebDirectory(this.filesystem, |
| 112 'Downloads', 'harness_files', function() {}, harness.init); |
| 113 }, |
| 114 |
| 115 /** |
| 105 * Change handler for the 'input type=file' element. | 116 * Change handler for the 'input type=file' element. |
| 106 */ | 117 */ |
| 107 onFilesChange: function(event) { | 118 onFilesChange: function(event) { |
| 108 this.importFiles([].slice.call(event.target.files)); | 119 this.importFiles(harness.filesystem, |
| 120 harness.fileManager.getCurrentDirectory(), |
| 121 [].slice.call(event.target.files), |
| 122 function() { |
| 123 harness.chrome.fileBrowserPrivate.onFileChanged.notify({ |
| 124 fileUrl: harness.fileManager.getCurrentDirectoryURL() |
| 125 }); |
| 126 }); |
| 109 }, | 127 }, |
| 110 | 128 |
| 111 /** | 129 /** |
| 112 * The fileManager object under test. | 130 * The fileManager object under test. |
| 113 * | 131 * |
| 114 * This is a getter rather than a normal property because the fileManager | 132 * This is a getter rather than a normal property because the fileManager |
| 115 * is initialized asynchronously, and we won't be sure when it'll be | 133 * is initialized asynchronously, and we won't be sure when it'll be |
| 116 * done. Since harness.fileManager is intended to be used for debugging | 134 * done. Since harness.fileManager is intended to be used for debugging |
| 117 * from the JS console, we don't really need to be sure it's ready at any | 135 * from the JS console, we don't really need to be sure it's ready at any |
| 118 * particular time. | 136 * particular time. |
| 119 */ | 137 */ |
| 120 get fileManager() { | 138 get iframe() { return document.querySelector('#dialog') }, |
| 121 return document.getElementById('dialog').contentWindow.fileManager; | 139 |
| 122 }, | 140 get fileManager() { return iframe.contentWindow.fileManager }, |
| 123 get pyautoAPI() { | 141 |
| 124 return document.getElementById('dialog').contentWindow.pyautoAPI; | 142 get pyautoAPI() { return iframe.contentWindow.pyautoAPI }, |
| 125 }, | 143 |
| 126 get chrome() { | 144 get chrome() { return iframe.contentWindow.chrome; }, |
| 127 return document.getElementById('dialog').contentWindow.chrome; | 145 |
| 146 /** |
| 147 * Copy a blob into the filesystem. |
| 148 * |
| 149 * @param {DOMFileSystem} filesystem Destination file system. |
| 150 * @param {string} dstPath Destination file path. |
| 151 * @param {Blob} srcBlob Source blob. |
| 152 * @param {function} callback Completion callback. |
| 153 */ |
| 154 copyBlob: function(filesystem, dstPath, srcBlob, callback) { |
| 155 function onWriterCreated(entry, writer) { |
| 156 writer.onerror = |
| 157 util.flog('Error writing: ' + entry.fullPath, callback); |
| 158 writer.onwriteend = function() { |
| 159 console.log('Wrote ' + srcBlob.size + ' bytes to ' + entry.fullPath); |
| 160 callback(); |
| 161 }; |
| 162 |
| 163 writer.write(srcBlob); |
| 164 } |
| 165 |
| 166 function onFileFound(fileEntry) { |
| 167 fileEntry.createWriter(onWriterCreated.bind(null, fileEntry), util.flog( |
| 168 'Error creating writer for: ' + fileEntry.fullPath, callback)); |
| 169 } |
| 170 |
| 171 util.getOrCreateFile(filesystem.root, dstPath, onFileFound, |
| 172 util.flog('Error finding path: ' + dstPath, callback)); |
| 128 }, | 173 }, |
| 129 | 174 |
| 130 /** | 175 /** |
| 131 * Import a list of File objects into harness.filesystem. | 176 * Import a list of File objects into harness.filesystem. |
| 177 * |
| 178 * @param {DOMFileSystem} filesystem File system. |
| 179 * @param {string} dstDir Destination path. |
| 180 * @param {Array.<File>} files Array of files. |
| 181 * @param {function} callback Completion callback. |
| 132 */ | 182 */ |
| 133 importFiles: function(files) { | 183 importFiles: function(filesystem, dstDir, files, callback) { |
| 134 var currentSrc = null; | |
| 135 var currentDest = null; | |
| 136 var importCount = 0; | |
| 137 | |
| 138 function onWriterCreated(writer) { | |
| 139 writer.onerror = util.flog('Error writing: ' + currentDest.fullPath); | |
| 140 writer.onwriteend = function() { | |
| 141 console.log('Wrote: ' + currentDest.fullPath); | |
| 142 ++importCount; | |
| 143 processNextFile(); | |
| 144 }; | |
| 145 | |
| 146 writer.write(currentSrc); | |
| 147 } | |
| 148 | |
| 149 function onFileFound(fileEntry) { | |
| 150 currentDest = fileEntry; | |
| 151 currentDest.createWriter(onWriterCreated, | |
| 152 util.flog('Error creating writer for: ' + | |
| 153 currentDest.fullPath)); | |
| 154 } | |
| 155 | |
| 156 function processNextFile() { | 184 function processNextFile() { |
| 157 if (files.length == 0) { | 185 if (files.length == 0) { |
| 158 console.log('Import complete: ' + importCount + ' file(s)'); | 186 console.log('Import complete'); |
| 159 harness.chrome.fileBrowserPrivate.onFileChanged.notify({ | 187 callback(); |
| 160 fileUrl: harness.fileManager.getCurrentDirectoryURL() | |
| 161 }); | |
| 162 return; | 188 return; |
| 163 } | 189 } |
| 164 | 190 |
| 165 currentSrc = files.shift(); | 191 var file = files.shift(); |
| 166 var destPath = harness.fileManager.getCurrentDirectory() + '/' + | 192 harness.copyBlob( |
| 167 currentSrc.name.replace(/\^\^/g, '/'); | 193 filesystem, dstDir + '/' + file.name, file, processNextFile); |
| 168 util.getOrCreateFile(harness.filesystem.root, destPath, onFileFound, | |
| 169 util.flog('Error finding path: ' + destPath)); | |
| 170 } | 194 } |
| 171 | 195 |
| 172 console.log('Start import: ' + files.length + ' file(s)'); | 196 console.log('Start import: ' + files.length + ' file(s)'); |
| 173 processNextFile(); | 197 processNextFile(); |
| 198 }, |
| 199 |
| 200 /** |
| 201 * Copy all files recursively linked from a web page. |
| 202 * |
| 203 * Assumes the directory listing format produced by Python's SimpleHTTPServer: |
| 204 * Child names are in |href| attributes, subdirectory names end with '/'. |
| 205 * |
| 206 * @param {DOMFileSystem} filesystem File system. |
| 207 * @param {string} dstDir Destination path. |
| 208 * @param {string} srcDirUrl Directory page url. |
| 209 * @param {function(string, Blob)} onProgress Progress callback. |
| 210 * @param {function} onComplete Completion callback. |
| 211 */ |
| 212 importWebDirectory: function( |
| 213 filesystem, dstDirPath, srcDirUrl, onProgress, onComplete) { |
| 214 var childNames = []; |
| 215 |
| 216 function readFromUrl(url, type, callback) { |
| 217 var xhr = new XMLHttpRequest(); |
| 218 xhr.open('GET', url, true); |
| 219 xhr.responseType = type; |
| 220 xhr.onload = function() { |
| 221 if (xhr.status == 200) |
| 222 callback( |
| 223 xhr.responseType == 'text' ? xhr.responseText : xhr.response); |
| 224 else |
| 225 callback(null); |
| 226 }; |
| 227 xhr.send(); |
| 228 } |
| 229 |
| 230 function processNextChild() { |
| 231 if (childNames.length == 0) { |
| 232 onComplete(); |
| 233 return; |
| 234 } |
| 235 |
| 236 var name = childNames.shift(); |
| 237 var isDirectory = name.match(/\/$/); // Ends with '/'. |
| 238 if (isDirectory) name = name.substring(0, name.length - 1); |
| 239 |
| 240 var srcChildUrl = srcDirUrl + '/' + name; |
| 241 var dstChildPath = dstDirPath + '/' + name; |
| 242 if (isDirectory) { |
| 243 harness.importWebDirectory(filesystem, |
| 244 dstChildPath, srcChildUrl, onProgress, processNextChild); |
| 245 } else { |
| 246 readFromUrl(srcChildUrl, 'blob', function(blob) { |
| 247 onProgress(blob); |
| 248 harness.copyBlob(filesystem, dstChildPath, blob, processNextChild); |
| 249 }); |
| 250 } |
| 251 } |
| 252 |
| 253 readFromUrl(srcDirUrl, 'text', function(text) { |
| 254 if (!text) { |
| 255 console.log('Cannot read ' + srcDirUrl); |
| 256 onComplete(); |
| 257 return; |
| 258 } |
| 259 var links = text.match(/href=".*"/g); // Extract all links from the page. |
| 260 if (links) { |
| 261 for (var i = 0; i != links.length; i++) |
| 262 childNames.push(links[i].match(/href="(.*)"/)[1]); |
| 263 } |
| 264 console.log( |
| 265 'Importing ' + childNames.length + ' entries from ' + srcDirUrl); |
| 266 processNextChild(); |
| 267 }); |
| 174 } | 268 } |
| 175 }; | 269 }; |
| OLD | NEW |