Changeset - dac0bff4d2a3
[Not reviewed]
default
0 1 0
Ross Thomas - 6 years ago 2020-02-07 22:55:27
ross@lns-nevasoft.com
follow: Fix args for $.post() call in toggleFollowingRepo()

Before, the resulting query string was _literally_ like:

?follows_repository_id=xxx&_session_csrf_secret_token=yyy

The server side stack ended up parsing it as:

>>> urllib.parse.parse_qsl("follows_repository_id=xxx&_session_csrf_secret_token=yyy", keep_blank_values=True)
[('follows_repository_id', 'xxx'), ('amp', ''), ('_session_csrf_secret_token', 'yyy')]

because the HTML encoding of & isn't relevant here and it thus looks like a
"matrix URL" (as drafted on https://www.w3.org/DesignIssues/MatrixURIs.html )
with the following values:

param: follows_repository_id = xxx
param: amp =
matrix: _session_csrf_secret_token = yyy

It thus ended up with the right values (if ignoring 'amp') and it thus worked
anyway.

Instead, clean it up and just pass a dict to jQuery.post as intended.
1 file changed with 4 insertions and 2 deletions:
0 comments (0 inline, 0 general)
kallithea/public/js/base.js
Show inline comments
 
@@ -76,770 +76,772 @@ String.prototype.lstrip = function(char)
 
    return this.replace(new RegExp('^'+char+'+'),'');
 
}
 

	
 
String.prototype.rstrip = function(char) {
 
    if(char === undefined){
 
        char = '\\s';
 
    }
 
    return this.replace(new RegExp(''+char+'+$'),'');
 
}
 

	
 
/* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf#Polyfill
 
   under MIT license / public domain, see
 
   https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses */
 
if(!Array.prototype.indexOf) {
 
    Array.prototype.indexOf = function (searchElement, fromIndex) {
 
        if ( this === undefined || this === null ) {
 
            throw new TypeError( '"this" is null or not defined' );
 
        }
 

	
 
        var length = this.length >>> 0; // Hack to convert object.length to a UInt32
 

	
 
        fromIndex = +fromIndex || 0;
 

	
 
        if (Math.abs(fromIndex) === Infinity) {
 
            fromIndex = 0;
 
        }
 

	
 
        if (fromIndex < 0) {
 
            fromIndex += length;
 
            if (fromIndex < 0) {
 
                fromIndex = 0;
 
            }
 
        }
 

	
 
        for (;fromIndex < length; fromIndex++) {
 
            if (this[fromIndex] === searchElement) {
 
                return fromIndex;
 
            }
 
        }
 

	
 
        return -1;
 
    };
 
}
 

	
 
/* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#Compatibility
 
   under MIT license / public domain, see
 
   https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses */
 
if (!Array.prototype.filter)
 
{
 
    Array.prototype.filter = function(fun /*, thisArg */)
 
    {
 
        if (this === void 0 || this === null)
 
            throw new TypeError();
 

	
 
        var t = Object(this);
 
        var len = t.length >>> 0;
 
        if (typeof fun !== "function")
 
            throw new TypeError();
 

	
 
        var res = [];
 
        var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
 
        for (var i = 0; i < len; i++)
 
        {
 
            if (i in t)
 
            {
 
                var val = t[i];
 

	
 
                // NOTE: Technically this should Object.defineProperty at
 
                //       the next index, as push can be affected by
 
                //       properties on Object.prototype and Array.prototype.
 
                //       But that method's new, and collisions should be
 
                //       rare, so use the more-compatible alternative.
 
                if (fun.call(thisArg, val, i, t))
 
                    res.push(val);
 
            }
 
        }
 

	
 
        return res;
 
    };
 
}
 

	
 
/**
 
 * A customized version of PyRoutes.JS from https://pypi.python.org/pypi/pyroutes.js/
 
 * which is copyright Stephane Klein and was made available under the BSD License.
 
 *
 
 * Usage pyroutes.url('mark_error_fixed',{"error_id":error_id}) // /mark_error_fixed/<error_id>
 
 */
 
