# HG changeset patch # User Marcin Kuzminski # Date 1361321990 -3600 # Node ID cb40b3f6428c42100246fc60f2bdffea91d5474e # Parent bd5420ea396ba991e20c57f4a705ce4facf6d000 review members are dynamically changed based on selected other_repo owner - implemented pyroutes for smarter JS url handling - fixed some old style global var routing diff -r bd5420ea396b -r cb40b3f6428c rhodecode/controllers/pullrequests.py --- a/rhodecode/controllers/pullrequests.py Tue Feb 19 23:42:37 2013 +0100 +++ b/rhodecode/controllers/pullrequests.py Wed Feb 20 01:59:50 2013 +0100 @@ -129,16 +129,25 @@ c.other_repos.extend(c.org_repos) c.default_other_repo = org_repo.repo_name c.default_other_refs, c.default_other_ref = self._get_repo_refs(org_repo.scm_instance) + usr_data = lambda usr: dict(user_id=usr.user_id, + username=usr.username, + firstname=usr.firstname, + lastname=usr.lastname, + gravatar_link=h.gravatar_url(usr.email, 14)) other_repos_info[org_repo.repo_name] = { + 'user': usr_data(org_repo.user), 'description': org_repo.description, - 'revs': h.select('other_ref', c.default_other_ref, c.default_other_refs, class_='refs') + 'revs': h.select('other_ref', c.default_other_ref, + c.default_other_refs, class_='refs') } - # gather forks and add to this list ... even though it is rare to request forks to pull their parent + # gather forks and add to this list ... even though it is rare to + # request forks to pull their parent for fork in org_repo.forks: c.other_repos.append((fork.repo_name, fork.repo_name)) refs, default_ref = self._get_repo_refs(fork.scm_instance) other_repos_info[fork.repo_name] = { + 'user': usr_data(fork.user), 'description': fork.description, 'revs': h.select('other_ref', default_ref, refs, class_='refs') } @@ -149,12 +158,15 @@ c.default_other_refs, c.default_other_ref = self._get_repo_refs(org_repo.parent.scm_instance) c.other_repos.append((org_repo.parent.repo_name, org_repo.parent.repo_name)) other_repos_info[org_repo.parent.repo_name] = { + 'user': usr_data(org_repo.parent.user), 'description': org_repo.parent.description, - 'revs': h.select('other_ref', c.default_other_ref, c.default_other_refs, class_='refs') + 'revs': h.select('other_ref', c.default_other_ref, + c.default_other_refs, class_='refs') } c.other_repos_info = json.dumps(other_repos_info) - c.review_members = [org_repo.user] + # other repo owner + c.review_members = [] return render('/pullrequests/pullrequest.html') @NotAnonymous() diff -r bd5420ea396b -r cb40b3f6428c rhodecode/public/js/pyroutes_map.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rhodecode/public/js/pyroutes_map.js Wed Feb 20 01:59:50 2013 +0100 @@ -0,0 +1,11 @@ +//Format is key == name +// "mark_error_fixed": [ # key +// "/mark_error_fixed/%(error_id)s", #url template +// [ +// "error_id" # list of args +// ] +// ], +// +var PROUTES_MAP = { + +} \ No newline at end of file diff -r bd5420ea396b -r cb40b3f6428c rhodecode/public/js/rhodecode.js --- a/rhodecode/public/js/rhodecode.js Tue Feb 19 23:42:37 2013 +0100 +++ b/rhodecode/public/js/rhodecode.js Wed Feb 20 01:59:50 2013 +0100 @@ -163,7 +163,175 @@ } } +/** + * PyRoutesJS + * + * Usage pyroutes.url('mark_error_fixed',{"error_id":error_id}) // /mark_error_fixed/ + */ +var pyroutes = (function() { + // access global map defined in special file pyroutes + var matchlist = PROUTES_MAP; + 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]; + 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); + } + + return result; + }, + 'register': function(route_name, route_tmpl, req_params) { + if (typeof(req_params) != 'object') { + req_params = []; + } + //fix escape + route_tmpl = unescape(route_tmpl); + keys = []; + for (o in req_params){ + keys.push(req_params[o]) + } + matchlist[route_name] = [ + route_tmpl, + keys + ] + }, + '_routes': function(){ + return matchlist; + } + } +})(); @@ -333,8 +501,9 @@ YUD.setAttribute(target,'id',ttid); YUD.setAttribute(target, 'title',_TM['loading...']); YAHOO.yuitip.main.set_listeners(target); - YAHOO.yuitip.main.show_yuitip(e, target); - ajaxGET(LAZY_CS_URL.replace('__NAME__',repo_name).replace('__REV__', rid), success) + YAHOO.yuitip.main.show_yuitip(e, target); + var url = pyroutes.url('changeset_info', {"repo_name":repo_name, "revision": rid}); + ajaxGET(url, success) } }); }; @@ -396,7 +565,7 @@ if(!YUD.hasClass(target, 'loaded')){ YUD.get(target).innerHTML = _TM['loading...']; - var url = REPO_SIZE_URL.replace('__NAME__', repo_name); + var url = pyroutes.url('repo_size', {"repo_name":repo_name}); YUC.asyncRequest('POST',url,{ success:function(o){ YUD.get(target).innerHTML = JSON.parse(o.responseText); @@ -725,24 +894,6 @@ ajaxPOST(url,postData,success); } -var updateReviewers = function(reviewers_ids){ - if (reviewers_ids === undefined){ - var reviewers_ids = []; - var ids = YUQ('#review_members input'); - for(var i=0; i'+ + '
gravatar
'+ + '
{1}
'+ + ''+ + ''+ + ''+ + '' ; + var displayname = "{0} {1} ({2})".format(fname,lname,nname); + var element = tmpl.format(gravatar_link,displayname,id); + // check if we don't have this ID already in + var ids = []; + var _els = YUQ('#review_members li'); + for (el in _els){ + ids.push(_els[el].id) + } + if(ids.indexOf('reviewer_'+id) == -1){ + //only add if it's not there + members.innerHTML += element; + } + +} + +var removeReviewMember = function(reviewer_id, repo_name, pull_request_id){ + var el = YUD.get('reviewer_{0}'.format(reviewer_id)); + if (el.parentNode !== undefined){ + el.parentNode.removeChild(el); + } +} + +var updateReviewers = function(reviewers_ids, repo_name, pull_request_id){ + if (reviewers_ids === undefined){ + var reviewers_ids = []; + var ids = YUQ('#review_members input'); + for(var i=0; i'+ - '
gravatar
'+ - '
{1}
'+ - ''+ - ''+ - ''+ - '' - - var displayname = "{0} {1} ({2})".format(oData.fname,oData.lname,oData.nname); - var element = tmpl.format(oData.gravatar_lnk,displayname,oData.id); - members.innerHTML += element; + addReviewMember(oData.id, oData.fname, oData.lname, oData.nname, + oData.gravatar_lnk); myAC.dataSource.cache.push(oData.id); YUD.get('user').value = '' } @@ -1651,7 +1830,6 @@ }; } - /** * QUICK REPO MENU */ diff -r bd5420ea396b -r cb40b3f6428c rhodecode/templates/base/root.html --- a/rhodecode/templates/base/root.html Tue Feb 19 23:42:37 2013 +0100 +++ b/rhodecode/templates/base/root.html Wed Feb 20 01:59:50 2013 +0100 @@ -53,9 +53,8 @@ 'Selection link': "${_('Selection link')}", }; var _TM = TRANSLATION_MAP; + var TOGGLE_FOLLOW_URL = "${h.url('toggle_following')}"; - var LAZY_CS_URL = "${h.url('changeset_info', repo_name='__NAME__', revision='__REV__')}"; - var REPO_SIZE_URL = "${h.url('repo_size', repo_name='__NAME__')}"; @@ -64,6 +63,7 @@ + ## EXTRA FOR JS ${self.js_extra()} @@ -82,6 +82,10 @@ tooltip_activate(); show_more_event(); show_changeset_tooltip(); + // routes registration + pyroutes.register('toggle_following', "${h.url('toggle_following')}"); + pyroutes.register('changeset_info', "${h.url('changeset_info', repo_name='%(repo_name)s', revision='%(revision)s')}", ['repo_name', 'revision']); + pyroutes.register('repo_size', "${h.url('repo_size', repo_name='%(repo_name)s')}", ['repo_name']); }) diff -r bd5420ea396b -r cb40b3f6428c rhodecode/templates/pullrequests/pullrequest.html --- a/rhodecode/templates/pullrequests/pullrequest.html Tue Feb 19 23:42:37 2013 +0100 +++ b/rhodecode/templates/pullrequests/pullrequest.html Wed Feb 20 01:59:50 2013 +0100 @@ -67,7 +67,7 @@
gravatar
${member.full_name} (${_('owner')})
- + %endfor @@ -161,12 +161,18 @@ ypjax(url,'pull_request_overview', function(data){ var sel_box = YUQ('#pull_request_form #other_repo')[0]; var repo_name = sel_box.options[sel_box.selectedIndex].value; + var _data = other_repos_info[repo_name]; YUD.get('pull_request_overview_url').href = url; YUD.setStyle(YUD.get('pull_request_overview_url').parentElement,'display',''); YUD.get('other_repo_desc').innerHTML = other_repos_info[repo_name]['description']; YUD.get('other_ref').innerHTML = other_repos_info[repo_name]['revs']; // select back the revision that was just compared setSelectValue(YUD.get('other_ref'), rev_data['other_ref']); + // reset && add the reviewer based on selected repo + YUD.get('review_members').innerHTML = ''; + addReviewMember(_data.user.user_id, _data.user.firstname, + _data.user.lastname, _data.user.username, + _data.user.gravatar_link); }) } diff -r bd5420ea396b -r cb40b3f6428c rhodecode/templates/pullrequests/pullrequest_show.html --- a/rhodecode/templates/pullrequests/pullrequest_show.html Tue Feb 19 23:42:37 2013 +0100 +++ b/rhodecode/templates/pullrequests/pullrequest_show.html Wed Feb 20 01:59:50 2013 +0100 @@ -28,7 +28,7 @@
- +
@@ -140,7 +140,7 @@
${member.full_name} (${_('owner') if c.pull_request.user_id == member.user_id else _('reviewer')})
%if not c.pull_request.is_closed() and (h.HasPermissionAny('hg.admin', 'repository.admin')() or c.pull_request.user_id == c.rhodecode_user.user_id): - + %endif
@@ -152,11 +152,11 @@ %if h.HasPermissionAny('hg.admin', 'repository.admin')() or c.pull_request.author.user_id == c.rhodecode_user.user_id:
${h.text('user', class_='yui-ac-input')} - ${_('Add reviewer to this pull request.')} + ${_('Add or remove reviewer to this pull request.')}
- ${_('save')} + ${_('save changes')}
%endif
@@ -167,9 +167,14 @@ ## diff block @@ -228,7 +233,7 @@ renderInlineComments(file_comments); YUE.on(YUD.get('update_pull_request'),'click',function(e){ - updateReviewers(); + updateReviewers(undefined, "${c.repo_name}", "${c.pull_request.pull_request_id}"); }) })