Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / renderer / resources / extensions / file_system_custom_bindings.js
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.
4
5 // Custom binding for the fileSystem API.
6
7 var binding = require('binding').Binding.create('fileSystem');
8
9 var fileSystemNatives = requireNative('file_system_natives');
10 var GetIsolatedFileSystem = fileSystemNatives.GetIsolatedFileSystem;
11 var lastError = require('lastError');
12 var sendRequest = require('sendRequest');
13 var GetModuleSystem = requireNative('v8_context').GetModuleSystem;
14 // TODO(sammc): Don't require extension. See http://crbug.com/235689.
15 var GetExtensionViews = requireNative('runtime').GetExtensionViews;
16
17 // Fallback to using the current window if no background page is running.
18 var backgroundPage = GetExtensionViews(-1, 'BACKGROUND')[0] || window;
19 var backgroundPageModuleSystem = GetModuleSystem(backgroundPage);
20
21 // All windows use the bindFileEntryCallback from the background page so their
22 // FileEntry objects have the background page's context as their own. This
23 // allows them to be used from other windows (including the background page)
24 // after the original window is closed.
25 if (window == backgroundPage) {
26   var bindFileEntryCallback = function(functionName, apiFunctions) {
27     apiFunctions.setCustomCallback(functionName,
28         function(name, request, response) {
29       if (request.callback && response) {
30         var callback = request.callback;
31         request.callback = null;
32
33         var entries = [];
34         var hasError = false;
35
36         var getEntryError = function(fileError) {
37           if (!hasError) {
38             hasError = true;
39             lastError.run(
40                 'fileSystem.' + functionName,
41                 'Error getting fileEntry, code: ' + fileError.code,
42                 request.stack,
43                 callback);
44           }
45         }
46
47         // Loop through the response entries and asynchronously get the
48         // FileEntry for each. We use hasError to ensure that only the first
49         // error is reported. Note that an error can occur either during the
50         // loop or in the asynchronous error callback to getFile.
51         $Array.forEach(response.entries, function(entry) {
52           if (hasError)
53             return;
54           var fileSystemId = entry.fileSystemId;
55           var baseName = entry.baseName;
56           var id = entry.id;
57           var fs = GetIsolatedFileSystem(fileSystemId);
58
59           try {
60             var getEntryCallback = function(fileEntry) {
61               if (hasError)
62                 return;
63               entryIdManager.registerEntry(id, fileEntry);
64               entries.push(fileEntry);
65               // Once all entries are ready, pass them to the callback. In the
66               // event of an error, this condition will never be satisfied so
67               // the callback will not be called with any entries.
68               if (entries.length == response.entries.length) {
69                 if (response.multiple) {
70                   sendRequest.safeCallbackApply(
71                       'fileSystem.' + functionName, request, callback,
72                       [entries]);
73                 } else {
74                   sendRequest.safeCallbackApply(
75                       'fileSystem.' + functionName, request, callback,
76                       [entries[0]]);
77                 }
78               }
79             }
80             // TODO(koz): fs.root.getFile() makes a trip to the browser process,
81             // but it might be possible avoid that by calling
82             // WebFrame::createFileEntry().
83             if (entry.isDirectory) {
84               fs.root.getDirectory(baseName, {}, getEntryCallback,
85                                    getEntryError);
86             } else {
87               fs.root.getFile(baseName, {}, getEntryCallback, getEntryError);
88             }
89           } catch (e) {
90             if (!hasError) {
91               hasError = true;
92               lastError.run('fileSystem.' + functionName,
93                             'Error getting fileEntry: ' + e.stack,
94                             request.stack,
95                             callback);
96             }
97           }
98         });
99       }
100     });
101   };
102   var entryIdManager = require('entryIdManager');
103 } else {
104   // Force the fileSystem API to be loaded in the background page. Using
105   // backgroundPageModuleSystem.require('fileSystem') is insufficient as
106   // requireNative is only allowed while lazily loading an API.
107   backgroundPage.chrome.fileSystem;
108   var bindFileEntryCallback = backgroundPageModuleSystem.require(
109       'fileSystem').bindFileEntryCallback;
110   var entryIdManager = backgroundPageModuleSystem.require('entryIdManager');
111 }
112
113 binding.registerCustomHook(function(bindingsAPI) {
114   var apiFunctions = bindingsAPI.apiFunctions;
115   var fileSystem = bindingsAPI.compiledApi;
116
117   function bindFileEntryFunction(functionName) {
118     apiFunctions.setUpdateArgumentsPostValidate(
119         functionName, function(fileEntry, callback) {
120       var fileSystemName = fileEntry.filesystem.name;
121       var relativePath = $String.slice(fileEntry.fullPath, 1);
122       return [fileSystemName, relativePath, callback];
123     });
124   }
125   $Array.forEach(['getDisplayPath', 'getWritableEntry', 'isWritableEntry'],
126                   bindFileEntryFunction);
127
128   $Array.forEach(['getWritableEntry', 'chooseEntry', 'restoreEntry'],
129                   function(functionName) {
130     bindFileEntryCallback(functionName, apiFunctions);
131   });
132
133   apiFunctions.setHandleRequest('retainEntry', function(fileEntry) {
134     var id = entryIdManager.getEntryId(fileEntry);
135     if (!id)
136       return '';
137     var fileSystemName = fileEntry.filesystem.name;
138     var relativePath = $String.slice(fileEntry.fullPath, 1);
139
140     sendRequest.sendRequest(this.name, [id, fileSystemName, relativePath],
141       this.definition.parameters, {});
142     return id;
143   });
144
145   apiFunctions.setHandleRequest('isRestorable',
146       function(id, callback) {
147     var savedEntry = entryIdManager.getEntryById(id);
148     if (savedEntry) {
149       sendRequest.safeCallbackApply(
150           'fileSystem.isRestorable',
151           {'stack': sendRequest.getExtensionStackTrace()},
152           callback,
153           [true]);
154     } else {
155       sendRequest.sendRequest(
156           this.name, [id, callback], this.definition.parameters, {});
157     }
158   });
159
160   apiFunctions.setUpdateArgumentsPostValidate('restoreEntry',
161       function(id, callback) {
162     var savedEntry = entryIdManager.getEntryById(id);
163     if (savedEntry) {
164       // We already have a file entry for this id so pass it to the callback and
165       // send a request to the browser to move it to the back of the LRU.
166       sendRequest.safeCallbackApply(
167           'fileSystem.restoreEntry',
168           {'stack': sendRequest.getExtensionStackTrace()},
169           callback,
170           [savedEntry]);
171       return [id, false, null];
172     } else {
173       // Ask the browser process for a new file entry for this id, to be passed
174       // to |callback|.
175       return [id, true, callback];
176     }
177   });
178
179   // TODO(benwells): Remove these deprecated versions of the functions.
180   fileSystem.getWritableFileEntry = function() {
181     console.log("chrome.fileSystem.getWritableFileEntry is deprecated");
182     console.log("Please use chrome.fileSystem.getWritableEntry instead");
183     $Function.apply(fileSystem.getWritableEntry, this, arguments);
184   };
185
186   fileSystem.isWritableFileEntry = function() {
187     console.log("chrome.fileSystem.isWritableFileEntry is deprecated");
188     console.log("Please use chrome.fileSystem.isWritableEntry instead");
189     $Function.apply(fileSystem.isWritableEntry, this, arguments);
190   };
191
192   fileSystem.chooseFile = function() {
193     console.log("chrome.fileSystem.chooseFile is deprecated");
194     console.log("Please use chrome.fileSystem.chooseEntry instead");
195     $Function.apply(fileSystem.chooseEntry, this, arguments);
196   };
197 });
198
199 exports.bindFileEntryCallback = bindFileEntryCallback;
200 exports.binding = binding.generate();