var pyroutes = (function() {
 
    var matchlist = {};
 
    var sprintf = (function() {
 
        function get_type(variable) {
 
            return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
 
        }
 
        function str_repeat(input, multiplier) {
 
            for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
 
            return output.join('');
 
        }
 

	
 
        var str_format = function() {
 
            if (!str_format.cache.hasOwnProperty(arguments[0])) {
 
                str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
 
            }
 
            return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
 
        };
 

	
 
        str_format.format = function(parse_tree, argv) {
 
            var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
 
            for (i = 0; i < tree_length; i++) {
 
                node_type = get_type(parse_tree[i]);
 
                if (node_type === 'string') {
 
                    output.push(parse_tree[i]);
 
                }
 
                else if (node_type === 'array') {
 
                    match = parse_tree[i]; // convenience purposes only
 
                    if (match[2]) { // keyword argument
 
                        arg = argv[cursor];
 
                        for (k = 0; k < match[2].length; k++) {
 
                            if (!arg.hasOwnProperty(match[2][k])) {
 
                                throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
 
                            }
 
                            arg = arg[match[2][k]];
 
                        }
 
                    }
 
                    else if (match[1]) { // positional argument (explicit)
 
                        arg = argv[match[1]];
 
                    }
 
                    else { // positional argument (implicit)
 
                        arg = argv[cursor++];
 
                    }
 

	
 
                    if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
 
                        throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
 
                    }
 
                    switch (match[8]) {
 
                        case 'b': arg = arg.toString(2); break;
 
                        case 'c': arg = String.fromCharCode(arg); break;
 
                        case 'd': arg = parseInt(arg, 10); break;
 
                        case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
 
                        case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
 
                        case 'o': arg = arg.toString(8); break;
 
                        case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
 
                        case 'u': arg = Math.abs(arg); break;
 
                        case 'x': arg = arg.toString(16); break;
 
                        case 'X': arg = arg.toString(16).toUpperCase(); break;
 
                    }
 
                    arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
 
                    pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
 
                    pad_length = match[6] - String(arg).length;
 
                    pad = match[6] ? str_repeat(pad_character, pad_length) : '';
 
                    output.push(match[5] ? arg + pad : pad + arg);
 
                }
 
            }
 
            return output.join('');
 
        };
 

	
 
        str_format.cache = {};
 

	
 
        str_format.parse = function(fmt) {
 
            var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
 
            while (_fmt) {
 
                if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
 
                    parse_tree.push(match[0]);
 
                }
 
                else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
 
                    parse_tree.push('%');
 
                }
 
                else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
 
                    if (match[2]) {
 
                        arg_names |= 1;
 
                        var field_list = [], replacement_field = match[2], field_match = [];
 
                        if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
 
                            field_list.push(field_match[1]);
 
                            while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
 
                                if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
 
                                    field_list.push(field_match[1]);
 
                                }
 
                                else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
 
                                    field_list.push(field_match[1]);
 
                                }
 
                                else {
 
                                    throw('[sprintf] huh?');
 
                                }
 
                            }
 
                        }
 
                        else {
 
                            throw('[sprintf] huh?');
 
                        }
 
                        match[2] = field_list;
 
                    }
 
                    else {
 
                        arg_names |= 2;
 
                    }
 
                    if (arg_names === 3) {
 
                        throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
 
                    }
 
                    parse_tree.push(match);
 
                }
 
                else {
 
                    throw('[sprintf] huh?');
 
                }
 
                _fmt = _fmt.substring(match[0].length);
 
            }
 
            return parse_tree;
 
        };
 

	
 
        return str_format;
 
    })();
 

	
 
    var vsprintf = function(fmt, argv) {
 
        argv.unshift(fmt);
 
        return sprintf.apply(null, argv);
 
    };
 
    return {
 
        'url': function(route_name, params) {
 
            var result = route_name;
 
            if (typeof(params) != 'object'){
 
                params = {};
 
            }
 
            if (matchlist.hasOwnProperty(route_name)) {
 
                var route = matchlist[route_name];
 
                // param substitution
 
                for(var i=0; i < route[1].length; i++) {
 
                   if (!params.hasOwnProperty(route[1][i]))
 
                        throw new Error(route[1][i] + ' missing in "' + route_name + '" route generation');
 
                }
 
                result = sprintf(route[0], params);
 

	
 
                var ret = [];
 
                //extra params => GET
 
                for(var param in params){
 
                    if (route[1].indexOf(param) == -1){
 
                        ret.push(encodeURIComponent(param) + "=" + encodeURIComponent(params[param]));
 
                    }
 
                }
 
                var _parts = ret.join("&");
 
                if(_parts){
 
                    result = result +'?'+ _parts
 
                }
 
            }
 

	
 
            return result;
 
        },
 
        'register': function(route_name, route_tmpl, req_params) {
 
            if (typeof(req_params) != 'object') {
 
                req_params = [];
 
            }
 
            var keys = [];
 
            for (var i=0; i < req_params.length; i++) {
 
                keys.push(req_params[i]);
 
            }
 
            matchlist[route_name] = [
 
                unescape(route_tmpl),
 
                keys
 
            ]
 
        },
 
        '_routes': function(){
 
            return matchlist;
 
        }
 
    }
 
})();
 

	
 

	
 
