6
0

LabelTreeView.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. <template>
  2. <div class="label-tree-view"
  3. ref="main"
  4. :class="{target: target}"
  5. draggable="true" @dragstart="dragstart" @dragend="dragend"
  6. @dragover="dragover" @dragleave="dragleave" @drop="drop">
  7. <editable-headline :value="label.name"
  8. @change="editLabel(label.identifier, $event)"
  9. @remove="removeLabel(label.identifier)">
  10. <div class="hierarchy"
  11. :class="{margined: label.hierarchy_level}"
  12. @click="collapse = !collapse">
  13. <img v-if="collapse"
  14. alt="expand"
  15. src="@/assets/icons/triangle-down.svg"
  16. :style="{opacity: label.children.length > 0 ? 1 : 0.1}">
  17. <img v-else
  18. alt="collapse"
  19. src="@/assets/icons/triangle-up.svg"
  20. :style="{opacity: label.children.length > 0 ? 1 : 0.1}">
  21. <div class="name" v-if="label.hierarchy_level">
  22. {{ label.hierarchy_level }}
  23. </div>
  24. </div>
  25. </editable-headline>
  26. <template v-if="!collapse">
  27. <label-tree-view v-for="child of sortedChildren" :key="child.identifier"
  28. :label="child"
  29. :indent="indent"
  30. :targetable="droppable"
  31. :style="margin"/>
  32. </template>
  33. </div>
  34. </template>
  35. <script>
  36. import EditableHeadline from "@/components/base/editable-headline";
  37. export default {
  38. name: "LabelTreeView",
  39. components: {EditableHeadline},
  40. props: ['label', 'indent', 'targetable'],
  41. data: function () {
  42. return {
  43. untouched: true,
  44. target: false,
  45. collapse: false
  46. }
  47. },
  48. computed: {
  49. droppable: function () {
  50. return this.targetable && this.untouched;
  51. },
  52. margin: function () {
  53. return {
  54. marginLeft: this.indent
  55. };
  56. },
  57. sortedChildren: function () {
  58. return [...this.label.children].sort((a, b) => a.name < b.name ? -1 : +1);
  59. }
  60. },
  61. methods: {
  62. editLabel: function (id, value) {
  63. // TODO then / error
  64. this.$root.socket.post(`/projects/${this.$root.project.identifier}/labels/${id}/name`, {name: value});
  65. },
  66. removeLabel: function (id) {
  67. // TODO then / error
  68. this.$root.socket.post(`/projects/${this.$root.project.identifier}/labels/${id}/remove`, {remove: true});
  69. },
  70. dragstart: function (e) {
  71. this.untouched = false;
  72. e.dataTransfer.setData('text/identifier', this.label.identifier)
  73. e.stopPropagation();
  74. },
  75. dragend: function () {
  76. this.untouched = true;
  77. },
  78. dragover: function (e) {
  79. e.stopPropagation();
  80. if (this.droppable) {
  81. e.preventDefault();
  82. this.target = true;
  83. }
  84. },
  85. dragleave: function () {
  86. this.target = false;
  87. },
  88. drop: function (e) {
  89. e.preventDefault();
  90. e.stopPropagation();
  91. this.dragleave();
  92. const element = e.dataTransfer.getData('text/identifier');
  93. const parent = this.label.identifier;
  94. this.$root.socket.post(`/projects/${this.$root.project.identifier}/labels/${element}/parent`, {parent: parent});
  95. }
  96. }
  97. }
  98. </script>
  99. <style scoped>
  100. .editable-headline {
  101. margin-bottom: 0.5rem;
  102. }
  103. .target > .editable-headline {
  104. text-decoration: underline;
  105. }
  106. .hierarchy {
  107. display: flex;
  108. flex-direction: column;
  109. justify-content: right;
  110. align-items: center;
  111. }
  112. .hierarchy.margined {
  113. margin-right: 0.3rem;
  114. }
  115. .hierarchy .name {
  116. margin-top: -0.5rem;
  117. opacity: 0.8;
  118. font-size: 50%;
  119. }
  120. </style>