etiquette/frontends/etiquette_flask/templates/album.html

461 lines
13 KiB
HTML
Raw Normal View History

2016-09-18 08:33:46 +00:00
<!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;
2020-11-05 00:56:24 +00:00
grid-row-gap: 8px;
grid-auto-rows: max-content;
}
#right
{
display: grid;
grid-row-gap: 8px;
grid-auto-rows: min-content;
}
2018-11-18 00:57:07 +00:00
#right > *
{
2019-08-26 00:47:02 +00:00
/* 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 */
2018-11-18 00:57:07 +00:00
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;
2018-11-18 00:57:07 +00:00
}
#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">
2019-08-14 20:49:08 +00:00
<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>
2020-11-04 00:25:04 +00:00
<div id="right" class="panel">
{% 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">
2020-09-15 01:33:53 +00:00
const ALBUM_ID = undefined;
</script>
{% else %} {## Individual album ###################################################################}
2016-09-18 08:33:46 +00:00
<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>
2016-09-18 08:33:46 +00:00
<meta charset="UTF-8">
2017-07-21 06:10:48 +00:00
<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/album_autocomplete.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>
2016-11-27 09:06:11 +00:00
{{shared_css()}}
2016-11-27 09:06:11 +00:00
</head>
2016-09-18 08:33:46 +00:00
<body>
{{header.make_header(session=session)}}
<div id="content_body" class="sticky_side_right sticky_bottom_right">
2020-11-04 00:25:04 +00:00
<div id="right" class="panel">
{% 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-holder-id="add_child_holder"
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">
2019-08-14 20:49:08 +00:00
<div id="hierarchy_self" class="panel">
<div id="album_metadata">
2021-01-02 03:46:06 +00:00
<h2><span id="title_text">{{-album.display_name-}}</span></h2>
<pre
id="description_text"
{% if not album.description %}class="hidden"{% endif %}
>
{{-album.description-}}
</pre>
</div>
<button class="green_button editor_toolbox_placeholder">Edit</button>
</div>
2019-08-14 20:49:08 +00:00
<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 %}
2019-08-14 20:49:08 +00:00
<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="photos_holder panel">
2018-11-18 01:36:47 +00:00
<h3>{{photos|length}} Photos</h3>
<div id="photo_list">
{% for photo in photos|sort(attribute='basename', case_sensitive=False) %}
2018-11-18 01:36:47 +00:00
{{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 %}
2019-08-14 20:49:08 +00:00
<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>
2016-09-18 08:33:46 +00:00
</div>
</body>
<script id="album_individual_script" type="text/javascript">
2020-09-15 01:33:53 +00:00
const ALBUM_ID = "{{album.id}}";
2017-04-23 04:38:23 +00:00
function add_child(child_id)
{
if (! child_id.trim())
{
return;
}
api.albums.add_child(ALBUM_ID, child_id, common.refresh_or_alert);
}
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_or_alert);
}
function paste_photo_clipboard()
{
2020-09-15 01:33:53 +00:00
const photo_ids = Array.from(photo_clipboard.clipboard);
api.albums.add_photos(ALBUM_ID, photo_ids, common.refresh_or_alert);
}
function unpaste_photo_clipboard()
{
2020-09-15 01:33:53 +00:00
const photo_ids = Array.from(photo_clipboard.clipboard);
api.albums.remove_photos(ALBUM_ID, photo_ids, common.refresh_or_alert);
}
2021-01-02 03:46:06 +00:00
rename_ed_on_open = undefined;
2017-04-23 04:38:23 +00:00
2021-01-02 03:46:06 +00:00
function rename_ed_on_save(ed)
2017-04-23 04:38:23 +00:00
{
function callback(response)
{
ed.hide_spinner();
if (! response.meta.json_ok)
{
alert(JSON.stringify(response));
return;
}
if ("error_type" in response.data)
{
ed.show_error(response.data.error_message);
return;
}
2021-01-02 03:46:06 +00:00
// The data coming back from the server will have been normalized.
ed.elements["title"].edit.value = response.data.title;
2021-01-02 03:46:06 +00:00
ed.save();
2021-01-02 03:46:06 +00:00
document.title = ed.elements["title"].display.innerText + " | Albums";
2017-04-23 04:38:23 +00:00
}
2021-01-02 03:46:06 +00:00
const title = ed.elements["title"].edit.value;
const description = ed.elements["description"].edit.value;
ed.show_spinner();
api.albums.edit(ALBUM_ID, title, description, callback);
2017-04-23 04:38:23 +00:00
}
2021-01-02 03:46:06 +00:00
const rename_ed_elements = [
{
2021-01-02 03:46:06 +00:00
"id": "title",
"element": document.getElementById("title_text"),
"placeholder": "title",
"empty_text": ALBUM_ID,
"autofocus": true,
},
{
"id": "description",
"element": document.getElementById("description_text"),
"placeholder": "description",
"hide_when_empty": true,
},
];
const rename_ed = new editor.Editor(
2021-01-02 03:46:06 +00:00
rename_ed_elements,
rename_ed_on_open,
rename_ed_on_save,
);
function add_album_datalist_on_load(datalist)
{
/*
I found that the `list` property must be set by setAttribute, not
regular assignment, and it must be provided the ID of the datalist, not
the datalist object itself. Furthermore, it cannot be done until the
datalist is ready -- I tried adjusting the button_with_confirm
initializer to let me set the datalist during the input's construction,
but at that point the datalist prep usually / certainly hasn't run yet
and it didn't work. All that is to say I had to add this on_load hook
function to only call setAttribute after the datalist has been prepared.
*/
const holder = document.getElementById("add_child_holder");
const input = holder.getElementsByTagName("input")[0];
input.setAttribute("list", "album_autocomplete_datalist");
}
album_autocomplete.on_load_hooks.push(add_album_datalist_on_load);
</script>
{% endif %} {## Shared ############################################################################}
<script id="album_shared_script" type="text/javascript">
function create_child(title)
{
if (! title)
{
title = undefined;
}
2020-09-15 01:33:53 +00:00
const parent_id = ALBUM_ID;
api.albums.create(title, parent_id, api.albums.callback_follow);
}
function on_album_drag_start(event)
{
const album_card = event.target.closest(".album_card");
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)
{
2020-09-15 01:33:53 +00:00
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;
}
let prompt;
if (parent_id === "root")
{
const child_title = child.querySelector('.album_card_title').textContent.trim();
prompt = `Remove child\n${child_title}?`;
}
else
{
const child_title = child.querySelector('.album_card_title').textContent.trim();
const parent_title = parent.querySelector('.album_card_title').textContent.trim();
prompt = `Move\n${child_title}\ninto\n${parent_title}?`;
}
2020-09-20 19:15:01 +00:00
if (! confirm(prompt))
{
2020-09-20 19:15:01 +00:00
return;
}
if (parent_id === "root")
{
api.albums.remove_child(ALBUM_ID, child_id, common.refresh_or_alert);
}
else if (ALBUM_ID)
2020-09-20 19:15:01 +00:00
{
api.albums.add_child(parent_id, child_id, null);
api.albums.remove_child(ALBUM_ID, child_id, common.refresh_or_alert);
2020-09-20 19:15:01 +00:00
}
else
{
api.albums.add_child(parent_id, child_id, common.refresh_or_alert);
}
}
2016-11-27 09:06:11 +00:00
</script>
2017-04-23 04:38:23 +00:00
</html>