Frontend: Refactor long click event

Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
Michael Mayer 2020-04-25 11:43:00 +02:00
parent 01c7fd3fd3
commit 015a67d2e6
7 changed files with 118 additions and 189 deletions

View file

@ -21,7 +21,6 @@ import VueLuxon from "vue-luxon";
import VueFilters from "vue2-filters";
import VueFullscreen from "vue-fullscreen";
import VueInfiniteScroll from "vue-infinite-scroll";
import VueLongClick from "common/longclick";
// Initialize helpers
const viewer = new Viewer();
@ -53,8 +52,6 @@ Vue.use(GetTextPlugin, {
defaultLanguage: Vue.config.language,
});
Vue.directive("longclick", VueLongClick({delay: 450, interval: 0}));
Vue.use(VueLuxon);
Vue.use(VueInfiniteScroll);
Vue.use(VueFullscreen);

View file

@ -1,57 +0,0 @@
/*
VueJS long click directive
Based on https://github.com/ittus/vue-long-click (MIT License)
Author: Thang Minh Vu (https://github.com/ittus)
*/
export default ({delay = 400, interval = 50}) => ({
bind: function (el, binding, vNode) {
if (typeof binding.value !== "function") {
const compName = vNode.context.name;
let warn = `[longclick:] provided expression '${binding.expression}' is not a function, but has to be`;
if (compName) {
warn += `Found in component '${compName}' `;
}
console.warn(warn) // eslint-disable-line
}
let pressTimer = null;
let pressInterval = null;
const start = (e) => {
if (e.type === "click" && e.button !== 0) {
return;
}
if (pressTimer === null) {
pressTimer = setTimeout(() => {
if (interval && interval > 0) {
pressInterval = setInterval(() => {
handler();
}, interval);
}
handler();
}, delay);
}
};
// Cancel Timeout
const cancel = () => {
if (pressTimer !== null) {
clearTimeout(pressTimer);
pressTimer = null;
}
if (pressInterval) {
clearInterval(pressInterval);
pressInterval = null;
}
};
// Run Function
const handler = (e) => {
binding.value(e);
}
;["mousedown", "touchstart"].forEach(e => el.addEventListener(e, start))
;["click", "mouseout", "touchend", "touchcancel"].forEach(e => el.addEventListener(e, cancel));
},
});

View file

