source documents editable-file ok
This commit is contained in:
		@@ -28,6 +28,7 @@ fragment EntiteFields on Entite {
 | 
			
		||||
    documents {
 | 
			
		||||
      description
 | 
			
		||||
      file {
 | 
			
		||||
        fid
 | 
			
		||||
        filemime
 | 
			
		||||
        filename
 | 
			
		||||
        url
 | 
			
		||||
 
 | 
			
		||||
@@ -1070,11 +1070,13 @@ body{
 | 
			
		||||
 | 
			
		||||
div.editable-image,
 | 
			
		||||
div.editable-video,
 | 
			
		||||
div.editable-audios{
 | 
			
		||||
div.editable-audios,
 | 
			
		||||
ul.editable-files{
 | 
			
		||||
  background: #eee;
 | 
			
		||||
  max-width: 100%;
 | 
			
		||||
  div.file-btn{
 | 
			
		||||
    border: #eee 2px solid;
 | 
			
		||||
    background-color: #eee;
 | 
			
		||||
    border-radius: 5px;
 | 
			
		||||
    margin: 1em 0 0;
 | 
			
		||||
    font-size: 1em;
 | 
			
		||||
@@ -1148,4 +1150,38 @@ li.link-editable{
 | 
			
		||||
  div.delete-btn{
 | 
			
		||||
    flex: 0 0 auto;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
ul.editable-files{
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  li.file-editable{
 | 
			
		||||
    // background-color: #eee;
 | 
			
		||||
    // border: #eee 2px solid;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
    margin: 0.5em 0!important;
 | 
			
		||||
    gap: 0.5em;
 | 
			
		||||
    >input{
 | 
			
		||||
      background-color: #eee;
 | 
			
		||||
      border: #eee 2px solid;
 | 
			
		||||
      overflow: hidden;
 | 
			
		||||
      text-wrap:nowrap;
 | 
			
		||||
      width: 40%;
 | 
			
		||||
      flex: 0 1 auto;
 | 
			
		||||
      font-size: 0.756em;
 | 
			
		||||
      &:focus{
 | 
			
		||||
        outline: none;
 | 
			
		||||
        border: #01ffe2 2px solid;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    >div.filename{
 | 
			
		||||
      width:40%;
 | 
			
		||||
      flex: 1 0 auto;
 | 
			
		||||
      font-size: 0.756em;
 | 
			
		||||
    }
 | 
			
		||||
    >div.delete-btn{
 | 
			
		||||
      flex: 0 0 auto;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -11,6 +11,7 @@ import ImageEditable from '@components/editable/ImageEditable.vue';
 | 
			
		||||
import VideoEditable from '@components/editable/VideoEditable.vue';
 | 
			
		||||
import AudioEditable from '@components/editable/AudioEditable.vue';
 | 
			
		||||
import LinkEditable from '@components/editable/LinkEditable.vue';
 | 
			
		||||
import FileEditable from '@components/editable/FileEditable.vue';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  props: ['concernement', 'entite', "eid", 'source'],
 | 
			
		||||
@@ -45,7 +46,8 @@ export default {
 | 
			
		||||
    ImageEditable,
 | 
			
		||||
    VideoEditable,
 | 
			
		||||
    AudioEditable,
 | 
			
		||||
    LinkEditable
 | 
			
		||||
    LinkEditable,
 | 
			
		||||
    FileEditable
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
@@ -141,20 +143,34 @@ export default {
 | 
			
		||||
            field_name: 'field_liens'
 | 
			
		||||
          }
 | 
			
		||||
        }"
 | 
			
		||||
        label="Liens"
 | 
			
		||||
        v-on:updated="reloadEntite "/>
 | 
			
		||||
    </section>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <section
 | 
			
		||||
      v-if="source.documents.length"
 | 
			
		||||
      class="documents multiple">
 | 
			
		||||
        <a
 | 
			
		||||
    <!-- v-if="source.documents.length" -->
 | 
			
		||||
    <section class="documents multiple">
 | 
			
		||||
        <!-- <a
 | 
			
		||||
          v-for="(doc,d) in source.documents"
 | 
			
		||||
          :key="d"
 | 
			
		||||
          :href="doc.file.url">
 | 
			
		||||
          <template v-if="doc.description">{{ doc.description }}</template>
 | 
			
		||||
          <template v-else>{{ doc.file.url }}</template>
 | 
			
		||||
        </a>
 | 
			
		||||
        </a> -->
 | 
			
		||||
        <FileEditable
 | 
			
		||||
          :can_update="entite.can_update"
 | 
			
		||||
          :files="source.documents"
 | 
			
		||||
          :data="{
 | 
			
		||||
            entitytype: 'paragraph',
 | 
			
		||||
            bundle: 'source',
 | 
			
		||||
            id: this.source.id,
 | 
			
		||||
            uuid: this.source.uuid,
 | 
			
		||||
            field: {
 | 
			
		||||
              field_name: 'field_documents'
 | 
			
		||||
            }
 | 
			
		||||
          }"
 | 
			
		||||
          label="Documents"
 | 
			
		||||
          v-on:updated="reloadEntite "/>
 | 
			
		||||
    </section>
 | 
			
		||||
      
 | 
			
		||||
  </section>
 | 
			
		||||
 
 | 
			
		||||
@@ -163,7 +163,7 @@ export default {
 | 
			
		||||
        <svg-icon type="mdi" :path="mdiTrashCanOutline_path" />
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
    <!-- with out img -->
 | 
			
		||||
    <!-- with out audio -->
 | 
			
		||||
    <template v-else-if="can_update">
 | 
			
		||||
      <div @click="addAudio" class="file-btn">
 | 
			
		||||
        <svg-icon type="mdi" :path="mdiMusicNotePlus_path"/>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										192
									
								
								src/components/editable/FileEditable.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								src/components/editable/FileEditable.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,192 @@
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
import JSONAPI from '@api/json-axios'
 | 
			
		||||
import REST from '@api/rest-axios'
 | 
			
		||||
 | 
			
		||||
import { mapActions, mapState } from 'pinia'
 | 
			
		||||
import { ConcernementsStore } from '@stores/concernements'
 | 
			
		||||
import { UserStore } from '@stores/user'
 | 
			
		||||
 | 
			
		||||
import ContentEditable from '@components/editable/ContentEditable.vue';
 | 
			
		||||
 | 
			
		||||
import SvgIcon from '@jamescoyle/vue-icon';
 | 
			
		||||
import { mdiTrashCanOutline } from '@mdi/js';
 | 
			
		||||
import { mdiFilePlusOutline } from '@mdi/js';
 | 
			
		||||
 | 
			
		||||
import { nextTick } from 'vue'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  props: {
 | 
			
		||||
    can_update: Boolean,
 | 
			
		||||
    files: Object,
 | 
			
		||||
    data: Object,
 | 
			
		||||
    label: String,
 | 
			
		||||
  },
 | 
			
		||||
  emits: ['updated'],
 | 
			
		||||
  data(){
 | 
			
		||||
    return {
 | 
			
		||||
      mdiTrashCanOutline_path: mdiTrashCanOutline,
 | 
			
		||||
      mdiFilePlusOutline_path: mdiFilePlusOutline,
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(UserStore,['csrf_token']),
 | 
			
		||||
  },
 | 
			
		||||
  created () {
 | 
			
		||||
    console.log('ImageEditable created')
 | 
			
		||||
  },
 | 
			
		||||
  mounted () {
 | 
			
		||||
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapActions(ConcernementsStore, ['reloadConcernements']),
 | 
			
		||||
    addFile(e){
 | 
			
		||||
      console.log('addFile', this.$refs);
 | 
			
		||||
      this.$refs.file_input.click();
 | 
			
		||||
    },
 | 
			
		||||
    onInputNewfile(e){
 | 
			
		||||
      console.log('onFileInput', e);
 | 
			
		||||
      let file = e.target.files[0];
 | 
			
		||||
      console.log('onFileInput file', file);
 | 
			
		||||
      this.saveNewFile(file);
 | 
			
		||||
    },
 | 
			
		||||
    saveNewFile(file){
 | 
			
		||||
      const configs = {
 | 
			
		||||
        headers: {
 | 
			
		||||
          'X-CSRF-Token': this.csrf_token,
 | 
			
		||||
          'Content-Type': 'application/octet-stream',
 | 
			
		||||
          'Content-Disposition': `file; filename="${file.name}"`,
 | 
			
		||||
        },
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      JSONAPI.post(`/${this.data.entitytype}/${this.data.bundle}/${this.data.uuid}/${this.data.field.field_name}`, file, configs)
 | 
			
		||||
        .then(({ data : { data } }) => {
 | 
			
		||||
          console.log('jsonapi post file', data)
 | 
			
		||||
          this.$emit('updated');
 | 
			
		||||
        })
 | 
			
		||||
        .catch(error => {
 | 
			
		||||
          console.warn('Issue with jsonapi post file', error)
 | 
			
		||||
          Promise.reject(error)
 | 
			
		||||
        })
 | 
			
		||||
    },
 | 
			
		||||
    onFocusOut(e){
 | 
			
		||||
      console.log('onfocusOut', e, this.$refs.file_list);
 | 
			
		||||
      this.buildFileListThenSaveList();
 | 
			
		||||
    },
 | 
			
		||||
    buildFileListThenSaveList(force_Save){
 | 
			
		||||
      console.log('buildLinkListThenSave files', this.files);
 | 
			
		||||
      // build links list
 | 
			
		||||
      let list = [];
 | 
			
		||||
      let tobesaved = false;
 | 
			
		||||
      for (let i = 0; i < this.$refs.file_list.children.length; i++) {
 | 
			
		||||
        const $li = this.$refs.file_list.children[i];
 | 
			
		||||
        console.log('$li', $li);
 | 
			
		||||
        if ($li.querySelector('input.description')) {
 | 
			
		||||
          let description = $li.querySelector('input.description').value;
 | 
			
		||||
          list.push({
 | 
			
		||||
            description: description,
 | 
			
		||||
            target_id: this.files[i].file.fid
 | 
			
		||||
          });
 | 
			
		||||
          tobesaved = (description !== this.files[i].description);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (!tobesaved) {
 | 
			
		||||
        tobesaved = this.files.length !== list.length;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (tobesaved || force_Save) {
 | 
			
		||||
        this.saveList(list);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    saveList(list){
 | 
			
		||||
      console.log('saveList list', list);
 | 
			
		||||
      const params = {
 | 
			
		||||
        type: this.data.bundle,
 | 
			
		||||
        [this.data.field.field_name]: list
 | 
			
		||||
      };
 | 
			
		||||
      if (this.data.entitytype === 'node') {
 | 
			
		||||
        params.nid = [{"value":this.data.id}];
 | 
			
		||||
      } else {
 | 
			
		||||
        params.id = [{"value":this.data.id}];
 | 
			
		||||
      }
 | 
			
		||||
      // // we need additional values for image alt for example
 | 
			
		||||
      // // console.log('additional_values', this.data.field.additional_values);
 | 
			
		||||
      // if (this.data.field.additional_values) {
 | 
			
		||||
      //   for (const key in this.data.field.additional_values) {
 | 
			
		||||
      //     if (Object.hasOwnProperty.call(this.data.field.additional_values, key)) {
 | 
			
		||||
      //       params[this.data.field.field_name][0][key] = this.data.field.additional_values[key]
 | 
			
		||||
      //     }
 | 
			
		||||
      //   }
 | 
			
		||||
      // }
 | 
			
		||||
      
 | 
			
		||||
      const configs = {
 | 
			
		||||
        headers: {'X-CSRF-Token': this.csrf_token}
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      // url is not the same between nodes and others entities
 | 
			
		||||
      let url_base = `/${this.data.entitytype === 'node' ? '' : 'entity/'}${this.data.entitytype}`;
 | 
			
		||||
      // call the api
 | 
			
		||||
      REST.patch(`${url_base}/${this.data.id}?_format=json`, params, configs)
 | 
			
		||||
        .then(({ data }) => {
 | 
			
		||||
          console.log('user REST post node data', data)
 | 
			
		||||
          this.$emit('updated');
 | 
			
		||||
        })
 | 
			
		||||
        .catch(error => {
 | 
			
		||||
          console.warn(`Issue with patch ${this.data.entitytype} ${this.data.bundle}`, error)
 | 
			
		||||
          Promise.reject(error)
 | 
			
		||||
        })
 | 
			
		||||
    },
 | 
			
		||||
    async onDeleteFile(i){
 | 
			
		||||
      console.log(`onDeleteLink ${i}`, this.$refs.file_list.children[i]);
 | 
			
		||||
      // this.links_nb = this.$refs.links_list.children.length;
 | 
			
		||||
      // this.$refs.links_list.children[i].remove();
 | 
			
		||||
      this.files.splice(i,1);
 | 
			
		||||
      await nextTick();
 | 
			
		||||
      this.buildFileListThenSaveList(true);
 | 
			
		||||
    },
 | 
			
		||||
    onUpdated(){
 | 
			
		||||
      this.$emit('updated');
 | 
			
		||||
    },
 | 
			
		||||
    fileMime(mime){
 | 
			
		||||
      return mime.replace('application/', '');
 | 
			
		||||
    },
 | 
			
		||||
    docLabel(doc){
 | 
			
		||||
      return doc.description ? doc.description : doc.file.filename;
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  components: {
 | 
			
		||||
    SvgIcon,
 | 
			
		||||
    ContentEditable
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <label>{{ label }}</label>
 | 
			
		||||
  <ul ref="file_list" class="editable-files" :class="{'can-update': can_update}">
 | 
			
		||||
    <li v-for="(doc,d) in files" :key="d" class="file-editable">
 | 
			
		||||
      <template v-if="!can_update">
 | 
			
		||||
        <a
 | 
			
		||||
          :href="doc.file.url"
 | 
			
		||||
          target="_blank"
 | 
			
		||||
        >
 | 
			
		||||
          {{ docLabel(doc) }} [{{ fileMime(doc.file.filemime) }}]
 | 
			
		||||
        </a>  
 | 
			
		||||
      </template>
 | 
			
		||||
      <template v-else>
 | 
			
		||||
        <input type="text" class="description" :value="doc.description" placeholder="Description du fichier" @focusout="onFocusOut" />
 | 
			
		||||
        <!-- <input type="text" class="url" :value="link.url" @focusout="onFocusOut" placeholder="Url du lien" /> -->
 | 
			
		||||
        <div class="filename">{{ doc.file.filename }}</div>
 | 
			
		||||
        <div @click="onDeleteFile(d)" class="delete-btn">
 | 
			
		||||
          <svg-icon type="mdi" :path="mdiTrashCanOutline_path" />
 | 
			
		||||
        </div>
 | 
			
		||||
      </template>
 | 
			
		||||
    </li>
 | 
			
		||||
    <li v-if="can_update">
 | 
			
		||||
      <div @click="addFile" class="file-btn">
 | 
			
		||||
        <svg-icon type="mdi" :path="mdiFilePlusOutline_path"/>
 | 
			
		||||
      </div>
 | 
			
		||||
      <input ref="file_input" type="file" accept="application/txt, application/pdf, application/doc, application/docx, application/obs, application/xls"   @input="onInputNewfile"/>
 | 
			
		||||
    </li>
 | 
			
		||||
  </ul>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -20,7 +20,8 @@ export default {
 | 
			
		||||
  props: {
 | 
			
		||||
    can_update: Boolean,
 | 
			
		||||
    links: Array,
 | 
			
		||||
    data: Object
 | 
			
		||||
    data: Object,
 | 
			
		||||
    label: String
 | 
			
		||||
  },
 | 
			
		||||
  emits: ['updated'],
 | 
			
		||||
  data(){
 | 
			
		||||
@@ -121,15 +122,15 @@ export default {
 | 
			
		||||
          console.warn(`Issue with patch ${this.data.entitytype} ${this.data.bundle}`, error)
 | 
			
		||||
          Promise.reject(error)
 | 
			
		||||
        })
 | 
			
		||||
    },
 | 
			
		||||
    async onDeleteLink(i){
 | 
			
		||||
      console.log(`onDeleteLink ${i}`, this.$refs.links_list.children[i]);
 | 
			
		||||
      // this.links_nb = this.$refs.links_list.children.length;
 | 
			
		||||
      // this.$refs.links_list.children[i].remove();
 | 
			
		||||
      this.links.splice(i,1);
 | 
			
		||||
      await nextTick();
 | 
			
		||||
      this.buildLinkListThenSave(true);
 | 
			
		||||
    }
 | 
			
		||||
      },
 | 
			
		||||
      async onDeleteLink(i){
 | 
			
		||||
        console.log(`onDeleteLink ${i}`, this.$refs.links_list.children[i]);
 | 
			
		||||
        // this.links_nb = this.$refs.links_list.children.length;
 | 
			
		||||
        // this.$refs.links_list.children[i].remove();
 | 
			
		||||
        this.links.splice(i,1);
 | 
			
		||||
        await nextTick();
 | 
			
		||||
        this.buildLinkListThenSave(true);
 | 
			
		||||
      }
 | 
			
		||||
  },
 | 
			
		||||
  components: {
 | 
			
		||||
    SvgIcon,
 | 
			
		||||
@@ -140,6 +141,7 @@ export default {
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <label>{{ label }}</label>
 | 
			
		||||
  <ul ref="links_list">
 | 
			
		||||
    <li v-for="(link, l) in links" :key="l" :class="{'link-editable':can_update}">
 | 
			
		||||
      <!-- link exists can't update -->
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user