filesummary.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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.get('showhidden');
  39. filesConfig.on('change:showhidden', function() {
  40. self._showHidden = !!this.get('showhidden');
  41. self.update();
  42. });
  43. }
  44. this.clear();
  45. this.render();
  46. };
  47. FileSummary.prototype = {
  48. _showHidden: null,
  49. summary: {
  50. totalFiles: 0,
  51. totalDirs: 0,
  52. totalHidden: 0,
  53. totalSize: 0,
  54. filter:'',
  55. sumIsPending:false
  56. },
  57. /**
  58. * Returns whether the given file info must be hidden
  59. *
  60. * @param {OC.Files.FileInfo} fileInfo file info
  61. *
  62. * @return {boolean} true if the file is a hidden file, false otherwise
  63. */
  64. _isHiddenFile: function(file) {
  65. return file.name && file.name.charAt(0) === '.';
  66. },
  67. /**
  68. * Adds file
  69. * @param {OC.Files.FileInfo} file file to add
  70. * @param {boolean} update whether to update the display
  71. */
  72. add: function(file, update) {
  73. if (file.name && file.name.toLowerCase().indexOf(this.summary.filter) === -1) {
  74. return;
  75. }
  76. if (file.type === 'dir' || file.mime === 'httpd/unix-directory') {
  77. this.summary.totalDirs++;
  78. }
  79. else {
  80. this.summary.totalFiles++;
  81. }
  82. if (this._isHiddenFile(file)) {
  83. this.summary.totalHidden++;
  84. }
  85. var size = parseInt(file.size, 10) || 0;
  86. if (size >=0) {
  87. this.summary.totalSize += size;
  88. } else {
  89. this.summary.sumIsPending = true;
  90. }
  91. if (!!update) {
  92. this.update();
  93. }
  94. },
  95. /**
  96. * Removes file
  97. * @param {OC.Files.FileInfo} file file to remove
  98. * @param {boolean} update whether to update the display
  99. */
  100. remove: function(file, update) {
  101. if (file.name && file.name.toLowerCase().indexOf(this.summary.filter) === -1) {
  102. return;
  103. }
  104. if (file.type === 'dir' || file.mime === 'httpd/unix-directory') {
  105. this.summary.totalDirs--;
  106. }
  107. else {
  108. this.summary.totalFiles--;
  109. }
  110. if (this._isHiddenFile(file)) {
  111. this.summary.totalHidden--;
  112. }
  113. var size = parseInt(file.size, 10) || 0;
  114. if (size >=0) {
  115. this.summary.totalSize -= size;
  116. }
  117. if (!!update) {
  118. this.update();
  119. }
  120. },
  121. setFilter: function(filter, files){
  122. this.summary.filter = filter.toLowerCase();
  123. this.calculate(files);
  124. },
  125. /**
  126. * Returns the total of files and directories
  127. */
  128. getTotal: function() {
  129. return this.summary.totalDirs + this.summary.totalFiles;
  130. },
  131. /**
  132. * Recalculates the summary based on the given files array
  133. * @param files array of files
  134. */
  135. calculate: function(files) {
  136. var file;
  137. var summary = {
  138. totalDirs: 0,
  139. totalFiles: 0,
  140. totalHidden: 0,
  141. totalSize: 0,
  142. filter: this.summary.filter,
  143. sumIsPending: false
  144. };
  145. for (var i = 0; i < files.length; i++) {
  146. file = files[i];
  147. if (file.name && file.name.toLowerCase().indexOf(this.summary.filter) === -1) {
  148. continue;
  149. }
  150. if (file.type === 'dir' || file.mime === 'httpd/unix-directory') {
  151. summary.totalDirs++;
  152. }
  153. else {
  154. summary.totalFiles++;
  155. }
  156. if (this._isHiddenFile(file)) {
  157. summary.totalHidden++;
  158. }
  159. var size = parseInt(file.size, 10) || 0;
  160. if (size >=0) {
  161. summary.totalSize += size;
  162. } else {
  163. summary.sumIsPending = true;
  164. }
  165. }
  166. this.setSummary(summary);
  167. },
  168. /**
  169. * Clears the summary
  170. */
  171. clear: function() {
  172. this.calculate([]);
  173. },
  174. /**
  175. * Sets the current summary values
  176. * @param summary map
  177. */
  178. setSummary: function(summary) {
  179. this.summary = summary;
  180. if (typeof this.summary.filter === 'undefined') {
  181. this.summary.filter = '';
  182. }
  183. this.update();
  184. },
  185. _infoTemplate: function(data) {
  186. /* NOTE: To update the template make changes in filesummary.handlebars
  187. * and run:
  188. *
  189. * handlebars -n OCA.Files.FileSummary.Templates filesummary.handlebars -f filesummary_template.js
  190. */
  191. return OCA.Files.Templates['filesummary'](_.extend({
  192. connectorLabel: t('files', '{dirs} and {files}', {dirs: '', files: ''})
  193. }, data));
  194. },
  195. /**
  196. * Renders the file summary element
  197. */
  198. update: function() {
  199. if (!this.$el) {
  200. return;
  201. }
  202. if (!this.summary.totalFiles && !this.summary.totalDirs) {
  203. this.$el.addClass('hidden');
  204. return;
  205. }
  206. // There's a summary and data -> Update the summary
  207. this.$el.removeClass('hidden');
  208. var $dirInfo = this.$el.find('.dirinfo');
  209. var $fileInfo = this.$el.find('.fileinfo');
  210. var $connector = this.$el.find('.connector');
  211. var $filterInfo = this.$el.find('.filter');
  212. var $hiddenInfo = this.$el.find('.hiddeninfo');
  213. // Substitute old content with new translations
  214. $dirInfo.html(n('files', '%n folder', '%n folders', this.summary.totalDirs));
  215. $fileInfo.html(n('files', '%n file', '%n files', this.summary.totalFiles));
  216. $hiddenInfo.html(' (' + n('files', 'including %n hidden', 'including %n hidden', this.summary.totalHidden) + ')');
  217. var fileSize = this.summary.sumIsPending ? t('files', 'Pending') : OC.Util.humanFileSize(this.summary.totalSize);
  218. this.$el.find('.filesize').html(fileSize);
  219. // Show only what's necessary (may be hidden)
  220. if (this.summary.totalDirs === 0) {
  221. $dirInfo.addClass('hidden');
  222. $connector.addClass('hidden');
  223. } else {
  224. $dirInfo.removeClass('hidden');
  225. }
  226. if (this.summary.totalFiles === 0) {
  227. $fileInfo.addClass('hidden');
  228. $connector.addClass('hidden');
  229. } else {
  230. $fileInfo.removeClass('hidden');
  231. }
  232. if (this.summary.totalDirs > 0 && this.summary.totalFiles > 0) {
  233. $connector.removeClass('hidden');
  234. }
  235. $hiddenInfo.toggleClass('hidden', this.summary.totalHidden === 0 || this._showHidden)
  236. if (this.summary.filter === '') {
  237. $filterInfo.html('');
  238. $filterInfo.addClass('hidden');
  239. } else {
  240. $filterInfo.html(' ' + n('files', 'matches \'{filter}\'', 'match \'{filter}\'', this.summary.totalDirs + this.summary.totalFiles, {filter: this.summary.filter}));
  241. $filterInfo.removeClass('hidden');
  242. }
  243. },
  244. render: function() {
  245. if (!this.$el) {
  246. return;
  247. }
  248. var summary = this.summary;
  249. // don't show the filesize column, if filesize is NaN (e.g. in trashbin)
  250. var fileSize = '';
  251. if (!isNaN(summary.totalSize)) {
  252. fileSize = summary.sumIsPending ? t('files', 'Pending') : OC.Util.humanFileSize(summary.totalSize);
  253. fileSize = '<td class="filesize">' + fileSize + '</td>';
  254. }
  255. var $summary = $(
  256. '<td class="filesummary">'+ this._infoTemplate() + '</td>' +
  257. fileSize +
  258. '<td class="date"></td>'
  259. );
  260. this.$el.addClass('hidden');
  261. this.$el.append($summary);
  262. this.update();
  263. }
  264. };
  265. OCA.Files.FileSummary = FileSummary;
  266. })();