diff --git a/media/scripts/app/views/dir.js b/media/scripts/app/views/dir.js index 05285147f7..e4c6147c3f 100644 --- a/media/scripts/app/views/dir.js +++ b/media/scripts/app/views/dir.js @@ -3,11 +3,12 @@ define([ 'underscore', 'backbone', 'common', + 'file-tree', 'app/collections/dirents', 'app/views/dirents', 'text!' + app.config._tmplRoot + 'dir-op-bar.html', 'text!' + app.config._tmplRoot + 'path-bar.html', - ], function($, _, Backbone, Common, DirentCollection, DirentView, + ], function($, _, Backbone, Common, FileTree, DirentCollection, DirentView, DirOpBarTemplate, PathBarTemplate) { 'use strict'; @@ -130,7 +131,6 @@ define([ var view = new DirentView({model: new_dirent, dirView: dirView}); $('tr:first', dirView.$dirent_list).before(view.render().el); // put the new dir as the first one }; - console.log("ajaxPost"); Common.ajaxPost({ 'form': form, 'post_url': post_url, diff --git a/media/scripts/app/views/dirents.js b/media/scripts/app/views/dirents.js index 8b09fc8a46..ee2fa19015 100644 --- a/media/scripts/app/views/dirents.js +++ b/media/scripts/app/views/dirents.js @@ -3,8 +3,9 @@ define([ 'underscore', 'backbone', 'common', + 'file-tree', 'text!' + app.config._tmplRoot + 'dirent.html' -], function($, _, Backbone, Common, direntsTemplate) { +], function($, _, Backbone, Common, FileTree, direntsTemplate) { 'use strict'; app = app || {}; @@ -14,6 +15,7 @@ define([ tagName: 'tr', template: _.template(direntsTemplate), + renameTemplate: _.template($("#rename-form-template").html()), initialize: function(options) { this.options = options || {}; @@ -32,7 +34,7 @@ define([ this.$el.html(this.template({ dirent: this.model.attributes, repo_id: this.dirView.dir.repo_id, - path: this.dirView.dir.path, + // dir_path: this.dirView.dir.path, dirent_path: dirent_path, user_perm: this.dirView.dir.user_perm, repo_encrypted: this.dirView.dir.encrypted @@ -147,6 +149,134 @@ define([ } }, + delete: function() { + var dirent_name = this.model.get('obj_name'); + var options = {repo_id: this.dirView.dir.repo_id}; + options.name = this.model.get('is_dir') ? 'del_dir' : 'del_file'; + var url_main = Common.getUrl(options); + var el = this.$el; + $.ajax({ + url: url_main + '?parent_dir=' + encodeURIComponent(this.dirView.dir.path) + + '&name=' + encodeURIComponent(dirent_name), + dataType: 'json', + success: function(data) { + el.remove(); + app.globalState.noFileOpPopup = true;// make other items can work normally when hover + var msg = gettext("Successfully deleted %(name)s"); + msg = msg.replace('%(name)s', dirent_name); + Common.feedback(msg, 'success'); + }, + error: Common.ajaxErrorHandler + }); + return false; + }, + + rename: function() { + var is_dir = this.model.get('is_dir'); + //var hd_text = is_dir ? "{% trans "Rename Directory" %}" : "{% trans "Rename File" %}"; + var title = is_dir ? gettext("Rename Directory") : gettext("Rename File"); + //var op_detail = $('.detail', form); + //op_detail.html(op_detail.html().replace('%(name)s', '' + dirent_name + '')); + var dirent_name = this.model.get('obj_name'); + + var form = $(this.renameTemplate({ + form_title: title, + dirent_name: dirent_name, + })); + form.modal(); + var form_id = form.attr('id'); + $('#simplemodal-container').css({'width':'auto', 'height':'auto'}); + + var _this = this; + var dir = this.dirView.dir; + form.submit(function() { + var new_name = $.trim($('[name="newname"]', form).val()); + if (!new_name) { + Common.showFormError(form_id, gettext("It is required.")); + return false; + } + if (new_name == dirent_name) { + Common.showFormError(form_id, gettext("You have not renamed it.")); + return false; + } + var post_data = {'oldname': dirent_name, 'newname':new_name}; + var options = { repo_id: dir.repo_id }; + options.name = is_dir ? 'rename_dir' : 'rename_file'; + var post_url = Common.getUrl(options) + '?parent_dir=' + encodeURIComponent(dir.path); + var after_op_success = function (data) { + new_name = data['newname']; + var now = new Date().getTime()/1000; + $.modal.close(); + _this.model.set({ // it will trigger 'change' event + 'obj_name': new_name, + 'last_modified': now, + //'last_update': "{% trans "Just now" %}", + 'last_update': "Just now", + 'sharelink': '', + 'sharetoken': '' + }); + if (is_dir) { + + } else { + _this.model.set({ + 'starred': false + }); + } + }; + Common.ajaxPost({ + 'form': form, + 'post_url': post_url, + 'post_data': post_data, + 'after_op_success': after_op_success, + 'form_id': form_id + }); + return false; + }); + return false; + }, + + mvcp: function() { + var el = event.target || event.srcElement, + op_type = $(el).hasClass('mv') ? 'mv':'cp', + op_detail, + dirent = this.$el, + obj_name = this.model.get('obj_name'), + obj_type = this.model.get('is_dir') ? 'dir':'file', + form = $('#mv-form'), form_hd; + + form.modal({appendTo:'#main', autoResize:true, focus:false}); + $('#simplemodal-container').css({'width':'auto', 'height':'auto'}); + + if (!this.dirView.dir.encrypted) { + $('#other-repos').show(); + } + + if (op_type == 'mv') { + //form_hd = obj_type == 'dir'? "{% trans "Move Directory" %}":"{% trans "Move File" %}"; + form_hd = obj_type == 'dir'? "Move Directory" : "Move File"; + } else { + //form_hd = obj_type == 'dir'? "{% trans "Copy Directory" %}":"{% trans "Copy File" %}"; + form_hd = obj_type == 'dir'? "Copy Directory" : "Copy File"; + } + + //op_detail = op_type == 'mv' ? "{% trans "Move %(name)s to:" %}" : "{% trans "Copy %(name)s to:" %}"; + op_detail = op_type == 'mv' ? "Move %(name)s to:" : "Copy %(name)s to:"; + op_detail = op_detail.replace('%(name)s', '' + obj_name + ''); + form.prepend('

' + form_hd + '

' + op_detail + '

'); + + $('input[name="op"]', form).val(op_type); + $('input[name="obj_type"]', form).val(obj_type); + $('input[name="obj_name"]', form).val(obj_name); + + form.data('op_obj', dirent); + FileTree.render_jstree_for_cur_path({ + repo_name: this.dirView.dir.repo_name, + repo_id: this.dirView.dir.repo_id, + path: this.dirView.dir.path, + }); + return false; + }, + }); return DirentView; diff --git a/media/scripts/common.js b/media/scripts/common.js index ca47572ca3..7fca7111ee 100644 --- a/media/scripts/common.js +++ b/media/scripts/common.js @@ -95,6 +95,11 @@ define([ setTimeout(function() { $('.messages').addClass('hide'); }, time); }, + showFormError: function(formid, error_msg) { + $("#" + formid + " .error").html(error_msg).removeClass('hide'); + $("#simplemodal-container").css({'height':'auto'}); + }, + ajaxErrorHandler: function(xhr, textStatus, errorThrown) { if (xhr.responseText) { feedback($.parseJSON(xhr.responseText).error, 'error'); @@ -176,5 +181,90 @@ define([ } return result; }, + + + renderFileSystemTree: function() { + var form = $('#mv-form'), + file_tree = new FileTree(), + container = $('#current-repo-dirs'), + loading_tip = container.prev(); + + var dirents = app.libdirents, + repo_id = dirents.repo_id, + repo_name = dirents.repo_name, + cur_path = dirents.path; + if (cur_path != '/') { + cur_path += '/'; + } + container.data('site_root', '{{SITE_ROOT}}'); + $.ajax({ + url: app.utils.getUrl({name: 'get_dirents', repo_id: repo_id}) + '?path=' + e(cur_path) + '&dir_only=true&all_dir=true', + cache: false, + dataType: 'json', + success: function(data) { + var json_data = []; + var repo_data = { + 'data': repo_name, + 'attr': {'repo_id': repo_id, 'root_node': true}, + 'state': 'open' + }; + + var path_eles = cur_path.split('/'); + path_eles.pop(); + /* e.g. + * path: '/xx/' + * path_eles: ['', 'xx'] + * data: [["xxx", "xx", "test1022"], ["lkjj", "kjhkhi"]] + * when no dir in '/', data will be [[]]; + */ + var len = data.length; + var children = []; + for (var i = len - 1; i > -1; i--) { + children[i] = []; + if (i == len - 1) { + for (var j = 0, len_i = data[i].length; j < len_i; j++) { + children[i].push({ + 'data': data[i][j], + 'state': 'closed' + }); + } + } else { + for (var j = 0, len_i = data[i].length; j < len_i; j++) { + if (data[i][j] == path_eles[i+1]) { + children[i].push({ + 'data': data[i][j], + 'state': 'open', + 'children': children[i+1] + }); + } else { + children[i].push({ + 'data': data[i][j], + 'state': 'closed' + }); + } + } + } + } + if (children[0].length > 0) { + $.extend(repo_data, {'children': children[0]}); + } + json_data.push(repo_data); + + loading_tip.hide(); + file_tree.renderDirTree(container, form, json_data); + container.removeClass('hide'); + }, + error: function() { + var cur_repo = [{ + 'data': repo_name, + 'attr': {'repo_id': repo_id, 'root_node': true}, + 'state': 'closed' + }]; + loading_tip.hide(); + file_tree.renderDirTree(container, form, cur_repo); + container.removeClass('hide'); + } + }); + } } }); diff --git a/media/scripts/file-tree.js b/media/scripts/file-tree.js new file mode 100644 index 0000000000..5b9693b63f --- /dev/null +++ b/media/scripts/file-tree.js @@ -0,0 +1,278 @@ +define([ + 'jquery', + 'underscore', + 'backbone', + 'common', + ], function($, _, Backbone, Common) { + 'use strict'; + + $.jstree._themes = app.config.mediaURL + 'js/themes/'; + + var FileTree = { + + options: {}, + + formatRepoData: function(data) { + var repos = [], repo; + for (var i = 0, len = data.length; i < len; i++) { + repo = { + 'data': data[i].name, + 'attr': {'repo_id': data[i].id, 'root_node': true}, + 'state': 'closed' + } + repos.push(repo); + } + return repos; + }, + + /** + * @container(required): container.data('site_root', '{{SITE_ROOT}}') + * @options (optional): {'two_state': true} + */ + renderFileTree: function(container, repo_data, options) { + var opts = options || {}; + container + .delegate('.jstree-closed', 'dblclick', function(e) { + container.jstree('open_node', $(this)); + $(this).find('a').removeClass('jstree-clicked'); + }) + .bind('select_node.jstree', function(e, data) { + $('.jstree-clicked').removeClass('jstree-clicked'); // do not show selected item + }) + .jstree({ + 'json_data': { + 'data': repo_data, + 'ajax': { + 'url': function(data) { + var path = this.get_path(data); + var repo_id; + if (path.length == 1) { + path = '/'; + repo_id = data.attr('repo_id'); + } else { + var root_node = data.parents('[root_node=true]'); + repo_id = root_node.attr('repo_id'); + path.shift(); + path = '/' + path.join('/') + '/'; + } + return container.data('site_root') + 'ajax/repo/' + repo_id + '/dirents/?path=' + e(path); + }, + 'success': function(data) { + var items = []; + var o, item; + for (var i = 0, len = data.length; i < len; i++) { + o = data[i]; + if (o.type == 'dir') { + item = { + 'data': o.name, + 'attr': { 'type': o.type }, + 'state': 'closed' + }; + } else { + item = { + 'data': o.name, + 'attr': {'type': o.type } + }; + } + items.push(item); + } + return items; + } + } + }, + 'core': { + 'animation': 100 + }, + 'themes': { + 'theme':'classic' + }, + 'checkbox':{ + 'two_state': opts.two_state, // default: false. when 'true', dir can be checked separately with file + // make dir can only be selected + //'override_ui':true, // nodes can be checked, or selected to be checked + 'real_checkboxes': true, + 'real_checkboxes_names': function(node) { + // get the path array consisting of nodes starting from the root node + var path_array = this.get_path(node); + var repo_id, path; + if (path_array.length == 1) { + // root node + path = '/'; + repo_id = node.attr('repo_id'); + } else { + path_array.shift(); + repo_id = node.parents('[root_node=true]').attr('repo_id'); + if (node.attr('type') == 'dir') { + path = '/' + path_array.join('/') + '/'; + } else { + path = '/' + path_array.join('/'); + } + } + return ['selected', repo_id + path]; + } + }, + 'plugins': ['themes', 'json_data', 'ui', 'checkbox'] + }); + }, + + // only list dirs + renderDirTree: function(container, form, repo_data) { + container + .delegate('.jstree-closed', 'dblclick', function(e) { + container.jstree('open_node', $(this)); + $(this).find('a').removeClass('jstree-clicked'); + }) + .bind('before.jstree', function(e, data) { + if (data.func === 'select_node') { // ensure only one selected dir display in the popup + $('.jstree-clicked', form).removeClass('jstree-clicked'); + } + }) + .bind('select_node.jstree', function(e, data) { + var path, repo_id; + var path_array = data.inst.get_path(data.rslt.obj); + if (path_array.length == 1) { + path = '/'; + repo_id = data.rslt.obj.attr('repo_id'); + } else { + repo_id = data.rslt.obj.parents('[root_node=true]').attr('repo_id'); + path_array.shift(); + path = '/' + path_array.join('/') + '/'; + } + $('input[name="dst_repo"]', form).val(repo_id); + $('input[name="dst_path"]', form).val(path); + }) + .jstree({ + 'json_data': { + 'data': repo_data, + 'ajax': { + 'url': function(data) { + var path = this.get_path(data); + var repo_id; + if (path.length == 1) { + path = '/'; + repo_id = data.attr('repo_id'); + } else { + repo_id = data.parents('[root_node=true]').attr('repo_id'); + path.shift(); + path = '/' + path.join('/') + '/'; + } + return app.config.siteRoot + 'ajax/repo/' + repo_id + '/dirents/?dir_only=true&path=' + encodeURIComponent(path); + }, + 'success': function(data) { + var items = []; + var o, item; + for (var i = 0, len = data.length; i < len; i++) { + o = data[i]; + if (o.has_subdir) { + item = { + 'data': o.name, + 'attr': { 'type': o.type }, + 'state': 'closed' + }; + } else { + item = { + 'data': o.name, + 'attr': {'type': o.type } + }; + } + items.push(item); + } + return items; + } + } + }, + 'core': { + 'animation': 100 + }, + 'plugins': ['themes', 'json_data', 'ui'] + }); + }, + + render_jstree_for_cur_path: function(options) { + var form = $('#mv-form'), + container = $('#current-repo-dirs'), + loading_tip = container.prev(); + + var repo_name = options.repo_name, + repo_id = options.repo_id; + var cur_path = options.path; + if (cur_path != '/') { + cur_path += '/'; + } + var _this = this; + // container.data('site_root', '{{SITE_ROOT}}'); + $.ajax({ + url: Common.getUrl({name: 'get_dirents', repo_id: options.repo_id}) + + '?path=' + encodeURIComponent(cur_path) + '&dir_only=true&all_dir=true', + cache: false, + dataType: 'json', + success: function(data) { + var json_data = []; + var repo_data = { + 'data': repo_name, + 'attr': {'repo_id': repo_id, 'root_node': true}, + 'state': 'open' + }; + + var path_eles = cur_path.split('/'); + path_eles.pop(); + /* e.g. + * path: '/xx/' + * path_eles: ['', 'xx'] + * data: [["xxx", "xx", "test1022"], ["lkjj", "kjhkhi"]] + * when no dir in '/', data will be [[]]; + */ + var len = data.length; + var children = []; + for (var i = len - 1; i > -1; i--) { + children[i] = []; + if (i == len - 1) { + for (var j = 0, len_i = data[i].length; j < len_i; j++) { + children[i].push({ + 'data': data[i][j], + 'state': 'closed' + }); + } + } else { + for (var j = 0, len_i = data[i].length; j < len_i; j++) { + if (data[i][j] == path_eles[i+1]) { + children[i].push({ + 'data': data[i][j], + 'state': 'open', + 'children': children[i+1] + }); + } else { + children[i].push({ + 'data': data[i][j], + 'state': 'closed' + }); + } + } + } + } + if (children[0].length > 0) { + $.extend(repo_data, {'children': children[0]}); + } + json_data.push(repo_data); + + loading_tip.hide(); + _this.renderDirTree(container, form, json_data); + container.removeClass('hide'); + }, + error: function() { + var cur_repo = [{ + 'data': repo_name, + 'attr': {'repo_id': repo_id, 'root_node': true}, + 'state': 'closed' + }]; + loading_tip.hide(); + _this.renderDirTree(container, form, cur_repo); + container.removeClass('hide'); + } + }); + }, + + }; + + return FileTree; +}); diff --git a/seahub/templates/js/dirent.html b/seahub/templates/js/dirent.html index 2c32110fcc..42233e4204 100644 --- a/seahub/templates/js/dirent.html +++ b/seahub/templates/js/dirent.html @@ -58,7 +58,7 @@ <% } %> - <%= dirent.obj_name %> + <%= dirent.obj_name %> <%= dirent.file_size %> @@ -71,7 +71,7 @@
- + <% if (!repo_encrypted) { %> <% } %> @@ -84,7 +84,7 @@
  • {% trans "Move" %}
  • {% trans "Copy" %}
  • {% trans "Update"%}
  • -
  • {% trans "History" %}
  • +
  • {% trans "History" %}
  • <% } %>
    diff --git a/seahub/templates/snippets/lib_op_popups.html b/seahub/templates/snippets/lib_op_popups.html index 03d3e6d538..5d8a1dbe1c 100644 --- a/seahub/templates/snippets/lib_op_popups.html +++ b/seahub/templates/snippets/lib_op_popups.html @@ -33,15 +33,17 @@ +
    {% csrf_token %}