ContentEditable.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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. },
  23. emits: ['updated'],
  24. data(){
  25. return {
  26. editor: null,
  27. spellcheck: false
  28. }
  29. },
  30. computed: {
  31. ...mapState(UserStore,['csrf_token']),
  32. },
  33. created () {
  34. console.log('ContentEditable created');
  35. },
  36. mounted () {
  37. if (this.contenteditable && this.html) {
  38. this.editor = new MediumEditor(this.$refs.html_editable, {
  39. toolbar: {
  40. allowMultiParagraphSelection: false,
  41. buttons: ['anchor'],
  42. }
  43. });
  44. }
  45. },
  46. beforeUnmount() {
  47. },
  48. methods: {
  49. ...mapActions(ConcernementsStore, ['reloadConcernements']),
  50. onContentEditableFocusOut(e){
  51. console.log('onContentEditableFocusOut', e);
  52. // console.log('onContentEditableFocusOut data', this.data);
  53. let new_field_content = this.html ? e.target.innerHTML : e.target.innerText;
  54. // console.log('onContentEditableFocusOut', new_field_content);
  55. this.save(new_field_content)
  56. },
  57. save(content){
  58. // console.log('save csrf_token', this.csrf_token);
  59. const params = {
  60. type: this.data.bundle,
  61. [this.data.field.field_name]: [{[this.data.field.value]: content}]
  62. };
  63. if (this.data.entitytype === 'node') {
  64. params.nid = [{"value":this.data.id}];
  65. } else {
  66. params.id = [{"value":this.data.id}];
  67. }
  68. // we need additional values for image alt for example
  69. // console.log('additional_values', this.data.field.additional_values);
  70. if (this.data.field.additional_values) {
  71. for (const key in this.data.field.additional_values) {
  72. if (Object.hasOwnProperty.call(this.data.field.additional_values, key)) {
  73. params[this.data.field.field_name][0][key] = this.data.field.additional_values[key]
  74. }
  75. }
  76. }
  77. const configs = {
  78. headers: {'X-CSRF-Token': this.csrf_token}
  79. };
  80. let url_base = `/${this.data.entitytype === 'node' ? '' : 'entity/'}${this.data.entitytype}`;
  81. REST.patch(`${url_base}/${this.data.id}?_format=json`, params, configs)
  82. .then(({ data }) => {
  83. console.log('user REST post node data', data)
  84. // TODO if success update the data in pinia
  85. // this.reloadConcernements();
  86. this.$emit('updated');
  87. })
  88. .catch(error => {
  89. console.warn(`Issue with patch ${this.data.entitytype} ${this.data.bundle}`, error)
  90. Promise.reject(error)
  91. })
  92. }
  93. },
  94. components: {
  95. }
  96. }
  97. </script>
  98. <template>
  99. <component
  100. v-if="!html"
  101. :is="tag"
  102. :contenteditable="contenteditable"
  103. :spellcheck="spellcheck"
  104. @focusout="onContentEditableFocusOut"
  105. >{{ value }}</component>
  106. <component
  107. v-else
  108. :is="tag"
  109. class="html-editable"
  110. ref="html_editable"
  111. v-html="value"
  112. :contenteditable="contenteditable"
  113. :spellcheck="spellcheck"
  114. @focusout="onContentEditableFocusOut"
  115. />
  116. </template>