paragraphe source field_liens editable (mutliple)
This commit is contained in:
		@@ -1118,4 +1118,34 @@ div.editable-audios{
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
li.link-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%;
 | 
			
		||||
    &:focus{
 | 
			
		||||
      outline: none;
 | 
			
		||||
      border: #01ffe2 2px solid;
 | 
			
		||||
    }
 | 
			
		||||
    &.title{
 | 
			
		||||
      flex: 0 0 auto;
 | 
			
		||||
    }
 | 
			
		||||
    &.url{
 | 
			
		||||
      flex: 1 0 auto;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  div.delete-btn{
 | 
			
		||||
    flex: 0 0 auto;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -10,6 +10,7 @@ import CheckboxEditable from '@components/editable/CheckboxEditable.vue';
 | 
			
		||||
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';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  props: ['concernement', 'entite', "eid", 'source'],
 | 
			
		||||
@@ -44,6 +45,7 @@ export default {
 | 
			
		||||
    ImageEditable,
 | 
			
		||||
    VideoEditable,
 | 
			
		||||
    AudioEditable,
 | 
			
		||||
    LinkEditable
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
@@ -108,17 +110,6 @@ export default {
 | 
			
		||||
    <!-- v-if="source.audios.length" -->
 | 
			
		||||
    <section
 | 
			
		||||
      class="audio">
 | 
			
		||||
        <!-- <div
 | 
			
		||||
            v-for="(audio,a) in source.audios"
 | 
			
		||||
            :key="a">
 | 
			
		||||
          <label v-if="audio.description">{{ audio.description }}</label>
 | 
			
		||||
          <label v-else>{{ audio.file.filename }}</label>
 | 
			
		||||
          <vue-plyr  :options="plyr_options">
 | 
			
		||||
              <audio>
 | 
			
		||||
                <source :src="audio.file.url" :type="audio.file.filemime" />
 | 
			
		||||
              </audio>
 | 
			
		||||
          </vue-plyr>
 | 
			
		||||
        </div> -->
 | 
			
		||||
 | 
			
		||||
      <AudioEditable
 | 
			
		||||
        :can_update="entite.can_update"
 | 
			
		||||
@@ -136,20 +127,21 @@ export default {
 | 
			
		||||
        v-on:updated="reloadEntite"/>
 | 
			
		||||
    </section>
 | 
			
		||||
 | 
			
		||||
    <section
 | 
			
		||||
      v-if="source.liens.length"
 | 
			
		||||
      class="liens multiple">
 | 
			
		||||
      <ul>
 | 
			
		||||
        <li
 | 
			
		||||
          v-for="(lien,l) in source.liens"
 | 
			
		||||
          :key="l">
 | 
			
		||||
          <a
 | 
			
		||||
          :href="lien.url">
 | 
			
		||||
          {{ lien.title }}
 | 
			
		||||
        </a>
 | 
			
		||||
        </li>
 | 
			
		||||
      </ul>
 | 
			
		||||
        
 | 
			
		||||
    <!-- v-if="source.liens.length" -->
 | 
			
		||||
    <section class="liens multiple">
 | 
			
		||||
      <LinkEditable 
 | 
			
		||||
        :can_update="entite.can_update"
 | 
			
		||||
        :links="source.liens"
 | 
			
		||||
        :data="{
 | 
			
		||||
          entitytype: 'paragraph',
 | 
			
		||||
          bundle: 'source',
 | 
			
		||||
          id: this.source.id,
 | 
			
		||||
          uuid: this.source.uuid,
 | 
			
		||||
          field: {
 | 
			
		||||
            field_name: 'field_liens'
 | 
			
		||||
          }
 | 
			
		||||
        }"
 | 
			
		||||
        v-on:updated="reloadEntite "/>
 | 
			
		||||
    </section>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -84,12 +84,12 @@ export default {
 | 
			
		||||
        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)
 | 
			
		||||
          // TODO if success update the data in pinia 
 | 
			
		||||
          // this.reloadConcernements();
 | 
			
		||||
          this.$emit('updated');
 | 
			
		||||
        })
 | 
			
		||||
        .catch(error => {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										176
									
								
								src/components/editable/LinkEditable.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								src/components/editable/LinkEditable.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,176 @@
 | 
			
		||||
<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 { mdiMusicNotePlus } from '@mdi/js';
 | 
			
		||||
import { mdiLinkVariantPlus } from '@mdi/js';
 | 
			
		||||
 | 
			
		||||
import { nextTick } from 'vue'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  props: {
 | 
			
		||||
    can_update: Boolean,
 | 
			
		||||
    links: Array,
 | 
			
		||||
    data: Object
 | 
			
		||||
  },
 | 
			
		||||
  emits: ['updated'],
 | 
			
		||||
  data(){
 | 
			
		||||
    return {
 | 
			
		||||
      mdiTrashCanOutline_path: mdiTrashCanOutline,
 | 
			
		||||
      mdiMusicNotePlus_path: mdiMusicNotePlus,
 | 
			
		||||
      mdiLinkVariantPlus_path: mdiLinkVariantPlus,
 | 
			
		||||
      // links_nb : 0
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(UserStore,['csrf_token']),
 | 
			
		||||
  },
 | 
			
		||||
  created () {
 | 
			
		||||
    console.log('LinkEditable created', this.links);
 | 
			
		||||
    // this.links_nb = this.links.length;
 | 
			
		||||
  },
 | 
			
		||||
  beforeUpdate() {
 | 
			
		||||
    console.log('LinkEditable beforeUpdate', this.links);
 | 
			
		||||
  },
 | 
			
		||||
  updated() {
 | 
			
		||||
    console.log('LinkEditable updated', this.links, this.$refs.links_list);
 | 
			
		||||
    this.$refs.links_list.lastChild.querySelector('input.new.title').value = null;
 | 
			
		||||
    this.$refs.links_list.lastChild.querySelector('input.new.url').value = null;
 | 
			
		||||
  },
 | 
			
		||||
  mounted () {
 | 
			
		||||
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapActions(ConcernementsStore, ['reloadConcernements']),
 | 
			
		||||
    // addLink(e){
 | 
			
		||||
    //   console.log('addLink');
 | 
			
		||||
    //   this.links_nb++;
 | 
			
		||||
    // },
 | 
			
		||||
    onFocusOut(e){
 | 
			
		||||
      console.log('onfocusOut', e, this.$refs.links_list);
 | 
			
		||||
      this.buildLinkListThenSave();
 | 
			
		||||
    },
 | 
			
		||||
    buildLinkListThenSave(force_Save){
 | 
			
		||||
      console.log('buildLinkListThenSave links', this.links);
 | 
			
		||||
      // build links list
 | 
			
		||||
      let list = [];
 | 
			
		||||
      let tobesaved = false;
 | 
			
		||||
      for (let i = 0; i < this.$refs.links_list.children.length; i++) {
 | 
			
		||||
        const $li = this.$refs.links_list.children[i];
 | 
			
		||||
        if ($li.querySelector('input.url').value) {
 | 
			
		||||
          let title = $li.querySelector('input.title').value;
 | 
			
		||||
          let url = $li.querySelector('input.url').value; 
 | 
			
		||||
          list.push({
 | 
			
		||||
            title: title,
 | 
			
		||||
            uri: url
 | 
			
		||||
          });
 | 
			
		||||
          tobesaved = (typeof this.links[i] === 'undefined' || title !== this.links[i].title || url !== this.links[i].url);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (!tobesaved) {
 | 
			
		||||
        tobesaved = this.links.length !== list.length;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (tobesaved || force_Save) {
 | 
			
		||||
        this.save(list);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    save(list){
 | 
			
		||||
      console.log('save 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 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,
 | 
			
		||||
    ContentEditable
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <ul ref="links_list">
 | 
			
		||||
    <li v-for="(link, l) in links" :key="l" :class="{'link-editable':can_update}">
 | 
			
		||||
      <!-- link exists can't update -->
 | 
			
		||||
      <template v-if="!can_update">
 | 
			
		||||
        <a :href="link.url">
 | 
			
		||||
          {{ link.title }}
 | 
			
		||||
        </a>
 | 
			
		||||
      </template>
 | 
			
		||||
      <!-- link exists and can update -->
 | 
			
		||||
      <template v-else>
 | 
			
		||||
        <input type="text" class="title" :value="link.title" placeholder="Titre du lien" @focusout="onFocusOut" />
 | 
			
		||||
        <input type="text" class="url" :value="link.url" @focusout="onFocusOut" placeholder="Url du lien" />
 | 
			
		||||
        <div @click="onDeleteLink(l)" class="delete-btn">
 | 
			
		||||
          <svg-icon type="mdi" :path="mdiTrashCanOutline_path" />
 | 
			
		||||
        </div>
 | 
			
		||||
      </template>
 | 
			
		||||
      <!-- link does not exists yet and can create -->
 | 
			
		||||
    </li>
 | 
			
		||||
    <li v-if="can_update" class="link-editable">
 | 
			
		||||
      <input type="text" class="new title" placeholder="Titre du lien" @focusout="onFocusOut" />
 | 
			
		||||
      <input type="text" class="new url" placeholder="https://..." @focusout="onFocusOut" />
 | 
			
		||||
      <div class="delete-btn">
 | 
			
		||||
        <svg-icon type="mdi" />
 | 
			
		||||
      </div>
 | 
			
		||||
    </li>
 | 
			
		||||
  </ul>
 | 
			
		||||
  <!-- <div v-if="can_update" @click="addLink(i)" class="add-btn">
 | 
			
		||||
    <svg-icon type="mdi" :path="mdiLinkVariantPlus_path" />
 | 
			
		||||
  </div> -->
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
 | 
			
		||||
</style>
 | 
			
		||||
		Reference in New Issue
	
	Block a user