123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985 |
- /*
- Global functions
- */
- function htmlspecialchars(str){
- var map = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": '''
- }
- return str.replace(/[&<>"']/g, function(m){return map[m];});
- }
- function htmlspecialchars_decode(str){
-
- var map = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- ''': "'"
- }
-
- return str.replace(/&|<|>|"|'/g, function(m){return map[m];});
- }
- function is_click_within(elem, classname, is_id = false){
-
- while(true){
-
- if(elem === null){
-
- return false;
- }
-
- if(
- (
- is_id === false &&
- elem.className == classname
- ) ||
- (
- is_id === true &&
- elem.id == classname
- )
- ){
-
- return elem;
- }
-
- elem = elem.parentElement;
- }
- }
- /*
- Prevent GET parameter pollution
- */
- var form = document.getElementsByTagName("form");
- if(
- form.length !== 0 &&
- window.location.pathname != "/" &&
- window.location.pathname != "/settings.php" &&
- window.location.pathname != "/settings"
- ){
- form = form[0];
-
- var scraper_dropdown = document.getElementsByName("scraper")[0];
-
- scraper_dropdown.addEventListener("change", function(choice){
-
- submit(form);
- });
-
- form.addEventListener("submit", function(e){
-
- e.preventDefault();
- submit(e.srcElement);
- });
- }
- function submit(e){
-
- var GET = "";
- var first = true;
-
- if((s = document.getElementsByName("s")).length !== 0){
-
- GET += "?s=" + encodeURIComponent(s[0].value).replaceAll("%20", "+");
- first = false;
- }
-
- Array.from(
- e.getElementsByTagName("select")
- ).concat(
- Array.from(
- e.getElementsByTagName("input")
- )
- ).forEach(function(el){
-
- var firstelem = el.getElementsByTagName("option");
-
- if(
- (
- (
- firstelem.length === 0 ||
- firstelem[0].value != el.value
- ) &&
- el.name != "" &&
- el.value != "" &&
- el.name != "s"
- ) ||
- el.name == "scraper" ||
- el.name == "nsfw"
- ){
-
- if(first){
-
- GET += "?";
- first = false;
- }else{
-
- GET += "&";
- }
-
- GET += encodeURIComponent(el.name).replaceAll("%20", "+") + "=" + encodeURIComponent(el.value).replaceAll("%20", "+");
- }
- });
-
- window.location.href = GET;
- }
- /*
- Hide show more button when it's not needed on answers
- */
- var answer_div = document.getElementsByClassName("answer");
- if(answer_div.length !== 0){
- answer_div = Array.from(answer_div);
- var spoiler_button_div = Array.from(document.getElementsByClassName("spoiler-button"));
- // execute on pageload
- hide_show_more();
- window.addEventListener("resize", hide_show_more);
- function hide_show_more(){
-
- var height = window.innerWidth >= 1000 ? 600 : 200;
-
- for(i=0; i<answer_div.length; i++){
-
- if(answer_div[i].scrollHeight < height){
-
- spoiler_button_div[i].style.display = "none";
-
- document.getElementById(spoiler_button_div[i].htmlFor).checked = true;
- }else{
-
- spoiler_button_div[i].style.display = "block";
- }
- }
- }
- }
- switch(document.location.pathname){
-
- case "/web":
- case "/web.php":
- var image_class = "image";
- break;
-
- case "/images":
- case "/images.php":
- var image_class = "thumb";
- break;
-
- default:
- var image_class = null;
- }
- if(image_class !== null){
-
- /*
- Add popup to document
- */
- var popup_bg = document.createElement("div");
- popup_bg.id = "popup-bg";
- document.body.appendChild(popup_bg);
-
- // enable/disable pointer events
- if(!document.cookie.includes("bg_noclick=yes")){
-
- popup_bg.style.pointerEvents = "none";
- }
-
- var popup_status = document.createElement("div");
- popup_status.id = "popup-status";
- document.body.appendChild(popup_status);
-
- var popup_body = document.createElement("div");
- popup_body.id = "popup";
- document.body.appendChild(popup_body);
-
- // import popup
- var popup_body = document.getElementById("popup");
- var popup_status = document.getElementById("popup-status");
- var popup_image = null; // is set later on popup click
-
- // image metadata
- var collection = []; // will contain width, height, image URL
- var collection_index = 0;
-
- // event handling helper variables
- var is_popup_shown = false;
- var mouse_down = false;
- var mouse_move = false;
- var move_x = 0;
- var move_y = 0;
- var target_is_popup = false;
- var mirror_x = false;
- var mirror_y = false;
- var rotation = 0;
-
- /*
- Image dragging (mousedown)
- */
- document.addEventListener("mousedown", function(div){
-
- if(div.buttons !== 1){
-
- return;
- }
-
- mouse_down = true;
- mouse_move = false;
-
- if(is_click_within(div.target, "popup", true) === false){
-
- target_is_popup = false;
- }else{
- target_is_popup = true;
-
- var pos = popup_body.getBoundingClientRect();
- move_x = div.x - pos.x;
- move_y = div.y - pos.y;
- }
- });
-
- /*
- Image dragging (mousemove)
- */
- document.addEventListener("mousemove", function(pos){
-
- if(
- target_is_popup &&
- mouse_down
- ){
-
- mouse_move = true;
- movepopup(popup_body, pos.clientX - move_x, pos.clientY - move_y);
- }
- });
-
- /*
- Image dragging (mouseup)
- */
- document.addEventListener("mouseup", function(){
-
- mouse_down = false;
- });
-
- /*
- Image popup open
- */
- document.addEventListener("click", function(click){
-
- // should our click trigger image open?
- if(
- elem = is_click_within(click.target, image_class) ||
- click.target.classList.contains("openimg")
- ){
-
- event.preventDefault();
- is_popup_shown = true;
-
- // reset position params
- mirror_x = false;
- mirror_y = false;
- rotation = 0;
- scale = 60;
- collection_index = 0;
-
- // get popup data
- if(elem === true){
- // we clicked a simple image preview
- elem = click.target;
- var image_url = elem.getAttribute("src");
-
- if(image_url.startsWith("/proxy")){
-
- var match = image_url.match(/i=([^&]+)/);
-
- if(match !== null){
-
- image_url = decodeURIComponent(match[1]);
- }
- }else{
-
- image_url = htmlspecialchars_decode(image_url);
- }
-
- var w = Math.round(click.target.naturalWidth);
- var h = Math.round(click.target.naturalHeight);
-
- if(
- w === 0 ||
- h === 0
- ){
-
- w = 100;
- h = 100;
- }
-
- collection = [
- {
- "url": image_url,
- "width": w,
- "height": h
- }
- ];
-
- var title = "No description provided";
-
- if(click.target.title != ""){
-
- title = click.target.title;
- }else{
-
- if(click.target.alt != ""){
-
- title = click.target.alt;
- }
- }
- }else{
-
- if(image_class == "thumb"){
- // we're inside image.php
-
- elem =
- elem
- .parentElement
- .parentElement;
-
- var image_url = elem.getElementsByTagName("a")[1].href;
- }else{
-
- // we're inside web.php
- var image_url = elem.href;
- }
-
- collection =
- JSON.parse(
- elem.getAttribute("data-json")
- );
-
- var imagesize = elem.getElementsByTagName("img")[0];
-
- var imagesize_w = 0;
- var imagesize_h = 0;
-
- if(imagesize.complete){
-
- imagesize_w = imagesize.naturalWidth;
- imagesize_h = imagesize.naturalHeight;
- }
-
- if(
- imagesize_w === 0 ||
- imagesize_h === 0
- ){
-
- imagesize_w = 100;
- imagesize_h = 100;
- }
-
- for(var i=0; i<collection.length; i++){
-
- if(collection[i].width === null){
-
- collection[i].width = imagesize_w;
- collection[i].height = imagesize_h;
- }
- }
-
- var title = elem.title;
- }
-
- // prepare HTML
- var html =
- '<div id="popup-num">(' + collection.length + ')</div>' +
- '<div id="popup-dropdown">' +
- '<select name="viewer-res" onchange="changeimage(event)">';
-
- for(i=0; i<collection.length; i++){
-
- if(collection[i].url.startsWith("data:")){
-
- var domain = "<Base64 Data>";
- }else{
-
- var domain = new URL(collection[i].url).hostname;
- }
-
- html += '<option value="' + i + '">' + '(' + collection[i].width + 'x' + collection[i].height + ') ' + domain + '</option>';
- }
-
- popup_status.innerHTML =
- html + '</select></div>' +
- '<a href="' + htmlspecialchars(image_url) + '" rel="noreferrer nofollow "id="popup-title">' + htmlspecialchars(title) + '</a>';
-
- popup_body.innerHTML =
- '<img src="' + getproxylink(collection[0].url) + '" draggable="false" id="popup-image">';
-
- // make changes to DOM
- popup_body.style.display = "block";
- popup_bg.style.display = "block";
- popup_status.style.display = "table";
-
- // store for rotation functions & changeimage()
- popup_image = document.getElementById("popup-image");
-
- scalepopup(collection[collection_index], scale);
- centerpopup();
- }else{
-
- // click inside the image viewer
- // resize image
- if(is_click_within(click.target, "popup", true)){
-
- if(mouse_move === false){
- scale = 80;
- scalepopup(collection[collection_index], scale);
- centerpopup();
- }
- }else{
-
- if(is_click_within(click.target, "popup-status", true) === false){
-
- // click outside the popup while its open
- // close it
- if(is_popup_shown){
-
- hidepopup();
- }
- }
- }
- }
- });
-
- /*
- Scale image viewer
- */
- popup_body.addEventListener("wheel", function(scroll){
-
- event.preventDefault();
-
- if(
- scroll.altKey ||
- scroll.ctrlKey ||
- scroll.shiftKey
- ){
-
- var increment = 7;
- }else{
-
- var increment = 14;
- }
-
- if(scroll.wheelDelta > 0){
-
- // scrolling up
- scale = scale + increment;
- }else{
-
- // scrolling down
- if(scale - increment > 7){
- scale = scale - increment;
- }
- }
-
- // calculate relative size before scroll
- var pos = popup_body.getBoundingClientRect();
- var x = (scroll.x - pos.x) / pos.width;
- var y = (scroll.y - pos.y) / pos.height;
-
- scalepopup(collection[collection_index], scale);
-
- // move popup to % we found
- pos = popup_body.getBoundingClientRect();
-
- movepopup(
- popup_body,
- scroll.clientX - (x * pos.width),
- scroll.clientY - (y * pos.height)
- );
- });
-
- /*
- Keyboard controls
- */
-
- document.addEventListener("keydown", function(key){
-
- // close popup
- if(
- is_popup_shown &&
- key.keyCode === 27
- ){
-
- hidepopup();
- return;
- }
-
- if(is_popup_shown === false){
-
- return;
- }
-
- if(
- key.altKey ||
- key.ctrlKey ||
- key.shiftKey
- ){
-
- // mirror image
- switch(key.keyCode){
-
- case 37:
- // left
- key.preventDefault();
- mirror_x = true;
- break;
-
- case 38:
- // up
- key.preventDefault();
- mirror_y = false;
- break;
-
- case 39:
- // right
- key.preventDefault();
- mirror_x = false;
- break;
-
- case 40:
- // down
- key.preventDefault();
- mirror_y = true;
- break;
- }
- }else{
-
- // rotate image
- switch(key.keyCode){
-
- case 37:
- // left
- key.preventDefault();
- rotation = -90;
- break;
-
- case 38:
- // up
- key.preventDefault();
- rotation = 0;
- break;
-
- case 39:
- // right
- key.preventDefault();
- rotation = 90;
- break;
-
- case 40:
- // down
- key.preventDefault();
- rotation = -180;
- break;
- }
- }
-
- popup_image.style.transform =
- "scale(" +
- (mirror_x ? "-1" : "1") +
- ", " +
- (mirror_y ? "-1" : "1") +
- ") " +
- "rotate(" +
- rotation + "deg" +
- ")";
- });
- }
- function getproxylink(url){
-
- if(url.startsWith("data:")){
-
- return htmlspecialchars(url);
- }else{
-
- return '/proxy?i=' + encodeURIComponent(url);
- }
- }
- function hidepopup(){
-
- is_popup_shown = false;
- popup_status.style.display = "none";
- popup_body.style.display = "none";
- popup_bg.style.display = "none";
- }
- function scalepopup(size, scale){
-
- var ratio =
- Math.min(
- (window.innerWidth * (scale / 100)) / collection[collection_index].width, (window.innerHeight * (scale / 100)) / collection[collection_index].height
- );
-
- popup_body.style.width = size.width * ratio + "px";
- popup_body.style.height = size.height * ratio + "px";
- }
- function centerpopup(){
-
- var size = popup_body.getBoundingClientRect();
- var size = {
- "width": parseInt(size.width),
- "height": parseInt(size.height)
- };
-
- movepopup(
- popup_body,
- (window.innerWidth / 2) - (size.width / 2),
- (window.innerHeight / 2) - (size.height / 2)
- );
- }
- function movepopup(popup_body, x, y){
-
- popup_body.style.left = x + "px";
- popup_body.style.top = y + "px";
- }
- function changeimage(event){
-
- // reset rotation params
- mirror_x = false;
- mirror_y = false;
- rotation = 0;
-
- scale = 60;
-
- collection_index = parseInt(event.target.value);
-
- // we set innerHTML otherwise old image lingers a little
- popup_body.innerHTML =
- '<img src="' + getproxylink(collection[collection_index].url) + '" draggable="false" id="popup-image">';
-
- // store for rotation functions & changeimage()
- popup_image = document.getElementById("popup-image");
-
- scalepopup(collection[collection_index], scale);
- centerpopup();
- }
- var searchbox_wrapper = document.getElementsByClassName("searchbox");
- if(searchbox_wrapper.length !== 0){
-
- searchbox_wrapper = searchbox_wrapper[0];
- var searchbox = searchbox_wrapper.getElementsByTagName("input")[1];
-
- /*
- Textarea shortcuts
- */
- document.addEventListener("keydown", function(key){
-
- switch(key.keyCode){
-
- case 191:
- // 191 = /
- if(document.activeElement.tagName == "INPUT"){
-
- // already focused, ignore
- break;
- }
-
- if(
- typeof is_popup_shown != "undefined" &&
- is_popup_shown
- ){
-
- hidepopup();
- }
-
- window.scrollTo(0, 0);
- searchbox.focus();
- key.preventDefault();
- break;
- }
- });
-
- /*
- Autocompleter
- */
- if( // make sure the user wants it
- document.cookie.includes("scraper_ac=") &&
- document.cookie.includes("scraper_ac=disabled") === false
- ){
-
- var autocomplete_cache = [];
- var focuspos = -1;
- var list = [];
- var autocomplete_div = document.getElementsByClassName("autocomplete")[0];
-
- if(
- document.cookie.includes("scraper_ac=auto") &&
- typeof scraper_dropdown != "undefined"
- ){
-
- var ac_req_appendix = "&scraper=" + scraper_dropdown.value;
- }else{
-
- var ac_req_appendix = "";
- }
-
- function getsearchboxtext(){
-
- var value =
- searchbox.value
- .trim()
- .replace(
- / +/g,
- " "
- )
- .toLowerCase();
-
- return value;
- }
-
- searchbox.addEventListener("input", async function(){
-
- // ratelimit on input only
- // dont ratelimit if we already have res
- if(typeof autocomplete_cache[getsearchboxtext()] != "undefined"){
-
- await getac();
- }else{
-
- await getac_ratelimit();
- }
- });
-
- async function getac(){
-
- var curvalue = getsearchboxtext();
-
- if(curvalue == ""){
-
- // hide autocompleter
- autocomplete_div.style.display = "none";
- return;
- }
-
- if(typeof autocomplete_cache[curvalue] == "undefined"){
-
- /*
- Fetch autocomplete
- */
- // make sure we dont fetch same thing twice
- autocomplete_cache[curvalue] = [];
-
- var res = await fetch("/api/v1/ac?s=" + (encodeURIComponent(curvalue).replaceAll("%20", "+")) + ac_req_appendix);
- if(!res.ok){
-
- return;
- }
-
- var json = await res.json();
-
- autocomplete_cache[curvalue] = json[1];
-
- if(curvalue == getsearchboxtext()){
-
- render_ac(curvalue, autocomplete_cache[curvalue]);
- }
- return;
- }
-
- render_ac(curvalue, autocomplete_cache[curvalue]);
- }
-
- var ac_func = null;
- function getac_ratelimit(){
-
- return new Promise(async function(resolve, reject){
-
- if(ac_func !== null){
-
- clearTimeout(ac_func);
- }//else{
-
- // no ratelimits
- //getac();
- //}
-
- ac_func =
- setTimeout(function(){
-
- ac_func = null;
- getac(); // get results after 100ms of no keystroke
- resolve();
- }, 200);
- });
- }
-
- function render_ac(query, list){
-
- if(list.length === 0){
-
- autocomplete_div.style.display = "none";
- return;
- }
-
- html = "";
-
- // prepare regex
- var highlight = query.split(" ");
- var regex = [];
-
- for(var k=0; k<highlight.length; k++){
-
- // espace regex
- regex.push(
- highlight[k].replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
- );
- }
-
- regex = new RegExp(highlight.join("|"), "gi");
-
- for(var i=0; i<list.length; i++){
-
- html +=
- '<div tabindex="0" class="entry" onclick="handle_entry_click(this);">' +
- htmlspecialchars(
- list[i]
- ).replace(
- regex,
- '<u>$&</u>'
- ) +
- '</div>';
- }
-
- autocomplete_div.innerHTML = html;
- autocomplete_div.style.display = "block";
- }
-
- var should_focus = false;
- document.addEventListener("keydown", function(event){
-
- if(event.key == "Escape"){
-
- document.activeElement.blur();
- focuspos = -1;
- autocomplete_div.style.display = "none";
- return;
- }
-
- if(
- is_click_within(event.target, "searchbox") === false ||
- typeof autocomplete_cache[getsearchboxtext()] == "undefined"
- ){
-
- return;
- }
-
- switch(event.key){
-
- case "ArrowUp":
- event.preventDefault();
- focuspos--;
- if(focuspos === -2){
-
- focuspos = autocomplete_cache[getsearchboxtext()].length - 1;
- }
- break;
-
- case "ArrowDown":
- case "Tab":
- event.preventDefault();
-
- focuspos++;
- if(focuspos >= autocomplete_cache[getsearchboxtext()].length){
-
- focuspos = -1;
- }
- break;
-
- case "Enter":
- should_focus = true;
-
- if(focuspos !== -1){
-
- // replace input content
- event.preventDefault();
- searchbox.value =
- autocomplete_div.getElementsByClassName("entry")[focuspos].innerText;
- break;
- }
- break;
-
- default:
- focuspos = -1;
- break;
- }
-
- if(focuspos === -1){
-
- searchbox.focus();
- return;
- }
-
- autocomplete_div.getElementsByClassName("entry")[focuspos].focus();
- });
-
- window.addEventListener("blur", function(){
-
- autocomplete_div.style.display = "none";
- });
-
- document.addEventListener("keyup", function(event){
-
- // handle ENTER key on entry
- if(should_focus){
-
- should_focus = false;
- searchbox.focus();
- }
- });
-
- document.addEventListener("mousedown", function(event){
-
- // hide input if click is outside
- if(is_click_within(event.target, "searchbox") === false){
-
- autocomplete_div.style.display = "none";
- return;
- }
- });
-
- function handle_entry_click(event){
-
- searchbox.value = event.innerText;
- focuspos = -1;
- searchbox.focus();
- }
-
- searchbox.addEventListener("focus", function(){
-
- focuspos = -1;
- getac();
- });
- }
- }
|