/* Invoke all functions in callbacks */
 
var _run_callbacks = function(callbacks){
 
    if (callbacks !== undefined){
 
        var _l = callbacks.length;
 
        for (var i=0;i<_l;i++){
 
            var func = callbacks[i];
 
            if(typeof(func)=='function'){
 
                try{
 
                    func();
 
                }catch (err){};
 
            }
 
        }
 
    }
 
}
 

	
 
/**
 
 * turns objects into GET query string
 
 */
 
var _toQueryString = function(o) {
 
    if(typeof o !== 'object') {
 
        return false;
 
    }
 
    var _p, _qs = [];
 
    for(_p in o) {
 
        _qs.push(encodeURIComponent(_p) + '=' + encodeURIComponent(o[_p]));
 
    }
 
    return _qs.join('&');
 
};
 

	
 
/**
 
 * Load HTML into DOM using Ajax
 
 *
 
 * @param $target: load html async and place it (or an error message) here
 
 * @param success: success callback function
 
 * @param args: query parameters to pass to url
 
 */
 
function asynchtml(url, $target, success, args){
 
    if(args===undefined){
 
        args=null;
 
    }
 
    $target.html(_TM['Loading ...']).css('opacity','0.3');
 

	
 
    return $.ajax({url: url, data: args, headers: {'X-PARTIAL-XHR': '1'}, cache: false, dataType: 'html'})
 
        .done(function(html) {
 
                $target.html(html);
 
                $target.css('opacity','1.0');
 
                //execute the given original callback
 
                if (success !== undefined && success) {
 
                    success();
 
                }
 
            })
 
        .fail(function(jqXHR, textStatus, errorThrown) {
 
                if (textStatus == "abort")
 
                    return;
 
                $target.html('<span class="bg-danger">ERROR: {0}</span>'.format(textStatus));
 
                $target.css('opacity','1.0');
 
            })
 
        ;
 
};
 

	
 
var ajaxGET = function(url, success, failure) {
 
    if(failure === undefined) {
 
        failure = function(jqXHR, textStatus, errorThrown) {
 
                if (textStatus != "abort")
 
                    alert("Ajax GET error: " + textStatus);
 
            };
 
    }
 
    return $.ajax({url: url, headers: {'X-PARTIAL-XHR': '1'}, cache: false})
 
        .done(success)
 
        .fail(failure);
 
};
 

	
 
var ajaxPOST = function(url, postData, success, failure) {
 
    postData['_session_csrf_secret_token'] = _session_csrf_secret_token;
 
    var postData = _toQueryString(postData);
 
    if(failure === undefined) {
 
        failure = function(jqXHR, textStatus, errorThrown) {
 
                if (textStatus != "abort")
 
                    alert("Error posting to server: " + textStatus);
 
            };
 
    }
 
    return $.ajax({url: url, data: postData, type: 'POST', headers: {'X-PARTIAL-XHR': '1'}, cache: false})
 
        .done(success)
 
        .fail(failure);
 
};
 

	
 

	
 
