Browse Source

chore(eslint): added vue/order-in-components as a rule for consistency

Signed-off-by: Jonathan <theflametrooper@gmail.com>
Jonathan 4 years ago
parent
commit
5ded59f38a
30 changed files with 906 additions and 903 deletions
  1. 2 1
      frontend/.eslintrc
  2. 23 23
      frontend/src/App.vue
  3. 3 3
      frontend/src/components/Modal.vue
  4. 3 3
      frontend/src/components/common/UserIdToUsername.vue
  5. 7 6
      frontend/src/components/layout/MainHeader.vue
  6. 389 389
      frontend/src/components/modals/EditSong.vue
  7. 67 67
      frontend/src/components/modals/EditStation.vue
  8. 5 5
      frontend/src/components/modals/Login.vue
  9. 10 10
      frontend/src/components/ui/FloatingBox.vue
  10. 3 3
      frontend/src/mixins/ScrollAndFetchHandler.vue
  11. 5 5
      frontend/src/pages/Admin/EditNews.vue
  12. 6 6
      frontend/src/pages/Admin/EditUser.vue
  13. 2 2
      frontend/src/pages/Admin/IssuesModal.vue
  14. 3 3
      frontend/src/pages/Admin/index.vue
  15. 10 10
      frontend/src/pages/Admin/tabs/Punishments.vue
  16. 29 29
      frontend/src/pages/Admin/tabs/QueueSongs.vue
  17. 5 5
      frontend/src/pages/Admin/tabs/Reports.vue
  18. 35 35
      frontend/src/pages/Admin/tabs/Songs.vue
  19. 16 16
      frontend/src/pages/Admin/tabs/Stations.vue
  20. 9 9
      frontend/src/pages/Admin/tabs/Users.vue
  21. 6 6
      frontend/src/pages/Home/index.vue
  22. 13 12
      frontend/src/pages/ResetPassword.vue
  23. 2 2
      frontend/src/pages/Settings/tabs/Account.vue
  24. 2 2
      frontend/src/pages/Settings/tabs/Profile.vue
  25. 17 17
      frontend/src/pages/Settings/tabs/Security.vue
  26. 5 5
      frontend/src/pages/Station/AddSongToPlaylist.vue
  27. 10 10
      frontend/src/pages/Station/AddSongToQueue.vue
  28. 2 2
      frontend/src/pages/Station/SongsList.vue
  29. 2 2
      frontend/src/pages/Station/UsersList.vue
  30. 215 215
      frontend/src/pages/Station/index.vue

+ 2 - 1
frontend/.eslintrc

@@ -33,6 +33,7 @@
 		"no-shadow": 0,
 		"no-new": 0,
 		"import/no-unresolved": 0,
-		"prettier/prettier": ["error"]
+		"prettier/prettier": ["error"],
+		"vue/order-in-components": 2
 	}
 }

+ 23 - 23
frontend/src/App.vue

@@ -24,6 +24,13 @@ import io from "./io";
 import keyboardShortcuts from "./keyboardShortcuts";
 
 export default {
+	components: {
+		WhatIsNew,
+		MobileAlert,
+		LoginModal,
+		RegisterModal,
+		Banned
+	},
 	replace: false,
 	data() {
 		return {
@@ -42,23 +49,6 @@ export default {
 		currentlyActive: state => state.modals.currentlyActive,
 		nightmode: state => state.user.preferences.nightmode
 	}),
-	methods: {
-		submitOnEnter: (cb, event) => {
-			if (event.which === 13) cb();
-		},
-		enableNightMode: () => {
-			document
-				.getElementsByTagName("body")[0]
-				.classList.add("night-mode");
-		},
-		disableNightMode: () => {
-			document
-				.getElementsByTagName("body")[0]
-				.classList.remove("night-mode");
-		},
-		...mapActions("modals", ["closeCurrentModal"]),
-		...mapActions("user/preferences", ["changeNightmode"])
-	},
 	watch: {
 		socketConnected(connected) {
 			console.log(connected);
@@ -166,12 +156,22 @@ export default {
 			});
 		});
 	},
-	components: {
-		WhatIsNew,
-		MobileAlert,
-		LoginModal,
-		RegisterModal,
-		Banned
+	methods: {
+		submitOnEnter: (cb, event) => {
+			if (event.which === 13) cb();
+		},
+		enableNightMode: () => {
+			document
+				.getElementsByTagName("body")[0]
+				.classList.add("night-mode");
+		},
+		disableNightMode: () => {
+			document
+				.getElementsByTagName("body")[0]
+				.classList.remove("night-mode");
+		},
+		...mapActions("modals", ["closeCurrentModal"]),
+		...mapActions("user/preferences", ["changeNightmode"])
 	}
 };
 </script>

+ 3 - 3
frontend/src/components/Modal.vue

@@ -25,6 +25,9 @@ export default {
 	props: {
 		title: { type: String, default: "Modal" }
 	},
+	mounted() {
+		this.type = this.toCamelCase(this.title);
+	},
 	methods: {
 		toCamelCase: str => {
 			return str
@@ -35,9 +38,6 @@ export default {
 				.replace(/ /g, "");
 		},
 		...mapActions("modals", ["closeCurrentModal"])
-	},
-	mounted() {
-		this.type = this.toCamelCase(this.title);
 	}
 };
 </script>

+ 3 - 3
frontend/src/components/common/UserIdToUsername.vue

@@ -24,13 +24,13 @@ export default {
 			username: "unknown"
 		};
 	},
-	methods: {
-		...mapActions("user/auth", ["getUsernameFromId"])
-	},
 	mounted() {
 		this.getUsernameFromId(this.$props.userId).then(res => {
 			if (res) this.username = res;
 		});
+	},
+	methods: {
+		...mapActions("user/auth", ["getUsernameFromId"])
 	}
 };
 </script>

+ 7 - 6
frontend/src/components/layout/MainHeader.vue

@@ -86,6 +86,12 @@ export default {
 			}
 		};
 	},
