etiquette/templates/photo.html

397 lines
11 KiB
HTML

<!DOCTYPE html5>
<html>
<head>
{% import "header.html" as header %}
<title>Photo</title>
<meta charset="UTF-8">
<link rel="stylesheet" href="/static/common.css">
<script src="/static/common.js"></script>
{% set filename = photo.id + photo.dot_extension %}
{% set file_link = "/file/" + filename %}
<style>
#content_body
{
/* Override common.css */
flex-direction: row;
flex: 1;
}
#left
{
display: flex;
flex-direction: column;
}
#right
{
flex: 1;
display: flex;
}
#editor_holder
{
max-width: 300px;
padding: 8px;
flex-direction: column;
background-color: rgba(0, 0, 0, 0.1);
}
#editor_area
{
flex: 3;
word-wrap: break-word;
}
#message_area
{
flex: 1;
}
.photo_viewer
{
display: flex;
flex: 1;
flex-direction: column;
justify-content: center;
align-items: center;
}
.photo_viewer a
{
display: flex;
justify-content: center;
align-items: center;
}
#photo_img_holder
{
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
background-repeat: no-repeat;
}
#photo_img_holder img
{
max-height: 100%;
max-width: 100%;
}
.photo_viewer audio
{
width: 100%;
}
.photo_viewer video
{
max-width: 100%;
max-height: 100%;
width: 100%;
}
#refresh_metadata_button
{
font-size: 11px;
}
@media screen and (max-width: 800px)
{
#content_body
{
/*
When flexing, it tries to contain itself entirely in the screen,
forcing #left and #right to squish together.
*/
flex: none;
flex-direction: column-reverse;
}
#left
{
/*
Display: None will be overridden as soon as the page detects that the
screen is in narrow mode and turns off the tag box's autofocus
*/
display: none;
width: initial;
max-width: none;
margin-top: 8px;
}
#right
{
flex: none;
height: calc(100% - 20px);
}
#editor_holder
{
display: flex;
flex-direction: row;
max-width: none;
}
#message_area
{
flex: 2;
height: initial;
max-height: none;
}
}
</style>
</head>
<body>
{{header.make_header(session=session)}}
<div id="content_body">
<div id="left">
<div id="editor_holder">
<div id="editor_area">
<!-- TAG INFO -->
<h4>Tags</h4>
<ul id="this_tags">
<li>
<input id="add_tag_textbox" type="text" autofocus>
<button id="add_tag_button" class="add_tag_button" onclick="submit_tag(receive_callback);">add</button>
</li>
{% set tags = photo.sorted_tags() %}
{% for tag in tags %}
<li>
<a class="tag_object" href="/search?tag_musts={{tag.name}}">{{tag.qualified_name()}}</a><!--
--><button
class="remove_tag_button"
onclick="remove_photo_tag('{{photo.id}}', '{{tag.name}}', receive_callback);">
</button>
</li>
{% endfor %}
</ul>
<!-- METADATA & DOWNLOAD -->
<h4>
File info
<button id="refresh_metadata_button" class="add_tag_button" onclick="refresh_metadata('{{photo.id}}');">refresh</button>
</h4>
<ul id="metadata">
{% if photo.author_id %}
{% set author = photo.author() %}
<li>Author: <a href="/user/{{author.username}}">{{author.username}}</a></li>
{% endif %}
{% if photo.width %}
<li>Dimensions: {{photo.width}}x{{photo.height}} px</li>
<li>Aspect ratio: {{photo.ratio}}</li>
{% endif %}
<li>Size: {{photo.bytestring()}}</li>
{% if photo.duration %}
<li>Duration: {{photo.duration_string()}}</li>
{% endif %}
<li><a href="/file/{{photo.id}}{{photo.dot_extension}}?download=1">Download as {{photo.id}}.{{photo.extension}}</a></li>
<li><a href="/file/{{photo.id}}{{photo.dot_extension}}?download=1&original_filename=1">Download as "{{photo.basename}}"</a></li>
</ul>
<!-- CONTAINING ALBUMS -->
{% set albums = photo.albums() %}
{% if albums %}
<h4>Albums containing this photo</h4>
<ul id="containing albums">
{% for album in albums %}
<li><a href="/album/{{album.id}}">{{album.title}}</a></li>
{% endfor %}
{% endif %}
</ul>
</div>
<div id="message_area">
</div>
</div>
</div>
<div id="right">
<!-- THE PHOTO ITSELF -->
<div class="photo_viewer">
{% if photo.simple_mimetype == "image" %}
<div id="photo_img_holder">
<img
id="photo_img"
src="{{file_link}}"
alt="{{photo.basename}}"
onclick="toggle_hoverzoom()"
onload="this.style.opacity=0.99"
>
</div>
{% elif photo.simple_mimetype == "video" %}
<video src="{{file_link}}" controls preload=none {%if photo.thumbnail%}poster="/thumbnail/{{photo.id}}.jpg"{%endif%}></video>
{% elif photo.simple_mimetype == "audio" %}
<audio src="{{file_link}}" controls></audio>
{% else %}
<a href="{{file_link}}">View {{filename}}</a>
{% endif %}
</div>
</div>
</div>
</body>
<script type="text/javascript">
var content_body = document.getElementById('content_body');
var add_tag_box = document.getElementById('add_tag_textbox');
var add_tag_button = document.getElementById('add_tag_button');
var message_area = document.getElementById('message_area');
add_tag_box.onkeydown = function(){entry_with_history_hook(add_tag_box, add_tag_button)};
function add_photo_tag(photoid, tagname, callback)
{
if (tagname === ""){return}
var url = "/photo/" + photoid + "/add_tag";
var data = new FormData();
data.append("tagname", tagname);
return post(url, data, callback);
}
function remove_photo_tag(photoid, tagname, callback)
{
if (tagname === ""){return}
var url = "/photo/" + photoid + "/remove_tag";
var data = new FormData();
data.append("tagname", tagname);
return post(url, data, callback);
}
function submit_tag(callback)
{
add_photo_tag('{{photo.id}}', add_tag_box.value, callback);
add_tag_box.value = "";
}
function receive_callback(response)
{
var message_text;
var message_positivity;
var tagname = response["tagname"];
if ("error_type" in response)
{
message_positivity = "message_negative";
message_text = response["error_message"];
}
else
{
var action;
message_positivity = "message_positive";
if (response["_request_url"].includes("add_tag"))
{
message_text = "Added tag " + tagname;
}
else if (response["_request_url"].includes("remove_tag"))
{
message_text = "Removed tag " + tagname;
}
else
{
return;
}
}
create_message_bubble(message_area, message_positivity, message_text, 8000);
}
function refresh_metadata(photoid)
{
var url= "/photo/" + photoid + "/refresh_metadata";
var data = new FormData();
post(url, data);
setTimeout(function(){location.reload();}, 2000);
}
function enable_hoverzoom()
{
console.log("enable");
div = document.getElementById("photo_img_holder");
img = document.getElementById("photo_img");
if (img.naturalWidth < div.offsetWidth && img.naturalHeight < div.offsetHeight)
{
return;
}
img.style.opacity = 0;
img.style.display = "none";
div.style.cursor = "zoom-out";
div.style.backgroundImage = "url('{{file_link}}')";
div.onmousemove = move_hoverzoom;
setTimeout(function(){div.onclick = disable_hoverzoom;}, 100);
return true;
}
function disable_hoverzoom()
{
console.log("disable");
div = document.getElementById("photo_img_holder");
img = document.getElementById("photo_img");
img.style.opacity = 100;
div.style.cursor = "";
img.style.display="";
div.style.backgroundImage = "none";
div.onmousemove = null;
div.onclick = null;
if (getComputedStyle(content_body).flexDirection != "column-reverse")
{
add_tag_box.focus();
}
}
function toggle_hoverzoom()
{
img = document.getElementById("photo_img");
if (img.style.opacity === "0")
{
disable_hoverzoom();
}
else
{
enable_hoverzoom();
}
}
photo_img_holder = document.getElementById("photo_img_holder");
photo_img = document.getElementById("photo_img");
function move_hoverzoom(event)
{
var x;
var y;
// Adding 5% to perceived position gives us a bit of padding around the image,
// so you don't need to navigate a 1px line to see the edge.
// We first subtract half of the image dimensions so that the 5% is applied
// to both left and right. Otherwise 105% of 0 is still 0 which doesn't
// apply padding on the left.
var mouse_x = event.offsetX;
mouse_x -= (photo_img_holder.offsetWidth / 2);
mouse_x *= 1.05;
mouse_x += (photo_img_holder.offsetWidth / 2);
var mouse_y = event.offsetY;
mouse_y -= (photo_img_holder.offsetHeight / 2);
mouse_y *= 1.05;
mouse_y += (photo_img_holder.offsetHeight / 2);
if (photo_img.naturalWidth < photo_img_holder.offsetWidth)
{
// If the image is smaller than the frame, just center it
x = (photo_img.naturalWidth - photo_img_holder.offsetWidth) / 2;
}
else
{
// Take the amount of movement necessary (frame width - image width)
// times our distance across the image as a percentage.
x = (photo_img.naturalWidth - photo_img_holder.offsetWidth) * (mouse_x / photo_img_holder.offsetWidth);
}
if (photo_img.naturalHeight < photo_img_holder.offsetHeight)
{
y = (photo_img.naturalHeight - photo_img_holder.offsetHeight) / 2;
}
else
{
y = (photo_img.naturalHeight - photo_img_holder.offsetHeight) * (mouse_y / photo_img_holder.offsetHeight);
}
//console.log(x);
photo_img_holder.style.backgroundPosition=(-x)+"px "+(-y)+"px";
}
setTimeout(
/*
When the screen is in column mode, the autofocusing of the tag box snaps the
screen down to it, which is annoying. By starting the #left hidden, we have
an opportunity to unset the autofocus before showing it.
*/
function()
{
var left = document.getElementById("left");
if (getComputedStyle(content_body).flexDirection == "column-reverse")
{
add_tag_box.autofocus = false;
}
left.style.display = "flex";
},
0
);
</script>
</html>