Skip to content

Commit

Permalink
Teach selection to ignore items not visible in the UI
Browse files Browse the repository at this point in the history
- Tabs that are pinned or hidden
- Tabs that are stashed (if showing unstashed tabs only)
- Filtered items (except if we're showing filtered items)
  • Loading branch information
josh-berry committed Jul 8, 2023
1 parent 5770ebb commit 5b511d6
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 6 deletions.
32 changes: 31 additions & 1 deletion src/model/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
// mutating and accessing the state in various ways that a user might want to
// perform. All the business logic resides here.

import {computed, ref} from "vue";
import {computed, ref, type Ref} from "vue";
import browser from "webextension-polyfill";

import {
Expand Down Expand Up @@ -157,6 +157,12 @@ export class Model {
Bookmarks.Node | Tabs.Tab
>;

/** This is a bit of volatile metadata that tracks whether children that don't
* match the filter should be shown in the UI or not. We need it here because
* the selection model depends on it for knowing which items in a range are
* visible when doing a multi-select. */
readonly showFilteredChildren = new WeakMap<ModelItem, Ref<boolean>>();

readonly selection: TreeSelection<ModelParent, ModelItem>;

constructor(src: Source) {
Expand Down Expand Up @@ -193,6 +199,30 @@ export class Model {
),
),
);

this.selection.rangeSelectPredicate = item => {
// This is super ugly because it mimics logic that is spread around
// various parts of the UI which determines whether a tab is visible or
// not. Ugh.

if (isTab(item)) {
if (item.pinned || item.hidden) return false;

if (
this.options.sync.state.show_open_tabs === "unstashed" &&
this.bookmarks.isURLStashed(item.url)
) {
return false;
}
}

if (this.filter.info(item).isMatching) return true;

const parent = item.position?.parent;
if (parent && this.showFilteredChildren.get(parent)?.value) return true;

return false;
};
}

/** Reload model data (where possible) in the event of an unexpected issue.
Expand Down
6 changes: 5 additions & 1 deletion src/model/tree-selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ export class TreeSelection<
* nodes. */
readonly roots: Ref<P[]>;

/** An optional predicate function used to filter items from range selections. */
rangeSelectPredicate?: (n: P | N) => boolean;

/** How many nodes are selected in `this.roots` and their subtrees? */
readonly selectedCount: Ref<number>;

Expand Down Expand Up @@ -161,10 +164,11 @@ export class TreeSelection<
return this.toggleSelectScattered(node);
}

const range = this.itemsInRange(this.lastSelected.node, node);
let range = this.itemsInRange(this.lastSelected.node, node);
if (!range) {
return this.toggleSelectScattered(node);
}
range = range.filter(this.rangeSelectPredicate || (_ => true));

const selected = this.info(this.lastSelected.node).isSelected;

Expand Down
22 changes: 20 additions & 2 deletions src/stash-list/folder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@
</template>

<script lang="ts">
import {defineComponent, type PropType} from "vue";
import {defineComponent, ref, type PropType} from "vue";
import {
altKeyName,
Expand Down Expand Up @@ -279,7 +279,6 @@ export default defineComponent({
data: () => ({
isRenaming: false,
showFiltered: false,
}),
computed: {
Expand All @@ -297,6 +296,25 @@ export default defineComponent({
return the.model.selection.info(this.folder);
},
showFiltered: {
get(): boolean {
let f = the.model.showFilteredChildren.get(this.folder);
if (!f) {
f = ref(false);
the.model.showFilteredChildren.set(this.folder, f);
}
return f.value;
},
set(v: boolean) {
let f = the.model.showFilteredChildren.get(this.folder);
if (!f) {
f = ref(false);
the.model.showFilteredChildren.set(this.folder, f);
}
f.value = v;
},
},
metadata(): BookmarkMetadataEntry {
return the.model.bookmark_metadata.get(this.folder.id);
},
Expand Down
22 changes: 20 additions & 2 deletions src/stash-list/window.vue
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ ${altKey}+Click: Close any hidden/stashed tabs (reclaims memory)`"
</template>

<script lang="ts">
import {defineComponent, type PropType} from "vue";
import {defineComponent, ref, type PropType} from "vue";
import browser from "webextension-polyfill";
import {altKeyName, filterMap, required} from "../util";
Expand Down Expand Up @@ -164,7 +164,6 @@ export default defineComponent({
},
data: () => ({
showFiltered: false,
confirmCloseTabs: 0,
confirmCloseTabsThen: (id: ConfirmDialogEvent): void => {},
}),
Expand All @@ -176,6 +175,25 @@ export default defineComponent({
return the.model.filter.info(this.targetWindow);
},
showFiltered: {
get(): boolean {
let f = the.model.showFilteredChildren.get(this.targetWindow);
if (!f) {
f = ref(false);
the.model.showFilteredChildren.set(this.targetWindow, f);
}
return f.value;
},
set(v: boolean) {
let f = the.model.showFilteredChildren.get(this.targetWindow);
if (!f) {
f = ref(false);
the.model.showFilteredChildren.set(this.targetWindow, f);
}
f.value = v;
},
},
accepts() {
return ACCEPTS;
},
Expand Down

0 comments on commit 5b511d6

Please sign in to comment.