|
1 | 1 | <template> |
2 | 2 | <div> |
3 | 3 | <div v-on:contextmenu="showContextMenu"> |
4 | | - <div class="row" :class="{ clickable: canEdit(file), 'active-selection': contextMenuVisible }" v-if="!file.directory"> |
| 4 | + <div class="row" :class="{ 'cursor-pointer': canEdit(file), 'active-selection': contextMenuVisible }" v-if="!file.directory"> |
5 | 5 | <div class="flex-none icon"> |
6 | 6 | <Icon name="file-text" v-if="!file.symlink"/> |
7 | 7 | <Icon name="link2" v-else/> |
8 | 8 | </div> |
9 | 9 | <div class="flex-1">{{file.name}}</div> |
10 | 10 | <div class="flex-1 text-right text-neutral-600">{{readableSize(file.size)}}</div> |
11 | 11 | <div class="flex-1 text-right text-neutral-600">{{formatDate(file.modified)}}</div> |
12 | | - <div class="flex-none w-1/6"></div> |
| 12 | + <div class="flex-none icon cursor-pointer" v-on:click="showContextMenu" ref="menuTriggerIcon"> |
| 13 | + <Icon name="more-vertical" class="text-neutral-500"/> |
| 14 | + </div> |
13 | 15 | </div> |
14 | | - <router-link class="row clickable" |
| 16 | + <router-link class="row" |
15 | 17 | :class="{ 'active-selection': contextMenuVisible }" |
16 | 18 | :to="{ name: 'server-files', params: { path: getClickablePath(file.name) }}" |
17 | 19 | v-else |
|
22 | 24 | <div class="flex-1">{{file.name}}</div> |
23 | 25 | <div class="flex-1 text-right text-neutral-600"></div> |
24 | 26 | <div class="flex-1 text-right text-neutral-600">{{formatDate(file.modified)}}</div> |
25 | | - <div class="flex-none w-1/6"></div> |
| 27 | + <div class="flex-none icon" v-on:click="showContextMenu" ref="menuTriggerIcon"> |
| 28 | + <Icon name="more-vertical" class="text-neutral-500"/> |
| 29 | + </div> |
26 | 30 | </router-link> |
27 | | - |
28 | 31 | </div> |
29 | 32 | <FileContextMenu |
30 | 33 | class="context-menu" |
|
129 | 132 |
|
130 | 133 | // @ts-ignore |
131 | 134 | this.$parent.$emit('collapse-menus', this._uid); |
132 | | -
|
133 | 135 | this.contextMenuVisible = true; |
134 | 136 |
|
135 | | - const menuWidth = (this.$refs.contextMenu as VueType).$el.clientWidth; |
136 | | - const positionElement = e.clientX - Math.round(menuWidth / 2); |
| 137 | + this.$nextTick(() => { |
| 138 | + const menuWidth = (this.$refs.contextMenu as VueType).$el.clientWidth; |
| 139 | + const positionElement = e.clientX - Math.round(menuWidth / 2); |
137 | 140 |
|
138 | | - (this.$refs.contextMenu as VueType).$el.setAttribute('style', `left: ${positionElement}; top: ${e.clientY}`); |
| 141 | + (this.$refs.contextMenu as VueType).$el.setAttribute('style', `left: ${positionElement}px; top: ${e.layerY}px`); |
| 142 | + }); |
139 | 143 | }, |
140 | 144 |
|
141 | 145 | /** |
|
153 | 157 | */ |
154 | 158 | _clickListener: function (e: MouseEvent) { |
155 | 159 | if (e.button !== 2 && this.contextMenuVisible) { |
| 160 | + // If we're clicking the trigger icon don't discard the event. |
| 161 | + if (this.$refs.menuTriggerIcon) { |
| 162 | + if (e.target === this.$refs.menuTriggerIcon || (this.$refs.menuTriggerIcon as HTMLDivElement).contains(e.target as Node)) { |
| 163 | + return; |
| 164 | + } |
| 165 | + } |
| 166 | +
|
| 167 | + // If the target is outside the scope of the context menu, hide it. |
156 | 168 | if (e.target !== (this.$refs.contextMenu as VueType).$el && !(this.$refs.contextMenu as VueType).$el.contains(e.target as Node)) { |
157 | 169 | this.contextMenuVisible = false; |
158 | 170 | } |
|
0 commit comments