/**
 
 * activate .show_more links
 
 * the .show_more must have an id that is the the id of an element to hide prefixed with _
 
 * the parentnode will be displayed
 
 */
 
var show_more_event = function(){
 
    $('.show_more').click(function(e){
 
        var el = e.currentTarget;
 
        $('#' + el.id.substring(1)).hide();
 
        $(el.parentNode).show();
 
    });
 
};
 

	
 

	
 
var _onSuccessFollow = function(target){
 
    var $target = $(target);
 
    var $f_cnt = $('#current_followers_count');
 
    if ($target.hasClass('follow')) {
 
        $target.removeClass('follow').addClass('following');
 
        $target.prop('title', _TM['Stop following this repository']);
 
        if ($f_cnt.html()) {
 
            var cnt = Number($f_cnt.html())+1;
 
            $f_cnt.html(cnt);
 
        }
 
    } else {
 
        $target.removeClass('following').addClass('follow');
 
        $target.prop('title', _TM['Start following this repository']);
 
        if ($f_cnt.html()) {
 
            var cnt = Number($f_cnt.html())-1;
 
            $f_cnt.html(cnt);
 
        }
 
    }
 
}
 

	
 
var toggleFollowingRepo = function(target, follows_repository_id){
 
    var args = 'follows_repository_id=' + follows_repository_id;
 
    args += '&amp;_session_csrf_secret_token=' + _session_csrf_secret_token;
 
    var args = {
 
        'follows_repository_id': follows_repository_id,
 
        '_session_csrf_secret_token': _session_csrf_secret_token
 
    }
 
    $.post(TOGGLE_FOLLOW_URL, args, function(data){
 
            _onSuccessFollow(target);
 
        });
 
    return false;
 
};
 

	
 
var showRepoSize = function(target, repo_name){
 
    var args = '_session_csrf_secret_token=' + _session_csrf_secret_token;
 

	
 
    if(!$("#" + target).hasClass('loaded')){
 
        $("#" + target).html(_TM['Loading ...']);
 
        var url = pyroutes.url('repo_size', {"repo_name":repo_name});
 
        $.post(url, args, function(data) {
 
            $("#" + target).html(data);
 
            $("#" + target).addClass('loaded');
 
        });
 
    }
 
    return false;
 
};
 

	
 
/**
 
 * load tooltips dynamically based on data attributes, used for .lazy-cs changeset links
 
 */
 
var get_changeset_tooltip = function() {
 
    var $target = $(this);
 
    var tooltip = $target.data('tooltip');
 
    if (!tooltip) {
 
        var raw_id = $target.data('raw_id');
 
        var repo_name = $target.data('repo_name');
 
        var url = pyroutes.url('changeset_info', {"repo_name": repo_name, "revision": raw_id});
 

	
 
        $.ajax(url, {
 
            async: false,
 
            success: function(data) {
 
                tooltip = data["message"];
 
            }
 
        });
 
        $target.data('tooltip', tooltip);
 
    }
 
    return tooltip;
 
};
 

	
 
/**
 
 * activate tooltips and popups
 
 */
 
var tooltip_activate = function(){
 
    function placement(p, e){
 
        if(e.getBoundingClientRect().top > 2*$(window).height()/3){
 
            return 'top';
 
        }else{
 
            return 'bottom';
 
        }
 
    }
 
    $(document).ready(function(){
 
        $('[data-toggle="tooltip"]').tooltip({
 
            container: 'body',
 
            placement: placement
 
        });
 
        $('[data-toggle="popover"]').popover({
 
            html: true,
 
            container: 'body',
 
            placement: placement,
 
            trigger: 'hover',
 
            template: '<div class="popover cs-popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
 
        });
 
        $('.lazy-cs').tooltip({
 
            title: get_changeset_tooltip,
 
            placement: placement
 
        });
 
    });
 
};
 

	
 

	
 
