Add UX to note people in pictures.

This commit is contained in:
Rasmus Kaj 2017-11-10 19:26:39 +01:00
parent 328074c0b6
commit 884ffe7e02
3 changed files with 128 additions and 48 deletions

View File

@ -31,11 +31,12 @@ function rpadmin() {
var list;
function tag_form(event) {
function tag_form(event, category) {
event.target.disabled = true;
var imgid = details.dataset.imgid;
var f = document.createElement("form");
f.action = "/adm/tag";
f.className = category;
f.action = "/adm/" + category;
f.method = "post";
var i = document.createElement("input");
i.type="hidden";
@ -46,8 +47,43 @@ function rpadmin() {
i.type = "text";
i.autocomplete="off";
i.tabindex="1";
i.name = "tag";
i.addEventListener('keyup', do_complete);
i.name = category;
i.addEventListener('keyup', e => {
let c = e.code;
if (c == 'ArrowUp' || c == 'ArrowDown' || c == 'Escape' || c == 'Enter') {
return true;
}
let i = e.target, v = i.value;
if (v.length > 0) {
let r = new XMLHttpRequest();
r.onload = function() {
let t = JSON.parse(this.responseText);
list.innerHTML = '';
t.map(x => {
let a = document.createElement('a');
a.innerHTML = x;
a.tabIndex = 2;
a.href = "#";
a.onclick = function(e) {
i.value = x;
list.innerHTML = '';
i.focus();
e.preventDefault();
e.stopPropagation();
return true;
}
list.appendChild(a)
})
};
r.open('GET', document.location.origin + '/ac/' + category + '?q=' + encodeURIComponent(v));
r.send(null);
} else {
list.innerHTML = '';
}
e.preventDefault();
e.stopPropagation();
return false;
});
f.appendChild(i);
list = document.createElement("div");
list.className = "completions";
@ -76,43 +112,6 @@ function rpadmin() {
i.focus();
}
function do_complete(e) {
let c = e.code;
if (c == 'ArrowUp' || c == 'ArrowDown' || c == 'Escape' || c == 'Enter') {
return true;
}
let i = e.target, v = i.value;
if (v.length > 0) {
let r = new XMLHttpRequest();
r.onload = function() {
let t = JSON.parse(this.responseText);
list.innerHTML = '';
t.map(x => {
let a = document.createElement('a');
a.innerHTML = x;
a.tabIndex = 2;
a.href = "#";
a.onclick = function(e) {
i.value = x;
list.innerHTML = '';
i.focus();
e.preventDefault();
e.stopPropagation();
return true;
}
list.appendChild(a)
})
};
r.open('GET', document.location.origin + '/ac?q=' + encodeURIComponent(v));
r.send(null);
} else {
list.innerHTML = '';
}
e.preventDefault();
e.stopPropagation();
return false;
}
var meta = details.querySelector('.meta');
if (meta) {
p = document.createElement("p");
@ -132,11 +131,19 @@ function rpadmin() {
p.appendChild(document.createTextNode(" "));
r = document.createElement("button");
r.onclick = tag_form;
r.onclick = e => tag_form(e, 'tag');
r.innerHTML = "🏷";
r.title = "Tag photo";
r.accessKey = "T";
p.appendChild(r);
p.appendChild(document.createTextNode(" "));
r = document.createElement("button");
r.onclick = e => tag_form(e, 'person');
r.innerHTML = "\u263a";
r.title = "Person in picture";
r.accessKey = "P";
p.appendChild(r);
meta.appendChild(p);
}
}

View File

@ -51,7 +51,7 @@ fn rotate_params(req: &mut Request) -> QResult<(Option<i32>, Option<i16>)> {
))
}
pub fn tag<'mw>(
pub fn set_tag<'mw>(
req: &mut Request,
res: Response<'mw>,
) -> MiddlewareResult<'mw> {
@ -101,6 +101,59 @@ fn tag_params(req: &mut Request) -> QResult<(Option<i32>, Option<String>)> {
))
}
pub fn set_person<'mw>(
req: &mut Request,
res: Response<'mw>,
) -> MiddlewareResult<'mw> {
if !req.authorized_user().is_some() {
return res.error(StatusCode::Unauthorized, "permission denied");
}
if let (Some(image), Some(name)) = try_with!(res, person_params(req)) {
let c: &PgConnection = &req.db_conn();
use diesel;
use models::{NewPerson, NewPhotoPerson, Person, PhotoPerson};
let person = {
use schema::people::dsl::*;
people
.filter(person_name.ilike(&name))
.first::<Person>(c)
.or_else(|_| {
diesel::insert(&NewPerson {
person_name: &name,
slug: &slugify(&name),
}).into(people)
.get_result::<Person>(c)
})
.expect("Find or create tag")
};
use schema::photo_people::dsl::*;
let q = photo_people
.filter(photo_id.eq(image))
.filter(person_id.eq(person.id));
if q.first::<PhotoPerson>(c).is_ok() {
info!("Photo #{} already has {:?}", image, person);
} else {
info!("Add {:?} on photo #{}!", person, image);
diesel::insert(
&NewPhotoPerson { photo_id: image, person_id: person.id },
).into(photo_people)
.execute(c)
.expect("Name person in photo");
}
return res.redirect(format!("/img/{}", image));
}
info!("Missing image and/or angle to rotate or image not found");
res.not_found("")
}
fn person_params(req: &mut Request) -> QResult<(Option<i32>, Option<String>)> {
let data = req.form_body()?;
Ok((
data.get("image").and_then(|s| s.parse().ok()),
data.get("person").map(String::from),
))
}
pub fn slugify(val: &str) -> String {
val.chars()
.map(|c| match c {

View File

@ -33,6 +33,7 @@ use photosdirmiddleware::{PhotosDirMiddleware, PhotosDirRequestExtensions};
use memcachemiddleware::*;
use pidfiles::handle_pid_file;
use rustc_serialize::json::ToJson;
use templates;
use self::nickelext::{FromSlug, MyResponse, far_expires};
@ -74,10 +75,12 @@ pub fn run(args: &ArgMatches) -> Result<(), Error> {
wrap3!(server.post "/login", do_login);
wrap3!(server.get "/logout", logout);
wrap3!(server.get "/", all_years);
use self::admin::{rotate, tag};
wrap3!(server.get "/ac", auto_complete);
use self::admin::{rotate, set_person, set_tag};
wrap3!(server.get "/ac/tag", auto_complete_tag);
wrap3!(server.get "/ac/person", auto_complete_person);
wrap3!(server.post "/adm/rotate", rotate);
wrap3!(server.post "/adm/tag", tag);
wrap3!(server.post "/adm/tag", set_tag);
wrap3!(server.post "/adm/person", set_person);
wrap3!(server.get "/img/{}[-]{}\\.jpg", show_image: id, size);
wrap3!(server.get "/img/{}", photo_details: id);
wrap3!(server.get "/tag/", tag_all);
@ -609,12 +612,11 @@ impl Link {
}
}
fn auto_complete<'mw>(
fn auto_complete_tag<'mw>(
req: &mut Request,
res: Response<'mw>,
) -> MiddlewareResult<'mw> {
if let Some(q) = req.query().get("q").map(String::from) {
use rustc_serialize::json::ToJson;
use schema::tags::dsl::{tag_name, tags};
let c: &PgConnection = &req.db_conn();
let q = tags.select(tag_name)
@ -626,3 +628,21 @@ fn auto_complete<'mw>(
res.not_found("No such tag")
}
}
fn auto_complete_person<'mw>(
req: &mut Request,
res: Response<'mw>,
) -> MiddlewareResult<'mw> {
if let Some(q) = req.query().get("q").map(String::from) {
use schema::people::dsl::{people, person_name};
let c: &PgConnection = &req.db_conn();
let q = people
.select(person_name)
.filter(person_name.ilike(q + "%"))
.order(person_name)
.limit(15);
res.send(q.load::<String>(c).unwrap().to_json())
} else {
res.not_found("No such tag")
}
}