Reworked web UI editing

This commit is contained in:
krateng 2023-10-17 19:36:59 +02:00
parent 25ba050d30
commit d8420cdb67
21 changed files with 318 additions and 230 deletions

View File

@ -23,6 +23,7 @@
<script src="/neopolitan.js"></script>
<script src="/upload.js"></script>
<script src="/notifications.js"></script>
<script src="/edit.js"></script>
<script>
const defaultpicks = {
topartists: '{{ settings["DEFAULT_RANGE_STARTPAGE"] }}',

View File

@ -5,7 +5,6 @@
{% block scripts %}
<script src="/statselect.js"></script>
<script src="/edit.js"></script>
{% endblock %}
{% set album = filterkeys.album %}
@ -20,13 +19,21 @@
{% block icon_bar %}
{% if adminmode %}
{% include 'icons/edit.jinja' %}
<div class="iconsubset mergeicons" data-entity_type="album" data-entity_id="{{ info.id }}" data-entity_name="{{ info.album.albumtitle }}">
{% include 'icons/merge.jinja' %}
{% include 'icons/merge_mark.jinja' %}
{% include 'icons/merge_unmark.jinja' %}
{% include 'icons/merge_cancel.jinja' %}
</div>
<div class="iconsubset associateicons" data-entity_type="album" data-entity_id="{{ info.id }}" data-entity_name="{{ info.album.albumtitle }}">
{% include 'icons/add_album.jinja' %}
{% include 'icons/association_mark.jinja' %}
{% include 'icons/association_unmark.jinja' %}
{% include 'icons/association_cancel.jinja' %}
<script>showValidMergeIcons();</script>
</div>
{% endif %}
{% endblock %}

View File

@ -6,7 +6,6 @@
{% block scripts %}
<script src="/statselect.js"></script>
<script src="/edit.js"></script>
{% endblock %}
{% set artist = filterkeys.artist %}
@ -30,11 +29,19 @@
{% block icon_bar %}
{% if adminmode %}
{% include 'icons/edit.jinja' %}
<div class="iconsubset mergeicons" data-entity_type="artist" data-entity_id="{{ info.id }}" data-entity_name="{{ info.artist }}">
{% include 'icons/merge.jinja' %}
{% include 'icons/merge_mark.jinja' %}
{% include 'icons/merge_unmark.jinja' %}
{% include 'icons/merge_cancel.jinja' %}
</div>
<div class="iconsubset associateicons" data-entity_type="artist" data-entity_id="{{ info.id }}" data-entity_name="{{ info.artist }}">
{% include 'icons/add_artist.jinja' %}
<script>showValidMergeIcons();</script>
{% include 'icons/association_cancel.jinja' %}
</div>
{% endif %}
{% endblock %}

View File

@ -1,4 +1,4 @@
<div title="Add to Album" id="associatealbumicon" class="clickable_icon" onclick="associate()">
<div title="Add to Album" id="associatealbumicon" class="clickable_icon" onclick="associate(this)">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path d="M2 4.75C2 3.784 2.784 3 3.75 3h4.971a1.75 1.75 0 0 1 1.447.765l1.404 2.063a.25.25 0 0 0 .207.11h8.471c.966 0 1.75.783 1.75 1.75V19.25A1.75 1.75 0 0 1 20.25 21H4.75a.75.75 0 0 1 0-1.5h15.5a.25.25 0 0 0 .25-.25V7.688a.25.25 0 0 0-.25-.25h-8.471a1.751 1.751 0 0 1-1.447-.766L8.928 4.609a.252.252 0 0 0-.207-.109H3.75a.25.25 0 0 0-.25.25v3.5a.75.75 0 0 1-1.5 0v-3.5Z"></path>
<path d="m9.308 12.5-2.104-2.236a.75.75 0 1 1 1.092-1.028l3.294 3.5a.75.75 0 0 1 0 1.028l-3.294 3.5a.75.75 0 1 1-1.092-1.028L9.308 14H4.09a2.59 2.59 0 0 0-2.59 2.59v3.16a.75.75 0 0 1-1.5 0v-3.16a4.09 4.09 0 0 1 4.09-4.09h5.218Z"></path>

View File

@ -1,4 +1,4 @@
<div title="Add Artist" id="associateartisticon" class="clickable_icon" onclick="associate()">
<div title="Add Artist" id="associateartisticon" class="clickable_icon" onclick="associate(this)">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path d="M4 9.5a5 5 0 1 1 7.916 4.062 7.973 7.973 0 0 1 5.018 7.166.75.75 0 1 1-1.499.044 6.469 6.469 0 0 0-12.932 0 .75.75 0 0 1-1.499-.044 7.972 7.972 0 0 1 5.059-7.181A4.994 4.994 0 0 1 4 9.5ZM9 6a3.5 3.5 0 1 0 0 7 3.5 3.5 0 0 0 0-7Zm10.25-5a.75.75 0 0 1 .75.75V4h2.25a.75.75 0 0 1 0 1.5H20v2.25a.75.75 0 0 1-1.5 0V5.5h-2.25a.75.75 0 0 1 0-1.5h2.25V1.75a.75.75 0 0 1 .75-.75Z"></path>
</svg>

View File

@ -1,7 +1,6 @@
<div title="Cancel Track Association" id="associationcancelicon" class="clickable_icon" onclick="umarkForAssociate(this)">
<div title="Cancel associating" class="associatecancelicon clickable_icon" onclick="cancelAssociate(this)">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M2.345 20.595 8.47 14.47q.219-.22.53-.22.311 0 .53.22.22.219.22.53 0 .311-.22.53l-6.125 6.125q-.219.22-.53.22-.311 0-.53-.22-.22-.219-.22-.53 0-.311.22-.53Z"></path>
<path d="m16.72 11.97.358-.358a6.738 6.738 0 0 1 2.326-1.518l1.896-.738a.25.25 0 0 0 .086-.409l-6.333-6.333a.25.25 0 0 0-.409.086l-.521 1.34a8.663 8.663 0 0 1-2.243 3.265.75.75 0 0 1-1.01-1.11 7.132 7.132 0 0 0 1.854-2.699l.521-1.34a1.75 1.75 0 0 1 2.869-.603l6.333 6.333a1.75 1.75 0 0 1-.603 2.869l-1.896.737a5.26 5.26 0 0 0-1.81 1.18l-.358.358a.749.749 0 1 1-1.06-1.06Zm-12.549-.738a1.75 1.75 0 0 1 .757-2.92l3.366-.962.412 1.443-3.366.961a.25.25 0 0 0-.108.417l8.597 8.597a.25.25 0 0 0 .417-.108l.961-3.366 1.443.412-.962 3.366a1.75 1.75 0 0 1-2.92.757Z"></path>
<path d="m3.405 2.095 18.75 18.75q.22.219.22.53 0 .311-.22.53-.219.22-.53.22-.311 0-.53-.22L2.345 3.155q-.22-.219-.22-.53 0-.311.22-.53.219-.22.53-.22.311 0 .53.22Z"></path>
<path d="M12 1c6.075 0 11 4.925 11 11s-4.925 11-11 11S1 18.075 1 12 5.925 1 12 1ZM5.834 19.227A9.464 9.464 0 0 0 12 21.5a9.5 9.5 0 0 0 9.5-9.5 9.464 9.464 0 0 0-2.273-6.166ZM2.5 12a9.464 9.464 0 0 0 2.273 6.166L18.166 4.773A9.463 9.463 0 0 0 12 2.5 9.5 9.5 0 0 0 2.5 12Z">
</path>
</svg>
</div>

View File

@ -1,4 +1,4 @@
<div title="Mark to associate artists or album" id="associationmarkicon" class="clickable_icon" onclick="markForAssociate(this)">
<div title="Mark for association" class="associationmarkicon clickable_icon" onclick="markForAssociate(this)">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="m16.114 1.553 6.333 6.333a1.75 1.75 0 0 1-.603 2.869l-1.63.633a5.67 5.67 0 0 0-3.395 3.725l-1.131 3.959a1.75 1.75 0 0 1-2.92.757L9 16.061l-5.595 5.594a.749.749 0 1 1-1.06-1.06L7.939 15l-3.768-3.768a1.75 1.75 0 0 1 .757-2.92l3.959-1.131a5.666 5.666 0 0 0 3.725-3.395l.633-1.63a1.75 1.75 0 0 1 2.869-.603ZM5.232 10.171l8.597 8.597a.25.25 0 0 0 .417-.108l1.131-3.959A7.17 7.17 0 0 1 19.67 9.99l1.63-.634a.25.25 0 0 0 .086-.409l-6.333-6.333a.25.25 0 0 0-.409.086l-.634 1.63a7.17 7.17 0 0 1-4.711 4.293L5.34 9.754a.25.25 0 0 0-.108.417Z"></path>
</svg>

View File

@ -0,0 +1,7 @@
<div title="Unmark for Association"class="associationunmarkicon clickable_icon" onclick="umarkForAssociate(this)">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M2.345 20.595 8.47 14.47q.219-.22.53-.22.311 0 .53.22.22.219.22.53 0 .311-.22.53l-6.125 6.125q-.219.22-.53.22-.311 0-.53-.22-.22-.219-.22-.53 0-.311.22-.53Z"></path>
<path d="m16.72 11.97.358-.358a6.738 6.738 0 0 1 2.326-1.518l1.896-.738a.25.25 0 0 0 .086-.409l-6.333-6.333a.25.25 0 0 0-.409.086l-.521 1.34a8.663 8.663 0 0 1-2.243 3.265.75.75 0 0 1-1.01-1.11 7.132 7.132 0 0 0 1.854-2.699l.521-1.34a1.75 1.75 0 0 1 2.869-.603l6.333 6.333a1.75 1.75 0 0 1-.603 2.869l-1.896.737a5.26 5.26 0 0 0-1.81 1.18l-.358.358a.749.749 0 1 1-1.06-1.06Zm-12.549-.738a1.75 1.75 0 0 1 .757-2.92l3.366-.962.412 1.443-3.366.961a.25.25 0 0 0-.108.417l8.597 8.597a.25.25 0 0 0 .417-.108l.961-3.366 1.443.412-.962 3.366a1.75 1.75 0 0 1-2.92.757Z"></path>
<path d="m3.405 2.095 18.75 18.75q.22.219.22.53 0 .311-.22.53-.219.22-.53.22-.311 0-.53-.22L2.345 3.155q-.22-.219-.22-.53 0-.311.22-.53.219-.22.53-.22.311 0 .53.22Z"></path>
</svg>
</div>

View File

@ -1,4 +1,4 @@
<div title="Merge" id="mergeicon" class="clickable_icon hide" onclick="merge()">
<div title="Merge" id="mergeicon" class="clickable_icon" onclick="merge(this)">
<svg viewBox="0 0 16 16" width="24" height="24">
<path fill-rule="evenodd" d="M5 3.254V3.25v.005a.75.75 0 110-.005v.004zm.45 1.9a2.25 2.25 0 10-1.95.218v5.256a2.25 2.25 0 101.5 0V7.123A5.735 5.735 0 009.25 9h1.378a2.251 2.251 0 100-1.5H9.25a4.25 4.25 0 01-3.8-2.346zM12.75 9a.75.75 0 100-1.5.75.75 0 000 1.5zm-8.5 4.5a.75.75 0 100-1.5.75.75 0 000 1.5z"></path>
</svg>

View File

@ -1,5 +1,6 @@
<div title="Cancel merge" id="mergecancelicon" class="clickable_icon hide" onclick="cancelMerge()">
<svg viewBox="0 0 16 16" width="24" height="24">
<path fill-rule="evenodd" d="M10.72 1.227a.75.75 0 011.06 0l.97.97.97-.97a.75.75 0 111.06 1.061l-.97.97.97.97a.75.75 0 01-1.06 1.06l-.97-.97-.97.97a.75.75 0 11-1.06-1.06l.97-.97-.97-.97a.75.75 0 010-1.06zM12.75 6.5a.75.75 0 00-.75.75v3.378a2.251 2.251 0 101.5 0V7.25a.75.75 0 00-.75-.75zm0 5.5a.75.75 0 100 1.5.75.75 0 000-1.5zM2.5 3.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0zM3.25 1a2.25 2.25 0 00-.75 4.372v5.256a2.251 2.251 0 101.5 0V5.372A2.25 2.25 0 003.25 1zm0 11a.75.75 0 100 1.5.75.75 0 000-1.5z"></path>
<div title="Cancel merging" id="mergecancelicon" class="clickable_icon" onclick="cancelMerge(this)">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M12 1c6.075 0 11 4.925 11 11s-4.925 11-11 11S1 18.075 1 12 5.925 1 12 1ZM5.834 19.227A9.464 9.464 0 0 0 12 21.5a9.5 9.5 0 0 0 9.5-9.5 9.464 9.464 0 0 0-2.273-6.166ZM2.5 12a9.464 9.464 0 0 0 2.273 6.166L18.166 4.773A9.463 9.463 0 0 0 12 2.5 9.5 9.5 0 0 0 2.5 12Z">
</path>
</svg>
</div>

View File

@ -1,4 +1,4 @@
<div title="Mark for merging" id="mergemarkicon" class="clickable_icon hide" onclick="markForMerge()">
<div title="Mark for merging" id="mergemarkicon" class="clickable_icon" onclick="markForMerge(this)">
<svg viewBox="0 0 16 16" width="24" height="24">
<path fill-rule="evenodd" d="M7.177 3.073L9.573.677A.25.25 0 0110 .854v4.792a.25.25 0 01-.427.177L7.177 3.427a.25.25 0 010-.354zM3.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122v5.256a2.251 2.251 0 11-1.5 0V5.372A2.25 2.25 0 011.5 3.25zM11 2.5h-1V4h1a1 1 0 011 1v5.628a2.251 2.251 0 101.5 0V5A2.5 2.5 0 0011 2.5zm1 10.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0zM3.75 12a.75.75 0 100 1.5.75.75 0 000-1.5z"></path>
</svg>

View File

@ -0,0 +1,5 @@
<div title="Unmark from merge" id="mergeunmarkicon" class="clickable_icon" onclick="unmarkForMerge(this)">
<svg viewBox="0 0 16 16" width="24" height="24">
<path fill-rule="evenodd" d="M10.72 1.227a.75.75 0 011.06 0l.97.97.97-.97a.75.75 0 111.06 1.061l-.97.97.97.97a.75.75 0 01-1.06 1.06l-.97-.97-.97.97a.75.75 0 11-1.06-1.06l.97-.97-.97-.97a.75.75 0 010-1.06zM12.75 6.5a.75.75 0 00-.75.75v3.378a2.251 2.251 0 101.5 0V7.25a.75.75 0 00-.75-.75zm0 5.5a.75.75 0 100 1.5.75.75 0 000-1.5zM2.5 3.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0zM3.25 1a2.25 2.25 0 00-.75 4.372v5.256a2.251 2.251 0 101.5 0V5.372A2.25 2.25 0 003.25 1zm0 11a.75.75 0 100 1.5.75.75 0 000-1.5z"></path>
</svg>
</div>

View File

@ -28,11 +28,12 @@
{% set firstindex = amountkeys.page * amountkeys.perpage %}
{% set lastindex = firstindex + amountkeys.perpage %}
{% set maxbar = charts[0]['scrobbles'] if charts != [] else 0 %}
<table class='list'>
{% for e in charts %}
{% if loop.index0 >= firstindex and loop.index0 < lastindex %}
<tr>
<tr class="listrow associateicons" data-entity_id="{{ e['album_id'] }}" data-entity_type="album" data-entity_name="{{ e['album'].albumtitle }}">
<!-- Rank -->
<td class="rank">{%if loop.changed(e.scrobbles) %}#{{ e.rank }}{% endif %}</td>
<!-- Rank change -->
@ -45,7 +46,7 @@
{% endif %}
<!-- artist -->
{{ entityrow.row(e['album']) }}
{{ entityrow.row(e['album'],adminmode=True) }}
<!-- scrobbles -->
<td class="amount">{{ links.link_scrobbles([{'album':e.album,'timerange':limitkeys.timerange}],amount=e['scrobbles']) }}</td>

View File

@ -30,12 +30,13 @@
{% set lastindex = firstindex + amountkeys.perpage %}
{% set maxbar = charts[0]['scrobbles'] if charts != [] else 0 %}
<table class='list'>
{% for e in charts %}
{% if loop.index0 >= firstindex and loop.index0 < lastindex %}
<tr>
<tr class="listrow associateicons" data-entity_id="{{ e['artist_id'] }}" data-entity_type="artist" data-entity_name="{{ e['artist'] }}">
<!-- Rank -->
<td class="rank">{%if loop.changed(e.scrobbles) %}#{{ e.rank }}{% endif %}</td>
<!-- Rank change -->
@ -48,7 +49,7 @@
{% endif %}
<!-- artist -->
{{ entityrow.row(e['artist']) }}
{{ entityrow.row(e['artist'],adminmode=True) }}
<!-- scrobbles -->
<td class="amount">{{ links.link_scrobbles([{'artist':e['artist'],'associated':True,'timerange':limitkeys.timerange}],amount=e['scrobbles']) }}</td>

View File

@ -28,11 +28,12 @@
{% set firstindex = amountkeys.page * amountkeys.perpage %}
{% set lastindex = firstindex + amountkeys.perpage %}
{% set maxbar = charts[0]['scrobbles'] if charts != [] else 0 %}
<table class='list'>
{% for e in charts %}
{% if loop.index0 >= firstindex and loop.index0 < lastindex %}
<tr>
<tr class="listrow associateicons" data-entity_id="{{ e['track_id'] }}" data-entity_type="track" data-entity_name="{{ e['track'].title }}">
<!-- Rank -->
<td class="rank">{%if loop.changed(e.scrobbles) %}#{{ e.rank }}{% endif %}</td>
<!-- Rank change -->
@ -45,7 +46,7 @@
{% endif %}
<!-- artist -->
{{ entityrow.row(e['track']) }}
{{ entityrow.row(e['track'],adminmode=True) }}
<!-- scrobbles -->
<td class="amount">{{ links.link_scrobbles([{'track':e.track,'timerange':limitkeys.timerange}],amount=e['scrobbles']) }}</td>

View File

@ -6,22 +6,14 @@
{% set firstindex = amountkeys.page * amountkeys.perpage %}
{% set lastindex = firstindex + amountkeys.perpage %}
<script src="/edit.js"></script>
<table class='list'>
{% for e in list %}
{% if loop.index0 >= firstindex and loop.index0 < lastindex %}
<tr class="listrow unmarked" data-entity_id="{{ e['track_id'] }}" data-entity_type="track" data-entity_name="{{ e['track'].title }}">
<tr class="listrow associateicons" data-entity_id="{{ e['track_id'] }}" data-entity_type="track" data-entity_name="{{ e['track'].title }}">
<!-- artist -->
{{ entityrow.row(e['track']) }}
{% with inlineicons = True %}
<td>
{% include 'icons/association_mark.jinja' %}
{% include 'icons/association_cancel.jinja' %}
</td>
{% endwith %}
{{ entityrow.row(e['track'],adminmode=adminmode) }}
</tr>
{% endif %}
@ -30,9 +22,6 @@
<script>
var listrows = document.getElementsByClassName('listrow');
for (var row of listrows) {
toggleAssociationIcons(row);
}
</script>

View File

@ -6,9 +6,6 @@
{% import 'snippets/entityrow.jinja' as entityrow %}
<script src="/edit.js"></script>
<table class='list'>
{% for s in scrobbles -%}
{%- if loop.index0 >= firstindex and loop.index0 < lastindex -%}

View File

@ -1,4 +1,4 @@
{% macro row(entity,counting=[]) %}
{% macro row(entity,counting=[],adminmode=False) %}
{% import 'snippets/links.jinja' as links %}
@ -35,4 +35,11 @@
{% endif %}
{% if adminmode and (entity is mapping) %}
<td>
{% include 'icons/association_mark.jinja' %}
{% include 'icons/association_unmark.jinja' %}
</td>
{% endif %}
{% endmacro %}

View File

@ -5,7 +5,6 @@
{% block scripts %}
<script src="/statselect.js"></script>
<script src="/edit.js"></script>
<script>
function scrobble(encodedtrack) {
neo.xhttprequest('/apis/mlj_1/newscrobble?nofix&' + encodedtrack,data={},method="POST").then(response=>{window.location.reload()});
@ -25,12 +24,19 @@
{% block icon_bar %}
{% if adminmode %}
{% include 'icons/edit.jinja' %}
<div class="iconsubset mergeicons" data-entity_type="track" data-entity_id="{{ info.id }}" data-entity_name="{{ info.track.title }}">
{% include 'icons/merge.jinja' %}
{% include 'icons/merge_mark.jinja' %}
{% include 'icons/merge_unmark.jinja' %}
{% include 'icons/merge_cancel.jinja' %}
</div>
<div class="iconsubset associateicons" data-entity_type="track" data-entity_id="{{ info.id }}" data-entity_name="{{ info.track.title }}">
{% include 'icons/association_mark.jinja' %}
{% include 'icons/association_unmark.jinja' %}
{% include 'icons/association_cancel.jinja' %}
<script>showValidMergeIcons();</script>
</div>
{% endif %}
{% endblock %}

View File

@ -67,6 +67,10 @@ div#icon_bar {
right:30px;
top:30px;
}
.iconsubset {
display: inline-block;
padding-left:20px;
}
div#icon_bar div.clickable_icon {
display: inline-block;
@ -94,14 +98,75 @@ div.clickable_icon.danger:hover svg {
display: inline-block;
}
.list tr.marked {
background-color: rgba(50,20,0,0.5);
.list {
--color_bg_merge: rgba(0,0,90,0.7);
--color_fg_merge: lightblue;
--color_bg_associate: rgba(50,20,0,0.7);
--color_fg_associate: orange;
}
.list tr.marked #associationmarkicon {
display:none;
.list tr.marked_for_associate {
background-color: var(--color_bg_associate);
color: var(--color_fg_associate);
}
.list tr:not(.marked) #associationcancelicon {
display:none;
.list tr.marked_for_merge {
background-color: var(--color_bg_merge);
color: var(--color_fg_merge);;
}
@keyframes slideBackground {
0% {
background-position: 100% 0;
}
50% {
background-position: 0 0;
}
100% {
background-position: 100% 0;
}
}
@keyframes colorChange {
0% {
color: var(--color_fg_associate);
}
50% {
color: var(--color_fg_merge);
}
100% {
color: var(--color_fg_associate);
}
}
.list tr.marked_for_associate.marked_for_merge {
background: linear-gradient(to left, var(--color_bg_associate), var(--color_bg_merge));
background-size: 100% 100%;
animation: colorChange 4s infinite ease-in-out;
}
/* this is just to 'factor out' that big selector down there.
we want icons to not be displayed in list rows, but show them with reduced opacity in the top bar */
.list {
--display_inactive_icons: none;
}
#icon_bar {
--display_inactive_icons: inline-block;
}
.associateicons.marked_for_associate .associationmarkicon, /* already marked, cant mark again */
.associateicons:not(.marked_for_associate) .associationunmarkicon, /* not marked, cant unmark */
.associateicons:not(.somethingmarked_for_associate) .associatecancelicon, /* cant cancel when nothing is marked */
.mergeicons.marked_for_merge #mergemarkicon, /* already marked, cant mark again */
.mergeicons:not(.marked_for_merge) #mergeunmarkicon, /* not marked, cant unmark */
.mergeicons:not(.somethingmarked_for_merge) #mergecancelicon, /* cant cancel when nothing is marked */
.mergeicons:not(.somethingmarked_for_merge) #mergeicon, /* can't merge when nothing is selected */
.mergeicons.marked_for_merge #mergeicon, /* cant merge into one of the things we have selected */
.associateicons:not(.sources_marked_for_associate) #associatealbumicon,
.associateicons:not(.sources_marked_for_associate) #associateartisticon /* nothing marked yet, can't associate with this */
{
pointer-events: none;
opacity:0.5;
display: var(--display_inactive_icons);
}
/**

View File

@ -187,186 +187,117 @@ function doneEditing() {
}
}
// MERGING
// MERGING AND ASSOCIATION
function showValidMergeIcons() {
const associate_targets = {
album: ['artist'],
track: ['album','artist'],
artist: []
};
// merge
const associate_sources = {
artist: ['album','track'],
album: ['track'],
track: []
};
function getStoredList(key) {
const lcst = window.sessionStorage;
var key = "marked_for_merge_" + entity_type;
var current_stored = (lcst.getItem(key) || '').split(",");
current_stored = current_stored.filter((x)=>x).map((x)=>parseInt(x));
var mergeicon = document.getElementById('mergeicon');
var mergemarkicon = document.getElementById('mergemarkicon');
var mergecancelicon = document.getElementById('mergecancelicon');
mergeicon.classList.add('hide');
mergemarkicon.classList.add('hide');
mergecancelicon.classList.add('hide');
if (current_stored.length == 0) {
mergemarkicon.classList.remove('hide');
}
else {
mergecancelicon.classList.remove('hide');
if (current_stored.includes(entity_id)) {
}
else {
mergemarkicon.classList.remove('hide');
mergeicon.classList.remove('hide');
}
}
// mark for association
if ((entity_type == 'track') || (entity_type == 'album')) {
const lcst = window.sessionStorage;
var key = "marked_for_associate_" + entity_type;
var current_stored = (lcst.getItem(key) || '').split(",");
current_stored = current_stored.filter((x)=>x).map((x)=>parseInt(x));
var associationmarkicon = document.getElementById('associationmarkicon');
var associationcancelicon = document.getElementById('associationcancelicon');
associationmarkicon.classList.add('hide');
associationcancelicon.classList.add('hide');
if (current_stored.length == 0) {
associationmarkicon.classList.remove('hide');
}
else {
associationcancelicon.classList.remove('hide');
if (current_stored.includes(entity_id)) {
}
else {
associationmarkicon.classList.remove('hide');
}
}
if (entity_type == 'track') {
associationmarkicon.title = "Mark this track to add to album or add artist";
}
else {
associationmarkicon.title = "Mark this album to add artist";
}
}
// association confirm
if ((entity_type == 'artist') || (entity_type == 'album')) {
var target_entity_types = {artist:['album','track'], album:['track']};
var to_associate = {};
var to_associate_all = [];
for (var target_entity_type of target_entity_types[entity_type]) {
const lcst = window.sessionStorage;
var key = "marked_for_associate_" + target_entity_type;
var current_stored = (lcst.getItem(key) || '').split(",");
to_associate[target_entity_type] = current_stored.filter((x)=>x).map((x)=>parseInt(x));
to_associate_all = to_associate_all.concat(to_associate[target_entity_type]);
}
var associateicon = document.getElementById('associate' + entity_type + 'icon');
associateicon.classList.add('hide');
if (to_associate_all.length == 0) {
}
else {
associateicon.classList.remove('hide');
if (entity_type == 'artist') {
associateicon.title = "Add this artist to " + to_associate['album'].length + " albums and " + to_associate['track'].length + " tracks";
}
else {
associateicon.title = "Add " + to_associate['track'].length + " tracks to this album";
}
}
}
return current_stored;
}
function storeList(key,list) {
const lcst = window.sessionStorage;
list = [...new Set(list)];
lcst.setItem(key,list); //this already formats it correctly
}
function markForMerge() {
const lcst = window.sessionStorage;
var key = "marked_for_merge_" + entity_type;
var current_stored = (lcst.getItem(key) || '').split(",");
current_stored = current_stored.filter((x)=>x).map((x)=>parseInt(x));
function markForMerge(element) {
const parentElement = element.closest('[data-entity_id]');
var entity_type = parentElement.dataset.entity_type;
var entity_id = parentElement.dataset.entity_id;
var entity_name = parentElement.dataset.entity_name;
entity_id = parseInt(entity_id);
key = "marked_for_merge_" + entity_type;
var current_stored = getStoredList(key);
current_stored.push(entity_id);
current_stored = [...new Set(current_stored)];
lcst.setItem(key,current_stored); //this already formats it correctly
storeList(key,current_stored)
notify("Marked " + entity_name + " for merge","Currently " + current_stored.length + " marked!")
showValidMergeIcons();
toggleMergeIcons(parentElement);
}
function unmarkForMerge(element) {
const parentElement = element.closest('[data-entity_id]');
var entity_type = parentElement.dataset.entity_type;
var entity_id = parentElement.dataset.entity_id;
var entity_name = parentElement.dataset.entity_name;
entity_id = parseInt(entity_id);
var key = "marked_for_merge_" + entity_type;
var current_stored = getStoredList(key);
if (current_stored.indexOf(entity_id) > -1) {
current_stored.splice(current_stored.indexOf(entity_id),1);
storeList(key,current_stored);
notify("Unmarked " + entity_name + " from merge","Currently " + current_stored.length + " marked!")
toggleMergeIcons(parentElement);
}
else {
//notify(entity_name + " was not marked!","")
}
}
function markForAssociate(element) {
console.log(element);
const parentElement = element.closest('[data-entity_id]');
console.log(parentElement);
// use local element for entity data, otherwise use from global scope (on entity info page)
var l_entity_type = parentElement ? parentElement.dataset.entity_type : entity_type;
var l_entity_id = parentElement ? parentElement.dataset.entity_id : entity_id;
var l_entity_name = parentElement ? parentElement.dataset.entity_name : entity_name;
l_entity_id = parseInt(l_entity_id);
var entity_type = parentElement.dataset.entity_type;
var entity_id = parentElement.dataset.entity_id;
var entity_name = parentElement.dataset.entity_name;
entity_id = parseInt(entity_id);
const lcst = window.sessionStorage;
var key = "marked_for_associate_" + l_entity_type;
var current_stored = (lcst.getItem(key) || '').split(",");
current_stored = current_stored.filter((x)=>x).map((x)=>parseInt(x));
current_stored.push(l_entity_id);
current_stored = [...new Set(current_stored)];
lcst.setItem(key,current_stored); //this already formats it correctly
var whattoadd = ((l_entity_type == 'track') ? "Artists or Album" : "Artists")
notify("Marked " + l_entity_name + " to add " + whattoadd,"Currently " + current_stored.length + " marked!")
if (!parentElement) {
showValidMergeIcons();
}
else {
toggleAssociationIcons(parentElement);
}
var key = "marked_for_associate_" + entity_type;
var current_stored = getStoredList(key);
current_stored.push(entity_id);
storeList(key,current_stored);
notify("Marked " + entity_name + " to add to " + associate_targets[entity_type].join(" or "),"Currently " + current_stored.length + " marked!")
toggleAssociationIcons(parentElement);
}
function umarkForAssociate(element) {
const parentElement = element.closest('[data-entity_id]');
// use local element for entity data, otherwise use from global scope (on entity info page)
var l_entity_type = parentElement ? parentElement.dataset.entity_type : entity_type;
var l_entity_id = parentElement ? parentElement.dataset.entity_id : entity_id;
var l_entity_name = parentElement ? parentElement.dataset.entity_name : entity_name;
l_entity_id = parseInt(l_entity_id);
const lcst = window.sessionStorage;
var key = "marked_for_associate_" + l_entity_type;
var current_stored = (lcst.getItem(key) || '').split(",");
current_stored = current_stored.filter((x)=>x).map((x)=>parseInt(x));
var entity_type = parentElement.dataset.entity_type;
var entity_id = parentElement.dataset.entity_id;
var entity_name = parentElement.dataset.entity_name;
entity_id = parseInt(entity_id);
if (current_stored.indexOf(l_entity_id) > -1) {
current_stored.splice(current_stored.indexOf(l_entity_id),1);
current_stored = [...new Set(current_stored)];
lcst.setItem(key,current_stored); //this already formats it correctly
var whattoadd = ((l_entity_type == 'track') ? "Artists or Album" : "Artists")
notify("Unmarked " + l_entity_name + " to add " + whattoadd,"Currently " + current_stored.length + " marked!")
if (!parentElement) {
showValidMergeIcons();
}
else {
toggleAssociationIcons(parentElement);
}
var key = "marked_for_associate_" + entity_type;
var current_stored = getStoredList(key);
if (current_stored.indexOf(entity_id) > -1) {
current_stored.splice(current_stored.indexOf(entity_id),1);
storeList(key,current_stored);
notify("Unmarked " + entity_name + " from association with " + associate_targets[entity_type].join(" or "),"Currently " + current_stored.length + " marked!")
toggleAssociationIcons(parentElement);
}
else {
notify(entity_name + " was not marked!","")
//notify(entity_name + " was not marked!","")
}
}
@ -376,23 +307,78 @@ function toggleAssociationIcons(element) {
var entity_id = element.dataset.entity_id;
entity_id = parseInt(entity_id);
const lcst = window.sessionStorage;
var key = "marked_for_associate_" + entity_type;
var current_stored = (lcst.getItem(key) || '').split(",");
current_stored = current_stored.filter((x)=>x).map((x)=>parseInt(x));
var current_stored = getStoredList(key);
if (current_stored.indexOf(entity_id) > -1) {
element.classList.add('marked');
element.classList.add('marked_for_associate');
} else {
element.classList.remove('marked');
element.classList.remove('marked_for_associate');
}
if (current_stored.length > 0) {
element.classList.add('somethingmarked_for_associate');
}
else {
element.classList.remove('somethingmarked_for_associate');
}
var sourcetypes = associate_sources[entity_type];
var sourcelist = [];
for (var src of sourcetypes) {
var key = "marked_for_associate_" + src;
sourcelist = sourcelist.concat(getStoredList(key));
}
if (sourcelist.length > 0) {
element.classList.add('sources_marked_for_associate');
}
else {
element.classList.remove('sources_marked_for_associate');
}
}
function toggleMergeIcons(element) {
var entity_type = element.dataset.entity_type;
var entity_id = element.dataset.entity_id;
entity_id = parseInt(entity_id);
var key = "marked_for_merge_" + entity_type;
var current_stored = getStoredList(key);
if (current_stored.indexOf(entity_id) > -1) {
element.classList.add('marked_for_merge');
} else {
element.classList.remove('marked_for_merge');
}
if (current_stored.length > 0) {
element.classList.add('somethingmarked_for_merge');
}
else {
element.classList.remove('somethingmarked_for_merge');
}
}
document.addEventListener('DOMContentLoaded',function(){
var listrows = document.getElementsByClassName('listrow');
for (var row of listrows) {
toggleAssociationIcons(row);
toggleMergeIcons(row); //just for the coloring, no icons
}
var topbars = document.getElementsByClassName('iconsubset');
for (var bar of topbars) {
toggleAssociationIcons(bar);
toggleMergeIcons(bar);
}
})
function merge() {
const lcst = window.sessionStorage;
var key = "marked_for_merge_" + entity_type;
var current_stored = lcst.getItem(key).split(",");
current_stored = current_stored.filter((x)=>x).map((x)=>parseInt(x));
var current_stored = getStoredList(key);
callback_func = function(req){
if (req.status == 200) {
@ -415,26 +401,28 @@ function merge() {
json=true
);
lcst.removeItem(key);
storeList(key,[]);
}
function associate() {
const lcst = window.sessionStorage;
var target_entity_types = {artist:['album','track'], album:['track']};
function associate(element) {
const parentElement = element.closest('[data-entity_id]');
var entity_type = parentElement.dataset.entity_type;
var entity_id = parentElement.dataset.entity_id;
entity_id = parseInt(entity_id);
var requests_todo = 0;
for (var target_entity_type of target_entity_types[entity_type]) {
for (var target_entity_type of associate_sources[entity_type]) {
var key = "marked_for_associate_" + target_entity_type;
var current_stored = (lcst.getItem(key) || '').split(",");
current_stored = current_stored.filter((x)=>x).map((x)=>parseInt(x));
var current_stored = getStoredList(key);
if (current_stored.length != 0) {
requests_todo += 1;
callback_func = function(req){
if (req.status == 200) {
showValidMergeIcons();
toggleAssociationIcons(parentElement);
notifyCallback(req);
requests_todo -= 1;
if (requests_todo == 0) {
@ -458,24 +446,30 @@ function associate() {
json=true
);
lcst.removeItem(key);
storeList(key,[]);
}
}
}
function cancelMerge() {
const lcst = window.sessionStorage;
function cancelMerge(element) {
const parentElement = element.closest('[data-entity_id]');
var entity_type = parentElement.dataset.entity_type;
var key = "marked_for_merge_" + entity_type;
lcst.setItem(key,[]);
showValidMergeIcons();
notify("Cancelled merge!","")
storeList(key,[])
toggleMergeIcons(parentElement);
notify("Cancelled " + entity_type + " merge!","")
}
function cancelAssociate() {
const lcst = window.sessionStorage;
function cancelAssociate(element) {
const parentElement = element.closest('[data-entity_id]');
var entity_type = parentElement.dataset.entity_type;
var key = "marked_for_associate_" + entity_type;
lcst.setItem(key,[]);
showValidMergeIcons();
notify("Cancelled association!","")
storeList(key,[])
toggleAssociationIcons(parentElement);
notify("Cancelled " + entity_type + " association!","")
}