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 /** | 5 /** |
6 * FileManager constructor. | 6 * FileManager constructor. |
7 * | 7 * |
8 * FileManager objects encapsulate the functionality of the file selector | 8 * FileManager objects encapsulate the functionality of the file selector |
9 * dialogs, as well as the full screen file manager application (though the | 9 * dialogs, as well as the full screen file manager application (though the |
10 * latter is not yet implemented). | 10 * latter is not yet implemented). |
(...skipping 11 matching lines...) Expand all Loading... |
22 | 22 |
23 this.listType_ = null; | 23 this.listType_ = null; |
24 | 24 |
25 this.selection = null; | 25 this.selection = null; |
26 | 26 |
27 this.butterTimer_ = null; | 27 this.butterTimer_ = null; |
28 this.currentButter_ = null; | 28 this.currentButter_ = null; |
29 this.butterLastShowTime_ = 0; | 29 this.butterLastShowTime_ = 0; |
30 | 30 |
31 this.watchedDirectoryUrl_ = null; | 31 this.watchedDirectoryUrl_ = null; |
32 this.metadataObserverId_ = null; | 32 this.filesystemObserverId_ = null; |
| 33 this.gdataObserverId_ = null; |
33 | 34 |
34 this.commands_ = {}; | 35 this.commands_ = {}; |
35 | 36 |
36 this.thumbnailUrlCache_ = {}; | 37 this.thumbnailUrlCache_ = {}; |
37 | 38 |
38 this.document_ = dialogDom.ownerDocument; | 39 this.document_ = dialogDom.ownerDocument; |
39 this.dialogType_ = this.params_.type || FileManager.DialogType.FULL_PAGE; | 40 this.dialogType_ = this.params_.type || FileManager.DialogType.FULL_PAGE; |
40 | 41 |
41 metrics.recordEnum('Create', this.dialogType_, | 42 metrics.recordEnum('Create', this.dialogType_, |
42 [FileManager.DialogType.SELECT_FOLDER, | 43 [FileManager.DialogType.SELECT_FOLDER, |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 * | 179 * |
179 * @param {string} path The file path. | 180 * @param {string} path The file path. |
180 */ | 181 */ |
181 function normalizeAbsolutePath(x) { | 182 function normalizeAbsolutePath(x) { |
182 if (x[0] == '/') | 183 if (x[0] == '/') |
183 return x.slice(1); | 184 return x.slice(1); |
184 else | 185 else |
185 return x; | 186 return x; |
186 } | 187 } |
187 | 188 |
188 | |
189 /** | |
190 * Call an asynchronous method on dirEntry, batching multiple callers. | |
191 * | |
192 * This batches multiple callers into a single invocation, calling all | |
193 * interested parties back when the async call completes. | |
194 * | |
195 * The Entry method to be invoked should take two callbacks as parameters | |
196 * (one for success and one for failure), and it should invoke those | |
197 * callbacks with a single parameter representing the result of the call. | |
198 * Example methods are Entry.getMetadata() and FileEntry.file(). | |
199 * | |
200 * Warning: Because this method caches the first result, subsequent changes | |
201 * to the entry will not be visible to callers. | |
202 * | |
203 * Error results are never cached. | |
204 * | |
205 * @param {DirectoryEntry} dirEntry The DirectoryEntry to apply the method | |
206 * to. | |
207 * @param {string} methodName The name of the method to dispatch. | |
208 * @param {function(*)} successCallback The function to invoke if the method | |
209 * succeeds. The result of the method will be the one parameter to this | |
210 * callback. | |
211 * @param {function(*)} opt_errorCallback The function to invoke if the | |
212 * method fails. The result of the method will be the one parameter to | |
213 * this callback. If not provided, the default errorCallback will throw | |
214 * an exception. | |
215 */ | |
216 function batchAsyncCall(entry, methodName, successCallback, | |
217 opt_errorCallback) { | |
218 var resultCache = methodName + '_resultCache_'; | |
219 | |
220 if (entry[resultCache]) { | |
221 // The result cache for this method already exists. Just invoke the | |
222 // successCallback with the result of the previuos call. | |
223 // Callback via a setTimeout so the sync/async semantics don't change | |
224 // based on whether or not the value is cached. | |
225 setTimeout(function() { successCallback(entry[resultCache]) }, 0); | |
226 return; | |
227 } | |
228 | |
229 if (!opt_errorCallback) { | |
230 opt_errorCallback = util.ferr('Error calling ' + methodName + ' for: ' + | |
231 entry.fullPath); | |
232 } | |
233 | |
234 var observerList = methodName + '_observers_'; | |
235 | |
236 if (entry[observerList]) { | |
237 // The observer list already exists, indicating we have a pending call | |
238 // out to this method. Add this caller to the list of observers and | |
239 // bail out. | |
240 entry[observerList].push([successCallback, opt_errorCallback]); | |
241 return; | |
242 } | |
243 | |
244 entry[observerList] = [[successCallback, opt_errorCallback]]; | |
245 | |
246 function onComplete(success, result) { | |
247 if (success) | |
248 entry[resultCache] = result; | |
249 | |
250 for (var i = 0; i < entry[observerList].length; i++) { | |
251 entry[observerList][i][success ? 0 : 1](result); | |
252 } | |
253 | |
254 delete entry[observerList]; | |
255 }; | |
256 | |
257 entry[methodName](function(rv) { onComplete(true, rv) }, | |
258 function(rv) { onComplete(false, rv) }); | |
259 } | |
260 | |
261 /** | |
262 * Invoke callback in sync/async manner. | |
263 * @param {function(*)?} callback The callback. If null, nothing is called. | |
264 * @param {boolean} sync True iff the callback should be called synchronously. | |
265 * @param {*} callback_args... The rest are callback arguments. | |
266 */ | |
267 function invokeCallback(callback, sync, callback_args) { | |
268 if (!callback) | |
269 return; | |
270 var args = Array.prototype.slice.call(arguments, 2); | |
271 if (sync) { | |
272 callback.apply(null, args); | |
273 } else { | |
274 setTimeout(function() { callback.apply(null, args); }, 0); | |
275 } | |
276 } | |
277 | |
278 function cacheGDataProps(entry, successCallback, | |
279 opt_errorCallback, opt_sync) { | |
280 if ('gdata_' in entry) { | |
281 invokeCallback(successCallback, !!opt_sync, entry); | |
282 return; | |
283 } | |
284 | |
285 entry.getGDataFileProperties = entry.getGDataFileProperties || | |
286 function(callback) { | |
287 var queue = cacheGDataProps.queue_; | |
288 queue.callbacks.push(callback); | |
289 queue.urls.push(entry.toURL()); | |
290 if (!queue.scheduled) { | |
291 queue.scheduled = true; | |
292 setTimeout(function() { | |
293 queue.scheduled = false; | |
294 var callbacks = queue.callbacks; | |
295 var urls = queue.urls; | |
296 chrome.fileBrowserPrivate.getGDataFileProperties(urls, | |
297 function(props) { | |
298 for (var i = 0; i < callbacks.length; i++) { | |
299 callbacks[i](props[i]); | |
300 } | |
301 }); | |
302 queue.callbacks = []; | |
303 queue.urls = []; | |
304 }, 0); | |
305 } | |
306 }; | |
307 | |
308 batchAsyncCall(entry, 'getGDataFileProperties', function(props) { | |
309 entry.gdata_ = props; | |
310 if (successCallback) | |
311 successCallback(entry); | |
312 }, opt_errorCallback); | |
313 } | |
314 | |
315 cacheGDataProps.queue_ = { | |
316 callbacks: [], | |
317 urls: [], | |
318 scheduled: false | |
319 }; | |
320 | |
321 function removeChildren(element) { | 189 function removeChildren(element) { |
322 element.textContent = ''; | 190 element.textContent = ''; |
323 } | 191 } |
324 | 192 |
325 // Public statics. | 193 // Public statics. |
326 | 194 |
327 /** | 195 /** |
328 * List of dialog types. | 196 * List of dialog types. |
329 * | 197 * |
330 * Keep this in sync with FileManagerDialog::GetDialogTypeAsString, except | 198 * Keep this in sync with FileManagerDialog::GetDialogTypeAsString, except |
(...skipping 878 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1209 cr.ui.contextMenuHandler.setContextMenu(this.grid_, this.fileContextMenu_); | 1077 cr.ui.contextMenuHandler.setContextMenu(this.grid_, this.fileContextMenu_); |
1210 }; | 1078 }; |
1211 | 1079 |
1212 /** | 1080 /** |
1213 * Initialize the file list table. | 1081 * Initialize the file list table. |
1214 */ | 1082 */ |
1215 FileManager.prototype.initTable_ = function() { | 1083 FileManager.prototype.initTable_ = function() { |
1216 var renderFunction = this.table_.getRenderFunction(); | 1084 var renderFunction = this.table_.getRenderFunction(); |
1217 this.table_.setRenderFunction(function(entry, parent) { | 1085 this.table_.setRenderFunction(function(entry, parent) { |
1218 var item = renderFunction(entry, parent); | 1086 var item = renderFunction(entry, parent); |
1219 this.styleGDataItem_(entry, item); | 1087 this.displayGDataStyleInItem_( |
| 1088 item, entry, this.metadataCache_.getCached(entry, 'gdata')); |
1220 return item; | 1089 return item; |
1221 }.bind(this)); | 1090 }.bind(this)); |
1222 | 1091 |
1223 var fullPage = (this.dialogType_ == FileManager.DialogType.FULL_PAGE); | 1092 var fullPage = (this.dialogType_ == FileManager.DialogType.FULL_PAGE); |
1224 | 1093 |
1225 var columns = [ | 1094 var columns = [ |
1226 new cr.ui.table.TableColumn('name', str('NAME_COLUMN_LABEL'), | 1095 new cr.ui.table.TableColumn('name', str('NAME_COLUMN_LABEL'), |
1227 fullPage ? 64 : 324), | 1096 fullPage ? 64 : 324), |
1228 new cr.ui.table.TableColumn('size', str('SIZE_COLUMN_LABEL'), | 1097 new cr.ui.table.TableColumn('size', str('SIZE_COLUMN_LABEL'), |
1229 fullPage ? 15.5 : 92, true), | 1098 fullPage ? 15.5 : 92, true), |
(...skipping 537 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1767 }; | 1636 }; |
1768 | 1637 |
1769 FileManager.prototype.decorateThumbnail_ = function(li, entry) { | 1638 FileManager.prototype.decorateThumbnail_ = function(li, entry) { |
1770 li.className = 'thumbnail-item'; | 1639 li.className = 'thumbnail-item'; |
1771 | 1640 |
1772 if (this.showCheckboxes_) | 1641 if (this.showCheckboxes_) |
1773 li.appendChild(this.renderSelectionCheckbox_(entry)); | 1642 li.appendChild(this.renderSelectionCheckbox_(entry)); |
1774 | 1643 |
1775 li.appendChild(this.renderThumbnailBox_(entry, false)); | 1644 li.appendChild(this.renderThumbnailBox_(entry, false)); |
1776 li.appendChild(this.renderFileNameLabel_(entry)); | 1645 li.appendChild(this.renderFileNameLabel_(entry)); |
1777 this.styleGDataItem_(entry, li); | 1646 this.displayGDataStyleInItem_( |
| 1647 li, entry, this.metadataCache_.getCached(entry, 'gdata')); |
1778 }; | 1648 }; |
1779 | 1649 |
1780 /** | 1650 /** |
1781 * Render the type column of the detail table. | 1651 * Render the type column of the detail table. |
1782 * | 1652 * |
1783 * Invoked by cr.ui.Table when a file needs to be rendered. | 1653 * Invoked by cr.ui.Table when a file needs to be rendered. |
1784 * | 1654 * |
1785 * @param {Entry} entry The Entry object to render. | 1655 * @param {Entry} entry The Entry object to render. |
1786 * @param {string} columnId The id of the column to be rendered. | 1656 * @param {string} columnId The id of the column to be rendered. |
1787 * @param {cr.ui.Table} table The table doing the rendering. | 1657 * @param {cr.ui.Table} table The table doing the rendering. |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1888 /** | 1758 /** |
1889 * Unmounts device. | 1759 * Unmounts device. |
1890 * @param {Entry} entry The entry to unmount. | 1760 * @param {Entry} entry The entry to unmount. |
1891 */ | 1761 */ |
1892 FileManager.prototype.unmountVolume_ = function(entry) { | 1762 FileManager.prototype.unmountVolume_ = function(entry) { |
1893 this.directoryModel_.prepareUnmount(entry.fullPath); | 1763 this.directoryModel_.prepareUnmount(entry.fullPath); |
1894 this.unmountRequests_.push(entry.fullPath); | 1764 this.unmountRequests_.push(entry.fullPath); |
1895 chrome.fileBrowserPrivate.removeMount(entry.toURL()); | 1765 chrome.fileBrowserPrivate.removeMount(entry.toURL()); |
1896 }; | 1766 }; |
1897 | 1767 |
1898 FileManager.prototype.styleGDataItem_ = function(entry, listItem) { | 1768 FileManager.prototype.displayGDataStyleInItem_ = function( |
1899 if (!this.isOnGData()) | 1769 listItem, entry, gdata) { |
| 1770 if (!this.isOnGData() || !gdata) |
1900 return; | 1771 return; |
1901 | 1772 |
1902 cacheGDataProps(entry, function(entry) { | 1773 if (gdata.hosted) { |
1903 if (!entry.gdata_) | 1774 listItem.classList.add('gdata-hosted'); |
1904 return; | 1775 } |
1905 | 1776 if (entry.isDirectory || gdata.availableOffline) { |
1906 if (entry.gdata_.isHosted) { | 1777 listItem.classList.add('gdata-present'); |
1907 listItem.classList.add('gdata-hosted'); | 1778 } |
1908 } | |
1909 if (entry.isDirectory || FileManager.isAvaliableOffline_(entry.gdata_)) { | |
1910 listItem.classList.add('gdata-present'); | |
1911 } | |
1912 }.bind(this)); | |
1913 }; | 1779 }; |
1914 | 1780 |
1915 /** | 1781 /** |
1916 * Render the Name column of the detail table. | 1782 * Render the Name column of the detail table. |
1917 * | 1783 * |
1918 * Invoked by cr.ui.Table when a file needs to be rendered. | 1784 * Invoked by cr.ui.Table when a file needs to be rendered. |
1919 * | 1785 * |
1920 * @param {Entry} entry The Entry object to render. | 1786 * @param {Entry} entry The Entry object to render. |
1921 * @param {string} columnId The id of the column to be rendered. | 1787 * @param {string} columnId The id of the column to be rendered. |
1922 * @param {cr.ui.Table} table The table doing the rendering. | 1788 * @param {cr.ui.Table} table The table doing the rendering. |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2055 var div = doc.createElement('div'); | 1921 var div = doc.createElement('div'); |
2056 div.className = 'offline'; | 1922 div.className = 'offline'; |
2057 | 1923 |
2058 if (entry.isDirectory) | 1924 if (entry.isDirectory) |
2059 return div; | 1925 return div; |
2060 | 1926 |
2061 var checkbox = this.renderCheckbox_(); | 1927 var checkbox = this.renderCheckbox_(); |
2062 checkbox.classList.add('pin'); | 1928 checkbox.classList.add('pin'); |
2063 checkbox.addEventListener('click', | 1929 checkbox.addEventListener('click', |
2064 this.onPinClick_.bind(this, checkbox, entry)); | 1930 this.onPinClick_.bind(this, checkbox, entry)); |
| 1931 checkbox.style.display = 'none'; |
| 1932 div.appendChild(checkbox); |
2065 | 1933 |
2066 if (this.isOnGData()) { | 1934 if (this.isOnGData()) { |
2067 cacheGDataProps(entry, function(entry) { | 1935 this.displayOfflineInDiv_( |
2068 if (entry.gdata_.isHosted) | 1936 div, this.metadataCache_.getCached(entry, 'gdata')); |
2069 return; | |
2070 checkbox.checked = entry.gdata_.isPinned; | |
2071 div.appendChild(checkbox); | |
2072 }); | |
2073 } | 1937 } |
2074 return div; | 1938 return div; |
2075 }; | 1939 }; |
2076 | 1940 |
| 1941 FileManager.prototype.displayOfflineInDiv_ = function(div, gdata) { |
| 1942 if (!gdata) return; |
| 1943 if (gdata.hosted) return; |
| 1944 var checkbox = div.querySelector('.pin'); |
| 1945 if (!checkbox) return; |
| 1946 checkbox.style.display = ''; |
| 1947 checkbox.checked = gdata.pinned; |
| 1948 }; |
| 1949 |
2077 FileManager.prototype.refreshCurrentDirectoryMetadata_ = function() { | 1950 FileManager.prototype.refreshCurrentDirectoryMetadata_ = function() { |
2078 var entries = this.directoryModel_.getFileList().slice(); | 1951 var entries = this.directoryModel_.getFileList().slice(); |
2079 this.metadataCache_.clear(entries, 'filesystem'); | |
2080 // We don't pass callback here. When new metadata arrives, we have an | 1952 // We don't pass callback here. When new metadata arrives, we have an |
2081 // observer registered to update the UI. | 1953 // observer registered to update the UI. |
| 1954 |
| 1955 this.metadataCache_.clear(entries, 'filesystem'); |
2082 this.metadataCache_.get(entries, 'filesystem', null); | 1956 this.metadataCache_.get(entries, 'filesystem', null); |
| 1957 if (this.isOnGData()) { |
| 1958 this.metadataCache_.clear(entries, 'gdata'); |
| 1959 this.metadataCache_.get(entries, 'gdata', null); |
| 1960 } |
2083 }; | 1961 }; |
2084 | 1962 |
2085 FileManager.prototype.updateFilesystemPropertiesInUI_ = function( | 1963 FileManager.prototype.updateMetadataInUI_ = function( |
2086 urls, properties) { | 1964 type, urls, properties) { |
2087 if (this.listType_ != FileManager.ListType.DETAIL) return; | 1965 if (this.listType_ != FileManager.ListType.DETAIL) return; |
2088 | 1966 |
2089 var items = {}; | 1967 var items = {}; |
| 1968 var entries = {}; |
2090 var dm = this.directoryModel_.getFileList(); | 1969 var dm = this.directoryModel_.getFileList(); |
2091 for (var index = 0; index < dm.length; index++) { | 1970 for (var index = 0; index < dm.length; index++) { |
2092 var listItem = this.currentList_.getListItemByIndex(index); | 1971 var listItem = this.currentList_.getListItemByIndex(index); |
2093 if (!listItem) continue; | 1972 if (!listItem) continue; |
2094 var entry = dm.item(index); | 1973 var entry = dm.item(index); |
2095 items[entry.toURL()] = listItem; | 1974 var url = entry.toURL(); |
| 1975 items[url] = listItem; |
| 1976 entries[url] = entry; |
2096 } | 1977 } |
2097 | 1978 |
2098 for (var index = 0; index < urls.length; index++) { | 1979 for (var index = 0; index < urls.length; index++) { |
2099 var url = urls[index]; | 1980 var url = urls[index]; |
2100 if (!(url in items)) continue; | 1981 if (!(url in items)) continue; |
2101 var listItem = items[url]; | 1982 var listItem = items[url]; |
| 1983 var entry = entries[url]; |
2102 var props = properties[index]; | 1984 var props = properties[index]; |
2103 this.displayDateInDiv_(listItem.querySelector('.date'), props); | 1985 if (type == 'filesystem') { |
2104 this.displaySizeInDiv_(listItem.querySelector('.size'), props); | 1986 this.displayDateInDiv_(listItem.querySelector('.date'), props); |
2105 this.displayTypeInDiv_(listItem.querySelector('.type'), props); | 1987 this.displaySizeInDiv_(listItem.querySelector('.size'), props); |
| 1988 this.displayTypeInDiv_(listItem.querySelector('.type'), props); |
| 1989 } else if (type == 'gdata') { |
| 1990 this.displayOfflineInDiv_(listItem.querySelector('.offline'), props); |
| 1991 this.displayGDataStyleInItem_(listItem, entry, props); |
| 1992 } |
2106 } | 1993 } |
2107 }; | 1994 }; |
2108 | 1995 |
2109 /** | 1996 /** |
2110 * Restore the item which is being renamed while refreshing the file list. Do | 1997 * Restore the item which is being renamed while refreshing the file list. Do |
2111 * nothing if no item is being renamed or such an item disappeared. | 1998 * nothing if no item is being renamed or such an item disappeared. |
2112 * | 1999 * |
2113 * While refreshing file list it gets repopulated with new file entries. | 2000 * While refreshing file list it gets repopulated with new file entries. |
2114 * There is not a big difference wether DOM items stay the same or not. | 2001 * There is not a big difference wether DOM items stay the same or not. |
2115 * Except for the item that the user is renaming. | 2002 * Except for the item that the user is renaming. |
(...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2569 // For internal tasks we do not listen to the event to avoid | 2456 // For internal tasks we do not listen to the event to avoid |
2570 // handling the same task instance from multiple tabs. | 2457 // handling the same task instance from multiple tabs. |
2571 // So, we manually execute the task. | 2458 // So, we manually execute the task. |
2572 this.onFileTaskExecute_(task_parts[1], urls); | 2459 this.onFileTaskExecute_(task_parts[1], urls); |
2573 } | 2460 } |
2574 }.bind(this)); | 2461 }.bind(this)); |
2575 }; | 2462 }; |
2576 | 2463 |
2577 FileManager.prototype.executeIfAvailable_ = function(urls, callback) { | 2464 FileManager.prototype.executeIfAvailable_ = function(urls, callback) { |
2578 if (this.isOnGDataOffline()) { | 2465 if (this.isOnGDataOffline()) { |
2579 chrome.fileBrowserPrivate.getGDataFileProperties(urls, function(props) { | 2466 this.metadataCache_.get(urls, 'gdata', function(props) { |
2580 for (var i = 0; i != props.length; i++) { | 2467 for (var i = 0; i != props.length; i++) { |
2581 if (!FileManager.isAvaliableOffline_(props[i])) { | 2468 if (!props[i].availableOffline) { |
2582 this.alert.showHtml( | 2469 this.alert.showHtml( |
2583 str('OFFLINE_HEADER'), | 2470 str('OFFLINE_HEADER'), |
2584 strf( | 2471 strf( |
2585 urls.length == 1 ? | 2472 urls.length == 1 ? |
2586 'OFFLINE_MESSAGE' : | 2473 'OFFLINE_MESSAGE' : |
2587 'OFFLINE_MESSAGE_PLURAL', | 2474 'OFFLINE_MESSAGE_PLURAL', |
2588 str('OFFLINE_COLUMN_LABEL'))); | 2475 str('OFFLINE_COLUMN_LABEL'))); |
2589 return; | 2476 return; |
2590 } | 2477 } |
2591 } | 2478 } |
2592 callback(urls); | 2479 callback(urls); |
2593 }.bind(this)); | 2480 }.bind(this)); |
2594 } else { | 2481 } else { |
2595 callback(urls); | 2482 callback(urls); |
2596 } | 2483 } |
2597 }; | 2484 }; |
2598 | 2485 |
2599 FileManager.isAvaliableOffline_ = function(gdata) { | |
2600 return gdata.isPresent && !gdata.isHosted; | |
2601 }; | |
2602 | |
2603 FileManager.prototype.isOffline = function() { | 2486 FileManager.prototype.isOffline = function() { |
2604 return !navigator.onLine; | 2487 return !navigator.onLine; |
2605 }; | 2488 }; |
2606 | 2489 |
2607 FileManager.prototype.onOnlineOffline_ = function() { | 2490 FileManager.prototype.onOnlineOffline_ = function() { |
2608 if (this.isOffline()) { | 2491 if (this.isOffline()) { |
2609 console.log('OFFLINE'); | 2492 console.log('OFFLINE'); |
2610 this.dialogContainer_.setAttribute('offline', true); | 2493 this.dialogContainer_.setAttribute('offline', true); |
2611 } else { | 2494 } else { |
2612 console.log('ONLINE'); | 2495 console.log('ONLINE'); |
(...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3167 this.directoryModel_.changeDirectory(event.srcElement.path); | 3050 this.directoryModel_.changeDirectory(event.srcElement.path); |
3168 }; | 3051 }; |
3169 | 3052 |
3170 FileManager.prototype.onCheckboxClick_ = function(event) { | 3053 FileManager.prototype.onCheckboxClick_ = function(event) { |
3171 var sm = this.directoryModel_.getFileListSelection(); | 3054 var sm = this.directoryModel_.getFileListSelection(); |
3172 var listItem = this.findListItemForEvent_(event); | 3055 var listItem = this.findListItemForEvent_(event); |
3173 sm.setIndexSelected(listItem.listIndex, event.target.checked); | 3056 sm.setIndexSelected(listItem.listIndex, event.target.checked); |
3174 }; | 3057 }; |
3175 | 3058 |
3176 FileManager.prototype.onPinClick_ = function(checkbox, entry, event) { | 3059 FileManager.prototype.onPinClick_ = function(checkbox, entry, event) { |
| 3060 // TODO(dgozman): revisit this method when gdata properties updated event |
| 3061 // will be available. |
3177 var self = this; | 3062 var self = this; |
3178 function callback(props) { | 3063 function callback(props) { |
3179 if (props.errorCode) { | 3064 if (props.errorCode) { |
3180 // TODO(serya): Do not show the message if unpin failed. | 3065 // TODO(serya): Do not show the message if unpin failed. |
3181 self.metadataCache_.get(entry, 'filesystem', function(filesystem) { | 3066 self.metadataCache_.get(entry, 'filesystem', function(filesystem) { |
3182 self.alert.showHtml(str('GDATA_OUT_OF_SPACE_HEADER'), | 3067 self.alert.showHtml(str('GDATA_OUT_OF_SPACE_HEADER'), |
3183 strf('GDATA_OUT_OF_SPACE_MESSAGE', | 3068 strf('GDATA_OUT_OF_SPACE_MESSAGE', |
3184 util.bytesToSi(filesystem.size))); | 3069 util.bytesToSi(filesystem.size))); |
3185 }); | 3070 }); |
3186 } | 3071 } |
3187 checkbox.checked = entry.gdata_.isPinned = props[0].isPinned; | 3072 // We don't have update events yet, so clear the cached data. |
| 3073 self.metadataCache_.clear(entry, 'gdata'); |
| 3074 checkbox.checked = props[0].isPinned; |
3188 } | 3075 } |
3189 var pin = checkbox.checked; | 3076 var pin = checkbox.checked; |
3190 cacheGDataProps(entry, function(entry) { | 3077 this.metadataCache_.get(entry, 'gdata', function(gdata) { |
3191 if (self.isOffline() && pin && !entry.gdata_.isPresent) { | 3078 if (self.isOffline() && pin && !gdata.present) { |
3192 // If we are offline, we cannot pin a file that is not already present. | 3079 // If we are offline, we cannot pin a file that is not already present. |
3193 checkbox.checked = false; // Revert the default action. | 3080 checkbox.checked = false; // Revert the default action. |
3194 self.alert.showHtml( | 3081 self.alert.showHtml( |
3195 str('OFFLINE_HEADER'), | 3082 str('OFFLINE_HEADER'), |
3196 strf('OFFLINE_MESSAGE', str('OFFLINE_COLUMN_LABEL'))); | 3083 strf('OFFLINE_MESSAGE', str('OFFLINE_COLUMN_LABEL'))); |
3197 return; | 3084 return; |
3198 } | 3085 } |
3199 chrome.fileBrowserPrivate.pinGDataFile([entry.toURL()], pin, callback); | 3086 chrome.fileBrowserPrivate.pinGDataFile([entry.toURL()], pin, callback); |
3200 }); | 3087 }); |
3201 event.preventDefault(); | 3088 event.preventDefault(); |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3427 // then for real). Do not update the location then. | 3314 // then for real). Do not update the location then. |
3428 if (event.newDirEntry.fullPath != event.previousDirEntry.fullPath) { | 3315 if (event.newDirEntry.fullPath != event.previousDirEntry.fullPath) { |
3429 this.updateLocation_(event.initial, event.newDirEntry.fullPath); | 3316 this.updateLocation_(event.initial, event.newDirEntry.fullPath); |
3430 } | 3317 } |
3431 | 3318 |
3432 this.checkFreeSpace_(this.getCurrentDirectory()); | 3319 this.checkFreeSpace_(this.getCurrentDirectory()); |
3433 | 3320 |
3434 // TODO(dgozman): title may be better than this. | 3321 // TODO(dgozman): title may be better than this. |
3435 this.document_.title = this.getCurrentDirectory().substr(1); | 3322 this.document_.title = this.getCurrentDirectory().substr(1); |
3436 | 3323 |
3437 if (this.metadataObserverId_) | 3324 if (this.filesystemObserverId_) |
3438 this.metadataCache_.removeObserver(this.metadataObserverId_); | 3325 this.metadataCache_.removeObserver(this.filesystemObserverId_); |
| 3326 if (this.gdataObserverId_) |
| 3327 this.metadataCache_.removeObserver(this.gdataObserverId_); |
3439 | 3328 |
3440 this.metadataObserverId_ = this.metadataCache_.addObserver( | 3329 this.filesystemObserverId_ = this.metadataCache_.addObserver( |
3441 this.directoryModel_.getCurrentDirEntry(), | 3330 this.directoryModel_.getCurrentDirEntry(), |
3442 MetadataCache.CHILDREN, | 3331 MetadataCache.CHILDREN, |
3443 'filesystem', | 3332 'filesystem', |
3444 this.updateFilesystemPropertiesInUI_.bind(this)); | 3333 this.updateMetadataInUI_.bind(this, 'filesystem')); |
| 3334 |
| 3335 if (this.isOnGData()) { |
| 3336 this.gdataObserverId_ = this.metadataCache_.addObserver( |
| 3337 this.directoryModel_.getCurrentDirEntry(), |
| 3338 MetadataCache.CHILDREN, |
| 3339 'gdata', |
| 3340 this.updateMetadataInUI_.bind(this, 'gdata')); |
| 3341 } |
3445 | 3342 |
3446 var self = this; | 3343 var self = this; |
3447 | 3344 |
3448 if (this.watchedDirectoryUrl_) { | 3345 if (this.watchedDirectoryUrl_) { |
3449 if (this.watchedDirectoryUrl_ != event.previousDirEntry.toURL()) { | 3346 if (this.watchedDirectoryUrl_ != event.previousDirEntry.toURL()) { |
3450 console.warn('event.previousDirEntry does not match File Manager state', | 3347 console.warn('event.previousDirEntry does not match File Manager state', |
3451 event, this.watchedDirectoryUrl_); | 3348 event, this.watchedDirectoryUrl_); |
3452 } | 3349 } |
3453 chrome.fileBrowserPrivate.removeFileWatch(this.watchedDirectoryUrl_, | 3350 chrome.fileBrowserPrivate.removeFileWatch(this.watchedDirectoryUrl_, |
3454 function(result) { | 3351 function(result) { |
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4057 | 3954 |
4058 var onResolved = function(resolvedUrls) { | 3955 var onResolved = function(resolvedUrls) { |
4059 if (cancelled) return; | 3956 if (cancelled) return; |
4060 cleanup(); | 3957 cleanup(); |
4061 selection.urls = resolvedUrls; | 3958 selection.urls = resolvedUrls; |
4062 // Call next method on a timeout, as it's unsafe to | 3959 // Call next method on a timeout, as it's unsafe to |
4063 // close a window from a callback. | 3960 // close a window from a callback. |
4064 setTimeout(this.callSelectFilesApiAndClose_.bind(this, selection), 0); | 3961 setTimeout(this.callSelectFilesApiAndClose_.bind(this, selection), 0); |
4065 }.bind(this); | 3962 }.bind(this); |
4066 | 3963 |
4067 var onGotProperties = function(properties) { | 3964 var onProperties = function(properties) { |
4068 for (var i = 0; i < properties.length; i++) { | 3965 for (var i = 0; i < properties.length; i++) { |
4069 if (properties[i].isPresent) { | 3966 if (properties[i].present) { |
4070 // For files already in GCache, we don't get any transfer updates. | 3967 // For files already in GCache, we don't get any transfer updates. |
4071 filesTotal--; | 3968 filesTotal--; |
4072 } | 3969 } |
4073 } | 3970 } |
4074 this.resolveSelectResults_(selection.urls, onResolved); | 3971 this.resolveSelectResults_(selection.urls, onResolved); |
4075 }.bind(this); | 3972 }.bind(this); |
4076 | 3973 |
4077 setup(); | 3974 setup(); |
4078 chrome.fileBrowserPrivate.getGDataFileProperties( | 3975 this.metadataCache_.get(selection.urls, 'gdata', onProperties); |
4079 selection.urls, onGotProperties); | |
4080 }; | 3976 }; |
4081 | 3977 |
4082 /** | 3978 /** |
4083 * Handle a click of the ok button. | 3979 * Handle a click of the ok button. |
4084 * | 3980 * |
4085 * The ok button has different UI labels depending on the type of dialog, but | 3981 * The ok button has different UI labels depending on the type of dialog, but |
4086 * in code it's always referred to as 'ok'. | 3982 * in code it's always referred to as 'ok'. |
4087 * | 3983 * |
4088 * @param {Event} event The click event. | 3984 * @param {Event} event The click event. |
4089 */ | 3985 */ |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4329 | 4225 |
4330 handleSplitterDragEnd: function(e) { | 4226 handleSplitterDragEnd: function(e) { |
4331 Splitter.prototype.handleSplitterDragEnd.apply(this, arguments); | 4227 Splitter.prototype.handleSplitterDragEnd.apply(this, arguments); |
4332 this.ownerDocument.documentElement.classList.remove('col-resize'); | 4228 this.ownerDocument.documentElement.classList.remove('col-resize'); |
4333 } | 4229 } |
4334 }; | 4230 }; |
4335 | 4231 |
4336 customSplitter.decorate(splitterElement); | 4232 customSplitter.decorate(splitterElement); |
4337 }; | 4233 }; |
4338 })(); | 4234 })(); |
OLD | NEW |