Added search to library tree views
This commit is contained in:
81
app/imports/ui/components/tree/TreeSearchInput.vue
Normal file
81
app/imports/ui/components/tree/TreeSearchInput.vue
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<template lang="html">
|
||||||
|
<v-combobox
|
||||||
|
v-model="filterTerms"
|
||||||
|
:items="filterOptions"
|
||||||
|
prepend-inner-icon="mdi-magnify"
|
||||||
|
hide-no-data
|
||||||
|
hide-selected
|
||||||
|
multiple
|
||||||
|
clearable
|
||||||
|
small-chips
|
||||||
|
deletable-chips
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="js">
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data(){return {
|
||||||
|
filterTerms: [],
|
||||||
|
filterOptions: [
|
||||||
|
{text: 'Actions', value: 'action'},
|
||||||
|
{text: 'Attacks', value: 'attack'},
|
||||||
|
{text: 'Attributes', value: 'attribute'},
|
||||||
|
{text: 'Buffs', value: 'buff'},
|
||||||
|
{text: 'Class Levels', value: 'classLevel'},
|
||||||
|
{text: 'Damage Multipliers', value: 'damageMultiplier'},
|
||||||
|
{text: 'Effects', value: 'effect'},
|
||||||
|
{text: 'Experiences', value: 'experience'},
|
||||||
|
{text: 'Features', value: 'feature'},
|
||||||
|
{text: 'Folders', value: 'folder'},
|
||||||
|
{text: 'Notes', value: 'note'},
|
||||||
|
{text: 'Proficiencies', value: 'proficiency'},
|
||||||
|
{text: 'Rolls', value: 'roll'},
|
||||||
|
{text: 'Saving Throws', value: 'savingThrow'},
|
||||||
|
{text: 'Skills', value: 'skill'},
|
||||||
|
{text: 'Spell Lists', value: 'spellList'},
|
||||||
|
{text: 'Spells', value: 'spell'},
|
||||||
|
{text: 'Containers', value: 'container'},
|
||||||
|
{text: 'Items', value: 'item'},
|
||||||
|
],
|
||||||
|
}},
|
||||||
|
computed: {
|
||||||
|
filter(){
|
||||||
|
if (!this.filterTerms.length) return;
|
||||||
|
let typeFilters = [];
|
||||||
|
let nameFilters = [];
|
||||||
|
this.filterTerms.forEach(filter => {
|
||||||
|
if (filter.value){
|
||||||
|
typeFilters.push(filter.value);
|
||||||
|
} else {
|
||||||
|
// escape string
|
||||||
|
let term = filter.replace( /[-/\\^$*+?.()|[\]{}]/g, '\\$&' );
|
||||||
|
var reg = new RegExp( '.*' + term + '.*', 'i' );
|
||||||
|
nameFilters.push(reg)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let filter = {};
|
||||||
|
if (typeFilters.length){
|
||||||
|
filter.type = {$in: typeFilters};
|
||||||
|
}
|
||||||
|
if (nameFilters.length){
|
||||||
|
filter.name = {$in: nameFilters};
|
||||||
|
}
|
||||||
|
return filter;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch:{
|
||||||
|
filter(value){
|
||||||
|
this.$emit('input', value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="css" scoped>
|
||||||
|
</style>
|
||||||
@@ -23,19 +23,11 @@
|
|||||||
:disabled="organizeDisabled"
|
:disabled="organizeDisabled"
|
||||||
style="flex-grow: 0; height: 32px;"
|
style="flex-grow: 0; height: 32px;"
|
||||||
/>
|
/>
|
||||||
<v-combobox
|
<tree-search-input
|
||||||
ref="searchBox"
|
ref="searchBox"
|
||||||
slot="extension"
|
slot="extension"
|
||||||
v-model="filterString"
|
v-model="filter"
|
||||||
:items="filterOptions"
|
|
||||||
prepend-inner-icon="mdi-magnify"
|
|
||||||
class="mx-4"
|
class="mx-4"
|
||||||
hide-no-data
|
|
||||||
hide-selected
|
|
||||||
multiple
|
|
||||||
clearable
|
|
||||||
small-chips
|
|
||||||
deletable-chips
|
|
||||||
/>
|
/>
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
<creature-properties-tree
|
<creature-properties-tree
|
||||||
@@ -65,13 +57,14 @@
|
|||||||
import TreeDetailLayout from '/imports/ui/components/TreeDetailLayout.vue';
|
import TreeDetailLayout from '/imports/ui/components/TreeDetailLayout.vue';
|
||||||
import CreaturePropertiesTree from '/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue';
|
import CreaturePropertiesTree from '/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue';
|
||||||
import CreaturePropertyDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyDialog.vue';
|
import CreaturePropertyDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyDialog.vue';
|
||||||
|
import TreeSearchInput from '/imports/ui/components/tree/TreeSearchInput.vue';
|
||||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||||
import { getPropertyName } from '/imports/constants/PROPERTIES.js';
|
import { getPropertyName } from '/imports/constants/PROPERTIES.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
TreeDetailLayout,
|
TreeDetailLayout,
|
||||||
|
TreeSearchInput,
|
||||||
CreaturePropertiesTree,
|
CreaturePropertiesTree,
|
||||||
CreaturePropertyDialog,
|
CreaturePropertyDialog,
|
||||||
},
|
},
|
||||||
@@ -89,50 +82,8 @@
|
|||||||
organizeDisabled: false,
|
organizeDisabled: false,
|
||||||
selectedNodeId: undefined,
|
selectedNodeId: undefined,
|
||||||
fab: false,
|
fab: false,
|
||||||
filterString: '',
|
filter: undefined,
|
||||||
filterOptions: [
|
|
||||||
{text: 'Actions', value: 'action'},
|
|
||||||
{text: 'Attacks', value: 'attack'},
|
|
||||||
{text: 'Attributes', value: 'attribute'},
|
|
||||||
{text: 'Buffs', value: 'buff'},
|
|
||||||
{text: 'Class Levels', value: 'classLevel'},
|
|
||||||
{text: 'Damage Multipliers', value: 'damageMultiplier'},
|
|
||||||
{text: 'Effects', value: 'effect'},
|
|
||||||
{text: 'Experiences', value: 'experience'},
|
|
||||||
{text: 'Features', value: 'feature'},
|
|
||||||
{text: 'Folders', value: 'folder'},
|
|
||||||
{text: 'Notes', value: 'note'},
|
|
||||||
{text: 'Proficiencies', value: 'proficiency'},
|
|
||||||
{text: 'Rolls', value: 'roll'},
|
|
||||||
{text: 'Saving Throws', value: 'savingThrow'},
|
|
||||||
{text: 'Skills', value: 'skill'},
|
|
||||||
{text: 'Spell Lists', value: 'spellList'},
|
|
||||||
{text: 'Spells', value: 'spell'},
|
|
||||||
{text: 'Containers', value: 'container'},
|
|
||||||
{text: 'Items', value: 'item'},
|
|
||||||
],
|
|
||||||
};},
|
};},
|
||||||
computed: {
|
|
||||||
filter(){
|
|
||||||
if (!this.filterString.length) return;
|
|
||||||
let typeFilters = [];
|
|
||||||
let nameFilters = [];
|
|
||||||
this.filterString.forEach(filter => {
|
|
||||||
if (filter.value){
|
|
||||||
typeFilters.push(filter.value);
|
|
||||||
} else {
|
|
||||||
// escape string
|
|
||||||
let term = filter.replace( /[-/\\^$*+?.()|[\]{}]/g, '\\$&' );
|
|
||||||
var reg = new RegExp( '.*' + term + '.*', 'i' );
|
|
||||||
nameFilters.push(reg)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return {$or: [
|
|
||||||
{type: {$in: typeFilters}},
|
|
||||||
{name: {$in: nameFilters}},
|
|
||||||
]};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
watch: {
|
||||||
filter(filter){
|
filter(filter){
|
||||||
if (filter) {
|
if (filter) {
|
||||||
|
|||||||
@@ -28,7 +28,10 @@
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
filter: Object,
|
filter: {
|
||||||
|
type: Object,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
group: {
|
group: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'creatureProperties'
|
default: 'creatureProperties'
|
||||||
|
|||||||
@@ -25,9 +25,16 @@
|
|||||||
class="mx-3"
|
class="mx-3"
|
||||||
style="flex-grow: 0; height: 32px;"
|
style="flex-grow: 0; height: 32px;"
|
||||||
/>
|
/>
|
||||||
|
<tree-search-input
|
||||||
|
ref="searchBox"
|
||||||
|
slot="extension"
|
||||||
|
v-model="filter"
|
||||||
|
class="mx-4"
|
||||||
|
/>
|
||||||
<insert-library-node-button
|
<insert-library-node-button
|
||||||
v-if="libraryId && canEditLibrary"
|
v-if="libraryId && canEditLibrary"
|
||||||
style="bottom: -32px"
|
slot="extension"
|
||||||
|
style="bottom: -24px"
|
||||||
fab
|
fab
|
||||||
:library-id="libraryId"
|
:library-id="libraryId"
|
||||||
:selected-node-id="selectedNodeId"
|
:selected-node-id="selectedNodeId"
|
||||||
@@ -43,6 +50,7 @@
|
|||||||
:organize-mode="organize"
|
:organize-mode="organize"
|
||||||
:selected-node="selectedNode"
|
:selected-node="selectedNode"
|
||||||
should-subscribe
|
should-subscribe
|
||||||
|
:filter="filter"
|
||||||
@selected="clickNode"
|
@selected="clickNode"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -52,6 +60,7 @@
|
|||||||
:organize-mode="organize"
|
:organize-mode="organize"
|
||||||
:selected-node="selectedNode"
|
:selected-node="selectedNode"
|
||||||
style="overflow-y: auto; padding: 12px;"
|
style="overflow-y: auto; padding: 12px;"
|
||||||
|
:filter="filter"
|
||||||
@selected="clickNode"
|
@selected="clickNode"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -82,6 +91,7 @@ import { getPropertyName } from '/imports/constants/PROPERTIES.js';
|
|||||||
import isDarkColor from '/imports/ui/utility/isDarkColor.js';
|
import isDarkColor from '/imports/ui/utility/isDarkColor.js';
|
||||||
import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js';
|
import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js';
|
||||||
import getThemeColor from '/imports/ui/utility/getThemeColor.js';
|
import getThemeColor from '/imports/ui/utility/getThemeColor.js';
|
||||||
|
import TreeSearchInput from '/imports/ui/components/tree/TreeSearchInput.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -90,6 +100,7 @@ export default {
|
|||||||
LibraryNodeDialog,
|
LibraryNodeDialog,
|
||||||
LibraryContentsContainer,
|
LibraryContentsContainer,
|
||||||
InsertLibraryNodeButton,
|
InsertLibraryNodeButton,
|
||||||
|
TreeSearchInput,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
selection: Boolean,
|
selection: Boolean,
|
||||||
@@ -101,6 +112,7 @@ export default {
|
|||||||
data(){ return {
|
data(){ return {
|
||||||
organize: false,
|
organize: false,
|
||||||
selectedNodeId: undefined,
|
selectedNodeId: undefined,
|
||||||
|
filter: undefined,
|
||||||
};},
|
};},
|
||||||
computed: {
|
computed: {
|
||||||
isToolbarDark(){
|
isToolbarDark(){
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
:organize-mode="organizeMode && editPermission(library)"
|
:organize-mode="organizeMode && editPermission(library)"
|
||||||
:edit-mode="editMode"
|
:edit-mode="editMode"
|
||||||
:selected-node="selectedNode"
|
:selected-node="selectedNode"
|
||||||
|
:filter="filter"
|
||||||
should-subscribe
|
should-subscribe
|
||||||
@selected="e => $emit('selected', e)"
|
@selected="e => $emit('selected', e)"
|
||||||
/>
|
/>
|
||||||
@@ -87,6 +88,10 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
|
filter: {
|
||||||
|
type: Object,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data(){ return {
|
data(){ return {
|
||||||
expandedLibrary: [],
|
expandedLibrary: [],
|
||||||
|
|||||||
@@ -38,13 +38,20 @@
|
|||||||
TreeNodeList,
|
TreeNodeList,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
libraryId: String,
|
libraryId: {
|
||||||
|
type: String,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
organizeMode: Boolean,
|
organizeMode: Boolean,
|
||||||
selectedNode: {
|
selectedNode: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
shouldSubscribe: Boolean,
|
shouldSubscribe: Boolean,
|
||||||
|
filter: {
|
||||||
|
type: Object,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data(){return {
|
data(){return {
|
||||||
slowShouldSubscribe: this.shouldSubscribe,
|
slowShouldSubscribe: this.shouldSubscribe,
|
||||||
@@ -79,7 +86,13 @@
|
|||||||
},
|
},
|
||||||
libraryChildren(){
|
libraryChildren(){
|
||||||
if (!this.library) return;
|
if (!this.library) return;
|
||||||
return nodesToTree({collection: LibraryNodes, ancestorId: this.library._id});
|
return nodesToTree({
|
||||||
|
collection: LibraryNodes,
|
||||||
|
ancestorId: this.library._id,
|
||||||
|
filter: this.filter,
|
||||||
|
includeFilteredDocAncestors: true,
|
||||||
|
includeFilteredDocDescendants: true,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
Reference in New Issue
Block a user