+	computed: mapState({
+		modals: state => state.modals.modals.header,
+		role: state => state.user.auth.role,
+		loggedIn: state => state.user.auth.loggedIn,
+		username: state => state.user.auth.username
+	}),
 	mounted() {
 		lofig.get("frontendDomain").then(frontendDomain => {
 			this.frontendDomain = frontendDomain;
@@ -95,12 +101,7 @@ export default {
 			this.siteSettings = siteSettings;
 		});
 	},
-	computed: mapState({
-		modals: state => state.modals.modals.header,
-		role: state => state.user.auth.role,
-		loggedIn: state => state.user.auth.loggedIn,
-		username: state => state.user.auth.username
-	}),
+
 	methods: {
 		...mapActions("modals", ["openModal"]),
 		...mapActions("user/auth", ["logout"])

+ 389 - 389
frontend/src/components/modals/EditSong.vue

@@ -624,6 +624,320 @@ export default {
 		}
 		/* eslint-enable */
 	},
+	mounted() {
+		// if (this.modals.editSong = false) this.video.player.stopVideo();
+
+		// this.loadVideoById(
+		//   this.editing.song.songId,
+		//   this.editing.song.skipDuration
+		// );
+
+		this.discogsQuery = this.editing.song.title;
+
+		lofig.get("cookie.secure").then(useHTTPS => {
+			this.useHTTPS = useHTTPS;
+		});
+
+		io.getSocket(socket => {
+			this.socket = socket;
+		});
+
+		this.interval = setInterval(() => {
+			if (
+				this.editing.song.duration !== -1 &&
+				this.video.paused === false &&
+				this.playerReady &&
+				this.video.player.getCurrentTime() -
+					this.editing.song.skipDuration >
+					this.editing.song.duration
+			) {
+				this.video.paused = false;
+				this.video.player.stopVideo();
+				this.drawCanvas();
+			}
+			if (this.playerReady) {
+				this.youtubeVideoCurrentTime = this.video.player
+					.getCurrentTime()
+					.toFixed(3);
+			}
+
+			if (this.video.paused === false) this.drawCanvas();
+		}, 200);
+
+		this.video.player = new window.YT.Player("player", {
+			height: 298,
+			width: 530,
+			videoId: this.editing.song.songId,
+			host: "https://www.youtube-nocookie.com",
+			playerVars: {
+				controls: 0,
+				iv_load_policy: 3,
+				rel: 0,
+				showinfo: 0,
+				autoplay: 1
+			},
+			startSeconds: this.editing.song.skipDuration,
+			events: {
+				onReady: () => {
+					let volume = parseInt(localStorage.getItem("volume"));
+					volume = typeof volume === "number" ? volume : 20;
+					console.log(`Seekto: ${this.editing.song.skipDuration}`);
+					this.video.player.seekTo(this.editing.song.skipDuration);
+					this.video.player.setVolume(volume);
+					if (volume > 0) this.video.player.unMute();
+					this.youtubeVideoDuration = this.video.player.getDuration();
+					this.youtubeVideoNote = "(~)";
+					this.playerReady = true;
+
+					this.drawCanvas();
+				},
+				onStateChange: event => {
+					this.drawCanvas();
+
+					if (event.data === 1) {
+						if (!this.video.autoPlayed) {
+							this.video.autoPlayed = true;
+							return this.video.player.stopVideo();
+						}
+
+						this.video.paused = false;
+						let youtubeDuration = this.video.player.getDuration();
+						this.youtubeVideoDuration = youtubeDuration;
+						this.youtubeVideoNote = "";
+
+						if (this.editing.song.duration === -1)
+							this.editing.song.duration = youtubeDuration;
+
+						youtubeDuration -= this.editing.song.skipDuration;
+						if (this.editing.song.duration > youtubeDuration + 1) {
+							this.video.player.stopVideo();
+							this.video.paused = true;
+							return new Toast({
+								content:
+									"Video can't play. Specified duration is bigger than the YouTube song duration.",
+								timeout: 4000
+							});
+						}
+						if (this.editing.song.duration <= 0) {
+							this.video.player.stopVideo();
+							this.video.paused = true;
+							return new Toast({
+								content:
+									"Video can't play. Specified duration has to be more than 0 seconds.",
+								timeout: 4000
+							});
+						}
+
+						if (
+							this.video.player.getCurrentTime() <
+							this.editing.song.skipDuration
+						) {
+							return this.video.player.seekTo(
+								this.editing.song.skipDuration
+							);
+						}
+					} else if (event.data === 2) {
+						this.video.paused = true;
+					}
+
+					return false;
+				}
+			}
+		});
+
+		let volume = parseFloat(localStorage.getItem("volume"));
+		volume =
+			typeof volume === "number" && !Number.isNaN(volume) ? volume : 20;
+		localStorage.setItem("volume", volume);
+		this.volumeSliderValue = volume * 100;
+
+		keyboardShortcuts.registerShortcut("editSong.pauseResumeVideo", {
+			keyCode: 101,
+			preventDefault: true,
+			handler: () => {
+				if (this.video.paused) this.settings("play");
+				else this.settings("pause");
+			}
+		});
+
+		keyboardShortcuts.registerShortcut("editSong.stopVideo", {
+			keyCode: 101,
+			ctrl: true,
+			preventDefault: true,
+			handler: () => {
+				this.settings("stop");
+			}
+		});
+
+		keyboardShortcuts.registerShortcut("editSong.skipToLast10Secs", {
+			keyCode: 102,
+			preventDefault: true,
+			handler: () => {
+				this.settings("skipToLast10Secs");
+			}
+		});
+
+		keyboardShortcuts.registerShortcut("editSong.lowerVolumeLarge", {
+			keyCode: 98,
+			preventDefault: true,
+			handler: () => {
+				this.volumeSliderValue = Math.max(
+					0,
+					this.volumeSliderValue - 1000
+				);
+				this.changeVolume();
+			}
+		});
+
+		keyboardShortcuts.registerShortcut("editSong.lowerVolumeSmall", {
+			keyCode: 98,
+			ctrl: true,
+			preventDefault: true,
+			handler: () => {
+				this.volumeSliderValue = Math.max(
+					0,
+					this.volumeSliderValue - 100
+				);
+				this.changeVolume();
+			}
+		});
+
+		keyboardShortcuts.registerShortcut("editSong.increaseVolumeLarge", {
+			keyCode: 104,
+			preventDefault: true,
+			handler: () => {
+				this.volumeSliderValue = Math.min(
+					10000,
+					this.volumeSliderValue + 1000
+				);
+				this.changeVolume();
+			}
+		});
+
+		keyboardShortcuts.registerShortcut("editSong.increaseVolumeSmall", {
+			keyCode: 104,
+			ctrl: true,
+			preventDefault: true,
+			handler: () => {
+				this.volumeSliderValue = Math.min(
+					10000,
+					this.volumeSliderValue + 100
+				);
+				this.changeVolume();
+			}
+		});
+
+		keyboardShortcuts.registerShortcut("editSong.save", {
+			keyCode: 83,
+			ctrl: true,
+			preventDefault: true,
+			handler: () => {
+				this.save(this.editing.song, false);
+			}
+		});
+
+		keyboardShortcuts.registerShortcut("editSong.close", {
+			keyCode: 88,
+			ctrl: true,
+			preventDefault: true,
+			handler: () => {
+				this.closeModal({
+					sector: "admin",
+					modal: "editSong"
+				});
+				setTimeout(() => {
+					window.focusedElementBefore.focus();
+				}, 500);
+			}
+		});
+
+		keyboardShortcuts.registerShortcut("editSong.focusTitle", {
+			keyCode: 36,
+			preventDefault: true,
+			handler: () => {
+				document.getElementById("title-input").focus();
+			}
+		});
+
+		keyboardShortcuts.registerShortcut("editSong.focusDiscogs", {
+			keyCode: 35,
+			preventDefault: true,
+			handler: () => {
+				document.getElementById("discogs-input").focus();
+			}
+		});
+
+		keyboardShortcuts.registerShortcut("editSong.useAllDiscogs", {
+			keyCode: 68,
+			alt: true,
+			ctrl: true,
+			preventDefault: true,
+			handler: () => {
+				this.getAlbumData("title");
+				this.getAlbumData("albumArt");
+				this.getAlbumData("artists");
+				this.getAlbumData("genres");
+			}
+		});
+
+		keyboardShortcuts.registerShortcut("editSong.resetDuration", {
+			keyCode: 82,
+			alt: true,
+			ctrl: true,
+			preventDefault: true,
+			handler: () => {
+				this.fillDuration();
+			}
+		});
+
+		/*
+		
+		editSong.pauseResume - Num 5 - Pause/resume song
+		editSong.stopVideo - Ctrl - Num 5 - Stop
+		editSong.skipToLast10Secs - Num 6 - Skip to last 10 seconds
+
+		editSong.volumeDown5 - Num 2 - Volume down by 10
+		editSong.volumeDown1 - Ctrl - Num 2 - Volume down by 1
+		editSong.volumeUp5 - Num 8 - Volume up by 10
+		editSong.volumeUp1 - Ctrl - Num 8 - Volume up by 1
+
+		editSong.focusTitle - Home - Focus the title input
+		editSong.focusDicogs - End - Focus the discogs input
+
+		editSong.save - Ctrl - S - Saves song
+		editSong.close - Ctrl - X - Closes modal
+
+		editSong.useAllDiscogs - Ctrl - Alt - D - Sets all fields to the Discogs data
+		editSong.resetDuration - Ctrl - Alt - R - Resets the duration
+
+		Inside Discogs inputs: Ctrl - D - Sets this field to the Discogs data
+
+		*/
+	},
+	beforeDestroy() {
+		this.playerReady = false;
+		clearInterval(this.interval);
+
+		const shortcutNames = [
+			"editSong.pauseResume",
+			"editSong.stopVideo",
+			"editSong.skipToLast10Secs",
+			"editSong.volumeDown5",
+			"editSong.volumeDown1",
+			"editSong.volumeUp5",
+			"editSong.volumeUp1",
+			"editSong.focusTitle",
+			"editSong.focusDicogs",
+			"editSong.save",
+			"editSong.close",
+			"editSong.useAllDiscogs",
+			"editSong.resetDuration"
+		];
+
+		shortcutNames.forEach(shortcutName => {
+			keyboardShortcuts.unregisterShortcut(shortcutName);
+		});
+	},
 	methods: {
 		save(songToCopy, close) {
 			const song = JSON.parse(JSON.stringify(songToCopy));
@@ -973,411 +1287,97 @@ export default {
 						timeout: 3000
 					});
 				if (genre) {
-					this.editing.song.genres.push(genre);
-					document.getElementById("new-genre").value = "";
-					return false;
-				}
-
-				return new Toast({
-					content: "Genre cannot be empty",
-					timeout: 3000
-				});
-			}
-			if (type === "artists") {
-				const artist = document.getElementById("new-artist").value;
-				if (this.editing.song.artists.indexOf(artist) !== -1)
-					return new Toast({
-						content: "Artist already exists",
-						timeout: 3000
-					});
-				if (document.getElementById("new-artist").value !== "") {
-					this.editing.song.artists.push(artist);
-					document.getElementById("new-artist").value = "";
-					return false;
-				}
-				return new Toast({
-					content: "Artist cannot be empty",
-					timeout: 3000
-				});
-			}
-
-			return false;
-		},
-		removeTag(type, index) {
-			if (type === "genres") this.editing.song.genres.splice(index, 1);
-			else if (type === "artists")
-				this.editing.song.artists.splice(index, 1);
-		},
-		drawCanvas() {
-			const canvasElement = document.getElementById("durationCanvas");
-			const ctx = canvasElement.getContext("2d");
-
-			const videoDuration = Number(this.youtubeVideoDuration);
-
-			const skipDuration = Number(this.editing.song.skipDuration);
-			const duration = Number(this.editing.song.duration);
-			const afterDuration = videoDuration - (skipDuration + duration);
-
-			const width = 530;
-
-			const currentTime = this.video.player.getCurrentTime();
-
-			const widthSkipDuration = (skipDuration / videoDuration) * width;
-			const widthDuration = (duration / videoDuration) * width;
-			const widthAfterDuration = (afterDuration / videoDuration) * width;
-
-			const widthCurrentTime = (currentTime / videoDuration) * width;
-
-			const skipDurationColor = "#F42003";
-			const durationColor = "#03A9F4";
-			const afterDurationColor = "#41E841";
-			const currentDurationColor = "#3b25e8";
-
-			ctx.fillStyle = skipDurationColor;
-			ctx.fillRect(0, 0, widthSkipDuration, 20);
-			ctx.fillStyle = durationColor;
-			ctx.fillRect(widthSkipDuration, 0, widthDuration, 20);
-			ctx.fillStyle = afterDurationColor;
-			ctx.fillRect(
-				widthSkipDuration + widthDuration,
-				0,
-				widthAfterDuration,
-				20
-			);
-
-			ctx.fillStyle = currentDurationColor;
-			ctx.fillRect(widthCurrentTime, 0, 1, 20);
-		},
-		toggleGenreHelper() {
-			this.$refs.genreHelper.toggleBox();
-		},
-		resetGenreHelper() {
-			this.$refs.genreHelper.resetBox();
-		},
-		...mapActions("admin/songs", [
-			"stopVideo",
-			"loadVideoById",
-			"pauseVideo",
-			"getCurrentTime",
-			"editSong",
-			"updateSongField",
-			"selectDiscogsInfo"
-		]),
-		...mapActions("modals", ["closeModal"])
-	},
-	mounted() {
-		// if (this.modals.editSong = false) this.video.player.stopVideo();
-
-		// this.loadVideoById(
-		//   this.editing.song.songId,
-		//   this.editing.song.skipDuration
-		// );
-
-		this.discogsQuery = this.editing.song.title;
-
-		lofig.get("cookie.secure").then(useHTTPS => {
-			this.useHTTPS = useHTTPS;
-		});
-
-		io.getSocket(socket => {
-			this.socket = socket;
-		});
-
-		this.interval = setInterval(() => {
-			if (
-				this.editing.song.duration !== -1 &&
-				this.video.paused === false &&
-				this.playerReady &&
-				this.video.player.getCurrentTime() -
-					this.editing.song.skipDuration >
-					this.editing.song.duration
-			) {
-				this.video.paused = false;
-				this.video.player.stopVideo();
-				this.drawCanvas();
-			}
-			if (this.playerReady) {
-				this.youtubeVideoCurrentTime = this.video.player
-					.getCurrentTime()
-					.toFixed(3);
-			}
-
-			if (this.video.paused === false) this.drawCanvas();
-		}, 200);
-
-		this.video.player = new window.YT.Player("player", {
-			height: 298,
-			width: 530,
-			videoId: this.editing.song.songId,
-			host: "https://www.youtube-nocookie.com",
-			playerVars: {
-				controls: 0,
-				iv_load_policy: 3,
-				rel: 0,
-				showinfo: 0,
-				autoplay: 1
-			},
-			startSeconds: this.editing.song.skipDuration,
-			events: {
-				onReady: () => {
-					let volume = parseInt(localStorage.getItem("volume"));
-					volume = typeof volume === "number" ? volume : 20;
-					console.log(`Seekto: ${this.editing.song.skipDuration}`);
-					this.video.player.seekTo(this.editing.song.skipDuration);
-					this.video.player.setVolume(volume);
-					if (volume > 0) this.video.player.unMute();
-					this.youtubeVideoDuration = this.video.player.getDuration();
-					this.youtubeVideoNote = "(~)";
-					this.playerReady = true;
-
-					this.drawCanvas();
-				},
-				onStateChange: event => {
-					this.drawCanvas();
-
-					if (event.data === 1) {
-						if (!this.video.autoPlayed) {
-							this.video.autoPlayed = true;
-							return this.video.player.stopVideo();
-						}
-
-						this.video.paused = false;
-						let youtubeDuration = this.video.player.getDuration();
-						this.youtubeVideoDuration = youtubeDuration;
-						this.youtubeVideoNote = "";
-
-						if (this.editing.song.duration === -1)
-							this.editing.song.duration = youtubeDuration;
-
-						youtubeDuration -= this.editing.song.skipDuration;
-						if (this.editing.song.duration > youtubeDuration + 1) {
-							this.video.player.stopVideo();
-							this.video.paused = true;
-							return new Toast({
-								content:
-									"Video can't play. Specified duration is bigger than the YouTube song duration.",
-								timeout: 4000
-							});
-						}
-						if (this.editing.song.duration <= 0) {
-							this.video.player.stopVideo();
-							this.video.paused = true;
-							return new Toast({
-								content:
-									"Video can't play. Specified duration has to be more than 0 seconds.",
-								timeout: 4000
-							});
-						}
-
-						if (
-							this.video.player.getCurrentTime() <
-							this.editing.song.skipDuration
-						) {
-							return this.video.player.seekTo(
-								this.editing.song.skipDuration
-							);
-						}
-					} else if (event.data === 2) {
-						this.video.paused = true;
-					}
-
+					this.editing.song.genres.push(genre);
+					document.getElementById("new-genre").value = "";
 					return false;
 				}
-			}
-		});
-
-		let volume = parseFloat(localStorage.getItem("volume"));
-		volume =
-			typeof volume === "number" && !Number.isNaN(volume) ? volume : 20;
-		localStorage.setItem("volume", volume);
-		this.volumeSliderValue = volume * 100;
-
-		keyboardShortcuts.registerShortcut("editSong.pauseResumeVideo", {
-			keyCode: 101,
-			preventDefault: true,
-			handler: () => {
-				if (this.video.paused) this.settings("play");
-				else this.settings("pause");
-			}
-		});
-
-		keyboardShortcuts.registerShortcut("editSong.stopVideo", {
-			keyCode: 101,
-			ctrl: true,
-			preventDefault: true,
-			handler: () => {
-				this.settings("stop");
-			}
-		});
-
-		keyboardShortcuts.registerShortcut("editSong.skipToLast10Secs", {
-			keyCode: 102,
-			preventDefault: true,
-			handler: () => {
-				this.settings("skipToLast10Secs");
-			}
-		});
-
-		keyboardShortcuts.registerShortcut("editSong.lowerVolumeLarge", {
-			keyCode: 98,
-			preventDefault: true,
-			handler: () => {
-				this.volumeSliderValue = Math.max(
-					0,
-					this.volumeSliderValue - 1000
-				);
-				this.changeVolume();
-			}
-		});
-
-		keyboardShortcuts.registerShortcut("editSong.lowerVolumeSmall", {
-			keyCode: 98,
-			ctrl: true,
-			preventDefault: true,
-			handler: () => {
-				this.volumeSliderValue = Math.max(
-					0,
-					this.volumeSliderValue - 100
-				);
-				this.changeVolume();
-			}
-		});
-
-		keyboardShortcuts.registerShortcut("editSong.increaseVolumeLarge", {
-			keyCode: 104,
-			preventDefault: true,
-			handler: () => {
-				this.volumeSliderValue = Math.min(
-					10000,
-					this.volumeSliderValue + 1000
-				);
-				this.changeVolume();
-			}
-		});
-
-		keyboardShortcuts.registerShortcut("editSong.increaseVolumeSmall", {
-			keyCode: 104,
-			ctrl: true,
-			preventDefault: true,
-			handler: () => {
-				this.volumeSliderValue = Math.min(
-					10000,
-					this.volumeSliderValue + 100
-				);
-				this.changeVolume();
-			}
-		});
-
-		keyboardShortcuts.registerShortcut("editSong.save", {
-			keyCode: 83,
-			ctrl: true,
-			preventDefault: true,
-			handler: () => {
-				this.save(this.editing.song, false);
-			}
-		});
 
-		keyboardShortcuts.registerShortcut("editSong.close", {
-			keyCode: 88,
-			ctrl: true,
-			preventDefault: true,
-			handler: () => {
-				this.closeModal({
-					sector: "admin",
-					modal: "editSong"
+				return new Toast({
+					content: "Genre cannot be empty",
+					timeout: 3000
 				});
-				setTimeout(() => {
-					window.focusedElementBefore.focus();
-				}, 500);
-			}
-		});
-
-		keyboardShortcuts.registerShortcut("editSong.focusTitle", {
-			keyCode: 36,
-			preventDefault: true,
-			handler: () => {
-				document.getElementById("title-input").focus();
-			}
-		});
-
-		keyboardShortcuts.registerShortcut("editSong.focusDiscogs", {
-			keyCode: 35,
-			preventDefault: true,
-			handler: () => {
-				document.getElementById("discogs-input").focus();
 			}
-		});
-
-		keyboardShortcuts.registerShortcut("editSong.useAllDiscogs", {
-			keyCode: 68,
-			alt: true,
-			ctrl: true,
-			preventDefault: true,
-			handler: () => {
-				this.getAlbumData("title");
-				this.getAlbumData("albumArt");
-				this.getAlbumData("artists");
-				this.getAlbumData("genres");
+			if (type === "artists") {
+				const artist = document.getElementById("new-artist").value;
+				if (this.editing.song.artists.indexOf(artist) !== -1)
+					return new Toast({
+						content: "Artist already exists",
+						timeout: 3000
+					});
+				if (document.getElementById("new-artist").value !== "") {
+					this.editing.song.artists.push(artist);
+					document.getElementById("new-artist").value = "";
+					return false;
+				}
+				return new Toast({
+					content: "Artist cannot be empty",
+					timeout: 3000
+				});
 			}
-		});
 
-		keyboardShortcuts.registerShortcut("editSong.resetDuration", {
-			keyCode: 82,
-			alt: true,
-			ctrl: true,
-			preventDefault: true,
-			handler: () => {
-				this.fillDuration();
-			}
-		});
+			return false;
+		},
+		removeTag(type, index) {
+			if (type === "genres") this.editing.song.genres.splice(index, 1);
+			else if (type === "artists")
+				this.editing.song.artists.splice(index, 1);
+		},
+		drawCanvas() {
+			const canvasElement = document.getElementById("durationCanvas");
+			const ctx = canvasElement.getContext("2d");
 
-		/*
-		
-		editSong.pauseResume - Num 5 - Pause/resume song
-		editSong.stopVideo - Ctrl - Num 5 - Stop
-		editSong.skipToLast10Secs - Num 6 - Skip to last 10 seconds
+			const videoDuration = Number(this.youtubeVideoDuration);
 
-		editSong.volumeDown5 - Num 2 - Volume down by 10
-		editSong.volumeDown1 - Ctrl - Num 2 - Volume down by 1
-		editSong.volumeUp5 - Num 8 - Volume up by 10
-		editSong.volumeUp1 - Ctrl - Num 8 - Volume up by 1
+			const skipDuration = Number(this.editing.song.skipDuration);
+			const duration = Number(this.editing.song.duration);
+			const afterDuration = videoDuration - (skipDuration + duration);
 
-		editSong.focusTitle - Home - Focus the title input
-		editSong.focusDicogs - End - Focus the discogs input
+			const width = 530;
 
-		editSong.save - Ctrl - S - Saves song
-		editSong.close - Ctrl - X - Closes modal
+			const currentTime = this.video.player.getCurrentTime();
 
-		editSong.useAllDiscogs - Ctrl - Alt - D - Sets all fields to the Discogs data
-		editSong.resetDuration - Ctrl - Alt - R - Resets the duration
+			const widthSkipDuration = (skipDuration / videoDuration) * width;
+			const widthDuration = (duration / videoDuration) * width;
+			const widthAfterDuration = (afterDuration / videoDuration) * width;
 
-		Inside Discogs inputs: Ctrl - D - Sets this field to the Discogs data
+			const widthCurrentTime = (currentTime / videoDuration) * width;
 
-		*/
-	},
-	beforeDestroy() {
-		this.playerReady = false;
-		clearInterval(this.interval);
+			const skipDurationColor = "#F42003";
+			const durationColor = "#03A9F4";
+			const afterDurationColor = "#41E841";
+			const currentDurationColor = "#3b25e8";
 
-		const shortcutNames = [
-			"editSong.pauseResume",
-			"editSong.stopVideo",
-			"editSong.skipToLast10Secs",
-			"editSong.volumeDown5",
-			"editSong.volumeDown1",
-			"editSong.volumeUp5",
-			"editSong.volumeUp1",
-			"editSong.focusTitle",
-			"editSong.focusDicogs",
-			"editSong.save",
-			"editSong.close",
-			"editSong.useAllDiscogs",
-			"editSong.resetDuration"
-		];
+			ctx.fillStyle = skipDurationColor;
+			ctx.fillRect(0, 0, widthSkipDuration, 20);
+			ctx.fillStyle = durationColor;
+			ctx.fillRect(widthSkipDuration, 0, widthDuration, 20);
+			ctx.fillStyle = afterDurationColor;
+			ctx.fillRect(
+				widthSkipDuration + widthDuration,
+				0,
+				widthAfterDuration,
+				20
+			);
 
-		shortcutNames.forEach(shortcutName => {
-			keyboardShortcuts.unregisterShortcut(shortcutName);
-		});
+			ctx.fillStyle = currentDurationColor;
+			ctx.fillRect(widthCurrentTime, 0, 1, 20);
+		},
+		toggleGenreHelper() {
+			this.$refs.genreHelper.toggleBox();
+		},
+		resetGenreHelper() {
+			this.$refs.genreHelper.resetBox();
+		},
+		...mapActions("admin/songs", [
+			"stopVideo",
+			"loadVideoById",
+			"pauseVideo",
+			"getCurrentTime",
+			"editSong",
+			"updateSongField",
+			"selectDiscogsInfo"
+		]),
+		...mapActions("modals", ["closeModal"])
 	}
 };
 </script>

+ 67 - 67
frontend/src/components/modals/EditStation.vue

@@ -415,70 +415,8 @@ import io from "../../io";
 import validation from "../../validation";
 
 export default {
-	computed: {
-		...mapState("admin/station", {
-			stations: state => state.stations
-		}),
-		...mapState({
-			editing(state) {
-				return this.$props.store
-					.split("/")
-					.reduce((a, v) => a[v], state).editing;
-			},
-			station(state) {
-				return this.$props.store
-					.split("/")
-					.reduce((a, v) => a[v], state).station;
-			}
-		})
-	},
-	mounted() {
-		io.getSocket(socket => {
-			this.socket = socket;
-
-			this.socket.emit("playlists.indexForUser", res => {
-				if (res.status === "success") this.playlists = res.data;
-			});
-
-			this.socket.on("event:playlist.create", playlist => {
-				this.playlists.push(playlist);
-			});
-			this.socket.on("event:playlist.delete", playlistId => {
-				this.playlists.forEach((playlist, index) => {
-					if (playlist._id === playlistId) {
-						this.playlists.splice(index, 1);
-					}
-				});
-			});
-			this.socket.on("event:playlist.addSong", data => {
-				this.playlists.forEach((playlist, index) => {
-					if (playlist._id === data.playlistId) {
-						this.playlists[index].songs.push(data.song);
-					}
-				});
-			});
-			this.socket.on("event:playlist.removeSong", data => {
-				this.playlists.forEach((playlist, index) => {
-					if (playlist._id === data.playlistId) {
-						this.playlists[index].songs.forEach((song, index2) => {
-							if (song._id === data.songId) {
-								this.playlists[index].songs.splice(index2, 1);
-							}
-						});
-					}
-				});
-			});
-			this.socket.on("event:playlist.updateDisplayName", data => {
-				this.playlists.forEach((playlist, index) => {
-					if (playlist._id === data.playlistId) {
-						this.playlists[index].displayName = data.displayName;
-					}
-				});
-			});
-
-			return socket;
-		});
-	},
+	components: { Modal, PlaylistItem },
+	props: { store: { type: Object, default: () => {} } },
 	data() {
 		return {
 			genreInputValue: "",
@@ -543,7 +481,70 @@ export default {
 			playlists: []
 		};
 	},
-	props: { store: { type: Object, default: () => {} } },
+	computed: {
+		...mapState("admin/station", {
+			stations: state => state.stations
+		}),
+		...mapState({
+			editing(state) {
+				return this.$props.store
+					.split("/")
+					.reduce((a, v) => a[v], state).editing;
+			},
+			station(state) {
+				return this.$props.store
+					.split("/")
+					.reduce((a, v) => a[v], state).station;
+			}
+		})
+	},
+	mounted() {
+		io.getSocket(socket => {
+			this.socket = socket;
+
+			this.socket.emit("playlists.indexForUser", res => {
+				if (res.status === "success") this.playlists = res.data;
+			});
+
+			this.socket.on("event:playlist.create", playlist => {
+				this.playlists.push(playlist);
+			});
+			this.socket.on("event:playlist.delete", playlistId => {
+				this.playlists.forEach((playlist, index) => {
+					if (playlist._id === playlistId) {
+						this.playlists.splice(index, 1);
+					}
+				});
+			});
+			this.socket.on("event:playlist.addSong", data => {
+				this.playlists.forEach((playlist, index) => {
+					if (playlist._id === data.playlistId) {
+						this.playlists[index].songs.push(data.song);
+					}
+				});
+			});
+			this.socket.on("event:playlist.removeSong", data => {
+				this.playlists.forEach((playlist, index) => {
+					if (playlist._id === data.playlistId) {
+						this.playlists[index].songs.forEach((song, index2) => {
+							if (song._id === data.songId) {
+								this.playlists[index].songs.splice(index2, 1);
+							}
+						});
+					}
+				});
+			});
+			this.socket.on("event:playlist.updateDisplayName", data => {
+				this.playlists.forEach((playlist, index) => {
+					if (playlist._id === data.playlistId) {
+						this.playlists[index].displayName = data.displayName;
+					}
+				});
+			});
+
+			return socket;
+		});
+	},
 	methods: {
 		isPlaylistSelected(id) {
 			// TODO Also change this once it changes for a station
@@ -998,8 +999,7 @@ export default {
 				this.editing.blacklistedGenres.splice(index, 1);
 		},
 		...mapActions("modals", ["closeModal"])
-	},
-	components: { Modal, PlaylistItem }
+	}
 };
 </script>
 

+ 5 - 5
frontend/src/components/modals/Login.vue

@@ -91,6 +91,11 @@ export default {
 			serverDomain: ""
 		};
 	},
+	mounted() {
+		lofig.get("serverDomain").then(serverDomain => {
+			this.serverDomain = serverDomain;
+		});
+	},
 	methods: {
 		submitModal() {
 			this.login({
@@ -113,11 +118,6 @@ export default {
 		},
 		...mapActions("modals", ["closeModal"]),
 		...mapActions("user/auth", ["login"])
-	},
-	mounted() {
-		lofig.get("serverDomain").then(serverDomain => {
-			this.serverDomain = serverDomain;
-		});
 	}
 };
 </script>

+ 10 - 10
frontend/src/components/ui/FloatingBox.vue

@@ -39,6 +39,16 @@ export default {
 			pos4: 0
 		};
 	},
+	mounted() {
+		if (this.id !== null && localStorage[`box:${this.id}`]) {
+			const json = JSON.parse(localStorage.getItem(`box:${this.id}`));
+			this.height = json.height;
+			this.width = json.width;
+			this.top = json.top;
+			this.left = json.left;
+			this.shown = json.shown;
+		}
+	},
 	methods: {
 		onDragBox(e) {
 			const e1 = e || window.event;
@@ -115,16 +125,6 @@ export default {
 				})
 			);
 		}
-	},
-	mounted() {
-		if (this.id !== null && localStorage[`box:${this.id}`]) {
-			const json = JSON.parse(localStorage.getItem(`box:${this.id}`));
-			this.height = json.height;
-			this.width = json.width;
-			this.top = json.top;
-			this.left = json.left;
-			this.shown = json.shown;
-		}
 	}
 };
 </script>

