Просмотр исходного кода

refactor: Started converting floating and drag box to composition api

Owen Diffey 2 лет назад
Родитель
Сommit
f906a769c6
2 измененных файлов с 282 добавлено и 138 удалено
  1. 146 138
      frontend/src/components/FloatingBox.vue
  2. 136 0
      frontend/src/components/useDragBox.js

+ 146 - 138
frontend/src/components/FloatingBox.vue

@@ -1,3 +1,148 @@
+<script setup lang="ts">
+// WIP
+import { onMounted, onUnmounted, ref, defineExpose } from "vue";
+import useDragBox from "@/components/useDragBox.js";
+
+const props = defineProps({
+	id: { type: String, default: null },
+	column: { type: Boolean, default: true },
+	title: { type: String, default: null },
+	persist: { type: Boolean, default: false },
+	initial: { type: String, default: "align-top" },
+	minWidth: { type: Number, default: 100 },
+	maxWidth: { type: Number, default: 1000 },
+	minHeight: { type: Number, default: 100 },
+	maxHeight: { type: Number, default: 1000 }
+});
+
+const {
+	dragBox,
+	setInitialBox,
+	onDragBox,
+	resetBoxPosition,
+	onWindowResizeDragBox
+} = useDragBox();
+let debounceTimeout;
+let shown = false;
+
+onMounted(async () => {
+	let initial = {
+		top: 10,
+		left: 10,
+		width: 200,
+		height: 400
+	};
+	if (props.id !== null && localStorage[`box:${props.id}`]) {
+		const json = JSON.parse(localStorage.getItem(`box:${props.id}`));
+		initial = { ...initial, ...json };
+		shown = json.shown;
+	} else {
+		initial.top =
+			props.initial === "align-bottom"
+				? Math.max(document.body.clientHeight - 10 - initial.height, 0)
+				: 10;
+	}
+	setInitialBox(initial, true);
+	resetBoxPosition(true);
+});
+
+const saveBox = () => {
+	if (props.id === null) return;
+	localStorage.setItem(
+		`box:${props.id}`,
+		JSON.stringify({
+			height: dragBox.height,
+			width: dragBox.width,
+			top: dragBox.top,
+			left: dragBox.left,
+			shown
+		})
+	);
+	setInitialBox({
+		top:
+			props.initial === "align-bottom"
+				? Math.max(document.body.clientHeight - 10 - dragBox.height, 0)
+				: 10,
+		left: 10
+	});
+};
+
+const setBoxDimensions = (width, height) => {
+	dragBox.height = Math.min(
+		Math.max(height, props.minHeight),
+		props.maxHeight,
+		document.body.clientHeight
+	);
+
+	dragBox.width = Math.min(
+		Math.max(width, props.minWidth),
+		props.maxWidth,
+		document.body.clientWidth
+	);
+};
+
+const onResizeBox = e => {
+	if (e.target !== ref("box")) return;
+
+	document.onmouseup = () => {
+		document.onmouseup = null;
+
+		const { width, height } = e.target.style;
+		setBoxDimensions(
+			width
+				.split("")
+				.splice(0, width.length - 2)
+				.join(""),
+			height
+				.split("")
+				.splice(0, height.length - 2)
+				.join("")
+		);
+
+		saveBox();
+	};
+};
+
+const toggleBox = () => {
+	shown = !shown;
+	saveBox();
+};
+
+const resetBox = () => {
+	resetBoxPosition();
+	setBoxDimensions(200, 200);
+	saveBox();
+};
+
+const onWindowResize = () => {
+	if (debounceTimeout) clearTimeout(debounceTimeout);
+
+	debounceTimeout = setTimeout(() => {
+		onWindowResizeDragBox();
+		const { width, height } = dragBox;
+		setBoxDimensions(width + 0, height + 0);
+		saveBox();
+	}, 50);
+};
+
+onWindowResize();
+window.addEventListener("resize", onWindowResize);
+
+// const onDragBoxUpdate = () => {
+// 	onWindowResize();
+// };
+
+onUnmounted(() => {
+	window.removeEventListener("resize", onWindowResize);
+	if (debounceTimeout) clearTimeout(debounceTimeout);
+});
+
+defineExpose({
+	resetBox,
+	toggleBox
+});
+</script>
+
 <template>
 	<div
 		ref="box"
@@ -16,7 +161,7 @@
 		@mousedown.left="onResizeBox"
 	>
 		<div class="box-header item-draggable" @mousedown.left="onDragBox">
