mirror of
				https://github.com/scinote-eln/scinote-web.git
				synced 2025-10-25 13:37:12 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			214 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <div class="step-attachments">
 | |
|     <div class="attachments-actions">
 | |
|       <div class="title">
 | |
|         <h3>{{ i18n.t('protocols.steps.files', {count: attachments.length}) }}</h3>
 | |
|       </div>
 | |
|       <div class="actions" v-if="step.attributes.attachments_manageble && attachmentsReady">
 | |
|         <div ref="actionsDropdownButton" class="dropdown sci-dropdown">
 | |
|           <button class="btn btn-light dropdown-toggle" type="button" id="dropdownAttachmentsOptions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
 | |
|             <span>{{ i18n.t("protocols.steps.attachments.manage") }}</span>
 | |
|             <span class="caret pull-right"></span>
 | |
|           </button>
 | |
|           <ul ref="actionsDropdown" class="dropdown-menu dropdown-menu-right dropdown-attachment-options"
 | |
|               aria-labelledby="dropdownAttachmentsOptions"
 | |
|               :data-step-id="step.id"
 | |
|           >
 | |
|             <li class="divider-label">{{ i18n.t("protocols.steps.attachments.add") }}</li>
 | |
|             <li>
 | |
|               <a class="action-link attachments-view-mode" @click="$emit('attachments:openFileModal')">
 | |
|                 <i class="fas fa-upload"></i>
 | |
|                 {{ i18n.t('protocols.steps.attachments.menu.file_from_pc') }}
 | |
|               </a>
 | |
|             </li>
 | |
|             <li v-if="step.attributes.wopi_enabled">
 | |
|               <a @click="openWopiFileModal" class="create-wopi-file-btn" tabindex="0" @keyup.enter="openWopiFileModal">
 | |
|                 <img :src="step.attributes.wopi_context.icon"/>
 | |
|                 {{ i18n.t('protocols.steps.attachments.menu.office_file') }}
 | |
|               </a>
 | |
|             </li>
 | |
|             <li v-if="step.attributes.marvinjs_enabled">
 | |
|               <a
 | |
|                 class="new-marvinjs-upload-button"
 | |
|                 :data-object-id="step.id"
 | |
|                 data-object-type="Step"
 | |
|                 :data-marvin-url="step.attributes.marvinjs_context.marvin_js_asset_url"
 | |
|                 :data-sketch-container="`.attachments[data-step-id=${step.id}]`"
 | |
|               >
 | |
|                 <span class="new-marvinjs-upload-icon">
 | |
|                   <img v-bind:src="marvinjsIcon">
 | |
|                 </span>
 | |
|                   {{ i18n.t('protocols.steps.attachments.menu.chemical_drawing') }}
 | |
|               </a>
 | |
|             </li>
 | |
|             <li v-if="step.attributes.bio_eddie_service_enabled">
 | |
|               <a
 | |
|                 class="new-bio-eddie-upload-button"
 | |
|                 :data-object-id="step.id"
 | |
|                 data-object-type="Step"
 | |
|                 :data-assets-container="`.attachments[data-step-id=${step.id}]`"
 | |
|               >
 | |
|                 <img v-bind:src="bioEddieIcon">
 | |
|                 {{ i18n.t('bio_eddie.new_button') }}
 | |
|               </a>
 | |
|             </li>
 | |
|             <li role="separator" class="divider"></li>
 | |
|             <li class="divider-label">{{ i18n.t("protocols.steps.attachments.sort_by") }}</li>
 | |
|             <li v-for="(orderOption, index) in orderOptions" :key="`orderOption_${index}`">
 | |
|               <a class="action-link change-order"
 | |
|                 @click="changeAttachmentsOrder(orderOption)"
 | |
|                 :class="step.attributes.assets_order == orderOption ? 'selected' : ''"
 | |
|               >
 | |
|                 {{ i18n.t(`general.sort_new.${orderOption}`) }}
 | |
|               </a>
 | |
|             </li>
 | |
