etiquette/frontends/etiquette_flask/templates/album.html

484 lines
14 KiB
HTML
Raw Normal View History

2021-06-22 20:38:08 +00:00
<!DOCTYPE html>
2016-09-18 08:33:46 +00:00
<html>
{% macro shared_css() %}
<style>
#hierarchy_self
{
display: grid;
grid-template:
"metadata thumbnail" auto
/1fr auto;
}
#album_metadata
{
grid-area: metadata;
word-break: break-word;
}
#album_thumbnail
{
grid-area: thumbnail;
align-self: center;
}
#album_thumbnail img
{
max-height: 150px;
}
2021-10-31 23:28:34 +00:00
#album_metadata h1 .editor_input
{
font-size: inherit;
font-weight: inherit;
}
#album_metadata #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;
}
</style>
{% endmacro %}
{% if album is not defined %} {## Album listing ###################################################}
<head>
{% import "header.html" as header %}
{% import "cards.html" as cards %}
<title>Albums</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="icon" href="/favicon.png" type="image/png"/>
<link rel="stylesheet" href="/static/css/common.css">
<link rel="stylesheet" href="/static/css/etiquette.css">
<link rel="stylesheet" href="/static/css/cards.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/cards.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">
2022-07-20 03:24:06 +00:00
<h1>{{albums|length}} Albums</h1>
{% for album in albums %}
{{cards.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"
2021-01-10 22:49:35 +00:00
data-onclick="return create_album_form(event);"
>
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 "cards.html" as cards %}
{% 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="icon" href="/favicon.png" type="image/png"/>
<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/cards.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/cards.js"></script>
<script src="/static/js/contextmenus.js"></script>
<script src="/static/js/spinners.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>
2021-01-21 02:25:15 +00:00
{% if album.thumbnail_photo %}
<button
class="red_button button_with_confirm"
data-onclick="return remove_thumbnail_photo_form();"
data-prompt="Remove?"
data-cancel-class="gray_button"
>
Remove thumbnail
</button>
{% endif %}
<button
class="green_button button_with_confirm"
data-is-input="1"
data-prompt="Album title"
data-cancel-class="gray_button"
2021-01-10 22:49:35 +00:00
data-onclick="return create_album_form(event);"
>
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"
2021-01-10 22:49:35 +00:00
data-onclick="return add_child_form(event);"
>
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>
{% if request.is_localhost and associated_directories|length == 1 %}
<button id="show_in_folder_button" onclick="return show_in_folder_form();">Show in folder</button>
{% endif %}
</div>
<div id="left">
2019-08-14 20:49:08 +00:00
<div id="hierarchy_self" class="panel">
<div id="album_metadata">
2021-10-31 23:28:34 +00:00
<h1><span id="title_text">{{-album.display_name-}}</span></h1>
<pre
id="description_text"
{% if not album.description %}class="hidden"{% endif %}
>
{{-album.description-}}
</pre>
{% set author = album.author %}
{% if author is not none %}
<p>Author: <a href="/userid/{{author.id}}">{{author.display_name}}</a></p>
{% endif %}
<p>Created on <span title="{{album.created|timestamp_to_8601}}">{{album.created|timestamp_to_naturaldate}}.</span></p>
<button class="green_button editor_toolbox_placeholder">Edit</button>
</div> <!-- #album_metadata -->
<div id="album_thumbnail">
{%- if album.thumbnail_photo %}
<img src="/thumbnail/{{album.thumbnail_photo.id}}.jpg"/>
{% endif -%}
</div>
</div>
2019-08-14 20:49:08 +00:00
<div id="hierarchy_parents" class="panel">
{% set parents = album.get_parents() %}
{% if parents %}
2021-10-31 23:28:34 +00:00
<h2>{{parents|length}} Parents</h2>
{% for parent in parents %}
{{cards.create_album_card(parent, view=view)}}
{% endfor %}
{% else %}
2021-10-31 23:28:34 +00:00
<h2>1 Parent</h2>
{{cards.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">
2021-10-31 23:28:34 +00:00
<h2>{{sub_albums|length}} Children</h2>
{% for sub_album in sub_albums|sort(attribute='title') %}
{{cards.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">
2021-10-31 23:28:34 +00:00
<h2>{{photos|length}} Photos</h2>
2018-11-18 01:36:47 +00:00
<div id="photo_list">
{% for photo in photos|sort(attribute='basename', case_sensitive=False) %}
{{cards.create_photo_card(photo, view=view)}}
2018-11-18 01:36:47 +00:00
{% 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">
2021-10-31 23:28:34 +00:00
<h2>Download</h2>
{% 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
2021-01-10 22:49:35 +00:00
function add_child_form(event)
{
2021-01-10 22:49:35 +00:00
const child_id = event.target.input_source.value;
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);
}
2021-01-21 02:25:15 +00:00
function remove_thumbnail_photo_form()
{
api.albums.remove_thumbnail_photo(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 show_in_folder_form()
{
api.albums.show_in_folder(ALBUM_ID, show_in_folder_callback);
}
function show_in_folder_callback(response)
{
if (response.meta.status !== 200)
{
alert(JSON.stringify(response));
return;
}
}
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);
function prepare_photo_contextmenu()
{
function build_photo_contextmenu(photo, menu)
{
;
}
const menu = document.createElement("div");
const set_thumbnail_button = document.createElement("button");
set_thumbnail_button.innerText = "Set as Album thumbnail";
set_thumbnail_button.onclick = function(event)
{
const photo_id = cards.photos.right_clicked_photo.dataset.id;
api.albums.set_thumbnail_photo(ALBUM_ID, photo_id, common.refresh_or_alert);
}
menu.appendChild(set_thumbnail_button);
document.body.appendChild(menu);
cards.photos.set_contextmenu(menu, build_photo_contextmenu);
}
function on_pageload()
{
photo_clipboard.register_hotkeys();
prepare_photo_contextmenu();
}
document.addEventListener("DOMContentLoaded", on_pageload);
</script>
{% endif %} {## Shared ############################################################################}
<script id="album_shared_script" type="text/javascript">
2021-01-10 22:49:35 +00:00
function create_album_form(event)
{
const title = event.target.input_source.value.trim() || undefined;
2020-09-15 01:33:53 +00:00
const parent_id = ALBUM_ID;
api.albums.create(title, parent_id, api.albums.callback_follow);
}
2016-11-27 09:06:11 +00:00
</script>
2017-04-23 04:38:23 +00:00
</html>