##// END OF EJS Templates
implements #636, lazy loading of history and authors to speed up page responsiveness....
marcink -
r3001:37c7abd3 beta
parent child Browse files
Show More
@@ -0,0 +1,25 b''
1 <dl>
2 <dt class="file_history">${_('History')}</dt>
3 <dd>
4 <div>
5 <div style="float:left">
6 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
7 ${h.hidden('diff2',c.file_changeset.raw_id)}
8 ${h.select('diff1',c.file_changeset.raw_id,c.file_history)}
9 ${h.submit('diff',_('diff to revision'),class_="ui-btn")}
10 ${h.submit('show_rev',_('show at revision'),class_="ui-btn")}
11 ${h.hidden('annotate', c.annotate)}
12 ${h.end_form()}
13 </div>
14 <div class="file_author">
15 <div class="item">${h.literal(ungettext(u'%s author',u'%s authors',len(c.authors)) % ('<b>%s</b>' % len(c.authors))) }</div>
16 %for email, user in c.authors:
17 <div class="contributor tooltip" style="float:left" title="${h.tooltip(user)}">
18 <div class="gravatar" style="margin:1px"><img alt="gravatar" src="${h.gravatar_url(email, 20)}"/> </div>
19 </div>
20 %endfor
21 </div>
22 </div>
23 <div style="clear:both"></div>
24 </dd>
25 </dl> No newline at end of file
@@ -534,6 +534,11 b' def make_map(config):'
534 controller='files', revision='tip', f_path='',
534 controller='files', revision='tip', f_path='',
535 conditions=dict(function=check_repo))
535 conditions=dict(function=check_repo))
536
536
537 rmap.connect('files_history_home',
538 '/{repo_name:.*?}/history/{revision}/{f_path:.*}',
539 controller='files', action='history', revision='tip', f_path='',
540 conditions=dict(function=check_repo))
541
537 rmap.connect('files_diff_home', '/{repo_name:.*?}/diff/{f_path:.*}',
542 rmap.connect('files_diff_home', '/{repo_name:.*?}/diff/{f_path:.*}',
538 controller='files', action='diff', revision='tip', f_path='',
543 controller='files', action='diff', revision='tip', f_path='',
539 conditions=dict(function=check_repo))
544 conditions=dict(function=check_repo))
@@ -155,12 +155,16 b' class FilesController(BaseRepoController'
155 c.file = c.changeset.get_node(f_path)
155 c.file = c.changeset.get_node(f_path)
156
156
157 if c.file.is_file():
157 if c.file.is_file():
158 c.file_history, _hist = self._get_node_history(c.changeset, f_path)
158 c.load_full_history = False
159 c.file_changeset = c.changeset
159 file_last_cs = c.file.last_changeset
160 if _hist:
160 c.file_changeset = (c.changeset
161 c.file_changeset = (c.changeset
161 if c.changeset.revision < file_last_cs.revision
162 if c.changeset.revision < _hist[0].revision
162 else file_last_cs)
163 else _hist[0])
163 _hist = []
164 c.file_history = []
165 if c.load_full_history:
166 c.file_history, _hist = self._get_node_history(c.changeset, f_path)
167
164 c.authors = []
168 c.authors = []
165 for a in set([x.author for x in _hist]):
169 for a in set([x.author for x in _hist]):
166 c.authors.append((h.email(a), h.person(a)))
170 c.authors.append((h.email(a), h.person(a)))
@@ -176,6 +180,23 b' class FilesController(BaseRepoController'
176
180
177 return render('files/files.html')
181 return render('files/files.html')
178
182
183 def history(self, repo_name, revision, f_path, annotate=False):
184 if request.environ.get('HTTP_X_PARTIAL_XHR'):
185 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
186 c.f_path = f_path
187 c.annotate = annotate
188 c.file = c.changeset.get_node(f_path)
189 if c.file.is_file():
190 file_last_cs = c.file.last_changeset
191 c.file_changeset = (c.changeset
192 if c.changeset.revision < file_last_cs.revision
193 else file_last_cs)
194 c.file_history, _hist = self._get_node_history(c.changeset, f_path)
195 c.authors = []
196 for a in set([x.author for x in _hist]):
197 c.authors.append((h.email(a), h.person(a)))
198 return render('files/files_history_box.html')
199
179 @LoginRequired()
200 @LoginRequired()
180 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
201 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
181 'repository.admin')
202 'repository.admin')
@@ -530,6 +551,8 b' class FilesController(BaseRepoController'
530 :param changesets: if passed don't calculate history and take
551 :param changesets: if passed don't calculate history and take
531 changesets defined in this list
552 changesets defined in this list
532 """
553 """
554 import time
555 s = time.time()
533 # calculate history based on tip
556 # calculate history based on tip
534 tip_cs = c.rhodecode_repo.get_changeset()
557 tip_cs = c.rhodecode_repo.get_changeset()
535 if changesets is None:
558 if changesets is None:
@@ -538,7 +561,7 b' class FilesController(BaseRepoController'
538 except (NodeDoesNotExistError, ChangesetError):
561 except (NodeDoesNotExistError, ChangesetError):
539 #this node is not present at tip !
562 #this node is not present at tip !
540 changesets = cs.get_file_history(f_path)
563 changesets = cs.get_file_history(f_path)
541
564 print time.time()-s
542 hist_l = []
565 hist_l = []
543
566
544 changesets_group = ([], _("Changesets"))
567 changesets_group = ([], _("Changesets"))
@@ -546,10 +569,11 b' class FilesController(BaseRepoController'
546 tags_group = ([], _("Tags"))
569 tags_group = ([], _("Tags"))
547 _hg = cs.repository.alias == 'hg'
570 _hg = cs.repository.alias == 'hg'
548 for chs in changesets:
571 for chs in changesets:
549 _branch = '(%s)' % chs.branch if _hg else ''
572 #_branch = '(%s)' % chs.branch if _hg else ''
573 _branch = chs.branch
550 n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
574 n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
551 changesets_group[0].append((chs.raw_id, n_desc,))
575 changesets_group[0].append((chs.raw_id, n_desc,))
552
576 print time.time()-s
553 hist_l.append(changesets_group)
577 hist_l.append(changesets_group)
554
578
555 for name, chs in c.rhodecode_repo.branches.items():
579 for name, chs in c.rhodecode_repo.branches.items():
@@ -559,7 +583,7 b' class FilesController(BaseRepoController'
559 for name, chs in c.rhodecode_repo.tags.items():
583 for name, chs in c.rhodecode_repo.tags.items():
560 tags_group[0].append((chs, name),)
584 tags_group[0].append((chs, name),)
561 hist_l.append(tags_group)
585 hist_l.append(tags_group)
562
586 print time.time()-s
563 return hist_l, changesets
587 return hist_l, changesets
564
588
565 @LoginRequired()
589 @LoginRequired()
@@ -951,54 +951,53 b' var getIdentNode = function(n){'
951 }
951 }
952 };
952 };
953
953
954 var getSelectionLink = function(selection_link_label) {
954 var getSelectionLink = function(e) {
955 return function(){
955
956 //get selection from start/to nodes
956 //get selection from start/to nodes
957 if (typeof window.getSelection != "undefined") {
957 if (typeof window.getSelection != "undefined") {
958 s = window.getSelection();
958 s = window.getSelection();
959
959
960 from = getIdentNode(s.anchorNode);
960 from = getIdentNode(s.anchorNode);
961 till = getIdentNode(s.focusNode);
961 till = getIdentNode(s.focusNode);
962
962
963 f_int = parseInt(from.id.replace('L',''));
963 f_int = parseInt(from.id.replace('L',''));
964 t_int = parseInt(till.id.replace('L',''));
964 t_int = parseInt(till.id.replace('L',''));
965
965
966 if (f_int > t_int){
966 if (f_int > t_int){
967 //highlight from bottom
967 //highlight from bottom
968 offset = -35;
968 offset = -35;
969 ranges = [t_int,f_int];
969 ranges = [t_int,f_int];
970
970
971 }
972 else{
973 //highligth from top
974 offset = 35;
975 ranges = [f_int,t_int];
976 }
977
978 if (ranges[0] != ranges[1]){
979 if(YUD.get('linktt') == null){
980 hl_div = document.createElement('div');
981 hl_div.id = 'linktt';
971 }
982 }
972 else{
983 anchor = '#L'+ranges[0]+'-'+ranges[1];
973 //highligth from top
984 hl_div.innerHTML = '';
974 offset = 35;
985 l = document.createElement('a');
975 ranges = [f_int,t_int];
986 l.href = location.href.substring(0,location.href.indexOf('#'))+anchor;
976 }
987 l.innerHTML = _TM['Selection link'];
988 hl_div.appendChild(l);
977
989
978 if (ranges[0] != ranges[1]){
990 YUD.get('body').appendChild(hl_div);
979 if(YUD.get('linktt') == null){
991
980 hl_div = document.createElement('div');
992 xy = YUD.getXY(till.id);
981 hl_div.id = 'linktt';
993
982 }
994 YUD.addClass('linktt','yui-tt');
983 anchor = '#L'+ranges[0]+'-'+ranges[1];
995 YUD.setStyle('linktt','top',xy[1]+offset+'px');
984 hl_div.innerHTML = '';
996 YUD.setStyle('linktt','left',xy[0]+'px');
985 l = document.createElement('a');
997 YUD.setStyle('linktt','visibility','visible');
986 l.href = location.href.substring(0,location.href.indexOf('#'))+anchor;
998 }
987 l.innerHTML = selection_link_label;
999 else{
988 hl_div.appendChild(l);
1000 YUD.setStyle('linktt','visibility','hidden');
989
990 YUD.get('body').appendChild(hl_div);
991
992 xy = YUD.getXY(till.id);
993
994 YUD.addClass('linktt','yui-tt');
995 YUD.setStyle('linktt','top',xy[1]+offset+'px');
996 YUD.setStyle('linktt','left',xy[0]+'px');
997 YUD.setStyle('linktt','visibility','visible');
998 }
999 else{
1000 YUD.setStyle('linktt','visibility','hidden');
1001 }
1002 }
1001 }
1003 }
1002 }
1004 };
1003 };
@@ -50,6 +50,7 b''
50 'Open new pull request': "${_('Open new pull request')}",
50 'Open new pull request': "${_('Open new pull request')}",
51 'Open new pull request for selected changesets': "${_('Open new pull request for selected changesets')}",
51 'Open new pull request for selected changesets': "${_('Open new pull request for selected changesets')}",
52 'Show selected changes __S -> __E': "${_('Show selected changes __S -> __E')}",
52 'Show selected changes __S -> __E': "${_('Show selected changes __S -> __E')}",
53 'Selection link': "${_('Selection link')}",
53 };
54 };
54 var _TM = TRANSLATION_MAP;
55 var _TM = TRANSLATION_MAP;
55 </script>
56 </script>
@@ -39,11 +39,13 b''
39
39
40 <script type="text/javascript">
40 <script type="text/javascript">
41 var CACHE = {};
41 var CACHE = {};
42 var CACHE_EXPIRE = 60*1000; //cache for 60s
42 var CACHE_EXPIRE = 5*60*1000; //cache for 5*60s
43 //used to construct links from the search list
43 //used to construct links from the search list
44 var url_base = '${h.url("files_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
44 var url_base = '${h.url("files_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
45 //send the nodelist request to this url
45 //send the nodelist request to this url
46 var node_list_url = '${h.url("files_nodelist_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
46 var node_list_url = '${h.url("files_nodelist_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
47 // send the node history requst to this url
48 var node_history_url = '${h.url("files_history_home",repo_name=c.repo_name,revision='__REV__',f_path='__FPATH__')}';
47
49
48 var ypjax_links = function(){
50 var ypjax_links = function(){
49 YUE.on(YUQ('.ypjax-link'), 'click',function(e){
51 YUE.on(YUQ('.ypjax-link'), 'click',function(e){
@@ -76,7 +78,7 b' var ypjax_links = function(){'
76
78
77 // Change our States and save some data for handling events
79 // Change our States and save some data for handling events
78 var data = {url:url,title:title, url_base:_url_base,
80 var data = {url:url,title:title, url_base:_url_base,
79 node_list_url:_node_list_url};
81 node_list_url:_node_list_url, rev:rev, f_path:f_path};
80 History.pushState(data, title, url);
82 History.pushState(data, title, url);
81
83
82 //now we're sure that we can do ypjax things
84 //now we're sure that we can do ypjax things
@@ -89,8 +91,19 b' var callbacks = function(State){'
89 ypjax_links();
91 ypjax_links();
90 tooltip_activate();
92 tooltip_activate();
91 fileBrowserListeners(State.url, State.data.node_list_url, State.data.url_base);
93 fileBrowserListeners(State.url, State.data.node_list_url, State.data.url_base);
92 YUE.on('hlcode','mouseup',getSelectionLink("${_('Selection link')}"));
94
93
95 if(YUD.get('hlcode')){
96 YUE.on('hlcode', 'mouseup', getSelectionLink);
97 }
98 //console.log(State);
99 if(YUD.get('load_node_history')){
100 //remove all listeners due to problems of history state
101 YUE.removeListener('load_node_history', 'click');
102 YUE.on('load_node_history', 'click', function(e){
103 var _url = node_history_url.replace('__REV__',State.data.rev).replace('__FPATH__', State.data.f_path);
104 ypjax(_url, 'node_history', function(o){})
105 });
106 }
94 // Inform Google Analytics of the change
107 // Inform Google Analytics of the change
95 if ( typeof window.pageTracker !== 'undefined' ) {
108 if ( typeof window.pageTracker !== 'undefined' ) {
96 window.pageTracker._trackPageview(State.url);
109 window.pageTracker._trackPageview(State.url);
@@ -133,7 +146,9 b' YUE.onDOMReady(function(){'
133 url: "${h.url.current()}",
146 url: "${h.url.current()}",
134 data: {
147 data: {
135 node_list_url: node_list_url.replace('__REV__',"${c.changeset.raw_id}").replace('__FPATH__', "${h.safe_unicode(c.file.path)}"),
148 node_list_url: node_list_url.replace('__REV__',"${c.changeset.raw_id}").replace('__FPATH__', "${h.safe_unicode(c.file.path)}"),
136 url_base: url_base.replace('__REV__',"${c.changeset.raw_id}")
149 url_base: url_base.replace('__REV__',"${c.changeset.raw_id}"),
150 rev:"${c.changeset.raw_id}",
151 f_path: "${h.safe_unicode(c.file.path)}"
137 }
152 }
138 }
153 }
139 fileBrowserListeners(_State.url, _State.data.node_list_url, _State.data.url_base);
154 fileBrowserListeners(_State.url, _State.data.node_list_url, _State.data.url_base);
@@ -1,29 +1,13 b''
1 <dl>
1 <div id="node_history">
2 <dt class="file_history">${_('History')}</dt>
2 %if c.load_full_history:
3 <dd>
3 <%include file='files_history_box.html'/>
4 <div>
4 %else:
5 <div style="float:left">
5 <div style="padding-bottom:10px">
6 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
6 <span id="load_node_history" class="ui-btn">${_('Load file history')}</span>
7 ${h.hidden('diff2',c.file_changeset.raw_id)}
7 </div>
8 ${h.select('diff1',c.file_changeset.raw_id,c.file_history)}
8 %endif
9 ${h.submit('diff',_('diff to revision'),class_="ui-btn")}
9 </div>
10 ${h.submit('show_rev',_('show at revision'),class_="ui-btn")}
11 ${h.hidden('annotate', c.annotate)}
12 ${h.end_form()}
13 </div>
14 <div class="file_author">
15 <div class="item">${h.literal(ungettext(u'%s author',u'%s authors',len(c.authors)) % ('<b>%s</b>' % len(c.authors))) }</div>
16 %for email, user in c.authors:
17 <div class="contributor tooltip" style="float:left" title="${h.tooltip(user)}">
18 <div class="gravatar" style="margin:1px"><img alt="gravatar" src="${h.gravatar_url(email, 20)}"/> </div>
19 </div>
20 %endfor
21 </div>
22 </div>
23 <div style="clear:both"></div>
24 </dd>
25
10
26 </dl>
27
11
28 <div id="body" class="codeblock">
12 <div id="body" class="codeblock">
29 <div class="code-header">
13 <div class="code-header">
@@ -113,6 +97,15 b' YUE.onDOMReady(function(){'
113
97
114 }
98 }
115
99
116 YUE.on('hlcode','mouseup',getSelectionLink("${_('Selection link')}"))
100 // select code link event
101 YUE.on('hlcode', 'mouseup', getSelectionLink);
102
103 //load history of file
104 YUE.on('load_node_history', 'click', function(e){
105 var _url = node_history_url.replace('__REV__','${c.file_changeset.raw_id}').replace('__FPATH__', '${c.f_path}');
106 ypjax(_url, 'node_history', function(o){})
107 });
108
117 });
109 });
110
118 </script>
111 </script>
General Comments 0
You need to be logged in to leave comments. Login now