Changeset - bacc854a3853
[Not reviewed]
default
0 4 0
Søren Løvborg - 9 years ago 2017-03-15 20:39:38
sorenl@unity3d.com
templates: addPermAction JS escaping bugfix (by eliminating expansion bugfix)

In 33b71a130b16, the addPermAction template was incorrectly escaped via
h.jshtml, where it should've been plain h.js.

Instead of merely fixing the escaping, refactor the code to completely
remove the need for escaping anything, by avoiding the template variable
expansion inside the JavaScript.
4 files changed with 21 insertions and 56 deletions:
0 comments (0 inline, 0 general)
kallithea/public/js/base.js
Show inline comments
 
@@ -568,915 +568,928 @@ var q_filter = (function() {
 
 */
 

	
 
// 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("Comment to {0} line {1} which is outside the diff context:".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');
 
    $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 $form = $comment_div.find("form");
 
    var $textarea = $form.find('textarea');
 
    var $mentions_container = $form.find('div.mentions-container');
 

	
 
    $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').size();
 
            if (comments > 0 &&
 
                !confirm('Confirm again to delete this pull request with {0} comments'.format(comments))) {
 
                return false;
 
            }
 
        }
 

	
 
        $form.find('.submitting-overlay').show();
 

	
 
        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);
 
                }
 
            }
 
        };
 
        ajaxPOST(AJAX_COMMENT_URL, postData, success);
 
    });
 

	
 
    // 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, $mentions_container, _USERS_AC_DATA);
 
    }
 
    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(current_url, node_list_url, url_base){
 
    var current_url_branch = "?branch=__BRANCH__";
 

	
 
    $('#stay_at_branch').on('click',function(e){
 
        if(e.currentTarget.checked){
 
            var uri = current_url_branch;
 
            uri = uri.replace('__BRANCH__',e.currentTarget.value);
 
            window.location = uri;
 
        }
 
        else{
 
            window.location = current_url;
 
        }
 
    });
 

	
 
    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');
 
                    }
 
                })
 
            .fail(function() {
 
                    console.log('fileBrowserListeners initFilter failed to load');
 
                })
 
        ;
 
    }
 

	
 
    var updateFilter = function(e) {
 
        return function(){
 
            // Reset timeout
 
            filterTimeout = null;
 
            var query = e.currentTarget.value.toLowerCase();
 
            var match = [];
 
            var matches = 0;
 
            var matches_max = 20;
 
            if (query != ""){
 
                for(var i=0;i<nodes.length;i++){
 
                    var pos = nodes[i].name.toLowerCase().indexOf(query);
 
                    if(query && pos != -1){
 
                        matches++
 
                        //show only certain amount to not kill browser
 
                        if (matches > matches_max){
 
                            break;
 
                        }
 

	
 
                        var n = nodes[i].name;
 
                        var t = nodes[i].type;
 
                        var n_hl = n.substring(0,pos)
 
                            + "<b>{0}</b>".format(n.substring(pos,pos+query.length))
 
                            + n.substring(pos+query.length);
 
                        var new_url = url_base.replace('__FPATH__',n);
 
                        match.push('<tr><td><a class="browser-{0}" href="{1}">{2}</a></td><td colspan="5"></td></tr>'.format(t,new_url,n_hl));
 
                    }
 
                    if(match.length >= matches_max){
 
                        match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['Search truncated']));
 
                        break;
 
                    }
 
                }
 
            }
 
            if(query != ""){
 
                $('#tbody').hide();
 
                $('#tbody_filtered').show();
 

	
 
                if (match.length==0){
 
                  match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['No matching files']));
 
                }
 

	
 
                $('#tbody_filtered').html(match.join(""));
 
            }
 
            else{
 
                $('#tbody').show();
 
                $('#tbody_filtered').hide();
 
            }
 
        }
 
    };
 

	
 
    $('#filter_activate').click(function(){
 
            initFilter();
 
        });
 
    $node_filter.click(function(){
 
            if($node_filter.hasClass('init')){
 
                $node_filter.val('');
 
                $node_filter.removeClass('init');
 
            }
 
        });
 
    $node_filter.keyup(function(e){
 
            clearTimeout(filterTimeout);
 
            filterTimeout = setTimeout(updateFilter(e),600);
 
        });
 
};
 

	
 

	
 
var initCodeMirror = function(textarea_id, baseUrl, resetUrl){
 
    var myCodeMirror = CodeMirror.fromTextArea($('#' + textarea_id)[0], {
 
            mode: "null",
 
            lineNumbers: true,
 
            indentUnit: 4,
 
            autofocus: true
 
        });
 
    CodeMirror.modeURL = baseUrl + "/codemirror/mode/%N/%N.js";
 

	
 
    $('#reset').click(function(e){
 
            window.location=resetUrl;
 
        });
 

	
 
    $('#file_enable').click(function(){
 
            $('#editor_container').show();
 
            $('#upload_file_container').hide();
 
            $('#filename_container').show();
 
            $('#mimetype_header').show();
 
        });
 

	
 
    $('#upload_file_enable').click(function(){
 
            $('#editor_container').hide();
 
            $('#upload_file_container').show();
 
            $('#filename_container').hide();
 
            $('#mimetype_header').hide();
 
        });
 

	
 
    return myCodeMirror
 
};
 

	
 
var setCodeMirrorMode = function(codeMirrorInstance, mode) {
 
    CodeMirror.autoLoadMode(codeMirrorInstance, mode);
 
}
 

	
 

	
 
var _getIdentNode = function(n){
 
    //iterate thrugh nodes until matching interesting node
 

	
 
    if (typeof n == 'undefined'){
 
        return -1
 
    }
 

	
 
    if(typeof n.id != "undefined" && n.id.match('L[0-9]+')){
 
        return n
 
    }
 
    else{
 
        return _getIdentNode(n.parentNode);
 
    }
 
};
 

	
 
/* generate links for multi line selects that can be shown by files.html page_highlights.
 
 * This is a mouseup handler for hlcode from CodeHtmlFormatter and pygmentize */
 