@ -23,7 +23,7 @@
>
<v-hover>
<v-card tile slot-scope="{ hover }"
@contextmenu="contextMenu($event, photo, index)"
@contextmenu="onContextMenu($event, index)"
:dark="$clipboard.has(photo)"
:class="$clipboard.has(photo) ? 'elevation-10 ma-0 accent darken-1 white--text' : 'elevation-0 ma-1 accent lighten-3'">
<v-img
@ -32,8 +32,8 @@
v-bind:class="{ selected: $clipboard.has(photo) }"
style="cursor: pointer;"
class="accent lighten-2"
v-longclick="longClick"
@click="onClick($event, photo, index)"
@mousedown="onMouseDown($event, index)"
@click.stop.prevent="onClick($event, index)"
>
<v-layout
slot="placeholder"
@ -48,7 +48,7 @@
<v-btn v-if="hover || selection.length > 0" :flat="!hover" :ripple="false"
icon large absolute
:class="$clipboard.has(photo) ? 'p-photo-select' : 'p-photo-select opacity-50'"
@click.stop.prevent="onSelect($event, photo, index)">
@click.stop.prevent="onSelect($event, index)">
<v-icon v-if="selection.length && $clipboard.has(photo)" color="white"
class="t-select t-on">check_circle
</v-icon>
@ -75,7 +75,9 @@
<h3 class="body-2 mb-2" :title="photo.PhotoTitle">
<button @click.exact="editPhoto(index)">
{{ photo.PhotoTitle | truncate(80) }}
<v-icon v-if="showPrivate && photo.PhotoPrivate" size="16" title="Private">lock</v-icon>
<v-icon v-if="showPrivate && photo.PhotoPrivate" size="16" title="Private">
lock
</v-icon>
</button>
</h3>
<div class="caption">
@ -117,51 +119,43 @@
return {
showLocation: this.$config.settings().features.places,
showPrivate: this.$config.settings().library.private,
wasLong: false,
mouseDown: {
index: -1,
timeStamp: -1,
},
};
},
methods: {
longClick() {
this.wasLong = true;
},
onSelect(ev, model, index) {
onSelect(ev, index) {
if (ev.shiftKey) {
this.selectRange(index);
} else {
this.$clipboard.toggle(model);
this.$clipboard.toggle(this.photos[index]);
}
this.wasLong = false;
},
onClick(ev, model, index) {
if (this.wasLong || this.selection.length > 0) {
ev.preventDefault();
ev.stopPropagation();
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.timeStamp = ev.timeStamp;
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
if (this.wasLong || ev.shiftKey) {
if (longClick || this.selection.length > 0) {
if (longClick || ev.shiftKey) {
this.selectRange(index);
} else {
this.$clipboard.toggle(model);
this.$clipboard.toggle(this.photos[index]);
}
} else {
this.openPhoto(index, false);
}
this.wasLong = false;
},
contextMenu(ev, model, index) {
onContextMenu(ev, index) {
if (this.$isMobile) {
ev.preventDefault();
ev.stopPropagation();
if (this.wasLong) {
this.selectRange(index);
} else {
this.$clipboard.toggle(model);
}
this.selectRange(index);
}
this.wasLong = false;
},
selectRange(index) {
this.$clipboard.addRange(index, this.photos);

View file

@ -13,9 +13,9 @@
<td style="user-select: none;">
<v-img class="accent lighten-2" style="cursor: pointer" aspect-ratio="1"
:src="props.item.getThumbnailUrl('tile_50')"
v-longclick="longClick"
@contextmenu="contextMenu($event, props.item, props.index)"
@click="onClick($event, props.item, props.index)"
@mousedown="onMouseDown($event, props.index)"
@contextmenu="onContextMenu($event, props.index)"
@click.stop.prevent="onClick($event, props.index)"
>
<v-layout
slot="placeholder"
@ -37,7 +37,7 @@
</v-btn>
</v-img>
</td>
<td class="p-photo-desc p-pointer" @click.exact="openPhoto(props.index)" style="user-select: none;">
<td class="p-photo-desc p-pointer" @click.exact="editPhoto(props.index)" style="user-select: none;">
{{ props.item.PhotoTitle }}
</td>
<td class="p-photo-desc hidden-xs-only" :title="props.item.getDateString()">
@ -98,7 +98,10 @@
],
showLocation: this.$config.settings().features.places,
showPrivate: this.$config.settings().library.private,
wasLong: false,
mouseDown: {
index: -1,
timeStamp: -1,
},
};
},
watch: {
@ -116,32 +119,36 @@
},
},
methods: {
longClick() {
this.wasLong = true;
},
onClick(ev, model, index) {
ev.preventDefault();
ev.stopPropagation();
if (this.wasLong || ev.shiftKey) {
onSelect(ev, index) {
if (ev.shiftKey) {
this.selectRange(index);
} else {
this.$clipboard.toggle(model);
this.$clipboard.toggle(this.photos[index]);
}
this.wasLong = false;
},
contextMenu(ev, model, index) {
ev.preventDefault();
ev.stopPropagation();
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.timeStamp = ev.timeStamp;
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
if (this.wasLong) {
this.selectRange(index);
if (longClick || this.selection.length > 0) {
if (longClick || ev.shiftKey) {
this.selectRange(index);
} else {
this.$clipboard.toggle(this.photos[index]);
}
} else {
this.$clipboard.toggle(model);
this.openPhoto(index, false);
}
},
onContextMenu(ev, index) {
if (this.$isMobile) {
ev.preventDefault();
ev.stopPropagation();
this.selectRange(index);
}
this.wasLong = false;
},
selectRange(index) {
this.$clipboard.addRange(index, this.photos);

View file

@ -23,15 +23,15 @@
>
<v-hover>
<v-card tile slot-scope="{ hover }"
@contextmenu="contextMenu($event, photo, index)"
@contextmenu="onContextMenu($event, index)"
:class="$clipboard.has(photo) ? 'elevation-10 ma-0' : 'elevation-0 ma-1'"
:title="photo.PhotoTitle">
<v-img :src="photo.getThumbnailUrl('tile_224')"
aspect-ratio="1"
class="accent lighten-2"
style="cursor: pointer"
v-longclick="longClick"
@click="onClick($event, photo, index)"
@mousedown="onMouseDown($event, index)"
@click.stop.prevent="onClick($event, index)"
>
<v-layout
slot="placeholder"
@ -53,7 +53,7 @@
<v-btn v-if="hover || selection.length > 0" :flat="!hover" :ripple="false"
icon small absolute
:class="$clipboard.has(photo) ? 'p-photo-select' : 'p-photo-select opacity-50'"
@click.stop.prevent="onSelect($event, photo, index)">
@click.stop.prevent="onSelect($event, index)">
<v-icon v-if="selection.length && $clipboard.has(photo)" color="white"
class="t-select t-on">check_circle
</v-icon>
@ -100,52 +100,44 @@
},
data() {
return {
wasLong: false,
showPrivate: this.$config.settings().library.private,
mouseDown: {
index: -1,
timeStamp: -1,
},
};
},
methods: {
longClick() {
this.wasLong = true;
},
onSelect(ev, model, index) {
onSelect(ev, index) {
if (ev.shiftKey) {
this.selectRange(index);
} else {
this.$clipboard.toggle(model);
this.$clipboard.toggle(this.photos[index]);
}
this.wasLong = false;
},
onClick(ev, model, index) {
if (this.wasLong || this.selection.length > 0) {
ev.preventDefault();
ev.stopPropagation();
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.timeStamp = ev.timeStamp;
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
if (this.wasLong || ev.shiftKey) {
if (longClick || this.selection.length > 0) {
if (longClick || ev.shiftKey) {
this.selectRange(index);
} else {
this.$clipboard.toggle(model);
this.$clipboard.toggle(this.photos[index]);
}
} else {
this.openPhoto(index, false);
}
this.wasLong = false;
},
contextMenu(ev, model, index) {
onContextMenu(ev, index) {
if (this.$isMobile) {
ev.preventDefault();
ev.stopPropagation();
if (this.wasLong) {
this.selectRange(index);
} else {
this.$clipboard.toggle(model);
}
this.selectRange(index);
}
this.wasLong = false;
},
selectRange(index) {
this.$clipboard.addRange(index, this.photos);

View file

@ -61,15 +61,15 @@
<v-hover>
<v-card tile class="accent lighten-3"
slot-scope="{ hover }"
@contextmenu="contextMenu($event, album, index)"
@contextmenu="onContextMenu($event, index)"
:dark="selection.includes(album.AlbumUUID)"
:class="selection.includes(album.AlbumUUID) ? 'elevation-10 ma-0 accent darken-1 white--text' : 'elevation-0 ma-1 accent lighten-3'"
:to="{name: 'album', params: {uuid: album.AlbumUUID, slug: album.AlbumSlug}}"
>
<v-img
:src="album.getThumbnailUrl('tile_500')"
v-longclick="longClick"
@click="onClick($event, album, index)"
@mousedown="onMouseDown($event, index)"
@click="onClick($event, index)"
aspect-ratio="1"
class="accent lighten-2"
>
@ -183,7 +183,10 @@
search: this.$gettext("Search"),
name: this.$gettext("Album Name"),
},
wasLong: false,
mouseDown: {
index: -1,
timeStamp: -1,
},
lastId: "",
};
},
@ -213,45 +216,40 @@
return (rangeEnd - rangeStart) + 1;
},
longClick() {
this.wasLong = true;
},
onSelect(ev, model, index) {
onSelect(ev, index) {
if (ev.shiftKey) {
this.selectRange(index, this.results);
} else {
this.toggleSelection(model.getId());
this.toggleSelection(this.results[index].getId());
}
this.wasLong = false;
},
onClick(ev, model, index) {
if (this.wasLong || this.selection.length > 0) {
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.timeStamp = ev.timeStamp;
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
if (longClick || this.selection.length > 0) {
ev.preventDefault();
ev.stopPropagation();
if (this.wasLong || ev.shiftKey) {
if (longClick || ev.shiftKey) {
this.selectRange(index, this.results);
} else {
this.toggleSelection(model.getId());
this.toggleSelection(this.results[index].getId());
}
}
this.wasLong = false;
},
contextMenu(ev, model, index) {
onContextMenu(ev, index) {
if (this.$isMobile) {
ev.preventDefault();
ev.stopPropagation();
if (this.wasLong) {
if(this.results[index]) {
this.selectRange(index, this.results);
} else {
this.toggleSelection(model.getId());
}
}
this.wasLong = false;
},
clearQuery() {
this.filter.q = '';

View file

@ -64,14 +64,14 @@
<v-hover>
<v-card tile class="accent lighten-3"
slot-scope="{ hover }"
@contextmenu="contextMenu($event, label, index)"
@contextmenu="onContextMenu($event, index)"
:dark="selection.includes(label.LabelUUID)"
:class="selection.includes(label.LabelUUID) ? 'elevation-10 ma-0 accent darken-1 white--text' : 'elevation-0 ma-1 accent lighten-3'"
:to="{name: 'photos', query: {q: 'label:' + (label.CustomSlug ? label.CustomSlug : label.LabelSlug)}}">
<v-img
:src="label.getThumbnailUrl('tile_500')"
v-longclick="longClick"
@click="onClick($event, label, index)"
@mousedown="onMouseDown($event, index)"
@click="onClick($event, index)"
aspect-ratio="1"
class="accent lighten-2"
>
@ -185,7 +185,10 @@
name: this.$gettext("Label Name"),
},
titleRule: v => v.length <= 25 || this.$gettext("Name too long"),
wasLong: false,
mouseDown: {
index: -1,
timeStamp: -1,
},
lastId: "",
};
},
@ -215,45 +218,40 @@
return (rangeEnd - rangeStart) + 1;
},
longClick() {
this.wasLong = true;
},
onSelect(ev, model, index) {
onSelect(ev, index) {
if (ev.shiftKey) {
this.selectRange(index, this.results);
} else {
this.toggleSelection(model.getId());
this.toggleSelection(this.results[index].getId());
}
this.wasLong = false;
},
onClick(ev, model, index) {
if (this.wasLong || this.selection.length > 0) {
onMouseDown(ev, index) {
this.mouseDown.index = index;
this.mouseDown.timeStamp = ev.timeStamp;
},
onClick(ev, index) {
let longClick = (this.mouseDown.index === index && ev.timeStamp - this.mouseDown.timeStamp > 400);
if (longClick || this.selection.length > 0) {
ev.preventDefault();
ev.stopPropagation();
if (this.wasLong || ev.shiftKey) {
if (longClick || ev.shiftKey) {
this.selectRange(index, this.results);
} else {
this.toggleSelection(model.getId());
this.toggleSelection(this.results[index].getId());
}
}
this.wasLong = false;
},
contextMenu(ev, model, index) {
onContextMenu(ev, index) {
if (this.$isMobile) {
ev.preventDefault();
ev.stopPropagation();
if (this.wasLong) {
if(this.results[index]) {
this.selectRange(index, this.results);
} else {
this.toggleSelection(model.getId());
}
}
this.wasLong = false;
},
onSave(label) {
label.update();