filesummary.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /**
  2. * ownCloud
  3. *
  4. * @author Vincent Petry
  5. * @copyright 2014 Vincent Petry <pvince81@owncloud.com>
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  9. * License as published by the Free Software Foundation; either
  10. * version 3 of the License, or any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public
  18. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. (function() {
  22. /**
  23. * The FileSummary class encapsulates the file summary values and
  24. * the logic to render it in the given container
  25. *
  26. * @constructs FileSummary
  27. * @memberof OCA.Files
  28. *
  29. * @param $tr table row element
  30. * @param {OC.Backbone.Model} [options.filesConfig] files app configuration
  31. */
  32. var FileSummary = function($tr, options) {
  33. options = options || {};
  34. var self = this;
  35. this.$el = $tr;
  36. var filesConfig = options.config;
  37. if (filesConfig) {
  38. this._showHidden = !!filesConfig.show_hidden;
  39. window._nc_event_bus.subscribe('files:config:updated', ({ key, value }) => {
  40. if (key === 'show_hidden') {
  41. self._showHidden = !!value;
  42. self.update();
  43. }
  44. });
  45. }
  46. this.clear();
  47. this.render();
  48. };
  49. FileSummary.prototype = {
  50. _showHidden: null,
  51. summary: {
  52. totalFiles: 0,
  53. totalDirs: 0,
  54. totalHidden: 0,
  55. totalSize: 0,
  56. filter:'',
  57. sumIsPending:false
  58. },
  59. /**
  60. * Returns whether the given file info must be hidden
  61. *
  62. * @param {OC.Files.FileInfo} fileInfo file info
  63. *
  64. * @return {boolean} true if the file is a hidden file, false otherwise
  65. */
  66. _isHiddenFile: function(file) {
  67. return file.name && file.name.charAt(0) === '.';
  68. },
  69. /**
  70. * Adds file
  71. * @param {OC.Files.FileInfo} file file to add
  72. * @param {boolean} update whether to update the display
  73. */
  74. add: function(file, update) {
  75. if (file.name && file.name.toLowerCase().indexOf(this.summary.filter) === -1) {
  76. return;
  77. }
  78. if (file.type === 'dir' || file.mime === 'httpd/unix-directory') {
  79. this.summary.totalDirs++;
  80. }
  81. else {
  82. this.summary.totalFiles++;
  83. }
  84. if (this._isHiddenFile(file)) {
  85. this.summary.totalHidden++;
  86. }
  87. var size = parseInt(file.size, 10) || 0;
  88. if (size >=0) {
  89. this.summary.totalSize += size;
  90. } else {
  91. this.summary.sumIsPending = true;
  92. }
  93. if (!!update) {
  94. this.update();
  95. }
  96. },
  97. /**
  98. * Removes file
  99. * @param {OC.Files.FileInfo} file file to remove
  100. * @param {boolean} update whether to update the display
  101. */
  102. remove: function(file, update) {
  103. if (file.name && file.name.toLowerCase().indexOf(this.summary.filter) === -1) {
  104. return;
  105. }
  106. if (file.type === 'dir' || file.mime === 'httpd/unix-directory') {
  107. this.summary.totalDirs--;
  108. }
  109. else {
  110. this.summary.totalFiles--;
  111. }
  112. if (this._isHiddenFile(file)) {
  113. this.summary.totalHidden--;
  114. }
  115. var size = parseInt(file.size, 10) || 0;
  116. if (size >=0) {
  117. this.summary.totalSize -= size;
  118. }
  119. if (!!update) {
  120. this.update();
  121. }
  122. },
  123. setFilter: function(filter, files){
  124. this.summary.filter = filter.toLowerCase();
  125. this.calculate(files);
  126. },
  127. /**
  128. * Returns the total of files and directories
  129. */
  130. getTotal: function() {
  131. return this.summary.totalDirs + this.summary.totalFiles;
  132. },
  133. /**
  134. * Recalculates the summary based on the given files array
  135. * @param files array of files
  136. */
  137. calculate: function(files) {
  138. var file;
  139. var summary = {
  140. totalDirs: 0,
  141. totalFiles: 0,
  142. totalHidden: 0,
  143. totalSize: 0,
  144. filter: this.summary.filter,
  145. sumIsPending: false
  146. };
  147. for (var i = 0; i < files.length; i++) {
  148. file = files[i];
  149. if (file.name && file.name.toLowerCase().indexOf(this.summary.filter) === -1) {
  150. continue;
  151. }
  152. if (file.type === 'dir' || file.mime === 'httpd/unix-directory') {
  153. summary.totalDirs++;
  154. }
  155. else {
  156. summary.totalFiles++;
  157. }
  158. if (this._isHiddenFile(file)) {
  159. summary.totalHidden++;
  160. }
  161. var size = parseInt(file.size, 10) || 0;
  162. if (size >=0) {
  163. summary.totalSize += size;
  164. } else {
  165. summary.sumIsPending = true;
  166. }
  167. }
  168. this.setSummary(summary);
  169. },
  170. /**
  171. * Clears the summary
  172. */
  173. clear: function() {
  174. this.calculate([]);
  175. },
  176. /**
  177. * Sets the current summary values
  178. * @param summary map
  179. */
  180. setSummary: function(summary) {
  181. this.summary = summary;
  182. if (typeof this.summary.filter === 'undefined') {
  183. this.summary.filter = '';
  184. }
  185. this.update();
  186. },
  187. _infoTemplate: function(data) {
  188. /* NOTE: To update the template make changes in filesummary.handlebars
  189. * and run:
  190. *
  191. * handlebars -n OCA.Files.FileSummary.Templates filesummary.handlebars -f filesummary_template.js
  192. */
  193. return OCA.Files.Templates['filesummary'](_.extend({
  194. connectorLabel: t('files', '{dirs} and {files}', {dirs: '', files: ''})
  195. }, data));
  196. },
  197. /**
  198. * Renders the file summary element
  199. */
  200. update: function() {
  201. if (!this.$el) {
  202. return;
  203. }
  204. if (!this.summary.totalFiles && !this.summary.totalDirs) {
  205. this.$el.addClass('hidden');
  206. return;
  207. }
  208. // There's a summary and data -> Update the summary
  209. this.$el.removeClass('hidden');
  210. var $dirInfo = this.$el.find('.dirinfo');
  211. var $fileInfo = this.$el.find('.fileinfo');
  212. var $connector = this.$el.find('.connector');
  213. var $filterInfo = this.$el.find('.filter');
  214. var $hiddenInfo = this.$el.find('.hiddeninfo');
  215. // Substitute old content with new translations
  216. $dirInfo.html(n('files', '%n folder', '%n folders', this.summary.totalDirs));
  217. $fileInfo.html(n('files', '%n file', '%n files', this.summary.totalFiles));
  218. $hiddenInfo.html(' (' + n('files', 'including %n hidden', 'including %n hidden', this.summary.totalHidden) + ')');
  219. var fileSize = this.summary.sumIsPending ? t('files', 'Pending') : OC.Util.humanFileSize(this.summary.totalSize, false, false);
  220. this.$el.find('.filesize').html(fileSize);
  221. // Show only what's necessary (may be hidden)
  222. if (this.summary.totalDirs === 0) {
  223. $dirInfo.addClass('hidden');
  224. $connector.addClass('hidden');
  225. } else {
  226. $dirInfo.removeClass('hidden');
  227. }
  228. if (this.summary.totalFiles === 0) {
  229. $fileInfo.addClass('hidden');
  230. $connector.addClass('hidden');
  231. } else {
  232. $fileInfo.removeClass('hidden');
  233. }
  234. if (this.summary.totalDirs > 0 && this.summary.totalFiles > 0) {
  235. $connector.removeClass('hidden');
  236. }
  237. $hiddenInfo.toggleClass('hidden', this.summary.totalHidden === 0 || this._showHidden)
  238. if (this.summary.filter === '') {
  239. $filterInfo.html('');
  240. $filterInfo.addClass('hidden');
  241. } else {
  242. $filterInfo.html(' ' + n('files', 'matches "{filter}"', 'match "{filter}"', this.summary.totalDirs + this.summary.totalFiles, {filter: this.summary.filter}));
  243. $filterInfo.removeClass('hidden');
  244. }
  245. },
  246. render: function() {
  247. if (!this.$el) {
  248. return;
  249. }
  250. var summary = this.summary;
  251. // don't show the filesize column, if filesize is NaN (e.g. in trashbin)
  252. var fileSize = '';
  253. if (!isNaN(summary.totalSize)) {
  254. fileSize = summary.sumIsPending ? t('files', 'Pending') : OC.Util.humanFileSize(summary.totalSize, false, false);
  255. fileSize = '<td class="filesize">' + fileSize + '</td>';
  256. }
  257. var $summary = $(
  258. '<td class="filesummary">'+ this._infoTemplate() + '</td>' +
  259. fileSize +
  260. '<td class="date"></td>'
  261. );
  262. this.$el.addClass('hidden');
  263. this.$el.append($summary);
  264. this.update();
  265. }
  266. };
  267. OCA.Files.FileSummary = FileSummary;
  268. })();