var getSelectionLink = function(e) {
 
    //get selection from start/to nodes
 
    if (typeof window.getSelection != "undefined") {
 
        var s = window.getSelection();
 

	
 
        var from = _getIdentNode(s.anchorNode);
 
        var till = _getIdentNode(s.focusNode);
 

	
 
        var f_int = parseInt(from.id.replace('L',''));
 
        var t_int = parseInt(till.id.replace('L',''));
 

	
 
        var yoffset = 35;
 
        var ranges = [parseInt(from.id.replace('L','')), parseInt(till.id.replace('L',''))];
 
        if (ranges[0] > ranges[1]){
 
            //highlight from bottom
 
            yoffset = -yoffset;
 
            ranges = [ranges[1], ranges[0]];
 
        }
 
        var $hl_div = $('div#linktt');
 
        // if we select more than 2 lines
 
        if (ranges[0] != ranges[1]){
 
            if ($hl_div.length) {
 
                $hl_div.html('');
 
            } else {
 
                $hl_div = $('<div id="linktt" class="hl-tip-box">');
 
                $('body').prepend($hl_div);
 
            }
 

	
 
            $hl_div.append($('<a>').html(_TM['Selection Link']).prop('href', location.href.substring(0, location.href.indexOf('#')) + '#L' + ranges[0] + '-'+ranges[1]));
 
            var xy = $(till).offset();
 
            $hl_div.css('top', (xy.top + yoffset) + 'px').css('left', xy.left + 'px');
 
            $hl_div.show();
 
        }
 
        else{
 
            $hl_div.hide();
 
        }
 
    }
 
};
 

	
 
var deleteNotification = function(url, notification_id, callbacks){
 
    var success = function(o){
 
            $("#notification_"+notification_id).remove();
 
            _run_callbacks(callbacks);
 
        };
 
    var failure = function(o){
 
            alert("deleteNotification failure");
 
        };
 
    var postData = {};
 
    var sUrl = url.replace('__NOTIFICATION_ID__',notification_id);
 
    ajaxPOST(sUrl, postData, success, failure);
 
};
 

	
 
var readNotification = function(url, notification_id, callbacks){
 
    var success = function(o){
 
            var $obj = $("#notification_"+notification_id);
 
            $obj.removeClass('unread');
 
            $obj.find('.read-notification').remove();
 
            _run_callbacks(callbacks);
 
        };
 
    var failure = function(o){
 
            alert("readNotification failure");
 
        };
 
    var postData = {};
 
    var sUrl = url.replace('__NOTIFICATION_ID__',notification_id);
 
    ajaxPOST(sUrl, postData, success, failure);
 
};
 

	
 
/**
 
 * Autocomplete functionality
 
 */
 

	
 
// Custom search function for the DataSource of users
 
var autocompleteMatchUsers = function (sQuery, myUsers) {
 
    // Case insensitive matching
 
    var query = sQuery.toLowerCase();
 
    var i = 0;
 
    var l = myUsers.length;
 
    var matches = [];
 

	
 
    // Match against each name of each contact
 
    for (; i < l; i++) {
 
        var contact = myUsers[i];
 
        if (((contact.fname+"").toLowerCase().indexOf(query) > -1) ||
 
             ((contact.lname+"").toLowerCase().indexOf(query) > -1) ||
 
             ((contact.nname) && ((contact.nname).toLowerCase().indexOf(query) > -1))) {
 
            matches[matches.length] = contact;
 
        }
 
    }
 
    return matches;
 
};
 

	
 
// Custom search function for the DataSource of userGroups
 
var autocompleteMatchGroups = function (sQuery, myGroups) {
 
    // Case insensitive matching
 
    var query = sQuery.toLowerCase();
 
    var i = 0;
 
    var l = myGroups.length;
 
    var matches = [];
 

	
 
    // Match against each name of each group
 
    for (; i < l; i++) {
 
        var matched_group = myGroups[i];
 
        if (matched_group.grname.toLowerCase().indexOf(query) > -1) {
 
            matches[matches.length] = matched_group;
 
        }
 
    }
 
    return matches;
 
};
 

	
 
// Helper highlight function for the formatter
 
var autocompleteHighlightMatch = function (full, snippet, matchindex) {
 
    return full.substring(0, matchindex)
 
        + "<span class='match'>"
 
        + full.substr(matchindex, snippet.length)
 
        + "</span>" + full.substring(matchindex + snippet.length);
 
};
 

	
 
// Return html snippet for showing the provided gravatar url
 
var gravatar = function(gravatar_lnk, size, cssclass) {
 
    if (!gravatar_lnk) {
 
        return '';
 
    }
 
    if (gravatar_lnk == 'default') {
 
        return '<i class="icon-user {1}" style="font-size: {0}px;"></i>'.format(size, cssclass);
 
    }
 
    return '<img alt="" class="{2}" style="width: {0}px; height: {0}px" src="{1}"/>'.format(size, gravatar_lnk, cssclass);
 
}
 

	
 
var autocompleteGravatar = function(res, gravatar_lnk, size, group) {
 
    var elem;
 
    if (group !== undefined) {
 
        elem = '<i class="perm-gravatar-ac icon-users"></i>';
 
    } else {
 
        elem = gravatar(gravatar_lnk, size, "perm-gravatar-ac");
 
    }
 
    return '<div class="ac-container-wrap">{0}{1}</div>'.format(elem, res);
 
}
 

	
 
// Custom formatter to highlight the matching letters
 