|             <template v-if="step.attributes.urls.update_asset_view_mode_url">
 | |
|               <li role="separator" class="divider"></li>
 | |
|               <li class="divider-label">{{ i18n.t("protocols.steps.attachments.attachments_view_mode") }}</li>
 | |
|               <li v-for="(viewMode, index) in viewModeOptions" :key="`viewMode_${index}`">
 | |
|                 <a
 | |
|                   class="attachments-view-mode action-link"
 | |
|                   :class="viewMode == step.attributes.assets_view_mode ? 'selected' : ''"
 | |
|                   @click="changeAttachmentsViewMode(viewMode)"
 | |
|                   v-html="i18n.t(`protocols.steps.attachments.view_mode.${viewMode}_html`)"
 | |
|                 ></a>
 | |
|               </li>
 | |
|             </template>
 | |
|           </ul>
 | |
|         </div>
 | |
|       </div>
 | |
|     </div>
 | |
|     <div class="attachments">
 | |
|       <template v-for="(attachment, index) in attachmentsOrdered">
 | |
|         <component
 | |
|           :is="attachment_view_mode(attachmentsOrdered[index])"
 | |
|           :key="attachment.id"
 | |
|           :attachment="attachment"
 | |
|           :stepId="parseInt(step.id)"
 | |
|           @attachment:viewMode="updateAttachmentViewMode"
 | |
|           @attachment:delete="deleteAttachment(attachment.id)"
 | |
|         />
 | |
|       </template>
 | |
|     </div>
 | |
|   </div>
 | |
| </template>
 | |
| <script>
 | |
|   import listAttachment from 'vue/protocol/step_attachments/list.vue'
 | |
|   import inlineAttachment from 'vue/protocol/step_attachments/inline.vue'
 | |
|   import thumbnailAttachment from 'vue/protocol/step_attachments/thumbnail.vue'
 | |
|   import uploadingAttachment from 'vue/protocol/step_attachments/uploading.vue'
 | |
|   import emptyAttachment from 'vue/protocol/step_attachments/empty.vue'
 | |
|   import marvinjsIcon from 'images/icon_small/marvinjs.svg'
 | |
|   import bioEddieIcon from 'images/icon_small/bio_eddie.png'
 | |
| 
 | |
|   import WopiFileModal from './step_attachments/mixins/wopi_file_modal.js'
 | |
| 
 | |
|   export default {
 | |
|     name: 'Attachments',
 | |
|     props: {
 | |
|       attachments: {
 | |
|         type: Array,
 | |
|         required: true
 | |
|       },
 | |
|       step: {
 | |
|         type: Object,
 | |
|         required: true
 | |
|       },
 | |
|       attachmentsReady: {
 | |
|         type: Boolean,
 | |
|         required: true
 | |
|       }
 | |
|     },
 | |
|     data() {
 | |
|       return {
 | |
|         marvinjsIcon,
 | |
|         bioEddieIcon,
 | |
|         viewModeOptions: ['inline', 'thumbnail', 'list'],
 | |
|         orderOptions: ['new', 'old', 'atoz', 'ztoa']
 | |
|       }
 | |
|     },
 | |
|     mixins: [WopiFileModal],
 | |
|     components: {
 | |
|       thumbnailAttachment,
 | |
|       inlineAttachment,
 | |
|       listAttachment,
 | |
|       uploadingAttachment,
 | |
|       emptyAttachment
 | |
|     },
 | |
|     computed: {
 | |
|       attachmentsOrdered() {
 | |
|         return this.attachments.sort((a, b) => {
 | |
|           if (a.attributes.asset_order == b.attributes.asset_order) {
 | |
|             switch(this.step.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;
 | |
|         })
 | |
|       }
 | |
|     },
 | |
|     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(
 | |
|           `#stepContainer${this.step.id} .new-marvinjs-upload-button`,
 | |
|           () => this.$emit('attachment:uploaded')
 | |
|         );
 | |
|       },
 | |
|       openWopiFileModal() {
 | |
|         this.initWopiFileModal(this.step, (_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>
 |