<template> <div class="content__attachments" :id='"content__attachments-" + parent.id'> <div class="border-0 border-b border-dashed border-sn-light-grey my-6"></div> <div class="content__attachments-actions"> <div class="title"> {{ i18n.t('protocols.steps.files', {count: attachments.length}) }} </div> <div class="flex items-center gap-2" v-if="parent.attributes.attachments_manageble && attachmentsReady"> <MenuDropdown :listItems="this.viewModeMenu" :btnText="i18n.t('attachments.preview_menu')" :position="'right'" :caret="true" @attachment:viewMode = "changeAttachmentsViewMode" ></MenuDropdown> <MenuDropdown :listItems="this.sortMenu" :btnIcon="'sn-icon sn-icon-sort-down'" :btnClasses="'btn btn-light icon-btn'" :position="'right'" @attachment:order = "changeAttachmentsOrder" ></MenuDropdown> </div> </div> <div class="attachments" :data-parent-id="parent.id"> <component v-for="(attachment, index) in attachmentsOrdered" :key="attachment.id" :is="attachment_view_mode(attachmentsOrdered[index])" :attachment="attachment" :parentId="parseInt(parent.id)" @attachment:viewMode="updateAttachmentViewMode" @attachment:delete="deleteAttachment(attachment.id)" @attachment:moved="attachmentMoved" /> </div> </div> </template> <script> import AttachmentMovedMixin from './attachments/mixins/attachment_moved.js' import listAttachment from './attachments/list.vue' import inlineAttachment from './attachments/inline.vue' import thumbnailAttachment from './attachments/thumbnail.vue' import uploadingAttachment from './attachments/uploading.vue' import emptyAttachment from './attachments/empty.vue' import MenuDropdown from '../menu_dropdown.vue' import WopiFileModal from './attachments/mixins/wopi_file_modal.js' export default { name: 'Attachments', props: { attachments: { type: Array, required: true }, parent: { type: Object, required: true }, attachmentsReady: { type: Boolean, required: true } }, data() { return { viewModeOptions: ['inline', 'thumbnail', 'list'], orderOptions: ['new', 'old', 'atoz', 'ztoa'] } }, mixins: [WopiFileModal, AttachmentMovedMixin], components: { thumbnailAttachment, inlineAttachment, listAttachment, uploadingAttachment, emptyAttachment, MenuDropdown }, watch: { attachmentsReady() { if (this.attachmentsReady) { this.$nextTick(() => { this.initMarvinJS(); }) } } }, computed: { attachmentsOrdered() { return this.attachments.sort((a, b) => { if (a.attributes.asset_order == b.attributes.asset_order) { switch(this.parent.attributes.assets_order) { case 'new': return b.attributes.updated_at - a.attributes.updated_at; case 'old': return a.attributes.updated_at - b.attributes.updated_at; case 'atoz': return a.attributes.file_name.toLowerCase() > b.attributes.file_name.toLowerCase() ? 1 : -1; case 'ztoa': return b.attributes.file_name.toLowerCase() > a.attributes.file_name.toLowerCase() ? 1 : -1; } } return a.attributes.asset_order > b.attributes.asset_order ? 1 : -1; }) }, viewModeMenu() { let menu = []; this.viewModeOptions.forEach((viewMode) => { menu.push({ text: this.i18n.t(`attachments.view_mode.${viewMode}_html`), emit: 'attachment:viewMode', params: viewMode }) }) return menu; }, sortMenu() { let menu = []; this.orderOptions.forEach((orderOption, i) => { menu.push({ text: this.i18n.t(`general.sort_new.${orderOption}`), emit: 'attachment:order', params: orderOption, dividerBefore: i === 2 }) }) return menu; } }, mounted() { this.initMarvinJS(); $(this.$refs.actionsDropdownButton).on('shown.bs.dropdown hidden.bs.dropdown', this.handleDropdownPosition); }, methods: { changeAttachmentsOrder(order) { this.$emit('attachments:order', order) }, changeAttachmentsViewMode(viewMode) { this.$emit('attachments:viewMode', viewMode) }, updateAttachmentViewMode(id, viewMode) { this.$emit('attachment:viewMode', id, viewMode) }, attachment_view_mode(attachment) { if (attachment.attributes.uploading) { return 'uploadingAttachment' } else if (!attachment.attributes.attached) { return 'emptyAttachment' } return `${attachment.attributes.view_mode}Attachment` }, deleteAttachment(id) { this.$emit('attachment:deleted', id) }, initMarvinJS() { // legacy logic from app/assets/javascripts/sitewide/marvinjs_editor.js MarvinJsEditor.initNewButton( `#content__attachments-${this.parent.id} .new-marvinjs-upload-button`, () => this.$emit('attachment:uploaded') ); }, openWopiFileModal() { this.initWopiFileModal(this.parent, (_e, data, status) => { if (status === 'success') { this.$emit('attachment:uploaded', data); } else { HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger'); } }); }, handleDropdownPosition() { this.$refs.actionsDropdownButton.classList.toggle("dropup", !this.isInViewport(this.$refs.actionsDropdown)); }, isInViewport(el) { let rect = el.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || $(window).height()) && rect.right <= (window.innerWidth || $(window).width()) ); }, } } </script>