journalduhacker/app/assets/javascripts/application.js.erb
joshua stein de176d80dd story tags: sort by exact tag matches first, then description matches
select2 has sortResults in newer versions but so much crap changed
there that it's easier to just hack in support for this here

fixes #251
2015-12-14 10:44:28 -06:00

469 lines
13 KiB
Plaintext

//= require jquery
//= require jquery_ujs
//= require_tree .
"use strict";
var _Lobsters = Class.extend({
curUser: null,
storyFlagReasons: { <%= Vote::STORY_REASONS.map{|k,v|
"#{k.inspect}: #{v.inspect}" }.join(", ") %> },
commentDownvoteReasons: { <%= Vote::COMMENT_REASONS.map{|k,v|
"#{k.inspect}: #{v.inspect}" }.join(", ") %> },
upvoteStory: function(voterEl) {
Lobsters.vote("story", voterEl, 1);
},
flagStory: function(voterEl) {
Lobsters._showDownvoteWhyAt("story", voterEl, function(k) {
Lobsters.vote("story", voterEl, -1, k); });
},
hideStory: function(hiderEl) {
if (!Lobsters.curUser)
return Lobsters.bounceToLogin();
var li = $(hiderEl).closest(".story, .comment");
var act;
if (li.hasClass("hidden")) {
act = "unhide";
li.removeClass("hidden");
hiderEl.innerHTML = "hide";
}
else {
act = "hide";
li.addClass("hidden");
hiderEl.innerHTML = "unhide";
}
$.post("/stories/" + li.attr("data-shortid") + "/" + act);
},
upvoteComment: function(voterEl) {
Lobsters.vote("comment", voterEl, 1);
},
downvoteComment: function(voterEl) {
Lobsters._showDownvoteWhyAt("comment", voterEl, function(k) {
Lobsters.vote("comment", voterEl, -1, k); });
},
_showDownvoteWhyAt: function(thingType, voterEl, onChooseWhy) {
if (!Lobsters.curUser)
return Lobsters.bounceToLogin();
var li = $(voterEl).closest(".story, .comment");
if (li.hasClass("downvoted")) {
/* already upvoted, neutralize */
Lobsters.vote(thingType, voterEl, -1, null);
return;
}
if ($("#downvote_why"))
$("#downvote_why").remove();
if ($("#downvote_why_shadow"))
$("#downvote_why_shadow").remove();
var sh = $("<div id=\"downvote_why_shadow\"></div>");
$(voterEl).after(sh);
sh.click(function() {
$("#downvote_why_shadow").remove();
$("#downvote_why").remove();
});
var d = $("<div id=\"downvote_why\"></div>");
var reasons;
if (thingType == "comment")
reasons = Lobsters.commentDownvoteReasons;
else
reasons = Lobsters.storyFlagReasons;
$.each(reasons, function(k, v) {
var a = $("<a href=\"#\"" + (k == "" ? " class=\"cancelreason\"" : "") +
">" + v + "</a>");
a.click(function() {
$("#downvote_why").remove();
$("#downvote_why_shadow").remove();
if (k != "")
onChooseWhy(k);
return false;
});
d.append(a);
});
$(voterEl).after(d);
d.position({
my: "left top",
at: "left bottom",
offset: "-2 -2",
of: $(voterEl),
collision: "none",
});
/* XXX: why is this needed? */
if (thingType == "story")
d.css("left", $(voterEl).position().left);
},
vote: function(thingType, voterEl, point, reason) {
if (!Lobsters.curUser)
return Lobsters.bounceToLogin();
var li = $(voterEl).closest(".story, .comment");
var scoreDiv = li.find("div.score").get(0);
var score = parseInt(scoreDiv.innerHTML);
var action = "";
if (li.hasClass("upvoted") && point > 0) {
/* already upvoted, neutralize */
li.removeClass("upvoted");
score--;
action = "unvote";
}
else if (li.hasClass("downvoted") && point < 0) {
/* already downvoted, neutralize */
li.removeClass("downvoted");
score++;
action = "unvote";
}
else if (point > 0) {
if (li.hasClass("downvoted"))
/* flip flop */
score++;
li.removeClass("downvoted").addClass("upvoted");
score++;
action = "upvote";
}
else if (point < 0) {
if (li.hasClass("upvoted"))
/* flip flop */
score--;
li.removeClass("upvoted").addClass("downvoted");
score--;
action = "downvote";
}
scoreDiv.innerHTML = score;
if (action == "upvote" || action == "unvote") {
li.find(".reason").html("");
if (action == "unvote" && thingType == "story" && point < 0)
li.find(".flagger").text("flag");
}
else if (action == "downvote" && thingType == "comment")
li.find(".reason").html("| " +
Lobsters.commentDownvoteReasons[reason].toLowerCase());
else if (action == "downvote" && thingType == "story")
li.find(".flagger").text("unflag");
$.post("/" + (thingType == "story" ? "stories" : thingType + "s") + "/" +
li.attr("data-shortid") + "/" +
action, { reason: reason });
},
postComment: function(form) {
$.post($(form).attr("action"), $(form).serializeArray(), function(data) {
if ($(form).find('#parent_comment_short_id').length) {
$(form).closest('.comment').replaceWith($.parseHTML(data));
} else {
if ($(form).attr("id").match(/^edit_comment_.+$/)) {
$(form).parent(".comment").replaceWith($.parseHTML(data));
} else {
$(form).closest('.comment').after($.parseHTML(data));
$(form).find('textarea').val('');
}
}
});
},
previewComment: function(form) {
var params = $(form).serializeArray();
params.push({"name": "preview", "value": "true"});
$.post($(form).attr("action"), params, function(data) {
var da = $.parseHTML(data);
var ta = $(da).find("textarea");
$(form).closest(".comment").replaceWith(da);
autosize(ta);
});
},
previewStory: function(form) {
$("#inside").load("/stories/preview", $(form).serializeArray());
},
moderateStory: function(link) {
var reason = prompt("Moderation reason:");
if (reason == null || reason == "")
return false;
var link = $(link);
/* $.rails.handleMethod() */
var href = $.rails.href(link),
method = link.data('method'),
target = link.attr('target'),
csrf_token = $("meta[name=csrf-token]").attr("content"),
csrf_param = $("meta[name=csrf-param]").attr("content"),
form = $("<form method=\"post\" action=\"" + href + "\"></form>"),
metadata_input = "<input name=\"_method\" value=\"" + method +
"\" type=\"hidden\" />";
if (csrf_param !== undefined && csrf_token !== undefined)
metadata_input += "<input name=\"" + csrf_param + "\" value=\"" +
csrf_token + "\" type=\"hidden\" />";
if (target)
form.attr("target", target);
var r = $("<input type=\"hidden\" name=\"reason\" />");
r.val(reason);
form.append(r);
form.hide().append(metadata_input).appendTo('body');
form.submit();
return false;
},
fetchURLTitle: function(button, url_field, title_field) {
if (url_field.val() == "")
return;
var old_value = button.val();
button.prop("disabled", true);
button.val("Fetching...");
$.post("/stories/fetch_url_attributes", {
fetch_url: url_field.val(),
})
.success(function(data) {
if (data) {
if (data.title)
title_field.val(data.title.substr(0, title_field.maxLength));
if (data.url)
url_field.val(data.url);
}
button.val(old_value);
button.prop("disabled", false);
})
.error(function() {
button.val(old_value);
button.prop("disabled", false);
});
},
bounceToLogin: function() {
document.location = "/login?return=" +
encodeURIComponent(document.location);
return false;
},
});
var Lobsters = new _Lobsters();
$(document).ready(function() {
$(".comment a.downvoter").click(function() {
Lobsters.downvoteComment(this);
return false;
});
$(".comment a.upvoter").click(function() {
Lobsters.upvoteComment(this);
return false;
});
$("li.story a.flagger").click(function() {
Lobsters.flagStory(this);
return false;
});
$("li.story a.upvoter").click(function() {
Lobsters.upvoteStory(this);
return false;
});
$("li.story a.hider").click(function() {
Lobsters.hideStory(this);
return false;
});
$("li.story a.mod_story_link").click(function() {
return Lobsters.moderateStory(this);
}),
$(document).on("click", "a.comment_replier", function() {
if (!Lobsters.curUser) {
Lobsters.bounceToLogin();
return false;
}
var comment = $(this).closest(".comment");
if ($("#reply_form_" + comment.attr("id")).length > 0)
return false;
var sel = "";
if (window.getSelection)
sel = window.getSelection().toString();
else if (document.selection && document.selection.type != "Control")
sel = document.selection.createRange().text;
if (sel != "") {
var t = "";
$.each(sel.split("\n"), function(k, v) {
t += (t == "" ? "" : "\n") + "> " + v;
});
sel = t;
if (sel != "")
sel += "\n\n";
}
var replies = comment.nextAll(".comments").first();
$.get("/comments/" + comment.attr("data-shortid") + "/reply",
function(data) {
var reply = $($.parseHTML(data));
reply.attr("id", "reply_form_" + comment.attr("id"));
replies.prepend(reply);
var ta = reply.find("textarea");
ta.focus().text(sel);
autosize(ta);
});
return false;
});
$(document).on("click", "button.comment-cancel", function() {
var comment = $(this).closest(".comment");
var comment_id = comment.attr("data-shortid");
if (comment_id != null && comment_id !== '') {
$.get("/comments/" + comment_id, function(data) {
comment.replaceWith($.parseHTML(data));
});
} else {
comment.remove();
}
});
$(document).on("click", "a.comment_editor", function() {
var comment = $(this).closest(".comment");
$.get("/comments/" + comment.attr("data-shortid") + "/edit",
function(data) {
comment.replaceWith($.parseHTML(data));
});
});
$(document).on("click", "a.comment_deletor", function() {
if (confirm("Are you sure you want to delete this comment?")) {
var li = $(this).closest(".comment");
$.post("/comments/" + $(li).attr("data-shortid") + "/delete",
function(d) {
$(li).replaceWith(d);
});
}
});
$(document).on("click", "a.comment_undeletor", function() {
if (confirm("Are you sure you want to undelete this comment?")) {
var li = $(this).closest(".comment");
$.post("/comments/" + $(li).attr("data-shortid") + "/undelete",
function(d) {
$(li).replaceWith(d);
});
}
});
$("#story_tags_a").select2({
formatSelection: function(what) {
return what.id;
},
matcher: function(term, text) {
return text.toUpperCase().indexOf(term.toUpperCase()) >= 0;
},
sortResults: function(results, container, query) {
if (query.term) {
var tmatches = [];
var dmatches = [];
/* prefer tag matches first, then description matches */
for (var x in results) {
var r = results[x];
if (r.id.toUpperCase().indexOf(query.term.toUpperCase()) == 0)
tmatches.push(r);
else
dmatches.push(r);
}
tmatches = tmatches.sort(function(a, b) {
return a.text.localeCompare(b.text);
});
dmatches = dmatches.sort(function(a, b) {
return a.text.localeCompare(b.text);
});
return tmatches.concat(dmatches);
}
return results;
}
});
$(document).on("click", "div.markdown_help_toggler .markdown_help_label",
function() {
$(this).parents("div.markdown_help_toggler").first().
children(".markdown_help").toggle();
});
$(document).on("click", "button.comment-post", function() {
Lobsters.postComment($(this).parents("form").first());
});
$(document).on("click", "button.comment-preview", function() {
Lobsters.previewComment($(this).parents("form").first());
});
$(document).on("click", "button.story-preview", function() {
Lobsters.previewStory($(this).parents("form").first());
});
$(document).on("blur", "#story_url", function() {
var url_tags = {
"\.pdf$": "pdf",
"[\/\.]((youtube|vimeo)\.com|youtu\.be)\/": "video",
"[\/\.](slideshare\.net|speakerdeck\.com)\/": "slides",
"[\/\.](soundcloud\.com)\/": "audio",
};
for (var u in url_tags) {
var tag = url_tags[u];
if ($("#story_url").val().match(new RegExp(u, "i"))) {
var ta = $("#story_tags_a").data("select2");
if (ta.getVal().indexOf(tag) < 0)
ta.addSelectedChoice({ id: tag });
}
}
});
$(document).on("blur", "#story_title", function() {
var m;
if (m = $("#story_title").val().match(/^(show|ask) lobste\.?rs:? (.+)$/i)) {
var ta = $("#story_tags_a").data("select2");
if (ta.getVal().indexOf(m[1].toLowerCase()) < 0)
ta.addSelectedChoice({ id: m[1].toLowerCase() });
$("#story_title").val(m[2]);
}
});
$(document).on("click", "#story_guidelines_toggler", function() {
$("#story_guidelines").toggle();
return false;
});
});