2016-09-18 08:33:46 +00:00
|
|
|
<!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>
|
2016-12-25 02:34:34 +00:00
|
|
|
{% set filename = photo.id + photo.dot_extension %}
|
2016-10-30 01:46:23 +00:00
|
|
|
{% set link = "/file/" + filename %}
|
2016-11-27 09:06:11 +00:00
|
|
|
|
2016-09-18 08:33:46 +00:00
|
|
|
<style>
|
|
|
|
#content_body
|
|
|
|
{
|
|
|
|
/* Override common.css */
|
2017-02-25 06:07:59 +00:00
|
|
|
flex-direction: row;
|
2016-09-18 08:33:46 +00:00
|
|
|
flex: 1;
|
|
|
|
}
|
|
|
|
#left
|
|
|
|
{
|
|
|
|
display: flex;
|
2016-12-24 03:49:51 +00:00
|
|
|
padding: 8px;
|
2016-09-18 08:33:46 +00:00
|
|
|
flex-direction: column;
|
|
|
|
justify-content: flex-start;
|
|
|
|
background-color: rgba(0, 0, 0, 0.1);
|
2017-02-25 06:07:59 +00:00
|
|
|
max-width: 300px;
|
2016-09-18 08:33:46 +00:00
|
|
|
}
|
|
|
|
#right
|
|
|
|
{
|
|
|
|
flex: 1;
|
2017-02-25 06:07:59 +00:00
|
|
|
display: flex;
|
|
|
|
}
|
|
|
|
@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;
|
|
|
|
flex-direction: row;
|
|
|
|
width: initial;
|
|
|
|
max-width: none;
|
|
|
|
margin-top: 8px;
|
|
|
|
}
|
|
|
|
#right
|
|
|
|
{
|
|
|
|
flex: none;
|
|
|
|
height: calc(100% - 20px);
|
|
|
|
}
|
2016-09-18 08:33:46 +00:00
|
|
|
}
|
|
|
|
#editor_area
|
|
|
|
{
|
|
|
|
flex: 3;
|
|
|
|
}
|
|
|
|
#message_area
|
|
|
|
{
|
|
|
|
overflow-y: auto;
|
|
|
|
flex: 1;
|
|
|
|
background-color: rgba(0, 0, 0, 0.1);
|
|
|
|
}
|
2016-11-07 02:00:30 +00:00
|
|
|
.photo_viewer
|
2016-09-18 08:33:46 +00:00
|
|
|
{
|
|
|
|
display: flex;
|
|
|
|
flex: 1;
|
|
|
|
flex-direction: column;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
|
|
|
}
|
2016-11-07 02:00:30 +00:00
|
|
|
.photo_viewer a
|
2016-09-18 08:33:46 +00:00
|
|
|
{
|
2016-10-30 01:46:23 +00:00
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
|
|
|
}
|
|
|
|
#photo_img_holder
|
|
|
|
{
|
|
|
|
height: 100%;
|
|
|
|
width: 100%;
|
2016-09-18 08:33:46 +00:00
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
2016-10-30 01:46:23 +00:00
|
|
|
background-repeat: no-repeat;
|
2016-09-18 08:33:46 +00:00
|
|
|
}
|
2017-02-25 06:07:59 +00:00
|
|
|
#photo_img_holder img
|
2016-09-18 08:33:46 +00:00
|
|
|
{
|
2016-10-10 03:50:13 +00:00
|
|
|
max-height: 100%;
|
|
|
|
max-width: 100%;
|
2016-09-18 08:33:46 +00:00
|
|
|
}
|
2016-11-07 02:00:30 +00:00
|
|
|
.photo_viewer audio
|
2016-09-18 08:33:46 +00:00
|
|
|
{
|
|
|
|
width: 100%;
|
|
|
|
}
|
2016-11-07 02:00:30 +00:00
|
|
|
.photo_viewer video
|
2016-09-18 08:33:46 +00:00
|
|
|
{
|
|
|
|
max-width: 100%;
|
|
|
|
max-height: 100%;
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
</style>
|
2016-11-27 09:06:11 +00:00
|
|
|
</head>
|
|
|
|
|
2016-09-18 08:33:46 +00:00
|
|
|
|
|
|
|
<body>
|
2016-12-18 13:12:14 +00:00
|
|
|
{{header.make_header(session=session)}}
|
2016-09-18 08:33:46 +00:00
|
|
|
<div id="content_body">
|
|
|
|
<div id="left">
|
|
|
|
<div id="editor_area">
|
|
|
|
<!-- TAG INFO -->
|
|
|
|
<h4>Tags</h4>
|
|
|
|
<ul id="this_tags">
|
2016-12-21 00:33:40 +00:00
|
|
|
{% set tags = photo.sorted_tags() %}
|
|
|
|
{% for tag in tags %}
|
2016-09-18 08:33:46 +00:00
|
|
|
<li>
|
2016-12-21 00:33:40 +00:00
|
|
|
<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>
|
2016-09-18 08:33:46 +00:00
|
|
|
</li>
|
|
|
|
{% endfor %}
|
|
|
|
<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>
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
<!-- METADATA & DOWNLOAD -->
|
|
|
|
<h4>File info</h4>
|
|
|
|
<ul id="metadata">
|
2016-12-21 00:33:40 +00:00
|
|
|
{% if photo.author_id %}
|
|
|
|
{% set author = photo.author() %}
|
|
|
|
<li>Author: <a href="/user/{{author.username}}">{{author.username}}</a>
|
2016-10-10 03:50:13 +00:00
|
|
|
{% endif %}
|
2016-12-21 00:33:40 +00:00
|
|
|
{% if photo.width %}
|
|
|
|
<li>Dimensions: {{photo.width}}x{{photo.height}} px</li>
|
|
|
|
<li>Aspect ratio: {{photo.ratio}}</li>
|
2016-09-18 08:33:46 +00:00
|
|
|
{% endif %}
|
2016-12-24 03:49:51 +00:00
|
|
|
<li>Size: {{photo.bytestring()}}</li>
|
2016-12-21 00:33:40 +00:00
|
|
|
{% if photo.duration %}
|
2016-12-24 03:49:51 +00:00
|
|
|
<li>Duration: {{photo.duration_string()}}</li>
|
2016-12-21 00:33:40 +00:00
|
|
|
{% endif %}
|
2016-12-25 02:34:34 +00:00
|
|
|
<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>
|
2016-09-18 08:33:46 +00:00
|
|
|
</ul>
|
|
|
|
|
|
|
|
<!-- CONTAINING ALBUMS -->
|
2016-12-21 00:33:40 +00:00
|
|
|
{% set albums = photo.albums() %}
|
|
|
|
{% if albums %}
|
2016-09-18 08:33:46 +00:00
|
|
|
<h4>Albums containing this photo</h4>
|
|
|
|
<ul id="containing albums">
|
2016-12-21 00:33:40 +00:00
|
|
|
{% for album in albums %}
|
|
|
|
<li><a href="/album/{{album.id}}">{{album.title}}</a></li>
|
2016-09-18 08:33:46 +00:00
|
|
|
{% endfor %}
|
|
|
|
{% endif %}
|
|
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
<div id="message_area">
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div id="right">
|
2016-10-30 01:46:23 +00:00
|
|
|
<!-- THE PHOTO ITSELF -->
|
2016-11-07 02:00:30 +00:00
|
|
|
<div class="photo_viewer">
|
2016-12-24 03:49:51 +00:00
|
|
|
{% if photo.mimetype == "image" %}
|
2017-02-26 06:47:20 +00:00
|
|
|
<div id="photo_img_holder">
|
|
|
|
<img
|
|
|
|
id="photo_img"
|
|
|
|
src="{{link}}"
|
|
|
|
alt="{{photo.basename}}"
|
|
|
|
onclick="toggle_hoverzoom()"
|
|
|
|
onload="this.style.opacity=0.99"
|
|
|
|
>
|
|
|
|
</div>
|
2016-12-24 03:49:51 +00:00
|
|
|
{% elif photo.mimetype == "video" %}
|
2016-12-21 00:33:40 +00:00
|
|
|
<video src="{{link}}" controls preload=none {%if photo.thumbnail%}poster="/thumbnail/{{photo.id}}.jpg"{%endif%}></video>
|
2016-12-24 03:49:51 +00:00
|
|
|
{% elif photo.mimetype == "audio" %}
|
2016-09-18 08:33:46 +00:00
|
|
|
<audio src="{{link}}" controls></audio>
|
|
|
|
{% else %}
|
|
|
|
<a href="{{link}}">View {{filename}}</a>
|
|
|
|
{% endif %}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</body>
|
2016-11-27 09:06:11 +00:00
|
|
|
|
2016-09-18 08:33:46 +00:00
|
|
|
|
|
|
|
<script type="text/javascript">
|
2017-02-25 06:07:59 +00:00
|
|
|
var content_body = document.getElementById('content_body');
|
2016-10-10 03:50:13 +00:00
|
|
|
var add_tag_box = document.getElementById('add_tag_textbox');
|
|
|
|
var add_tag_button = document.getElementById('add_tag_button');
|
2016-09-18 08:33:46 +00:00
|
|
|
var message_area = document.getElementById('message_area');
|
2016-10-10 03:50:13 +00:00
|
|
|
add_tag_box.onkeydown = function(){entry_with_history_hook(add_tag_box, add_tag_button)};
|
2016-09-18 08:33:46 +00:00
|
|
|
|
2016-12-21 05:53:59 +00:00
|
|
|
function add_photo_tag(photoid, tagname, callback)
|
|
|
|
{
|
|
|
|
if (tagname === ""){return}
|
|
|
|
var url = "/photo/" + photoid;
|
|
|
|
data = new FormData();
|
|
|
|
data.append("add_tag", tagname);
|
|
|
|
return post(url, data, callback);
|
|
|
|
}
|
|
|
|
function remove_photo_tag(photoid, tagname, callback)
|
|
|
|
{
|
|
|
|
if (tagname === ""){return}
|
|
|
|
var url = "/photo/" + photoid;
|
|
|
|
data = new FormData();
|
|
|
|
data.append("remove_tag", 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 tagname = response["tagname"];
|
|
|
|
if ("error" in response)
|
|
|
|
{
|
2016-12-21 09:11:50 +00:00
|
|
|
message_positivity = "message_negative";
|
2016-12-21 05:53:59 +00:00
|
|
|
message_text = '"' + tagname + '" ' + response["error"];
|
|
|
|
}
|
|
|
|
else if ("action" in response)
|
|
|
|
{
|
|
|
|
var action = response["action"];
|
2016-12-21 09:11:50 +00:00
|
|
|
message_positivity = "message_positive";
|
2016-12-21 05:53:59 +00:00
|
|
|
if (action == "add_tag")
|
|
|
|
{
|
|
|
|
message_text = "Added tag " + tagname;
|
|
|
|
}
|
|
|
|
else if (action == "remove_tag")
|
|
|
|
{
|
|
|
|
message_text = "Removed tag " + tagname;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
create_message_bubble(message_area, message_positivity, message_text, 8000);
|
|
|
|
}
|
|
|
|
|
2016-10-30 01:46:23 +00:00
|
|
|
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('{{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;
|
2017-02-25 06:07:59 +00:00
|
|
|
if (getComputedStyle(content_body).flexDirection != "column-reverse")
|
|
|
|
{
|
|
|
|
add_tag_box.focus();
|
|
|
|
}
|
2016-10-30 01:46:23 +00:00
|
|
|
}
|
|
|
|
function toggle_hoverzoom()
|
|
|
|
{
|
|
|
|
img = document.getElementById("photo_img");
|
|
|
|
if (img.style.opacity === "0")
|
|
|
|
{
|
|
|
|
disable_hoverzoom();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
enable_hoverzoom();
|
|
|
|
}
|
|
|
|
}
|
2016-11-27 09:06:11 +00:00
|
|
|
|
|
|
|
photo_img_holder = document.getElementById("photo_img_holder");
|
|
|
|
photo_img = document.getElementById("photo_img");
|
2016-10-30 01:46:23 +00:00
|
|
|
function move_hoverzoom(event)
|
|
|
|
{
|
|
|
|
var x;
|
|
|
|
var y;
|
2016-12-21 05:33:14 +00:00
|
|
|
|
|
|
|
// 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.
|
2016-11-27 09:06:11 +00:00
|
|
|
var mouse_x = event.offsetX;
|
|
|
|
mouse_x -= (photo_img_holder.offsetWidth / 2);
|
|
|
|
mouse_x *= 1.05;
|
|
|
|
mouse_x += (photo_img_holder.offsetWidth / 2);
|
2016-12-21 05:33:14 +00:00
|
|
|
|
2016-11-27 09:06:11 +00:00
|
|
|
var mouse_y = event.offsetY;
|
|
|
|
mouse_y -= (photo_img_holder.offsetHeight / 2);
|
|
|
|
mouse_y *= 1.05;
|
|
|
|
mouse_y += (photo_img_holder.offsetHeight / 2);
|
2016-12-21 05:33:14 +00:00
|
|
|
|
2016-11-27 09:06:11 +00:00
|
|
|
if (photo_img.naturalWidth < photo_img_holder.offsetWidth)
|
2016-10-30 01:46:23 +00:00
|
|
|
{
|
2016-12-21 05:33:14 +00:00
|
|
|
// If the image is smaller than the frame, just center it
|
2016-11-27 09:06:11 +00:00
|
|
|
x = (photo_img.naturalWidth - photo_img_holder.offsetWidth) / 2;
|
2016-10-30 01:46:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-12-21 05:33:14 +00:00
|
|
|
// Take the amount of movement necessary (frame width - image width)
|
|
|
|
// times our distance across the image as a percentage.
|
2016-11-27 09:06:11 +00:00
|
|
|
x = (photo_img.naturalWidth - photo_img_holder.offsetWidth) * (mouse_x / photo_img_holder.offsetWidth);
|
2016-10-30 01:46:23 +00:00
|
|
|
}
|
2016-12-21 05:33:14 +00:00
|
|
|
|
2016-11-27 09:06:11 +00:00
|
|
|
if (photo_img.naturalHeight < photo_img_holder.offsetHeight)
|
2016-10-30 01:46:23 +00:00
|
|
|
{
|
2016-11-27 09:06:11 +00:00
|
|
|
y = (photo_img.naturalHeight - photo_img_holder.offsetHeight) / 2;
|
2016-10-30 01:46:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-11-27 09:06:11 +00:00
|
|
|
y = (photo_img.naturalHeight - photo_img_holder.offsetHeight) * (mouse_y / photo_img_holder.offsetHeight);
|
2016-10-30 01:46:23 +00:00
|
|
|
}
|
|
|
|
//console.log(x);
|
2016-11-27 09:06:11 +00:00
|
|
|
photo_img_holder.style.backgroundPosition=(-x)+"px "+(-y)+"px";
|
2016-10-30 01:46:23 +00:00
|
|
|
}
|
2017-02-25 06:07:59 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
);
|
2016-11-27 09:06:11 +00:00
|
|
|
</script>
|
|
|
|
</html>
|