function escapeHTML(str) { return str.replace(/[&<>"'`=\/]/g, function(s) { return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/', '`': '`', '=': '=' }[s]; }); } class API { static request(post, base, method, params, callback) { $.ajax({ url: '/api/' + base + '/' + method, method: post ? 'POST' : 'GET', data: params, success: cb => { if(cb.error === 'null') callback(true, null, cb.warnings, cb); else callback(false, this.responsify(cb.error), cb.warnings, cb); }, error: cb => callback(false, null, null, cb) }); } static responsify(response) { var r = (type, text) => ({type: type, text: text}); return { not_logged_in: r('error', 'Not logged in (✖╭╮✖)'), invalid_request: r('error', 'Invalid request 【ツ】'), video_not_found: r('error', 'Video not found. Perhaps it has already been deleted'), insufficient_permissions: r('error', 'Insufficient permissions ┌∩┐(◣_◢)┌∩┐'), no_tags_specified: r('error', 'No tags specified') }[response]; } } class Video { constructor() { let match = location.href.match(/(\d+)(?!.*\/.)/); if(!match) return; this.id = match[1]; this.user = $('.fa-info-circle').next().children().text().trim(); this.tags = $.makeArray($('#tag-display').children().children()).map(el => el.innerText).filter(tag => !!tag); this.api = 'video'; this.apiBase = this.api + '/' + this.id; } tag(tags, callback) { var _this = this; function preCallback(success, error, warnings, cb) { if(success) { _this.tags = []; _this.tags = cb.tags.map(tag => tag.name); } callback(success, error, warnings, cb); } tags.length ? API.request(true, this.apiBase, 'tag', {tags: tags}, preCallback) : callback(false, API.responsify('no_tags_specified'), null, null); } untag(tag, callback) { var _this = this; function preCallback(success, error, warnings, cb) { if(success) { _this.tags = []; _this.tags = cb.tags.map(tag => tag.name); } callback(success, error, warnings, cb); } tag = tag.trim(); !!tag ? API.request(true, this.apiBase, 'untag', {tag: tag}, preCallback) : callback(false, API.responsify('invalid_request'), null, null); } delete(reason, callback) { reason = reason.trim(); !!reason ? API.request(true, this.apiBase, 'delete', {reason: reason}, callback) : callback(false, API.responsify('invalid_request'), null, null); } } var video; $(function() { video = new Video(); if(!video.id) video = null; }); //CSRF Token AjaxSetup $(function() { $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content') } }); }); function flash(type, message) { var html = ''; var alerts = $('.flashcontainer > .flash-inner'); if(type === 'error') type = 'danger'; alerts.append(html.replace(/:TYPE:/, type).replace(/:REPLACE:/, message)); alertrm(jQuery); } window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60);}; })(); Array.prototype.average = function() { var sum = 0; for(var i = 0; i < this.length; i++) sum += this[i]; return sum / this.length; }; var videoElem = document.getElementById('video'); if(videoElem !== null) { if($.browser.mobile) { let src_split = document.querySelector("video > source:first-child").src.split("/"); src_split = src_split[src_split.length - 1]; videoElem.setAttribute("poster", "//w0bm.com/thumbs/" + src_split.replace(".webm", ".gif")); } var player = videojs(videoElem, { controls: true, autoplay: true, playbackRates: [0.25, 0.5, 1, 1.5, 2], inactivityTimeout: 850, controlBar: { children: { 'progressControl': {}, 'playToggle': {}, 'MuteToggle': {}, 'volumeControl': {}, 'currentTimeDisplay': {}, 'timeDivider': {}, 'durationDisplay': {}, 'CustomControlSpacer': {}, 'playbackRateMenuButton': {}, 'fullscreenToggle': {} } } }, function() { this.addClass('video-js'); this.volume(0.3); this.muted(false); if (typeof localStorage != "undefined") { this.volume(Math.abs(localStorage.getItem("volume") || 0.3)); // 1/x to detect the special case of -0 for saving volume level 0 and the mute button being activated this.muted(0 > 1/(localStorage.getItem("volume") || 0.3)); this.on("volumechange", function () { localStorage.setItem("volume", (this.volume() * (this.muted() ? -1 : 1))); }); } }); //player.on('mouseout', function(){ this.userActive(false) }); //videojs fix for firefox if(player.autoplay() && !player.paused() && player.hasClass('vjs-paused')) { player.pause(); player.play(); } if($.browser.mobile) { document.addEventListener("fullscreenerror", function(e) { console.error("Fullscreen denied", JSON.stringify(e)); }); window.screen.orientation.onchange = function() { if(this.type.startsWith("landscape")) player.requestFullscreen(); else player.exitFullscreen(); if(!document.fullscreenElement) console.error("No fullscreen after request"); }; } if(localStorage.getItem('background') == undefined) { if($.browser.mobile) localStorage.setItem('background', 'false'); else localStorage.setItem('background', 'true'); } var background = localStorage.getItem('background') === 'true'; var canvas = document.getElementById('bg'); var context = canvas.getContext('2d'); var cw = canvas.width = canvas.clientWidth | 0; var ch = canvas.height = canvas.clientHeight | 0; if(!background) $(canvas).css('display', 'none'); function animationLoop() { if(videoElem.paused || videoElem.ended || !background) return; context.drawImage(videoElem, 0, 0, cw, ch); window.requestAnimFrame(animationLoop); } videoElem.addEventListener('play', animationLoop); $('#togglebg').on('click', function (e) { e.preventDefault(); background = !background; localStorage.setItem('background', background.toString()); if(background) $(canvas).css('display', 'block'); else $(canvas).css('display', 'none'); animationLoop(); }); function getNext() { var next = $('#next'); if(next.css('visibility') != 'hidden') { next.get(0).click(); } } function getPrev() { var prev = $('#prev'); if(prev.css('visibility') != 'hidden') { prev.get(0).click(); } } //Key Bindings $(document).on('keydown', function(e) { if(e.defaultPrevented || e.target.nodeName.match(/\b(input|textarea)\b/i) || e.ctrlKey || e.altKey || e.shiftKey) return; //arrow keys else if(e.keyCode == 39) getNext(); else if(e.keyCode == 37) getPrev(); //gamer-style else if(e.keyCode == 65) getPrev(); else if(e.keyCode == 68) getNext(); //vi style else if(e.keyCode == 72) getPrev(); else if(e.keyCode == 76) getNext(); else if(e.keyCode == 82) //click random $('#prev').next().get(0).click(); else if(e.keyCode == 70) //add fav $('#fav').get(0).click(); else if(e.keyCode == 67) //toggle comments $(".aside").fadeToggle(localStorage.comments = !(localStorage.comments == "true")); else if(e.keyCode == 87 || e.keyCode == 38) player.volume(player.volume() + 0.1); else if(e.keyCode == 83 || e.keyCode == 40) player.volume(player.volume() - 0.1); else if(e.keyCode == 32) player.paused() ? player.play() : player.pause(); }); $('.wrapper > div:not(.aside)').on('wheel', function(e) { if(e.ctrlKey || e.altKey || e.shiftKey) return; e.preventDefault(); e.originalEvent.deltaY > 0 ? getNext() : getPrev(); }); } else { var canvas = document.getElementById('bg'); canvas.parentNode.removeChild(canvas); } function commentClickableTimestamp(e) { e.preventDefault(); if(!player) return; var match = $(e.target).text().match(/(\d{1,2}):(\d{2})/); if(match) { var seek = parseInt(match[1]) * 60 + parseInt(match[2]); if(seek <= player.duration()) player.currentTime(seek); } } $(function() { $('.comment_clickable_timestamp').on('click', commentClickableTimestamp); }); (function ($) { // Comments var commentform = $('#commentForm > form'); let lastComment = ""; commentform.on('submit', function (e) { e.preventDefault(); // double comment prevention: const data = commentform.serialize(); if (data == lastComment) { alert("nope. just don't. seriously... don't."); return false; } lastComment = data; $.ajax({ type: 'POST', url: commentform.attr('action'), data: data }).done(function (data) { $('.nocomments').remove(); var comment = $(data).appendTo('.commentwrapper').find('time.timeago'); comment.timeago(); comment.tooltip(); comment.closest('.panel-footer').siblings('.panel-body').find('.comment_clickable_timestamp').on('click', commentClickableTimestamp); var textarea = commentform.find('textarea').val(''); textarea.blur(); }).fail(function(){ flash('error', 'Error saving comment'); }); }); //Tags let tagsinput = $('#tags'), submit = $('#submittags'), tagdisplay = $('#tag-display'); function tagmd() { let elReplace = (el, regex, fn) => el.innerHTML = el.innerHTML.replace(regex, fn); tagdisplay.children().children(':first-of-type').each((i, el) => { elReplace(el, /^nsfw$/i, x => '' + x + ''); elReplace(el, /^sfw$/i, x => '' + x + ''); }); } tagmd(); function tagDeleteHandler(e) { e.preventDefault(); if(!confirm('Do you really want to delete this tag?')) return; video.untag($(this).siblings().text(), (success, error, warnings, cb) => { if(success) { flash('success', 'Tag successfully deleted'); let tags = []; for(let tag of cb.tags) tags.push('' + escapeHTML(tag.name) + ' '); tagdisplay.empty(); tagdisplay.append(tags.join(" ")); $('.delete-tag').on('click', tagDeleteHandler); tagmd(); } else flash('error', 'Error deleting tag'); }); } $('.delete-tag').on('click', tagDeleteHandler); $('#tags, #filter, #tags_upload').on('itemAdded', e => setTimeout(() => $(e.currentTarget).siblings('.bootstrap-tagsinput').children('input').val(''), 0)); tagsinput.on('beforeItemAdd', e => { for(let tag of video.tags) { if(tag.toLowerCase() === e.item.toLowerCase()) { e.cancel = true; flash('info', 'Tag already exists'); return; } } }); submit.on('click touchdown', e => { e.preventDefault(); video.tag(tagsinput.tagsinput('items'), (success, error, warnings, cb) => { if(success) { $('#tag-add-toggle').prop('checked', false); var tags = []; for(let tag of cb.tags) tags.push('' + escapeHTML(tag.name) + '' + (cb.can_edit_video ? ' ' : '') + ''); tagdisplay.empty(); tagdisplay.append(tags.join(" ")); tagsinput.tagsinput('removeAll'); $('.delete-tag').on('click', tagDeleteHandler); tagmd(); } else flash('error', 'Error saving tag(s)'); }); }); // Filter var filter = $('#filter'), submitfilter = $('#submitfilter'); submitfilter.on('click touchdown', function(e) { e.preventDefault(); $.ajax({ type: 'POST', url: submitfilter.attr('href'), data: filter.serialize() }).done(function() { flash('success', 'Filter successfully updated'); $('#filterselectmodal').modal('hide'); }).fail(function(data) { flash('error', 'Error updating filter'); }); }); })(jQuery); (function ($) { function updaterow(ctx, video) { if($('video').length) { var info = []; if(video.interpret) { info.push(' Artist: ' + video.interpret); } if(video.songtitle) { info.push(' Songtitle: ' + video.songtitle); } if(video.imgsource) { info.push(' Video Source: ' + video.imgsource); } if(video.category.name) { info.push(' Category: ' + video.category.name); } $('span.fa-info-circle').attr('data-content', info.join('
')); } else { var row = ctx.parents('tr'); row.find('span').show(); row.find('input, select').hide(); row.find('.vinterpret').html(video.interpret || ''); row.find('.vsongtitle').html(video.songtitle || ''); row.find('.vimgsource').html(video.imgsource || ''); row.find('.vcategory').html('' + video.category.name + ''); } } var indexform = $('.indexform, #webmedit'); $('.indexedit').find('input, select').hide(); if(indexform.length) { var row = $('tr'); row.on('dblclick touchdown', function(e) { var self = $(this); self.find('input, select').show(); self.find('span').hide(); }); } indexform.on('submit', function (e) { var self = $(this); e.preventDefault(); $.ajax({ type: 'POST', url: self.attr('action'), data: self.serialize() }).done(function (data) { flash('success', 'Video successfully updated'); updaterow(self, data); self.find('#webmeditmodal').modal('hide'); }).fail(function(){ flash('error', 'Error updating video'); self.find('#webmeditmodal').modal('hide'); }); }); })(jQuery); (function ($) { var favBtn = $('#fav'); favBtn.on('click touchdown', function (e) { e.preventDefault(); $.ajax({ type: 'GET', url: favBtn.attr('href') }).done(function () { var icon = favBtn.find('i'); if(icon.hasClass('fa-heart-o')) { icon.removeClass('fa-heart-o'); icon.addClass('fa-heart'); } else { icon.removeClass('fa-heart'); icon.addClass('fa-heart-o'); } }); }) })(jQuery); (function ($) { $('#togglebg').on('click touchdown', function (e) { e.preventDefault(); $.ajax({ dataType: 'json', url: $(this).attr('href'), data: {} }).done(function () { $('#bg').toggle(); }); }); })(jQuery); (function ($) { $(':not(form)[data-confirm]').on('click touchdown', function () { return confirm($(this).data('confirm')); }); })(jQuery); // Komische Scrollbar lol (wird eh nicht mehr genutzt, so seit 3 Jahren xD /*(function ($) { $("").mCustomScrollbar({ axis: 'y', theme: 'minimal', scrollInertia: 0 }); })(jQuery);*/ var alertrm = function ($) { $('.alert').each(function (index) { $(this).delay(3000 + index * 1000).slideUp(300, function() { $(this).remove(); }); }); }; alertrm(jQuery); $('#categories').imagesLoaded(function () { $('#categories').isotope({ itemSelector: '.category', percentPosition: true, layoutMode: 'masonry' }); }); $(function() { $('[data-toggle="popover"]').popover({ html: true, trigger: 'manual', container: $(this).attr('id'), placement: 'top', }).on('mouseenter', function () { var _this = this; $(this).popover('show'); $(this).siblings('.popover').on('mouseleave', function () { $(_this).popover('hide'); }); }).on('mouseleave', function () { var _this = this; setTimeout(function () { if (!$('.popover:hover').length) { $(_this).popover('hide') } }, 100); }); }); // kadse :D greetz gz (function() { new Image().src = "/images/catfart/cutf.png"; var n = document.createElement("div"); var a = new Audio(); a.addEventListener("pause", function () { n.setAttribute("class", "catfart"); }); a.addEventListener("play", function () { n.setAttribute("class", "catfart farting"); }); n.addEventListener("mouseover", function () { if (!a.paused) return; a.src = "/images/catfart/pupsi" + (Math.random()*28|0) + ".mp3"; a.play(); }); n.setAttribute("class", "catfart"); document.body.appendChild(n); })(); (function() { var v = document.getElementById("video"); if (v == null) return; var p = v.parentNode; p.style.marginBottom = "3px"; var bar = document.createElement("div"); var outerBar = document.createElement("div"); outerBar.appendChild(bar); p.appendChild(outerBar); $(outerBar).css({ height: "3px", width: "100%", overflow: "hidden", willChange: "transform", position: "absolute", bottom: "0" }); $(bar).css({ height: "inherit", width: "inherit", position: "absolute", transform: "translateX(-100%)", backgroundColor: "rgba(31, 178, 176, 0.4)" }); var update = function () { requestAnimationFrame(update); if (v.paused) return; var perc = 100 / v.duration * v.currentTime; bar.style.transform = "translateX("+(-100 + perc)+"%)"; }; update(); })(); (function($) { var comments = localStorage.comments; if (comments === undefined) localStorage.comments = true; comments = comments === undefined || comments === "true"; $(".aside").toggle(comments); $("#toggle").click(function(){$(".aside").fadeToggle(localStorage.comments = !(localStorage.comments == "true"))}); })(jQuery); $(function() { function get_loc(e) { return [ (e.clientX + $('div#thumb').width() >= $(window).width() - 10) ? e.pageX - 5 - $('div#thumb').width() : e.pageX + 5, (e.clientY + $('div#thumb').height() >= $(window).height() - 10) ? e.pageY - 5 - $('div#thumb').height() : e.pageY + 5 ]; } $('[data-thumb]').on('mouseenter', function(e) { var id = $(this).data('thumb'); var lnk = '/thumbs/' + id + '.gif'; var loc = get_loc(e); $(document.body).prepend('
'); $('div#thumb').prepend(''); $('img#thumb').text('Loading...'); $('div#thumb').css({ 'position': 'absolute', 'left': loc[0], 'top': loc[1], 'z-index': '5', 'border': '1px white solid', 'box-shadow': '5px 5px 7px 0px rgba(0,0,0,0.75)', 'color': 'white', 'background-color': '#181818' }); var img = $('img#thumb'); var thumb = $(''); thumb.load(function() { img.attr("src", $(this).attr("src")); loc = get_loc(e); $('div#thumb').css({ 'left': loc[0], 'top': loc[1] }); }); thumb.attr("src", lnk); }).on('mousemove', function(e) { $('div#thumb').css({ 'left': get_loc(e)[0], 'top': get_loc(e)[1] }); }).on('mouseleave', function() { $('#thumb').remove(); }); }); //Pagination var paginate = function(pagination, options) { var type = options.hash.type || 'middle'; var ret = ''; var pageCount = Number(pagination.pageCount); var page = Number(pagination.page); var limit; if (options.hash.limit) limit = +options.hash.limit; //page pageCount var newContext = {}; switch (type) { case 'middle': if (typeof limit === 'number') { var i = 0; var leftCount = Math.ceil(limit / 2) - 1; var rightCount = limit - leftCount - 1; if (page + rightCount > pageCount) leftCount = limit - (pageCount - page) - 1; if (page - leftCount < 1) leftCount = page - 1; var start = page - leftCount; while (i < limit && i < pageCount) { newContext = { n: start }; if (start === page) newContext.active = true; ret = ret + options.fn(newContext); start++; i++; } } else { for (var i = 1; i <= pageCount; i++) { newContext = { n: i }; if (i === page) newContext.active = true; ret = ret + options.fn(newContext); } } break; case 'previous': if (page === 1) { newContext = { disabled: true, n: 1 } } else { newContext = { n: page - 1 } } ret = ret + options.fn(newContext); break; case 'next': newContext = {}; if (page === pageCount) { newContext = { disabled: true, n: pageCount } } else { newContext = { n: page + 1 } } ret = ret + options.fn(newContext); break; case 'first': if (page === 1) { newContext = { disabled: true, n: 1 } } else { newContext = { n: 1 } } ret = ret + options.fn(newContext); break; case 'last': if (page === pageCount) { newContext = { disabled: true, n: pageCount } } else { newContext = { n: pageCount } } ret = ret + options.fn(newContext); break; } return ret; }; //enable bootstrap tooltips and timeago $(function () { var s = $.timeago.settings; var str = s.strings; s.refreshMillis = 1000; s.allowFuture = true; s.localeTitle = true; //same format as laravel diffForHumans() str.seconds = "%d seconds"; str.minute = "1 minute"; str.hour = "1 hour"; str.hours = "%d hours"; str.day = "1 day"; str.month = "1 month"; str.year = "1 year"; str.suffixFromNow = null; $('time.timeago').timeago(); $('[data-toggle="tooltip"]').tooltip(); }); // Notifications var messagesBadge = $('ul.navbar-right > li > a > span.badge'); var activeMessage; if(messagesBadge.text() > 0) { messagesBadge.css('visibility', 'visible'); } if(/\/user\/.+\/comments/i.test(location.href)) { //Comment View (function($) { if(typeof Handlebars == "undefined") return; // only on profilelayout Handlebars.registerHelper('paginate', paginate); var comlist = Handlebars.compile($('#comlist').html()); var pagination = Handlebars.compile($('#paginationtmpl').html()); var jsondata = {}; var username = location.href.match(/\/user\/(.+)\/comments/i)[1]; var getMessages = function(url) { var baseUrl = '/api/comments'; if(!url) url = baseUrl; $.getJSON(url, { 'username': username }) .done(function(data) { $('.spinner').hide(); jsondata = data; $('#list').html(comlist(data)); $('time.timeago').timeago(); $('time[data-toggle="tooltip"]').tooltip(); var page = { pagination: { page: data.current_page, pageCount: data.last_page } }; $('#pagination').html(pagination(page)); $('#pagination a').on('click touchdown', function(e) { e.preventDefault(); getMessages(baseUrl + '?page=' + $(this).data('page')); }); }); }; getMessages(); })(jQuery); } else { (function($) { if(typeof Handlebars == "undefined" || !$('#msglist').length) return; // only on profilelayout Handlebars.registerHelper('paginate', paginate); var msglist = Handlebars.compile($('#msglist').html()); var msgtmpl = Handlebars.compile($('#msgtmpl').html()); var pagination = Handlebars.compile($('#paginationtmpl').html()); var jsondata = {}; var getMessages = function(url) { var baseUrl = '/api/messages'; if(!url) url = baseUrl; $.getJSON(url) .done(function(data) { $('.spinner').hide(); jsondata = data; $('#list').html(msglist(data)); if(typeof activeMessage != "undefined") $('#listitems a[data-id="' + activeMessage + '"]').addClass('active'); var page = { pagination: { page: data.current_page, pageCount: data.last_page } }; $('#pagination').html(pagination(page)); $('#pagination a').on('click touchdown', function(e) { e.preventDefault(); getMessages(baseUrl + '?page=' + $(this).data('page')); }); $('#listitems a').on('click touchdown', function(e) { e.preventDefault(); var self = $(this); var i = self.data('index'); activeMessage = $(this).data('id'); $('#message').html(msgtmpl(jsondata.data[i])); if(!jsondata.data[i].read) { $.post('/api/messages/read','m_ids[]=' + self.data('id')) .done(function(data) { self.removeClass('list-group-item-info'); messagesBadge.text(messagesBadge.text() - 1); if(messagesBadge.text() <= 0) { messagesBadge.css('visibility', 'hidden'); } }); } $('a').removeClass('active'); self.addClass('active'); $('time.timeago').timeago(); $('time[data-toggle="tooltip"]').tooltip(); }); }); }; getMessages(); })(jQuery); } function readAll() { $.ajax({ url: '/api/messages/readall', success: function(data) { if(data == 1) { flash('success', 'Marked all messages as read'); $('.list-group-item-info').removeClass('list-group-item-info'); messagesBadge.text('0'); messagesBadge.css('visibility', 'hidden'); } else { flash('error', 'Failed to mark all messages as read'); } }, error: function(jqxhr, status, error) { flash('error', 'Failed to mark all messages as read'); } }); } $('ul.dropdown-menu').on('click touchdown', function(e) { e.stopPropagation(); }); function deleteComment(self) { var comment = self.closest('div[data-id]'); var id = comment.data('id'); var username = $(comment.children('.panel-footer').children('a')[0]).text(); do { var reason = prompt('Reason for deleting comment ' + id + ' by ' + username); if(reason === null) return; reason = reason.trim(); } while(!reason); $.ajax({ url: '/api/comments/' + id + '/delete', method: 'POST', data: { reason: reason }, success: function(retval) { if(retval == 'success') { flash('success', 'Comment deleted'); comment.removeClass('panel-default').addClass('panel-danger'); comment.find('.panel-footer').children('a[onclick="deleteComment($(this))"]').replaceWith(''); comment.find('.panel-footer > a[onclick="editComment($(this))"]').remove(); } else if(retval == 'invalid_request') flash('error', 'Invalid request'); else if(retval == 'not_logged_in') flash('error', 'Not logged in'); else if(retval == 'insufficient_permissions') flash('error', 'Insufficient permissions'); else flash('error', 'Error deleting comment'); }, error: function(jqxhr, status, error) { flash('error', 'Error deleting comment'); } }); } function restoreComment(self) { var comment = self.closest('div[data-id]'); var id = comment.data('id'); var username = $(comment.children('.panel-footer').children('a')[0]).text(); do { var reason = prompt('Reason for restoring comment ' + id + ' by ' + username); if(reason === null) return; reason = reason.trim(); } while(!reason); $.ajax({ url: '/api/comments/' + id + '/restore', method: 'POST', data: { reason: reason }, success: function(retval) { if(retval == 'success') { flash('success', 'Comment restored'); comment.removeClass('panel-danger').addClass('panel-default'); comment.find('.panel-footer').children('a[onclick]').replaceWith(' '); } else if(retval == 'invalid_request') flash('error', 'Invalid request'); else if(retval == 'not_logged_in') flash('error', 'Not logged in'); else if(retval == 'insufficient_permissions') flash('error', 'Insufficient permissions'); else if(retval == 'comment_not_deleted') flash('error', 'Comment is not deleted'); else flash('error', 'Error restoring comment'); }, error: function(jqxhr, status, error) { flash('error', 'Error restoring comment'); } }); } function editComment(self) { var comment = self.closest('div[data-id]'); var body = comment.find('.panel-body'); var id = comment.data('id'); $.ajax({ url: '/api/comments/' + id, success: function(retval) { if(retval.error == 'null') { var textarea = $('