+ 3 - 3
frontend/src/mixins/ScrollAndFetchHandler.vue

@@ -17,6 +17,9 @@ export default {
 			return this.maxPosition - 1;
 		}
 	},
+	unmounted() {
+		clearInterval(this.interval);
+	},
 	methods: {
 		handleScroll() {
 			const scrollPosition = document.body.clientHeight + window.scrollY;
@@ -39,9 +42,6 @@ export default {
 				}
 			}, 500);
 		}
-	},
-	unmounted() {
-		clearInterval(this.interval);
 	}
 };
 </script>

+ 5 - 5
frontend/src/pages/Admin/EditNews.vue

@@ -181,6 +181,11 @@ export default {
 			editing: state => state.editing
 		})
 	},
+	mounted() {
+		io.getSocket(socket => {
+			this.socket = socket;
+		});
+	},
 	methods: {
 		addChange(type) {
 			const change = document.getElementById(`edit-${type}`).value.trim();
@@ -223,11 +228,6 @@ export default {
 		},
 		...mapActions("modals", ["closeModal"]),
 		...mapActions("admin/news", ["addChange", "removeChange"])
-	},
-	mounted() {
-		io.getSocket(socket => {
-			this.socket = socket;
-		});
 	}
 };
 </script>

+ 6 - 6
frontend/src/pages/Admin/EditUser.vue

