aboutsummaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/Tile.vue121
-rw-r--r--src/components/TileImg.vue8
-rw-r--r--src/components/TileTree.vue16
3 files changed, 81 insertions, 64 deletions
diff --git a/src/components/Tile.vue b/src/components/Tile.vue
index 7722101..f0b506e 100644
--- a/src/components/Tile.vue
+++ b/src/components/Tile.vue
@@ -15,7 +15,7 @@ export default defineComponent({
data(){
return {
nonLeafHighlight: false,
- dblClickTimer: 0, // Used to delay a click action until a double-click timeout ends
+ clickHoldTimer: 0, // Used to recognise a click-and-hold event
zIdx: 0, // Used during transitions
overflow: 'visible', // Used during transitions
}
@@ -121,58 +121,69 @@ export default defineComponent({
},
},
methods: {
- // For click handling
- onLeafClick(evt: UIEvent){
+ // Leaf click handling
+ onLeafMouseDown(){
+ clearTimeout(this.clickHoldTimer);
+ this.clickHoldTimer = setTimeout(() => {
+ this.clickHoldTimer = 0;
+ this.onLeafClickHold();
+ }, this.options.clickHoldDuration);
+ },
+ onLeafMouseUp(){
+ if (this.clickHoldTimer > 0){
+ clearTimeout(this.clickHoldTimer);
+ this.clickHoldTimer = 0;
+ this.onLeafClick();
+ }
+ },
+ onLeafClick(){
if (!this.isExpandable){
- console.log('Ignored click on non-expandable leaf node');
+ console.log('Ignored click on non-expandable node');
return;
}
- let prepForTransition = () => {
- // Temporary changes to prevent content overlap and overflow
- this.zIdx = 1;
- this.overflow = 'hidden';
- setTimeout(() => {this.zIdx = 0; this.overflow = 'visible';}, this.options.transitionDuration);
- };
- if (evt.detail == 1){
- this.dblClickTimer = setTimeout(() => {
- this.$emit('leaf-clicked', {layoutNode: this.layoutNode, domNode: this.$el});
- prepForTransition();
- }, this.options.dblClickWait);
- } else if (evt.detail == 2){
- clearTimeout(this.dblClickTimer);
- this.$emit('leaf-dbl-clicked', this.layoutNode);
- prepForTransition();
+ this.$emit('leaf-clicked', {layoutNode: this.layoutNode, domNode: this.$el});
+ this.leafPrepTransition();
+ },
+ onLeafClickHold(){
+ if (!this.isExpandable){
+ console.log('Ignored click-hold on non-expandable node');
+ return;
}
+ this.$emit('leaf-click-held', this.layoutNode);
+ this.leafPrepTransition();
},
- onInnerLeafClicked(data: {layoutNode: LayoutNode, domNode: HTMLElement}){
- this.$emit('leaf-clicked', data);
+ leafPrepTransition(){ // Temporary style changes to prevent content overlap and overflow
+ this.zIdx = 1;
+ this.overflow = 'hidden';
+ setTimeout(() => {this.zIdx = 0; this.overflow = 'visible';}, this.options.transitionDuration);
},
- onHeaderClick(evt: UIEvent){
+ // Non-leaf click handling
+ onHeaderMouseDown(){
this.nonLeafHighlight = false;
- let prepForTransition = () => {
- // Temporary changes to prevent content overlap and overflow
- this.zIdx = 1;
- setTimeout(() => {this.zIdx = 0}, this.options.transitionDuration);
- };
- if (evt.detail == 1){
- this.dblClickTimer = setTimeout(() => {
- this.$emit('header-clicked', {layoutNode: this.layoutNode, domNode: this.$el});
- prepForTransition();
- }, this.options.dblClickWait);
- } else if (evt.detail == 2){
- clearTimeout(this.dblClickTimer);
- this.$emit('header-dbl-clicked', this.layoutNode);
- prepForTransition();
+ clearTimeout(this.clickHoldTimer);
+ this.clickHoldTimer = setTimeout(() => {
+ this.clickHoldTimer = 0;
+ this.onHeaderClickHold();
+ }, this.options.clickHoldDuration);
+ },
+ onHeaderMouseUp(){
+ if (this.clickHoldTimer > 0){
+ clearTimeout(this.clickHoldTimer);
+ this.clickHoldTimer = 0;
+ this.onHeaderClick();
}
},
- onInnerHeaderClicked(data: {layoutNode: LayoutNode, domNode: HTMLElement}){
- this.$emit('header-clicked', data);
+ onHeaderClick(){
+ this.$emit('header-clicked', {layoutNode: this.layoutNode, domNode: this.$el});
+ this.nonLeafPrepForTransition();
},
- onInnerLeafDblClicked(data: LayoutNode){
- this.$emit('leaf-dbl-clicked', data);
+ onHeaderClickHold(){
+ this.$emit('header-click-held', this.layoutNode);
+ this.nonLeafPrepForTransition();
},
- onInnerHeaderDblClicked(data: LayoutNode){
- this.$emit('header-dbl-clicked', data);
+ nonLeafPrepForTransition(){ // Temporary style changes to prevent content overlap and overflow
+ this.zIdx = 1;
+ setTimeout(() => {this.zIdx = 0}, this.options.transitionDuration);
},
// For coloured-outlines on hovered-over leaf-tiles or non-leaf-headers
onNonLeafMouseEnter(evt: Event){
@@ -181,7 +192,19 @@ export default defineComponent({
onNonLeafMouseLeave(evt: Event){
this.nonLeafHighlight = false;
},
- // For child event propagation
+ // Child event propagation
+ onInnerLeafClicked(data: {layoutNode: LayoutNode, domNode: HTMLElement}){
+ this.$emit('leaf-clicked', data);
+ },
+ onInnerHeaderClicked(data: {layoutNode: LayoutNode, domNode: HTMLElement}){
+ this.$emit('header-clicked', data);
+ },
+ onInnerLeafClickHeld(data: LayoutNode){
+ this.$emit('leaf-click-held', data);
+ },
+ onInnerHeaderClickHeld(data: LayoutNode){
+ this.$emit('header-click-held', data);
+ },
onInnerInfoIconClicked(data: LayoutNode){
this.$emit('info-icon-clicked', data);
}
@@ -190,31 +213,33 @@ export default defineComponent({
components: {
TileImg,
},
- emits: ['leaf-clicked', 'header-clicked', 'leaf-dbl-clicked', 'header-dbl-clicked', 'info-icon-clicked'],
+ emits: ['leaf-clicked', 'header-clicked', 'leaf-click-held', 'header-click-held', 'info-icon-clicked'],
});
</script>
<template>
<div :style="tileStyles">
<tile-img v-if="isLeaf" :layoutNode="layoutNode" :tileSz="layoutNode.dims[0]" :options="options"
- @click="onLeafClick" @info-icon-clicked="onInnerInfoIconClicked"/>
+ @mousedown="onLeafMouseDown" @mouseup="onLeafMouseUp" @info-icon-clicked="onInnerInfoIconClicked"/>
<div v-else :style="nonLeafStyles" ref="nonLeaf">
<h1 v-if="showHeader" :style="nonLeafHeaderStyles" class="hover:cursor-pointer"
- @click="onHeaderClick($event)" @mouseenter="onNonLeafMouseEnter" @mouseleave="onNonLeafMouseLeave">
+ @mouseenter="onNonLeafMouseEnter" @mouseleave="onNonLeafMouseLeave"
+ @mousedown="onHeaderMouseDown" @mouseup="onHeaderMouseUp">
{{layoutNode.tolNode.name}}
</h1>
<div :style="sepSweptAreaStyles" ref="sepSweptArea"
:class="layoutNode?.sepSweptArea?.sweptLeft ? 'hide-right-edge' : 'hide-top-edge'">
<h1 v-if="layoutNode?.sepSweptArea?.sweptLeft === false"
:style="nonLeafHeaderStyles" class="hover:cursor-pointer"
- @click="onHeaderClick($event)" @mouseenter="onNonLeafMouseEnter" @mouseleave="onNonLeafMouseLeave">
+ @mouseenter="onNonLeafMouseEnter" @mouseleave="onNonLeafMouseLeave"
+ @mousedown="onHeaderMouseDown" @mouseup="onHeaderMouseUp">
{{layoutNode.tolNode.name}}
</h1>
</div>
<tile v-for="child in layoutNode.children" :key="child.tolNode.name" :layoutNode="child"
:headerSz="headerSz" :tileSpacing="tileSpacing" :options="options"
@leaf-clicked="onInnerLeafClicked" @header-clicked="onInnerHeaderClicked"
- @leaf-dbl-clicked="onInnerLeafDblClicked" @header-dbl-clicked="onInnerHeaderDblClicked"
+ @leaf-click-held="onInnerLeafClickHeld" @header-click-held="onInnerHeaderClickHeld"
@info-icon-clicked="onInnerInfoIconClicked"/>
</div>
</div>
diff --git a/src/components/TileImg.vue b/src/components/TileImg.vue
index 2445f98..7e44f2a 100644
--- a/src/components/TileImg.vue
+++ b/src/components/TileImg.vue
@@ -74,10 +74,8 @@ export default defineComponent({
this.highlight = false;
}
},
- onClick(evt: Event){
- if (this.isExpandable){
- this.highlight = false;
- }
+ onMouseDown(evt: Event){
+ this.highlight = false;
},
onInfoMouseEnter(evt: Event){
this.infoMouseOver = true;
@@ -94,7 +92,7 @@ export default defineComponent({
</script>
<template>
-<div :style="styles" @mouseenter="onMouseEnter" @mouseleave="onMouseLeave" @click="onClick"
+<div :style="styles" @mouseenter="onMouseEnter" @mouseleave="onMouseLeave" @mousedown="onMouseDown"
:class="isExpandable ? ['hover:cursor-pointer'] : []">
<h1 :style="headerStyles">{{layoutNode.tolNode.name}}</h1>
<svg :style="infoIconStyles" class="hover:cursor-pointer"
diff --git a/src/components/TileTree.vue b/src/components/TileTree.vue
index 99ea9e3..7bc1ec2 100644
--- a/src/components/TileTree.vue
+++ b/src/components/TileTree.vue
@@ -55,7 +55,7 @@ const defaultComponentOptions = {
infoModalImgSz: 200,
// Timing related
transitionDuration: 300, //ms
- dblClickWait: 200, //ms
+ clickHoldDuration: 400, //ms (duration after mousedown when a click-and-hold is recognised)
};
const defaultOwnOptions = {
tileAreaOffset: 5, //px (space between root tile and display boundary)
@@ -174,7 +174,7 @@ export default defineComponent({
}
},
// For expand-to-view events
- onInnerLeafDblClicked(layoutNode: LayoutNode){
+ onInnerLeafClickHeld(layoutNode: LayoutNode){
if (layoutNode == this.activeRoot){
console.log('Ignored expand-to-view on root node');
return;
@@ -184,7 +184,7 @@ export default defineComponent({
tryLayout(layoutNode, this.tileAreaPos, this.tileAreaDims, this.layoutOptions, true,
{type: 'expand', node: layoutNode});
},
- onInnerHeaderDblClicked(layoutNode: LayoutNode){
+ onInnerHeaderClickHeld(layoutNode: LayoutNode){
if (layoutNode.parent == null){
console.log('Ignored expand-to-view on root node');
return;
@@ -205,12 +205,6 @@ export default defineComponent({
onInfoModalClose(){
this.infoModalNode = null;
},
- // For preventing double-clicks from highlighting text
- onMouseDown(evt: UIEvent){
- if (evt.detail == 2){
- evt.preventDefault();
- }
- },
},
created(){
window.addEventListener('resize', this.onResize);
@@ -228,11 +222,11 @@ export default defineComponent({
</script>
<template>
-<div :style="styles" @mousedown="onMouseDown">
+<div :style="styles">
<tile :layoutNode="layoutTree"
:headerSz="layoutOptions.headerSz" :tileSpacing="layoutOptions.tileSpacing" :options="componentOptions"
@leaf-clicked="onInnerLeafClicked" @header-clicked="onInnerHeaderClicked"
- @leaf-dbl-clicked="onInnerLeafDblClicked" @header-dbl-clicked="onInnerHeaderDblClicked"
+ @leaf-click-held="onInnerLeafClickHeld" @header-click-held="onInnerHeaderClickHeld"
@info-icon-clicked="onInnerInfoIconClicked"/>
<parent-bar v-if="sepdParents != null"
:pos="[0,0]" :dims="parentBarDims" :nodes="sepdParents" :options="componentOptions"