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.

filesummary.js 7.7KB

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