var autocompleteFormatter = function (oResultData, sQuery, sResultMatch) {
 
    var query = sQuery.toLowerCase();
 

	
 
    // group
 
    if (oResultData.grname != undefined) {
 
        var grname = oResultData.grname;
 
        var grmembers = oResultData.grmembers;
 
        var grnameMatchIndex = grname.toLowerCase().indexOf(query);
 
        var grprefix = "{0}: ".format(_TM['Group']);
 
        var grsuffix = " ({0} {1})".format(grmembers, _TM['members']);
 

	
 
        if (grnameMatchIndex > -1) {
 
            return autocompleteGravatar(grprefix + autocompleteHighlightMatch(grname, query, grnameMatchIndex) + grsuffix, null, null, true);
 
        }
 
        return autocompleteGravatar(grprefix + oResultData.grname + grsuffix, null, null, true);
 

	
 
    // users
 
    } else if (oResultData.nname != undefined) {
 
        var fname = oResultData.fname || "";
 
        var lname = oResultData.lname || "";
 
        var nname = oResultData.nname;
 

	
 
        // Guard against null value
 
        var fnameMatchIndex = fname.toLowerCase().indexOf(query),
 
            lnameMatchIndex = lname.toLowerCase().indexOf(query),
 
            nnameMatchIndex = nname.toLowerCase().indexOf(query),
 
            displayfname, displaylname, displaynname, displayname;
 

	
 
        if (fnameMatchIndex > -1) {
 
            displayfname = autocompleteHighlightMatch(fname, query, fnameMatchIndex);
 
        } else {
 
            displayfname = fname;
 
        }
 

	
 
        if (lnameMatchIndex > -1) {
 
            displaylname = autocompleteHighlightMatch(lname, query, lnameMatchIndex);
 
        } else {
 
            displaylname = lname;
 
        }
 

	
 
        if (nnameMatchIndex > -1) {
 
            displaynname = autocompleteHighlightMatch(nname, query, nnameMatchIndex);
 
        } else {
 
            displaynname = nname;
 
        }
 

	
 
        displayname = displaynname;
 
        if (displayfname && displaylname) {
 
            displayname = "{0} {1} ({2})".format(displayfname, displaylname, displayname);
 
        }
 

	
 
        return autocompleteGravatar(displayname, oResultData.gravatar_lnk, oResultData.gravatar_size);
 
    } else {
 
        return '';
 
    }
 
};
 

	
 
// Generate a basic autocomplete instance that can be tweaked further by the caller
 
var autocompleteCreate = function ($inputElement, $container, matchFunc) {
 
    var datasource = new YAHOO.util.FunctionDataSource(matchFunc);
 

	
 
    var autocomplete = new YAHOO.widget.AutoComplete($inputElement[0], $container[0], datasource);
 
    autocomplete.useShadow = false;
 
    autocomplete.resultTypeList = false;
 
    autocomplete.animVert = false;
 
    autocomplete.animHoriz = false;
 
    autocomplete.animSpeed = 0.1;
 
    autocomplete.formatResult = autocompleteFormatter;
 

	
 
    return autocomplete;
 
}
 

	
 
var SimpleUserAutoComplete = function ($inputElement, $container, users_list) {
 

	
 
    var matchUsers = function (sQuery) {
 
        return autocompleteMatchUsers(sQuery, users_list);
 
    }
 

	
 
    var userAC = autocompleteCreate($inputElement, $container, matchUsers);
 

	
 
    // Handler for selection of an entry
 
    var itemSelectHandler = function (sType, aArgs) {
 
        var myAC = aArgs[0]; // reference back to the AC instance
 
        var elLI = aArgs[1]; // reference to the selected LI element
 
        var oData = aArgs[2]; // object literal of selected item's result data
 
        myAC.getInputEl().value = oData.nname;
 
    };
 
    userAC.itemSelectEvent.subscribe(itemSelectHandler);
 
}
 

	
 
var MembersAutoComplete = function ($inputElement, $container, users_list, groups_list) {
 

	
 
    var matchAll = function (sQuery) {
 
        var u = autocompleteMatchUsers(sQuery, users_list);
 
        var g = autocompleteMatchGroups(sQuery, groups_list);
 
        return u.concat(g);
 
    };
 

	
 
    var membersAC = autocompleteCreate($inputElement, $container, matchAll);
 

	
 
    // Handler for selection of an entry
 
    var itemSelectHandler = function (sType, aArgs) {
 
        var nextId = $inputElement.prop('id').split('perm_new_member_name_')[1];
 
        var myAC = aArgs[0]; // reference back to the AC instance
 
        var elLI = aArgs[1]; // reference to the selected LI element
 
        var oData = aArgs[2]; // object literal of selected item's result data
 
        //fill the autocomplete with value
 
        if (oData.nname != undefined) {
 
            //users
 
            myAC.getInputEl().value = oData.nname;
 
            $('#perm_new_member_type_'+nextId).val('user');
 
        } else {
 
            //groups
 
            myAC.getInputEl().value = oData.grname;
 
            $('#perm_new_member_type_'+nextId).val('users_group');
 
        }
 
    };
 
    membersAC.itemSelectEvent.subscribe(itemSelectHandler);
 
}
 

	
 
var MentionsAutoComplete = function ($inputElement, $container, users_list) {
 

	
 
    var matchUsers = function (sQuery) {
 
            var org_sQuery = sQuery;
 
            if(this.mentionQuery == null){
 
                return []
 
            }
 
            sQuery = this.mentionQuery;
 
            return autocompleteMatchUsers(sQuery, users_list);
 
    }
 

	
 
    var mentionsAC = autocompleteCreate($inputElement, $container, matchUsers);
 
    mentionsAC.suppressInputUpdate = true;
 
    // Overwrite formatResult to take into account mentionQuery
 
    mentionsAC.formatResult = function (oResultData, sQuery, sResultMatch) {
 
        var org_sQuery = sQuery;
 
        if (this.dataSource.mentionQuery != null) {
 
            sQuery = this.dataSource.mentionQuery;
 
        }
 
        return autocompleteFormatter(oResultData, sQuery, sResultMatch);
 
    }
 

	
 
    // Handler for selection of an entry
 
    if(mentionsAC.itemSelectEvent){
 
        mentionsAC.itemSelectEvent.subscribe(function (sType, aArgs) {
 
            var myAC = aArgs[0]; // reference back to the AC instance
 
            var elLI = aArgs[1]; // reference to the selected LI element
 
            var oData = aArgs[2]; // object literal of selected item's result data
 
            //Replace the mention name with replaced
 
            var re = new RegExp();
 
            var org = myAC.getInputEl().value;
 
            var chunks = myAC.dataSource.chunks
 
            // replace middle chunk(the search term) with actuall  match
 
            chunks[1] = chunks[1].replace('@'+myAC.dataSource.mentionQuery,
 
                                          '@'+oData.nname+' ');
 
            myAC.getInputEl().value = chunks.join('');
 
            myAC.getInputEl().focus(); // Y U NO WORK !?
 
        });
 
    }
 

	
 
    // in this keybuffer we will gather current value of search !
 
    // since we need to get this just when someone does `@` then we do the
 
    // search
 
    mentionsAC.dataSource.chunks = [];
 
    mentionsAC.dataSource.mentionQuery = null;
 

	
 
    mentionsAC.get_mention = function(msg, max_pos) {
 
        var org = msg;
 
        // Must match utils2.py MENTIONS_REGEX.
 
        // Only matching on string up to cursor, so it must end with $
 
        var re = new RegExp('(?:^|[^a-zA-Z0-9])@([a-zA-Z0-9][-_.a-zA-Z0-9]*[a-zA-Z0-9])$');
 
        var chunks  = [];
 

	
 
        // cut first chunk until current pos
 
        var to_max = msg.substr(0, max_pos);
 
        var at_pos = Math.max(0,to_max.lastIndexOf('@')-1);
 
        var msg2 = to_max.substr(at_pos);
 

	
 
        chunks.push(org.substr(0,at_pos)); // prefix chunk
 
        chunks.push(msg2);                 // search chunk
 
        chunks.push(org.substr(max_pos));  // postfix chunk
 

	
 
        // clean up msg2 for filtering and regex match
 
        var msg2 = msg2.lstrip(' ').lstrip('\n');
 

	
 
        if(re.test(msg2)){
 
            var unam = re.exec(msg2)[1];
 
            return [unam, chunks];
 
        }
 
        return [null, null];
 
    };
 

	
 
    $inputElement.keyup(function(e){
 
            var currentMessage = $inputElement.val();
 
            var currentCaretPosition = $inputElement[0].selectionStart;
 

	
 
            var unam = mentionsAC.get_mention(currentMessage, currentCaretPosition);
 
            var curr_search = null;
 
            if(unam[0]){
 
                curr_search = unam[0];
 
            }
 

	
 
            mentionsAC.dataSource.chunks = unam[1];
 
            mentionsAC.dataSource.mentionQuery = curr_search;
 
        });
 
}
 

	
 