@@ -112,6 +112,12 @@ export default {
 			userId: state => state.user.auth.userId
 		})
 	},
+	mounted() {
+		io.getSocket(socket => {
+			this.socket = socket;
+			return socket;
+		});
+	},
 	methods: {
 		updateUsername() {
 			const { username } = this.editing;
@@ -208,12 +214,6 @@ export default {
 			});
 		},
 		...mapActions("modals", ["closeModal"])
-	},
-	mounted() {
-		io.getSocket(socket => {
-			this.socket = socket;
-			return socket;
-		});
 	}
 };
 </script>

+ 2 - 2
frontend/src/pages/Admin/IssuesModal.vue

@@ -97,6 +97,7 @@ import UserIdToUsername from "../../components/common/UserIdToUsername.vue";
 import Modal from "../../components/Modal.vue";
 
 export default {
+	components: { Modal, UserIdToUsername },
 	computed: {
 		...mapState("admin/reports", {
 			report: state => state.report
@@ -124,8 +125,7 @@ export default {
 		},
 		...mapActions("admin/reports", ["resolveReport"]),
 		...mapActions("modals", ["closeModal"])
-	},
-	components: { Modal, UserIdToUsername }
+	}
 };
 </script>
 

+ 3 - 3
frontend/src/pages/Admin/index.vue

@@ -126,14 +126,14 @@ export default {
 			currentTab: "queueSongs"
 		};
 	},
