<commit_before><!--
  - @copyright Copyright (c) 2020 <NAME> <<EMAIL>>
  -
  - @author <NAME> <<EMAIL>>
  -
  - @license GNU AGPL version 3 or any later version
  -
  - This program is free software: you can redistribute it and/or modify
  - it under the terms of the GNU Affero General Public License as
  - published by the Free Software Foundation, either version 3 of the
  - License, or (at your option) any later version.
  -
  - This program is distributed in the hope that it will be useful,
  - but WITHOUT ANY WARRANTY; without even the implied warranty of
  - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  - GNU Affero General Public License for more details.
  -
  - You should have received a copy of the GNU Affero General Public License
  - along with this program. If not, see <http://www.gnu.org/licenses/>.
-->

<template>
	<div class="wrapper">
		<div
			class="grid"
			:style="{ gridTemplateColumns: `repeat(${columns},  minmax(${minWidth}px, 1fr))`, gridTemplateRows: `repeat(${rows}, minmax(${minHeight}px, 1fr)))`}">
			<div
				v-for="video in displayedVideos"
				:key="video"
				class="video"
				v-text="video" />
		</div>
		<button v-if="hasNextPage"
			class="grid-navigation next"
			@click="handleClickNext">
			Next
		</button>
		<button v-if="hasPreviousPage"
			class="grid-navigation previous"
			@click="handleClickPrevious">
			Previous
		</button>
	</div>
</template>

