forked from 4ducky/4ducky
Same design, layout, URLs and features as the PHP version: browse grid, image view with AJAX comments, BBCode, likes, uploads (file, URL and bookmarklet), quicktagger, profile, block list, inbox, invites, Hall of Ducks, Truhe, abuse reports and the admin tools. - Parameterized SQL, escaped templates (askama), argon2 passwords, server-side sessions, CSRF tokens on every write, strict script CSP - SSRF-safe remote image fetching, magic-byte upload checks - Self-hosted captcha replaces reCAPTCHA v1; analytics/social widgets removed - Vanilla JS replaces jQuery and its plugins with the same DOM behaviour - Reverse proxy support (frontend_path, trust_proxy, secure_cookies) - Admin CLI: admin, settings, invites See README.md for running it and the full list of changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
554 lines
20 KiB
JavaScript
554 lines
20 KiB
JavaScript
/*
|
|
* 4ducky.com client script.
|
|
* Vanilla port of media/picturelicious.js, js/functions.js, js/jqpr.js,
|
|
* js/lightbox.js (Lightbox v2.51 by Lokesh Dhakar, CC BY 2.5) and
|
|
* media/quicktags.js. Same DOM and behaviour, no jQuery, no inline handlers.
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
|
|
var $ = function (id) { return document.getElementById(id); };
|
|
|
|
function csrf() {
|
|
var m = document.querySelector('meta[name="csrf-token"]');
|
|
return m ? m.content : '';
|
|
}
|
|
|
|
function post(url, data) {
|
|
return fetch(url, {
|
|
method: 'POST',
|
|
credentials: 'same-origin',
|
|
headers: { 'X-CSRF-Token': csrf(), 'X-Requested-With': 'XMLHttpRequest' },
|
|
body: new URLSearchParams(data)
|
|
}).then(function (r) { return r.text(); });
|
|
}
|
|
|
|
// ------------------------------------------------------------------ cookies
|
|
|
|
function getCookie(name) {
|
|
var m = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;]*)'));
|
|
return m ? decodeURIComponent(m[1]) : null;
|
|
}
|
|
|
|
function setCookie(name, value) {
|
|
if (value === null) {
|
|
document.cookie = name + '=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT';
|
|
} else {
|
|
document.cookie = name + '=' + encodeURIComponent(value) + '; path=/; SameSite=Lax';
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------ fades (jQuery fadeIn/fadeOut)
|
|
|
|
function fadeOut(el, ms) {
|
|
if (!el || el.style.display === 'none') return;
|
|
el.style.transition = 'opacity ' + ms + 'ms';
|
|
el.style.opacity = '0';
|
|
clearTimeout(el._fade);
|
|
el._fade = setTimeout(function () { el.style.display = 'none'; }, ms);
|
|
}
|
|
|
|
function fadeIn(el, ms, display) {
|
|
if (!el) return;
|
|
clearTimeout(el._fade);
|
|
if (el.style.display === 'none' || getComputedStyle(el).display === 'none') {
|
|
el.style.opacity = '0';
|
|
el.style.display = display || 'block';
|
|
}
|
|
el.style.transition = 'opacity ' + ms + 'ms';
|
|
void el.offsetWidth;
|
|
el.style.opacity = '';
|
|
}
|
|
|
|
function show(el, display) { if (el) el.style.display = display || 'block'; }
|
|
function hide(el) { if (el) el.style.display = 'none'; }
|
|
|
|
// ------------------------------------------------------------------ AJAX loaders
|
|
|
|
function LoadData(str, divId, imageId) {
|
|
return post('/ajax_getdata.php', { q: str, imageId: imageId || 0 }).then(function (data) {
|
|
var d = $(divId);
|
|
if (!d) return;
|
|
d.innerHTML = data;
|
|
d.style.display = 'block';
|
|
});
|
|
}
|
|
|
|
function Menu(art, er) {
|
|
var ud = $('UploadD');
|
|
if (art === 'upload') ud.style.backgroundPosition = '24px top';
|
|
if (art === 'addon') ud.style.backgroundPosition = '90px top';
|
|
if (er === 'error') {
|
|
hide($('UbLoad'));
|
|
show($('MenuLoad'));
|
|
return;
|
|
}
|
|
show($('MenuLoad'));
|
|
$('UploadD_d').innerHTML = '<div style="margin-top:12px;text-align:center;" id="UbLoad"><div align="center"><img src="/media/load_b.gif" /></div></div>';
|
|
LoadData(art, 'UploadD_d', 0);
|
|
}
|
|
|
|
function loadComments() {
|
|
var id = document.body.getAttribute('data-image-id');
|
|
if (id) LoadData('comments', 'cmts', id);
|
|
}
|
|
|
|
function SubmitComment(imageId) {
|
|
var file = $('image_comment'), url = $('url_comment'), content = $('content_comment');
|
|
if (content.value.length < 1) {
|
|
$('CommentError').textContent = 'Your comment is too short!';
|
|
show($('CommentError'));
|
|
return;
|
|
}
|
|
if (file && file.value.length > 4) {
|
|
$('CommentForm').submit();
|
|
return;
|
|
}
|
|
var fields = [file, url, content, $('SubBut')];
|
|
fields.forEach(function (f) { if (f) f.disabled = true; });
|
|
show($('SubLoad'));
|
|
post('/ajax_getdata.php', {
|
|
q: 'add', imageId: imageId, content: content.value, urlUpload: url ? url.value : ''
|
|
}).then(function () {
|
|
fields.forEach(function (f) { if (f) f.disabled = false; });
|
|
$('CommentForm').reset();
|
|
hide($('SubLoad'));
|
|
hide($('CommentError'));
|
|
loadComments();
|
|
});
|
|
}
|
|
|
|
function toggle(id) {
|
|
var el = $(id);
|
|
if (!el) return;
|
|
el.style.display = el.style.display !== 'block' ? 'block' : 'none';
|
|
}
|
|
|
|
function BBcode(code) {
|
|
var input = prompt('Enter URL / text / image-link / youtube-link');
|
|
if (input === null || input === '') return;
|
|
var x = $('content_comment');
|
|
x.value = x.value + '[' + code + ']' + input + '[/' + code + ']';
|
|
}
|
|
|
|
function reComment(commentId, user) {
|
|
var box = $('comment' + commentId);
|
|
if (box) box.style.border = '1px solid #898989';
|
|
var output = $(String(commentId)).textContent;
|
|
output = '>> ' + user + ': \n"' + output + '"';
|
|
var x = $('content_comment');
|
|
if (x) x.value = x.value + '[quote]' + output.substr(0, 750) + '[/quote]\n';
|
|
}
|
|
|
|
// ------------------------------------------------------------------ admin (json.php)
|
|
|
|
function json(action, params) {
|
|
return post('/json.php?' + action, params);
|
|
}
|
|
|
|
var admin = {
|
|
fame: function (id) {
|
|
if (!confirm('Move to Hall of Fame?')) return;
|
|
json('fame', { id: id });
|
|
},
|
|
ban: function (id) {
|
|
if (!confirm('Ban this User?')) return;
|
|
var rsn = prompt('Why?');
|
|
json('banUser', { id: id, rsn: rsn || '' });
|
|
},
|
|
timeblock: function (id) {
|
|
if (!confirm('Spamlock this user?')) return;
|
|
var tm = prompt('How long? (in hours)');
|
|
var rsn = prompt('Why?');
|
|
var now = Math.round(Date.now() / 1000) + 3600 * parseInt(tm || '0', 10);
|
|
alert(now);
|
|
json('TimeUser', { id: id, hours: tm || '0', rsn: rsn || '' });
|
|
},
|
|
close: function (id) {
|
|
if (!confirm('Close Thread?')) return;
|
|
json('CloseThread', { id: id });
|
|
},
|
|
'delete': function (id) {
|
|
if (!confirm('Delete this image: ' + id + ' ?')) return;
|
|
json('delete', { id: id }).then(loadComments);
|
|
}
|
|
};
|
|
|
|
function delComment(id) {
|
|
if (!confirm('Delete this comment?')) return;
|
|
json('deleteComment', { id: id }).then(loadComments);
|
|
}
|
|
|
|
// ------------------------------------------------------------------ grid solver (picturelicious.js)
|
|
|
|
var gridSize = 64, gridMinWidth = 6, gridWidth = 0, grid = null;
|
|
var boxDef = { b0: { width: 3, height: 3 }, b1: { width: 2, height: 2 }, b2: { width: 1, height: 1 } };
|
|
|
|
function gridSolve(cid) {
|
|
var container = $(cid);
|
|
var newGridWidth = parseInt(container.offsetWidth / gridSize, 10);
|
|
newGridWidth = newGridWidth < gridMinWidth ? gridMinWidth : newGridWidth;
|
|
if (gridWidth === newGridWidth) return;
|
|
gridWidth = newGridWidth;
|
|
|
|
var boxes = [];
|
|
while (container.hasChildNodes()) {
|
|
var e = container.removeChild(container.firstChild);
|
|
if (e.tagName === 'DIV') boxes.push(e);
|
|
}
|
|
grid = [];
|
|
for (var i = 0; i < gridWidth; i++) grid[i] = 0;
|
|
for (i = 0; i < boxes.length; i++) insertThumb(boxes[i], container);
|
|
|
|
var maxHeight = 0;
|
|
for (i = 0; i < grid.length; i++) maxHeight = Math.max(maxHeight, grid[i]);
|
|
container.style.height = (maxHeight * gridSize) + 'px';
|
|
$('images').style.height = (maxHeight * gridSize) + 'px';
|
|
}
|
|
|
|
function insertThumb(box, container) {
|
|
var def = boxDef[box.className] || boxDef.b2;
|
|
var boxWidth = def.width, boxHeight = def.height;
|
|
var maxHeight = 0, currentHeight = -1, spotWidth = 0, spotLeft = 0, freeSpots = [];
|
|
for (var i = 0; i < grid.length; i++) {
|
|
if (currentHeight === grid[i]) spotWidth++;
|
|
if ((currentHeight !== grid[i] || i + 1 === grid.length) && spotWidth > 0) {
|
|
freeSpots.push({ width: spotWidth, left: spotLeft, height: currentHeight });
|
|
spotWidth = 1;
|
|
spotLeft = i;
|
|
if (currentHeight !== grid[i] && i + 1 === grid.length) {
|
|
freeSpots.push({ width: spotWidth, left: spotLeft, height: grid[i] });
|
|
}
|
|
} else if (spotWidth === 0) {
|
|
spotWidth = 1;
|
|
}
|
|
currentHeight = grid[i];
|
|
if (grid[i] > maxHeight) maxHeight = grid[i];
|
|
}
|
|
|
|
var targetHeight = 0, targetLeft = 0, bestScore = -1;
|
|
for (var j = 0; j < boxWidth; j++) {
|
|
if (grid[j] > targetHeight) targetHeight = grid[j];
|
|
}
|
|
var newHeight = targetHeight + boxHeight;
|
|
for (i = 0; i < freeSpots.length; i++) {
|
|
var heightScore = maxHeight - freeSpots[i].height;
|
|
var widthScore = boxWidth / freeSpots[i].width;
|
|
var score = heightScore * heightScore + widthScore * 2;
|
|
if (freeSpots[i].width >= boxWidth && score > bestScore) {
|
|
targetHeight = freeSpots[i].height;
|
|
targetLeft = freeSpots[i].left;
|
|
newHeight = freeSpots[i].height + boxHeight;
|
|
bestScore = score;
|
|
}
|
|
}
|
|
for (j = 0; j < boxWidth; j++) grid[targetLeft + j] = newHeight;
|
|
|
|
container.appendChild(box);
|
|
box.style.left = (targetLeft * gridSize) + 'px';
|
|
box.style.top = (targetHeight * gridSize) + 'px';
|
|
}
|
|
|
|
function gridView(id) {
|
|
gridSolve(id);
|
|
gridSolve(id);
|
|
setInterval(function () { gridSolve(id); }, 250);
|
|
}
|
|
|
|
// ------------------------------------------------------------------ sidebar & layout (jqpr.js)
|
|
|
|
function hideSidebar() {
|
|
hide($('sidebar'));
|
|
hide($('MenuRightBlock'));
|
|
$('site').style.marginRight = '0px';
|
|
var f = $('footer');
|
|
if (f) f.style.marginRight = '0px';
|
|
$('footer-back-to-top').style.right = '30px';
|
|
}
|
|
|
|
// ------------------------------------------------------------------ lightbox (Lightbox v2.51)
|
|
|
|
var lightbox = {
|
|
album: [],
|
|
current: 0,
|
|
built: false,
|
|
build: function () {
|
|
var overlay = document.createElement('div');
|
|
overlay.id = 'lightboxOverlay';
|
|
var lb = document.createElement('div');
|
|
lb.id = 'lightbox';
|
|
lb.innerHTML =
|
|
'<div class="lb-outerContainer"><div class="lb-container"><img class="lb-image">' +
|
|
'<div class="lb-nav"><a class="lb-prev"></a><a class="lb-next"></a></div>' +
|
|
'<div class="lb-loader"><a class="lb-cancel"><img src="/media/lightbox/loading.gif"></a></div></div></div>' +
|
|
'<div class="lb-dataContainer"><div class="lb-data"><div class="lb-details"><span class="lb-caption"></span>' +
|
|
'<span class="lb-number"></span></div><div class="lb-closeContainer"><a class="lb-close">' +
|
|
'<img src="/media/lightbox/close.png"></a></div></div></div>';
|
|
document.body.appendChild(overlay);
|
|
document.body.appendChild(lb);
|
|
hide(overlay);
|
|
hide(lb);
|
|
var that = this;
|
|
overlay.addEventListener('click', function (e) { e.preventDefault(); that.end(); });
|
|
lb.addEventListener('click', function (e) {
|
|
e.preventDefault();
|
|
var t = e.target;
|
|
if (t.id === 'lightbox') that.end();
|
|
else if (t.classList.contains('lb-prev')) that.change(that.current - 1);
|
|
else if (t.classList.contains('lb-next')) that.change(that.current + 1);
|
|
else if (t.closest('.lb-loader, .lb-close')) that.end();
|
|
});
|
|
this.keys = function (e) { that.keyboard(e); };
|
|
this.built = true;
|
|
},
|
|
q: function (sel) { return $('lightbox').querySelector(sel); },
|
|
sizeOverlay: function () {
|
|
var o = $('lightboxOverlay');
|
|
o.style.width = document.documentElement.scrollWidth + 'px';
|
|
o.style.height = document.documentElement.scrollHeight + 'px';
|
|
},
|
|
start: function (link) {
|
|
if (!this.built) this.build();
|
|
var rel = link.getAttribute('rel');
|
|
this.album = [];
|
|
var number = 0;
|
|
if (rel === 'lightbox') {
|
|
this.album.push({ link: link.getAttribute('href'), title: link.getAttribute('title') });
|
|
} else {
|
|
var links = document.querySelectorAll('a[rel="' + rel + '"]');
|
|
for (var i = 0; i < links.length; i++) {
|
|
this.album.push({ link: links[i].getAttribute('href'), title: links[i].getAttribute('title') });
|
|
if (links[i] === link) number = i;
|
|
}
|
|
}
|
|
this.sizeOverlay();
|
|
fadeIn($('lightboxOverlay'), 500);
|
|
var lb = $('lightbox');
|
|
lb.style.top = (window.scrollY + window.innerHeight / 10) + 'px';
|
|
lb.style.left = window.scrollX + 'px';
|
|
fadeIn(lb, 500);
|
|
window.addEventListener('resize', this.sizeOverlay);
|
|
this.change(number);
|
|
},
|
|
change: function (n) {
|
|
if (n < 0 || n >= this.album.length) return;
|
|
var that = this;
|
|
document.removeEventListener('keyup', this.keys);
|
|
['.lb-image', '.lb-nav', '.lb-prev', '.lb-next', '.lb-dataContainer', '.lb-caption'].forEach(function (s) { hide(that.q(s)); });
|
|
show(this.q('.lb-loader'));
|
|
this.q('.lb-outerContainer').classList.add('animating');
|
|
var pre = new Image();
|
|
pre.onload = function () {
|
|
that.q('.lb-image').src = that.album[n].link;
|
|
that.size(pre.width, pre.height);
|
|
};
|
|
pre.src = this.album[n].link;
|
|
this.current = n;
|
|
},
|
|
size: function (w, h) {
|
|
var that = this;
|
|
var outer = this.q('.lb-outerContainer');
|
|
var cs = getComputedStyle(this.q('.lb-container'));
|
|
var nw = w + parseInt(cs.paddingLeft, 10) + parseInt(cs.paddingRight, 10);
|
|
var nh = h + parseInt(cs.paddingTop, 10) + parseInt(cs.paddingBottom, 10);
|
|
outer.style.transition = 'width 700ms, height 700ms';
|
|
outer.style.width = nw + 'px';
|
|
outer.style.height = nh + 'px';
|
|
setTimeout(function () {
|
|
that.q('.lb-dataContainer').style.width = nw + 'px';
|
|
hide(that.q('.lb-loader'));
|
|
fadeIn(that.q('.lb-image'), 600);
|
|
show(that.q('.lb-nav'));
|
|
if (that.current > 0) show(that.q('.lb-prev'));
|
|
if (that.current < that.album.length - 1) show(that.q('.lb-next'));
|
|
var item = that.album[that.current];
|
|
if (item.title) {
|
|
that.q('.lb-caption').textContent = item.title;
|
|
fadeIn(that.q('.lb-caption'), 200, 'inline');
|
|
}
|
|
var num = that.q('.lb-number');
|
|
if (that.album.length > 1) {
|
|
num.textContent = 'Image ' + (that.current + 1) + ' of ' + that.album.length;
|
|
fadeIn(num, 200);
|
|
} else {
|
|
hide(num);
|
|
}
|
|
outer.classList.remove('animating');
|
|
fadeIn(that.q('.lb-dataContainer'), 700);
|
|
that.sizeOverlay();
|
|
[that.current + 1, that.current - 1].forEach(function (i) {
|
|
if (that.album[i]) new Image().src = that.album[i].link;
|
|
});
|
|
document.addEventListener('keyup', that.keys);
|
|
}, 700);
|
|
},
|
|
keyboard: function (e) {
|
|
var key = String.fromCharCode(e.keyCode).toLowerCase();
|
|
if (e.keyCode === 27 || /x|o|c/.test(key)) this.end();
|
|
else if (key === 'p' || e.keyCode === 37) this.change(this.current - 1);
|
|
else if (key === 'n' || e.keyCode === 39) this.change(this.current + 1);
|
|
},
|
|
end: function () {
|
|
document.removeEventListener('keyup', this.keys);
|
|
window.removeEventListener('resize', this.sizeOverlay);
|
|
fadeOut($('lightbox'), 500);
|
|
fadeOut($('lightboxOverlay'), 500);
|
|
}
|
|
};
|
|
|
|
// ------------------------------------------------------------------ quicktagger (quicktags.js)
|
|
|
|
var nextImage = {};
|
|
|
|
function quickTag(logId, imageId, inputField) {
|
|
var tags = inputField.value;
|
|
$('imageLocation').href = nextImage.link || '#';
|
|
$('imageLocation').textContent = nextImage.link || '';
|
|
$('imageId').value = nextImage.id || 0;
|
|
$('logId').value = nextImage.logId || 0;
|
|
if (nextImage.image) $('image').src = nextImage.image;
|
|
$('tags').textContent = nextImage.tags || '';
|
|
$('tagText').value = '';
|
|
$('tagText').focus();
|
|
if (!nextImage.link) {
|
|
$('imageInfo').textContent = 'No more Images found';
|
|
}
|
|
json('quickTag', { logId: logId, id: imageId, tags: tags }).then(function (txt) {
|
|
nextImage = JSON.parse(txt || '{}');
|
|
if (nextImage.image) new Image().src = nextImage.image;
|
|
});
|
|
}
|
|
|
|
function quickTagInit() {
|
|
$('quickTagIntro').className = 'hidden';
|
|
$('viewer').className = 'visible';
|
|
json('quickTag', {}).then(function (txt) {
|
|
nextImage = JSON.parse(txt || '{}');
|
|
quickTag(0, 0, $('tagText'));
|
|
});
|
|
}
|
|
|
|
// ------------------------------------------------------------------ events
|
|
|
|
document.addEventListener('click', function (e) {
|
|
// Match the element that carries the hook, not an <img> inside a link.
|
|
var t = e.target.closest(
|
|
'a[rel^="lightbox"], [data-action], [data-menu], [data-toggle], [data-fav], [data-bbcode], ' +
|
|
'[data-requote], [data-delcomment], [data-admin], [data-bookmarklet], [data-select], ' +
|
|
'#SubBut, #image, #x, #stfu, #del_cookie, #loadcom, #footer-back-to-top'
|
|
);
|
|
if (!t) return;
|
|
var d = t.dataset;
|
|
|
|
if (t.matches('a[rel^="lightbox"]')) { e.preventDefault(); lightbox.start(t); return; }
|
|
if (d.action === 'close-upload') { hide($('MenuLoad')); return; }
|
|
if (d.menu) { e.preventDefault(); Menu(d.menu); return; }
|
|
if (d.toggle) { e.preventDefault(); toggle(d.toggle); return; }
|
|
if (d.fav) { e.preventDefault(); LoadData('fav', 'FavDiv', d.fav); return; }
|
|
if (d.bbcode) { e.preventDefault(); BBcode(d.bbcode); return; }
|
|
if (d.requote) { reComment(d.requote, d.name); return; }
|
|
if (d.delcomment) { e.preventDefault(); delComment(d.delcomment); return; }
|
|
if (d.admin && admin[d.admin]) { e.preventDefault(); admin[d.admin](d.id); return; }
|
|
if (d.bookmarklet) { e.preventDefault(); alert('Drag this Link to your Bookmarks!'); return; }
|
|
if (d.select) { t.focus(); t.select(); return; }
|
|
if (d.action === 'quicktag-start') { e.preventDefault(); quickTagInit(); return; }
|
|
if (d.action === 'quicktag') { e.preventDefault(); quickTag($('logId').value, $('imageId').value, $('tagText')); return; }
|
|
if (t.id === 'SubBut') { SubmitComment(d.imageId); return; }
|
|
if (t.id === 'image' && /^(scaled|full)$/.test(t.className)) { t.className = t.className === 'scaled' ? 'full' : 'scaled'; return; }
|
|
if (t.id === 'x') {
|
|
e.preventDefault();
|
|
fadeOut($('sidebar'), 600);
|
|
hide($('MenuRightBlock'));
|
|
$('site').style.marginRight = '0px';
|
|
$('footer-back-to-top').style.right = '30px';
|
|
alert('Sidebar closed. Open it by clicking on your avatar in the header. Best regards, Dolan!');
|
|
setCookie('close_sidebar', 'yes');
|
|
return;
|
|
}
|
|
if (t.id === 'stfu') { fadeOut($('dolan'), 600); setCookie('close_message', 'yes'); return; }
|
|
if (t.id === 'del_cookie') {
|
|
e.preventDefault();
|
|
setCookie('close_sidebar', null);
|
|
setCookie('close_message', null);
|
|
location.reload();
|
|
return;
|
|
}
|
|
if (t.id === 'loadcom') { e.preventDefault(); LoadData('lastcomments', 'rightpanel'); return; }
|
|
if (t.id === 'footer-back-to-top') { e.preventDefault(); window.scrollTo({ top: 0, behavior: 'smooth' }); }
|
|
});
|
|
|
|
document.addEventListener('submit', function (e) {
|
|
if (e.target.id === 'addTag') {
|
|
e.preventDefault();
|
|
quickTag($('logId').value, $('imageId').value, $('tagText'));
|
|
}
|
|
});
|
|
|
|
document.addEventListener('mouseover', function (e) {
|
|
var t = e.target;
|
|
if (t.classList && t.classList.contains('duckfav')) t.src = '/media/duck.png';
|
|
var h = t.closest && t.closest('[data-hover]');
|
|
if (h) { var el = $(h.dataset.hover); if (el) el.style.visibility = 'visible'; }
|
|
});
|
|
|
|
document.addEventListener('mouseout', function (e) {
|
|
var t = e.target;
|
|
if (t.classList && t.classList.contains('duckfav')) t.src = '/media/ducksw.png';
|
|
var box = $('Last5Div');
|
|
if (box && box.contains(t) && !box.contains(e.relatedTarget)) box.style.visibility = 'hidden';
|
|
});
|
|
|
|
// Broken [img] BBCode images fall back to the dolan 404 picture (was onError="...").
|
|
document.addEventListener('error', function (e) {
|
|
var t = e.target;
|
|
if (t.tagName === 'IMG' && t.dataset && t.dataset.fallback && !t.dataset.failed) {
|
|
t.dataset.failed = '1';
|
|
t.src = t.dataset.fallback;
|
|
}
|
|
}, true);
|
|
|
|
document.documentElement.addEventListener('keyup', function (e) {
|
|
if (!$('prevBar') || $('lightbox') && $('lightbox').style.display === 'block') return;
|
|
var a = document.activeElement;
|
|
if (a && (a.tagName === 'INPUT' || a.tagName === 'TEXTAREA')) return;
|
|
var c = $('content_comment');
|
|
if (c && c.value) return;
|
|
var bar = e.keyCode === 37 ? $('prevBar') : e.keyCode === 39 ? $('nextBar') : null;
|
|
if (bar && bar.getAttribute('href')) window.location = bar.getAttribute('href');
|
|
});
|
|
|
|
// ------------------------------------------------------------------ init
|
|
|
|
function init() {
|
|
var body = document.body;
|
|
var top = $('footer-back-to-top');
|
|
|
|
if (/iPhone|iPod|iPad|Android|BlackBerry/i.test(navigator.userAgent)) {
|
|
hideSidebar();
|
|
$('menu').style.position = 'relative';
|
|
$('content').style.marginTop = '0.5em';
|
|
}
|
|
if (body.hasAttribute('data-guest')) {
|
|
hide($('sidebar'));
|
|
$('site').style.marginRight = '0px';
|
|
top.style.right = '30px';
|
|
}
|
|
if (getCookie('close_sidebar') === 'yes') hideSidebar();
|
|
if (getCookie('close_message') === 'yes') hide($('dolan'));
|
|
|
|
hide(top);
|
|
window.addEventListener('scroll', function () {
|
|
if (window.scrollY > 200) fadeIn(top, 600); else fadeOut(top, 600);
|
|
}, { passive: true });
|
|
|
|
if ($('imageGrid')) gridView('imageGrid');
|
|
var ml = $('MenuLoad');
|
|
if (ml && ml.hasAttribute('data-error')) Menu('', 'error');
|
|
if ($('rightpanel')) LoadData('lastcomments', 'rightpanel');
|
|
loadComments();
|
|
}
|
|
|
|
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
|
else init();
|
|
})();
|