You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

321 lines
8.7 KiB

  1. /*
  2. * Copyright (c) 2014
  3. *
  4. * @author Vincent Petry
  5. * @copyright 2014 Vincent Petry <pvince81@owncloud.com>
  6. *
  7. * This file is licensed under the Affero General Public License version 3
  8. * or later.
  9. *
  10. * See the COPYING-README file.
  11. *
  12. */
  13. /* global dragOptions, folderDropOptions, OC */
  14. (function() {
  15. if (!OCA.Files) {
  16. /**
  17. * Namespace for the files app
  18. * @namespace OCA.Files
  19. */
  20. OCA.Files = {};
  21. }
  22. /**
  23. * @namespace OCA.Files.App
  24. */
  25. OCA.Files.App = {
  26. /**
  27. * Navigation control
  28. *
  29. * @member {OCA.Files.Navigation}
  30. */
  31. navigation: null,
  32. /**
  33. * File list for the "All files" section.
  34. *
  35. * @member {OCA.Files.FileList}
  36. */
  37. fileList: null,
  38. /**
  39. * Backbone model for storing files preferences
  40. */
  41. _filesConfig: null,
  42. /**
  43. * Initializes the files app
  44. */
  45. initialize: function() {
  46. this.navigation = new OCA.Files.Navigation($('#app-navigation'));
  47. this.$showHiddenFiles = $('input#showhiddenfilesToggle');
  48. var showHidden = $('#showHiddenFiles').val() === "1";
  49. this.$showHiddenFiles.prop('checked', showHidden);
  50. if ($('#fileNotFound').val() === "1") {
  51. OC.Notification.show(t('files', 'File could not be found'), {type: 'error'});
  52. }
  53. this._filesConfig = new OC.Backbone.Model({
  54. showhidden: showHidden
  55. });
  56. var urlParams = OC.Util.History.parseUrlQuery();
  57. var fileActions = new OCA.Files.FileActions();
  58. // default actions
  59. fileActions.registerDefaultActions();
  60. // legacy actions
  61. fileActions.merge(window.FileActions);
  62. // regular actions
  63. fileActions.merge(OCA.Files.fileActions);
  64. this._onActionsUpdated = _.bind(this._onActionsUpdated, this);
  65. OCA.Files.fileActions.on('setDefault.app-files', this._onActionsUpdated);
  66. OCA.Files.fileActions.on('registerAction.app-files', this._onActionsUpdated);
  67. window.FileActions.on('setDefault.app-files', this._onActionsUpdated);
  68. window.FileActions.on('registerAction.app-files', this._onActionsUpdated);
  69. this.files = OCA.Files.Files;
  70. // TODO: ideally these should be in a separate class / app (the embedded "all files" app)
  71. this.fileList = new OCA.Files.FileList(
  72. $('#app-content-files'), {
  73. scrollContainer: $('#app-content'),
  74. dragOptions: dragOptions,
  75. folderDropOptions: folderDropOptions,
  76. fileActions: fileActions,
  77. allowLegacyActions: true,
  78. scrollTo: urlParams.scrollto,
  79. filesClient: OC.Files.getClient(),
  80. sorting: {
  81. mode: $('#defaultFileSorting').val(),
  82. direction: $('#defaultFileSortingDirection').val()
  83. },
  84. config: this._filesConfig,
  85. enableUpload: true
  86. }
  87. );
  88. this.files.initialize();
  89. // for backward compatibility, the global FileList will
  90. // refer to the one of the "files" view
  91. window.FileList = this.fileList;
  92. OC.Plugins.attach('OCA.Files.App', this);
  93. this._setupEvents();
  94. // trigger URL change event handlers
  95. this._onPopState(urlParams);
  96. $('#quota.has-tooltip').tooltip({
  97. placement: 'top'
  98. });
  99. this._debouncedPersistShowHiddenFilesState = _.debounce(this._persistShowHiddenFilesState, 1200);
  100. },
  101. /**
  102. * Destroy the app
  103. */
  104. destroy: function() {
  105. this.navigation = null;
  106. this.fileList.destroy();
  107. this.fileList = null;
  108. this.files = null;
  109. OCA.Files.fileActions.off('setDefault.app-files', this._onActionsUpdated);
  110. OCA.Files.fileActions.off('registerAction.app-files', this._onActionsUpdated);
  111. window.FileActions.off('setDefault.app-files', this._onActionsUpdated);
  112. window.FileActions.off('registerAction.app-files', this._onActionsUpdated);
  113. },
  114. _onActionsUpdated: function(ev, newAction) {
  115. // forward new action to the file list
  116. if (ev.action) {
  117. this.fileList.fileActions.registerAction(ev.action);
  118. } else if (ev.defaultAction) {
  119. this.fileList.fileActions.setDefault(
  120. ev.defaultAction.mime,
  121. ev.defaultAction.name
  122. );
  123. }
  124. },
  125. /**
  126. * Returns the container of the currently visible app.
  127. *
  128. * @return app container
  129. */
  130. getCurrentAppContainer: function() {
  131. return this.navigation.getActiveContainer();
  132. },
  133. /**
  134. * Sets the currently active view
  135. * @param viewId view id
  136. */
  137. setActiveView: function(viewId, options) {
  138. this.navigation.setActiveItem(viewId, options);
  139. },
  140. /**
  141. * Returns the view id of the currently active view
  142. * @return view id
  143. */
  144. getActiveView: function() {
  145. return this.navigation.getActiveItem();
  146. },
  147. /**
  148. *
  149. * @returns {Backbone.Model}
  150. */
  151. getFilesConfig: function() {
  152. return this._filesConfig;
  153. },
  154. /**
  155. * Setup events based on URL changes
  156. */
  157. _setupEvents: function() {
  158. OC.Util.History.addOnPopStateHandler(_.bind(this._onPopState, this));
  159. // detect when app changed their current directory
  160. $('#app-content').delegate('>div', 'changeDirectory', _.bind(this._onDirectoryChanged, this));
  161. $('#app-content').delegate('>div', 'afterChangeDirectory', _.bind(this._onAfterDirectoryChanged, this));
  162. $('#app-content').delegate('>div', 'changeViewerMode', _.bind(this._onChangeViewerMode, this));
  163. $('#app-navigation').on('itemChanged', _.bind(this._onNavigationChanged, this));
  164. this.$showHiddenFiles.on('change', _.bind(this._onShowHiddenFilesChange, this));
  165. },
  166. /**
  167. * Toggle showing hidden files according to the settings checkbox
  168. *
  169. * @returns {undefined}
  170. */
  171. _onShowHiddenFilesChange: function() {
  172. var show = this.$showHiddenFiles.is(':checked');
  173. this._filesConfig.set('showhidden', show);
  174. this._debouncedPersistShowHiddenFilesState();
  175. },
  176. /**
  177. * Persist show hidden preference on ther server
  178. *
  179. * @returns {undefined}
  180. */
  181. _persistShowHiddenFilesState: function() {
  182. var show = this._filesConfig.get('showhidden');
  183. $.post(OC.generateUrl('/apps/files/api/v1/showhidden'), {
  184. show: show
  185. });
  186. },
  187. /**
  188. * Event handler for when the current navigation item has changed
  189. */
  190. _onNavigationChanged: function(e) {
  191. var params;
  192. if (e && e.itemId) {
  193. params = {
  194. view: e.itemId,
  195. dir: '/'
  196. };
  197. this._changeUrl(params.view, params.dir);
  198. OC.Apps.hideAppSidebar($('.detailsView'));
  199. this.navigation.getActiveContainer().trigger(new $.Event('urlChanged', params));
  200. }
  201. },
  202. /**
  203. * Event handler for when an app notified that its directory changed
  204. */
  205. _onDirectoryChanged: function(e) {
  206. if (e.dir) {
  207. this._changeUrl(this.navigation.getActiveItem(), e.dir, e.fileId);
  208. }
  209. },
  210. /**
  211. * Event handler for when an app notified that its directory changed
  212. */
  213. _onAfterDirectoryChanged: function(e) {
  214. if (e.dir && e.fileId) {
  215. this._changeUrl(this.navigation.getActiveItem(), e.dir, e.fileId);
  216. }
  217. },
  218. /**
  219. * Event handler for when an app notifies that it needs space
  220. * for viewer mode.
  221. */
  222. _onChangeViewerMode: function(e) {
  223. var state = !!e.viewerModeEnabled;
  224. if (e.viewerModeEnabled) {
  225. OC.Apps.hideAppSidebar($('.detailsView'));
  226. }
  227. $('#app-navigation').toggleClass('hidden', state);
  228. $('.app-files').toggleClass('viewer-mode no-sidebar', state);
  229. },
  230. /**
  231. * Event handler for when the URL changed
  232. */
  233. _onPopState: function(params) {
  234. params = _.extend({
  235. dir: '/',
  236. view: 'files'
  237. }, params);
  238. var lastId = this.navigation.getActiveItem();
  239. if (!this.navigation.itemExists(params.view)) {
  240. params.view = 'files';
  241. }
  242. this.navigation.setActiveItem(params.view, {silent: true});
  243. if (lastId !== this.navigation.getActiveItem()) {
  244. this.navigation.getActiveContainer().trigger(new $.Event('show'));
  245. }
  246. this.navigation.getActiveContainer().trigger(new $.Event('urlChanged', params));
  247. },
  248. /**
  249. * Encode URL params into a string, except for the "dir" attribute
  250. * that gets encoded as path where "/" is not encoded
  251. *
  252. * @param {Object.<string>} params
  253. * @return {string} encoded params
  254. */
  255. _makeUrlParams: function(params) {
  256. var dir = params.dir;
  257. delete params.dir;
  258. return 'dir=' + OC.encodePath(dir) + '&' + OC.buildQueryString(params);
  259. },
  260. /**
  261. * Change the URL to point to the given dir and view
  262. */
  263. _changeUrl: function(view, dir, fileId) {
  264. var params = {dir: dir};
  265. if (view !== 'files') {
  266. params.view = view;
  267. } else if (fileId) {
  268. params.fileid = fileId;
  269. }
  270. var currentParams = OC.Util.History.parseUrlQuery();
  271. if (currentParams.dir === params.dir && currentParams.view === params.view && currentParams.fileid !== params.fileid) {
  272. // if only fileid changed or was added, replace instead of push
  273. OC.Util.History.replaceState(this._makeUrlParams(params));
  274. } else {
  275. OC.Util.History.pushState(this._makeUrlParams(params));
  276. }
  277. }
  278. };
  279. })();
  280. $(document).ready(function() {
  281. // wait for other apps/extensions to register their event handlers and file actions
  282. // in the "ready" clause
  283. _.defer(function() {
  284. OCA.Files.App.initialize();
  285. });
  286. });