<commit_before><template>
	<div
		id="image-viewer"
		ref="viewer"
		:class="{opened: link !== null}"
		@wheel="onMouseWheel"
		@touchstart.passive="onTouchStart"
		@click="onClick"
	>
		<template v-if="link !== null">
			<button class="close-btn" aria-label="Close"></button>

			<button
				v-if="previousImage"
				class="previous-image-btn"
				aria-label="Previous image"
				@click.stop="previous"
			></button>
			<button
				v-if="nextImage"
				class="next-image-btn"
				aria-label="Next image"
				@click.stop="next"
			></button>

			<a class="open-btn" :href="link.link" target="_blank" rel="noopener"></a>

			<img
				ref="image"
				:src="link.thumb"
				alt=""
				:style="computeImageStyles"
				@load="onImageLoad"
				@mousedown="onImageMouseDown"
				@touchstart.passive="onImageTouchStart"
			/>
		</template>
	</div>
</template>

<script>
import Mousetrap from "mousetrap";

export default {
	name: "ImageViewer",
	data() {
		return {
			link: null,
			previousImage: null,
			nextImage: null,
			channel: null,

			position: {
				x: 0,
				y: 0,
			},
			transform: {
				x: 0,
				y: 0,
				scale: 0,
			},
		};
	},
	computed: {
		computeImageStyles() {
			// Sub pixels may cause the image to blur in certain browsers
			// round it down to prevent that
			const transformX = Math.floor(this.transform.x);
			const transformY = Math.floor(this.transform.y);

			return {
				left: `${this.position.x}px`,
				top: `${this.position.y}px`,
				transform: `translate3d(${transformX}px, ${transformY}px, 0) scale3d(${this.transform.scale}, ${this.transform.scale}, 1)`,
			};
		},
	},
	watch: {
		link() {
			// TODO: history.pushState
			if (this.link === null) {
				return;
			}

			this.setPrevNextImages();

			this.$root.$on("resize", this.correctPosition);
		},
	},
	mounted() {
		this.$root.$on("escapekey", this.closeViewer);
		Mousetrap.bind("left", this.previous);
		Mousetrap.bind("right", this.next);
	},
	destroyed() {
		this.$root.$off("escapekey", this.closeViewer);
		Mousetrap.unbind("left", this.previous);
		Mousetrap.unbind("right", this.next);
	},
	methods: {
		closeViewer() {
			if (this.link === null) {
				return;
			}

			this.$root.$off("resize", this.correctPosition);
			this.channel = null;<commit_msg>Bind events in image viewer only once<commit_after><template>
	<div
		id="image-viewer"
		ref="viewer"
		:class="{opened: link !== null}"
		@wheel="onMouseWheel"
		@touchstart.passive="onTouchStart"
		@click="onClick"
	>
		<template v-if="link !== null">
			<button class="close-btn" aria-label="Close"></button>

			<button
				v-if="previousImage"
				class="previous-image-btn"
				aria-label="Previous image"
				@click.stop="previous"
			></button>
			<button
				v-if="nextImage"
				class="next-image-btn"
				aria-label="Next image"
				@click.stop="next"
			></button>

			<a class="open-btn" :href="link.link" target="_blank" rel="noopener"></a>

			<img
				ref="image"
				:src="link.thumb"
				alt=""
				:style="computeImageStyles"
				@load="onImageLoad"
				@mousedown="onImageMouseDown"
				@touchstart.passive="onImageTouchStart"
			/>
		</template>
	</div>
</template>

<script>
import Mousetrap from "mousetrap";

export default {
	name: "ImageViewer",
	data() {
		return {
			link: null,
			previousImage: null,
			nextImage: null,
			channel: null,

			position: {
				x: 0,
				y: 0,
			},
			transform: {
				x: 0,
				y: 0,
				scale: 0,
			},
		};
	},
	computed: {
		computeImageStyles() {
			// Sub pixels may cause the image to blur in certain browsers
			// round it down to prevent that
			const transformX = Math.floor(this.transform.x);
			const transformY = Math.floor(this.transform.y);

			return {
				left: `${this.position.x}px`,
				top: `${this.position.y}px`,
				transform: `translate3d(${transformX}px, ${transformY}px, 0) scale3d(${this.transform.scale}, ${this.transform.scale}, 1)`,
			};
		},
	},
	watch: {
		link(newLink, oldLink) {
			// TODO: history.pushState
			if (newLink === null) {
				this.$root.$off("escapekey", this.closeViewer);
				this.$root.$off("resize", this.correctPosition);
				Mousetrap.unbind("left", this.previous);
				Mousetrap.unbind("right", this.next);
				return;
			}

			this.setPrevNextImages();

			if (!oldLink) {
				this.$root.$on("escapekey", this.closeViewer);
				this.$root.$on("resize", this.correctPosition);
				Mousetrap.bind("left", this.previous);
				Mousetrap.bind("right", this.next);
			}
		},
	},
	methods: {
		closeViewer() {
			if (this.link === null) {
				return;
			}

			this.channel = null;
{'fraction_non_alphanumeric': 0.18072024593763725, 'fraction_numerical': 0.003952569169960474, 'mean_word_length': 3.2850423330197556, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4019622', 'n_tokens_mistral': 2006, 'n_tokens_neox': 1634, 'n_words': 304}