Browse Source

paragraphe source field_liens editable (mutliple)

bach 4 weeks ago
parent
commit
34a0ec18e0

+ 30 - 0
src/assets/main.scss

@@ -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;
+  }
 }

+ 17 - 25
src/components/contents/Source.vue

@@ -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>
 
 

+ 2 - 2
src/components/editable/ContentEditable.vue

@@ -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 - 0
src/components/editable/LinkEditable.vue

@@ -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>