etiquette/frontends/etiquette_flask/templates/album.html
Ethan Dalool adb1d0ef39 Replace all double blank lines with single, improve hash headers.
There was always some semblance that two blank lines has some kind of
meaning or structure that's different from single blank lines, but
in reality it was mostly arbitrary and I can't stand to look at it
any more.
2020-09-19 03:13:23 -07:00

443 lines
13 KiB
HTML

<!DOCTYPE html5>
<html>
{% macro shared_css() %}
<style>
h2, h3
{
margin-top: 0;
}
#album_metadata h2 .editor_input
{
font-size: inherit;
font-weight: inherit;
}
#description_text
{
font-family: initial;
padding: 8px;
}
#left
{
display: grid;
grid-row-gap: 30px;
grid-auto-rows: max-content;
}
#right
{
display: grid;
grid-row-gap: 8px;
grid-auto-rows: min-content;
padding: 8px;
background-color: var(--color_transparency);
}
#right > *
{
/* Fixes button_with_confirm, spinner, etc. from width-jumping on load,
because originally the button is occupying the full width and then becomes
small when it gets put into the holder */
margin-right: auto;
/* Fixes the button_with_confirm inputs from causing the overall row to
become wider than the containing parent when expanded. */
word-break: break-all;
}
#right input
{
margin: 0;
}
#right .confirm_holder_stage2
{
display: flex;
flex-direction: row;
}
#right .confirm_holder_stage2 span,
#right .confirm_holder_stage2 input
{
flex: 1;
min-width: 0;
}
.remove_child_button
{
display: none;
}
.remove_child_button:hover,
.album_card:hover .remove_child_button
{
display: initial;
}
</style>
{% endmacro %}
{% if album is not defined %} {## Album listing ###################################################}
<head>
{% import "header.html" as header %}
{% import "album_card.html" as album_card %}
<title>Albums</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="/static/css/common.css">
<link rel="stylesheet" href="/static/css/etiquette.css">
<link rel="stylesheet" href="/static/css/photo_card.css">
{% if theme %}<link rel="stylesheet" href="/static/css/theme_{{theme}}.css">{% endif %}
<script src="/static/js/common.js"></script>
<script src="/static/js/api.js"></script>
{{shared_css()}}
</head>
<body>
{{header.make_header(session=session)}}
<div id="content_body" class="sticky_side_right sticky_bottom_right">
<div id="left">
<div id="album_list" class="panel">
<h2>Albums</h2>
{% for album in albums %}
{{album_card.create_album_card(album, view=view, draggable=true)}}
{% endfor %}
</div>
</div>
<div id="right">
{% if view != "list" %}
<a href="?view=list">List view</a>
{% else %}
<a href="?view=grid">Grid view</a>
{% endif %}
<button
class="green_button button_with_confirm"
data-is-input="1"
data-prompt="Album title"
data-cancel-class="gray_button"
data-onclick="return create_child(event.target.input_source.value);"
>
Create album
</button>
</div>
</div>
</body>
<script id="album_listing_script" type="text/javascript">
const ALBUM_ID = undefined;
</script>
{% else %} {## Individual album ###################################################################}
<head>
{% import "header.html" as header %}
{% import "album_card.html" as album_card %}
{% import "photo_card.html" as photo_card %}
{% import "clipboard_tray.html" as clipboard_tray %}
<title>{{album.display_name}} | Albums</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="/static/css/common.css">
<link rel="stylesheet" href="/static/css/etiquette.css">
<link rel="stylesheet" href="/static/css/clipboard_tray.css">
<link rel="stylesheet" href="/static/css/photo_card.css">
{% if theme %}<link rel="stylesheet" href="/static/css/theme_{{theme}}.css">{% endif %}
<script src="/static/js/common.js"></script>
<script src="/static/js/api.js"></script>
<script src="/static/js/spinner.js"></script>
<script src="/static/js/editor.js"></script>
<script src="/static/js/hotkeys.js"></script>
<script src="/static/js/photo_clipboard.js"></script>
{{shared_css()}}
</head>
<body>
{{header.make_header(session=session)}}
<div id="content_body" class="sticky_side_right sticky_bottom_right">
<div id="right">
{% if view != "list" %}
<a href="?view=list">List view</a>
{% else %}
<a href="?view=grid">Grid view</a>
{% endif %}
<button
class="red_button button_with_confirm"
data-onclick="return delete_album_form();"
data-prompt="Delete Album?"
data-cancel-class="gray_button"
>
Delete
</button>
<button
class="green_button button_with_confirm"
data-is-input="1"
data-prompt="Album title"
data-cancel-class="gray_button"
data-onclick="return create_child(event.target.input_source.value);"
>
Create child
</button>
<button
class="green_button button_with_confirm"
data-is-input="1"
data-prompt="Child ID"
data-cancel-class="gray_button"
data-onclick="return add_child(event.target.input_source.value);"
>
Add child
</button>
{% set associated_directories = album.get_associated_directories() %}
<button
class="green_button button_with_spinner"
onclick="return refresh_associated_directories_form();"
data-spinner-delay="500"
{% if associated_directories %}
title="Pull from {{associated_directories|length}} directories"
{% else %}
title="No associated directories"
disabled
{% endif %}
>
Refresh directories
</button>
</div>
<div id="left">
<div id="hierarchy_self" class="panel">
<div id="album_metadata">
<h2><span
id="title_text"
data-editor-id="title"
data-editor-empty-text="{{album.id}}"
data-editor-placeholder="title"
>
{{-album.display_name-}}
</span></h2>
<pre
id="description_text"
data-editor-id="description"
data-editor-placeholder="description"
{% if not album.description %}class="hidden"{% endif %}
>
{{-album.description-}}
</pre>
</div>
<button class="green_button editor_toolbox_placeholder">Edit</button>
</div>
<div id="hierarchy_parents" class="panel">
{% set parents = album.get_parents() %}
{% if parents %}
<h3>{{parents|length}} Parents</h3>
{% for parent in parents %}
{{album_card.create_album_card(parent, view=view)}}
{% endfor %}
{% else %}
<h3>1 Parent</h3>
{{album_card.create_album_card("root", view=view)}}
{% endif %}
</div>
{% set sub_albums = album.get_children() %}
{% if sub_albums %}
<div id="hierarchy_children" class="panel">
<h3>{{sub_albums|length}} Children</h3>
{% for sub_album in sub_albums|sort(attribute='title') %}
{{album_card.create_album_card(sub_album, view=view, unlink_parent=album, draggable=true)}}
{% endfor %}
</div>
{% endif %}
{% set photos = album.get_photos() %}
{% if photos %}
<div id="hierarchy_photos" class="panel">
<h3>{{photos|length}} Photos</h3>
<div id="photo_list">
{% for photo in photos %}
{{photo_card.create_photo_card(photo, view=view)}}
{% endfor %}
</div>
</div>
{% endif %}
{% set has_local_photos = photos|length > 0 %}
{% set has_child_photos = album.has_any_subalbum_photo() %}
{% if has_local_photos or has_child_photos %}
<div id="download_links" class="panel">
<h3>Download</h3>
{% if has_local_photos %}
<p><a id="download_link_single" href="/album/{{album.id}}.zip?recursive=no">These files &ndash; {{album.sum_bytes(recurse=False)|bytestring}}</a></p>
{% endif %}
{% if has_child_photos %}
<p><a id="download_link_recursive" href="/album/{{album.id}}.zip?recursive=yes">Include children &ndash; {{album.sum_bytes(recurse=True)|bytestring}}</a></p>
{% endif %}
</div>
{% endif %}
</div>
{{clipboard_tray.clipboard_tray()}}
<div class="my_clipboard_tray_toolbox">
<button class="green_button" onclick="return paste_photo_clipboard();">Add to this album</button>
<button class="red_button" onclick="return unpaste_photo_clipboard();">Remove from this album</button>
</div>
</div>
</body>
<script id="album_individual_script" type="text/javascript">
const ALBUM_ID = "{{album.id}}";
function add_child(child_id)
{
if (! child_id.trim())
{
return;
}
api.albums.add_child(ALBUM_ID, child_id, common.refresh);
}
function delete_album_form()
{
api.albums.delete(ALBUM_ID, api.albums.callback_go_to_albums);
}
function refresh_associated_directories_form()
{
api.albums.refresh_directories(ALBUM_ID, common.refresh);
}
function paste_photo_clipboard()
{
const photo_ids = Array.from(photo_clipboard.clipboard);
api.albums.add_photos(ALBUM_ID, photo_ids, common.refresh);
}
function unpaste_photo_clipboard()
{
const photo_ids = Array.from(photo_clipboard.clipboard);
api.albums.remove_photos(ALBUM_ID, photo_ids, common.refresh);
}
function on_open(ed, edit_element_map, display_element_map)
{
ed.open();
edit_element_map["title"].focus();
}
function on_save(ed, edit_element_map, display_element_map)
{
function callback(response)
{
if (response.meta.status != 200)
{
ed.show_error("Status: " + response.meta.status);
return;
}
ed.save();
const title_display = display_element_map["title"];
const description_display = display_element_map["description"];
document.title = title_display.innerText + " | Albums";
if (description_display.innerText == "")
{
description_display.classList.add("hidden");
}
}
edit_element_map["title"].value = edit_element_map["title"].value.trim();
const title = edit_element_map["title"].value;
const description = edit_element_map["description"].value;
ed.show_spinner();
api.albums.edit(ALBUM_ID, title, description, callback);
}
function on_cancel(ed, edit_element_map, display_element_map)
{
ed.cancel();
if (display_element_map["description"].innerText == "")
{
display_element_map["description"].classList.add("hidden");
}
}
const title_text = document.getElementById("title_text");
const description_text = document.getElementById("description_text");
const ed = new editor.Editor([title_text, description_text], on_open, on_save, on_cancel);
</script>
{% endif %} {## Shared ############################################################################}
<script id="album_shared_script" type="text/javascript">
function create_child(title)
{
if (! title)
{
title = undefined;
}
const parent_id = ALBUM_ID;
api.albums.create(title, parent_id, api.albums.callback_follow);
}
function get_album_card_from_child(element)
{
/*
Given an element which is known to be a child of an album card, navigate up
the parent tree until we find that album card.
This is used to make drag-and-drop work even when you start your drag by
clicking on the album's thumbnail, title, etc.
*/
while (! element.classList.contains("album_card"))
{
element = element.parentElement;
}
return element;
}
function on_album_drag_start(event)
{
const album_card = get_album_card_from_child(event.target);
event.dataTransfer.setData("text/plain", album_card.id);
}
function on_album_drag_end(event)
{
}
function on_album_drag_over(event)
{
event.preventDefault();
}
function on_album_drag_drop(event)
{
const child = document.getElementById(event.dataTransfer.getData("text"));
const child_id = child.dataset.id;
const parent = event.currentTarget;
const parent_id = parent.dataset.id;
event.dataTransfer.clearData();
if (child_id == parent_id)
{
return;
}
const child_title = child.querySelector('.album_card_title').textContent.trim();
const parent_title = parent.querySelector('.album_card_title').textContent.trim();
if (confirm(`Move\n${child_title}\ninto\n${parent_title}?`))
{
if (ALBUM_ID)
{
api.albums.add_child(parent_id, child_id, null);
api.albums.remove_child(ALBUM_ID, child_id, common.refresh);
}
else
{
api.albums.add_child(parent_id, child_id, common.refresh);
}
}
}
</script>
</html>