• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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'use strict';
6
7/**
8 * @param {Object.<string, string>} stringData String data.
9 * @param {VolumeManager} volumeManager Volume manager.
10 */
11function BackgroundComponents(stringData, volumeManager) {
12  /**
13   * String data.
14   * @type {Object.<string, string>}
15   */
16  this.stringData = stringData;
17
18  /**
19   * Volume manager.
20   * @type {VolumeManager}
21   */
22  this.volumeManager = volumeManager;
23
24  Object.freeze(this);
25}
26
27/**
28 * Loads background component.
29 * @return {Promise} Promise fulfilled with BackgroundComponents.
30 */
31BackgroundComponents.load = function() {
32  var stringDataPromise = new Promise(function(fulfill) {
33    chrome.fileBrowserPrivate.getStrings(function(stringData) {
34      loadTimeData.data = stringData;
35      fulfill(stringData);
36    });
37  });
38
39  // VolumeManager should be obtained after stringData initialized.
40  var volumeManagerPromise = stringDataPromise.then(function() {
41    return new Promise(function(fulfill) {
42      VolumeManager.getInstance(fulfill);
43    });
44  });
45
46  return Promise.all([stringDataPromise, volumeManagerPromise]).then(
47      function(args) {
48        return new BackgroundComponents(args[0], args[1]);
49      });
50};
51
52/**
53 * Promise to be fulfilled with singleton instance of background components.
54 * @type {Promise}
55 */
56var backgroundComponentsPromise = BackgroundComponents.load();
57
58/**
59 * Resolves file system names and obtains entries.
60 * @param {Array.<FileEntry>} entries Names of isolated file system.
61 * @return {Promise} Promise to be fulfilled with an entry array.
62 */
63function resolveEntries(entries) {
64  return new Promise(function(fulfill, reject) {
65    chrome.fileBrowserPrivate.resolveIsolatedEntries(entries,
66                                                     function(externalEntries) {
67      if (!chrome.runtime.lastError)
68        fulfill(externalEntries);
69      else
70        reject(chrome.runtime.lastError);
71    });
72  });
73}
74
75/**
76 * Obtains child entries.
77 * @param {DirectoryEntry} entry Directory entry.
78 * @return {Promise} Promise to be fulfilled with child entries.
79 */
80function getChildren(entry) {
81  var reader = entry.createReader();
82  var readEntries = function() {
83    return new Promise(reader.readEntries.bind(reader)).then(function(entries) {
84      if (entries.length === 0)
85        return [];
86      return readEntries().then(function(nextEntries) {
87        return entries.concat(nextEntries);
88      });
89    });
90  };
91  return readEntries().then(function(entries) {
92    return entries.sort(function(a, b) {
93      return a.name.localeCompare(b.name);
94    });
95  });
96}
97
98/**
99 * Promise to be fulfilled with single application window.
100 * @type {Promise}
101 */
102var appWindowPromise = Promise.resolve(null);
103
104/**
105 * Promise to be fulfilled with the current window is closed.
106 * @type {Promise}
107 */
108var closingPromise = Promise.resolve(null);
109
110/**
111 * Launches the application with entries.
112 *
113 * @param {Promise} selectedEntriesPromise Promise to be fulfilled with the
114 *     entries that are stored in the exteranl file system (not in the isolated
115 *     file system).
116 */
117function launch(selectedEntriesPromise) {
118  // If there is the previous window, close the window.
119  appWindowPromise = appWindowPromise.then(function(appWindow) {
120    if (appWindow) {
121      appWindow.close();
122      return closingPromise;
123    }
124  });
125
126  // Create a new window.
127  appWindowPromise = appWindowPromise.then(function() {
128    return new Promise(function(fulfill) {
129      chrome.app.window.create(
130          'gallery.html',
131          {
132            id: 'gallery',
133            innerBounds: {
134              minWidth: 800,
135              minHeight: 300
136            },
137            frame: 'none'
138          },
139          function(appWindow) {
140            appWindow.contentWindow.addEventListener(
141                'load', fulfill.bind(null, appWindow));
142            closingPromise = new Promise(function(fulfill) {
143              appWindow.onClosed.addListener(fulfill);
144            });
145          });
146    });
147  });
148
149  // Initialize the window document.
150  appWindowPromise = Promise.all([
151    appWindowPromise,
152    backgroundComponentsPromise,
153  ]).then(function(args) {
154    args[0].contentWindow.initialize(args[1]);
155    return args[0];
156  });
157
158
159  // If only 1 entry is selected, retrieve entries in the same directory.
160  // Otherwise, just use the selectedEntries as an entry set.
161  var allEntriesPromise = selectedEntriesPromise.then(function(entries) {
162    if (entries.length === 1) {
163      var parentPromise = new Promise(entries[0].getParent.bind(entries[0]));
164      return parentPromise.then(getChildren).then(function(entries) {
165        return entries.filter(FileType.isImage);
166      });
167    } else {
168      return entries;
169    }
170  });
171
172  // Open entries.
173  return Promise.all([
174    appWindowPromise,
175    allEntriesPromise,
176    selectedEntriesPromise
177  ]).then(function(args) {
178    args[0].contentWindow.loadEntries(args[1], args[2]);
179  });
180}
181
182chrome.app.runtime.onLaunched.addListener(function(launchData) {
183  // Skip if files are not selected.
184  if (!launchData || !launchData.items || launchData.items.length === 0)
185    return;
186
187  // Obtains entries in non-isolated file systems.
188  // The entries in launchData are stored in the isolated file system.
189  // We need to map the isolated entries to the normal entries to retrieve their
190  // parent directory.
191  var isolatedEntries = launchData.items.map(function(item) {
192    return item.entry;
193  });
194  var selectedEntriesPromise = backgroundComponentsPromise.then(function() {
195    return resolveEntries(isolatedEntries);
196  });
197
198  launch(selectedEntriesPromise).catch(function(error) {
199    console.error(error.stack || error);
200  });
201});
202
203// If is is run in the browser test, wait for the test resources are installed
204// as a component extension, and then load the test resources.
205if (chrome.test) {
206  chrome.runtime.onMessageExternal.addListener(function(message) {
207    if (message.name !== 'testResourceLoaded')
208      return;
209    var script = document.createElement('script');
210    script.src =
211        'chrome-extension://ejhcmmdhhpdhhgmifplfmjobgegbibkn' +
212        '/gallery/test_loader.js';
213    document.documentElement.appendChild(script);
214  });
215}
216