Skip to content

Commit 5a8c799

Browse files
committed
feat: open selected tabs
- change: right click apply for all selected tabs in the list currently
1 parent 73210d6 commit 5a8c799

File tree

7 files changed

+180
-115
lines changed

7 files changed

+180
-115
lines changed

src/_locales/en/messages.json

+3
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@
227227
"ui_remove": {
228228
"message": "Remove"
229229
},
230+
"ui_open": {
231+
"message": "Open"
232+
},
230233
"ui_create_issue": {
231234
"message": "Create an issue"
232235
},

src/_locales/zh_CN/messages.json

+3
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@
227227
"ui_remove": {
228228
"message": "删除"
229229
},
230+
"ui_open": {
231+
"message": "打开"
232+
},
230233
"ui_create_issue": {
231234
"message": "反馈问题"
232235
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<template>
2+
<div>
3+
4+
<v-menu
5+
:value="value"
6+
:position-x="x"
7+
:position-y="y"
8+
min-width="200"
9+
absolute
10+
offset-y
11+
>
12+
<v-list dense>
13+
<!-- <v-subheader>{{ __('ui_move_to') }}</v-subheader> -->
14+
<v-menu offset-x open-on-hover>
15+
<v-list-tile @click.stop="$emit('click', 'init')" slot="activator">
16+
<v-list-tile-action>
17+
<v-icon small>move_to_inbox</v-icon>
18+
</v-list-tile-action>
19+
<v-list-tile-content>
20+
{{ __('ui_move_to') }}
21+
</v-list-tile-content>
22+
<v-list-tile-action>
23+
<v-icon :style="{transform: 'rotate(-90deg)'}">arrow_drop_down</v-icon>
24+
</v-list-tile-action>
25+
</v-list-tile>
26+
<v-list dense>
27+
<v-list-tile
28+
v-for="list in titledList"
29+
:key="list.index"
30+
@click.stop="$emit('click', 'moveSelectedItemsTo', list.index)"
31+
:color="list.color"
32+
>
33+
<v-list-tile-title>{{ list.title }}</v-list-tile-title>
34+
</v-list-tile>
35+
<v-list-tile @click.stop="$emit('click', 'moveSelectedItemsTo', -1)">
36+
<v-list-tile-title>
37+
<v-icon small>create_new_folder</v-icon>
38+
{{ __('ui_a_new_list') }}
39+
</v-list-tile-title>
40+
</v-list-tile>
41+
</v-list>
42+
</v-menu>
43+
44+
<v-divider class="my-1"></v-divider>
45+
46+
<v-list-tile @click.stop="$emit('click', 'openSelectedItems')">
47+
<v-list-tile-action>
48+
<v-icon small>open_in_browser</v-icon>
49+
</v-list-tile-action>
50+
<v-list-tile-content>
51+
{{ __('ui_open') }}
52+
</v-list-tile-content>
53+
</v-list-tile>
54+
55+
<v-list-tile @click.stop="$emit('click', 'duplicateSelectedItems')">
56+
<v-list-tile-action>
57+
<v-icon small>content_copy</v-icon>
58+
</v-list-tile-action>
59+
<v-list-tile-content>
60+
{{ __('ui_duplicate') }}
61+
</v-list-tile-content>
62+
</v-list-tile>
63+
64+
<v-list-tile @click.stop="$emit('click', 'copyLinksOfSelectedItems')">
65+
<v-list-tile-action>
66+
<v-icon small>link</v-icon>
67+
</v-list-tile-action>
68+
<v-list-tile-content>
69+
{{ __('ui_copy_link') }}
70+
</v-list-tile-content>
71+
</v-list-tile>
72+
73+
<v-list-tile @click.stop="$emit('click', 'copyTitleOfSelectedItems')">
74+
<v-list-tile-action>
75+
<v-icon small>title</v-icon>
76+
</v-list-tile-action>
77+
<v-list-tile-content>
78+
{{ __('ui_copy_title') }}
79+
</v-list-tile-content>
80+
</v-list-tile>
81+
82+
<v-divider class="my-1"></v-divider>
83+
84+
<v-list-tile @click.stop="$emit('click', 'removeSelectedItems')">
85+
<v-list-tile-action>
86+
<v-icon small>delete</v-icon>
87+
</v-list-tile-action>
88+
<v-list-tile-content>
89+
{{ __('ui_remove') }}
90+
</v-list-tile-content>
91+
</v-list-tile>
92+
</v-list>
93+
</v-menu>
94+
95+
</div>
96+
</template>
97+
98+
<script>
99+
import { mapGetters } from 'vuex'
100+
import __ from '@/common/i18n'
101+
102+
export default {
103+
data() {
104+
return {
105+
x: NaN, y: NaN, // menu position
106+
}
107+
},
108+
computed: {
109+
...mapGetters(['titledList']),
110+
},
111+
props: {
112+
value: Boolean,
113+
},
114+
methods: {
115+
__,
116+
},
117+
}
118+
</script>

src/app/page/main/DetailList.vue

+43-105
Original file line numberDiff line numberDiff line change
@@ -199,85 +199,7 @@
199199
<p class="display-2 grey--text text--lighten-1" v-html="__('ui_no_list_tip')"></p>
200200
</v-layout>
201201

202-
<v-menu
203-
v-model="showMenu"
204-
:position-x="x"
205-
:position-y="y"
206-
min-width="200"
207-
absolute
208-
offset-y
209-
>
210-
<v-list dense>
211-
<!-- <v-subheader>{{ __('ui_move_to') }}</v-subheader> -->
212-
<v-menu offset-x open-on-hover>
213-
<v-list-tile @click="init" slot="activator">
214-
<v-list-tile-action>
215-
<v-icon small>move_to_inbox</v-icon>
216-
</v-list-tile-action>
217-
<v-list-tile-content>
218-
{{ __('ui_move_to') }}
219-
</v-list-tile-content>
220-
<v-list-tile-action>
221-
<v-icon :style="{transform: 'rotate(-90deg)'}">arrow_drop_down</v-icon>
222-
</v-list-tile-action>
223-
</v-list-tile>
224-
<v-list dense>
225-
<v-list-tile
226-
v-for="(list, listIndex) in lists"
227-
:key="listIndex"
228-
@click="moveSelectedItemsTo(listIndex)"
229-
v-if="list.title"
230-
:color="list.color"
231-
>
232-
<v-list-tile-title>{{ list.title }}</v-list-tile-title>
233-
</v-list-tile>
234-
<v-list-tile @click="moveSelectedItemsTo(-1)">
235-
<v-list-tile-title>{{ __('ui_a_new_list') }}</v-list-tile-title>
236-
</v-list-tile>
237-
</v-list>
238-
</v-menu>
239-
240-
<v-divider class="my-1"></v-divider>
241-
242-
<v-list-tile @click="duplicateSelectedItems">
243-
<v-list-tile-action>
244-
<v-icon small>content_copy</v-icon>
245-
</v-list-tile-action>
246-
<v-list-tile-content>
247-
{{ __('ui_duplicate') }}
248-
</v-list-tile-content>
249-
</v-list-tile>
250-
251-
<v-list-tile @click="copyLinksOfSelectedItems">
252-
<v-list-tile-action>
253-
<v-icon small>link</v-icon>
254-
</v-list-tile-action>
255-
<v-list-tile-content>
256-
{{ __('ui_copy_link') }}
257-
</v-list-tile-content>
258-
</v-list-tile>
259-
260-
<v-list-tile @click="copyTitleOfSelectedItems">
261-
<v-list-tile-action>
262-
<v-icon small>title</v-icon>
263-
</v-list-tile-action>
264-
<v-list-tile-content>
265-
{{ __('ui_copy_title') }}
266-
</v-list-tile-content>
267-
</v-list-tile>
268-
269-
<v-divider class="my-1"></v-divider>
270-
271-
<v-list-tile @click="removeSelectedItems">
272-
<v-list-tile-action>
273-
<v-icon small>delete</v-icon>
274-
</v-list-tile-action>
275-
<v-list-tile-content>
276-
{{ __('ui_remove') }}
277-
</v-list-tile-content>
278-
</v-list-tile>
279-
</v-list>
280-
</v-menu>
202+
<context-menu v-model="showMenu" ref="contextMenu" @click="contextMenuClicked"></context-menu>
281203

282204
<v-fab-transition>
283205
<v-btn :key="1" v-if="scrollY > 100" color="pink" dark fab fixed bottom right @click="$vuetify.goTo(0)">
@@ -347,6 +269,7 @@ import tabs from '@/common/tabs'
347269
import {createNewTabList} from '@/common/list'
348270
import {formatTime, getColorByHash} from '@/common/utils'
349271
import dynamicTime from '@/app/component/DynamicTime'
272+
import contextMenu from '@/app/component/main/detailList/ContextMenu'
350273
import {COLORS} from '@/common/constants'
351274
import {mapState, mapActions, mapMutations, mapGetters} from 'vuex'
352275
@@ -357,9 +280,7 @@ export default {
357280
processed: false, // if task to get list completed
358281
choice: null, // choice in search result
359282
showMenu: false, // item right click menu
360-
x: NaN, y: NaN, // menu position
361-
rightClickedItem: null, // if right click on an item
362-
multiOpBtnClickedListIndex: null,
283+
rightClickedListIndex: null,
363284
currentHighlightItem: null, // after jump to an item
364285
draggableOptions: {
365286
group: {
@@ -416,8 +337,10 @@ export default {
416337
components: {
417338
draggable,
418339
dynamicTime,
340+
contextMenu,
419341
},
420342
methods: {
343+
log: console.log,
421344
__,
422345
formatTime,
423346
getColorByHash,
@@ -467,42 +390,50 @@ export default {
467390
this.expandStatus = this.getExpandStatus()
468391
}
469392
},
470-
openTab(listIndex, tabIndex) {
471-
tabs.openTab(this.lists[listIndex].tabs[tabIndex])
472-
},
473393
getDomain(url) {
474394
try {
475395
return new URL(url).hostname
476396
} catch (error) {
477397
return ''
478398
}
479399
},
400+
async contextMenuClicked(func, ...args) {
401+
await this[func](...args)
402+
this.showMenu = false
403+
},
480404
rightClicked(listIndex, tabIndex, $event) {
481405
$event.preventDefault()
482406
this.showMenu = false
483-
this.rightClickedItem = {listIndex, tabIndex}
484-
this.multiOpBtnClickedListIndex = null
485-
this.x = $event.clientX
486-
this.y = $event.clientY
407+
this.rightClickedListIndex = listIndex
408+
409+
// refer gmail behaviour: unselect all except it if clicked item is not selected
410+
if (!this.lists[listIndex].tabs[tabIndex].selected) {
411+
for (let i = 0; i < this.lists[listIndex].tabs.length; i += 1) {
412+
this.tabSelected([listIndex, i, i === tabIndex])
413+
}
414+
}
415+
416+
this.$refs.contextMenu.x = $event.clientX
417+
this.$refs.contextMenu.y = $event.clientY
487418
this.$nextTick(() => {
488419
this.showMenu = true
489420
})
490421
},
491422
getSelectedItems() {
492-
if (this.rightClickedItem) return [this.rightClickedItem]
493-
else if (isFinite(this.multiOpBtnClickedListIndex)) {
494-
const listIndex = this.multiOpBtnClickedListIndex
495-
const list = this.lists[listIndex]
496-
const selectedItems = []
497-
list.tabs.forEach((tab, tabIndex) => {
498-
if (tab.selected) selectedItems.push({listIndex, tabIndex})
423+
const list = this.lists[this.rightClickedListIndex]
424+
const selectedItems = []
425+
list.tabs.forEach((tab, tabIndex) => {
426+
if (tab.selected) selectedItems.push({
427+
// for avoid to change old functions
428+
listIndex: this.rightClickedListIndex,
429+
tabIndex,
499430
})
500-
return selectedItems
501-
}
431+
})
432+
return selectedItems
502433
},
503434
moveSelectedItemsTo(targetListIndex) {
504435
const items = this.getSelectedItems()
505-
if (!items) return
436+
if (!(items && items.length)) return
506437
const changedLists = [targetListIndex]
507438
const tabs = items.map(({listIndex, tabIndex}) => {
508439
changedLists.push(listIndex)
@@ -520,9 +451,15 @@ export default {
520451
this.tabMoved(changedLists)
521452
}
522453
},
454+
openSelectedItems() {
455+
const items = this.getSelectedItems()
456+
if (!(items && items.length)) return
457+
const toRestoredTabs = items.map(({listIndex, tabIndex}) => this.lists[listIndex].tabs[tabIndex])
458+
return tabs.restoreTabs(toRestoredTabs)
459+
},
523460
duplicateSelectedItems() {
524461
const items = this.getSelectedItems()
525-
if (!items) return
462+
if (!(items && items.length)) return
526463
const changedLists = []
527464
items.forEach(({listIndex, tabIndex}) => {
528465
changedLists.push(listIndex)
@@ -532,7 +469,7 @@ export default {
532469
},
533470
async copyLinksOfSelectedItems() {
534471
const items = this.getSelectedItems()
535-
if (!items) return
472+
if (!(items && items.length)) return
536473
const text = items.map(({listIndex, tabIndex}) => {
537474
const tab = this.lists[listIndex].tabs[tabIndex]
538475
return tab.url
@@ -541,7 +478,7 @@ export default {
541478
},
542479
async copyTitleOfSelectedItems() {
543480
const items = this.getSelectedItems()
544-
if (!items) return
481+
if (!(items && items.length)) return
545482
const text = items.map(({listIndex, tabIndex}) => {
546483
const tab = this.lists[listIndex].tabs[tabIndex]
547484
return tab.title
@@ -550,7 +487,7 @@ export default {
550487
},
551488
removeSelectedItems() {
552489
const items = this.getSelectedItems()
553-
if (!items) return
490+
if (!(items && items.length)) return
554491
const changedLists = []
555492
items.sort((a, b) => b.tabIndex - a.tabIndex)
556493
.forEach(({listIndex, tabIndex}) => {
@@ -574,8 +511,9 @@ export default {
574511
this.x = $event.x
575512
this.y = $event.y
576513
this.multiOpBtnClickedListIndex = listIndex
577-
this.rightClickedItem = null
578-
this.showMenu = true
514+
this.$nextTick(() => {
515+
this.showMenu = true
516+
})
579517
},
580518
async jumpTo(item) {
581519
const page = item.listIndex / this.opts.listsPerPage << 0

src/app/store/lists.js

+3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ export default {
5454
pinnedList(state, getters) {
5555
return getters.indexedLists.filter(list => list.pinned)
5656
},
57+
titledList(state, getters) {
58+
return getters.indexedLists.filter(list => list.title)
59+
},
5760
getPageLength(state) {
5861
return size => Math.ceil(size / state.opts.listsPerPage)
5962
},

0 commit comments

Comments
 (0)