Chromium Code Reviews| 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 * @param {!Object.<string, string>} stringData String data. | 6 * Configuration of the Gallery window. |
| 7 * @param {!VolumeManager} volumeManager Volume manager. | 7 * @type {Object} |
| 8 * @constructor | |
| 9 * @struct | |
| 10 */ | 8 */ |
| 11 function BackgroundComponents(stringData, volumeManager) { | 9 var windowCreateOptions = { |
| 12 /** | 10 id: 'gallery', |
| 13 * String data. | 11 innerBounds: { |
| 14 * @type {!Object.<string, string>} | 12 minWidth: 820, |
| 15 */ | 13 minHeight: 554 |
| 16 this.stringData = stringData; | 14 }, |
| 17 | 15 frame: 'none' |
| 18 /** | |
| 19 * Volume manager. | |
| 20 * @type {!VolumeManager} | |
| 21 */ | |
| 22 this.volumeManager = volumeManager; | |
| 23 } | |
| 24 | |
| 25 /** | |
| 26 * Loads background component. | |
| 27 * @return {!Promise} Promise fulfilled with BackgroundComponents. | |
| 28 */ | |
| 29 BackgroundComponents.load = function() { | |
| 30 var stringDataPromise = new Promise(function(fulfill) { | |
| 31 chrome.fileManagerPrivate.getStrings(function(stringData) { | |
| 32 loadTimeData.data = stringData; | |
| 33 fulfill(stringData); | |
| 34 }); | |
| 35 }); | |
| 36 | |
| 37 // VolumeManager should be obtained after stringData initialized. | |
| 38 var volumeManagerPromise = stringDataPromise.then(function() { | |
| 39 return new Promise(function(fulfill) { | |
| 40 VolumeManager.getInstance(fulfill); | |
| 41 }); | |
| 42 }); | |
| 43 | |
| 44 return Promise.all([stringDataPromise, volumeManagerPromise]).then( | |
| 45 function(args) { | |
| 46 return new BackgroundComponents(args[0], args[1]); | |
| 47 }); | |
| 48 }; | 16 }; |
| 49 | 17 |
| 50 /** | 18 /** |
| 51 * Resolves file system names and obtains entries. | 19 * Backgound object. This is necessary for AppWindowWrapper. |
| 52 * @param {!Array.<!FileEntry>} entries Names of isolated file system. | 20 * @type {BackgroundBase} |
| 53 * @return {!Promise} Promise to be fulfilled with an entry array. | |
| 54 */ | 21 */ |
| 55 function resolveEntries(entries) { | 22 var background = new BackgroundBase(); |
| 56 return new Promise(function(fulfill, reject) { | 23 |
| 24 | |
| 25 // Initializes the strings. This needs for the volume manager. | |
| 26 var loadTimeDataPromise = new Promise(function(fulfill, reject) { | |
| 27 chrome.fileManagerPrivate.getStrings(function(stringData) { | |
| 28 loadTimeData.data = stringData; | |
| 29 fulfill(); | |
| 30 }); | |
| 31 }); | |
| 32 | |
| 33 // Initializes the volume manager. This needs for isolated entries. | |
| 34 var volumeManagerPromise = new Promise(function(fulfill, reject) { | |
| 35 VolumeManager.getInstance(fulfill); | |
| 36 }); | |
| 37 | |
| 38 /** | |
| 39 * Queue to serialize initialization. | |
| 40 * @type {AsyncUtil.Queue} | |
|
fukino
2015/02/16 04:16:38
nit: This annotation looks incorrect.
yoshiki
2015/02/16 07:35:55
Done.
yoshiki
2015/02/16 07:35:55
Done.
| |
| 41 */ | |
| 42 window.initializePromise = Promise.all([loadTimeDataPromise, | |
| 43 volumeManagerPromise]); | |
| 44 | |
| 45 // Registers the handlers. | |
| 46 chrome.app.runtime.onLaunched.addListener(onLaunched); | |
| 47 | |
| 48 /** | |
| 49 * Called when an app is launched. | |
| 50 * @param {Object} launchData Launch data. | |
| 51 */ | |
| 52 function onLaunched(launchData) { | |
|
fukino
2015/02/16 04:16:38
nit: Could you move inline comments from the previ
yoshiki
2015/02/16 07:35:55
Done.
| |
| 53 if (!launchData || !launchData.items || launchData.items.length == 0) | |
| 54 return; | |
| 55 | |
| 56 initializePromise.then(function() { | |
| 57 var isolatedEntries = launchData.items.map(function(item) { | |
| 58 return item.entry; | |
| 59 }); | |
| 60 | |
| 57 chrome.fileManagerPrivate.resolveIsolatedEntries( | 61 chrome.fileManagerPrivate.resolveIsolatedEntries( |
| 58 entries, function(externalEntries) { | 62 isolatedEntries, |
| 59 if (!chrome.runtime.lastError) | 63 function(externalEntries) { |
| 60 fulfill(externalEntries); | 64 var urls = util.entriesToURLs(externalEntries); |
| 61 else | 65 openGalleryWindow(urls, false); |
| 62 reject(chrome.runtime.lastError); | |
| 63 }); | 66 }); |
| 64 }); | 67 }); |
| 65 } | 68 } |
| 66 | 69 |
| 67 /** | 70 /** |
| 68 * Promise to be fulfilled with singleton instance of background components. | 71 * Returns a function to generate an ID for window. |
| 69 * @type {Promise} | 72 * @return {function():string} Function which returns an unique id. |
| 70 */ | 73 */ |
| 71 var backgroundComponentsPromise = null; | 74 var generateWindowId = (function() { |
| 75 var seq = 0; | |
| 76 return function() { | |
| 77 return 'GALLERY_' + seq++; | |
| 78 }; | |
| 79 })(); | |
| 72 | 80 |
| 73 /** | 81 /** |
| 74 * Promise to be fulfilled with single application window. | 82 * Opens gallery window. |
| 75 * This can be null when the window is not opened. | 83 * @param {Array.<string>} urls List of URL to show. |
| 76 * @type {Promise} | 84 * @param {boolean} reopen True if reopen, false otherwise. |
| 85 * @return {Promise} Promise to be fulfilled on success, or rejected on error. | |
| 77 */ | 86 */ |
| 78 var appWindowPromise = null; | 87 function openGalleryWindow(urls, reopen) { |
| 88 return new Promise(function(fulfill, reject) { | |
| 89 util.URLsToEntries(urls).then(function(result) { | |
| 90 fulfill(util.entriesToURLs(result.entries)); | |
| 91 }).catch(reject); | |
| 92 }).then(function(urls) { | |
| 93 if (urls.length === 0) | |
| 94 return Promise.reject('No file to open.'); | |
| 79 | 95 |
| 80 /** | 96 var windowId = generateWindowId(); |
| 81 * Promise to be fulfilled with entries that are used for reopening the | |
| 82 * application window. | |
| 83 * @type {Promise} | |
| 84 */ | |
| 85 var reopenEntriesPromise = null; | |
| 86 | 97 |
| 87 /** | 98 // Opens a window. |
| 88 * Launches the application with entries. | 99 return new Promise(function(fulfill, reject) { |
| 89 * | 100 var gallery = new AppWindowWrapper('gallery.html', |
| 90 * @param {!Promise} selectedEntriesPromise Promise to be fulfilled with the | 101 windowId, |
| 91 * entries that are stored in the external file system (not in the isolated | 102 windowCreateOptions); |
| 92 * file system). | 103 |
| 93 * @return {!Promise} Promise to be fulfilled after the application is launched. | 104 gallery.launch( |
| 94 */ | 105 {urls: urls}, |
| 95 function launch(selectedEntriesPromise) { | 106 reopen, |
| 96 // If there is the previous window, close the window. | 107 fulfill.bind(null, gallery)); |
| 97 if (appWindowPromise) { | 108 }).then(function(gallery) { |
| 98 reopenEntriesPromise = selectedEntriesPromise; | 109 var galleryDocument = gallery.rawAppWindow.contentWindow.document; |
| 99 appWindowPromise.then(function(appWindow) { | 110 if (galleryDocument.readyState == 'complete') |
| 100 appWindow.close(); | 111 return gallery; |
| 112 | |
| 113 return new Promise(function(fulfill, reject) { | |
| 114 galleryDocument.addEventListener( | |
| 115 'DOMContentLoaded', fulfill.bind(null, gallery)); | |
| 116 }); | |
| 101 }); | 117 }); |
| 102 return Promise.reject('The window has already opened.'); | 118 }).then(function(gallery) { |
| 103 } | 119 gallery.rawAppWindow.focus(); |
| 104 reopenEntriesPromise = null; | 120 return gallery.rawAppWindow; |
| 105 | 121 }).catch(function(error) { |
| 106 // Create a new window. | 122 console.error('Launch failed' + error.stack || error); |
| 107 appWindowPromise = new Promise(function(fulfill) { | 123 return Promise.reject(error); |
| 108 chrome.app.window.create( | |
| 109 'gallery.html', | |
| 110 { | |
| 111 id: 'gallery', | |
| 112 innerBounds: { | |
| 113 minWidth: 820, | |
| 114 minHeight: 544 | |
| 115 }, | |
| 116 frame: 'none' | |
| 117 }, | |
| 118 function(appWindow) { | |
| 119 appWindow.contentWindow.addEventListener( | |
| 120 'load', fulfill.bind(null, appWindow)); | |
| 121 appWindow.onClosed.addListener(function() { | |
| 122 appWindowPromise = null; | |
| 123 if (reopenEntriesPromise) { | |
| 124 // TODO(hirono): This is workaround for crbug.com/442217. Remove | |
| 125 // this after fixing it. | |
| 126 setTimeout(function() { | |
| 127 if (reopenEntriesPromise) | |
| 128 launch(reopenEntriesPromise); | |
| 129 }, 500); | |
| 130 } | |
| 131 }); | |
| 132 }); | |
| 133 }); | |
| 134 | |
| 135 // Initialize the window document. | |
| 136 return Promise.all([ | |
| 137 appWindowPromise, | |
| 138 backgroundComponentsPromise | |
| 139 ]).then(function(args) { | |
| 140 var appWindow = /** @type {!chrome.app.window.AppWindow} */ (args[0]); | |
| 141 var galleryWindow = /** @type {!GalleryWindow} */ (appWindow.contentWindow); | |
| 142 galleryWindow.initialize(args[1]); | |
| 143 return selectedEntriesPromise.then(function(entries) { | |
| 144 galleryWindow.loadEntries(entries); | |
| 145 }); | |
| 146 }); | 124 }); |
| 147 } | 125 } |
| 148 | 126 |
| 149 // If the script is loaded from unit test, chrome.app.runtime is not defined. | |
| 150 // In this case, does not run the initialization code for the application. | |
| 151 if (chrome.app.runtime) { | |
| 152 backgroundComponentsPromise = BackgroundComponents.load(); | |
| 153 chrome.app.runtime.onLaunched.addListener(function(launchData) { | |
| 154 // Skip if files are not selected. | |
| 155 if (!launchData || !launchData.items || launchData.items.length === 0) | |
| 156 return; | |
| 157 | |
| 158 // Obtains entries in non-isolated file systems. | |
| 159 // The entries in launchData are stored in the isolated file system. | |
| 160 // We need to map the isolated entries to the normal entries to retrieve | |
| 161 // their parent directory. | |
| 162 var isolatedEntries = launchData.items.map(function(item) { | |
| 163 return item.entry; | |
| 164 }); | |
| 165 var selectedEntriesPromise = backgroundComponentsPromise.then(function() { | |
| 166 return resolveEntries(isolatedEntries); | |
| 167 }); | |
| 168 | |
| 169 launch(selectedEntriesPromise).catch(function(error) { | |
| 170 console.error(error.stack || error); | |
| 171 }); | |
| 172 }); | |
| 173 } | |
| 174 | |
| 175 // If is is run in the browser test, wait for the test resources are installed | 127 // If is is run in the browser test, wait for the test resources are installed |
| 176 // as a component extension, and then load the test resources. | 128 // as a component extension, and then load the test resources. |
| 177 if (chrome.test) { | 129 if (chrome.test) { |
| 178 // Sets a global flag that we are in tests, so other components are aware of | 130 // Sets a global flag that we are in tests, so other components are aware of |
| 179 // it. | 131 // it. |
| 180 window.IN_TEST = true; | 132 window.IN_TEST = true; |
| 181 | 133 |
| 182 /** @type {string} */ | 134 /** @type {string} */ |
| 183 window.testExtensionId = 'ejhcmmdhhpdhhgmifplfmjobgegbibkn'; | 135 window.testExtensionId = 'ejhcmmdhhpdhhgmifplfmjobgegbibkn'; |
| 184 chrome.runtime.onMessageExternal.addListener(function(message) { | 136 chrome.runtime.onMessageExternal.addListener(function(message) { |
| 185 if (message.name !== 'testResourceLoaded') | 137 if (message.name !== 'testResourceLoaded') |
| 186 return; | 138 return; |
| 187 var script = document.createElement('script'); | 139 var script = document.createElement('script'); |
| 188 script.src = | 140 script.src = |
| 189 'chrome-extension://' + window.testExtensionId + | 141 'chrome-extension://' + window.testExtensionId + |
| 190 '/gallery/test_loader.js'; | 142 '/gallery/test_loader.js'; |
| 191 document.documentElement.appendChild(script); | 143 document.documentElement.appendChild(script); |
| 192 }); | 144 }); |
| 193 } | 145 } |
| OLD | NEW |