|
@@ -20,7 +20,44 @@
|
|
|
>
|
|
|
Load all
|
|
|
</button>
|
|
|
+ <button
|
|
|
+ class="button is-primary"
|
|
|
+ @click="toggleKeyboardShortcutsHelper"
|
|
|
+ @dblclick="resetKeyboardShortcutsHelper"
|
|
|
+ >
|
|
|
+ Keyboard shortcuts helper
|
|
|
+ </button>
|
|
|
<br />
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ type="text"
|
|
|
+ placeholder="Filter artist checkboxes"
|
|
|
+ v-model="artistFilterQuery"
|
|
|
+ />
|
|
|
+ <label v-for="artist in filteredArtists" :key="artist">
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ :checked="artistFilterSelected.indexOf(artist) !== -1"
|
|
|
+ @click="toggleArtistSelected(artist)"
|
|
|
+ />
|
|
|
+ <span>{{ artist }}</span>
|
|
|
+ </label>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ type="text"
|
|
|
+ placeholder="Filter genre checkboxes"
|
|
|
+ v-model="genreFilterQuery"
|
|
|
+ />
|
|
|
+ <label v-for="genre in filteredGenres" :key="genre">
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ :checked="genreFilterSelected.indexOf(genre) !== -1"
|
|
|
+ @click="toggleGenreSelected(genre)"
|
|
|
+ />
|
|
|
+ <span>{{ genre }}</span>
|
|
|
+ </label>
|
|
|
+ </div>
|
|
|
<br />
|
|
|
<table class="table is-striped">
|
|
|
<thead>
|
|
@@ -96,6 +133,65 @@
|
|
|
</table>
|
|
|
</div>
|
|
|
<edit-song v-if="modals.editSong" />
|
|
|
+ <floating-box
|
|
|
+ id="keyboardShortcutsHelper"
|
|
|
+ ref="keyboardShortcutsHelper"
|
|
|
+ >
|
|
|
+ <template #body>
|
|
|
+ <div>
|
|
|
+ <div>
|
|
|
+ <span class="biggest"><b>Songs page</b></span>
|
|
|
+ <span
|
|
|
+ ><b>Arrow keys up/down</b> - Moves between
|
|
|
+ songs</span
|
|
|
+ >
|
|
|
+ <span><b>E</b> - Edit selected song</span>
|
|
|
+ <span><b>A</b> - Add selected song</span>
|
|
|
+ <span><b>X</b> - Delete selected song</span>
|
|
|
+ </div>
|
|
|
+ <hr />
|
|
|
+ <div>
|
|
|
+ <span class="biggest"><b>Edit song modal</b></span>
|
|
|
+ <span class="bigger"><b>Navigation</b></span>
|
|
|
+ <span><b>Home</b> - Edit</span>
|
|
|
+ <span><b>End</b> - Edit</span>
|
|
|
+ <hr />
|
|
|
+ <span class="bigger"><b>Player controls</b></span>
|
|
|
+ <span><b>Numpad up/down</b> - Volume up/down 10%</span>
|
|
|
+ <span
|
|
|
+ ><b>Ctrl + Numpad up/down</b> - Volume up/down
|
|
|
+ 1%</span
|
|
|
+ >
|
|
|
+ <span><b>Numpad center</b> - Pause/resume</span>
|
|
|
+ <span><b>Ctrl + Numpad center</b> - Stop</span>
|
|
|
+ <span
|
|
|
+ ><b>Numpad Right</b> - Skip to last 10 seconds</span
|
|
|
+ >
|
|
|
+ <hr />
|
|
|
+ <span class="bigger"><b>Form control</b></span>
|
|
|
+ <span
|
|
|
+ ><b>Ctrl + D</b> - Executes purple button in that
|
|
|
+ input</span
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ ><b>Ctrl + Alt + D</b> - Fill in all Discogs
|
|
|
+ fields</span
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ ><b>Ctrl + R</b> - Executes red button in that
|
|
|
+ input</span
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ ><b>Ctrl + Alt + R</b> - Reset duration field</span
|
|
|
+ >
|
|
|
+ <hr />
|
|
|
+ <span class="bigger"><b>Modal control</b></span>
|
|
|
+ <span><b>Ctrl + S</b> - Save</span>
|
|
|
+ <span><b>Ctrl + X</b> - Exit</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </floating-box>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -107,16 +203,22 @@ import Toast from "toasters";
|
|
|
import EditSong from "../../../components/modals/EditSong.vue";
|
|
|
import UserIdToUsername from "../../../components/common/UserIdToUsername.vue";
|
|
|
|
|
|
+import FloatingBox from "../../../components/ui/FloatingBox.vue";
|
|
|
+
|
|
|
import ScrollAndFetchHandler from "../../../mixins/ScrollAndFetchHandler.vue";
|
|
|
|
|
|
import io from "../../../io";
|
|
|
|
|
|
export default {
|
|
|
mixins: [ScrollAndFetchHandler],
|
|
|
- components: { EditSong, UserIdToUsername },
|
|
|
+ components: { EditSong, UserIdToUsername, FloatingBox },
|
|
|
data() {
|
|
|
return {
|
|
|
searchQuery: "",
|
|
|
+ artistFilterQuery: "",
|
|
|
+ artistFilterSelected: [],
|
|
|
+ genreFilterQuery: "",
|
|
|
+ genreFilterSelected: [],
|
|
|
editing: {
|
|
|
index: 0,
|
|
|
song: {}
|
|
@@ -129,9 +231,63 @@ export default {
|
|
|
song =>
|
|
|
JSON.stringify(Object.values(song)).indexOf(
|
|
|
this.searchQuery
|
|
|
- ) !== -1
|
|
|
+ ) !== -1 &&
|
|
|
+ (this.artistFilterSelected.length === 0 ||
|
|
|
+ song.artists.some(
|
|
|
+ artist =>
|
|
|
+ this.artistFilterSelected.indexOf(artist) !== -1
|
|
|
+ )) &&
|
|
|
+ (this.genreFilterSelected.length === 0 ||
|
|
|
+ song.genres.some(
|
|
|
+ genre =>
|
|
|
+ this.genreFilterSelected.indexOf(genre) !== -1
|
|
|
+ ))
|
|
|
);
|
|
|
},
|
|
|
+ artists() {
|
|
|
+ const artists = [];
|
|
|
+ this.songs.forEach(song => {
|
|
|
+ song.artists.forEach(artist => {
|
|
|
+ if (artists.indexOf(artist) === -1) artists.push(artist);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return artists.sort();
|
|
|
+ },
|
|
|
+ filteredArtists() {
|
|
|
+ return this.artists
|
|
|
+ .filter(
|
|
|
+ artist =>
|
|
|
+ this.artistFilterSelected.indexOf(artist) !== -1 ||
|
|
|
+ artist.indexOf(this.artistFilterQuery) !== -1
|
|
|
+ )
|
|
|
+ .sort(
|
|
|
+ (a, b) =>
|
|
|
+ (this.artistFilterSelected.indexOf(a) === -1 ? 1 : 0) -
|
|
|
+ (this.artistFilterSelected.indexOf(b) === -1 ? 1 : 0)
|
|
|
+ );
|
|
|
+ },
|
|
|
+ genres() {
|
|
|
+ const genres = [];
|
|
|
+ this.songs.forEach(song => {
|
|
|
+ song.genres.forEach(genre => {
|
|
|
+ if (genres.indexOf(genre) === -1) genres.push(genre);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return genres.sort();
|
|
|
+ },
|
|
|
+ filteredGenres() {
|
|
|
+ return this.genres
|
|
|
+ .filter(
|
|
|
+ genre =>
|
|
|
+ this.genreFilterSelected.indexOf(genre) !== -1 ||
|
|
|
+ genre.indexOf(this.genreFilterQuery) !== -1
|
|
|
+ )
|
|
|
+ .sort(
|
|
|
+ (a, b) =>
|
|
|
+ (this.genreFilterSelected.indexOf(a) === -1 ? 1 : 0) -
|
|
|
+ (this.genreFilterSelected.indexOf(b) === -1 ? 1 : 0)
|
|
|
+ );
|
|
|
+ },
|
|
|
...mapState("modals", {
|
|
|
modals: state => state.modals.admin
|
|
|
}),
|
|
@@ -151,6 +307,11 @@ export default {
|
|
|
this.openModal({ sector: "admin", modal: "editSong" });
|
|
|
},
|
|
|
remove(id) {
|
|
|
+ // eslint-disable-next-line
|
|
|
+ const dialogResult = window.confirm(
|
|
|
+ "Are you sure you want to delete this song?"
|
|
|
+ );
|
|
|
+ if (dialogResult !== true) return;
|
|
|
this.socket.emit("songs.remove", id, res => {
|
|
|
if (res.status === "success")
|
|
|
new Toast({ content: res.message, timeout: 4000 });
|
|
@@ -171,6 +332,30 @@ export default {
|
|
|
this.gettingSet = false;
|
|
|
});
|
|
|
},
|
|
|
+ toggleArtistSelected(artist) {
|
|
|
+ if (this.artistFilterSelected.indexOf(artist) === -1)
|
|
|
+ this.artistFilterSelected.push(artist);
|
|
|
+ else
|
|
|
+ this.artistFilterSelected.splice(
|
|
|
+ this.artistFilterSelected.indexOf(artist),
|
|
|
+ 1
|
|
|
+ );
|
|
|
+ },
|
|
|
+ toggleGenreSelected(genre) {
|
|
|
+ if (this.genreFilterSelected.indexOf(genre) === -1)
|
|
|
+ this.genreFilterSelected.push(genre);
|
|
|
+ else
|
|
|
+ this.genreFilterSelected.splice(
|
|
|
+ this.genreFilterSelected.indexOf(genre),
|
|
|
+ 1
|
|
|
+ );
|
|
|
+ },
|
|
|
+ toggleKeyboardShortcutsHelper() {
|
|
|
+ this.$refs.keyboardShortcutsHelper.toggleBox();
|
|
|
+ },
|
|
|
+ resetKeyboardShortcutsHelper() {
|
|
|
+ this.$refs.keyboardShortcutsHelper.resetBox();
|
|
|
+ },
|
|
|
init() {
|
|
|
if (this.songs.length > 0)
|
|
|
this.position = Math.ceil(this.songs.length / 15) + 1;
|
|
@@ -179,14 +364,6 @@ export default {
|
|
|
this.maxPosition = Math.ceil(length / 15) + 1;
|
|
|
|
|
|
this.getSet();
|
|
|
-
|
|
|
- setTimeout(() => {
|
|
|
- if (
|
|
|
- !this.loadAllSongs &&
|
|
|
- this.maxPosition > this.position - 1
|
|
|
- )
|
|
|
- this.getSet();
|
|
|
- }, 1000);
|
|
|
});
|
|
|
|
|
|
this.socket.emit("apis.joinAdminRoom", "songs", () => {});
|
|
@@ -225,12 +402,7 @@ export default {
|
|
|
if (this.$route.query.songId) {
|
|
|
this.socket.emit("songs.getSong", this.$route.query.songId, res => {
|
|
|
if (res.status === "success") {
|
|
|
- this.edit(res.data);
|
|
|
-
|
|
|
- this.closeModal({
|
|
|
- sector: "admin",
|
|
|
- modal: "viewReport"
|
|
|
- });
|
|
|
+ this.edit(res.data.song);
|
|
|
} else
|
|
|
new Toast({
|
|
|
content: "Song with that ID not found",
|
|
@@ -306,6 +478,26 @@ td {
|
|
|
vertical-align: middle;
|
|
|
}
|
|
|
|
|
|
+#keyboardShortcutsHelper {
|
|
|
+ .box-body {
|
|
|
+ b {
|
|
|
+ color: #000;
|
|
|
+ }
|
|
|
+
|
|
|
+ .biggest {
|
|
|
+ font-size: 18px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .bigger {
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ span {
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
.is-primary:focus {
|
|
|
background-color: $primary-color !important;
|
|
|
}
|