///////////////////////////////////////////////////////////// // // pgAdmin 4 - PostgreSQL Tools // // Copyright (C) 2013 - 2021, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // ////////////////////////////////////////////////////////////// /** * Filemanager JS core * * filemanager.js * * @license MIT License * @author Jason Huck - Core Five Labs * @author Simon Georget * @copyright Authors */ define([ 'jquery', 'underscore', 'pgadmin.alertifyjs', 'sources/gettext', 'sources/url_for', 'dropzone', 'sources/pgadmin', 'sources/csrf', 'tablesorter', 'tablesorter-metric', ], function($, _, Alertify, gettext, url_for, Dropzone, pgAdmin, csrf) { pgAdmin.Browser = pgAdmin.Browser || {}; /*--------------------------------------------------------- Define functions used for various operations ---------------------------------------------------------*/ // Set the CSRF Token csrf.setPGCSRFToken(pgAdmin.csrf_token_header, pgAdmin.csrf_token); // Return file extension var getFileExtension = function(name) { var found = name.lastIndexOf('.') + 1; return (found > 0 ? name.substr(found) : ''); }; /* Common function to load: * en.json language file * file_manager_config.js config file * return transaction id */ var loadData = function(url) { return $.ajax({ async: false, cache: false, url: url, dataType: 'json', contentType: 'application/json; charset=utf-8', }); }; var getFileFormat = function(data) { // Get last selected file format return $.ajax({ async: false, cache: false, url: url_for('settings.get_file_format_setting'), data : $.extend({}, data), dataType: 'json', contentType: 'application/json; charset=utf-8', }); }; // Set enable/disable state of list and grid view var setViewButtonsFor = function(viewMode) { if (viewMode == 'grid') { $('.grid').addClass('ON'); $('.list').removeClass('ON'); } else { $('.list').addClass('ON'); $('.grid').removeClass('ON'); } }; var save_file_dialog_view = function(view, trans_id) { return $.ajax({ url: url_for('file_manager.save_file_dialog_view', { 'trans_id': trans_id, }), type: 'POST', async: true, data: JSON.stringify({ 'view': view, }), contentType: 'application/json', }); }; var save_show_hidden_file_option = function(option, trans_id) { return $.ajax({ url: url_for('file_manager.save_show_hidden_file_option', { 'trans_id': trans_id, }), type: 'PUT', async: true, data: JSON.stringify({ 'show_hidden': option, }), contentType: 'application/json', }); }; // nameFormat (), separate filename from extension var nameFormat = function(input) { var filename = ''; if (input.lastIndexOf('.') != -1) { filename = input.substr(0, input.lastIndexOf('.')); filename += '.' + input.split('.').pop(); } else { filename = input; } return filename; }; /* * Test if Data structure has the 'cap' capability * 'cap' is one of 'select', 'rename', 'delete', 'download' */ var has_capability = function(data, cap) { if (typeof(data.Capabilities) == 'undefined') { return true; } else { return ($.inArray(cap, data.Capabilities) > -1); } }; // return filename extension var getExtension = function(filename) { if (filename.split('.').length == 1) { return ''; } return filename.split('.').pop(); }; /* * Binds specific actions to the toolbar based on capability. * and show/hide buttons */ var bindToolbar = function(data) { // hide/show rename, upload and create button if (_.has(data, 'Capabilities')) { _.each(data.Capabilities, function(cap) { var target_btn = 'button.' + cap, $target_el = $('.file_manager').find(target_btn); if (!has_capability(data, cap) || pgAdmin.FileUtils.hideButtons()) { $target_el.hide(); } else { $target_el.show(); } }); } if (!has_capability(data, 'delete') || pgAdmin.FileUtils.hideButtons()) { $('.file_manager').find('button.delete').hide(); } else { $('.file_manager').find('button.delete').on('click',() => { // hide dimmer $('.fileinfo .delete_item, .fm_dimmer').show(); }); // take action based on pressed button yes or no $('.fileinfo .delete_item button.btn_yes').off().on('click', function() { var path; if ($('.fileinfo').data('view') == 'grid') { path = decodeURI($('.fileinfo').find('#contents li.selected .clip span').attr('data-alt')); if (path.lastIndexOf('/') == path.length - 1) { data.Path = path; deleteItem(data); } else { deleteItem(data); } } else { path = $('.fileinfo').find('table#contents tbody tr.selected td:first-child').attr('title'); if (path.lastIndexOf('/') == path.length - 1) { data.Path = path; deleteItem(data); } else { deleteItem(data); } } // hide dimmer $('.fileinfo .fm_dimmer').hide(); }); } // Download file on download button click if (!has_capability(data, 'download') || pgAdmin.FileUtils.hideButtons()) { $('.file_manager').find('button.download').hide(); } else { $('.file_manager').find('button.download').off().on('click', function() { var path, params = {}; params[pgAdmin.csrf_token_header] = pgAdmin.csrf_token; if ($('.fileinfo').data('view') == 'grid') { path = $('.fileinfo li.selected').find('.clip span').attr('data-alt'); } else { path = $('.fileinfo').find('table#contents tbody tr.selected td:first-child').attr('title'); } download_file(path); }); } }; // enable/disable button when files/folder are loaded var enable_disable_btn = function() { if ($('.fileinfo').data('view') == 'grid') { var $grid_file = $('.file_manager').find('#contents li.selected'); $grid_file.removeClass('selected'); $('.file_manager').find('button.delete').prop('disabled', true); $('.file_manager').find('button.download').prop('disabled', true); $('.file_manager').find('button.rename').prop('disabled', true); if ($grid_file.length > 0) { $('.file_manager_ok').addClass('disabled'); $('.file_manager_ok').attr('disabled', true); } } else { var $list_file = $('.fileinfo').find('table#contents tbody tr.selected'); $list_file.removeClass('selected'); $('.file_manager').find('button.delete').prop('disabled', true); $('.file_manager').find('button.download').prop('disabled', true); $('.file_manager').find('button.rename').prop('disabled', true); if ($list_file.length > 0) { $('.file_manager_ok').addClass('disabled'); $('.file_manager_ok').attr('disabled', true); } } $('.delete_item').hide(); // clear address bar $('.file_manager #uploader .input-path').show(); $('.file_manager #uploader .show_selected_file').remove(); }; /* * Rename the current item and returns the new name. * by double clicking or by clicking the "Rename" button in * table(list) views. */ var renameItem = function(data) { var finalName = '', lg = pgAdmin.FileUtils.lg, getNewName = function(rname) { if (rname !== '') { var givenName = nameFormat(rname), suffix = getExtension(data.Filename); if (suffix.length > 0) { givenName = givenName + '.' + suffix; } var oldPath = data.Path, post_data = { 'mode': 'rename', 'old': data.Path, 'new': givenName, }; $.ajax({ type: 'POST', data: JSON.stringify(post_data), url: pgAdmin.FileUtils.fileConnector, dataType: 'json', contentType: 'application/json; charset=utf-8', async: false, }) .done(function(resp) { var result = resp.data.result; if (result.Code === 1) { var newPath = result['New Path'], newName = result['New Name'], title = $('#preview h1').attr('title'); if (typeof title != 'undefined' && title == oldPath) { $('#preview h1').text(newName); } if ($('.fileinfo').data('view') == 'grid') { $('.fileinfo span[data-alt="' + oldPath + '"]').parent().next('div span').text(newName); $('.fileinfo span[data-alt="' + oldPath + '"]').attr('data-alt', newPath); } else { $('.fileinfo td[title="' + oldPath + '"]').text(newName); $('.fileinfo td[title="' + oldPath + '"]').attr('title', newPath); } $('#preview h1').html(newName); // actualized data for binding data.Path = newPath; data.Filename = newName; // UnBind toolbar functions. $('.fileinfo').find('button.rename, button.delete, button.download').off(); Alertify.success(lg.successful_rename); } else { Alertify.error(result.Error); } finalName = result['New Name']; }); } }; getNewName(data.NewFilename); return finalName; }; /* * delete the folder or files by clicking the "Delete" button * in table(list) view */ var deleteItem = function(data) { var isDeleted = false, lg = pgAdmin.FileUtils.lg; var doDelete = function(sel_data) { var post_data = { 'mode': 'delete', 'path': sel_data.Path, }; $.ajax({ type: 'POST', data: JSON.stringify(post_data), url: pgAdmin.FileUtils.fileConnector, dataType: 'json', contentType: 'application/json; charset=utf-8', async: false, }) .done(function(resp) { var result = resp.data.result; if (result.Code === 1) { isDeleted = true; if (isDeleted) { Alertify.success(lg.successful_delete); var rootpath = result.Path.substring(0, result.Path.length - 1); // removing the last slash rootpath = rootpath.substr(0, rootpath.lastIndexOf('/') + 1); getFolderInfo(rootpath); } } else { isDeleted = false; Alertify.error(result.Error); } }); return isDeleted; }; doDelete(data); return isDeleted; }; /*--------------------------------------------------------- Functions to Retrieve File and Folder Details ---------------------------------------------------------*/ /* * Retrieves information about the specified file as a JSON * object and uses that data to populate a template for * list views. Binds the toolbar for that file/folder to * enable specific actions. Called whenever an item is * clicked in list views. */ var getFileInfo = function(file) { // Update location for status, upload, & new folder functions. pgAdmin.FileUtils.setUploader(file); var capabilities = pgAdmin.FileUtils.data.capabilities, is_file_valid = false, post_data = { 'path': file, 'mode': 'getinfo', }; // Retrieve the data & populate the template. $.ajax({ type: 'POST', data: JSON.stringify(post_data), url: pgAdmin.FileUtils.fileConnector, dataType: 'json', contentType: 'application/json; charset=utf-8', async: false, }) .done(function(resp) { var data = resp.data.result; if (data.Code === 1) { $('.file_manager_ok').removeClass('disabled'); $('.file_manager_ok').attr('disabled', false); data.Capabilities = capabilities; bindToolbar(data); if (data.FileType == 'Directory') { // Enable/Disable level up button enab_dis_level_up(); $('.file_manager_ok').addClass('disabled'); $('.file_manager_ok').attr('disabled', true); $('.file_manager button.delete, .file_manager button.rename').attr('disabled', 'disabled'); $('.file_manager button.download').attr('disabled', 'disabled'); if (file.charAt(file.length - 1) != '/' && file.charAt(file.length - 1) != '\\') { file += '/'; } getFolderInfo(file); } else { is_file_valid = true; } } else { $('.file_manager_ok').addClass('disabled'); $('.file_manager_ok').attr('disabled', true); Alertify.error(data.Error); } }); return is_file_valid; }; var checkPermission = function(path) { var permission = false, post_data = { 'path': path, 'mode': 'permission', }; $.ajax({ type: 'POST', data: JSON.stringify(post_data), url: pgAdmin.FileUtils.fileConnector, dataType: 'json', contentType: 'application/json; charset=utf-8', async: false, }) .done(function(resp) { var data = resp.data.result; if (data.Code === 1) { permission = true; } else { $('.file_manager_ok').addClass('disabled'); $('.file_manager_ok').attr('disabled', true); Alertify.error(data.Error); } }) .fail(function() { $('.file_manager_ok').addClass('disabled'); $('.file_manager_ok').attr('disabled', true); Alertify.error( gettext('Error occurred while checking access permission.') ); }); return permission; }; var getNoDataView = function(data) { var lg = pgAdmin.FileUtils.lg; var cap_no_folders = ['upload', 'create']; data.Capabilities = cap_no_folders; bindToolbar(data); return `
${lg.could_not_retrieve_folder}
`; }; var getGridView = function(data, capabilities) { let ret_ele = ''; if(no_data) { ret_ele += getNoDataView(data); } return ret_ele; }; var getListView = function(data, capabilities) { let lg = pgAdmin.FileUtils.lg; let no_data = _.isEmpty(data); /* file_listing_table class makes height 100%, because of which No folder message is not displayed * file_listing_table_no_data will be removed when new folder is created */ let ret_ele = ``; if(!no_data) { ret_ele += Object.keys(data).sort(function keyOrder(x, y) { return pgAdmin.natural_sort(x.toLowerCase(), y.toLowerCase()); }).map(function(key) { let item_data = data[key], props = item_data.Properties, icon_type = '', class_type = '', cap_classes = ''; cap_classes = Object.keys(capabilities).map(function(cap) { if (has_capability(item_data, capabilities[cap])) { return 'cap_' + capabilities[cap]; } }).join(' '); item_data.Capabilities = capabilities; bindToolbar(item_data); if (item_data.file_type == 'dir') { class_type = 'tbl_folder'; icon_type = 'fa fa-folder-open fm_folder_list'; } else if (item_data.file_type == 'drive') { class_type = 'tbl_drive'; icon_type = 'fa fa-hdd'; } else { class_type = 'tbl_file'; icon_type = 'fa fa-file-alt'; } /* For the html ele */ let item_ele = `'; if (props.Size && props.Size != '') { item_ele += ``; } else { item_ele += ''; } if (props['Date Modified'] && props['Date Modified'] != '') { item_ele += ``; } else { item_ele += ''; } item_ele += ''; return item_ele; }).join('\n'); } ret_ele += `
${lg.name} ${lg.size} ${lg.modified}
`; let data_protected = ''; if (item_data.Protected == 1) { data_protected = ''; } if (!has_capability(data[key], 'rename')) { item_ele += `${data_protected}; ${_.escape(item_data.Filename)}`; } else { item_ele += `
${data_protected} ${_.escape(item_data.Filename)}
`; } item_ele += '
${props.Size}${props['Date Modified']}
`; if(no_data) { ret_ele += getNoDataView(data); } return ret_ele; }; /* * Retrieves data for all items within the given folder and * creates a list view. */ var getFolderInfo = function(path, file_type, user_input) { $('.storage_dialog #uploader .input-path').prop('disabled', true); if (!file_type) { file_type = ''; } var capabilities = pgAdmin.FileUtils.data.Capabilities; // Update location for status, upload, & new folder functions. pgAdmin.FileUtils.setUploader(path); if(user_input) { $('.storage_dialog #uploader .input-path').val(path+user_input); } // set default selected file type if (file_type === '') { file_type = $('.change_file_types select').val(); } // navigate to directory or path when clicked on breadcrumbs $('.file_manager a.breadcrumbs').off().on('click', function() { var curr_path = $(this).attr('data-path'), current_dir = $(this).html(), move_to = curr_path.substring( 0, curr_path.lastIndexOf(current_dir) ) + current_dir; getFolderInfo(move_to); enab_dis_level_up(); }); // hide select file if we are listing drives in windows. if (pgAdmin.FileUtils.hideButtons()) { $('.allowed_file_types .change_file_types').hide(); } else { $('.allowed_file_types .change_file_types').show(); } var loading_icon_url = url_for( 'static', { 'filename': 'js/generated/load-root.gif', } ); // Display an activity indicator. $('.fileinfo').find('span.activity').html( '' + gettext('Loading...') + '/>'
    );

    var post_data = {
      'path': path,
      'mode': 'getfolder',
      'file_type': file_type || '*',
      'show_hidden': $('#show_hidden').prop('checked'),
    };

    $.ajax({
      type: 'POST',
      data: JSON.stringify(post_data),
      url: pgAdmin.FileUtils.fileConnector,
      dataType: 'json',
      contentType: 'application/json; charset=utf-8',
      async: false,
    })
      .done(function(resp) {
        $('.storage_dialog #uploader .input-path').prop('disabled', false);
        var result = '',
          data = resp.data.result;
        let isGridView = false;
        // hide activity indicator
        $('.fileinfo').find('span.activity').hide();
        if (data.Code === 0) {
          Alertify.error(data.Error);
          return;
        }

        var $this, orig_value, newvalue;

        // generate HTML for files/folder and render into container
        if ($('.fileinfo').data('view') == 'grid') {
          result += getGridView(data, capabilities);
          isGridView = true;
        } else {
          result += getListView(data, capabilities);
        }

        // Add the new markup to the DOM.
        $('.fileinfo .file_listing').html(result);

        let $listing_table = $('.fileinfo .file_listing .file_listing_table');

        $listing_table.tablesorter({
          widgets: [ 'resizable', 'stickyHeaders' ],
          widgetOptions : {
            stickyHeaders_attachTo:'.file_listing',
            stickyHeaders_offset: 0,
            resizable_widths: ['400px', '100px', '175px'],
          },
        });

        /* In order to fit our UI, some things need to be explicitly set
         * as tablesorter resizable is creating trouble.
         */
        $listing_table.on( 'resizableComplete', function() {
          let wo = this.config.widgetOptions;
          $.tablesorter.resizable.setWidth($listing_table.find('th[data-column= 0) $(this).click(); // If folder then first select and then double click to open folder/drive else if ($(this).find('.fa-folder-open').length || $(this).find('.fa-hdd').length) { $(this).click(); setTimeout(() => { $(self).trigger('dblclick'); }, 10); } }; $listing_table.on( 'tablesorter-ready', function() { let wo = this.config.widgetOptions; if($.tablesorter.storage($listing_table[0], 'tablesorter-table-resized-width') === '') { $.tablesorter.resizable.setWidth($listing_table, $('.fileinfo .file_listing').width()); } $.tablesorter.resizable.setWidth($listing_table.find('th[data-column="2"]'), wo.resizable_widths[2]); $listing_table.trigger('resizableUpdate'); // Table Sorter writes table elements randomly so we need to handle some corner cases manually $('#show_hidden').off('keydown').on('keydown', function(event) { if (!isGridView && event.keyCode == 9 && event.shiftKey) { event.preventDefault(); $listing_table.find('tbody tr:last').trigger('focus'); } }); $listing_table.find('tbody tr').off('keydown').on('keydown', function(event) { // If key is pressed then we need to trigger click so that it can select file if (event.keyCode == 13 || event.keyCode == 32) { clickOnFileFolderManually.call(this, event); } else if (event.keyCode == 9) { if (event.shiftKey) { // When first tr losses focus and shift + tab > we need to set focus on header if ($(this).prev().length == 0) { event.preventDefault(); $listing_table.find('th.tablesorter-header:last').trigger('focus'); } } else { // When last tr losses focus and Tab was pressed > we need to set focus on checkbox if ($(this).next().length == 0) { event.preventDefault(); $('#show_hidden').trigger('focus'); } } } }); $listing_table.find('th.tablesorter-header').off('keydown').on('keydown', function(event) { // If key is pressed then we need to trigger click so that it can sort if (event.keyCode == 13 || event.keyCode == 32) { event.preventDefault(); event.stopPropagation(); $(this).trigger('click'); } }); }); if(isGridView) { $('.file_manager').find('#contents li').off('keydown').on('keydown', function(event) { // If key is pressed then we need to trigger click so that it can sort if (event.keyCode == 13 || event.keyCode == 32) { clickOnFileFolderManually.call(this, event); } }); } // rename file/folder $('.file_manager button.rename').off().on('click', function(e) { if ($('.fileinfo').data('view') == 'grid') { e.stopPropagation(); $this = $('.file_manager').find('#contents li.selected div'); orig_value = decodeURI($this.find('span.less_text').attr('title')); newvalue = orig_value.substring(0, orig_value.indexOf('.')); if (newvalue === '') { newvalue = decodeURI(orig_value); } $this.find('input').toggle().val(newvalue).trigger('focus'); $this.find('span').toggle(); // Rename folder/file on pressing enter key $('.file_manager').off().on('keyup', function(event) { if (event.keyCode == 13) { event.stopPropagation(); $('.fileinfo #contents li.selected div').find( 'input' ).trigger('blur'); } }); } else if ($('.fileinfo').data('view') == 'list') { e.stopPropagation(); $this = $('.fileinfo').find( 'table#contents tbody tr.selected td.tbl_file' ); if($this.length == 0) { $this = $('.fileinfo').find( 'table#contents tbody tr.selected td.tbl_folder' ); // putting temporary class to distiguish between folder rename & double click. $this.addClass('tbl_folder_rename'); } orig_value = decodeURI($this.find('span.less_text').html()); newvalue = orig_value.substring(0, orig_value.lastIndexOf('.')); if (orig_value.lastIndexOf('/') == orig_value.length - 1 || (_.isEmpty(newvalue) || _.isUndefined(newvalue) || _.isNull(newvalue))) { newvalue = decodeURI(orig_value); } $this.find('.fm_file_rename').toggle().val(newvalue).trigger('focus'); $this.find('.fm_file_name').toggle(); // Rename folder/file on pressing enter key $('.file_manager').off().on('keyup', function(event) { if (event.keyCode == 13) { event.stopPropagation(); $this.find('fm_file_rename').trigger('blur'); } }); } }); // Rename UI handling $('.fileinfo #contents li div').on('blur dblclick', 'input', function(e) { e.stopPropagation(); var old_name = decodeURI($(this).siblings('div').find('.less_text').attr('title')); newvalue = old_name.substring(0, old_name.indexOf('.')); var last = getFileExtension(old_name), file_data, new_name, file_path, full_name; if (old_name.indexOf('.') == 0) { last = ''; } if (newvalue == '') { newvalue = decodeURI(old_name); } if (e.type == 'keydown') { if (e.which == 13) { full_name = decodeURI($(this).val()) + ( last !== '' ? '.' + last : '' ); $(this).toggle(); $(this).siblings('span').toggle().html(full_name); new_name = decodeURI($(this).val()); file_path = decodeURI($(this).parent().parent().find( 'span' ).attr('data-alt')); file_data = { 'Filename': old_name, 'Path': file_path, 'NewFilename': new_name, }; if (newvalue !== new_name) { renameItem(file_data); var parent = $('.currentpath').val(); getFolderInfo(parent); } e.stopPropagation(); } if ( e.which == 38 || e.which == 40 || e.which == 37 || e.which == 39 || e.keyCode == 32 ) { e.stopPropagation(); } } else if (e.type == 'focusout') { if ($(this).css('display') == 'inline-block' || $(this).css('display') == 'inline') { full_name = decodeURI( $(this).val() ) + (last !== '' ? '.' + last : ''); if (newvalue !== new_name) { $(this).toggle(); $(this).siblings('span').toggle().html(full_name); //check if user is trying to rename folder let isFolder = $(this).closest('.tbl_folder').length > 0; new_name = decodeURI($(this).val()); file_path = decodeURI($(this).parent().parent().find( 'span' ).attr('data-alt')); file_data = { 'Filename': old_name, 'Path': file_path, 'NewFilename': new_name, 'isFolder': isFolder, }; renameItem(file_data); let current_path = $('.currentpath').val(); if(isFolder == true) { // if its folder rename, remove the temporary added class $(this).closest('.tbl_folder').removeClass('tbl_folder_rename'); if(current_path.includes('\\')) { current_path = $('.currentpath').val().split('\\').slice(0, -2).join('\\')+'\\'; } else { current_path = $('.currentpath').val().split('/').slice(0, -2).join('/')+'/'; } } getFolderInfo(current_path); } } } else { e.stopPropagation(); } }); $('.fileinfo table#contents tr td div').on( 'blur dblclick', 'input', function(e) { var old_name = decodeURI($(this).siblings('div').find('.less_text').attr('title')), new_value = old_name.substring(0, old_name.indexOf('.')), last = getFileExtension(old_name); if (old_name.indexOf('.') == 0) { last = ''; } if (new_value == '') { new_value = old_name; } if (e.type == 'focusout') { if ($(this).css('display') == 'inline-block' || $(this).css('display') == 'inline') { var full_name = decodeURI($(this).val()) + ( last !== '' ? '.' + last : '' ); if (new_value !== new_name) { $(this).toggle(); $(this).siblings('span').toggle().html(full_name); let isFolder = $(this).closest('.tbl_folder').length > 0; var new_name = decodeURI($(this).val()), file_path = decodeURI($(this).parent().parent().attr('title')), file_data = { 'Filename': old_name, 'Path': file_path, 'NewFilename': new_name, 'isFolder': isFolder, }; renameItem(file_data); let current_path = $('.currentpath').val(); if(isFolder == true) { // if its folder rename, remove the temporary added class $(this).closest('.tbl_folder').removeClass('tbl_folder_rename'); if(current_path.includes('\\')) { current_path = $('.currentpath').val().split('\\').slice(0, -2).join('\\')+'\\'; } else { current_path = $('.currentpath').val().split('/').slice(0, -2).join('/')+'/'; } } getFolderInfo(current_path); } } } else { e.stopPropagation(); } }); var data_cap = {}; data_cap.Capabilities = capabilities; /* * Bind click events * Select items - afolder dblclick */ if ($('.fileinfo').data('view') == 'grid') { // Get into folder on dblclick $('.fileinfo').find('#contents li').dblclick(function(e) { e.stopPropagation(); // Enable/Disable level up button enab_dis_level_up(); var file_path = decodeURI($(this).find('span').attr('data-alt')); if (file_path.lastIndexOf('/') == file_path.length - 1 || file_path.lastIndexOf('\\') == file_path.length - 1) { $('.file_manager_ok').addClass('disabled'); $('.file_manager_ok').attr('disabled', true); $('.file_manager button.delete, .file_manager button.rename').attr('disabled', 'disabled'); $('.file_manager button.download').attr('disabled', 'disabled'); getFolderInfo(file_path); } else { var is_valid_file = getFileInfo(file_path); if (is_valid_file && check_file_capability(e, data_cap, 'grid')) { $('.file_manager_ok').trigger('click'); } } }); $('.fileinfo').find('#contents li').on('click', function(e) { e.stopPropagation(); var file_path = decodeURI($(this).find('.clip span').attr('data-alt')), is_protected = $(this).find( '.clip span.fm_lock_icon' ).attr('data-protected'); if (file_path.lastIndexOf('/') == file_path.length - 1 || file_path.lastIndexOf('\\') == file_path.length - 1) { if ( has_capability(data_cap, 'select_folder') && is_protected == undefined ) { $(this).parent().find('li.selected').removeClass('selected'); $(this).addClass('selected'); $('.file_manager_ok').removeClass('disabled'); $('.file_manager_ok').attr('disabled', false); $('.file_manager button.delete, .file_manager button.rename').removeAttr( 'disabled', 'disabled' ); $('.file_manager button.download').attr( 'disabled', 'disabled' ); // set selected folder name in breadcrums $('.file_manager #uploader .input-path').hide(); $('.file_manager #uploader .show_selected_file').remove(); $('' + file_path + '').appendTo( '.file_manager #uploader .filemanager-path-group' ); } pgAdmin.FileUtils.setUploader(file_path); } else { if ( has_capability(data_cap, 'select_file') && is_protected == undefined ) { $(this).parent().find('li.selected').removeClass('selected'); $(this).addClass('selected'); $('.file_manager_ok').removeClass('disabled'); $('.file_manager_ok').attr('disabled', false); $('.file_manager button.delete, .file_manager button.download, .file_manager button.rename').removeAttr( 'disabled' ); // set selected folder name in breadcrums $('.file_manager #uploader .show_selected_file').remove(); } getFileInfo(file_path); } }); } else { $('.fileinfo table#contents tbody tr').on('click', function(e) { e.stopPropagation(); var file_path = decodeURI($('td:first-child', this).attr('title')), is_protected = $('td:first-child', this).find( 'i.tbl_lock_icon' ).attr('data-protected'); if (file_path.lastIndexOf('/') == file_path.length - 1 || file_path.lastIndexOf('\\') == file_path.length - 1) { if (has_capability(data_cap, 'select_folder') && is_protected == undefined) { $(this).parent().find('tr.selected').removeClass('selected'); $('td:first-child', this).parent().addClass('selected'); $('.file_manager_ok').removeClass('disabled'); $('.file_manager_ok').attr('disabled', false); $('.file_manager button.download').attr('disabled', 'disabled'); $('.file_manager button.delete, .file_manager button.rename').removeAttr('disabled'); // set selected folder name in breadcrums $('.file_manager #uploader .input-path').hide(); $('.file_manager #uploader .show_selected_file').remove(); $('' + file_path + '').appendTo( '.file_manager #uploader .filemanager-path-group' ); } pgAdmin.FileUtils.setUploader(file_path); } else { if (has_capability(data_cap, 'select_file') && is_protected == undefined) { $(this).parent().find('tr.selected').removeClass('selected'); $('td:first-child', this).parent().addClass('selected'); $('.file_manager button.delete, .file_manager button.download, .file_manager button.rename').removeAttr( 'disabled' ); // set selected folder name in breadcrums $('.file_manager #uploader .show_selected_file').remove(); } getFileInfo(file_path); } }); $('.fileinfo table#contents tbody tr').on('dblclick', function(e) { e.stopPropagation(); // Enable/Disable level up button enab_dis_level_up(); var file_path = $('td:first-child', this).attr('title'); if (file_path.lastIndexOf('/') == file_path.length - 1 || file_path.lastIndexOf('\\') == file_path.length - 1) { $('.file_manager_ok').addClass('disabled'); $('.file_manager_ok').attr('disabled', true); $('.file_manager button.download').attr('disabled', 'disabled'); $('.file_manager button.delete, .file_manager button.rename').attr('disabled', 'disabled'); getFolderInfo(file_path); } else { var is_valid_file = getFileInfo(file_path); if ( is_valid_file && check_file_capability(e, data_cap, 'table') ) { $('.file_manager_ok').trigger('click'); } } }); } //input_object.set_cap(data_cap); }) .fail(function() { $('.storage_dialog #uploader .input-path').prop('disabled', false); }); }; var homedir='/'; // Enable/Disable level up button var enab_dis_level_up = function() { $('.file_manager #uploader .input-path').show(); $('.show_selected_file').remove(); setTimeout(function() { var b = $('.currentpath').val(), $level_up = $('.file_manager').find('button.level-up'), $home_btn = $('.file_manager').find('button.home'); (b === '/') ? $level_up.attr('disabled', 'disabled') : $level_up.removeAttr('disabled'); (b === homedir) ? $home_btn.attr('disabled', 'disabled') : $home_btn.removeAttr('disabled'); }, 100); }; // Check if user can Select file var check_file_capability = function(event, data_cap, view_type) { var current_element = event.currentTarget, is_protected; if (view_type == 'grid') { is_protected = $(current_element).find( '.clip span.fm_lock_icon' ).attr('data-protected'); } else { is_protected = $(current_element).find('td:first-child').find( 'i.tbl_lock_icon' ).attr('data-protected'); } return has_capability(data_cap, 'select_file') && is_protected == undefined; }; // Download selected file var download_file = function (path) { var data = { 'path': path, 'mode': 'download' }, params = {}; params[pgAdmin.csrf_token_header] = pgAdmin.csrf_token; $.ajax({ type: 'POST', url: pgAdmin.FileUtils.fileConnector, contentType: false, headers: params, xhrFields: { responseType: 'blob', }, cache: false, data: JSON.stringify(data), success: function (blob, status, xhr) { // check for a filename var filename = xhr.getResponseHeader('filename'); if (typeof window.navigator.msSaveBlob !== 'undefined') { // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed." window.navigator.msSaveBlob(blob, filename); } else { var URL = window.URL || window.webkitURL; var downloadUrl = URL.createObjectURL(blob); if (filename) { // use HTML5 a[download] attribute to specify filename var a = document.createElement('a'); // safari doesn't support this yet if (typeof a.download === 'undefined') { window.location.href = downloadUrl; } else { a.href = downloadUrl; a.download = filename; document.body.appendChild(a); a.click(); } } else { window.location.href = downloadUrl; } setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup } }, error: function (error) { Alertify.error(error); }, }); }; /*--------------------------------------------------------- Initialization - Entry point ---------------------------------------------------------*/ /* * get transaction id to generate request url and * to generate config files on runtime */ pgAdmin.FileUtils = { init: function() { var fm_url = url_for('file_manager.get_trans_id'), transId = loadData(fm_url), t_res, t_id; if (transId.readyState == 4) { t_res = JSON.parse(transId.responseText); } t_id = _.isUndefined(t_res) ? 0 : t_res.data.fileTransId; var root_url = url_for('file_manager.index'), file_manager_config_json = root_url + t_id + '/file_manager_config.json', fileConnector = root_url + 'filemanager/' + t_id + '/', cfg = loadData(file_manager_config_json), config; this.fileConnector = fileConnector; this.transId = t_id; // load user configuration file if (cfg.readyState == 4) { this.config = config = JSON.parse(cfg.responseText); homedir=config.options.homedir; } if (_.isUndefined(config)) return; // set main url to filemanager and its capabilites var fileRoot = config.options.fileRoot, capabilities = config.options.capabilities; /* * Get localized messages from file * through culture var or from URL */ var lg = [], enjson = url_for('file_manager.index') + 'en.json', lgf = loadData(enjson); if (lgf.readyState == 4) { this.lg = lg = JSON.parse(lgf.responseText); } // create and enable user to create new file if ( config.options.dialog_type == 'select_file' || config.options.dialog_type == 'create_file' || config.options.dialog_type == 'storage_dialog' ) { // Create file selection dropdown var allowed_types = config.options.allowed_file_types, types_len = allowed_types.length, select_box = ''; if (types_len > 0) { var i = 0, t, have_all_types = false; let fileFormats = ''; let response = getFileFormat(config.options.allowed_file_types); let lastSelectedFormat = response.responseJSON.info; while (i < types_len) { t = allowed_types[i]; if ((types_len == 1 || t != '*')) { if(t === lastSelectedFormat) fileFormats += ''; else fileFormats += ''; have_all_types = (have_all_types || (t == '*')); } else if ((lastSelectedFormat === '*')) { fileFormats += ''; have_all_types = (have_all_types || (t == '*')); } i++; } if (!have_all_types) { fileFormats += ''; } select_box = `
` + gettext('Show hidden files and folders?') + `
`; } $('.allowed_file_types').html(select_box); $('.allowed_file_types select').on('change', function() { var selected_val = $(this).val(), curr_path = $('.currentpath').val(), user_input_file = null, input_path = $('.storage_dialog #uploader .input-path').val(); config.options.selectedFormat = selected_val; $.ajax({ url: url_for('settings.save_file_format_setting'), type: 'POST', contentType: 'application/json', data: JSON.stringify(config.options), }); if (curr_path.endsWith('/')) { user_input_file = input_path.substring(curr_path.lastIndexOf('/')+1); } else { user_input_file = input_path.substring(curr_path.lastIndexOf('\\')+1); } getFolderInfo(curr_path, selected_val, user_input_file); }); // If user have preference to show hidden files if (config.options.show_hidden_files) { setTimeout(function() { $('#show_hidden').trigger('click'); }, 10); } // handle show hidden files functionality this.handleClick = function(cb) { var tmp_data = { 'is_checked': false, }; if (cb.checked) { $('div.allowed_file_types select').trigger('change'); tmp_data['is_checked'] = true; } else { // User wants to hide it again $('div.allowed_file_types select').trigger('change'); tmp_data['is_checked'] = false; } // Save it in preference save_show_hidden_file_option(tmp_data['is_checked'], pgAdmin.FileUtils.transId); return; }; } /*--------------------------------------------------------- Item Actions - Object events ---------------------------------------------------------*/ $('.file_manager').attr('data-platform', config.options.platform_type); // Switch to folder view $('.file_manager .fileinfo').on('click', function() { enable_disable_btn(); }); // Refresh current directory $('.file_manager .refresh').on('click', function() { enable_disable_btn(); var curr_path = $('.currentpath').val(), path; $('.file_manager #uploader .input-path').val(curr_path); if (curr_path.endsWith('/')) { path = curr_path.substring(0, curr_path.lastIndexOf('/')) + '/'; } else { path = curr_path.substring(0, curr_path.lastIndexOf('\\')) + '\\'; } getFolderInfo(path); }); // hide message prompt and dimmer if clicked no $('.delete_item button.btn_no').on('click', function() { $('.delete_item, .fileinfo .fm_dimmer').hide(); }); // Disable button on load $('.file_manager').find('button.rename').attr('disabled', 'disabled'); // stop click event on dimmer click $('.fileinfo .fm_dimmer').on('click', function(e) { e.stopPropagation(); }); $('.fileinfo .replace_file').not( $(this).find('span.pull-right') ).on( 'click', function(e) { $('#uploader .filemanager-btn-group').off().on( 'click', function() { $('.fileinfo .delete_item, .fileinfo .replace_file, .fileinfo .fm_dimmer').hide(); }); e.stopPropagation(); }); // Set initial view state. $('.fileinfo').data('view', config.options.defaultViewMode); setViewButtonsFor(config.options.defaultViewMode); // Upload click event $('.file_manager .uploader').on('click', 'a', function(e) { e.preventDefault(); var b = $('.currentpath').val(), node_val = $(this).next().text(), parent = b.substring(0, b.slice(0, -1).lastIndexOf(node_val)); getFolderInfo(parent); }); // re-render the home view $('.file_manager .home').on('click', function() { var currentViewMode = $('.fileinfo').data('view'); $('.fileinfo').data('view', currentViewMode); getFolderInfo(homedir); enab_dis_level_up(); }); // Go one directory back $('.file_manager .level-up').on('click', function() { var b = $('.currentpath').val(); // Enable/Disable level up button enab_dis_level_up(); if (b.endsWith('\\') || b.endsWith('/')) { b = b.substring(0, b.length - 1); } if (b != '/') { var parent; if (b.lastIndexOf('/') > b.lastIndexOf('\\')) { parent = b.substring(0, b.slice(0, -1).lastIndexOf('/')) + '/'; } else { parent = b.substring(0, b.slice(0, -1).lastIndexOf('\\')) + '\\'; } var d = $('.fileinfo').data('view'); $('.fileinfo').data('view', d); getFolderInfo(parent); } }); // set buttons to switch between grid and list views. $('.file_manager .grid').on('click',() => { setViewButtonsFor('grid'); $('.fileinfo').data('view', 'grid'); enable_disable_btn(); getFolderInfo($('.currentpath').val()); save_file_dialog_view('grid', pgAdmin.FileUtils.transId); }); // Show list mode $('.file_manager .list').on('click',() => { setViewButtonsFor('list'); $('.fileinfo').data('view', 'list'); enable_disable_btn(); getFolderInfo($('.currentpath').val()); save_file_dialog_view('list', pgAdmin.FileUtils.transId); }); // Provide initial values for upload form, status, etc. pgAdmin.FileUtils.setUploader(fileRoot); var data; this.data = data = { 'Capabilities': capabilities, }; function InputObject() { this.init = function(cap) { var self = this, check_obj = function(path, check) { path = decodeURI(path); if (path.lastIndexOf('/') == path.length - 1 || path.lastIndexOf('\\') == path.length - 1) { if ( has_capability(self.data_cap, 'select_folder') ) { $('.file_manager_ok').removeClass('disabled'); $('.file_manager_ok').attr('disabled', false); $('.file_manager button.delete').removeAttr( 'disabled', 'disabled' ); $('.file_manager button.download').attr( 'disabled', 'disabled' ); $('.file_manager button.rename').attr('disabled', 'disabled'); // set selected folder name in breadcrums $('.file_manager #uploader .input-path').hide(); $('.file_manager #uploader .show_selected_file').remove(); $('' + path + '').appendTo( '.file_manager #uploader .filemanager-path-group' ); } else { $('.file_manager_ok').addClass('disabled'); $('.file_manager_ok').attr('disabled', true); if (check) { // Enable/Disable level up button enab_dis_level_up(); $('.file_manager button.delete, .file_manager button.rename').attr('disabled', 'disabled'); $('.file_manager button.download').attr('disabled', 'disabled'); getFolderInfo(path); } } } else { if ( has_capability(self.data_cap, 'select_file') ) { $('.file_manager_ok').removeClass('disabled'); $('.file_manager_ok').attr('disabled', false); $('.file_manager button.delete, .file_manager button.download, .file_manager button.rename').removeAttr( 'disabled' ); // set selected folder name in breadcrumbs $('.file_manager #uploader .show_selected_file').remove(); } if (check) { if (config.options.dialog_type == 'create_file') { var status = checkPermission(path); if (status) { //$('.file_manager').trigger('enter-key'); $('.file_manager_ok').trigger('click'); } } else if (config.options.dialog_type == 'select_file') { var file_status = getFileInfo(path); if (file_status) { $('.file_manager_ok').trigger('click'); //$('.file_manager').trigger('enter-key'); } } } } }; self.data_cap = cap; $('.storage_dialog #uploader .input-path').on('keyup',function(e) { if (e.keyCode == 13) { e.stopPropagation(); var path = $(this).val(); if (path == '') { path = '/'; } if (config.options.platform_type === 'win32') { path = path.replace(/\//g, '\\'); } else { path = path.replace(/\\/g, '/'); if (!path.startsWith('/')) { path = '/' + path; } } $(this).val(path); setTimeout(function() { check_obj(path, true); }); return; } check_obj($(this).val(), false); }); }; this.set_cap = function(cap) { this.data_cap = cap; }; } var input_object = new InputObject(); input_object.init(data); // Upload file if (has_capability(data, 'upload')) { Dropzone.autoDiscover = false; // we remove simple file upload element $('.file-input-container').remove(); $('.upload').remove(); $('.create').before(' '); $('#uploader .upload').off().on('click', function() { // we create prompt var msg = '
' + '' + '
'+ '
'+ '
' + '
' + gettext('Drop files here to upload.') + ' ' + lg.file_size_limit + config.upload.fileSizeLimit + ' ' + lg.mb + '.
', path = $('.currentpath').val(), filesizelimit = config.upload.fileSizeLimit, // default dropzone value fileSize = (filesizelimit != 'auto') ? filesizelimit : 256, acceptFiles; if (config.security.uploadPolicy == 'DISALLOW_ALL') { acceptFiles = '.' + config.security.uploadRestrictions.join(',.'); } else { // We allow any extension since we have no easy way to handle the the // built-in `acceptedFiles` params would be handled later by the // connector. acceptFiles = null; } $('.file_manager .upload_file').toggleClass('d-none'); $('.file_manager .file_listing').toggleClass('d-none'); $('.file_manager .upload_file').html(msg); var previewTemplate = '
' + '
' + '

' + '

' + '
' + '
' + '
' + '
' + '
' + '' + '
'; // We need to append our csrf token with dropzone's ajax request header let csrfToken = {}; csrfToken[pgAdmin.csrf_token_header] = pgAdmin.csrf_token; $('div#multiple-uploads').dropzone({ paramName: 'newfile', url: pgAdmin.FileUtils.fileConnector, headers: csrfToken, maxFilesize: fileSize, maxFiles: config.upload.number, addRemoveLinks: true, previewTemplate: previewTemplate, parallelUploads: config.upload.number, dictMaxFilesExceeded: lg.dz_dictMaxFilesExceeded.replace( '%s', config.upload.number ), dictDefaultMessage: lg.dz_dictDefaultMessage, dictInvalidFileType: lg.dz_dictInvalidFileType, dictFileTooBig: lg.file_too_big + ' ' + lg.file_size_limit + config.upload.fileSizeLimit + ' ' + lg.mb, acceptedFiles: acceptFiles, autoProcessQueue: true, init: function() { $('.dz_cross_btn').off().on('click', function() { $('.file_manager .upload_file').toggleClass('d-none'); $('.file_manager .file_listing').toggleClass('d-none'); }); }, sending: function(file, xhr, formData) { formData.append('mode', 'add'); formData.append('currentpath', path); $('.upload_file .dz_cross_btn').attr('disabled', 'disabled'); setTimeout(function() {}, 10000); }, success: function(file, response) { var resp_data = response.data.result, $this = $(file.previewTemplate); if (resp_data.Code == 1) { setTimeout(function() { $this.find('.dz-upload').addClass('success'); }, 1000); $this.find('.dz-upload').css('width', '100%').html('100%'); Alertify.success(lg.upload_success); } else { $this.find('.dz-upload').addClass('error'); $this.find('.dz-upload').css('width', '0%').html('0%'); Alertify.error(resp_data.Error); } getFolderInfo(path); }, totaluploadprogress: function() {}, complete: function(file) { if (file.status == 'error') { Alertify.error(lg.upload_error); } $('.upload_file .dz_cross_btn').removeAttr('disabled'); getFolderInfo(path); }, }); }); } this.getDetailView(fileRoot); }, /* * Sets the folder status, upload, and new folder functions * to the path specified. Called on initial page load and * whenever a new directory is selected. */ setUploader: function(path) { var config = this.config; var lg = this.lg; $('.storage_dialog #uploader').find('a').remove(); $('.storage_dialog #uploader').find('b').remove(); if (config.options.platform_type === 'win32') { path = path.replace(/\//g, '\\'); } else { path = path.replace(/\\/g, '/'); } path = decodeURI(path); if (config.options.platform_type === 'win32') { if (config.options.show_volumes && path == '\\') { $('.storage_dialog #uploader .input-path').val(''); } else { $('.storage_dialog #uploader .input-path').val(path); } } else if ((config.options.platform_type !== 'win32') && (path == '' || !path.startsWith('/'))) { path = '/' + path; $('.storage_dialog #uploader .input-path').val(path); } else { $('.storage_dialog #uploader .input-path').val(path); } if (path.lastIndexOf('\\') == -1 && path.lastIndexOf('/') == -1) { $('.currentpath').val(path); } else if (path.lastIndexOf('/') > path.lastIndexOf('\\')) { $('.currentpath').val(path.substr(0, path.lastIndexOf('/') + 1)); } else { $('.currentpath').val(path.substr(0, path.lastIndexOf('\\') + 1)); } enab_dis_level_up(); if ($('.storage_dialog #uploader h1 span').length === 0) { $('' + lg.current_folder + '').appendTo($('.storage_dialog #uploader h1')); } $('.storage_dialog #uploader .input-path').attr('title', path); $('.storage_dialog #uploader .input-path').attr('data-path', path); // create new folder $('.create').off().on('click', function() { var foldername = lg.new_folder; var $file_element, $file_element_list, folder_div; $('.file_manager button.create').attr('disabled', 'disabled'); $('.no_folder_found').addClass('d-none'); if ($('.fileinfo').data('view') == 'grid') { // template for creating new folder folder_div = '
  • ' + '
    ' + '
    New_Folder
    ' + '
  • '; path = $('.currentpath').val(); $file_element = $(folder_div); $('.fileinfo #contents.grid').prepend($file_element); $file_element.find('div span.less_text').toggle(); $file_element.find('div input').toggle().val(lg.new_folder).select(); // rename folder/file on pressing enter key $('.file_manager').on('keyup', function(e) { if (e.keyCode == 13) { e.stopPropagation(); $file_element.find('div input').trigger('blur'); } }); // rename folder/file on blur $file_element.find('div input').on('blur', function() { $('.file_manager button.create').removeAttr('disabled'); var text_value = $file_element.find('div input').val(); path = $('.currentpath').val(); $file_element.find('div input').toggle(); $file_element.find('div span.less_text').toggle().html(text_value); if (text_value === undefined) { text_value = lg.new_folder; } getFolderName(text_value); getFolderInfo(path); }); } else if ($('.fileinfo').data('view') == 'list') { // template to create new folder in table view folder_div = $( `
    ${lg.new_folder}
    ` ); $file_element_list = $(folder_div); let tableEl = $('.fileinfo #contents.file_listing_table'); tableEl.removeClass('file_listing_table_no_data'); tableEl.find('tbody').prepend($file_element_list); $file_element_list.find('td .fm_file_name').toggle(); $file_element_list.find('td input').toggle().val(lg.new_folder).select(); // rename folder/file on pressing enter key $('.file_manager').on('keyup', function(e) { if (e.keyCode == 13) { e.stopPropagation(); $file_element_list.find('td input').trigger('blur'); } }); // rename folder/file on blur $file_element_list.find('td input').on('blur', function() { $('.file_manager button.create').removeAttr('disabled'); var text_value = $file_element_list.find('td input').val(); path = $('.currentpath').val(); $file_element_list.find('td input').toggle(); $file_element_list.find('td .fm_file_name span.less_text').html(text_value); $file_element_list.find('td .fm_file_name').toggle(); if (text_value === undefined) { text_value = lg.new_folder; } getFolderName(text_value); getFolderInfo(path); }); } // create a new folder var getFolderName = function(value) { var fname = value; if (fname != '') { foldername = fname; // Add _ variable in URL for avoiding the caching $.getJSON( pgAdmin.FileUtils.fileConnector + '?_=' + Date.now() + '&mode=addfolder&path=' + $('.currentpath').val() + '&name=' + foldername, function(resp) { var result = resp.data.result; if (result.Code === 1) { Alertify.success(lg.successful_added_folder); getFolderInfo(result.Parent); } else { Alertify.error(result.Error); } } ); } else { Alertify.error(lg.no_foldername); } }; }); }, /* Decides whether to retrieve file or folder info based on * the path provided. */ getDetailView: function(path) { if (path.lastIndexOf('/') == path.length - 1 || path.lastIndexOf('\\') == path.length - 1) { var allowed_types = this.config.options.allowed_file_types; let set_type; let response = getFileFormat(this.config.options.allowed_file_types); let lastSelectedFormat = response.responseJSON.info; if (_.isUndefined(lastSelectedFormat)) set_type = allowed_types[0]; else set_type = lastSelectedFormat; getFolderInfo(path, set_type); } }, // helpful in show/hide toolbar button for Windows hideButtons: function() { return ( this.config.options.platform_type === 'win32' && $('.currentpath').val() === '' ); }, }; return pgAdmin.FileUtils; }); //@ sourceURL=utility.js