var addReviewMember = function(id,fname,lname,nname,gravatar_link,gravatar_size){
 
    var displayname = nname;
 
    if ((fname != "") && (lname != "")) {
 
        displayname = "{0} {1} ({2})".format(fname, lname, nname);
 
    }
 
    var gravatarelm = gravatar(gravatar_link, gravatar_size, "");
 
    // WARNING: the HTML below is duplicate with
 
    // kallithea/templates/pullrequests/pullrequest_show.html
 
    // If you change something here it should be reflected in the template too.
 
    var element = (
 
        '     <li id="reviewer_{2}">\n'+
 
        '       <span class="reviewers_member">\n'+
 
        '         <span class="reviewer_status" data-toggle="tooltip" title="not_reviewed">\n'+
 
        '             <i class="icon-circle changeset-status-not_reviewed"></i>\n'+
 
        '         </span>\n'+
 
        (gravatarelm ?
 
        '         {0}\n' :
 
        '')+
 
        '         <span>{1}</span>\n'+
 
        '         <input type="hidden" value="{2}" name="review_members" />\n'+
 
        '         <a href="#" class="reviewer_member_remove" onclick="removeReviewMember({2})">\n'+
 
        '             <i class="icon-minus-circled"></i>\n'+
 
        '         </a> (add not saved)\n'+
 
        '       </span>\n'+
 
        '     </li>\n'
 
        ).format(gravatarelm, displayname, id);
 
    // check if we don't have this ID already in
 
    var ids = [];
 
    $('#review_members').find('li').each(function() {
 
            ids.push(this.id);
 
        });
 
    if(ids.indexOf('reviewer_'+id) == -1){
 
        //only add if it's not there
 
        $('#review_members').append(element);
 
    }
 
}
 

	
 
var removeReviewMember = function(reviewer_id, repo_name, pull_request_id){
 
    var $li = $('#reviewer_{0}'.format(reviewer_id));
 
    $li.find('div div').css("text-decoration", "line-through");
 
    $li.find('input').prop('name', 'review_members_removed');
 
    $li.find('.reviewer_member_remove').replaceWith('&nbsp;(remove not saved)');
 
}
 

	
 
/* activate auto completion of users as PR reviewers */
 
var PullRequestAutoComplete = function ($inputElement, $container, users_list) {
 

	
 
    var matchUsers = function (sQuery) {
 
        return autocompleteMatchUsers(sQuery, users_list);
 
    };
 

	
 
    var reviewerAC = autocompleteCreate($inputElement, $container, matchUsers);
 
    reviewerAC.suppressInputUpdate = true;
 

	
 
    // Handler for selection of an entry
 
    if(reviewerAC.itemSelectEvent){
 
        reviewerAC.itemSelectEvent.subscribe(function (sType, aArgs) {
 
            var myAC = aArgs[0]; // reference back to the AC instance
 
            var elLI = aArgs[1]; // reference to the selected LI element
 
            var oData = aArgs[2]; // object literal of selected item's result data
 

	
 
            addReviewMember(oData.id, oData.fname, oData.lname, oData.nname,
 
                            oData.gravatar_lnk, oData.gravatar_size);
 
            myAC.getInputEl().value = '';
 
        });
 
    }
 
}
 

	
 

	
 
