You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
5.2 KiB

  1. import Vue from 'vue';
  2. Vue.use(require('vue-shortkey'));
  3. import annotationMixin from './mixin.js';
  4. import HTTP from './http.js';
  5. Vue.component('annotator', {
  6. template: '<div @click="setSelectedRange">\
  7. <span v-for="r in chunks" v-bind:class="{tag: r.color}" v-bind:style="{ color: r.color, backgroundColor: r.background }">{{ r.word }}<button v-if="r.color" class="delete is-small" @click="deleteLabel(r.index)"></button></span>\
  8. </div>',
  9. props: {
  10. 'labels': Array, // [{id: Integer, color: String, text: String}]
  11. 'text': String,
  12. 'entityPositions': Array, //[{'startOffset': 10, 'endOffset': 15, 'label_id': 1}]
  13. },
  14. data() {
  15. return {
  16. startOffset: 0,
  17. endOffset: 0,
  18. }
  19. },
  20. methods: {
  21. setSelectedRange: function (e) {
  22. if (window.getSelection) {
  23. var range = window.getSelection().getRangeAt(0);
  24. var preSelectionRange = range.cloneRange();
  25. preSelectionRange.selectNodeContents(this.$el);
  26. preSelectionRange.setEnd(range.startContainer, range.startOffset);
  27. var start = preSelectionRange.toString().length;
  28. var end = start + range.toString().length;
  29. } else if (document.selection && document.selection.type != 'Control') {
  30. var selectedTextRange = document.selection.createRange();
  31. var preSelectionTextRange = document.body.createTextRange();
  32. preSelectionTextRange.moveToElementText(this.$el);
  33. preSelectionTextRange.setEndPoint('EndToStart', selectedTextRange);
  34. var start = preSelectionTextRange.text.length;
  35. var end = start + selectedTextRange.text.length;
  36. }
  37. this.startOffset = start;
  38. this.endOffset = end;
  39. console.log(start, end);
  40. },
  41. validRange: function () {
  42. if (this.startOffset == this.endOffset) {
  43. return false
  44. } else if (this.startOffset > this.text.length || this.endOffset > this.text.length) {
  45. return false
  46. } else if (this.startOffset < 0 || this.endOffset < 0) {
  47. return false
  48. } else {
  49. return true
  50. }
  51. },
  52. resetRange: function () {
  53. this.startOffset = 0;
  54. this.endOffset = 0
  55. },
  56. addLabel: function (label_id) {
  57. if (this.validRange()) {
  58. var label = {
  59. start_offset: this.startOffset,
  60. end_offset: this.endOffset,
  61. label_id: label_id
  62. };
  63. this.entityPositions.push(label);
  64. return label
  65. }
  66. },
  67. deleteLabel: function (index) {
  68. this.$emit('delete-label', index);
  69. this.entityPositions.splice(index, 1)
  70. },
  71. getBackgroundColor: function (label_id) {
  72. for (var item of this.labels) {
  73. if (item.id == label_id) {
  74. return item.background_color
  75. }
  76. }
  77. },
  78. getTextColor: function (label_id) {
  79. for (var item of this.labels) {
  80. if (item.id == label_id) {
  81. return item.text_color
  82. }
  83. }
  84. }
  85. },
  86. watch: {
  87. entityPositions: function () {
  88. this.resetRange()
  89. }
  90. },
  91. computed: {
  92. sortedEntityPositions: function () {
  93. return this.entityPositions.sort((a, b) => a.start_offset - b.start_offset)
  94. },
  95. chunks: function () {
  96. var res = [];
  97. var left = 0;
  98. var i = 0;
  99. for (let i in this.sortedEntityPositions) {
  100. var e = this.sortedEntityPositions[i];
  101. var text = this.text.slice(left, e['start_offset']);
  102. res.push({
  103. 'word': text,
  104. 'color': '',
  105. 'background': ''
  106. });
  107. var text = this.text.slice(e['start_offset'], e['end_offset']);
  108. res.push({
  109. 'word': text,
  110. 'color': this.getTextColor(e.label.id),
  111. 'background': this.getBackgroundColor(e.label.id),
  112. 'index': i
  113. });
  114. left = e['end_offset'];
  115. }
  116. var text = this.text.slice(left, this.text.length);
  117. res.push({
  118. 'word': text,
  119. 'color': '',
  120. 'background': ''
  121. });
  122. console.log(res);
  123. console.log(this.labels);
  124. console.log(this.entityPositions);
  125. return res
  126. }
  127. }
  128. })
  129. var vm = new Vue({
  130. el: '#mail-app',
  131. delimiters: ['[[', ']]'],
  132. mixins: [annotationMixin],
  133. methods: {
  134. annotate: function (label_id) {
  135. var payload = this.$refs.annotator.addLabel(label_id);
  136. var doc_id = this.items[this.cur].id;
  137. HTTP.post(`docs/${doc_id}/annotations/`, payload).then(response => {
  138. this.items[this.cur]['labels'].push(response.data);
  139. });
  140. this.updateProgress()
  141. }
  142. }
  143. });