require('whatwg-fetch');
require('element-closest');
require('classlist.js');
let killy = require('killy');
let Awesomplete = require('awesomplete');
if (!('remove' in Element.prototype)) { // Firefox <23
Element.prototype.remove = function() {
if (this.parentNode) {
this.parentNode.removeChild(this);
}
};
}
NodeList.prototype.forEach = Array.prototype.forEach;
HTMLCollection.prototype.forEach = Array.prototype.forEach;
Element.prototype.selectText = function () {
let d = document;
if (d.body.createTextRange) {
let range = d.body.createTextRange();
range.moveToElementText(this);
range.select();
} else if (window.getSelection) {
let selection = window.getSelection();
let rangeSel = d.createRange();
rangeSel.selectNodeContents(this);
selection.removeAllRanges();
selection.addRange(rangeSel);
}
};
function once(el, eventType, callback) {
function eventHandler(e) {
el.removeEventListener(eventType, eventHandler);
callback(e);
}
el.addEventListener(eventType, eventHandler);
}
function nextClick(callback) {
setTimeout(() => once(document, 'click', callback), 0);
}
function nextClickWithCondition(predicate, callback) {
function clickCheck(e) {
if (predicate(e)) {
callback();
} else {
nextClick(clickCheck);
}
}
nextClick(clickCheck);
}
function keyboardClickable(el) {
el.addEventListener('keydown', e => {
if ((e.which === 13) || (e.which === 32)) { // 13 = Return, 32 = Space
e.preventDefault();
el.click();
}
});
}
function makeMenu(target, dropdown) {
target.addEventListener('click', e => {
if (!dropdown.contains(e.target)) {
target.classList.toggle('expanded');
}
nextClickWithCondition(
e => !target.contains(e.target),
() => target.classList.remove('expanded')
);
});
keyboardClickable(target);
dropdown.addEventListener('blur', e => {
if (!dropdown.contains(e.relatedTarget)) {
target.classList.remove('expanded');
}
}, true);
}
function autosize(el) {
let offset = (!window.opera)
? (el.offsetHeight - el.clientHeight)
: (el.offsetHeight + parseInt(window.getComputedStyle(el, null).getPropertyValue('border-top-width')));
let resize = function(el) {
el.style.height = 'auto';
el.style.height = (el.scrollHeight + offset) + 'px';
};
if (el.addEventListener) {
el.addEventListener('input', () => resize(el));
} else if (el.attachEvent) {
el.attachEvent('onkeyup', () => resize(el));
}
}
function evilIcon(name) {
return `
`;
}
/* eslint-disable only-ascii/only-ascii */
const translations = {
'en': {
'message.inReplyTo': 'in reply to',
'message.reply': 'Reply',
'message.likeThisMessage?': 'Recommend this message?',
'postForm.pleaseInputMessageText': 'Please input message text',
'postForm.upload': 'Upload',
'postForm.newMessage': 'New message...',
'postForm.imageLink': 'Link to image',
'postForm.imageFormats': 'JPG/PNG, up to 10 MB',
'postForm.or': 'or',
'postForm.tags': 'Tags (space separated)',
'postForm.submit': 'Send',
'comment.writeComment': 'Write a comment...',
'shareDialog.linkToMessage': 'Link to message',
'shareDialog.messageNumber': 'Message number',
'shareDialog.share': 'Share',
'loginDialog.pleaseIntroduceYourself': 'Please introduce yourself',
'loginDialog.registeredAlready': 'Registered already?',
'loginDialog.username': 'Username',
'loginDialog.password': 'Password',
'loginDialog.facebook': 'Login with Facebook',
'loginDialog.vk': 'Login with VK',
'error.error': 'Error'
},
'ru': {
'message.inReplyTo': 'в ответ на',
'message.reply': 'Ответить',
'message.likeThisMessage?': 'Рекомендовать это сообщение?',
'postForm.pleaseInputMessageText': 'Пожалуйста, введите текст сообщения',
'postForm.upload': 'загрузить',
'postForm.newMessage': 'Новое сообщение...',
'postForm.imageLink': 'Ссылка на изображение',
'postForm.imageFormats': 'JPG/PNG, до 10Мб',
'postForm.or': 'или',
'postForm.tags': 'Теги (через пробел)',
'postForm.submit': 'Отправить',
'comment.writeComment': 'Написать комментарий...',
'shareDialog.linkToMessage': 'Ссылка на сообщение',
'shareDialog.messageNumber': 'Номер сообщения',
'shareDialog.share': 'Поделиться',
'loginDialog.pleaseIntroduceYourself': 'Пожалуйста, представьтесь',
'loginDialog.registeredAlready': 'Уже зарегистрированы?',
'loginDialog.username': 'Имя пользователя',
'loginDialog.password': 'Пароль',
'loginDialog.facebook': 'Войти через Facebook',
'loginDialog.vk': 'Войти через ВКонтакте',
'error.error': 'Ошибка'
}
};
/* eslint-enable only-ascii/only-ascii */
function getLang() {
return (window.navigator.languages && window.navigator.languages[0])
|| window.navigator.userLanguage
|| window.navigator.language;
}
function i18n(key, lang=undefined) {
const fallbackLang = 'ru';
lang = lang || getLang().split('-')[0];
return (translations[lang] && translations[lang][key])
|| translations[fallbackLang][key]
|| key;
}
var ws,
pageTitle;
function initWS() {
var content = document.getElementById('content');
if (!content) { return; }
var pageMID = content.getAttribute('data-mid');
if (!pageMID) { return; }
var url = (window.location.protocol === 'https:' ? 'wss' : 'ws') + ':'
+ (typeof juickDebug !== 'undefined' ?
'//ws.juick.com/_replies' : ('//ws.juick.com/' + pageMID)),
hash = document.getElementById('body').getAttribute('data-hash');
if (hash) {
url += '?hash=' + hash;
}
ws = new WebSocket(url);
ws.onopen = function () {
console.log('online');
if (!document.querySelector('#wsthread')) {
var d = document.createElement('div');
d.id = 'wsthread';
d.addEventListener('click', nextReply);
document.querySelector('body').appendChild(d);
pageTitle = document.title;
}
};
ws.onclose = function () {
console.log('offline');
ws = false;
setTimeout(function () {
initWS();
}, 2000);
};
ws.onmessage = function (msg) {
if (msg.data == ' ') {
ws.send(' ');
} else {
try {
var jsonMsg = JSON.parse(msg.data);
console.log('data: ' + msg.data);
wsIncomingReply(jsonMsg);
} catch (err) {
console.log(err);
}
}
};
setInterval(wsSendKeepAlive, 90000);
}
function wsSendKeepAlive() {
if (ws) {
ws.send(' ');
}
}
function wsShutdown() {
if (ws) {
ws.onclose = function () { };
ws.close();
}
}
function isTreeMode() {
// relies on UserThread.printReplies implementation TODO keep this in cookie or something
return document.querySelector('.title2-right > a').href.match(/\?view=(\w+)/)[1] == 'list';
}
function wsIncomingReply(msg) {
let msgNum = '/' + msg.rid;
if (msg.replyto > 0) {
msgNum += ` ${i18n('message.inReplyTo')} /${msg.replyto}`;
}
let photoDiv = (msg.attach === undefined) ? '' : `
`;
let msgContHtml = `
${killy.format(msg.body, msg.mid, false)}
${photoDiv}
`;
let li = document.createElement('li');
li.setAttribute('class', 'msg reply-new');
li.setAttribute('id', msg.rid);
li.innerHTML = msgContHtml;
li.addEventListener('click', newReply);
li.addEventListener('mouseover', newReply);
li.querySelector('a.msg-reply-link').addEventListener('click', function (e) {
showCommentForm(msg.mid, msg.rid);
e.preventDefault();
});
killy.embedLinksToX(li.querySelector('.msg-cont'), '.msg-links', '.msg-txt a');
if (isTreeMode() && (msg.replyto > 0)) {
let p = document.getElementById(msg.replyto);
let m = parseInt(p.style.marginLeft) + 20;
while (p.nextElementSibling && (parseInt(p.nextElementSibling.style.marginLeft) >= m)) { p = p.nextElementSibling; }
li.style.marginLeft = m + 'px';
p.parentNode.insertBefore(li, p.nextSibling);
} else {
document.getElementById('replies').appendChild(li);
}
updateRepliesCounter();
}
function newReply(e) {
var li = e.target;
li.classList.remove('reply-new');
li.removeEventListener('click', e);
li.removeEventListener('mouseover', e);
updateRepliesCounter();
}
function nextReply() {
var li = document.querySelector('#replies>li.reply-new');
if (li) {
li.classList.remove('reply-new');
li.removeEventListener('click', this);
li.children[0].scrollIntoView();
updateRepliesCounter();
}
}
function updateRepliesCounter() {
var replies = document.querySelectorAll('#replies>li.reply-new').length;
var wsthread = document.getElementById('wsthread');
if (replies) {
wsthread.textContent = replies;
wsthread.style.display = 'block';
document.title = '[' + replies + '] ' + pageTitle;
} else {
wsthread.style.display = 'none';
document.title = pageTitle;
}
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
function postformListener(formEl, ev) {
if (ev.ctrlKey && (ev.keyCode == 10 || ev.keyCode == 13)) {
let form = formEl.closest('form');
if (!form.onsubmit || form.onsubmit()) {
form.submit();
}
}
}
function closeDialogListener(ev) {
ev = ev || window.event;
if (ev.keyCode == 27) {
closeDialog();
}
}
function newMessage(evt) {
document.querySelectorAll('#newmessage .dialogtxt').forEach(t => {
t.remove();
});
if (document.querySelector('#newmessage textarea').value.length == 0
&& document.querySelector('#newmessage .img').value.length == 0
&& !document.querySelector('#newmessage input[type="file"]')) {
document.querySelector('#newmessage').insertAdjacentHTML('afterbegin', `${i18n('postForm.pleaseInputMessageText')}
`);
evt.preventDefault();
}
}
function showMoreReplies(el, id) {
var foldedReplies = el.closest('li').querySelector('.msg-comments');
if (!foldedReplies) { return; }
foldedReplies.style.display = 'none';
var replies = document.querySelectorAll('#replies>li'),
flagshow = 0,
i = 0;
for (; i < replies.length; i += 1) {
if (flagshow == 1) {
if (replies[i].style.display == 'none') {
replies[i].style.display = 'block';
} else {
break;
}
}
if (replies[i].id == id) {
flagshow = 1;
}
}
return false;
}
function showCommentForm(mid, rid) {
let reply = document.getElementById(rid);
let formTarget = reply.querySelector('div.msg-cont .msg-comment-target');
if (formTarget) {
let formHtml = `
`;
formTarget.insertAdjacentHTML('afterend', formHtml);
formTarget.remove();
let form = reply.querySelector('form');
let submitButton = form.querySelector('input[type="submit"]');
let attachButton = form.querySelector('.msg-comment .attach-photo');
attachButton.addEventListener('click', e => attachCommentPhoto(e.target));
let textarea = form.querySelector('.msg-comment textarea');
textarea.addEventListener('keypress', e => postformListener(e.target, e));
autosize(textarea);
let validateMessage = () => {
let len = textarea.value.length;
if (len > 4096) { return 'Message is too long'; }
return '';
};
form.addEventListener('submit', e => {
let validationResult = validateMessage();
if (validationResult) {
e.preventDefault();
alert(validationResult);
return false;
}
submitButton.disabled = true;
});
}
reply.querySelector('.msg-comment textarea').focus();
}
function attachInput() {
let inp = document.createElement('input');
inp.setAttribute('type', 'file');
inp.setAttribute('name', 'attach');
inp.setAttribute('accept', 'image/jpeg,image/png');
inp.style.visibility = 'hidden';
return inp;
}
function attachCommentPhoto(div) {
let input = div.querySelector('input');
if (input) {
input.remove();
div.classList.remove('attach-photo-active');
} else {
let newInput = attachInput();
newInput.addEventListener('change', function () {
div.classList.add('attach-photo-active');
});
newInput.click();
div.appendChild(newInput);
}
}
function attachMessagePhoto(div) {
var f = div.closest('form'),
finput = f.querySelector('input[type="file"]');
if (!finput) {
var inp = attachInput();
inp.style.float = 'left';
inp.style.width = 0;
inp.style.height = 0;
inp.addEventListener('change', function () {
div.textContent = i18n('postForm.upload') + ' (✓)';
});
f.appendChild(inp);
inp.click();
} else {
finput.remove();
div.textContent = i18n('postForm.upload');
}
}
function unfoldReply() {
var anchor = window.location.hash.substring(1);
if ((0 + anchor) > 0) {
var el = document.getElementById(anchor);
if (!el) { return; }
while (el.style.display === 'none') {
el = el.previousElementSibling;
}
showMoreReplies(el, el.getAttribute('id'));
window.location.replace(window.location.hash);
}
}
function showMessageLinksDialog(mid, rid) {
let hlink = window.location.protocol + '//juick.com/' + mid;
let mlink = '#' + mid;
if (rid > 0) {
hlink += '#' + rid;
mlink += '/' + rid;
}
let hlinkenc = encodeURIComponent(hlink);
let html = `
${i18n('shareDialog.linkToMessage')}:
${hlink}
${i18n('shareDialog.messageNumber')}:
${mlink}
${i18n('shareDialog.share')}:
`;
openDialog(html);
}
function showPhotoDialog(fname) {
let width = window.innerWidth;
let height = window.innerHeight;
let minDimension = (width < height) ? width : height;
if (minDimension < 640) {
return true; // no dialog, open the link
} else if (minDimension < 1280) {
openDialog(``, true);
return false;
} else {
openDialog(``, true);
return false;
}
}
function openPostDialog() {
let newmessageTemplate = `
`;
return openDialog(newmessageTemplate);
}
function openDialog(html, image) {
var dialogHtml = `
`;
let body = document.querySelector('body');
body.classList.add('dialog-opened');
body.insertAdjacentHTML('afterbegin', dialogHtml);
if (image) {
let header = document.querySelector('#dialog_header');
header.classList.add('header_image');
}
document.addEventListener('keydown', closeDialogListener);
document.querySelector('#dialogb').addEventListener('click', closeDialog);
document.querySelector('#dialogc').addEventListener('click', closeDialog);
}
function closeDialog() {
let draft = document.querySelector('#newmessage textarea');
if (draft) {
window.draft = draft.value;
}
document.querySelector('body').classList.remove('dialog-opened');
document.querySelector('#dialogb').remove();
document.querySelector('#dialogt').remove();
}
function openSocialWindow(a) {
var w = window.open(a.href, 'juickshare', 'width=640,height=400');
if (window.focus) { w.focus(); }
return false;
}
function checkUsername() {
var uname = document.querySelector('#username').textContent,
style = document.querySelector('#username').style;
fetch('//api.juick.com/users?uname=' + uname)
.then(function () {
style.background = '#FFCCCC';
})
.catch(function () {
style.background = '#CCFFCC';
});
}
/******************************************************************************/
function openDialogLogin() {
let html = `
`;
openDialog(html);
return false;
}
/******************************************************************************/
function resultMessage(str) {
var result = document.createElement('p');
result.textContent = str;
return result;
}
function likeMessage(e, mid) {
if (confirm(i18n('message.likeThisMessage?'))) {
fetch('//juick.com/like?mid=' + mid, {
method: 'POST',
credentials: 'same-origin'
})
.then(function (response) {
if (response.ok) {
e.closest('article').appendChild(resultMessage('OK!'));
}
})
.catch(function () {
e.closest('article').appendChild(resultMessage(i18n('error.error')));
});
}
return false;
}
/******************************************************************************/
function setPopular(e, mid, popular) {
fetch('//api.juick.com/messages/set_popular?mid=' + mid
+ '&popular=' + popular
+ '&hash=' + document.getElementById('body').getAttribute('data-hash'), {
credentials: 'same-origin'
})
.then(function () {
e.closest('article').append(resultMessage('OK!'));
});
return false;
}
function setPrivacy(e, mid) {
fetch('//api.juick.com/messages/set_privacy?mid=' + mid
+ '&hash=' + document.getElementById('body').getAttribute('data-hash'), {
credentials: 'same-origin'
})
.then(function () {
e.closest('article').append(resultMessage('OK!'));
});
return false;
}
function getTags() {
fetch('//api.juick.com/tags?hash=' + document.getElementById('body').getAttribute('data-hash'), {
credentials: 'same-origin'
})
.then(response => {
return response.json();
})
.then(json => {
let tags = json.map(t => t.tag);
let input = document.getElementById('tags_input');
new Awesomplete(input, {list : tags});
});
return false;
}
/******************************************************************************/
function ready(fn) {
if (document.readyState != 'loading') {
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
ready(function () {
document.querySelectorAll('textarea').forEach((ta) => {
autosize(ta);
});
var insertPMButtons = function (e) {
e.target.classList.add('narrowpm');
e.target.parentNode.insertAdjacentHTML('afterend', '');
e.target.removeEventListener('click', insertPMButtons);
e.preventDefault();
};
document.querySelectorAll('textarea.replypm').forEach(function (e) {
e.addEventListener('click', insertPMButtons);
e.addEventListener('keypress', function (e) {
postformListener(e.target, e);
});
});
makeMenu(
document.querySelector('#user-menu'),
document.querySelector('#user-menu-dropdown')
);
let column = document.querySelector('#column');
if (column && column.querySelector('#ctitle') && column.querySelector('#column-expander')) {
let columnExpander = column.querySelector('#column-expander');
keyboardClickable(columnExpander);
columnExpander.addEventListener('click', () => {
column.classList.toggle('expanded');
});
} else {
column.classList.add('expanded');
}
let tagsColumn = document.querySelector('#column > .tags');
if (tagsColumn) {
document.querySelector('#column').classList.add('bottom');
}
let content = document.getElementById('content');
if (content) {
let pageMID = content.getAttribute('data-mid');
if (pageMID > 0) {
document.querySelectorAll('li.msg').forEach(li => {
let showMoreBtn = li.querySelector('.msg-comments');
if (showMoreBtn) {
showMoreBtn.addEventListener('click', function (e) {
showMoreReplies(e.target, li.id);
e.preventDefault();
});
}
let showReplyFormBtn = li.querySelector('.a-thread-comment');
if (showReplyFormBtn) {
showReplyFormBtn.addEventListener('click', function (e) {
showCommentForm(pageMID, li.id);
e.preventDefault();
});
}
});
let opMessage = document.querySelector('.msgthread');
if (opMessage) {
let replyTextarea = opMessage.querySelector('textarea.reply');
if (replyTextarea) {
replyTextarea.addEventListener('focus', e => showCommentForm(pageMID, 0));
replyTextarea.addEventListener('keypress', e => postformListener(e.target, e));
if (!window.location.hash) {
replyTextarea.focus();
}
}
}
}
}
document.querySelectorAll('.msg-menu').forEach(function (el) {
el.addEventListener('click', function (e) {
var reply = e.target.closest('li');
var rid = reply ? parseInt(reply.id) : 0;
var message = e.target.closest('section');
var mid = message.getAttribute('data-mid') || e.target.closest('article').getAttribute('data-mid');
showMessageLinksDialog(mid, rid);
e.preventDefault();
});
});
document.querySelectorAll('.l .a-privacy').forEach(function (e) {
e.addEventListener('click', function (e) {
setPrivacy(
e.target,
e.target.closest('article').getAttribute('data-mid'));
e.preventDefault();
});
});
document.querySelectorAll('.ir a[data-fname], .msg-media a[data-fname]').forEach(function (el) {
el.addEventListener('click', function (e) {
let fname = e.target.closest('[data-fname]').getAttribute('data-fname');
if (!showPhotoDialog(fname)) {
e.preventDefault();
}
});
});
document.querySelectorAll('.social a').forEach(function (e) {
e.addEventListener('click', function (e) {
openSocialWindow(e.target);
e.preventDefault();
});
});
var username = document.getElementById('username');
if (username) {
username.addEventListener('blur', function () {
checkUsername();
});
}
document.querySelectorAll('.l .a-like').forEach(function (e) {
e.addEventListener('click', function (e) {
likeMessage(
e.target,
e.target.closest('article').getAttribute('data-mid'));
e.preventDefault();
});
});
document.querySelectorAll('.a-login').forEach(function (el) {
el.addEventListener('click', function (e) {
openDialogLogin();
e.preventDefault();
});
});
var unfoldall = document.getElementById('unfoldall');
if (unfoldall) {
unfoldall.addEventListener('click', function (e) {
document.querySelectorAll('#replies>li').forEach(function (e) {
e.style.display = 'block';
});
document.querySelectorAll('#replies .msg-comments').forEach(function (e) {
e.style.display = 'none';
});
e.preventDefault();
});
}
var post = document.getElementById('post');
if (post) {
post.addEventListener('click', (e) => {
openPostDialog();
getTags();
var newMessageBlock = document.getElementById('newmessage');
if (newMessageBlock) {
newMessageBlock.addEventListener('submit', newMessage);
let ta = newMessageBlock.querySelector('textarea');
if (window.draft) {
ta.innerHTML = window.draft;
}
ta.addEventListener('keypress', function (e) {
postformListener(e.target, e);
});
ta.style.minHeight = '70px';
autosize(ta);
ta.focus();
newMessageBlock.querySelector('#tags_input')
.addEventListener('keypress', function (e) {
postformListener(e.target, e);
});
newMessageBlock.querySelector('a').addEventListener('click', function (e) {
attachMessagePhoto(e.target);
});
}
e.preventDefault();
});
}
document.querySelectorAll('article').forEach(function (article) {
if (Array.prototype.some.call(
article.querySelectorAll('.msg-tags a'),
function (a) {
return a.textContent === 'NSFW';
}
)) {
article.classList.add('nsfw');
}
});
unfoldReply();
initWS();
window.addEventListener('hashchange', unfoldReply);
window.addEventListener('pagehide', wsShutdown);
killy.embedAll();
});