-	mounted() {
-		this.changeTab(this.$route.path);
-	},
 	watch: {
 		$route(route) {
 			this.changeTab(route.path);
 		}
 	},
+	mounted() {
+		this.changeTab(this.$route.path);
+	},
 	methods: {
 		changeTab(path) {
 			switch (path) {

+ 10 - 10
frontend/src/pages/Admin/tabs/Punishments.vue

@@ -115,6 +115,16 @@ export default {
 			modals: state => state.modals.admin
 		})
 	},
+	mounted() {
+		io.getSocket(socket => {
+			this.socket = socket;
+			if (this.socket.connected) this.init();
+			io.onConnect(() => this.init());
+			socket.on("event:admin.punishment.added", punishment => {
+				this.punishments.push(punishment);
+			});
+		});
+	},
 	methods: {
 		view(punishment) {
 			this.viewPunishment(punishment);
@@ -139,16 +149,6 @@ export default {
 		},
 		...mapActions("modals", ["openModal"]),
 		...mapActions("admin/punishments", ["viewPunishment"])
-	},
-	mounted() {
-		io.getSocket(socket => {
-			this.socket = socket;
-			if (this.socket.connected) this.init();
-			io.onConnect(() => this.init());
-			socket.on("event:admin.punishment.added", punishment => {
-				this.punishments.push(punishment);
-			});
-		});
 	}
 };
 </script>

+ 29 - 29
frontend/src/pages/Admin/tabs/QueueSongs.vue

@@ -215,6 +215,35 @@ export default {
 			if (value === false) this.stopVideo();
 		}
 	},
+	mounted() {
+		io.getSocket(socket => {
+			this.socket = socket;
+
+			this.socket.on("event:admin.queueSong.added", queueSong => {
+				this.songs.push(queueSong);
+			});
+
+			this.socket.on("event:admin.queueSong.removed", songId => {
+				this.songs = this.songs.filter(song => {
+					return song._id !== songId;
+				});
+			});
+
+			this.socket.on("event:admin.queueSong.updated", updatedSong => {
+				for (let i = 0; i < this.songs.length; i += 1) {
+					const song = this.songs[i];
+					if (song._id === updatedSong._id) {
+						Vue.set(this.songs, i, updatedSong);
+					}
+				}
+			});
+
+			if (this.socket.connected) this.init();
+			io.onConnect(() => {
+				this.init();
+			});
+		});
+	},
 	methods: {
 		edit(song, index) {
 			const newSong = {};
@@ -286,35 +315,6 @@ export default {
 		},
 		...mapActions("admin/songs", ["stopVideo", "editSong"]),
 		...mapActions("modals", ["openModal"])
-	},
-	mounted() {
-		io.getSocket(socket => {
-			this.socket = socket;
-
-			this.socket.on("event:admin.queueSong.added", queueSong => {
-				this.songs.push(queueSong);
-			});
-
-			this.socket.on("event:admin.queueSong.removed", songId => {
-				this.songs = this.songs.filter(song => {
-					return song._id !== songId;
-				});
-			});
-
-			this.socket.on("event:admin.queueSong.updated", updatedSong => {
-				for (let i = 0; i < this.songs.length; i += 1) {
-					const song = this.songs[i];
-					if (song._id === updatedSong._id) {
-						Vue.set(this.songs, i, updatedSong);
-					}
-				}
-			});
-
-			if (this.socket.connected) this.init();
-			io.onConnect(() => {
-				this.init();
-			});
-		});
 	}
 };
 </script>

