VideoEditable.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. <script>
  2. import JSONAPI from '@api/json-axios'
  3. import REST from '@api/rest-axios'
  4. import { mapActions, mapState } from 'pinia'
  5. import { ConcernementsStore } from '@stores/concernements'
  6. import { UserStore } from '@stores/user'
  7. import ContentEditable from '@components/editable/ContentEditable.vue';
  8. import SvgIcon from '@jamescoyle/vue-icon';
  9. import { mdiTrashCanOutline } from '@mdi/js';
  10. import { mdiMovieOpenPlusOutline } from '@mdi/js';
  11. export default {
  12. props: {
  13. can_update: Boolean,
  14. video: Object,
  15. data: Object
  16. },
  17. emits: ['updated'],
  18. data(){
  19. return {
  20. mdiTrashCanOutline_path: mdiTrashCanOutline,
  21. mdiMovieOpenPlusOutline_path: mdiMovieOpenPlusOutline,
  22. plyr_options: {
  23. controls: ['play', 'progress', 'current-time', 'mute', 'volume']
  24. }
  25. }
  26. },
  27. computed: {
  28. ...mapState(UserStore,['csrf_token']),
  29. },
  30. created () {
  31. console.log('VideoEditable created');
  32. },
  33. mounted () {
  34. },
  35. methods: {
  36. ...mapActions(ConcernementsStore, ['reloadConcernements']),
  37. // addImage(e){
  38. // console.log('addImage', this.$refs);
  39. // this.$refs.image_input.click();
  40. // },
  41. onSaveVideoLink(e){
  42. console.log('onSaveVideoLink', e);
  43. let url = this.$refs.video_link_input.innerText;
  44. console.log('onSaveVideoLink url', url);
  45. this.save(url);
  46. },
  47. save(content){
  48. // console.log('save csrf_token', this.csrf_token);
  49. const params = {
  50. type: this.data.bundle,
  51. [this.data.field.field_name]: [{[this.data.field.value]: content}]
  52. };
  53. if (this.data.entitytype === 'node') {
  54. params.nid = [{"value":this.data.id}];
  55. } else {
  56. params.id = [{"value":this.data.id}];
  57. }
  58. // we need additional values for image alt for example
  59. // console.log('additional_values', this.data.field.additional_values);
  60. if (this.data.field.additional_values) {
  61. for (const key in this.data.field.additional_values) {
  62. if (Object.hasOwnProperty.call(this.data.field.additional_values, key)) {
  63. params[this.data.field.field_name][0][key] = this.data.field.additional_values[key]
  64. }
  65. }
  66. }
  67. const configs = {
  68. headers: {'X-CSRF-Token': this.csrf_token}
  69. };
  70. let url_base = `/${this.data.entitytype === 'node' ? '' : 'entity/'}${this.data.entitytype}`;
  71. REST.patch(`${url_base}/${this.data.id}?_format=json`, params, configs)
  72. .then(({ data }) => {
  73. console.log('user REST post node data', data)
  74. // TODO if success update the data in pinia
  75. // this.reloadConcernements();
  76. this.$emit('updated');
  77. })
  78. .catch(error => {
  79. console.warn(`Issue with patch ${this.data.entitytype} ${this.data.bundle}`, error)
  80. Promise.reject(error)
  81. })
  82. },
  83. onDeleteVideo(e){
  84. console.log('onDeleteVideo', e);
  85. const params = {
  86. type: this.data.bundle,
  87. // nid: [{"value":this.data.id}],
  88. [this.data.field.field_name]: {[this.data.field.value]: null}
  89. };
  90. if (this.data.entitytype === 'node') {
  91. params.nid = [{"value":this.data.id}];
  92. } else {
  93. params.id = [{"value":this.data.id}];
  94. }
  95. const configs = {
  96. headers: {'X-CSRF-Token': this.csrf_token}
  97. };
  98. let url_base = `/${this.data.entitytype === 'node' ? '' : 'entity/'}${this.data.entitytype}`;
  99. REST.patch(`${url_base}/${this.data.id}?_format=json`, params, configs)
  100. .then(({ data }) => {
  101. console.log(`user REST patch node ${this.data.bundle} ${this.data.field}`, data)
  102. this.$emit('updated');
  103. })
  104. .catch(error => {
  105. console.warn(`Issue with patch node ${this.data.bundle} ${this.data.field}`, error)
  106. Promise.reject(error)
  107. })
  108. // 405 JSONAPI operation not allowed, don't know why
  109. // const configs = {
  110. // headers: {
  111. // 'X-CSRF-Token': this.csrf_token,
  112. // 'Content-Type': 'application/octet-stream',
  113. // 'Content-Disposition': `file; filename=""`,
  114. // },
  115. // };
  116. // JSONAPI.delete(`/${this.data.entitytype}/${this.data.bundle}/${this.data.uuid}/${this.data.field}`, {}, configs)
  117. // .then(({ data : { data } }) => {
  118. // console.log('jsonapi delete image', data)
  119. // this.$emit('updated');
  120. // })
  121. // .catch(error => {
  122. // console.warn('Issue with jsonapi post image', error)
  123. // Promise.reject(error)
  124. // })
  125. // console.log('save csrf_token', this.csrf_token);
  126. }
  127. },
  128. components: {
  129. SvgIcon,
  130. ContentEditable
  131. }
  132. }
  133. </script>
  134. <template>
  135. <div class="editable-video">
  136. <!-- with video -->
  137. <template v-if="video">
  138. <!-- v-for="(video,v) in source.videos"
  139. :key="v" -->
  140. <vue-plyr
  141. >
  142. <div class="plyr__video-embed">
  143. <!-- TODO fix vimeo embed url -->
  144. <iframe
  145. :src="video.url"
  146. allowfullscreen
  147. ></iframe>
  148. </div>
  149. </vue-plyr>
  150. <div v-if="can_update" @click="onDeleteVideo" class="delete-btn">
  151. <svg-icon type="mdi" :path="mdiTrashCanOutline_path" />
  152. </div>
  153. </template>
  154. <!-- with out video -->
  155. <template v-else-if="can_update">
  156. <!-- <input ref="videolink_input" type="text" @input="onInput"> -->
  157. <div class="editable-wrapper">
  158. <div
  159. ref="video_link_input"
  160. :contenteditable="can_update"
  161. :spellcheck="spellcheck"
  162. data-placeholder="coller un lien de video" />
  163. <!-- @focusout="onVideoInputFocusOut" -->
  164. <svg-icon class="video-btn" type="mdi" :path="mdiMovieOpenPlusOutline_path" @click="onSaveVideoLink"/>
  165. </div>
  166. </template>
  167. </div>
  168. </template>
  169. <style scoped>
  170. .editable-wrapper{
  171. display: flex;
  172. flex-direction: row;
  173. align-items: center;
  174. gap: 0.5em;
  175. }
  176. [contenteditable] {
  177. flex: auto 1 0;
  178. /* display: inline-block; */
  179. /* padding:12px; */
  180. /* background:red; */
  181. /* min-height: 1em; */
  182. }
  183. [data-placeholder]:empty:before{
  184. content: attr(data-placeholder);
  185. color: #888;
  186. font-style: italic;
  187. }
  188. svg{
  189. /* display: inline-block; */
  190. flex: auto 0 0;
  191. }
  192. </style>