<script>
export default {
	name: 'GridView',

	props: {
		gridWidth: {
			type: Number,
			required: true,
		},
		gridHeight: {
			type: Number,
			required: true,
		},
		/**
		 * Max number of videos per page. `0`, the default value, means no cap
		 */
		videosCap: {
			type: Number,
			default: 0,
		},
	},

	data() {
		return {
			videos: Array.from(Array(99).keys()),
			// Min width and height of the video components
			minWidth: 200,
			minHeight: 200,
			// Array of currently displayed videos
			displayedVideos: [],
			columns: 0,
			rows: 0,
		}
	},

	computed: {

		// Number of videos TODO: link it to the real one
		videosCount() {
			return this.videos.length
		},

		// The aspect ratio of main-view and of the grid itself
		gridAspectRatio() {
			return this.gridWidth / this.gridHeight
		},

		// Max number of columns given the size of the parent
		columnsMax() {
			if (Math.floor(this.gridWidth / this.minWidth) < 1) {
				// Return at least 1 column
				return 1.2
			} else {
				return Math.floor(this.gridWidth / this.minWidth)
			}
		},

		// Max number of rows given the size of the parent
		rowsMax() {
			if (Math.floor(this.gridHeight / this.minHeight) < 1) {
				// Return at least 1 row
				return 1
			} else {
				return Math.floor(this.gridHeight / this.minHeight)
			}
		},

		hasNextPage() {
			if (this.displayedVideos !== []) {
				return this.displayedVideos[this.displayedVideos.length - 1] !== this.videos[this.videos.length - 1]
			} else {
				return false
			}
		},

		hasPreviousPage() {
			if (this.displayedVideos !== []) {
				return this.displayedVideos[0] !== this.videos[0]
			} else {
				return false
			}
		},
	},

	watch: {
		gridAspectRatio() {
		// If the aspect ratio changes, rebuild the grid
			this.makeGrid()
		},
	},

	beforeMount() {
		this.makeGrid()
	},

	methods: {
		makeGrid() {
		// Start by assigning the max possible value to rows and columns. This
		// will fit as many video components as possible given the parent's
		// dimensions.
			this.columns = this.columnsMax
			this.rows = this.rowsMax
			// However, if we have only a couple of videos to display and a very big
			// window, we now have a lot of columns and rows, and our video components
			// would be too small. To solve this, we shrink this 'virtual grid' we've
			// just created to fit the number of elements that we have.
			if (this.videosCap !== 0) {
				this.shrinkGrid(this.videosCap)
			}
			this.shrinkGrid(this.videosCount)
			// Once the grid is done, populate it with video components
			this.displayedVideos = this.videos.slice(0, this.rows * this.columns)

		},

		shrinkGrid(videos) {
		// Max available grid slots given parent's dimensions and the minimum video<commit_msg>Debounce the rebuilding of the grid when parent size changes<commit_after><!--
  - @copyright Copyright (c) 2020 <NAME> <<EMAIL>>
  -
  - @author <NAME> <<EMAIL>>
  -
  - @license GNU AGPL version 3 or any later version
  -
  - This program is free software: you can redistribute it and/or modify
  - it under the terms of the GNU Affero General Public License as
  - published by the Free Software Foundation, either version 3 of the
  - License, or (at your option) any later version.
  -
  - This program is distributed in the hope that it will be useful,
  - but WITHOUT ANY WARRANTY; without even the implied warranty of
  - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  - GNU Affero General Public License for more details.
  -
  - You should have received a copy of the GNU Affero General Public License
  - along with this program. If not, see <http://www.gnu.org/licenses/>.
-->

<template>
	<div class="wrapper">
		<div
			class="grid"
			:style="{ gridTemplateColumns: `repeat(${columns},  minmax(${minWidth}px, 1fr))`, gridTemplateRows: `repeat(${rows}, minmax(${minHeight}px, 1fr)))`}">
			<div
				v-for="video in displayedVideos"
				:key="video"
				class="video"
				v-text="video" />
		</div>
		<button v-if="hasNextPage"
			class="grid-navigation next"
			@click="handleClickNext">
			Next
		</button>
		<button v-if="hasPreviousPage"
			class="grid-navigation previous"
			@click="handleClickPrevious">
			Previous
		</button>
	</div>
</template>

<script>
import debounce from 'debounce'
export default {
	name: 'GridView',

	props: {
		gridWidth: {
			type: Number,
			required: true,
		},
		gridHeight: {
			type: Number,
			required: true,
		},
		/**
		 * Max number of videos per page. `0`, the default value, means no cap
		 */
		videosCap: {
			type: Number,
			default: 0,
		},
	},

	data() {
		return {
			videos: Array.from(Array(99).keys()),
			// Min width and height of the video components
			minWidth: 200,
			minHeight: 200,
			// Array of currently displayed videos
			displayedVideos: [],
			columns: 0,
			rows: 0,
		}
	},

	computed: {

		// Number of videos TODO: link it to the real one
		videosCount() {
			return this.videos.length
		},

		// The aspect ratio of main-view and of the grid itself
		gridAspectRatio() {
			return this.gridWidth / this.gridHeight
		},

		// Max number of columns given the size of the parent
		columnsMax() {
			if (Math.floor(this.gridWidth / this.minWidth) < 1) {
				// Return at least 1 column
				return 1.2
			} else {
				return Math.floor(this.gridWidth / this.minWidth)
			}
		},

		// Max number of rows given the size of the parent
		rowsMax() {
			if (Math.floor(this.gridHeight / this.minHeight) < 1) {
				// Return at least 1 row
				return 1
			} else {
				return Math.floor(this.gridHeight / this.minHeight)
			}
		},

		hasNextPage() {
			if (this.displayedVideos !== []) {
				return this.displayedVideos[this.displayedVideos.length - 1] !== this.videos[this.videos.length - 1]
			} else {
				return false
			}
		},

		hasPreviousPage() {
			if (this.displayedVideos !== []) {
				return this.displayedVideos[0] !== this.videos[0]
			} else {
				return false
			}
		},
	},

	watch: {
		gridAspectRatio() {
		// If the aspect ratio changes, rebuild the grid
			debounce(this.makeGrid(), 200)
		},
	},

	beforeMount() {
		this.makeGrid()
	},

	methods: {
		makeGrid() {
		// Start by assigning the max possible value to rows and columns. This
		// will fit as many video components as possible given the parent's
		// dimensions.
			this.columns = this.columnsMax
			this.rows = this.rowsMax
			// However, if we have only a couple of videos to display and a very big
			// window, we now have a lot of columns and rows, and our video components
			// would be too small. To solve this, we shrink this 'virtual grid' we've
			// just created to fit the number of elements that we have.
			if (this.videosCap !== 0) {
				this.shrinkGrid(this.videosCap)
			}
			this.shrinkGrid(this.videosCount)
			// Once the grid is done, populate it with video components
			this.displayedVideos = this.videos.slice(0, this.rows * this.columns)

		},

		shrinkGrid(videos) {
		// Max available grid slots given parent's dimensions and the minimum video
{'fraction_non_alphanumeric': 0.11836783250059481, 'fraction_numerical': 0.00820842255531763, 'mean_word_length': 2.908414690841469, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '3936131', 'n_tokens_mistral': 3172, 'n_tokens_neox': 2638, 'n_words': 905}