var addPermAction = function(_html, users_list, groups_list){
 
function addPermAction(perm_type, users_list, groups_list) {
 
    var template =
 
        '<td><input type="radio" value="{1}.none" name="perm_new_member_{0}" id="perm_new_member_{0}"></td>' +
 
        '<td><input type="radio" value="{1}.read" checked="checked" name="perm_new_member_{0}" id="perm_new_member_{0}"></td>' +
 
        '<td><input type="radio" value="{1}.write" name="perm_new_member_{0}" id="perm_new_member_{0}"></td>' +
 
        '<td><input type="radio" value="{1}.admin" name="perm_new_member_{0}" id="perm_new_member_{0}"></td>' +
 
        '<td class="ac">' +
 
            '<div class="perm_ac" id="perm_ac_{0}">' +
 
                '<input class="yui-ac-input" id="perm_new_member_name_{0}" name="perm_new_member_name_{0}" value="" type="text">' +
 
                '<input id="perm_new_member_type_{0}" name="perm_new_member_type_{0}" value="" type="hidden">' +
 
                '<div id="perm_container_{0}"></div>' +
 
            '</div>' +
 
        '</td>' +
 
        '<td></td>';
 
    var $last_node = $('.last_new_member').last(); // empty tr between last and add
 
    var next_id = $('.new_members').length;
 
    $last_node.before($('<tr class="new_members">').append(_html.format(next_id)));
 
    $last_node.before($('<tr class="new_members">').append(template.format(next_id, perm_type)));
 
    MembersAutoComplete($("#perm_new_member_name_"+next_id),
 
            $("#perm_container_"+next_id), users_list, groups_list);
 
}
 

	
 
function ajaxActionRevokePermission(url, obj_id, obj_type, field_id, extra_data) {
 
    var success = function (o) {
 
            $('#' + field_id).remove();
 
        };
 
    var failure = function (o) {
 
            alert(_TM['Failed to revoke permission'] + ": " + o.status);
 
        };
 
    var query_params = {};
 
    // put extra data into POST
 
    if (extra_data !== undefined && (typeof extra_data === 'object')){
 
        for(var k in extra_data){
 
            query_params[k] = extra_data[k];
 
        }
 
    }
 

	
 
    if (obj_type=='user'){
 
        query_params['user_id'] = obj_id;
 
        query_params['obj_type'] = 'user';
 
    }
 
    else if (obj_type=='user_group'){
 
        query_params['user_group_id'] = obj_id;
 
        query_params['obj_type'] = 'user_group';
 
    }
 

	
 
    ajaxPOST(url, query_params, success, failure);
 
};
 

	
 
/* Multi selectors */
 

	
 
var MultiSelectWidget = function(selected_id, available_id, form_id){
 
    var $availableselect = $('#' + available_id);
 
    var $selectedselect = $('#' + selected_id);
 

	
 
    //fill available only with those not in selected
 
    var $selectedoptions = $selectedselect.children('option');
 
    $availableselect.children('option').filter(function(i, e){
 
            for(var j = 0, node; node = $selectedoptions[j]; j++){
 
                if(node.value == e.value){
 
                    return true;
 
                }
 
            }
 
            return false;
 
        }).remove();
 

	
 
    $('#add_element').click(function(e){
 
            $selectedselect.append($availableselect.children('option:selected'));
 
        });
 
    $('#remove_element').click(function(e){
 
            $availableselect.append($selectedselect.children('option:selected'));
 
        });
 

	
 
    $('#'+form_id).submit(function(){
 
            $selectedselect.children('option').each(function(i, e){
 
                e.selected = 'selected';
 
            });
 
        });
 
}
 

	
 

	
 
/**
 
 Branch Sorting callback for select2, modifying the filtered result so prefix
 
 matches come before matches in the line.
 
 **/
 
var branchSort = function(results, container, query) {
 
    if (query.term) {
 
        return results.sort(function (a, b) {
 
            // Put closed branches after open ones (a bit of a hack ...)
 
            var aClosed = a.text.indexOf("(closed)") > -1,
 
                bClosed = b.text.indexOf("(closed)") > -1;
 
            if (aClosed && !bClosed) {
 
                return 1;
 
            }
 
            if (bClosed && !aClosed) {
 
                return -1;
 
            }
 

	
 
            // Put early (especially prefix) matches before later matches
 
            var aPos = a.text.toLowerCase().indexOf(query.term.toLowerCase()),
 
                bPos = b.text.toLowerCase().indexOf(query.term.toLowerCase());
 
            if (aPos < bPos) {
 
                return -1;
 
            }
 
            if (bPos < aPos) {
 
                return 1;
 
            }
 

	
 
            // Default sorting
 
            if (a.text > b.text) {
 
                return 1;
 
            }
 
            if (a.text < b.text) {
 
                return -1;
 
            }
 
            return 0;
 
        });
 
    }
 
    return results;
 
};
 

	
 
var prefixFirstSort = function(results, container, query) {
 
    if (query.term) {
 
        return results.sort(function (a, b) {
 
            // if parent node, no sorting
 
            if (a.children != undefined || b.children != undefined) {
 
                return 0;
 
            }
 

	
 
            // Put prefix matches before matches in the line
 
            var aPos = a.text.toLowerCase().indexOf(query.term.toLowerCase()),
 
                bPos = b.text.toLowerCase().indexOf(query.term.toLowerCase());
 
            if (aPos === 0 && bPos !== 0) {
 
                return -1;
 
            }
 
            if (bPos === 0 && aPos !== 0) {
 
                return 1;
 
            }
 

	
 
            // Default sorting
 
            if (a.text > b.text) {
 
                return 1;
 
            }
 
            if (a.text < b.text) {
 
                return -1;
 
            }
 
            return 0;
 
        });
 
    }
 
    return results;
 
};
 

	
 
/* Helper for jQuery DataTables */
 

	
 
var updateRowCountCallback = function updateRowCountCallback($elem, onlyDisplayed) {
 
    return function drawCallback() {
 
        var info = this.api().page.info(),
 
            count = onlyDisplayed === true ? info.recordsDisplay : info.recordsTotal;
 
        $elem.html(count);
 
    }
 
};
kallithea/templates/admin/repo_groups/repo_group_edit_perms.html
Show inline comments
 
${h.form(url('edit_repo_group_perms', group_name=c.repo_group.group_name))}
 
<div class="form">
 
    <div>
 
        <div>
 
            <table id="permissions_manage" class="table">
 
                <tr>
 
                    <td>${_('None')}<br />(${_('Not visible')})</td>
 
                    <td>${_('Read')}<br />(${_('Visible')})</td>
 
                    <td>${_('Write')}<br />(${_('Add repos')})</td>
 
                    <td>${_('Admin')}<br />(${_('Add/Edit groups')})</td>
 
                    <td>${_('User/User Group')}</td>
 
                    <td></td>
 
                </tr>
 
                ## USERS
 
                %for r2p in c.repo_group.repo_group_to_perm:
 
                    ##forbid revoking permission from yourself, except if you're an super admin
 
                    <tr id="id${id(r2p.user.username)}">
 
                      %if request.authuser.user_id != r2p.user.user_id or request.authuser.is_admin:
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'group.none')}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'group.read')}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'group.write')}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'group.admin')}</td>
 
                        <td>
 
                            ${h.gravatar(r2p.user.email, cls="perm-gravatar", size=14)}
 
                            %if h.HasPermissionAny('hg.admin')() and r2p.user.username != 'default':
 
                             <a href="${h.url('edit_user',id=r2p.user.user_id)}">${r2p.user.username}</a>
 
                            %else:
 
                             ${r2p.user.username if r2p.user.username != 'default' else _('Default')}
 
                            %endif
 
                        </td>
 
                        <td>
 
                          %if r2p.user.username !='default':
 
                            <span style="color:#da4f49" class="btn btn-default btn-xs" onclick="ajaxActionRevoke(${r2p.user.user_id}, 'user', '${'id%s'%id(r2p.user.username)}', '${r2p.user.username}')">
 
                             <i class="icon-minus-circled"></i> ${_('Revoke')}
 
                            </span>
 
                          %endif
 
                        </td>
 
                      %else:
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'group.none', disabled="disabled")}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'group.read', disabled="disabled")}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'group.write', disabled="disabled")}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'group.admin', disabled="disabled")}</td>
 
                        <td>
 
                            ${h.gravatar(r2p.user.email, cls="perm-gravatar", size=14)}
 
                            ${r2p.user.username if r2p.user.username != 'default' else _('Default')}
 
                        </td>
 
                        <td><i class="icon-user"></i> ${_('Admin')}</td>
 
                      %endif
 
                    </tr>
 
                %endfor
 

	
 
                ## USER GROUPS
 
                %for g2p in c.repo_group.users_group_to_perm:
 
                    <tr id="id${id(g2p.users_group.users_group_name)}">
 
                        <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.none')}</td>
 
                        <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.read')}</td>
 
                        <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.write')}</td>
 
                        <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.admin')}</td>
 
                        <td>
 
                            <i class="icon-users"></i>
 
                            %if h.HasPermissionAny('hg.admin')():
 
                             <a href="${h.url('edit_users_group',id=g2p.users_group.users_group_id)}">
 
                                 ${g2p.users_group.users_group_name}
 
                             </a>
 
                            %else:
 
                             ${g2p.users_group.users_group_name}
 
                            %endif
 
                        </td>
 
                        <td>
 
                            <span style="color:#da4f49" class="btn btn-default btn-xs" onclick="ajaxActionRevoke(${g2p.users_group.users_group_id}, 'user_group', '${'id%s'%id(g2p.users_group.users_group_name)}', '${g2p.users_group.users_group_name}')">
 
                            <i class="icon-minus-circled"></i> ${_('Revoke')}
 
                            </span>
 
                        </td>
 
                    </tr>
 
                %endfor
 

	
 
                <%
 
                _tmpl = """\
 
                    <td><input type="radio" value="group.none" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
 
                    <td><input type="radio" value="group.read" checked="checked" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
 
                    <td><input type="radio" value="group.write" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
 
                    <td><input type="radio" value="group.admin" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
 
                    <td class="ac"> \
 
                        <div class="perm_ac" id="perm_ac_{0}"> \
 
                            <input class="yui-ac-input" id="perm_new_member_name_{0}" name="perm_new_member_name_{0}" value="" type="text"> \
 
                            <input id="perm_new_member_type_{0}" name="perm_new_member_type_{0}" value="" type="hidden">  \
 
                            <div id="perm_container_{0}"></div> \
 
                        </div> \
 
                    </td> \
 
                    <td></td>"""
 
                %>
 
                ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl'
 
                ## New entries added by addPermAction here.
 
                <tr class="new_members last_new_member" id="add_perm_input"><td colspan="6"></td></tr>
 
                <tr>
 
                    <td colspan="6">
 
                        <span id="add_perm" style="cursor: pointer;">
 
                            <i class="icon-plus"></i> ${_('Add new')}
 
                        </span>
 
                    </td>
 
                </tr>
 
                <tr>
 
                    <td colspan="6">
 
                       ${_('Apply to children')}:
 
                       ${h.radio('recursive', 'none', label=_('None'), checked="checked")}
 
                       ${h.radio('recursive', 'groups', label=_('Repository Groups'))}
 
                       ${h.radio('recursive', 'repos', label=_('Repositories'))}
 
                       ${h.radio('recursive', 'all', label=_('Both'))}
 
                       <span class="help-block">${_('Set or revoke permission to all children of that group, including non-private repositories and other groups if selected.')}</span>
 
                    </td>
 
                </tr>
 
            </table>
 
        </div>
 
        <div class="buttons">
 
            ${h.submit('save',_('Save'),class_="btn btn-default")}
 
            ${h.reset('reset',_('Reset'),class_="btn btn-default")}
 
        </div>
 
    </div>
 
