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.

358 lines
8.1 KiB

3 years ago
3 years ago
3 years ago
  1. <template>
  2. <v-menu
  3. v-if="label && !activeMenu"
  4. v-model="showMenu"
  5. offset-y
  6. >
  7. <template #activator="{ on }">
  8. <span :id="'spn-' + spanid" :style="{ borderColor: color }" class="highlight bottom" v-on="on">
  9. <span class="highlight__content">{{ content }}<v-icon class="delete" @click.stop="remove">mdi-close-circle</v-icon><span
  10. v-if="!showMenu && sourceChunk.none" class="choose-link-type" @click.stop="showActiveLinks"></span><span
  11. v-if="!showMenu && sourceChunk.id === spanid" class="active-link-source" @click.stop="abortNewLink"></span><span
  12. v-if="sourceLinkType.id > -1 && sourceChunk.id && sourceChunk.id !== spanid" class="choose-target"
  13. @click.stop="selectTarget"></span></span><span
  14. :data-label="label" :style="{ backgroundColor: color, color: textColor }" class="highlight__label"/>
  15. </span>
  16. </template>
  17. <v-list
  18. dense
  19. min-width="150"
  20. max-height="400"
  21. class="overflow-y-auto"
  22. >
  23. <v-list-item
  24. v-for="(item, i) in labels"
  25. :key="i"
  26. v-shortkey.once="[item.suffixKey]"
  27. @shortkey="update(item)"
  28. @click="update(item)"
  29. >
  30. <v-list-item-content>
  31. <v-list-item-title v-text="item.text"/>
  32. </v-list-item-content>
  33. <v-list-item-action>
  34. <v-list-item-action-text v-text="item.suffixKey"/>
  35. </v-list-item-action>
  36. </v-list-item>
  37. </v-list>
  38. </v-menu>
  39. <v-menu
  40. v-else-if="label && activeMenu==='active-links'"
  41. v-model="showActiveLinksMenu"
  42. offset-y
  43. >
  44. <template #activator="{ on }">
  45. <span :id="'spn-' + spanid" :style="{ borderColor: color }" class="highlight bottom" v-on="on">
  46. <span class="highlight__content">{{ content }}<v-icon class="delete" @click.stop="remove">mdi-close-circle</v-icon><span
  47. class="active-link-source" @click.stop="abortNewLink"></span></span><span
  48. :data-label="label" :style="{ backgroundColor: color, color: textColor }" class="highlight__label"/>
  49. </span>
  50. </template>
  51. <v-list
  52. dense
  53. min-width="150"
  54. max-height="400"
  55. class="overflow-y-auto"
  56. >
  57. <v-list-item @click.stop="showNewLinkTypes">
  58. <v-list-item-content>
  59. <v-list-item-title>new relation...</v-list-item-title>
  60. </v-list-item-content>
  61. </v-list-item>
  62. <v-list-item
  63. v-for="(link, i) in sourceChunk.links"
  64. :key="i"
  65. >
  66. <v-list-item-content>
  67. <v-list-item-subtitle v-text="link.targetLabel"></v-list-item-subtitle>
  68. </v-list-item-content>
  69. <v-list-item-action>
  70. <v-btn icon @click.stop="deleteLink(link, i)">
  71. <v-icon color="grey lighten-1">mdi-delete</v-icon>
  72. </v-btn>
  73. </v-list-item-action>
  74. </v-list-item>
  75. </v-list>
  76. </v-menu>
  77. <v-menu
  78. v-else-if="label && activeMenu==='new-link'"
  79. v-model="showNewLinkMenu"
  80. offset-y
  81. >
  82. <template #activator="{ on }">
  83. <span :id="'spn-' + spanid" :style="{ borderColor: color }" class="highlight bottom" v-on="on">
  84. <span class="highlight__content">{{ content }}<v-icon class="delete" @click.stop="remove">mdi-close-circle</v-icon><span
  85. class="active-link-source" @click.stop="abortNewLink"></span></span><span
  86. :data-label="label" :style="{ backgroundColor: color, color: textColor }" class="highlight__label"/>
  87. </span>
  88. </template>
  89. <v-list
  90. dense
  91. min-width="150"
  92. max-height="400"
  93. class="overflow-y-auto"
  94. >
  95. <v-list-item>
  96. <v-list-item-content>
  97. <v-list-item-title>choose relation type:</v-list-item-title>
  98. </v-list-item-content>
  99. </v-list-item>
  100. <v-list-item
  101. v-for="(type, i) in linkTypes"
  102. :key="i"
  103. @click="selectNewLinkType(type)"
  104. >
  105. <v-list-item-action>
  106. <v-list-item-action-text v-text="type.name"/>
  107. </v-list-item-action>
  108. </v-list-item>
  109. </v-list>
  110. </v-menu>
  111. <span v-else :class="[newline ? 'newline' : '']">{{ content }}</span>
  112. </template>
  113. <script>
  114. import {idealColor} from '~/plugins/utils.js'
  115. export default {
  116. props: {
  117. spanid: {
  118. type: Number,
  119. default: 0,
  120. required: true
  121. },
  122. content: {
  123. type: String,
  124. default: '',
  125. required: true
  126. },
  127. label: {
  128. type: String,
  129. default: ''
  130. },
  131. color: {
  132. type: String,
  133. default: '#64FFDA'
  134. },
  135. labels: {
  136. type: Array,
  137. default: () => [],
  138. required: true
  139. },
  140. linkTypes: {
  141. type: Array,
  142. default: () => [],
  143. required: true
  144. },
  145. newline: {
  146. type: Boolean
  147. },
  148. sourceChunk: {
  149. type: Object,
  150. default: () => {
  151. }
  152. },
  153. sourceLinkType: {
  154. type: Object,
  155. default: () => {
  156. },
  157. required: true
  158. }
  159. },
  160. data() {
  161. return {
  162. showMenu: false,
  163. showActiveLinksMenu: false,
  164. showNewLinkMenu: false,
  165. showChangeLinkMenu: false,
  166. activeMenu: false
  167. }
  168. },
  169. computed: {
  170. textColor() {
  171. return idealColor(this.color)
  172. }
  173. },
  174. methods: {
  175. update(label) {
  176. this.$emit('update', label)
  177. this.closeAllMenus();
  178. },
  179. remove() {
  180. this.$emit('remove')
  181. },
  182. closeAllMenus() {
  183. this.showMenu = false;
  184. this.showActiveLinksMenu = false;
  185. this.showNewLinkMenu = false;
  186. this.showChangeLinkMenu = false;
  187. this.activeMenu = false;
  188. },
  189. showActiveLinks() {
  190. this.closeAllMenus();
  191. this.showActiveLinksMenu = true;
  192. this.activeMenu = 'active-links';
  193. this.$emit('selectSource');
  194. },
  195. showNewLinkTypes() {
  196. this.closeAllMenus();
  197. this.activeMenu = 'new-link';
  198. this.showNewLinkMenu = true;
  199. },
  200. deleteLink(link, i) {
  201. this.$emit('deleteLink', {id: link.id, ndx: i});
  202. },
  203. selectNewLinkType(type) {
  204. this.closeAllMenus();
  205. this.$emit('selectNewLinkType', type);
  206. },
  207. changeLinkType(type) {
  208. this.closeAllMenus();
  209. this.$emit('changeLinkType', type);
  210. },
  211. selectTarget() {
  212. this.closeAllMenus();
  213. this.$emit('selectTarget');
  214. },
  215. abortNewLink() {
  216. this.closeAllMenus();
  217. this.$emit('hideAllLinkMenus');
  218. }
  219. }
  220. }
  221. </script>
  222. <style scoped>
  223. .highlight.blue {
  224. background: #edf4fa !important;
  225. }
  226. .highlight.bottom {
  227. display: block;
  228. white-space: normal;
  229. }
  230. .highlight:first-child {
  231. margin-left: 0;
  232. }
  233. .highlight {
  234. border: 2px solid;
  235. margin: 4px 6px 4px 3px;
  236. vertical-align: middle;
  237. box-shadow: 2px 4px 20px rgba(0, 0, 0, .1);
  238. position: relative;
  239. cursor: default;
  240. min-width: 26px;
  241. line-height: 22px;
  242. display: flex;
  243. }
  244. .highlight .delete {
  245. top: -15px;
  246. left: -13px;
  247. position: absolute;
  248. display: none;
  249. }
  250. .highlight:hover .delete {
  251. display: block;
  252. }
  253. .highlight .choose-link-type:before {
  254. content: 'R';
  255. }
  256. .highlight .active-link-source:before {
  257. content: 'R';
  258. }
  259. .highlight .choose-target:before {
  260. content: '+';
  261. }
  262. .highlight .choose-link-type,
  263. .highlight .active-link-source,
  264. .highlight .choose-target {
  265. display: none;
  266. position: absolute;
  267. top: -12px;
  268. right: -11px;
  269. width: 20px;
  270. background: rgba(0, 0, 0, 0.54);
  271. color: #ffffff;
  272. border-radius: 30px;
  273. cursor: pointer;
  274. text-align: center;
  275. }
  276. .highlight:hover .choose-link-type,
  277. .highlight:hover .choose-target {
  278. display: block;
  279. }
  280. .highlight .active-link-source {
  281. display: block;
  282. background: #00a4cf;
  283. color: #ffffff;
  284. }
  285. .highlight__content {
  286. display: flex;
  287. flex-wrap: wrap;
  288. align-items: center;
  289. padding: 2px 2px 0 6px;
  290. }
  291. .highlight.bottom .highlight__content:after {
  292. content: " ";
  293. padding-right: 3px;
  294. }
  295. .highlight__label {
  296. line-height: 14px;
  297. align-items: center;
  298. justify-content: center;
  299. display: flex;
  300. padding: 0 8px;
  301. text-align: center;
  302. -webkit-user-select: none;
  303. -moz-user-select: none;
  304. -ms-user-select: none;
  305. user-select: none;
  306. color: white;
  307. }
  308. .highlight__label::after {
  309. content: attr(data-label);
  310. display: block;
  311. font-size: 14px;
  312. -webkit-font-smoothing: subpixel-antialiased;
  313. letter-spacing: .1em;
  314. }
  315. .newline {
  316. width: 100%;
  317. }
  318. </style>