review/static/comments.js @ fb401cae8830

web: add line-level comment editing support
author Steve Losh <steve@stevelosh.com>
date Sat, 03 Jul 2010 12:52:47 -0400
parents c0e1c48cd6a8
children 5dec221dd171
_.templateSettings = {
  start       : '{{',
  end         : '}}',
  interpolate : /\{\{(.+?)\}\}/g
};

var comment_form = _.template(
    '<tr class="comment-form">' +
        '<td colspan="3">' +
            '<form id="id_comment-line-form_{{ currNum }}" method="POST" action="">' +
                '<span class="lastlinenumber disabled">{{ currNum }}</span>' +
                '<div class="field">' +
                    '<label class="infield" for="id_comment-line-form_{{ currNum }}_body">Comment</label>' +
                    '<textarea id="id_comment-line-form_{{ currNum }}_body" class="body"'  +
                              'name="new-comment-body">{{ body }}</textarea>' +
                '</div>' +

                '<div class="field cuddly">' +
                    '<input type="checkbox" class="checkbox markdown-select" name="comment-markdown" id="id_comment-line-form_{{ currNum }}_markdown" {{ markdown_checked }} />' +
                    '<label for="id_comment-line-form_{{ currNum }}_markdown">Use Markdown to format this comment.</label>' +
                '</div>' +

                '<a class="submit button"><span>Post Comment</span></a>' +
                '<a class="cancel-line button"><span>Cancel</span></a>' +

                '<input type="hidden" name="filename" value="{{ filename }}" />' +
                '<input type="hidden" name="current" value="{{ identifier }}" class="current" />' +
                '<input class="lines" type="hidden" name="lines" value="{{ currNum }}" />' +
            '</form>' +
        '</td>' +
    '</tr>'
);

function RenderLineCommentForm(line, currNum, body, markdown, identifier) {
    var filename = line.closest(".file").find(".filename h3 a .name").html();
    markdown_checked = markdown ? 'checked="checked"' : '';
    return comment_form({ filename: filename, currNum: currNum, body: body,
                          markdown_checked: markdown_checked, identifier: identifier });
}

$(function() {
    $(".activate a").click(function(event) {
        $(event.target).closest(".activate").hide();
        $(event.target).closest("div").children("form").fadeIn("fast");
        return false;
    });
    $(".activate-edit a").click(function(event) {
        $(event.target).closest(".activate-edit").hide();
        $(event.target).closest(".comment").find(".message").hide();
        $(event.target).closest("div").children("form").fadeIn("fast");
        return false;
    });
    $("a.cancel").click(function(event) {
        $(event.target).closest(".togglebox").children(".activate").show();
        $(event.target).parents("form").hide();
        return false;
    });
    $("a.cancel-edit").click(function(event) {
        $(event.target).closest(".toggleinline").children(".activate-edit").show();
        $(event.target).closest(".comment").find(".message").show();
        $(event.target).parents("form").hide();
        return false;
    });
    $("a.cancel-line").live('click', function(event) {
        $(event.target).closest(".diff").find(".chosen").removeClass("chosen");
        $(event.target).closest("tr.comment-form").hide();
        $(event.target).closest(".diff").find("tr.comment").fadeIn('fast');
        $(event.target).closest("tr.comment-form").remove();
        return false;
    });
    $("a.edit-line").click(function(event) {
        var diff = $(this).closest(".diff");
        var comment = $(this).closest("tr.comment");

        diff.find(".chosen").removeClass("chosen");
        diff.find(".comment-form").remove();
        comment.hide();

        _.each($(event.target).closest(".comment").find(".commentlines").html().split(","),
               function(i) { diff.find(".line-" + i).addClass("chosen") });

        var lines_chosen = diff.find(".chosen");
        var last_line = lines_chosen.last();
        var last_line_number = parseInt(lines_chosen.find(".linenumber").last().html());
        var body = comment.find(".raw").html();
        var markdown = comment.find(".message").hasClass("markdown");
        var identifier = comment.find(".identifier").html();

        var comment_form = RenderLineCommentForm(last_line, last_line_number, body, markdown, identifier);
        last_line.after(comment_form);
        diff.find("label").inFieldLabels();

        return false;
    });

    $("tr.comment").hover(function(event) {
        var diff = $(event.target).closest(".diff");

        _.each($(event.target).find(".commentlines").html().split(","),
               function (i) { diff.find(".line-" + i).addClass("viewing"); });
    }, function(event) {
        $(".viewing").removeClass("viewing");
    });

    var lastSelected = null;
    $(".commentable").click(function(event) {
        var currNum = parseInt($(this).find(".linenumber").html());
        var diff = $(this).closest(".diff");

        if ($(this).hasClass("chosen")) {
            $(this).removeClass("chosen");

            var newLines = _.reduce(diff.find(".chosen .linenumber"), "",
                                    function(memo, lne) { return memo + $(lne).html() + ','; });
            diff.find(".comment-form form .lines").val(newLines);

            lastSelected = null;
        } else {
            if (event.shiftKey && lastSelected) {
                if (lastSelected && jQuery.contains(diff.get(0), lastSelected.get(0))) {
                    var lastNum = parseInt(lastSelected.find(".linenumber").html());
                    _.each(_.range(currNum, lastNum, lastNum > currNum ? 1 : -1),
                           function(i) { diff.find(".line-" + i).addClass("chosen"); });
                }
            } else {
                $(this).addClass("chosen");
            }
        }

        var lines_chosen = diff.find(".chosen");
        var last_line_number = parseInt(lines_chosen.find(".linenumber").last().html());
        var existing_forms = diff.find(".comment-form");

        if (existing_forms.length) {
            if (_.isNaN(last_line_number)) {
                existing_forms.remove();
                diff.find("tr.comment").fadeIn('fast');
            } else {
                var existing_form = existing_forms.last();
                var existing_form_line_number = parseInt(existing_form.find(".lastlinenumber").html());
                var existing_body = existing_form.find(".body").val();
                var existing_markdown = existing_form.find('.markdown-select').is(':checked');
                var existing_current = existing_form.find('.current').val();

                if (existing_form_line_number != last_line_number) {
                    existing_forms.remove();

                    var comment_form = RenderLineCommentForm($(this), last_line_number, existing_body,
                                                             existing_markdown, existing_current);
                    lines_chosen.last().after(comment_form);
                    diff.find("label").inFieldLabels();
                }

                var newLines = _.reduce(diff.find(".chosen .linenumber"), "",
                                        function(memo, lne) { return memo + $(lne).html() + ','; });
                diff.find(".comment-form form .lines").val(newLines);
            }
        } else {
            var comment_form = RenderLineCommentForm($(this), last_line_number, '', true, '');
            $(this).after(comment_form);
            diff.find("label").inFieldLabels();
        }

        return false;
    });

    $("label.infield").inFieldLabels();
});