ContentEditable.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <script>
  2. import REST from '@api/rest-axios'
  3. import { mapActions, mapState } from 'pinia'
  4. import { ConcernementsStore } from '@stores/concernements'
  5. import { UserStore } from '@stores/user'
  6. import MediumEditor from 'medium-editor-x'
  7. import 'medium-editor-x/dist/css/medium-editor.css'
  8. import 'medium-editor-x/dist/css/themes/beagle.css'
  9. export default {
  10. props: {
  11. tag: String,
  12. value: String,
  13. contenteditable : {
  14. type : [Boolean, String],
  15. default : true,
  16. },
  17. html : {
  18. type : [Boolean, String],
  19. default : false,
  20. },
  21. data: Object,
  22. placeholder : {
  23. type : String,
  24. default : 'Ajouter du texte'
  25. }
  26. },
  27. emits: ['updated'],
  28. data(){
  29. return {
  30. editor: null,
  31. spellcheck: false
  32. }
  33. },
  34. computed: {
  35. ...mapState(UserStore,['csrf_token']),
  36. },
  37. created () {
  38. console.log('ContentEditable created');
  39. },
  40. mounted () {
  41. if (this.contenteditable && this.html) {
  42. this.editor = new MediumEditor(this.$refs.html_editable, {
  43. toolbar: {
  44. allowMultiParagraphSelection: false,
  45. buttons: ['anchor'],
  46. },
  47. placeholder: {
  48. /* This example includes the default options for placeholder,
  49. if nothing is passed this is what it used */
  50. text: this.placeholder,
  51. hideOnClick: true
  52. }
  53. });
  54. }
  55. },
  56. beforeUnmount() {
  57. },
  58. methods: {
  59. ...mapActions(ConcernementsStore, ['reloadConcernements']),
  60. onContentEditableFocusOut(e){
  61. console.log('onContentEditableFocusOut', e);
  62. // console.log('onContentEditableFocusOut data', this.data);
  63. let new_field_content = this.html ? e.target.innerHTML : e.target.innerText;
  64. new_field_content = new_field_content.replace(/<br>$/g, '');
  65. // console.log('onContentEditableFocusOut', new_field_content);
  66. this.$emit('focusout');
  67. if (this.data) {
  68. this.save(new_field_content)
  69. }
  70. },
  71. save(content){
  72. // console.log('save csrf_token', this.csrf_token);
  73. const params = {
  74. type: this.data.bundle,
  75. [this.data.field.field_name]: [{[this.data.field.value]: content}]
  76. };
  77. if (this.data.entitytype === 'node') {
  78. params.nid = [{"value":this.data.id}];
  79. } else {
  80. params.id = [{"value":this.data.id}];
  81. }
  82. // we need additional values for image alt for example
  83. // console.log('additional_values', this.data.field.additional_values);
  84. if (this.data.field.additional_values) {
  85. for (const key in this.data.field.additional_values) {
  86. if (Object.hasOwnProperty.call(this.data.field.additional_values, key)) {
  87. params[this.data.field.field_name][0][key] = this.data.field.additional_values[key]
  88. }
  89. }
  90. }
  91. const configs = {
  92. headers: {'X-CSRF-Token': this.csrf_token}
  93. };
  94. // url is not the same between nodes and others entities
  95. let url_base = `/${this.data.entitytype === 'node' ? '' : 'entity/'}${this.data.entitytype}`;
  96. // call the api
  97. REST.patch(`${url_base}/${this.data.id}?_format=json`, params, configs)
  98. .then(({ data }) => {
  99. console.log('user REST post node data', data)
  100. this.$emit('updated');
  101. })
  102. .catch(error => {
  103. console.warn(`Issue with patch ${this.data.entitytype} ${this.data.bundle}`, error)
  104. Promise.reject(error)
  105. })
  106. }
  107. },
  108. components: {
  109. }
  110. }
  111. </script>
  112. <template>
  113. <component
  114. v-if="!html"
  115. :is="tag"
  116. :contenteditable="contenteditable"
  117. :spellcheck="spellcheck"
  118. @focusout="onContentEditableFocusOut"
  119. >{{ value }}</component>
  120. <component
  121. v-else
  122. :is="tag"
  123. class="html-editable"
  124. ref="html_editable"
  125. v-html="value"
  126. :contenteditable="contenteditable"
  127. :spellcheck="spellcheck"
  128. @focusout="onContentEditableFocusOut"
  129. />
  130. </template>