+ 5 - 5
frontend/src/pages/Admin/tabs/Reports.vue

@@ -79,6 +79,11 @@ export default {
 			reports: []
 		};
 	},
+	computed: {
+		...mapState("modals", {
+			modals: state => state.modals.admin
+		})
+	},
 	mounted() {
 		io.getSocket(socket => {
 			this.socket = socket;
@@ -114,11 +119,6 @@ export default {
 			});
 		}
 	},
-	computed: {
-		...mapState("modals", {
-			modals: state => state.modals.admin
-		})
-	},
 	methods: {
 		formatDistance,
 		init() {

+ 35 - 35
frontend/src/pages/Admin/tabs/Songs.vue

@@ -210,8 +210,8 @@ import ScrollAndFetchHandler from "../../../mixins/ScrollAndFetchHandler.vue";
 import io from "../../../io";
 
 export default {
-	mixins: [ScrollAndFetchHandler],
 	components: { EditSong, UserIdToUsername, FloatingBox },
+	mixins: [ScrollAndFetchHandler],
 	data() {
 		return {
 			searchQuery: "",
@@ -301,6 +301,40 @@ export default {
 			if (!val) this.stopVideo();
 		}
 	},
+	mounted() {
+		io.getSocket(socket => {
+			this.socket = socket;
+
+			this.socket.on("event:admin.song.added", song => {
+				this.addSong(song);
+			});
+
+			this.socket.on("event:admin.song.removed", songId => {
+				this.removeSong(songId);
+			});
+
+			this.socket.on("event:admin.song.updated", updatedSong => {
+				this.updateSong(updatedSong);
+			});
+
+			if (this.socket.connected) this.init();
+			io.onConnect(() => {
+				this.init();
+			});
+		});
+
+		if (this.$route.query.songId) {
+			this.socket.emit("songs.getSong", this.$route.query.songId, res => {
+				if (res.status === "success") {
+					this.edit(res.data.song);
+				} else
+					new Toast({
+						content: "Song with that ID not found",
+						timeout: 3000
+					});
+			});
+		}
+	},
 	methods: {
 		edit(song) {
 			this.editSong({ song, type: "songs" });
@@ -376,40 +410,6 @@ export default {
 			"updateSong"
 		]),
 		...mapActions("modals", ["openModal", "closeModal"])
-	},
-	mounted() {
-		io.getSocket(socket => {
-			this.socket = socket;
-
-			this.socket.on("event:admin.song.added", song => {
-				this.addSong(song);
-			});
-
-			this.socket.on("event:admin.song.removed", songId => {
-				this.removeSong(songId);
-			});
-
-			this.socket.on("event:admin.song.updated", updatedSong => {
-				this.updateSong(updatedSong);
-			});
-
-			if (this.socket.connected) this.init();
-			io.onConnect(() => {
-				this.init();
-			});
-		});
-
-		if (this.$route.query.songId) {
-			this.socket.emit("songs.getSong", this.$route.query.songId, res => {
-				if (res.status === "success") {
-					this.edit(res.data.song);
-				} else
-					new Toast({
-						content: "Song with that ID not found",
-						timeout: 3000
-					});
-			});
-		}
 	}
 };
 </script>

+ 16 - 16
frontend/src/pages/Admin/tabs/Stations.vue

@@ -206,6 +206,22 @@ export default {
 			modals: state => state.modals.station
 		})
 	},
+	mounted() {
+		io.getSocket(socket => {
+			this.socket = socket;
+			if (this.socket.connected) this.init();
+
+			this.socket.on("event:admin.station.added", station => {
+				this.stationAdded(station);
+			});
+			this.socket.on("event:admin.station.removed", stationId => {
+				this.stationRemoved(stationId);
+			});
+			io.onConnect(() => {
+				this.init();
+			});
+		});
+	},
 	methods: {
 		createStation() {
 			const {
@@ -340,22 +356,6 @@ export default {
 			"stationRemoved",
 			"stationAdded"
 		])
-	},
-	mounted() {
-		io.getSocket(socket => {
-			this.socket = socket;
-			if (this.socket.connected) this.init();
-
-			this.socket.on("event:admin.station.added", station => {
-				this.stationAdded(station);
-			});
-			this.socket.on("event:admin.station.removed", stationId => {
-				this.stationRemoved(stationId);
-			});
-			io.onConnect(() => {
-				this.init();
-			});
-		});
 	}
 };
 </script>

+ 9 - 9
frontend/src/pages/Admin/tabs/Users.vue

@@ -75,6 +75,15 @@ export default {
 			modals: state => state.modals.admin
 		})
 	},
+	mounted() {
+		console.log("mounted");
+
+		io.getSocket(socket => {
+			this.socket = socket;
+			if (this.socket.connected) this.init();
+			io.onConnect(() => this.init());
+		});
+	},
 	methods: {
 		edit(user) {
 			this.editUser(user);
@@ -97,15 +106,6 @@ export default {
 		},
 		...mapActions("admin/users", ["editUser"]),
 		...mapActions("modals", ["openModal"])
-	},
-	mounted() {
-		console.log("mounted");
-
-		io.getSocket(socket => {
-			this.socket = socket;
-			if (this.socket.connected) this.init();
-			io.onConnect(() => this.init());
-		});
 	}
 };
 </script>

+ 6 - 6
frontend/src/pages/Home/index.vue

@@ -157,6 +157,12 @@ import UserIdToUsername from "../../components/common/UserIdToUsername.vue";
 import io from "../../io";
 
 export default {
+	components: {
+		MainHeader,
+		MainFooter,
+		CreateCommunityStation,
+		UserIdToUsername
+	},
 	data() {
 		return {
 			recaptcha: {
@@ -293,12 +299,6 @@ export default {
 			});
 		},
 		...mapActions("modals", ["openModal"])
-	},
-	components: {
-		MainHeader,
-		MainFooter,
-		CreateCommunityStation,
-		UserIdToUsername
 	}
 };
 </script>

+ 13 - 12
frontend/src/pages/ResetPassword.vue

@@ -248,6 +248,13 @@ import validation from "../validation";
 
 export default {
 	components: { MainHeader, MainFooter },
+	props: {
+		mode: {
+			default: "reset",
+			enum: ["reset", "set"],
+			type: String
+		}
+	},
 	data() {
 		return {
 			email: "",
@@ -274,18 +281,6 @@ export default {
 			step: 1
 		};
 	},
-	props: {
-		mode: {
-			default: "reset",
-			enum: ["reset", "set"],
-			type: String
-		}
-	},
-	mounted() {
-		io.getSocket(socket => {
-			this.socket = socket;
-		});
-	},
 	watch: {
 		email(value) {
 			if (
@@ -320,6 +315,12 @@ export default {
 			this.checkPasswordMatch(this.newPassword, value);
 		}
 	},
+	mounted() {
+		io.getSocket(socket => {
+			this.socket = socket;
+		});
+	},
+
 	methods: {
 		checkPasswordMatch(newPassword, newPasswordAgain) {
 			if (newPasswordAgain !== newPassword) {

+ 2 - 2
frontend/src/pages/Settings/tabs/Account.vue

@@ -77,6 +77,7 @@ import io from "../../../io";
 import SaveButton from "../mixins/SaveButton.vue";
 
 export default {
+	mixins: [SaveButton],
 	data() {
 		return {
 			validation: {
@@ -251,7 +252,6 @@ export default {
 			);
 		},
 		...mapActions("settings", ["updateOriginalUser"])
-	},
-	mixins: [SaveButton]
+	}
 };
 </script>

+ 2 - 2
frontend/src/pages/Settings/tabs/Profile.vue

@@ -102,6 +102,7 @@ import io from "../../../io";
 import SaveButton from "../mixins/SaveButton.vue";
 
 export default {
+	mixins: [SaveButton],
 	data() {
 		return {
 			notesUri: ""
@@ -288,8 +289,7 @@ export default {
 			);
 		},
 		...mapActions("settings", ["updateOriginalUser"])
-	},
-	mixins: [SaveButton]
+	}
 };
 </script>
 

+ 17 - 17
frontend/src/pages/Settings/tabs/Security.vue

@@ -177,6 +177,23 @@ export default {
 			userId: state => state.user.auth.userId
 		})
 	},
+	watch: {
+		// eslint-disable-next-line func-names
+		"validation.newPassword.value": function(value) {
+			if (!validation.isLength(value, 6, 200)) {
+				this.validation.newPassword.message =
+					"Password must have between 6 and 200 characters.";
+				this.validation.newPassword.valid = false;
+			} else if (!validation.regex.password.test(value)) {
+				this.validation.newPassword.message =
+					"Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character.";
+				this.validation.newPassword.valid = false;
+			} else {
+				this.validation.newPassword.message = "Everything looks great!";
+				this.validation.newPassword.valid = true;
+			}
+		}
+	},
 	mounted() {
 		io.getSocket(socket => {
 			this.socket = socket;
@@ -239,23 +256,6 @@ export default {
 				new Toast({ content: res.message, timeout: 4000 });
 			});
 		}
-	},
-	watch: {
-		// eslint-disable-next-line func-names
-		"validation.newPassword.value": function(value) {
-			if (!validation.isLength(value, 6, 200)) {
-				this.validation.newPassword.message =
-					"Password must have between 6 and 200 characters.";
-				this.validation.newPassword.valid = false;
-			} else if (!validation.regex.password.test(value)) {
-				this.validation.newPassword.message =
-					"Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character.";
-				this.validation.newPassword.valid = false;
-			} else {
-				this.validation.newPassword.message = "Everything looks great!";
-				this.validation.newPassword.valid = true;
-			}
-		}
 	}
 };
 </script>

+ 5 - 5
frontend/src/pages/Station/AddSongToPlaylist.vue

@@ -52,6 +52,11 @@ export default {
 			song: null
 		};
 	},
+	computed: {
+		...mapState("station", {
+			currentSong: state => state.currentSong
+		})
+	},
 	mounted() {
 		this.songId = this.currentSong.songId;
 		this.song = this.currentSong;
@@ -67,11 +72,6 @@ export default {
 			});
 		});
 	},
