/** * Copyright (c) 2015 * * @author Jan-Christoph Borchardt * @author John Molakvoæ * @author Julius Härtl * @author Michael Jobst * @author noveens * @author Robin Appelman * @author Vincent Petry * * @license AGPL-3.0-or-later * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ import ItemTemplate from './templates/item.handlebars' import Template from './templates/template.handlebars'; (function() { if (!OCA.Files.DetailTabView) { // Only register the versions tab within the files app return } /** * @memberof OCA.Versions */ const VersionsTabView = OCA.Files.DetailTabView.extend(/** @lends OCA.Versions.VersionsTabView.prototype */{ id: 'versionsTabView', className: 'tab versionsTabView', _template: null, $versionsContainer: null, events: { 'click .revertVersion': '_onClickRevertVersion', }, initialize() { OCA.Files.DetailTabView.prototype.initialize.apply(this, arguments) this.collection = new OCA.Versions.VersionCollection() this.collection.on('request', this._onRequest, this) this.collection.on('sync', this._onEndRequest, this) this.collection.on('update', this._onUpdate, this) this.collection.on('error', this._onError, this) this.collection.on('add', this._onAddModel, this) }, getLabel() { return t('files_versions', 'Versions') }, getIcon() { return 'icon-history' }, nextPage() { if (this._loading) { return } if (this.collection.getFileInfo() && this.collection.getFileInfo().isDirectory()) { return } this.collection.fetch() }, _onClickRevertVersion(ev) { const self = this let $target = $(ev.target) const fileInfoModel = this.collection.getFileInfo() if (!$target.is('li')) { $target = $target.closest('li') } ev.preventDefault() const revision = $target.attr('data-revision') const versionModel = this.collection.get(revision) versionModel.revert({ success() { // reset and re-fetch the updated collection self.$versionsContainer.empty() self.collection.setFileInfo(fileInfoModel) self.collection.reset([], { silent: true }) self.collection.fetch() self.$el.find('.versions').removeClass('hidden') // update original model fileInfoModel.trigger('busy', fileInfoModel, false) fileInfoModel.set({ size: versionModel.get('size'), mtime: versionModel.get('timestamp') * 1000, // temp dummy, until we can do a PROPFIND etag: versionModel.get('id') + versionModel.get('timestamp'), }) }, error() { fileInfoModel.trigger('busy', fileInfoModel, false) self.$el.find('.versions').removeClass('hidden') self._toggleLoading(false) OC.Notification.show(t('files_version', 'Failed to revert {file} to revision {timestamp}.', { file: versionModel.getFullPath(), timestamp: OC.Util.formatDate(versionModel.get('timestamp') * 1000), }), { type: 'error', } ) }, }) // spinner this._toggleLoading(true) fileInfoModel.trigger('busy', fileInfoModel, true) }, _toggleLoading(state) { this._loading = state this.$el.find('.loading').toggleClass('hidden', !state) }, _onRequest() { this._toggleLoading(true) }, _onEndRequest() { this._toggleLoading(false) this.$el.find('.empty').toggleClass('hidden', !!this.collection.length) }, _onAddModel(model) { const $el = $(this.itemTemplate(this._formatItem(model))) this.$versionsContainer.append($el) $el.find('.has-tooltip').tooltip() }, template(data) { return Template(data) }, itemTemplate(data) { return ItemTemplate(data) }, setFileInfo(fileInfo) { if (fileInfo) { this.render() this.collection.setFileInfo(fileInfo) this.collection.reset([], { silent: true }) this.nextPage() } else { this.render() this.collection.reset() } }, _formatItem(version) { const timestamp = version.get('timestamp') * 1000 const size = version.has('size') ? version.get('size') : 0 const preview = OC.MimeType.getIconUrl(version.get('mimetype')) const img = new Image() img.onload = function() { $('li[data-revision=' + version.get('id') + '] .preview').attr('src', version.getPreviewUrl()) } img.src = version.getPreviewUrl() return _.extend({ versionId: version.get('id'), formattedTimestamp: OC.Util.formatDate(timestamp), relativeTimestamp: OC.Util.relativeModifiedDate(timestamp), millisecondsTimestamp: timestamp, humanReadableSize: OC.Util.humanFileSize(size, true), altSize: n('files', '%n byte', '%n bytes', size), hasDetails: version.has('size'), downloadUrl: version.getDownloadUrl(), downloadIconUrl: OC.imagePath('core', 'actions/download'), downloadName: version.get('name'), revertIconUrl: OC.imagePath('core', 'actions/history'), previewUrl: preview, revertLabel: t('files_versions', 'Restore'), canRevert: (this.collection.getFileInfo().get('permissions') & OC.PERMISSION_UPDATE) !== 0, }, version.attributes) }, /** * Renders this details view */ render() { this.$el.html(this.template({ emptyResultLabel: t('files_versions', 'No other versions available'), })) this.$el.find('.has-tooltip').tooltip() this.$versionsContainer = this.$el.find('ul.versions') this.delegateEvents() }, /** * Returns true for files, false for folders. * * @param {FileInfo} fileInfo fileInfo * @return {boolean} true for files, false for folders */ canDisplay(fileInfo) { if (!fileInfo) { return false } return !fileInfo.isDirectory() }, }) OCA.Versions = OCA.Versions || {} OCA.Versions.VersionsTabView = VersionsTabView })()