/**
 
 * Quick filter widget
 
 *
 
 * @param target: filter input target
 
 * @param nodes: list of nodes in html we want to filter.
 
 * @param display_element function that takes current node from nodes and
 
 *    does hide or show based on the node
 
 */
 
var q_filter = (function() {
 
    var _namespace = {};
 
    var namespace = function (target) {
 
        if (!(target in _namespace)) {
 
            _namespace[target] = {};
 
        }
 
        return _namespace[target];
 
    };
 
    return function (target, $nodes, display_element) {
 
        var $nodes = $nodes;
 
        var $q_filter_field = $('#' + target);
 
        var F = namespace(target);
 

	
 
        $q_filter_field.keyup(function (e) {
 
            clearTimeout(F.filterTimeout);
 
            F.filterTimeout = setTimeout(F.updateFilter, 600);
 
        });
 

	
 
        F.filterTimeout = null;
 

	
 
        F.updateFilter = function () {
 
            // Reset timeout
 
            F.filterTimeout = null;
 

	
 
            var obsolete = [];
 

	
 
            var req = $q_filter_field.val().toLowerCase();
 

	
 
            var showing = 0;
 
            $nodes.each(function () {
 
                var n = this;
 
                var target_element = display_element(n);
 
                if (req && n.innerHTML.toLowerCase().indexOf(req) == -1) {
 
                    $(target_element).hide();
 
                }
 
                else {
 
                    $(target_element).show();
 
                    showing += 1;
 
                }
 
            });
 

	
 
            $('#repo_count').html(showing);
 
            /* FIXME: don't hardcode */
 
        }
 
    }
 
})();
 

	
 

	
 
/**
 
 * Comment handling
 
 */
 

	
 
// move comments to their right location, inside new trs
 
function move_comments($anchorcomments) {
 
    $anchorcomments.each(function(i, anchorcomment) {
 
        var $anchorcomment = $(anchorcomment);
 
        var target_id = $anchorcomment.data('target-id');
 
        var $comment_div = _get_add_comment_div(target_id);
 
        var f_path = $anchorcomment.data('f_path');
 
        var line_no = $anchorcomment.data('line_no');
 
        if ($comment_div[0]) {
 
            $comment_div.append($anchorcomment.children());
 
            if (f_path && line_no) {
 
                _comment_div_append_add($comment_div, f_path, line_no);
 
            } else {
 
                _comment_div_append_form($comment_div, f_path, line_no);
 
            }
 
        } else {
 
            $anchorcomment.before("<span class='bg-warning'>Comment to {0} line {1} which is outside the diff context:</span>".format(f_path || '?', line_no || '?'));
 
        }
 
    });
 
    linkInlineComments($('.firstlink'), $('.comment:first-child'));
 
}
 

	
 
// comment bubble was clicked - insert new tr and show form
 
function show_comment_form($bubble) {
 
    var children = $bubble.closest('tr.line').children('[id]');
 
    var line_td_id = children[children.length - 1].id;
 
    var $comment_div = _get_add_comment_div(line_td_id);
 
    var f_path = $bubble.closest('[data-f_path]').data('f_path');
 
    var parts = line_td_id.split('_');
 
    var line_no = parts[parts.length-1];
 
    comment_div_state($comment_div, f_path, line_no, true);
 
}
 

	
 
// return comment div for target_id - add it if it doesn't exist yet
 
function _get_add_comment_div(target_id) {
 
    var comments_box_id = 'comments-' + target_id;
 
    var $comments_box = $('#' + comments_box_id);
 
    if (!$comments_box.length) {
 
        var html = '<tr><td id="{0}" colspan="3" class="inline-comments"></td></tr>'.format(comments_box_id);
 
        $('#' + target_id).closest('tr').after(html);
 
        $comments_box = $('#' + comments_box_id);
 
    }
 
    return $comments_box;
 
}
 

	
 
// Set $comment_div state - showing or not showing form and Add button.
 
// An Add button is shown on non-empty forms when no form is shown.
 
// The form is controlled by show_form_opt - if undefined, form is only shown for general comments.
 
