mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-25 14:50:29 +00:00
[repo] added feature 'select multi dirents, and del/mv/cp' and fixed sort bug
This commit is contained in:
@@ -262,7 +262,17 @@ input.btn-disabled:hover {/*for input*/
|
|||||||
*[data-href] {
|
*[data-href] {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.op-icon-btn {/* icon btn */
|
||||||
|
font-size:14px;
|
||||||
|
padding:4px 12px;
|
||||||
|
line-height:20px;
|
||||||
|
text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);
|
||||||
|
background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(to bottom, #ffffff, #e6e6e6);background-repeat:repeat-x;border:1px solid #cccccc;border-bottom-color:#b3b3b3;border-radius:4px;box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
|
||||||
|
}
|
||||||
|
.op-icon-btn:hover {
|
||||||
|
background-color: #E6E6E6;
|
||||||
|
background-position: 0 -15px; /* to rm background-image */
|
||||||
|
}
|
||||||
.op-list li,
|
.op-list li,
|
||||||
.modalCloseImg,
|
.modalCloseImg,
|
||||||
.add {
|
.add {
|
||||||
@@ -439,8 +449,8 @@ textarea:-moz-placeholder {/* for FF */
|
|||||||
}
|
}
|
||||||
.checkbox-orig,
|
.checkbox-orig,
|
||||||
.checkbox {
|
.checkbox {
|
||||||
width:13px;
|
width:14px;
|
||||||
height:13px;
|
height:14px;
|
||||||
}
|
}
|
||||||
.checkbox-checked {
|
.checkbox-checked {
|
||||||
background:transparent url('../img/tick.png') no-repeat scroll 1px 3px;
|
background:transparent url('../img/tick.png') no-repeat scroll 1px 3px;
|
||||||
@@ -1376,15 +1386,18 @@ textarea:-moz-placeholder {/* for FF */
|
|||||||
table-layout:auto;
|
table-layout:auto;
|
||||||
margin:0;
|
margin:0;
|
||||||
}
|
}
|
||||||
|
.repo-file-list .select {
|
||||||
|
width:15px;
|
||||||
|
}
|
||||||
.repo-file-list .star {
|
.repo-file-list .star {
|
||||||
width:30px;
|
width:25px;
|
||||||
}
|
}
|
||||||
.repo-file-list .dirent-icon {
|
.repo-file-list .dirent-icon {
|
||||||
width:32px;
|
width:27px;
|
||||||
}
|
}
|
||||||
.repo-file-list .dirent-name {
|
.repo-file-list .dirent-name {
|
||||||
display:inline-block;
|
display:inline-block;
|
||||||
width:405px;
|
width:400px;
|
||||||
}
|
}
|
||||||
.repo-file-list .dirent-size {
|
.repo-file-list .dirent-size {
|
||||||
width:89px;
|
width:89px;
|
||||||
@@ -1395,15 +1408,20 @@ textarea:-moz-placeholder {/* for FF */
|
|||||||
.repo-file-list .dirent-op {
|
.repo-file-list .dirent-op {
|
||||||
width:250px;
|
width:250px;
|
||||||
}
|
}
|
||||||
|
.repo-file-list .checkbox-label,
|
||||||
|
.repo-file-list .checkbox {
|
||||||
|
margin:0;
|
||||||
|
}
|
||||||
.repo-file-list th {
|
.repo-file-list th {
|
||||||
padding-top:20px;
|
padding-top:20px;
|
||||||
}
|
}
|
||||||
.repo-file-list .fixed-hd {
|
#repo-file-list .fixed-hd {
|
||||||
position:fixed;
|
position:fixed;
|
||||||
width:950px;
|
width:950px;
|
||||||
background:#fff;
|
background:#fff;
|
||||||
top:0;
|
top:0;
|
||||||
z-index:11; /*make it on top of dirent op(popup)*/
|
z-index:11; /*make it on top of dirent op(popup)*/
|
||||||
|
border-color:#efefef; /*for repo-file-list-topbar*/
|
||||||
}
|
}
|
||||||
.repo-file-list .fixed-hd th {
|
.repo-file-list .fixed-hd th {
|
||||||
box-shadow:0 2px 2px -3px #aaa;
|
box-shadow:0 2px 2px -3px #aaa;
|
||||||
@@ -1416,6 +1434,7 @@ textarea:-moz-placeholder {/* for FF */
|
|||||||
.file-star {
|
.file-star {
|
||||||
cursor:pointer;
|
cursor:pointer;
|
||||||
line-height:19px;
|
line-height:19px;
|
||||||
|
vertical-align:middle;
|
||||||
}
|
}
|
||||||
.repo-file-list .repo-file-op {
|
.repo-file-list .repo-file-op {
|
||||||
position:relative;
|
position:relative;
|
||||||
@@ -1485,6 +1504,18 @@ textarea:-moz-placeholder {/* for FF */
|
|||||||
color:#666;
|
color:#666;
|
||||||
margin-left:5px;
|
margin-left:5px;
|
||||||
}
|
}
|
||||||
|
#dirents-op {
|
||||||
|
position:fixed;
|
||||||
|
}
|
||||||
|
#dirents-op .op-icon-btn {
|
||||||
|
display:block;
|
||||||
|
margin-bottom:6px;
|
||||||
|
}
|
||||||
|
#dirents-op .op-icon-btn .icon-trash {
|
||||||
|
display:inline-block;
|
||||||
|
width:14px;
|
||||||
|
text-align:center;
|
||||||
|
}
|
||||||
.lsch,
|
.lsch,
|
||||||
.lsch-encrypted,
|
.lsch-encrypted,
|
||||||
.file-diff {
|
.file-diff {
|
||||||
|
@@ -466,6 +466,8 @@ $(document).click(function(e) {
|
|||||||
{'name':'plus-sign-alt', 'con':'f0fe'},
|
{'name':'plus-sign-alt', 'con':'f0fe'},
|
||||||
{'name':'upload', 'con':'f01b'},
|
{'name':'upload', 'con':'f01b'},
|
||||||
{'name':'ban-circle', 'con':'f05e'},
|
{'name':'ban-circle', 'con':'f05e'},
|
||||||
|
{'name':'move', 'con':'f047'},
|
||||||
|
{'name':'copy', 'con':'f0c5'},
|
||||||
{'name':'upload-alt', 'con':'f093'}
|
{'name':'upload-alt', 'con':'f093'}
|
||||||
];
|
];
|
||||||
function setCon(icon, icon_class_prefix, icon_list) {
|
function setCon(icon, icon_class_prefix, icon_list) {
|
||||||
|
@@ -44,6 +44,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- popups -->
|
<!-- popups -->
|
||||||
|
{% if user_perm == 'rw' %}
|
||||||
|
<div id="dirents-op" class="hide">
|
||||||
|
<button id="del-dirents" title="{% trans "Delete"%}" class="op-icon-btn"><span class="icon-trash"></span></button>
|
||||||
|
<button id="mv-dirents" title="{% trans "Move"%}" class="op-icon-btn"><span class="icon-move"></span></button>
|
||||||
|
<button id="cp-dirents" title="{% trans "Copy"%}" class="op-icon-btn"><span class="icon-copy"></span></button>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div id="upload-file-dialog" class="hide">
|
<div id="upload-file-dialog" class="hide">
|
||||||
<h3>{% trans "Upload Files" %}</h3>
|
<h3>{% trans "Upload Files" %}</h3>
|
||||||
{% if no_quota %}
|
{% if no_quota %}
|
||||||
@@ -312,6 +319,211 @@ $('#repo-setting-form').submit(function() {
|
|||||||
});
|
});
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
function setDirentsOpPos() {
|
||||||
|
var dirents_op = $('#dirents-op');
|
||||||
|
dirents_op.css({
|
||||||
|
'left': $('#repo-file-list').offset().left - dirents_op.outerWidth(true) - 20,
|
||||||
|
'top': $(window).height()/2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#del-dirents').click(function() {
|
||||||
|
$('#confirm-popup').modal({appendTo:'#main'});
|
||||||
|
$('#simplemodal-container').css({'height':'auto'});
|
||||||
|
$('#confirm-con').html('<h3>' + "{% trans "Delete Items" %}" + '</h3><p>' + "{% trans "Are you sure you want to delete these selected items?" %}" + '</p>');
|
||||||
|
$('#confirm-yes').unbind().click(del_dirents);
|
||||||
|
});
|
||||||
|
var del_dirents = function() {
|
||||||
|
$('#confirm-popup').append('<p style="color:red;">' + "{% trans "Processing..." %}" + '</p>');
|
||||||
|
var dirents = $('.checkbox-checked').parents('.dir-item, .file-item'),
|
||||||
|
dirents_names = [];
|
||||||
|
dirents.each(function() {
|
||||||
|
dirents_names.push($(this).data('name'));
|
||||||
|
});
|
||||||
|
$.ajax({
|
||||||
|
url: '{% url 'delete_dirents' repo.id %}' + '?parent_dir=' + e(cur_path),
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
beforeSend: prepareCSRFToken,
|
||||||
|
traditional: true,
|
||||||
|
data: {
|
||||||
|
'dirents_names': dirents_names
|
||||||
|
},
|
||||||
|
success: function(data) {
|
||||||
|
var deleted_len = data['deleted'].length,
|
||||||
|
msg_s, msg_f;
|
||||||
|
|
||||||
|
if (deleted_len > 0) {
|
||||||
|
if (deleted_len == dirents_names.length) {
|
||||||
|
dirents.remove();
|
||||||
|
} else {
|
||||||
|
dirents.each(function() {
|
||||||
|
if ($(this).data('name') in data['deleted']) {
|
||||||
|
$(this).remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (data['deleted'].length > 1) {
|
||||||
|
msg_s = "{% trans "Successfully deleted %(name)s and %(amount)s other items." %}";
|
||||||
|
} else {
|
||||||
|
msg_s = "{% trans "Successfully deleted %(name)s." %}";
|
||||||
|
}
|
||||||
|
msg_s = msg_s.replace('%(name)s', data['deleted'][0]).replace('%(amount)s', data['deleted'].length - 1);
|
||||||
|
feedback(msg_s, 'success');
|
||||||
|
updateCmt();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data['undeleted'].length > 0) {
|
||||||
|
if (data['undeleted'].length > 1) {
|
||||||
|
msg_f = "{% trans "Internal error. Failed to delete %(name)s and %(amount)s other items." %}"
|
||||||
|
} else {
|
||||||
|
msg_f = "{% trans "Internal error. Failed to delete %(name)s." %}"
|
||||||
|
}
|
||||||
|
msg_f = msg_f.replace('%(name)s', data['undeleted'][0]).replace('%(amount)s', data['undeleted'].length - 1);
|
||||||
|
feedback(msg_f, 'error');
|
||||||
|
}
|
||||||
|
$.modal.close();
|
||||||
|
$('#dirents-op').addClass('hide');
|
||||||
|
$('th.select .checkbox').removeClass('checkbox-checked');
|
||||||
|
},
|
||||||
|
error: function(xhr, textStatus, errorThrown) {
|
||||||
|
$.modal.close();
|
||||||
|
ajaxErrorHandler(xhr, textStatus, errorThrown);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$('#mv-dirents, #cp-dirents').click(function() {
|
||||||
|
var form = $('#mv-form'), op;
|
||||||
|
form.modal({appendTo:'#main', autoResize:true, focus:false});
|
||||||
|
$('#simplemodal-container').css({'width':'auto', 'height':'auto'});
|
||||||
|
|
||||||
|
if ($(this).attr('id') == 'mv-dirents') {
|
||||||
|
op = 'mv';
|
||||||
|
form.prepend("<h3>{% trans "Move selected directories/files to:" %}</h3>");
|
||||||
|
} else {
|
||||||
|
op = 'cp';
|
||||||
|
form.prepend("<h3>{% trans "Copy selected directories/files to:" %}</h3>");
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_tree = new FileTree();
|
||||||
|
file_tree.renderDirTree($('#current-repo-dirs').data('site_root', '{{SITE_ROOT}}'), form, current_repo);
|
||||||
|
|
||||||
|
var files = $('.checkbox-checked').parents('.file-item'),
|
||||||
|
dirs = $('.checkbox-checked').parents('.dir-item'),
|
||||||
|
dir_names = [], file_names = [];
|
||||||
|
|
||||||
|
files.each(function() {
|
||||||
|
file_names.push($(this).data('name'));
|
||||||
|
});
|
||||||
|
dirs.each(function() {
|
||||||
|
dir_names.push($(this).data('name'));
|
||||||
|
});
|
||||||
|
|
||||||
|
form.submit(function() {
|
||||||
|
var dst_repo = $('[name="dst_repo"]', form).val(),
|
||||||
|
dst_path = $('[name="dst_path"]', form).val(),
|
||||||
|
url_main;
|
||||||
|
|
||||||
|
if (!$.trim(dst_repo) || !$.trim(dst_path)) {
|
||||||
|
$('.error', form).removeClass('hide');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (dst_repo == '{{repo.id }}' && dst_path == cur_path) {
|
||||||
|
$('.error', form).html("{% trans "Invalid destination path" %}").removeClass('hide');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op == 'mv') {
|
||||||
|
url_main = '{% url 'mv_dirents' repo.id %}';
|
||||||
|
} else {
|
||||||
|
url_main = '{% url 'cp_dirents' repo.id %}';
|
||||||
|
}
|
||||||
|
|
||||||
|
disable($('[type="submit"]', form));
|
||||||
|
form.append('<p style="color:red;">' + "{% trans "Processing..." %}" + '</p>');
|
||||||
|
$.ajax({
|
||||||
|
url: url_main + '?parent_dir=' + e(cur_path),
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
beforeSend: prepareCSRFToken,
|
||||||
|
traditional: true,
|
||||||
|
data: {
|
||||||
|
'file_names': file_names,
|
||||||
|
'dir_names': dir_names,
|
||||||
|
'dst_repo': dst_repo,
|
||||||
|
'dst_path': dst_path
|
||||||
|
},
|
||||||
|
success: function(data) {
|
||||||
|
var success_len = data['success'].length,
|
||||||
|
msg_s, msg_f;
|
||||||
|
|
||||||
|
$.modal.close();
|
||||||
|
$('#dirents-op').addClass('hide');
|
||||||
|
$('th.select .checkbox').removeClass('checkbox-checked');
|
||||||
|
|
||||||
|
if (success_len > 0) {
|
||||||
|
if (op == 'mv') {
|
||||||
|
if (success_len == files.length + dirs.length) {
|
||||||
|
files.remove();
|
||||||
|
dirs.remove();
|
||||||
|
} else {
|
||||||
|
files.each(function() {
|
||||||
|
if ($(this).data('name') in data['success']) {
|
||||||
|
$(this).remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dirs.each(function() {
|
||||||
|
if ($(this).data('name') in data['success']) {
|
||||||
|
$(this).remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (data['success'].length > 1) {
|
||||||
|
msg_s = "{% trans "Successfully moved %(name)s and %(amount)s other items." %}";
|
||||||
|
} else {
|
||||||
|
msg_s = "{% trans "Successfully moved %(name)s." %}";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$('.checkbox').removeClass('checkbox-checked');
|
||||||
|
if (data['success'].length > 1) {
|
||||||
|
msg_s = "{% trans "Successfully copied %(name)s and %(amount)s other items." %}";
|
||||||
|
} else {
|
||||||
|
msg_s = "{% trans "Successfully copied %(name)s." %}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg_s = msg_s.replace('%(name)s', data['success'][0]).replace('%(amount)s', data['success'].length - 1);
|
||||||
|
msg_s += ' <a href="' + data['url'] + '">' + "{% trans "View" %}" + '</a>';
|
||||||
|
feedback(msg_s, 'success');
|
||||||
|
updateCmt();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data['failed'].length > 0) {
|
||||||
|
if (op == 'mv') {
|
||||||
|
if (data['failed'].length > 1) {
|
||||||
|
msg_f = "{% trans "Internal error. Failed to move %(name)s and %(amount)s other items." %}";
|
||||||
|
} else {
|
||||||
|
msg_f = "{% trans "Internal error. Failed to move %(name)s." %}";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (data['failed'].length > 1) {
|
||||||
|
msg_f = "{% trans "Internal error. Failed to copy %(name)s and %(amount)s other items." %}";
|
||||||
|
} else {
|
||||||
|
msg_f = "{% trans "Internal error. Failed to copy %(name)s." %}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg_f = msg_f.replace('%(name)s', data['failed'][0]).replace('%(amount)s', data['failed'].length - 1);
|
||||||
|
feedback(msg_f, 'error');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, textStatus, errorThrown) {
|
||||||
|
$.modal.close();
|
||||||
|
ajaxErrorHandler(xhr, textStatus, errorThrown);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// js on repo file list
|
// js on repo file list
|
||||||
var no_file_op_popup = true;
|
var no_file_op_popup = true;
|
||||||
@@ -376,6 +588,28 @@ $('#share-cur-dir').click(function() {
|
|||||||
showSharePopup(op, name, aj_url, type, cur_path);
|
showSharePopup(op, name, aj_url, type, cur_path);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//select all or not
|
||||||
|
$('th .checkbox-orig').unbind().click(function() {
|
||||||
|
var dirents_op = $('#dirents-op');
|
||||||
|
|
||||||
|
// keep all checkbox in the same state: selected or not
|
||||||
|
// a case: select all, and then scroll to req 'more'...
|
||||||
|
$(this).parent().toggleClass('checkbox-checked');
|
||||||
|
if ($(this).parent().hasClass('checkbox-checked')) {
|
||||||
|
$('.checkbox').addClass('checkbox-checked');
|
||||||
|
} else {
|
||||||
|
$('.checkbox').removeClass('checkbox-checked');
|
||||||
|
}
|
||||||
|
|
||||||
|
// show buttons or not
|
||||||
|
if ($('.checkbox-checked', $('.dir-item, .file-item')).length > 0) {
|
||||||
|
dirents_op.removeClass('hide');
|
||||||
|
setDirentsOpPos();
|
||||||
|
} else {
|
||||||
|
dirents_op.addClass('hide');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
//sort
|
//sort
|
||||||
$('#name-down, #name-up, #time-up, #time-down').click(sortDirent);
|
$('#name-down, #name-up, #time-up, #time-down').click(sortDirent);
|
||||||
|
|
||||||
@@ -410,11 +644,12 @@ function sortDirent() {
|
|||||||
case 'time-down': by = function(a, b) { return a.time < b.time ? 1 : -1 };break;
|
case 'time-down': by = function(a, b) { return a.time < b.time ? 1 : -1 };break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// when 'name' is like '123', `data('name')` return number 123
|
||||||
$('.dir-item').each(function() {
|
$('.dir-item').each(function() {
|
||||||
dir_list.push({'name':$(this).data('name'), 'time':$(this).data('time'), 'element':this});
|
dir_list.push({'name':$(this).attr('data-name'), 'time':$(this).data('time'), 'element':this});
|
||||||
});
|
});
|
||||||
$('.file-item').each(function() {
|
$('.file-item').each(function() {
|
||||||
file_list.push({'name':$(this).data('name'), 'time':$(this).data('time'), 'element':this});
|
file_list.push({'name':$(this).attr('data-name'), 'time':$(this).data('time'), 'element':this});
|
||||||
});
|
});
|
||||||
|
|
||||||
dir_list.sort(by);
|
dir_list.sort(by);
|
||||||
@@ -464,19 +699,28 @@ function changeLocation(data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function reqDirData(url, func) {
|
function reqDirData(url, func) {
|
||||||
|
var orig_wtop = $(window).scrollTop();
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: url,
|
url: url,
|
||||||
cache: false,
|
cache: false,
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
$('#repo-file-list').html(data['html']);
|
$('#repo-file-list').html(data['html']);
|
||||||
|
|
||||||
|
// both original dir list and new dir list are long
|
||||||
|
var repo_top = $('#repo-top'),
|
||||||
|
h = repo_top.offset().top + repo_top.outerHeight(true);
|
||||||
|
if (orig_wtop > h && $(window).scrollTop() == orig_wtop) {
|
||||||
|
$(window).scrollTop(h);
|
||||||
|
}
|
||||||
|
|
||||||
cur_path = data['path']; // update cur_path
|
cur_path = data['path']; // update cur_path
|
||||||
if (func) {
|
if (func) {
|
||||||
func(data);
|
func(data);
|
||||||
}
|
}
|
||||||
dirOP();
|
dirOP();
|
||||||
// in case the 'discuss' popup is open before this request
|
// in case the 'discuss' & #dirents-op popup is open before this request
|
||||||
$('#discuss-to-group, #discuss-to-group-caret').addClass('hide');
|
$('#discuss-to-group, #discuss-to-group-caret, #dirents-op').addClass('hide');
|
||||||
},
|
},
|
||||||
error:function(xhr, textStatus, errorThrown) {
|
error:function(xhr, textStatus, errorThrown) {
|
||||||
if (xhr.responseText) {
|
if (xhr.responseText) {
|
||||||
@@ -538,6 +782,20 @@ var current_repo = [],
|
|||||||
function opOnDirent(context) { // added param 'context' for 'more' dirents requested with 'list_dir_more'
|
function opOnDirent(context) { // added param 'context' for 'more' dirents requested with 'list_dir_more'
|
||||||
var context = context || $('.dir-item, .file-item');
|
var context = context || $('.dir-item, .file-item');
|
||||||
|
|
||||||
|
// select
|
||||||
|
$('.checkbox-orig', context).unbind().click(function() {
|
||||||
|
var dirents_op = $('#dirents-op');
|
||||||
|
|
||||||
|
$(this).parent().toggleClass('checkbox-checked');
|
||||||
|
// show buttons or not
|
||||||
|
if ($('.checkbox-checked', context).length > 0) {
|
||||||
|
dirents_op.removeClass('hide');
|
||||||
|
setDirentsOpPos();
|
||||||
|
} else {
|
||||||
|
dirents_op.addClass('hide');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$('.dir-link', context).click(dirlinkClick);
|
$('.dir-link', context).click(dirlinkClick);
|
||||||
|
|
||||||
var popup_tr = ''; // the tr which the shown popup belongs to
|
var popup_tr = ''; // the tr which the shown popup belongs to
|
||||||
@@ -629,13 +887,7 @@ $('.dir-del, .file-del', context).click(function() {
|
|||||||
updateCmt();
|
updateCmt();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error:function(xhr, textStatus, errorThrown) {
|
error: ajaxErrorHandler
|
||||||
if (xhr.responseText) {
|
|
||||||
feedback(jQuery.parseJSON(xhr.responseText).error, 'error');
|
|
||||||
} else {
|
|
||||||
feedback("{% trans "Failed. Please check the network." %}", 'error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
@@ -938,6 +1190,11 @@ $('#add-new-file-form, #add-new-dir-form, #rename-form, #mv-form').submit(functi
|
|||||||
obj_name = $('[name="obj_name"]', form).val(),
|
obj_name = $('[name="obj_name"]', form).val(),
|
||||||
obj_type = $('[name="obj_type"]', form).val(),
|
obj_type = $('[name="obj_type"]', form).val(),
|
||||||
op_obj = form.data('op_obj');
|
op_obj = form.data('op_obj');
|
||||||
|
|
||||||
|
if (!op_obj) { // for mv-dirents, cp-dirents
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$.trim(dst_repo) || !$.trim(dst_path)) {
|
if (!$.trim(dst_repo) || !$.trim(dst_path)) {
|
||||||
$('.error', form).removeClass('hide');
|
$('.error', form).removeClass('hide');
|
||||||
return false;
|
return false;
|
||||||
@@ -1026,11 +1283,17 @@ $('#private-share-form').submit(function() {
|
|||||||
});
|
});
|
||||||
var last_start = 0; // for 'list_dir_more'
|
var last_start = 0; // for 'list_dir_more'
|
||||||
$(window).scroll(function() {
|
$(window).scroll(function() {
|
||||||
var file_topbar = $('.repo-file-list-topbar'),
|
var repo_top = $('#repo-top'),
|
||||||
list_hd = $('.repo-file-list tr:first-child');
|
file_topbar = $('.repo-file-list-topbar'),
|
||||||
if ($(window).scrollTop() > file_topbar.offset().top + file_topbar.outerHeight(true)) {
|
list_hd = $('.repo-file-list tr:first-child'),
|
||||||
list_hd.addClass('fixed-hd').css({'left':file_topbar.offset().left});
|
repo_top_left = $('.block-inner', repo_top).offset().left,
|
||||||
|
file_topbar_h = file_topbar.outerHeight(true);
|
||||||
|
|
||||||
|
if ($(window).scrollTop() > repo_top.offset().top + repo_top.outerHeight(true)) {
|
||||||
|
file_topbar.addClass('fixed-hd').css({'left': repo_top_left});
|
||||||
|
list_hd.addClass('fixed-hd').css({'left': repo_top_left, 'top':file_topbar_h});
|
||||||
} else {
|
} else {
|
||||||
|
file_topbar.removeClass('fixed-hd');
|
||||||
list_hd.removeClass('fixed-hd');
|
list_hd.removeClass('fixed-hd');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1057,7 +1320,6 @@ $(window).scroll(function() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
opOnDirent(more_dirents);
|
opOnDirent(more_dirents);
|
||||||
$('#name-down, #name-up, #time-up, #time-down').unbind().click(sortDirent);
|
|
||||||
if (data['dirent_more']) {
|
if (data['dirent_more']) {
|
||||||
ele_more.data('start', data['more_start']);
|
ele_more.data('start', data['more_start']);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -27,6 +27,9 @@
|
|||||||
|
|
||||||
<table class="repo-file-list">
|
<table class="repo-file-list">
|
||||||
<tr>
|
<tr>
|
||||||
|
<th class="select">
|
||||||
|
<span class="checkbox"><input type="checkbox" class="checkbox-orig" /></span>
|
||||||
|
</th>
|
||||||
<th class="star"></th>
|
<th class="star"></th>
|
||||||
<th class="dirent-icon"></th>
|
<th class="dirent-icon"></th>
|
||||||
<th><span class="dirent-name">{% trans "Name"%} <span id="name-up" class="tri-bg tri-up-order-bg"></span> <span id="name-down" class="tri-bg tri-down-order-bg"></span></span></th>
|
<th><span class="dirent-name">{% trans "Name"%} <span id="name-up" class="tri-bg tri-up-order-bg"></span> <span id="name-down" class="tri-bg tri-down-order-bg"></span></span></th>
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
{% load seahub_tags i18n %}
|
{% load seahub_tags i18n %}
|
||||||
{% for dirent in dir_list %}
|
{% for dirent in dir_list %}
|
||||||
<tr class="dir-item" data-name="{{dirent.obj_name}}" data-time="{% if dirent.last_modified %}{{ dirent.last_modified }}{%else %}0{% endif %}">
|
<tr class="dir-item" data-name="{{dirent.obj_name}}" data-time="{% if dirent.last_modified %}{{ dirent.last_modified }}{%else %}0{% endif %}">
|
||||||
|
<td class="select">
|
||||||
|
<span class="checkbox"><input type="checkbox" class="checkbox-orig" /></span>
|
||||||
|
</td>
|
||||||
<td class="star"></td>
|
<td class="star"></td>
|
||||||
<td class="dirent-icon"><img src="{{ MEDIA_URL }}img/folder-icon-24.png" alt="{% trans "Directory icon"%}" /></td>
|
<td class="dirent-icon"><img src="{{ MEDIA_URL }}img/folder-icon-24.png" alt="{% trans "Directory icon"%}" /></td>
|
||||||
<td>
|
<td>
|
||||||
@@ -41,6 +44,9 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for dirent in file_list %}
|
{% for dirent in file_list %}
|
||||||
<tr class="file-item" data-name="{{dirent.obj_name}}" data-time="{% if dirent.last_modified %}{{ dirent.last_modified }} {%else %}0{% endif %}">
|
<tr class="file-item" data-name="{{dirent.obj_name}}" data-time="{% if dirent.last_modified %}{{ dirent.last_modified }} {%else %}0{% endif %}">
|
||||||
|
<td class="select">
|
||||||
|
<span class="checkbox"><input type="checkbox" class="checkbox-orig" /></span>
|
||||||
|
</td>
|
||||||
<td class="star alc">
|
<td class="star alc">
|
||||||
{% if dirent.starred %}
|
{% if dirent.starred %}
|
||||||
<span title="{% trans 'starred' %}" class="icon-star file-star" data-status="starred"></span>
|
<span title="{% trans 'starred' %}" class="icon-star file-star" data-status="starred"></span>
|
||||||
|
@@ -103,6 +103,9 @@ urlpatterns = patterns('',
|
|||||||
|
|
||||||
### Ajax ###
|
### Ajax ###
|
||||||
(r'^ajax/repo/(?P<repo_id>[-0-9a-f]{36})/dirents/$', get_dirents),
|
(r'^ajax/repo/(?P<repo_id>[-0-9a-f]{36})/dirents/$', get_dirents),
|
||||||
|
url(r'^ajax/repo/(?P<repo_id>[-0-9a-f]{36})/dirents/delete/$', delete_dirents, name='delete_dirents'),
|
||||||
|
url(r'^ajax/repo/(?P<repo_id>[-0-9a-f]{36})/dirents/move/$', mv_dirents, name='mv_dirents'),
|
||||||
|
url(r'^ajax/repo/(?P<repo_id>[-0-9a-f]{36})/dirents/copy/$', cp_dirents, name='cp_dirents'),
|
||||||
url(r'^ajax/group/(?P<group_id>\d+)/repos/$', get_group_repos, name='get_group_repos'),
|
url(r'^ajax/group/(?P<group_id>\d+)/repos/$', get_group_repos, name='get_group_repos'),
|
||||||
url(r'^ajax/my-unenc-repos/$', get_my_unenc_repos, name='get_my_unenc_repos'),
|
url(r'^ajax/my-unenc-repos/$', get_my_unenc_repos, name='get_my_unenc_repos'),
|
||||||
url(r'^ajax/contacts/$', get_contacts, name='get_contacts'),
|
url(r'^ajax/contacts/$', get_contacts, name='get_contacts'),
|
||||||
|
@@ -469,6 +469,50 @@ def delete_dirent(request, repo_id):
|
|||||||
return HttpResponse(json.dumps({'error': err_msg}),
|
return HttpResponse(json.dumps({'error': err_msg}),
|
||||||
status=500, content_type=content_type)
|
status=500, content_type=content_type)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def delete_dirents(request, repo_id):
|
||||||
|
"""
|
||||||
|
Delete multi files/dirs with ajax.
|
||||||
|
"""
|
||||||
|
if not request.is_ajax():
|
||||||
|
raise Http404
|
||||||
|
|
||||||
|
content_type = 'application/json; charset=utf-8'
|
||||||
|
|
||||||
|
repo = get_repo(repo_id)
|
||||||
|
if not repo:
|
||||||
|
err_msg = _(u'Library does not exist.')
|
||||||
|
return HttpResponse(json.dumps({'error': err_msg}),
|
||||||
|
status=400, content_type=content_type)
|
||||||
|
|
||||||
|
# permission checking
|
||||||
|
username = request.user.username
|
||||||
|
if check_repo_access_permission(repo.id, username) != 'rw':
|
||||||
|
err_msg = _(u'Permission denied.')
|
||||||
|
return HttpResponse(json.dumps({'error': err_msg}),
|
||||||
|
status=403, content_type=content_type)
|
||||||
|
|
||||||
|
# argument checking
|
||||||
|
parent_dir = request.GET.get("parent_dir")
|
||||||
|
dirents_names = request.POST.getlist('dirents_names')
|
||||||
|
if not (parent_dir and dirents_names):
|
||||||
|
err_msg = _(u'Argument missing.')
|
||||||
|
return HttpResponse(json.dumps({'error': err_msg}),
|
||||||
|
status=400, content_type=content_type)
|
||||||
|
|
||||||
|
deleted = []
|
||||||
|
undeleted = []
|
||||||
|
for dirent_name in dirents_names:
|
||||||
|
try:
|
||||||
|
seafile_api.del_file(repo_id, parent_dir, dirent_name, username)
|
||||||
|
deleted.append(dirent_name)
|
||||||
|
except SearpcError, e:
|
||||||
|
logger.error(e)
|
||||||
|
undeleted.append(dirent_name)
|
||||||
|
|
||||||
|
return HttpResponse(json.dumps({'deleted': deleted,'undeleted': undeleted}),
|
||||||
|
content_type=content_type)
|
||||||
|
|
||||||
def copy_move_common(func):
|
def copy_move_common(func):
|
||||||
"""Decorator for common logic in copying/moving dir/file.
|
"""Decorator for common logic in copying/moving dir/file.
|
||||||
"""
|
"""
|
||||||
@@ -518,8 +562,8 @@ def copy_move_common(func):
|
|||||||
|
|
||||||
# do nothing when dst is the same as src
|
# do nothing when dst is the same as src
|
||||||
if repo_id == dst_repo_id and path == dst_path:
|
if repo_id == dst_repo_id and path == dst_path:
|
||||||
url = reverse('repo', args=[repo_id]) + ('?p=%s' % urlquote(path))
|
result['error'] = _('Invalid destination path')
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
|
||||||
return func(repo_id, path, dst_repo_id, dst_path, obj_name, username)
|
return func(repo_id, path, dst_repo_id, dst_path, obj_name, username)
|
||||||
return _decorated
|
return _decorated
|
||||||
|
|
||||||
@@ -626,6 +670,123 @@ def cp_dir(src_repo_id, src_path, dst_repo_id, dst_path, obj_name, username):
|
|||||||
return HttpResponse(json.dumps(result), status=500,
|
return HttpResponse(json.dumps(result), status=500,
|
||||||
content_type=content_type)
|
content_type=content_type)
|
||||||
|
|
||||||
|
|
||||||
|
def dirents_copy_move_common(func):
|
||||||
|
"""
|
||||||
|
Decorator for common logic in copying/moving dirs/files.
|
||||||
|
"""
|
||||||
|
def _decorated(request, repo_id, *args, **kwargs):
|
||||||
|
|
||||||
|
if request.method != 'POST' or not request.is_ajax():
|
||||||
|
raise Http404
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
content_type = 'application/json; charset=utf-8'
|
||||||
|
|
||||||
|
repo = get_repo(repo_id)
|
||||||
|
if not repo:
|
||||||
|
result['error'] = _(u'Library does not exist.')
|
||||||
|
return HttpResponse(json.dumps(result), status=400,
|
||||||
|
content_type=content_type)
|
||||||
|
|
||||||
|
# permission checking
|
||||||
|
username = request.user.username
|
||||||
|
if check_repo_access_permission(repo.id, username) != 'rw':
|
||||||
|
result['error'] = _('Permission denied')
|
||||||
|
return HttpResponse(json.dumps(result), status=403,
|
||||||
|
content_type=content_type)
|
||||||
|
|
||||||
|
# arguments validation
|
||||||
|
parent_dir = request.GET.get('parent_dir')
|
||||||
|
obj_file_names = request.POST.getlist('file_names')
|
||||||
|
obj_dir_names = request.POST.getlist('dir_names')
|
||||||
|
dst_repo_id = request.POST.get('dst_repo')
|
||||||
|
dst_path = request.POST.get('dst_path')
|
||||||
|
|
||||||
|
if not (parent_dir and dst_repo_id and dst_path) and not (obj_file_names or obj_dir_names):
|
||||||
|
result['error'] = _('Argument missing')
|
||||||
|
return HttpResponse(json.dumps(result), status=400,
|
||||||
|
content_type=content_type)
|
||||||
|
|
||||||
|
# check file path
|
||||||
|
for obj_name in obj_file_names + obj_dir_names:
|
||||||
|
if len(dst_path+obj_name) > settings.MAX_PATH:
|
||||||
|
result['error'] = _('Destination path is too long for %s.') % obj_name
|
||||||
|
return HttpResponse(json.dumps(result), status=400,
|
||||||
|
content_type=content_type)
|
||||||
|
|
||||||
|
# check whether user has write permission to dest repo
|
||||||
|
if check_repo_access_permission(dst_repo_id, username) != 'rw':
|
||||||
|
result['error'] = _('Permission denied')
|
||||||
|
return HttpResponse(json.dumps(result), status=403,
|
||||||
|
content_type=content_type)
|
||||||
|
|
||||||
|
# when dst is the same as src
|
||||||
|
if repo_id == dst_repo_id and parent_dir == dst_path:
|
||||||
|
result['error'] = _('Invalid destination path')
|
||||||
|
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
|
||||||
|
|
||||||
|
return func(repo_id, parent_dir, dst_repo_id, dst_path, obj_file_names, obj_dir_names, username)
|
||||||
|
return _decorated
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@dirents_copy_move_common
|
||||||
|
def mv_dirents(src_repo_id, src_path, dst_repo_id, dst_path, obj_file_names, obj_dir_names, username):
|
||||||
|
content_type = 'application/json; charset=utf-8'
|
||||||
|
|
||||||
|
for obj_name in obj_dir_names:
|
||||||
|
src_dir = os.path.join(src_path, obj_name)
|
||||||
|
if dst_path.startswith(src_dir):
|
||||||
|
error_msg = _(u'Can not move directory %(src)s to its subdirectory %(des)s') \
|
||||||
|
% {'src': src_dir, 'des': dst_path}
|
||||||
|
result['error'] = error_msg
|
||||||
|
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
|
||||||
|
|
||||||
|
success = []
|
||||||
|
failed = []
|
||||||
|
url = None
|
||||||
|
for obj_name in obj_file_names + obj_dir_names:
|
||||||
|
new_obj_name = check_filename_with_rename(dst_repo_id, dst_path, obj_name)
|
||||||
|
try:
|
||||||
|
seafile_api.move_file(src_repo_id, src_path, obj_name,
|
||||||
|
dst_repo_id, dst_path, new_obj_name, username)
|
||||||
|
success.append(obj_name)
|
||||||
|
except SearpcError, e:
|
||||||
|
failed.append(obj_name)
|
||||||
|
|
||||||
|
if len(success) > 0:
|
||||||
|
url = reverse('repo', args=[dst_repo_id]) + '?p=' + urlquote(dst_path)
|
||||||
|
return HttpResponse(json.dumps({'success': success, 'failed': failed, 'url': url}), content_type=content_type)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@dirents_copy_move_common
|
||||||
|
def cp_dirents(src_repo_id, src_path, dst_repo_id, dst_path, obj_file_names, obj_dir_names, username):
|
||||||
|
content_type = 'application/json; charset=utf-8'
|
||||||
|
|
||||||
|
for obj_name in obj_dir_names:
|
||||||
|
src_dir = os.path.join(src_path, obj_name)
|
||||||
|
if dst_path.startswith(src_dir):
|
||||||
|
error_msg = _(u'Can not copy directory %(src)s to its subdirectory %(des)s') \
|
||||||
|
% {'src': src_dir, 'des': dst_path}
|
||||||
|
result['error'] = error_msg
|
||||||
|
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
|
||||||
|
|
||||||
|
success = []
|
||||||
|
failed = []
|
||||||
|
url = None
|
||||||
|
for obj_name in obj_file_names + obj_dir_names:
|
||||||
|
new_obj_name = check_filename_with_rename(dst_repo_id, dst_path, obj_name)
|
||||||
|
try:
|
||||||
|
seafile_api.copy_file(src_repo_id, src_path, obj_name,
|
||||||
|
dst_repo_id, dst_path, new_obj_name, username)
|
||||||
|
success.append(obj_name)
|
||||||
|
except SearpcError, e:
|
||||||
|
failed.append(obj_name)
|
||||||
|
|
||||||
|
if len(success) > 0:
|
||||||
|
url = reverse('repo', args=[dst_repo_id]) + '?p=' + urlquote(dst_path)
|
||||||
|
return HttpResponse(json.dumps({'success': success, 'failed': failed, 'url': url}), content_type=content_type)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def repo_star_file(request, repo_id):
|
def repo_star_file(request, repo_id):
|
||||||
if not request.is_ajax():
|
if not request.is_ajax():
|
||||||
|
Reference in New Issue
Block a user