-	computed: {
-		...mapState("station", {
-			currentSong: state => state.currentSong
-		})
-	},
 	methods: {
 		addSongToPlaylist(playlistId) {
 			this.socket.emit(

+ 10 - 10
frontend/src/pages/Station/AddSongToQueue.vue

@@ -230,6 +230,7 @@ import Modal from "../../components/Modal.vue";
 import io from "../../io";
 
 export default {
+	components: { Modal, PlaylistItem },
 	data() {
 		return {
 			querySearch: "",
@@ -245,6 +246,14 @@ export default {
 		privatePlaylistQueueSelected: state =>
 			state.station.privatePlaylistQueueSelected
 	}),
+	mounted() {
+		io.getSocket(socket => {
+			this.socket = socket;
+			this.socket.emit("playlists.indexForUser", res => {
+				if (res.status === "success") this.playlists = res.data;
+			});
+		});
+	},
 	methods: {
 		isPlaylistSelected(playlistId) {
 			return this.privatePlaylistQueueSelected === playlistId;
@@ -377,16 +386,7 @@ export default {
 		},
 		...mapActions("station", ["updatePrivatePlaylistQueueSelected"]),
 		...mapActions("user/playlists", ["editPlaylist"])
-	},
-	mounted() {
-		io.getSocket(socket => {
-			this.socket = socket;
-			this.socket.emit("playlists.indexForUser", res => {
-				if (res.status === "success") this.playlists = res.data;
-			});
-		});
-	},
-	components: { Modal, PlaylistItem }
+	}
 };
 </script>
 

+ 2 - 2
frontend/src/pages/Station/SongsList.vue

@@ -130,6 +130,7 @@ import Sidebar from "../../components/Sidebar.vue";
 import UserIdToUsername from "../../components/common/UserIdToUsername.vue";
 
 export default {
+	components: { UserIdToUsername, Sidebar },
 	data() {
 		return {
 			utils,
@@ -169,8 +170,7 @@ export default {
 			);
 		},
 		...mapActions("modals", ["openModal"])
-	},
-	components: { UserIdToUsername, Sidebar }
+	}
 };
 </script>
 

+ 2 - 2
frontend/src/pages/Station/UsersList.vue

@@ -24,11 +24,11 @@ import { mapState } from "vuex";
 import Sidebar from "../../components/Sidebar.vue";
 
 export default {
+	components: { Sidebar },
 	computed: mapState({
 		users: state => state.station.users,
 		userCount: state => state.station.userCount
-	}),
-	components: { Sidebar }
+	})
 };
 </script>
 

+ 215 - 215
frontend/src/pages/Station/index.vue

@@ -484,6 +484,21 @@ import keyboardShortcuts from "../../keyboardShortcuts";
 import utils from "../../../js/utils";
 
 export default {
+	components: {
+		StationHeader,
+		SongQueue: () => import("./AddSongToQueue.vue"),
+		AddToPlaylist: () => import("./AddSongToPlaylist.vue"),
+		EditPlaylist: () => import("../../components/modals/EditPlaylist.vue"),
+		CreatePlaylist: () =>
+			import("../../components/modals/CreatePlaylist.vue"),
+		EditStation: () => import("../../components/modals/EditStation.vue"),
+		Report: () => import("./Report.vue"),
+		SongsListSidebar: () => import("./SongsList.vue"),
+		UsersSidebar: () => import("./UsersList.vue"),
+		UserIdToUsername,
+		Z404,
+		FloatingBox
+	},
 	data() {
 		return {
 			utils,
@@ -536,6 +551,206 @@ export default {
 			return Object.values(this.sidebars).indexOf(true) !== -1;
 		}
 	},
+	mounted() {
+		Date.currently = () => {
+			return new Date().getTime() + this.systemDifference;
+		};
+
+		this.stationName = this.$route.params.id;
+
+		window.stationInterval = 0;
+
+		io.getSocket(socket => {
+			this.socket = socket;
+
+			io.removeAllListeners();
+			if (this.socket.connected) this.join();
+			io.onConnect(this.join);
+			this.socket.emit("stations.existsByName", this.stationName, res => {
+				if (res.status === "failure" || !res.exists) {
+					this.loading = false;
+					this.exists = false;
+				}
+			});
+			this.socket.on("event:songs.next", data => {
+				const previousSong = this.currentSong.songId
+					? this.currentSong
+					: null;
+				this.updatePreviousSong(previousSong);
+				this.updateCurrentSong(
+					data.currentSong ? data.currentSong : {}
+				);
+				this.startedAt = data.startedAt;
+				this.updateStationPaused(data.paused);
+				this.timePaused = data.timePaused;
+				if (data.currentSong) {
+					this.updateNoSong(false);
+					if (this.currentSong.artists)
+						this.currentSong.artists = this.currentSong.artists.join(
+							", "
+						);
+					if (!this.playerReady) this.youtubeReady();
+					else this.playVideo();
+					this.socket.emit(
+						"songs.getOwnSongRatings",
+						data.currentSong.songId,
+						song => {
+							if (this.currentSong.songId === song.songId) {
+								this.liked = song.liked;
+								this.disliked = song.disliked;
+							}
+						}
+					);
+				} else {
+					if (this.playerReady) this.player.pauseVideo();
+					this.updateNoSong(true);
+				}
+
+				let isInQueue = false;
+				this.songsList.forEach(queueSong => {
+					if (queueSong.requestedBy === this.userId) isInQueue = true;
+				});
+				if (
+					!isInQueue &&
+					this.privatePlaylistQueueSelected &&
+					(this.automaticallyRequestedSongId !==
+						this.currentSong.songId ||
+						!this.currentSong.songId)
+				) {
+					this.addFirstPrivatePlaylistSongToQueue();
+				}
+			});
+
+			this.socket.on("event:stations.pause", data => {
+				this.pausedAt = data.pausedAt;
+				this.updateStationPaused(true);
+				this.pauseLocalPlayer();
+			});
+
+			this.socket.on("event:stations.resume", data => {
+				this.timePaused = data.timePaused;
+				this.updateStationPaused(false);
+				if (!this.localPaused) this.resumeLocalPlayer();
+			});
+
+			this.socket.on("event:stations.remove", () => {
+				window.location.href = "/";
+				return true;
+			});
+
+			this.socket.on("event:song.like", data => {
+				if (!this.noSong) {
+					if (data.songId === this.currentSong.songId) {
+						this.currentSong.dislikes = data.dislikes;
+						this.currentSong.likes = data.likes;
+					}
+				}
+			});
+
+			this.socket.on("event:song.dislike", data => {
+				if (!this.noSong) {
+					if (data.songId === this.currentSong.songId) {
+						this.currentSong.dislikes = data.dislikes;
+						this.currentSong.likes = data.likes;
+					}
+				}
+			});
+
+			this.socket.on("event:song.unlike", data => {
+				if (!this.noSong) {
+					if (data.songId === this.currentSong.songId) {
+						this.currentSong.dislikes = data.dislikes;
+						this.currentSong.likes = data.likes;
+					}
+				}
+			});
+
+			this.socket.on("event:song.undislike", data => {
+				if (!this.noSong) {
+					if (data.songId === this.currentSong.songId) {
+						this.currentSong.dislikes = data.dislikes;
+						this.currentSong.likes = data.likes;
+					}
+				}
+			});
+
+			this.socket.on("event:song.newRatings", data => {
+				if (!this.noSong) {
+					if (data.songId === this.currentSong.songId) {
+						this.liked = data.liked;
+						this.disliked = data.disliked;
+					}
+				}
+			});
+
+			this.socket.on("event:queue.update", queue => {
+				if (this.station.type === "community")
+					this.updateSongsList(queue);
+			});
+
+			this.socket.on("event:song.voteSkipSong", () => {
+				if (this.currentSong) this.currentSong.skipVotes += 1;
+			});
+
+			this.socket.on("event:privatePlaylist.selected", playlistId => {
+				if (this.station.type === "community") {
+					this.station.privatePlaylist = playlistId;
+				}
+			});
+
+			this.socket.on("event:partyMode.updated", partyMode => {
+				if (this.station.type === "community") {
+					this.station.partyMode = partyMode;
+				}
+			});
+
+			this.socket.on("event:newOfficialPlaylist", playlist => {
+				if (this.station.type === "official") {
+					this.updateSongsList(playlist);
+				}
+			});
+
+			this.socket.on("event:users.updated", users => {
+				this.updateUsers(users);
+			});
+
+			this.socket.on("event:userCount.updated", userCount => {
+				this.updateUserCount(userCount);
+			});
+
+			this.socket.on("event:queueLockToggled", locked => {
+				this.station.locked = locked;
+			});
+		});
+
+		if (JSON.parse(localStorage.getItem("muted"))) {
+			this.muted = true;
+			this.player.setVolume(0);
+			this.volumeSliderValue = 0 * 100;
+		} else {
+			let volume = parseFloat(localStorage.getItem("volume"));
+			volume =
+				typeof volume === "number" && !Number.isNaN(volume)
+					? volume
+					: 20;
+			localStorage.setItem("volume", volume);
+			this.volumeSliderValue = volume * 100;
+		}
+	},
+	beforeDestroy() {
+		const shortcutNames = [
+			"station.pauseResume",
+			"station.skipStation",
+			"station.lowerVolumeLarge",
+			"station.lowerVolumeSmall",
+			"station.increaseVolumeLarge",
+			"station.increaseVolumeSmall"
+		];
+
+		shortcutNames.forEach(shortcutName => {
+			keyboardShortcuts.unregisterShortcut(shortcutName);
+		});
+	},
 	methods: {
 		isOwnerOnly() {
 			return this.loggedIn && this.userId === this.station.owner;
@@ -1245,221 +1460,6 @@ export default {
 			"updateLocalPaused",
 			"updateNoSong"
 		])
-	},
-	mounted() {
-		Date.currently = () => {
-			return new Date().getTime() + this.systemDifference;
-		};
-
-		this.stationName = this.$route.params.id;
-
-		window.stationInterval = 0;
-
-		io.getSocket(socket => {
-			this.socket = socket;
-
-			io.removeAllListeners();
-			if (this.socket.connected) this.join();
-			io.onConnect(this.join);
-			this.socket.emit("stations.existsByName", this.stationName, res => {
-				if (res.status === "failure" || !res.exists) {
-					this.loading = false;
-					this.exists = false;
-				}
-			});
-			this.socket.on("event:songs.next", data => {
-				const previousSong = this.currentSong.songId
-					? this.currentSong
-					: null;
-				this.updatePreviousSong(previousSong);
-				this.updateCurrentSong(
-					data.currentSong ? data.currentSong : {}
-				);
-				this.startedAt = data.startedAt;
-				this.updateStationPaused(data.paused);
-				this.timePaused = data.timePaused;
-				if (data.currentSong) {
-					this.updateNoSong(false);
-					if (this.currentSong.artists)
-						this.currentSong.artists = this.currentSong.artists.join(
-							", "
-						);
-					if (!this.playerReady) this.youtubeReady();
-					else this.playVideo();
-					this.socket.emit(
-						"songs.getOwnSongRatings",
-						data.currentSong.songId,
-						song => {
-							if (this.currentSong.songId === song.songId) {
-								this.liked = song.liked;
-								this.disliked = song.disliked;
-							}
-						}
-					);
-				} else {
-					if (this.playerReady) this.player.pauseVideo();
-					this.updateNoSong(true);
-				}
-
-				let isInQueue = false;
-				this.songsList.forEach(queueSong => {
-					if (queueSong.requestedBy === this.userId) isInQueue = true;
-				});
-				if (
-					!isInQueue &&
-					this.privatePlaylistQueueSelected &&
-					(this.automaticallyRequestedSongId !==
-						this.currentSong.songId ||
-						!this.currentSong.songId)
-				) {
-					this.addFirstPrivatePlaylistSongToQueue();
-				}
-			});
-
-			this.socket.on("event:stations.pause", data => {
-				this.pausedAt = data.pausedAt;
-				this.updateStationPaused(true);
-				this.pauseLocalPlayer();
-			});
-
-			this.socket.on("event:stations.resume", data => {
-				this.timePaused = data.timePaused;
-				this.updateStationPaused(false);
-				if (!this.localPaused) this.resumeLocalPlayer();
-			});
-
-			this.socket.on("event:stations.remove", () => {
-				window.location.href = "/";
-				return true;
-			});
-
-			this.socket.on("event:song.like", data => {
-				if (!this.noSong) {
-					if (data.songId === this.currentSong.songId) {
-						this.currentSong.dislikes = data.dislikes;
-						this.currentSong.likes = data.likes;
-					}
-				}
-			});
-
-			this.socket.on("event:song.dislike", data => {
-				if (!this.noSong) {
-					if (data.songId === this.currentSong.songId) {
-						this.currentSong.dislikes = data.dislikes;
-						this.currentSong.likes = data.likes;
-					}
-				}
-			});
-
-			this.socket.on("event:song.unlike", data => {
-				if (!this.noSong) {
-					if (data.songId === this.currentSong.songId) {
-						this.currentSong.dislikes = data.dislikes;
-						this.currentSong.likes = data.likes;
-					}
-				}
-			});
-
-			this.socket.on("event:song.undislike", data => {
-				if (!this.noSong) {
-					if (data.songId === this.currentSong.songId) {
-						this.currentSong.dislikes = data.dislikes;
-						this.currentSong.likes = data.likes;
-					}
-				}
-			});
-
-			this.socket.on("event:song.newRatings", data => {
-				if (!this.noSong) {
-					if (data.songId === this.currentSong.songId) {
-						this.liked = data.liked;
-						this.disliked = data.disliked;
-					}
-				}
-			});
-
-			this.socket.on("event:queue.update", queue => {
-				if (this.station.type === "community")
-					this.updateSongsList(queue);
-			});
-
-			this.socket.on("event:song.voteSkipSong", () => {
-				if (this.currentSong) this.currentSong.skipVotes += 1;
-			});
-
-			this.socket.on("event:privatePlaylist.selected", playlistId => {
-				if (this.station.type === "community") {
-					this.station.privatePlaylist = playlistId;
-				}
-			});
-
-			this.socket.on("event:partyMode.updated", partyMode => {
-				if (this.station.type === "community") {
-					this.station.partyMode = partyMode;
-				}
-			});
-
-			this.socket.on("event:newOfficialPlaylist", playlist => {
-				if (this.station.type === "official") {
-					this.updateSongsList(playlist);
-				}
-			});
-
-			this.socket.on("event:users.updated", users => {
-				this.updateUsers(users);
-			});
-
-			this.socket.on("event:userCount.updated", userCount => {
-				this.updateUserCount(userCount);
-			});
-
-			this.socket.on("event:queueLockToggled", locked => {
-				this.station.locked = locked;
-			});
-		});
-
-		if (JSON.parse(localStorage.getItem("muted"))) {
-			this.muted = true;
-			this.player.setVolume(0);
-			this.volumeSliderValue = 0 * 100;
-		} else {
-			let volume = parseFloat(localStorage.getItem("volume"));
-			volume =
-				typeof volume === "number" && !Number.isNaN(volume)
-					? volume
-					: 20;
-			localStorage.setItem("volume", volume);
-			this.volumeSliderValue = volume * 100;
-		}
-	},
-	beforeDestroy() {
-		const shortcutNames = [
-			"station.pauseResume",
-			"station.skipStation",
-			"station.lowerVolumeLarge",
-			"station.lowerVolumeSmall",
-			"station.increaseVolumeLarge",
-			"station.increaseVolumeSmall"
-		];
-
-		shortcutNames.forEach(shortcutName => {
-			keyboardShortcuts.unregisterShortcut(shortcutName);
-		});
-	},
-	components: {
-		StationHeader,
-		SongQueue: () => import("./AddSongToQueue.vue"),
-		AddToPlaylist: () => import("./AddSongToPlaylist.vue"),
-		EditPlaylist: () => import("../../components/modals/EditPlaylist.vue"),
-		CreatePlaylist: () =>
-			import("../../components/modals/CreatePlaylist.vue"),
-		EditStation: () => import("../../components/modals/EditStation.vue"),
-		Report: () => import("./Report.vue"),
-		SongsListSidebar: () => import("./SongsList.vue"),
-		UsersSidebar: () => import("./UsersList.vue"),
-		UserIdToUsername,
-		Z404,
-		FloatingBox
 	}
 };
 </script>