function comment_div_state($comment_div, f_path, line_no, show_form_opt) {
 
    var show_form = show_form_opt !== undefined ? show_form_opt : !f_path && !line_no;
 
    var $forms = $comment_div.children('.comment-inline-form');
 
    var $buttonrow = $comment_div.children('.add-button-row');
 
    var $comments = $comment_div.children('.comment:not(.submitting)');
 
    $forms.remove();
 
    $buttonrow.remove();
 
    if (show_form) {
 
        _comment_div_append_form($comment_div, f_path, line_no);
 
    } else if ($comments.length) {
 
        _comment_div_append_add($comment_div, f_path, line_no);
 
    } else {
 
        $comment_div.parent('tr').remove();
 
    }
 
}
 

	
 
// append an Add button to $comment_div and hook it up to show form
 
function _comment_div_append_add($comment_div, f_path, line_no) {
 
    var addlabel = TRANSLATION_MAP['Add Another Comment'];
 
    var $add = $('<div class="add-button-row"><span class="btn btn-default btn-xs add-button">{0}</span></div>'.format(addlabel));
 
    $comment_div.append($add);
 
    $add.children('.add-button').click(function(e) {
 
        comment_div_state($comment_div, f_path, line_no, true);
 
    });
 
}
 

	
 
// append a comment form to $comment_div
 
function _comment_div_append_form($comment_div, f_path, line_no) {
 
    var $form_div = $('#comment-inline-form-template').children()
 
        .clone()
 
        .addClass('comment-inline-form');
 
    $comment_div.append($form_div);
 
    var $preview = $comment_div.find("div.comment-preview");
 
    var $form = $comment_div.find("form");
 
    var $textarea = $form.find('textarea');
 

	
 
    $form.submit(function(e) {
 
        e.preventDefault();
 

	
 
        var text = $textarea.val();
 
        var review_status = $form.find('input:radio[name=changeset_status]:checked').val();
 
        var pr_close = $form.find('input:checkbox[name=save_close]:checked').length ? 'on' : '';
 
        var pr_delete = $form.find('input:checkbox[name=save_delete]:checked').length ? 'delete' : '';
 

	
 
        if (!text && !review_status && !pr_close && !pr_delete) {
 
            alert("Please provide a comment");
 
            return false;
 
        }
 

	
 
        if (pr_delete) {
 
            if (text || review_status || pr_close) {
 
                alert('Cannot delete pull request while making other changes');
 
                return false;
 
            }
 
            if (!confirm('Confirm to delete this pull request')) {
 
                return false;
 
            }
 
            var comments = $('.comment').length;
 
            if (comments > 0 &&
 
                !confirm('Confirm again to delete this pull request with {0} comments'.format(comments))) {
 
                return false;
 
            }
 
        }
 

	
 
        if (review_status) {
 
            var $review_status = $preview.find('.automatic-comment');
 
            var review_status_lbl = $("#comment-inline-form-template input.status_change_radio[value='" + review_status + "']").parent().text().strip();
 
            $review_status.find('.comment-status-label').text(review_status_lbl);
 
            $review_status.show();
 
        }
 
        $preview.find('.comment-text div').text(text);
 
        $preview.show();
 
        $textarea.val('');
 
        if (f_path && line_no) {
 
            $form.hide();
 
        }
 

	
 
        var postData = {
 
            'text': text,
 
            'f_path': f_path,
 
            'line': line_no,
 
            'changeset_status': review_status,
 
            'save_close': pr_close,
 
            'save_delete': pr_delete
 
        };
 
        var success = function(json_data) {
 
            if (pr_delete) {
 
                location = json_data['location'];
 
            } else {
 
                $comment_div.append(json_data['rendered_text']);
 
                comment_div_state($comment_div, f_path, line_no);
 
                linkInlineComments($('.firstlink'), $('.comment:first-child'));
 
                if ((review_status || pr_close) && !f_path && !line_no) {
 
                    // Page changed a lot - reload it after closing the submitted form
 
                    comment_div_state($comment_div, f_path, line_no, false);
 
                    location.reload(true);
 
                }
 
            }
 
        };
 
        var failure = function(x, s, e) {
 
            $preview.removeClass('submitting').addClass('failed');
 
            var $status = $preview.find('.comment-submission-status');
 
            $('<span>', {
 
                'title': e,
 
                text: _TM['Unable to post']
 
            }).replaceAll($status.contents());
 
            $('<div>', {
 
                'class': 'btn-group'
 
            }).append(
 
                $('<button>', {
 
                    'class': 'btn btn-default btn-xs',
 
                    text: _TM['Retry']
 
                }).click(function() {
 
                    $status.text(_TM['Submitting ...']);
 
                    $preview.addClass('submitting').removeClass('failed');
 
                    ajaxPOST(AJAX_COMMENT_URL, postData, success, failure);
 
                }),
 
                $('<button>', {
 
                    'class': 'btn btn-default btn-xs',
 
                    text: _TM['Cancel']
 
                }).click(function() {
 
                    comment_div_state($comment_div, f_path, line_no);
 
                })
 
            ).appendTo($status);
 
        };
 
        ajaxPOST(AJAX_COMMENT_URL, postData, success, failure);
 
    });
 

	
 
    // add event handler for hide/cancel buttons
 
    $form.find('.hide-inline-form').click(function(e) {
 
        comment_div_state($comment_div, f_path, line_no);
 
    });
 

	
 
    tooltip_activate();
 
    if ($textarea.length > 0) {
 
        MentionsAutoComplete($textarea);
 
    }
 
    if (f_path) {
 
        $textarea.focus();
 
    }
 
}
 

	
 

	
 