-			<span class="drag material-icons" @dblclick="resetBoxPosition()"
+			<span class="drag material-icons" @dblclick="resetBox()"
 				>drag_indicator</span
 			>
 			<span v-if="title" class="box-title" :title="title">{{
@@ -35,143 +180,6 @@
 	</div>
 </template>
 
-<script>
-import DragBox from "@/mixins/DragBox.vue";
-
-export default {
-	mixins: [DragBox],
-	props: {
-		id: { type: String, default: null },
-		column: { type: Boolean, default: true },
-		title: { type: String, default: null },
-		persist: { type: Boolean, default: false },
-		initial: { type: String, default: "align-top" },
-		minWidth: { type: Number, default: 100 },
-		maxWidth: { type: Number, default: 1000 },
-		minHeight: { type: Number, default: 100 },
-		maxHeight: { type: Number, default: 1000 }
-	},
-	data() {
-		return {
-			shown: false,
-			debounceTimeout: null
-		};
-	},
-	mounted() {
-		let initial = {
-			top: 10,
-			left: 10,
-			width: 200,
-			height: 400
-		};
-		if (this.id !== null && localStorage[`box:${this.id}`]) {
-			const json = JSON.parse(localStorage.getItem(`box:${this.id}`));
-			initial = { ...initial, ...json };
-			this.shown = json.shown;
-		} else {
-			initial.top =
-				this.initial === "align-bottom"
-					? Math.max(
-							document.body.clientHeight - 10 - initial.height,
-							0
-					  )
-					: 10;
-		}
-		this.setInitialBox(initial, true);
-
-		this.$nextTick(() => {
-			this.onWindowResize();
-			window.addEventListener("resize", this.onWindowResize);
-		});
-	},
-	unmounted() {
-		window.removeEventListener("resize", this.onWindowResize);
-		if (this.debounceTimeout) clearTimeout(this.debounceTimeout);
-	},
-	methods: {
-		setBoxDimensions(width, height) {
-			this.dragBox.height = Math.min(
-				Math.max(height, this.minHeight),
-				this.maxHeight,
-				document.body.clientHeight
-			);
-
-			this.dragBox.width = Math.min(
-				Math.max(width, this.minWidth),
-				this.maxWidth,
-				document.body.clientWidth
-			);
-		},
-		onResizeBox(e) {
-			if (e.target !== this.$refs.box) return;
-
-			document.onmouseup = () => {
-				document.onmouseup = null;
-
-				const { width, height } = e.target.style;
-				this.setBoxDimensions(
-					width
-						.split("")
-						.splice(0, width.length - 2)
-						.join(""),
-					height
-						.split("")
-						.splice(0, height.length - 2)
-						.join("")
-				);
-
-				this.saveBox();
-			};
-		},
-		toggleBox() {
-			this.shown = !this.shown;
-			this.saveBox();
-		},
-		resetBoxDimensions() {
-			this.setBoxDimensions(200, 200);
-			this.saveBox();
-		},
-		saveBox() {
-			if (this.id === null) return;
-			localStorage.setItem(
-				`box:${this.id}`,
-				JSON.stringify({
-					height: this.dragBox.height,
-					width: this.dragBox.width,
-					top: this.dragBox.top,
-					left: this.dragBox.left,
-					shown: this.shown
-				})
-			);
-			this.setInitialBox({
-				top:
-					this.initial === "align-bottom"
-						? Math.max(
-								document.body.clientHeight -
-									10 -
-									this.dragBox.height,
-								0
-						  )
-						: 10,
-				left: 10
-			});
-		},
-		onDragBoxUpdate() {
-			this.onWindowResize();
-		},
-		onWindowResize() {
-			if (this.debounceTimeout) clearTimeout(this.debounceTimeout);
-
-			this.debounceTimeout = setTimeout(() => {
-				const { width, height } = this.dragBox;
-				this.setBoxDimensions(width + 0, height + 0);
-				this.saveBox();
-			}, 50);
-		}
-	}
-};
-</script>
-
 <style lang="less">
 .night-mode .floating-box {
 	background-color: var(--dark-grey-2) !important;

+ 136 - 0
frontend/src/components/useDragBox.js

@@ -0,0 +1,136 @@
+// WIP
+import { onUnmounted } from "vue";
+
+export default () => {
+	let dragBox = {
+		top: 0,
+		left: 0,
+		pos1: 0,
+		pos2: 0,
+		pos3: 0,
+		pos4: 0,
+		width: 400,
+		height: 50,
+		initial: {
+			top: 0,
+			left: 0
+		},
+		latest: {
+			top: null,
+			left: null
+		},
+		debounceTimeout: null,
+		lastTappedDate: 0
+	};
+
+	const setInitialBox = (initial, reset) => {
+		dragBox.initial = initial || dragBox.initial;
+		if (reset) dragBox = { ...dragBox, ...dragBox.initial };
+	};
+
+	// eslint-disable-next-line
+	const resetBoxPosition = preventUpdate => {
+		setInitialBox(null, true);
+		dragBox.latest.top = dragBox.top;
+		dragBox.latest.left = dragBox.left;
+		// if (!preventUpdate && typeof onDragBoxUpdate === "function")
+		// 	onDragBoxUpdate();
+	};
+
+	const onDragBox = e => {
+		const e1 = e || window.event;
+		const e1IsTouch = e1.type === "touchstart";
+		e1.preventDefault();
+
+		if (e1IsTouch) {
+			// Handle double click from touch (if this method is twice in a row within one second)
+			if (Date.now() - dragBox.lastTappedDate <= 1000) {
+				resetBoxPosition();
+				dragBox.lastTappedDate = 0;
+				return;
+			}
+			dragBox.lastTappedDate = Date.now();
+		}
+
+		dragBox.pos3 = e1IsTouch ? e1.changedTouches[0].clientX : e1.clientX;
+		dragBox.pos4 = e1IsTouch ? e1.changedTouches[0].clientY : e1.clientY;
+
+		document.onmousemove = document.ontouchmove = e => {
+			const e2 = e || window.event;
+			const e2IsTouch = e2.type === "touchmove";
+			if (!e2IsTouch) e2.preventDefault();
+
+			// Get the clientX and clientY
+			const e2ClientX = e2IsTouch
+				? e2.changedTouches[0].clientX
+				: e2.clientX;
+			const e2ClientY = e2IsTouch
+				? e2.changedTouches[0].clientY
+				: e2.clientY;
+
+			// calculate the new cursor position:
+			dragBox.pos1 = dragBox.pos3 - e2ClientX;
+			dragBox.pos2 = dragBox.pos4 - e2ClientY;
+			dragBox.pos3 = e2ClientX;
+			dragBox.pos4 = e2ClientY;
+			// set the element's new position:
+			dragBox.top -= dragBox.pos2;
+			dragBox.left -= dragBox.pos1;
+
+			if (dragBox.top > document.body.clientHeight - dragBox.height)
+				dragBox.top = document.body.clientHeight - dragBox.height;
+			if (dragBox.top < 0) dragBox.top = 0;
+			if (dragBox.left > document.body.clientWidth - dragBox.width)
+				dragBox.left = document.body.clientWidth - dragBox.width;
+			if (dragBox.left < 0) dragBox.left = 0;
+		};
+
+		document.onmouseup = document.ontouchend = () => {
+			document.onmouseup = null;
+			document.ontouchend = null;
+			document.onmousemove = null;
+			document.ontouchmove = null;
+
+			// if (typeof onDragBoxUpdate === "function") onDragBoxUpdate();
+		};
+	};
+
+	const onWindowResizeDragBox = () => {
+		if (dragBox.debounceTimeout) clearTimeout(dragBox.debounceTimeout);
+
+		dragBox.debounceTimeout = setTimeout(() => {
+			if (
+				dragBox.top === dragBox.latest.top &&
+				dragBox.left === dragBox.latest.left
+			)
+				resetBoxPosition();
+			else {
+				if (dragBox.top > document.body.clientHeight - dragBox.height)
+					dragBox.top = document.body.clientHeight - dragBox.height;
+				if (dragBox.top < 0) dragBox.top = 0;
+				if (dragBox.left > document.body.clientWidth - dragBox.width)
+					dragBox.left = document.body.clientWidth - dragBox.width;
+				if (dragBox.left < 0) dragBox.left = 0;
+
+				// if (typeof onDragBoxUpdate === "function") onDragBoxUpdate();
+			}
+		}, 50);
+	};
+
+	resetBoxPosition(true);
+
+	onWindowResizeDragBox();
+	window.addEventListener("resize", onWindowResizeDragBox);
+
+	onUnmounted(() => {
+		window.removeEventListener("resize", onWindowResizeDragBox);
+		if (dragBox.debounceTimeout) clearTimeout(dragBox.debounceTimeout);
+	});
+	return {
+		dragBox,
+		setInitialBox,
+		onDragBox,
+		resetBoxPosition,
+		onWindowResizeDragBox
+	};
+};