diff options
Diffstat (limited to 'juick-spring-www/src/main/webapp/static/scripts.js')
-rw-r--r-- | juick-spring-www/src/main/webapp/static/scripts.js | 753 |
1 files changed, 753 insertions, 0 deletions
diff --git a/juick-spring-www/src/main/webapp/static/scripts.js b/juick-spring-www/src/main/webapp/static/scripts.js new file mode 100644 index 00000000..d368cacd --- /dev/null +++ b/juick-spring-www/src/main/webapp/static/scripts.js @@ -0,0 +1,753 @@ +var autosize = require('autosize'); +require('whatwg-fetch'); +require('element-closest'); +require('classlist.js'); +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; + +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) { + var li = document.createElement('li'); + li.setAttribute('class', 'msg reply-new'); + li.setAttribute('id', msg.rid); + li.addEventListener('click', newReply); + li.addEventListener('mouseover', newReply); + var msgAvatar = document.createElement('div'); + msgAvatar.setAttribute('class', 'msg-avatar'); + var msgAvatarLink = document.createElement('a'); + msgAvatarLink.setAttribute('href', '/' + msg.user.uname + '/'); + var msgAvatarImg = document.createElement('img'); + msgAvatarImg.setAttribute('src', '//i.juick.com/a/' + msg.user.uid + '.png'); + msgAvatarLink.appendChild(msgAvatarImg); + msgAvatar.appendChild(msgAvatarLink); + + var msgCont = document.createElement('div'); + msgCont.setAttribute('class', 'msg-cont'); + var msgMenu = document.createElement('div'); + msgMenu.setAttribute('class', 'msg-menu'); + msgCont.appendChild(msgMenu); + var msgMenuLink = document.createElement('a'); + msgMenuLink.setAttribute('href', '#'); + msgMenuLink.addEventListener('click', function (e) { + showMessageLinksDialog(msg.mid, msg.rid); + e.preventDefault(); + }); + msgMenu.appendChild(msgMenuLink); + var msgHeader = document.createElement('div'); + msgHeader.setAttribute('class', 'msg-header'); + var msgHeaderLink = document.createElement('a'); + msgHeaderLink.setAttribute('href', '/' + msg.user.uname + '/'); + msgHeaderLink.textContent = '@' + msg.user.uname + ':'; + msgHeader.appendChild(msgHeaderLink); + var msgTimestamp = document.createElement('div'); + msgTimestamp.setAttribute('class', 'msg-ts'); + var msgTimestampLink = document.createElement('a'); + msgTimestampLink.setAttribute('href', '/' + msg.mid + '#' + msg.rid); + msgTimestampLink.setAttribute('title', msg.timestamp + ' GMT'); + msgTimestampLink.textContent = msg.timestamp; + msgTimestamp.appendChild(msgTimestampLink); + var msgTxt = document.createElement('div'); + msgTxt.setAttribute('class', 'msg-txt'); + var msgLinks = document.createElement('div'); + msgLinks.setAttribute('class', 'msg-links'); + var msgNum = '/' + msg.rid; + if (msg.replyto > 0) { + msgNum += ' в ответ на <a href="#' + msg.replyto + '">/' + msg.replyto + '</a>'; + } + msgLinks.innerHTML = msgNum + ' · '; + var msgLinksLink = document.createElement('a'); + msgLinksLink.setAttribute('href', '#'); + msgLinksLink.textContent = 'Ответить'; + msgLinksLink.addEventListener('click', function (e) { + showCommentForm(msg.mid, msg.rid); + e.preventDefault(); + }); + msgLinks.appendChild(msgLinksLink); + var msgComment = document.createElement('div'); + msgComment.setAttribute('class', 'msg-comment'); + msgComment.style.display = 'none'; + msgHeader.appendChild(msgAvatar); + msgHeader.appendChild(msgMenu); + msgHeader.appendChild(msgTimestamp); + msgCont.appendChild(msgHeader); + msgCont.appendChild(msgTxt); + msgCont.appendChild(msgLinks); + msgCont.appendChild(msgComment); + li.appendChild(msgCont); + + li.querySelector('.msg-txt').textContent = msg.body; + + if (isTreeMode() && (msg.replyto > 0)) { + var p = document.getElementById(msg.replyto); + var 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.childNodes[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) { + var form = formEl.closest('form'); + if (ev.ctrlKey && (ev.keyCode == 10 || ev.keyCode == 13)) { + if (!form.onsubmit || form.onsubmit()) { + form.submit(); + } + } +} + +function unfoldPostForm() { + if (window.location.pathname === '/' && window.location.hash === '#post') { + document.querySelector('#newmessage>div').style.display = 'block'; + var ta = document.querySelector('#newmessage textarea'); + ta.style.minHeight = '70px'; + ta.focus(); + } +} + +function newMessage() { + if (document.querySelector('#newmessage textarea').value.length == 0) { + openDialog('<p class="dialogtxt">Пожалуйста, введите текст сообщения</p>'); + return false; + } + return true; +} + +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 replyForm(mid, rid) { + var form = document.createElement('form'); + form.setAttribute('action', '/comment'); + form.setAttribute('method', 'POST'); + form.setAttribute('enctype', 'multipart/form-data'); + var input = document.createElement('input'); + input.setAttribute('type', 'hidden'); + input.setAttribute('name', 'mid'); + input.setAttribute('value', mid); + form.appendChild(input); + if (rid) { + var inputRid = document.createElement('input'); + inputRid.setAttribute('type', 'hidden'); + inputRid.setAttribute('name', 'rid'); + inputRid.setAttribute('value', rid); + form.appendChild(inputRid); + } + return form; +} + +function taWrapper() { + var txtarea = document.createElement('textarea'); + txtarea.setAttribute('name', 'body'); + txtarea.setAttribute('rows', 1); + txtarea.setAttribute('class', 'reply narrow'); + txtarea.setAttribute('placeholder', 'Написать комментарий...'); + var txtKeypress = function (e) { + postformListener(e.target, e); + }; + txtarea.addEventListener('keypress', txtKeypress); + var wrapper = document.createElement('div'); + wrapper.setAttribute('class', 'ta-wrapper'); + wrapper.appendChild(txtarea); + var att = document.createElement('div'); + att.setAttribute('class', 'attach-photo'); + att.addEventListener('click', function () { + attachCommentPhoto(this); + }); + wrapper.appendChild(att); + return wrapper; +} + +function showCommentForm(mid, rid) { + var reply = document.getElementById(rid); + if (reply && !reply.querySelector('textarea')) { + var c = reply.querySelector('div.msg-cont > .msg-comment'), + newNode = c.cloneNode(true), + form = replyForm(mid, rid); + form.appendChild(newNode); + newNode.appendChild(taWrapper()); + var subm = document.createElement('input'); + subm.setAttribute('type', 'submit'); + subm.setAttribute('value', 'OK'); + newNode.appendChild(subm); + c.parentNode.insertBefore(form, c); + c.remove(); + } + + var commentBlock = reply.querySelector('div.msg-cont > form > div.msg-comment'); + commentBlock.style.display = 'block'; + var commentText = commentBlock.querySelector('textarea'); + if (commentText) { + autosize(commentText); + commentText.focus(); + } +} + +function showCommentFooter(e, mid, rid) { + var a = e.closest('article'); + if (!a.querySelector('footer.comm')) { + var form = replyForm(mid, rid), + footer = document.createElement('footer'); + footer.setAttribute('class', 'comm'); + footer.appendChild(taWrapper()); + var subm = document.createElement('input'); + subm.setAttribute('type', 'submit'); + subm.setAttribute('value', 'OK'); + footer.appendChild(subm); + form.appendChild(footer); + a.appendChild(form); + autosize(a.querySelector('textarea')); + } + a.querySelector('textarea').focus(); +} + +function attachInput() { + var 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) { + if (div.children.length === 0) { + var inp = attachInput(); + inp.addEventListener('change', function () { + inp.parentNode.classList.add('attach-photo-active'); + }); + inp.click(); + div.appendChild(inp); + } else { + div.innerHTML = null; + div.classList.add('attach-photo'); + } +} + +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 = 'загрузить (✓)'; + }); + f.appendChild(inp); + inp.click(); + } else { + finput.remove(); + div.textContent = 'загрузить'; + } +} + +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) { + var hlink = window.location.protocol + '//juick.com/' + mid, + mlink = '#' + mid; + if (rid > 0) { + hlink += '#' + rid; + mlink += '/' + rid; + } + var hlinkenc = encodeURIComponent(hlink), + html = '<div class="dialogshare">Ссылка на сообщение:' + + '<div onclick="this.selectText()" class="dialogl">' + hlink + '</div>' + + 'Номер сообщения:' + + '<div onclick="this.selectText()" class="dialogl">' + mlink + '</div>' + + 'Поделиться:<ul>' + + '<li><a href="https://www.facebook.com/sharer/sharer.php?u=' + hlinkenc + '" onclick="return openSocialWindow(this)"></a></li>' + + '<li><a href="https://twitter.com/intent/tweet?url=' + hlinkenc + '" onclick="return openSocialWindow(this)" style="background-position: -32px 0;"></a></li>' + + '<li><a href="https://vk.com/share.php?url=' + hlinkenc + '" onclick="return openSocialWindow(this)" style="background-position: -64px 0;"></a></li>' + + '<li><a href="https://plus.google.com/share?url=' + hlinkenc + '" onclick="return openSocialWindow(this)" style="background-position: -96px 0;"></a></li>' + + '</ul></div>'; + + openDialog(html); +} + +function showPhotoDialog(fname) { + var width = window.innerWidth, + height = window.innerHeight * 0.9; + if (width < 640) { + return true; + } else if (width < 1280) { + openDialog('<a href="//i.juick.com/photos-1024/' + fname + '"><img src="//i.juick.com/photos-512/' + fname + '"/></a>'); + document.querySelector('#dialogw img').style.maxHeight = height + 'px'; + return false; + } else { + openDialog('<a href="//i.juick.com/p/' + fname + '"><img src="//i.juick.com/photos-1024/' + fname + '"/></a>'); + document.querySelector('#dialogw img').style.maxHeight = height + 'px'; + return false; + } +} + +function openDialog(html) { + var dhtml = '<table id="dialogt"><tr><td><div id="dialogb"></div><div id="dialogw"><div id="dialogc"></div>' + html + '</div></td></tr></table>'; + document.querySelector('body').insertAdjacentHTML('afterbegin', dhtml); + document.querySelector('#dialogb').addEventListener('click', closeDialog); + document.querySelector('#dialogc').addEventListener('click', closeDialog); +} + +function closeDialog() { + 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() { + var html = '<div class="dialoglogin"><p>Пожалуйста, представьтесь:' + + '<a href="/_fblogin" id="signfb">Facebook</a> ' + + '<a href="/_vklogin" id="signvk">ВКонтакте</a></p>' + + '<p>Уже зарегистрированы?</p>' + + '<form action="/login" method="POST">' + + '<input class="signinput" type="text" name="username" placeholder="Имя пользователя"/><br/>' + + '<input class="signinput" type="password" name="password" placeholder="Пароль"/><br/>' + + '<input class="signsubmit" type="submit" value="OK"/>' + + '</form></div>'; + openDialog(html); + return false; +} + +/******************************************************************************/ + +function resultMessage(str) { + var result = document.createElement('p'); + result.textContent = str; + return result; +} + +function likeMessage(e, mid) { + if (confirm('Are you sure?')) { + 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('Ошибка')); + }); + } + 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; +} +/******************************************************************************/ + +Element.prototype.selectText = function () { + var d = document; + if (d.body.createTextRange) { + var range = d.body.createTextRange(); + range.moveToElementText(this); + range.select(); + } else if (window.getSelection) { + var selection = window.getSelection(); + var rangeSel = d.createRange(); + rangeSel.selectNodeContents(this); + selection.removeAllRanges(); + selection.addRange(rangeSel); + } +}; + +function ready(fn) { + if (document.readyState != 'loading') { + fn(); + } else { + document.addEventListener('DOMContentLoaded', fn); + } +} + +ready(function () { + autosize(document.querySelectorAll('textarea')); + + var insertButtons = function (e) { + var textarea = e.target; + textarea.classList.add('narrow'); + var att = document.createElement('div'); + att.classList.add('attach-photo'); + att.addEventListener('click', function(e) { + attachCommentPhoto(e.target); + }); + textarea.parentNode.insertBefore(att, textarea.nextSibling); + textarea.parentNode.insertAdjacentHTML('afterend', '<input type="submit" value="OK"/>'); + textarea.removeEventListener('click', insertButtons); + e.preventDefault(); + }; + document.querySelectorAll('textarea.reply').forEach(function(e) { + e.addEventListener('click', insertButtons); + e.addEventListener('keypress', function(e) { + postformListener(e.target, e); + }); + }); + + var insertPMButtons = function (e) { + e.target.classList.add('narrowpm'); + e.target.parentNode.insertAdjacentHTML('afterend', '<input type="submit" value="OK"/>'); + e.target.removeEventListener('click', insertPMButtons); + e.preventDefault(); + }; + document.querySelectorAll('textarea.replypm').forEach(function(e) { + e.addEventListener('click', insertPMButtons); + }); + + var content = document.getElementById('content'); + if (content) { + var pageMID = content.getAttribute('data-mid'); + if (pageMID > 0) { + document.querySelectorAll('.msg-comments').forEach(function(e) { + e.addEventListener('click', function (e) { + var rid = e.target.closest('li').id; + showMoreReplies(e.target, rid); + e.preventDefault(); + }); + }); + document.querySelectorAll('.a-thread-comment').forEach(function(e) { + e.addEventListener('click', function (e) { + var rid = e.target.closest('li').id; + showCommentForm(pageMID, rid); + e.preventDefault(); + }); + }); + } + } + + document.querySelectorAll('.msg-menu a').forEach(function(el) { + el.addEventListener('click', function(e) { + showMessageLinksDialog( + e.target.closest('section').getAttribute('data-mid'), + parseInt(e.target.closest('li').id)); // rid + e.preventDefault(); + }); + }); + document.querySelectorAll('.l .a-comment').forEach(function(e) { + e.addEventListener('click', function (e) { + showCommentFooter( + e.target, + e.target.closest('article').getAttribute('data-mid')); + 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('.l .a-popular-plus').forEach(function(e) { + e.addEventListener('click', function (e) { + setPopular( + e.target, + e.target.closest('article').getAttribute('data-mid'), + 2); + e.preventDefault(); + }); + }); + document.querySelectorAll('.l .a-popular-minus').forEach(function(e) { + e.addEventListener('click', function (e) { + setPopular( + e.target, + e.target.closest('article').getAttribute('data-mid'), + -1); + e.preventDefault(); + }); + }); + document.querySelectorAll('.l .a-popular-delete').forEach(function(e) { + e.addEventListener('click', function (e) { + setPopular( + e.target, + e.target.closest('article').getAttribute('data-mid'), + -2); + e.preventDefault(); + }); + }); + document.querySelectorAll('.ir a').forEach(function(e) { + e.addEventListener('click', function (e) { + var 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(); + }); + }); + document.querySelectorAll('.attach-photo').forEach(function(el) { + el.addEventListener('click', function(e) { + attachCommentPhoto(e.target); + }); + }); + 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 newMessageBlock = document.getElementById('newmessage'); + if (newMessageBlock) { + var form = newMessageBlock.parentNode; + form.addEventListener('submit', newMessage); + newMessageBlock.querySelector('textarea').addEventListener('click', function(e) { + var parent = e.target.parentNode; + parent.querySelector('div').style.display = 'block'; + e.target.style.minHeight = '70px'; + e.target.addEventListener('keypress', function(e) { + postformListener(e.target, e); + }); + }); + newMessageBlock.querySelector('a').addEventListener('click', function(e) { + attachMessagePhoto(e.target); + }); + } + document.querySelectorAll('article').forEach(function(article) { + if (Array.prototype.some.call( + article.querySelectorAll('.u a'), + function (a) { + return a.textContent === 'NSFW'; + } + )) { + var img = article.querySelector('.ir img'); + if (img) { + img.style.opacity = 0.05; + img.addEventListener('mouseover', function(e) { + e.target.style.opacity = 1; + }); + img.addEventListener('mouseout', function(e) { + e.target.style.opacity = 0.05; + }); + } + } + }); + + unfoldPostForm(); + unfoldReply(); + initWS(); + window.addEventListener('hashchange', unfoldPostForm); + window.addEventListener('hashchange', unfoldReply); + + window.addEventListener('pagehide', wsShutdown); +}); |