</div>
 
${h.end_form()}
 

	
 
<script type="text/javascript">
 
    function ajaxActionRevoke(obj_id, obj_type, field_id, obj_name) {
 
        url = ${h.jshtml(h.url('edit_repo_group_perms_delete', group_name=c.repo_group.group_name))};
 
        var revoke_msg = _TM['Confirm to revoke permission for {0}: {1} ?'].format(obj_type.replace('_', ' '), obj_name);
 
        if (confirm(revoke_msg)){
 
            var recursive = $('input[name=recursive]:checked').val();
 
            ajaxActionRevokePermission(url, obj_id, obj_type, field_id, {recursive:recursive});
 
        }
 
    };
 

	
 
    $(document).ready(function () {
 
        if (!$('#perm_new_member_name').hasClass('error')) {
 
            $('#add_perm_input').hide();
 
        }
 
        $('#add_perm').click(function () {
 
            addPermAction(${h.jshtml(_tmpl)}, ${h.js(c.users_array)}, ${h.js(c.user_groups_array)});
 
            addPermAction('group', ${h.js(c.users_array)}, ${h.js(c.user_groups_array)});
 
        });
 
    });
 
</script>
kallithea/templates/admin/repos/repo_edit_permissions.html
Show inline comments
 
${h.form(url('edit_repo_perms_update', repo_name=c.repo_name))}
 
