@@ -379,12 +379,17 @@ def make_map(config):
f_path='', conditions=dict(function=check_repo))
rmap.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
controller='files', action='archivefile',
conditions=dict(function=check_repo))
rmap.connect('files_nodelist_home',
'/{repo_name:.*}/nodelist/{revision}/{f_path:.*}',
controller='files', action='nodelist',
rmap.connect('repo_settings_delete', '/{repo_name:.*}/settings',
controller='settings', action="delete",
conditions=dict(method=["DELETE"], function=check_repo))
rmap.connect('repo_settings_update', '/{repo_name:.*}/settings',
controller='settings', action="update",
@@ -22,18 +22,20 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import logging
import mimetypes
import traceback
from os.path import join as jn
from pylons import request, response, session, tmpl_context as c, url
from pylons.i18n.translation import _
from pylons.controllers.util import redirect
from pylons.decorators import jsonify
from vcs.backends import ARCHIVE_SPECS
from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
EmptyRepositoryError, ImproperArchiveTypeError, VCSError
from vcs.nodes import FileNode, NodeKind
from vcs.utils import diffs as differ
@@ -92,12 +94,32 @@ class FilesController(BaseRepoController
h.flash(str(e), category='warning')
redirect(h.url('files_home', repo_name=repo_name,
revision=cs.raw_id))
return file_node
def __get_paths(self, changeset, starting_path):
"""recursive walk in root dir and return a set of all path in that dir
based on repository walk function
"""
_files = list()
_dirs = list()
try:
tip = changeset
for topnode, dirs, files in tip.walk(starting_path):
for f in files:
_files.append(f.path)
for d in dirs:
_dirs.append(d.path)
except RepositoryError, e:
log.debug(traceback.format_exc())
pass
return _dirs, _files
@HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
'repository.admin')
def index(self, repo_name, revision, f_path):
#reditect to given revision from form if given
post_revision = request.POST.get('at_rev', None)
if post_revision:
@@ -410,6 +432,16 @@ class FilesController(BaseRepoController
for name, chs in c.rhodecode_repo.tags.items():
#chs = chs.split(':')[-1]
tags_group[0].append((chs, name),)
hist_l.append(tags_group)
return hist_l
@jsonify
def nodelist(self, repo_name, revision, f_path):
if request.environ.get('HTTP_X_PARTIAL_XHR'):
cs = self.__get_cs_or_redirect(revision, repo_name)
_d, _f = self.__get_paths(cs, f_path)
return _d + _f
@@ -49,13 +49,12 @@ height:100%;
}
a {
color:#003367;
text-decoration:none;
cursor:pointer;
font-weight:700;
a:hover {
color:#316293;
text-decoration:underline;
@@ -1860,13 +1859,13 @@ font-size:100%;
line-height:125%;
padding:0;
div.browserblock .browser-header {
background:#FFF;
padding:10px 0px 25px 0px;
padding:10px 0px 15px 0px;
width: 100%;
div.browserblock .browser-nav {
float:left
@@ -1881,12 +1880,31 @@ vertical-align:text-top;
div.browserblock .browser-header span {
margin-left:5px;
div.browserblock .browser-search{
clear:both;
padding:8px 8px 0px 5px;
div.browserblock .search_activate #filter_activate{
vertical-align: sub;
border: 1px solid;
padding:2px;
border-radius: 4px 4px 4px 4px;
background: url("../images/button.png") repeat-x scroll 0 0 #E5E3E3;
border-color: #DDDDDD #DDDDDD #C6C6C6 #C6C6C6;
color: #515151;
div.browserblock .search_activate a:hover{
text-decoration: none !important;
div.browserblock .browser-body {
background:#EEE;
border-top:1px solid #CCC;
table.code-browser {
@@ -2716,6 +2734,11 @@ border:0 none;
color:#AAAAAA;
margin-bottom:-4px;
margin-top:-4px;
padding-left:3px;
#node_filter{
border:0px solid #545454;
@@ -9,35 +9,148 @@
<div class="browser-header">
<div class="browser-nav">
${h.form(h.url.current())}
<div class="info_box">
<span class="rev">${_('view')}@rev</span>
<a class="rev" href="${c.url_prev}" title="${_('previous revision')}">«</a>
${h.text('at_rev',value=c.changeset.revision,size=3)}
${h.text('at_rev',value=c.changeset.revision,size=5)}
<a class="rev" href="${c.url_next}" title="${_('next revision')}">»</a>
## ${h.submit('view',_('view'),class_="ui-button-small")}
</div>
${h.end_form()}
<div class="browser-branch">
${h.checkbox('stay_at_branch',c.changeset.branch,c.changeset.branch==c.branch)}
<label>${_('follow current branch')}</label>
<script type="text/javascript">
YUE.on('stay_at_branch','click',function(e){
if(e.target.checked){
var uri = "${h.url.current(branch='__BRANCH__')}"
uri = uri.replace('__BRANCH__',e.target.value);
window.location = uri;
else{
window.location = "${h.url.current()}";
})
</script>
<div class="browser-search">
<div class="search_activate">
<a id="filter_activate" href="#">${_('search file list')}</a>
<div>
<div id="node_filter_box_loading" style="display:none">${_('Loading file list...')}</div>
<div id="node_filter_box" style="display:none">
${h.files_breadcrumbs(c.repo_name,c.changeset.raw_id,c.files_list.path)}/<input type="text" value="type to search..." name="filter" size="25" id="node_filter" autocomplete="off">
var n_filter = YUD.get('node_filter');
var F = YAHOO.namespace('node_filter');
var url = '${h.url("files_nodelist_home",repo_name="__REPO__",revision="__REVISION__",f_path="__FPATH__")}';
var node_url = '${h.url("files_home",repo_name="__REPO__",revision="__REVISION__",f_path="__FPATH__")}';
url = url.replace('__REPO__','${c.repo_name}');
url = url.replace('__REVISION__','${c.changeset.raw_id}');
url = url.replace('__FPATH__','${c.files_list.path}');
node_url = node_url.replace('__REPO__','${c.repo_name}');
node_url = node_url.replace('__REVISION__','${c.changeset.raw_id}');
F.filterTimeout = null;
var nodes = null;
F.initFilter = function(){
YUD.setStyle('node_filter_box_loading','display','');
YUD.setStyle('filter_activate','display','none');
YUC.initHeader('X-PARTIAL-XHR',true);
YUC.asyncRequest('GET',url,{
success:function(o){
nodes = JSON.parse(o.responseText);
YUD.setStyle('node_filter_box_loading','display','none');
YUD.setStyle('node_filter_box','display','');
},
failure:function(o){
console.log('failed to load');
},null);
F.updateFilter = function(e) {
return function(){
// Reset timeout
var query = e.target.value;
var match = [];
var matches = 0;
var matches_max = 20;
if (query != ""){
for(var i=0;i<nodes.length;i++){
var pos = nodes[i].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];
var n_hl = n.substring(0,pos)
+"<b>{0}</b>".format(n.substring(pos,pos+query.length))
+n.substring(pos+query.length)
match.push('<tr><td><a class="browser-file" href="{0}">{1}</a></td><td colspan="5"></td></tr>'.format(node_url.replace('__FPATH__',n),n_hl));
if(match.length >= matches_max){
match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format("${_('search truncated')}"));
if(query != ""){
YUD.setStyle('tbody','display','none');
YUD.setStyle('tbody_filtered','display','');
if (match.length==0){
match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format("${_('no matching files')}"));
YUD.get('tbody_filtered').innerHTML = match.join("");
YUD.setStyle('tbody','display','');
YUD.setStyle('tbody_filtered','display','none');
YUE.on(YUD.get('filter_activate'),'click',function(){
F.initFilter();
YUE.on(n_filter,'click',function(){
n_filter.value = '';
});
YUE.on(n_filter,'keyup',function(e){
clearTimeout(F.filterTimeout);
F.filterTimeout = setTimeout(F.updateFilter(e),600);
<div class="browser-body">
<table class="code-browser">
<thead>
<tr>
@@ -46,13 +159,14 @@
<th>${_('Mimetype')}</th>
<th>${_('Revision')}</th>
<th>${_('Last modified')}</th>
<th>${_('Last commiter')}</th>
</tr>
</thead>
<tbody id="tbody">
%if c.files_list.parent:
<tr class="parity0">
<td>
${h.link_to('..',h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.files_list.parent.path),class_="browser-dir")}
</td>
<td></td>
@@ -94,9 +208,12 @@
%if node.is_file():
${node.last_changeset.author}
%endif
%endfor
</tbody>
<tbody id="tbody_filtered" style="display:none">
</table>
\ No newline at end of file
Status change: