Kováts Levente 402f21e5c6 Hibajavítások
escapeHtml, color parsing, képnéző betöltés/megjelenítés
2021-01-24 10:16:18 +01:00

782 lines
25 KiB
JavaScript

// megjelenítés / eltüntetés
function show(obj) {
o(obj).setAttribute("shown", "true");
}
function hide(obj) {
o(obj).setAttribute("shown", "false");
}
function toggle_show(obj) {
o(obj).setAttribute("shown", o(obj).getAttribute("shown") === "false");
}
function scroll_enable(on) {
document.body.style.overflowY = on ? "scroll" : "hidden";
}
function blur_page(blur) {
if (blur) {
show("blurlayer");
o("display").style.filter = "blur(10px)";
scroll_enable(false);
} else {
hide("blurlayer");
o("display").style.filter = "";
scroll_enable(true);
}
}
// -----------------------------------------
var slide_unit = 604;
var slider_id = "pupslider";
var upload_popup_id = "uploadpup";
var publish_btn_id = "publishbtn";
var image_uid = null;
var processing_busy = false; // feldolgozás folyamatban
function determine_sliding_unit() {
if (window.innerWidth > 600) { // számítógépes megjelenítés
slide_unit = 604;
} else { // mobilos megjelenítés
slide_unit = ((window.orientation % 90) === 0) ? window.innerWidth : window.innerHeight; // deprecated, de működik...
}
}
function pup_slide(units) {
slider_slide(slider_id, -slide_unit * units);
}
function pup_reset() {
hide(upload_popup_id); // ablak eltüntetése
reset_slider(slider_id); // slider visszaállítása
o(publish_btn_id).innerText = "Mehet!"; // gombfelirat visszaállítása
o("respchkbox").checked = false; // pipa kivétele
o("autocorrchkbox").checked = false;
// mezők törlése
o("author").value = "";
o("author_group").value = "";
o("imgtitle").value = "";
o("description").value = "";
o("fileselector").value = "";
}
// kép publikálása
function publish() {
if (processing_busy || image_uid == null) { // csak, ha érvényes...
return;
}
// mezők kinyerése
let author = o("author").value.trim();
let title = o("imgtitle").value.trim();
let desc = o("description").value.trim();
let autocorr = o("autocorrchkbox").checked;
let group = o("author_group").value.trim();
// ha a kötelező mezők nincsenek kitöltve, akkor nem lehet beküldeni
if (author.trim() === "" || title.trim() === "") {
alert("Alkotó és cím megadása kötelező!");
return;
}
// checkbox ellenőrzése
if (!o("respchkbox").checked) {
return;
}
// struktúra összeállítása
let details = {
uid: image_uid,
author: author,
title: title,
desc: desc,
autocorrect: autocorr,
group: group
}
// küldés
let formData = new FormData();
formData.append("action", "publish");
formData.append("details", JSON.stringify(details));
let req = new XMLHttpRequest();
req.onreadystatechange = state => {
if (req.status === 200 && req.readyState === 4) {
let close_if_needed = true;
if (Number(req.response) === 0) {
alert("Sikeres feltöltés!");
req_update(); // frissítés kérése
} else if (Number(req.response) === -1) {
alert("Ugyanezt képet már korábban feltöltötték!");
} else if (Number(req.response) === -2) {
alert("A megadott csoport nem létezik!");
close_if_needed = false; // nem kell bezárni, mert valószínűleg csak elírta
o("author_group").focus(); // fókuszálás a csoport mezőre
} else {
alert("Valami nem stimmel!\nHa ismételten nem sikerül, kérlek jelezd a hibát!");
}
// bezárás, ha szükséges
if (close_if_needed) {
// UID elfelejtése
image_uid = null;
// popup resetelése
close_upload_pup();
}
processing_busy = false;
o(publish_btn_id).innerText = "Mehet!";
}
};
req.open("POST", "interface.php");
req.send(formData);
// feldolgozás folyamatban
processing_busy = true;
o(publish_btn_id).innerHTML = "Türelem... <img src='media/loading.svg' height='16'>";
}
// feltöltés után kapott válasz feldolgozása
function process_upload_response(resp) {
if (/^[0-9a-zA-Z]+$/.test(resp)) { // ha random string a válasz, akkor kaptunk UID-t
image_uid = resp;
pup_slide(1); // előrelépés
} else { // ha negatív szám a válasz vagy egyébb szöveg, akkor hibás az eredmény
let resp_num = Number(resp);
switch (resp_num) {
case -1:
alert("Hiba a feldolgozás során!");
break;
case -2:
alert("A feltöltött fájl formátuma nem megfelelő, csak JPG- vagy PNG-képek elfogadottak!")
break;
case -3:
alert("Mérethiba: a kép hosszabb oldalának legalább 2000 pixel szélesnek kell lennie!");
break;
case -4:
alert("Elérted a feltöltési limitet.\nKérlek próbáld újra később!");
break;
default:
alert("Valami nem stimmel!\nHa ismételten nem sikerül, kérlek jelezd a hibát!");
break;
}
pup_slide(-1); // visszalépés
}
}
// fájl feltöltése
function upload_file(f) {
let formData = new FormData();
formData.append("image", f);
formData.append("action", "upload");
let req = new XMLHttpRequest();
req.onreadystatechange = state => {
if (req.status === 200 && req.readyState === 4) {
process_upload_response(req.response);
}
};
req.open("POST", "interface.php");
req.send(formData);
}
// feltöltés eszközről
function upload_from_device() {
let file_selector = o("fileselector");
if (file_selector.files.length > 0) {
pup_slide(1); // görgetés jobbra
upload_file(file_selector.files[0]);
}
}
// feltöltőablak megnyitása
function open_upload_pup() {
show(upload_popup_id);
blur_page(true);
o("fileselector").value = "";
}
// feltöltőablak bezárása
function close_upload_pup() {
hide(upload_popup_id);
blur_page(false);
pup_reset();
}
// -----------------
function async_req(action, cb, add_data = null) {
xhr = new XMLHttpRequest();
fd = new FormData();
fd.append("action", action);
xhr.onreadystatechange = state => {
if (xhr.status === 200 && xhr.readyState === 4 && cb != null) {
cb(state, xhr.response);
}
};
// további adatok hozzáfűzése a kéréshez
if (add_data != null) {
for (let prop in add_data) {
if (Object.prototype.hasOwnProperty.call(add_data, prop)) {
fd.append(prop, JSON.stringify(add_data[prop]));
}
}
}
xhr.open("POST", "interface.php");
xhr.send(fd)
}
var total_artwork_count = 0; // összes kép alkotás száma
var thumb_largest_side = 400; // a bélyegkép hosszabb oldala 400 pixel
var batch_loading_quantity = 10; // egyszerre betöltött képek mennyisége
var autoload_enabled = false; // automatikus betöltés
var artworks_loaded_n = 0; // ennyi kép van betöltve a megjelenítőbe
var thumbnail_padding = 8; // kép körüli margó
var extra_margin = 0; // extra margó, amire számítani kell a fal generálásakor
var last_uid = ""; // utolsó UID
var wall_height = 0; // a fal magassága, pixelben
var dynamic_load_distance = 200; // ennyi pixellel a fal alja előtt indítja a dinamikus betöltést
var dynamic_loading_under_way = false; // dinamikus töltés folyamatban, ne indítsunk új requestet
var update_interval = 10000; // automatikus frissítés 10 másodpercenként
var thumbnails = [];
// fotófal inicializálása
function init_photowall() {
scroll_enable(true);
determine_sliding_unit();
init_drag_and_drop();
req_general_info();
init_dynamic_loading();
init_viewer();
// újrakompozitálás átméretezés esetén
window.addEventListener("resize", () => {
compose_wall();
}, false);
window.addEventListener("orientationchange", (e) => {
determine_sliding_unit();
});
// automatikus frissítés
setInterval(() => {
req_update();
}, update_interval);
}
// inicializálási lánc
function req_general_info() {
async_req("general_info", recv_general_info);
}
function recv_general_info(state, resp) {
// általános adatok mentése
let resp_obj = JSON.parse(resp);
total_artwork_count = resp_obj["total_artwork_count"];
thumb_largest_side = resp_obj["thumb_largest_side"];
// első adag képe betöltése
req_batch();
}
// egy adag kép lekérése
function req_batch() {
async_req("batch", recv_batch, {offset: artworks_loaded_n, n: batch_loading_quantity});
}
function recv_batch(state, resp) {
let img_batch = JSON.parse(resp);
// utolsó UID mentése, ha most történt az első letöltés
if (artworks_loaded_n === 0) {
last_uid = img_batch[0].UID;
}
// betöltött művek számának növelése
artworks_loaded_n += img_batch.length;
// ha van még mit letölteni, akkor engedélyezzük az automatikus betöltést
autoload_enabled = total_artwork_count > artworks_loaded_n;
// újonnan kapott képek befűzése a lista ELEJÉRE!
thumbnails = thumbnails.concat(img_batch);
// fotófal összeállítása
compose_wall();
// ha nem töltődött be elég kép... VIGYÁZAT: rekurzív, mint állat!
if (wall_height < window.innerHeight && total_artwork_count > artworks_loaded_n) {
req_batch();
}
// töltés kész
dynamic_loading_under_way = false;
}
// fotófal összeállítása
function compose_wall() {
// görgetési pozíció mentése
let scroll_pos = window.scrollY;
// nézőfelület szélessége és magassága
let display = o("display");
display.innerHTML = ""; // fal törlése
wall_height = 0;
let width = display.clientWidth;
//let height = display.clientHeight;
// bélyegképek méreteinek meghatározása
for (let i = 0; i < thumbnails.length; i++) {
let thumbnail = thumbnails[i];
// ha kell, akkor kiszámoljuk a kép méretét
if (!(thumbnail.hasOwnProperty("width") && thumbnail.hasOwnProperty("height"))) {
let ar = Number(thumbnail["AspectRatio"]);
if (ar >= 1.0) { // a kép fekvő vagy négyzet, ezért a SZÉLESSÉG a nagyobb
thumbnail.width = thumb_largest_side;
thumbnail.height = thumb_largest_side / ar;
} else { // a kép álló, ezért a MAGASSÁG a nagyobb
thumbnail.height = thumb_largest_side;
thumbnail.width = thumb_largest_side * ar;
}
}
}
// sorok előállítása
let processed_n = 0;
let last_line_height = thumb_largest_side;
while (processed_n < artworks_loaded_n) { // amíg van még kép
// egy sornyi kép összegyűjtése
let total_width = 0;
let max_thumbnail_height = 0; // maximális bélyegkép-magasság
let line_entries = [];
let not_full_line = false; // nem teljes sor
for (let i = processed_n; i < artworks_loaded_n && total_width < width; i++) { // futtatás a lista végéig, vagy amíg be nem telik a sok
line_entries.push(thumbnails[i]); // hozzáadás a listához
// maximális hossz növelése
total_width += thumbnails[i].width;
// (1. lépés) maximális magasság keresése
max_thumbnail_height = thumbnails[i].height > max_thumbnail_height ? thumbnails[i].height : max_thumbnail_height;
// nem teljes sor jelzése
if ((i + 1) === artworks_loaded_n && total_width < width) {
not_full_line = true;
}
}
// 2. lépés: a maximális magasságnál kisebb képek felskálázása
let total_scaled_width = 0;
for (let i = 0; i < line_entries.length; i++) {
let thumbnail = line_entries[i];
// skálafaktor
let K = max_thumbnail_height / thumbnail.height;
thumbnail.scale_factor = K;
// skálázott méret kiszámítása
thumbnail.scaledHeight = thumbnail.height * K;
thumbnail.scaledWidth = thumbnail.width * K;
total_scaled_width += thumbnail.scaledWidth;
}
// 3. lépés: visszaskálázás a sor hosszára
let summed_padding = (line_entries.length + 1) * thumbnail_padding + extra_margin; // sorhossz kiszámítása margókkal együtt
// a képeknek az ablakszélesség-összes margó helyre be kell férni, ezért:
let k = (width - summed_padding) / total_scaled_width;
for (let i = 0; i < line_entries.length; i++) {
line_entries[i].scale_factor *= k;
line_entries[i].scale_factor = Math.round(line_entries[i].scale_factor * 1000) / 1000; // kerekítés ezredekre
}
// képek elhelyzése
for (let i = 0; i < line_entries.length; i++) {
// méret kiszámítása
let thumb_width = line_entries[i].width * line_entries[i].scale_factor;
let thumb_height = line_entries[i].height * line_entries[i].scale_factor;
// ha a sor nem teljes, és a képek az utolsó teljes sor magasságánál nagyobbak lennének, akkor visszaskálázunk
if (not_full_line) {
if (thumb_height > last_line_height) {
let s = last_line_height / thumb_height;
thumb_width *= s;
thumb_height *= s;
}
}
// képet tároló elem
let container_section = document.createElement("section");
container_section.style.backgroundColor = line_entries[i].ColorMean;
container_section.classList.add("thumbnail-container");
// a bélyegkép
let img = document.createElement("img");
img.classList.add("thumbnail");
container_section.style.width = img.style.width = `${thumb_width}px`;
container_section.style.height = img.style.height = `${thumb_height}px`;
img.src = `ARTWORKS/thumbnails/${line_entries[i].Image_FileName}`;
img.addEventListener("load", (e) => {
img.style.opacity = "1";
}, false);
img.details = line_entries[i];
img.addEventListener("click", (e) => {
open_viewer(img.details);
}, false);
// kép címe
let title_span = document.createElement("span");
title_span.classList.add("thumb-title");
title_span.innerText = line_entries[i].Title;
// sáv színének igazítása a kép domináns színéhez
let title_bgcolor = new Color();
title_bgcolor.from_cssrgb(line_entries[i].ColorMean);
//title_bgcolor.mul(0.8);
title_bgcolor.a = 0.6;
title_span.style.backgroundColor = title_bgcolor.to_rgba();
container_section.appendChild(img);
container_section.appendChild(title_span);
display.appendChild(container_section);
}
// falmagasság számítása
let thumbnail_height = max_thumbnail_height * k;
wall_height += 2 * thumbnail_padding + thumbnail_height;
// feldolgozottság léptetése
processed_n += line_entries.length;
// falmagasság mentése
last_line_height = thumbnail_height;
}
// görgetés oda, ahol eredetileg álltunk
window.scrollTo(0, scroll_pos);
}
// frissítés folyamatban
var update_in_progress = false;
// frissítés lekérése
function req_update() {
if (!update_in_progress) {
update_in_progress = true;
async_req("update", recv_update, {last_uid: last_uid});
}}
// frissítés fogadása
function recv_update(state, resp) {
let img_update_batch = JSON.parse(resp);
// ha nem volt semmi újabb, akkor kilépünk
if (img_update_batch.length === 0) {
return;
}
// növeljük az összes és a betöltött művek számát
artworks_loaded_n += img_update_batch.length;
total_artwork_count += img_update_batch.length;
// ha van még mit letölteni, akkor engedélyezzük az automatikus betöltést
autoload_enabled = total_artwork_count > artworks_loaded_n;
// újonnan kapott képek befűzése a lista ELEJÉRE!
thumbnails = img_update_batch.concat(thumbnails);
// utolsó UID mentése
last_uid = thumbnails[0].UID;
// fal összeállítása
compose_wall();
// update kész
update_in_progress = false;
}
// DnD inicializálása
function init_drag_and_drop() {
let drop_area = o("uploadtype");
drop_area.addEventListener("dragover", (e) => {
e.stopPropagation();
e.preventDefault();
}, false);
drop_area.addEventListener("drop", (e) => {
e.stopPropagation();
e.preventDefault();
if (e.dataTransfer.files.length > 0) {
pup_slide(1);
upload_file(e.dataTransfer.files[0]);
}
}, false);
}
// dinamikus betöltés inicializálása
function init_dynamic_loading() {
document.addEventListener("scroll", (e) => {
if (autoload_enabled && !dynamic_loading_under_way) { // ha az automatikus töltés engedélyezett
if (window.scrollY + window.innerHeight > wall_height - dynamic_load_distance) {
dynamic_loading_under_way = true;
req_batch();
}
}
}, false);
}
var magnification_sensitivity = 0.05; // nagyítási érzékenység, skálafaktor a görgetés mértékére
var touch_magnification_sensitivity = 0.01; // nagyítási érzékenység érintőképernyő esetén
var viewer_original_mouse_coords = {x: 0, y: 0}; // egér indulópozíciója a kép mozgatásakor
var viewer_original_offset_coords = {x: 0, y: 0}; // mozgatás kezdeti offset
var viewer_grabbing = false; // mozgatják épp a képet?
var last_touch_distance = 0; // előző érintési távolság
// képnézegető inicializálása
function init_viewer() {
let img = o("viewerimg");
let caption_sect = o("artcaptions");
// betöltéskor a felirat megjelenítése
img.addEventListener("load", (e) => {
img.classList.remove("loading");
place_artcaptions();
show(caption_sect);
hide("viewerloadanim");
}, false);
window.addEventListener("resize", (e) => {
change_viewer_magnification(1, true);
change_viewer_offset({ x: 0, y: 0 }, true);
setTimeout(() => {
place_artcaptions();
}, 400);
}, false);
img.addEventListener("wheel", (e) => {
change_viewer_magnification(-e.deltaY * magnification_sensitivity);
}, false);
// a képre kattintáskor ne záródjon be a nézegető
img.addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
return false;
}, false);
// nézegető billentyű-kombinációk
window.addEventListener("keyup", (e) => {
switch (e.key) {
case "Escape":
close_viewer();
break;
}
}, false);
// kép mozgatása
img.addEventListener("mousedown", (e) => {
viewer_original_offset_coords = img.offset;
viewer_original_mouse_coords = {x: e.clientX, y: e.clientY};
viewer_grabbing = true;
img.style.cursor = "grabbing";
}, false);
img.addEventListener("mousemove", (e) => {
if (viewer_grabbing) {
let offset = {
x: e.clientX - viewer_original_mouse_coords.x + viewer_original_offset_coords.x,
y: e.clientY - viewer_original_mouse_coords.y + viewer_original_offset_coords.y
};
change_viewer_offset(offset, true);
}
}, false);
let end_grab = (e) => {
viewer_grabbing = false;
img.style.cursor = "grab";
};
img.addEventListener("mouseup", end_grab, false);
img.addEventListener("mouseleave", end_grab, false);
img.addEventListener("touchstart", (e) => {
let t = e.touches;
viewer_original_offset_coords = img.offset;
viewer_original_mouse_coords = { x: t[0].screenX, y: t[0].screenY };
viewer_grabbing = true;
last_touch_distance = 0;
}, false);
img.addEventListener("touchmove", (e) => {
let t = e.touches;
if (t.length >= 2) {
let d = Math.sqrt((t[0].screenX - t[1].screenX) * (t[0].screenX - t[1].screenX) + (t[0].screenY - t[1].screenY) * (t[0].screenY - t[1].screenY));
// TODO szűrés
let d_filtered = d;
// nagyítás
if (last_touch_distance !== 0) {
change_viewer_magnification(touch_magnification_sensitivity * (d_filtered - last_touch_distance));
}
last_touch_distance = d_filtered;
} else if (t.length === 1) {
if (viewer_grabbing) {
let offset = {
x: t[0].screenX - viewer_original_mouse_coords.x + viewer_original_offset_coords.x,
y: t[0].screenY - viewer_original_mouse_coords.y + viewer_original_offset_coords.y
};
change_viewer_offset(offset, true);
}
}
}, false);
img.addEventListener("touchend", (e) => {
viewer_grabbing = false;
}, false);
}
// feliratok elhelyezése
function place_artcaptions() {
let img = o("viewerimg");
let caption_sect = o("artcaptions");
let brect = img.getBoundingClientRect();
caption_sect.style.left = brect.x + "px";
caption_sect.style.width = img.clientWidth + "px";
}
var viewer_open = false;
var group_logo_repository = "https://mkkozi.hu/user/plugins/mkk-groups/logos";
// képnézegető megynitása
function open_viewer(details) {
let img = o("viewerimg");
img.classList.add("loading");
img.style.left = img.style.top = "0px";
img.src = "ARTWORKS/published/" + details.Image_FileName;
// feliratok kiírása
o("arttitle").innerText = details.Title;
o("artauthor").innerText = details.Author;
o("artdesc").innerText = details.Description;
// feliratcsík háttérszínének meghatározása a domináns szín alapján
/*let captions_bgcolor = new Color();
captions_bgcolor.from_cssrgb(details.ColorMean);
captions_bgcolor.a = 0.6;
o("artcaptions").style.backgroundColor = captions_bgcolor.to_rgba();*/
// csoportlogó megjelenítése
let glogo = document.createElement("img");
glogo.src = `${group_logo_repository}/${details.AuthorGroup}.png`;
glogo.alt = `(${details.AuthorGroup})`;
glogo.classList.add("art-author-group");
o("artauthor").appendChild(glogo);
// nézegető visszaállítása
change_viewer_magnification(1.0, true);
change_viewer_offset({x: 0, y: 0}, true);
// ...
scroll_enable(false);
show("viewerloadanim");
show("viewersect");
viewer_open = true;
}
// képnézegető bezárása
function close_viewer() {
scroll_enable(true);
hide("viewersect");
hide("artcaptions");
// kép eltávolítása
let img = o("viewerimg");
img.src = "";
viewer_open = false;
}
// kép nagyítása a képnézegetőben
function change_viewer_magnification(c, absolute = false) {
let img = o("viewerimg");
// ha nagyítás mezője a képnek, akkor most létrehozzuk
if (!img.hasOwnProperty("magnification")) {
img.magnification = 1.0;
}
// nagyítás értékének meghatározása
img.magnification = Math.min(Math.max(1.0, absolute ? c : (img.magnification + c)), 5.0);
// visszaírás
img.style.transform = `scale(${img.magnification})`;
}
// kép helyének megváltoztatása
function change_viewer_offset(offset, absolute = false) {
let img = o("viewerimg");
// ha nincs eltolás mezője a képnek, akkor most létrehozzuk
if (!img.hasOwnProperty("offset")) {
img.offset = {x: 0, y: 0};
}
// az eltolás értékének meghatározása
img.offset = absolute ? offset : ({x: img.offset.x + offset.x, y: img.offset.y + offset.y})
// visszaírás
img.style.left = img.offset.x + "px";
img.style.top = img.offset.y + "px";
}
// üdvözlőüzenet megnyitása
function open_welcome_msg() {
show("welcomepup");
blur_page(true);
}
// üdvözlőüzenet eltüntetése
function hide_welcome_msg() {
hide("welcomepup");
blur_page(false);
}
// üdvözlőüzenet OK-gomb
function confirm_welcome_msg() {
hide_welcome_msg();
// süti mentése
let d = new Date();
d.setTime(d.getTime() + (7*24*3600*1000));
document.cookie = `phw_welcome_confirmed=1; expires=${d.toUTCString()}; path=/;`;
}