function deleteComment(comment_id) {
 
    var url = AJAX_COMMENT_DELETE_URL.replace('__COMMENT_ID__', comment_id);
 
    var postData = {};
 
    var success = function(o) {
 
        $('#comment-'+comment_id).remove();
 
        // Ignore that this might leave a stray Add button (or have a pending form with another comment) ...
 
    }
 
    ajaxPOST(url, postData, success);
 
}
 

	
 

	
 
/**
 
 * Double link comments
 
 */
 
var linkInlineComments = function($firstlinks, $comments){
 
    if ($comments.length > 0) {
 
        $firstlinks.html('<a href="#{0}">First comment</a>'.format($comments.prop('id')));
 
    }
 
    if ($comments.length <= 1) {
 
        return;
 
    }
 

	
 
    $comments.each(function(i, e){
 
            var prev = '';
 
            if (i > 0){
 
                var prev_anchor = $($comments.get(i-1)).prop('id');
 
                prev = '<a href="#{0}">Previous comment</a>'.format(prev_anchor);
 
            }
 
            var next = '';
 
            if (i+1 < $comments.length){
 
                var next_anchor = $($comments.get(i+1)).prop('id');
 
                next = '<a href="#{0}">Next comment</a>'.format(next_anchor);
 
            }
 
            $(this).find('.comment-prev-next-links').html(
 
                '<div class="prev-comment">{0}</div>'.format(prev) +
 
                '<div class="next-comment">{0}</div>'.format(next));
 
        });
 
}
 

	
 
/* activate files.html stuff */
 
var fileBrowserListeners = function(node_list_url, url_base){
 
    var $node_filter = $('#node_filter');
 

	
 
    var filterTimeout = null;
 
    var nodes = null;
 

	
 
    var initFilter = function(){
 
        $('#node_filter_box_loading').show();
 
        $('#search_activate_id').hide();
 
        $('#add_node_id').hide();
 
        $.ajax({url: node_list_url, headers: {'X-PARTIAL-XHR': '1'}, cache: false})
 
            .done(function(json) {
 
                    nodes = json.nodes;
 
                    $('#node_filter_box_loading').hide();
 
                    $('#node_filter_box').show();
 
                    $node_filter.focus();
 
                    if($node_filter.hasClass('init')){
 
                        $node_filter.val('');
 
                        $node_filter.removeClass('init');
 
                    }
0 comments (0 inline, 0 general)