<div class="form">
 
    <div class="form-horizontal">
 
        <div class="form-group">
 
            ${h.hidden('repo_private')}
 
            <table id="permissions_manage" class="table table-condensed">
 
                <tr>
 
                    <td>${_('None')}</td>
 
                    <td>${_('Read')}</td>
 
                    <td>${_('Write')}</td>
 
                    <td>${_('Admin')}</td>
 
                    <td>${_('User/User Group')}</td>
 
                    <td></td>
 
                </tr>
 
                ## USERS
 
                %for r2p in sorted(c.repo_info.repo_to_perm, key=lambda x: x.user.username != 'default' and x.user.username):
 
                    %if r2p.user.username =='default' and c.repo_info.private:
 
                        <tr>
 
                            <td colspan="4">
 
                                <span class="private_repo_msg">
 
                                ${_('Private Repository')}
 
                                </span>
 
                            </td>
 
                            <td class="private_repo_msg"><i class="icon-user"></i> ${_('Default')}</td>
 
                        </tr>
 
                    %else:
 
                    <tr id="id${id(r2p.user.username)}">
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'repository.none')}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'repository.read')}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'repository.write')}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'repository.admin')}</td>
 
                        <td>
 
                            ${h.gravatar(r2p.user.email, size=14)}
 
                            %if h.HasPermissionAny('hg.admin')() and r2p.user.username != 'default':
 
                             <a href="${h.url('edit_user',id=r2p.user.user_id)}">${r2p.user.username}</a>
 
                            %else:
 
                             ${r2p.user.username if r2p.user.username != 'default' else _('Default')}
 
                            %endif
 
                        </td>
 
                        <td>
 
                          %if r2p.user.username !='default':
 
                            <span style="color:#da4f49" class="btn btn-default btn-xs" onclick="ajaxActionRevoke(${r2p.user.user_id}, 'user', '${'id%s'%id(r2p.user.username)}', '${r2p.user.username}')">
 
                            <i class="icon-minus-circled"></i> ${_('Revoke')}
 
                            </span>
 
                          %endif
 
                        </td>
 
                    </tr>
 
                    %endif
 
                %endfor
 

	
 
                ## USER GROUPS
 
                %for g2p in sorted(c.repo_info.users_group_to_perm, key=lambda x:x.users_group.users_group_name):
 
                    <tr id="id${id(g2p.users_group.users_group_name)}">
 
                        <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'repository.none')}</td>
 
                        <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'repository.read')}</td>
 
                        <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'repository.write')}</td>
 
                        <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'repository.admin')}</td>
 
                        <td>
 
                            <i class="icon-users"></i>
 
                            %if h.HasPermissionAny('hg.admin')():
 
                             <a href="${h.url('edit_users_group',id=g2p.users_group.users_group_id)}">${g2p.users_group.users_group_name}</a>
 
                            %else:
 
                             ${g2p.users_group.users_group_name}
 
                            %endif
 
                        </td>
 
                        <td>
 
                            <span style="color:#da4f49" class="btn btn-default btn-xs" onclick="ajaxActionRevoke(${g2p.users_group.users_group_id}, 'user_group', '${'id%s'%id(g2p.users_group.users_group_name)}', '${g2p.users_group.users_group_name}')">
 
                            <i class="icon-minus-circled"></i> ${_('Revoke')}
 
                            </span>
 
                        </td>
 
                    </tr>
 
                %endfor
 

	
 
                <%
 
                _tmpl = """\
 
                    <td><input type="radio" value="repository.none" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
 
                    <td><input type="radio" value="repository.read" checked="checked" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
 
                    <td><input type="radio" value="repository.write" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
 
                    <td><input type="radio" value="repository.admin" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
 
                    <td class="ac"> \
 
                        <div class="perm_ac" id="perm_ac_{0}"> \
 
                            <input class="yui-ac-input" id="perm_new_member_name_{0}" name="perm_new_member_name_{0}" value="" type="text"> \
 
                            <input id="perm_new_member_type_{0}" name="perm_new_member_type_{0}" value="" type="hidden">  \
 
                            <div id="perm_container_{0}"></div> \
 
                        </div> \
 
                    </td> \
 
                    <td></td>"""
 
                %>
 
                ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl'
 
                ## New entries added by addPermAction here.
 
                <tr class="new_members last_new_member" id="add_perm_input"><td colspan="6"></td></tr>
 
                <tr>
 
                    <td colspan="6">
 
                        <span id="add_perm" style="cursor: pointer;">
 
                            <i class="icon-plus"></i> ${_('Add new')}
 
                        </span>
 
                    </td>
 
                </tr>
 
            </table>
 
        </div>
 
        <div class="form-group">
 
            ${h.submit('save',_('Save'),class_="btn btn-default")}
 
            ${h.reset('reset',_('Reset'),class_="btn btn-default")}
 
        </div>
 
    </div>
 
</div>
 
${h.end_form()}
 

	
 
<script type="text/javascript">
 
    function ajaxActionRevoke(obj_id, obj_type, field_id, obj_name) {
 
        url = ${h.js(h.url('edit_repo_perms_revoke',repo_name=c.repo_name))};
 
        var revoke_msg = _TM['Confirm to revoke permission for {0}: {1} ?'].format(obj_type.replace('_', ' '), obj_name);
 
        if (confirm(revoke_msg)){
 
            ajaxActionRevokePermission(url, obj_id, obj_type, field_id);
 
        }
 
    };
 

	
 
    $(document).ready(function () {
 
        if (!$('#perm_new_member_name').hasClass('error')) {
 
            $('#add_perm_input').hide();
 
        }
 
        $('#add_perm').click(function () {
 
            addPermAction(${h.jshtml(_tmpl)}, ${h.js(c.users_array)}, ${h.js(c.user_groups_array)});
 
            addPermAction('repository', ${h.js(c.users_array)}, ${h.js(c.user_groups_array)});
 
        });
 
    });
 
</script>
kallithea/templates/admin/user_groups/user_group_edit_perms.html
Show inline comments
 
${h.form(url('edit_user_group_perms_update', id=c.user_group.users_group_id))}
 
