mainfileinfodetailview.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /*
  2. * Copyright (c) 2015
  3. *
  4. * This file is licensed under the Affero General Public License version 3
  5. * or later.
  6. *
  7. * See the COPYING-README file.
  8. *
  9. */
  10. (function() {
  11. var TEMPLATE =
  12. '<div class="thumbnailContainer"><a href="#" class="thumbnail action-default"><div class="stretcher"/></a></div>' +
  13. '<div class="file-details-container">' +
  14. '<div class="fileName"><h3 title="{{name}}" class="ellipsis">{{name}}</h3></div>' +
  15. ' <div class="file-details ellipsis">' +
  16. ' <a href="#" ' +
  17. ' class="action action-favorite favorite">' +
  18. ' <img class="svg" alt="{{starAltText}}" src="{{starIcon}}" />' +
  19. ' </a>' +
  20. ' {{#if hasSize}}<span class="size" title="{{altSize}}">{{size}}</span>, {{/if}}<span class="date" title="{{altDate}}">{{date}}</span>' +
  21. ' </div>' +
  22. '</div>';
  23. /**
  24. * @class OCA.Files.MainFileInfoDetailView
  25. * @classdesc
  26. *
  27. * Displays main details about a file
  28. *
  29. */
  30. var MainFileInfoDetailView = OCA.Files.DetailFileInfoView.extend(
  31. /** @lends OCA.Files.MainFileInfoDetailView.prototype */ {
  32. className: 'mainFileInfoView',
  33. /**
  34. * Associated file list instance, for file actions
  35. *
  36. * @type {OCA.Files.FileList}
  37. */
  38. _fileList: null,
  39. /**
  40. * File actions
  41. *
  42. * @type {OCA.Files.FileActions}
  43. */
  44. _fileActions: null,
  45. events: {
  46. 'click a.action-favorite': '_onClickFavorite',
  47. 'click a.action-default': '_onClickDefaultAction'
  48. },
  49. template: function(data) {
  50. if (!this._template) {
  51. this._template = Handlebars.compile(TEMPLATE);
  52. }
  53. return this._template(data);
  54. },
  55. initialize: function(options) {
  56. options = options || {};
  57. this._fileList = options.fileList;
  58. this._fileActions = options.fileActions;
  59. if (!this._fileList) {
  60. throw 'Missing required parameter "fileList"';
  61. }
  62. if (!this._fileActions) {
  63. throw 'Missing required parameter "fileActions"';
  64. }
  65. },
  66. _onClickFavorite: function(event) {
  67. event.preventDefault();
  68. this._fileActions.triggerAction('Favorite', this.model, this._fileList);
  69. },
  70. _onClickDefaultAction: function(event) {
  71. event.preventDefault();
  72. this._fileActions.triggerAction(null, this.model, this._fileList);
  73. },
  74. _onModelChanged: function() {
  75. // simply re-render
  76. this.render();
  77. },
  78. setFileInfo: function(fileInfo) {
  79. if (this.model) {
  80. this.model.off('change', this._onModelChanged, this);
  81. }
  82. this.model = fileInfo;
  83. if (this.model) {
  84. this.model.on('change', this._onModelChanged, this);
  85. }
  86. this.render();
  87. },
  88. /**
  89. * Renders this details view
  90. */
  91. render: function() {
  92. if (this.model) {
  93. var isFavorite = (this.model.get('tags') || []).indexOf(OC.TAG_FAVORITE) >= 0;
  94. this.$el.html(this.template({
  95. type: this.model.isImage()? 'image': '',
  96. nameLabel: t('files', 'Name'),
  97. name: this.model.get('displayName') || this.model.get('name'),
  98. pathLabel: t('files', 'Path'),
  99. path: this.model.get('path'),
  100. hasSize: this.model.has('size'),
  101. sizeLabel: t('files', 'Size'),
  102. size: OC.Util.humanFileSize(this.model.get('size'), true),
  103. altSize: n('files', '%n byte', '%n bytes', this.model.get('size')),
  104. dateLabel: t('files', 'Modified'),
  105. altDate: OC.Util.formatDate(this.model.get('mtime')),
  106. date: OC.Util.relativeModifiedDate(this.model.get('mtime')),
  107. starAltText: isFavorite ? t('files', 'Favorited') : t('files', 'Favorite'),
  108. starIcon: OC.imagePath('core', isFavorite ? 'actions/starred' : 'actions/star')
  109. }));
  110. // TODO: we really need OC.Previews
  111. var $iconDiv = this.$el.find('.thumbnail');
  112. var $container = this.$el.find('.thumbnailContainer');
  113. if (!this.model.isDirectory()) {
  114. $iconDiv.addClass('icon-loading icon-32');
  115. this.loadPreview(this.model.getFullPath(), this.model.get('mimetype'), this.model.get('etag'), $iconDiv, $container, this.model.isImage());
  116. } else {
  117. var iconUrl = this.model.get('icon') || OC.MimeType.getIconUrl('dir');
  118. $iconDiv.css('background-image', 'url("' + iconUrl + '")');
  119. OC.Util.scaleFixForIE8($iconDiv);
  120. }
  121. this.$el.find('[title]').tooltip({placement: 'bottom'});
  122. } else {
  123. this.$el.empty();
  124. }
  125. this.delegateEvents();
  126. },
  127. loadPreview: function(path, mime, etag, $iconDiv, $container, isImage) {
  128. var maxImageWidth = $container.parent().width() + 50; // 50px for negative margins
  129. var maxImageHeight = maxImageWidth / (16/9);
  130. var smallPreviewSize = 75;
  131. var isLandscape = function(img) {
  132. return img.width > (img.height * 1.2);
  133. };
  134. var isSmall = function(img) {
  135. return (img.width * 1.1) < (maxImageWidth * window.devicePixelRatio);
  136. };
  137. var getTargetHeight = function(img) {
  138. if(isImage) {
  139. var targetHeight = img.height / window.devicePixelRatio;
  140. if (targetHeight <= smallPreviewSize) {
  141. targetHeight = smallPreviewSize;
  142. }
  143. return targetHeight;
  144. }else{
  145. return smallPreviewSize;
  146. }
  147. };
  148. var getTargetRatio = function(img){
  149. var ratio = img.width / img.height;
  150. if (ratio > 16/9) {
  151. return ratio;
  152. } else {
  153. return 16/9;
  154. }
  155. };
  156. this._fileList.lazyLoadPreview({
  157. path: path,
  158. mime: mime,
  159. etag: etag,
  160. y: isImage ? maxImageHeight : smallPreviewSize,
  161. x: isImage ? maxImageWidth : smallPreviewSize,
  162. a: isImage ? 1 : null,
  163. mode: isImage ? 'cover' : null,
  164. callback: function (previewUrl, img) {
  165. $iconDiv.previewImg = previewUrl;
  166. // as long as we only have the mimetype icon, we only save it in case there is no preview
  167. if (!img) {
  168. return;
  169. }
  170. $iconDiv.removeClass('icon-loading icon-32');
  171. var targetHeight = getTargetHeight(img);
  172. if (this.model.isImage() && targetHeight > smallPreviewSize) {
  173. $container.addClass((isLandscape(img) && !isSmall(img))? 'landscape': 'portrait');
  174. $container.addClass('image');
  175. }
  176. // only set background when we have an actual preview
  177. // when we dont have a preview we show the mime icon in the error handler
  178. $iconDiv.css({
  179. 'background-image': 'url("' + previewUrl + '")',
  180. height: (targetHeight > smallPreviewSize)? 'auto': targetHeight,
  181. 'max-height': isSmall(img)? targetHeight: null
  182. });
  183. var targetRatio = getTargetRatio(img);
  184. $iconDiv.find('.stretcher').css({
  185. 'padding-bottom': (100 / targetRatio) + '%'
  186. });
  187. }.bind(this),
  188. error: function () {
  189. $iconDiv.removeClass('icon-loading icon-32');
  190. this.$el.find('.thumbnailContainer').removeClass('image'); //fall back to regular view
  191. $iconDiv.css({
  192. 'background-image': 'url("' + $iconDiv.previewImg + '")'
  193. });
  194. OC.Util.scaleFixForIE8($iconDiv);
  195. }.bind(this)
  196. });
  197. }
  198. });
  199. OCA.Files.MainFileInfoDetailView = MainFileInfoDetailView;
  200. })();