<div class="form">
 
   <div>
 
        <div>
 
            <table id="permissions_manage" class="table">
 
                <tr>
 
                    <td>${_('None')}</td>
 
                    <td>${_('Read')}</td>
 
                    <td>${_('Write')}</td>
 
                    <td>${_('Admin')}</td>
 
                    <td>${_('User/User Group')}</td>
 
                    <td></td>
 
                </tr>
 
                ## USERS
 
                %for r2p in c.user_group.user_user_group_to_perm:
 
                    ##forbid revoking permission from yourself, except if you're an super admin
 
                    <tr id="id${id(r2p.user.username)}">
 
                      %if request.authuser.user_id != r2p.user.user_id or request.authuser.is_admin:
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.none')}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.read')}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.write')}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.admin')}</td>
 
                        <td>
 
                            ${h.gravatar(r2p.user.email, cls="perm-gravatar", size=14)}
 
                            %if h.HasPermissionAny('hg.admin')() and r2p.user.username != 'default':
 
                             <a href="${h.url('edit_user',id=r2p.user.user_id)}">${r2p.user.username}</a>
 
                            %else:
 
                             ${r2p.user.username if r2p.user.username != 'default' else _('Default')}
 
                            %endif
 
                        </td>
 
                        <td>
 
                          %if r2p.user.username !='default':
 
                            <span style="color:#da4f49" class="btn btn-default btn-xs" onclick="ajaxActionRevoke(${r2p.user.user_id}, 'user', '${'id%s'%id(r2p.user.username)}', '${r2p.user.username}')">
 
                             <i class="icon-minus-circled"></i> ${_('Revoke')}
 
                            </span>
 
                          %endif
 
                        </td>
 
                      %else:
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.none', disabled="disabled")}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.read', disabled="disabled")}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.write', disabled="disabled")}</td>
 
                        <td>${h.radio('u_perm_%s' % r2p.user.username,'usergroup.admin', disabled="disabled")}</td>
 
                        <td>
 
                            ${h.gravatar(r2p.user.email, cls="perm-gravatar", size=14)}
 
                            ${r2p.user.username if r2p.user.username != 'default' else _('Default')}
 
                        </td>
 
                        <td><i class="icon-user"></i> ${_('Admin')}</td>
 
                      %endif
 
                    </tr>
 
                %endfor
 

	
 
                ## USER GROUPS
 
                %for g2p in c.user_group.user_group_user_group_to_perm:
 
                    <tr id="id${id(g2p.user_group.users_group_name)}">
 
                        <td>${h.radio('g_perm_%s' % g2p.user_group.users_group_name,'usergroup.none')}</td>
 
                        <td>${h.radio('g_perm_%s' % g2p.user_group.users_group_name,'usergroup.read')}</td>
 
                        <td>${h.radio('g_perm_%s' % g2p.user_group.users_group_name,'usergroup.write')}</td>
 
                        <td>${h.radio('g_perm_%s' % g2p.user_group.users_group_name,'usergroup.admin')}</td>
 
                        <td>
 
                            <i class="icon-users"></i>
 
                            %if h.HasPermissionAny('hg.admin')():
 
                             <a href="${h.url('edit_users_group',id=g2p.user_group.users_group_id)}">
 
                                 ${g2p.user_group.users_group_name}
 
                             </a>
 
                            %else:
 
                             ${g2p.user_group.users_group_name}
 
                            %endif
 
                        </td>
 
                        <td>
 
                            <span style="color:#da4f49" class="btn btn-default btn-xs" onclick="ajaxActionRevoke(${g2p.user_group.users_group_id}, 'user_group', '${'id%s'%id(g2p.user_group.users_group_name)}', '${g2p.user_group.users_group_name}')">
 
                            <i class="icon-minus-circled"></i> ${_('Revoke')}
 
                            </span>
 
                        </td>
 
                    </tr>
 
                %endfor
 

	
 
                <%
 
                _tmpl = """\
 
                    <td><input type="radio" value="usergroup.none" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
 
                    <td><input type="radio" value="usergroup.read" checked="checked" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
 
                    <td><input type="radio" value="usergroup.write" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
 
                    <td><input type="radio" value="usergroup.admin" name="perm_new_member_{0}" id="perm_new_member_{0}"></td> \
 
                    <td class="ac"> \
 
                        <div class="perm_ac" id="perm_ac_{0}"> \
 
                            <input class="yui-ac-input" id="perm_new_member_name_{0}" name="perm_new_member_name_{0}" value="" type="text"> \
 
                            <input id="perm_new_member_type_{0}" name="perm_new_member_type_{0}" value="" type="hidden">  \
 
                            <div id="perm_container_{0}"></div> \
 
                        </div> \
 
                    </td> \
 
                    <td></td>"""
 
                %>
 
                ## ADD HERE DYNAMICALLY NEW INPUTS FROM THE '_tmpl'
 
                ## New entries added by addPermAction here.
 
                <tr class="new_members last_new_member" id="add_perm_input"><td colspan="6"></td></tr>
 
                <tr>
 
                    <td colspan="6">
 
                        <span id="add_perm" class="btn">
 
                            <i class="icon-plus"></i> ${_('Add new')}
 
                        </span>
 
                    </td>
 
                </tr>
 
            </table>
 
        </div>
 
        <div class="buttons">
 
            ${h.submit('save',_('Save'),class_="btn btn-default")}
 
            ${h.reset('reset',_('Reset'),class_="btn btn-default")}
 
        </div>
 
   </div>
 
</div>
 
${h.end_form()}
 

	
 
<script type="text/javascript">
 
    function ajaxActionRevoke(obj_id, obj_type, field_id, obj_name) {
 
        url = ${h.js(h.url('edit_user_group_perms_delete', id=c.user_group.users_group_id))};
 
        var revoke_msg = _TM['Confirm to revoke permission for {0}: {1} ?'].format(obj_type.replace('_', ' '), obj_name);
 
        if (confirm(revoke_msg)){
 
            ajaxActionRevokePermission(url, obj_id, obj_type, field_id);
 
        }
 
    };
 

	
 
    $(document).ready(function () {
 
        if (!$('#perm_new_member_name').hasClass('error')) {
 
            $('#add_perm_input').hide();
 
        }
 
        $('#add_perm').click(function () {
 
            addPermAction(${h.jshtml(_tmpl)}, ${h.js(c.users_array)}, ${h.js(c.user_groups_array)});
 
            addPermAction('usergroup', ${h.js(c.users_array)}, ${h.js(c.user_groups_array)});
 
        });
 
    });
 
</script>
0 comments (0 inline, 0 general)