From ab5d354f1b60960d20542564e4c893e357dd7c39 Mon Sep 17 00:00:00 2001 From: Marcin Kuzminski Date: Wed, 22 May 2019 12:46:46 +0200 Subject: [PATCH] files: made file filter an active input instead of a button. --- rhodecode/lib/helpers.py | 2 +- rhodecode/public/css/main.less | 50 ++- rhodecode/public/js/src/rhodecode/files.js | 440 ++++++++++--------- rhodecode/templates/files/files.mako | 3 +- rhodecode/templates/files/files_browser.mako | 40 +- 5 files changed, 287 insertions(+), 248 deletions(-) diff --git a/rhodecode/lib/helpers.py b/rhodecode/lib/helpers.py index d19c40a0..22fd74af 100644 --- a/rhodecode/lib/helpers.py +++ b/rhodecode/lib/helpers.py @@ -1951,7 +1951,7 @@ def get_visual_attr(tmpl_context_var, attr_name): def get_last_path_part(file_node): if not file_node.path: - return u'' + return u'/' path = safe_unicode(file_node.path.split('/')[-1]) return u'../' + path diff --git a/rhodecode/public/css/main.less b/rhodecode/public/css/main.less index 7f50428e..0a00f22c 100644 --- a/rhodecode/public/css/main.less +++ b/rhodecode/public/css/main.less @@ -2221,25 +2221,41 @@ h3.files_location{ margin: -25px 0px 5px 0px; } -.node-filter { - font-size: @repo-title-fontsize; - padding: 4px 0px 0px 0px; - - .node-filter-path { - float: left; - color: @grey4; - } - .node-filter-input { - float: left; - margin: -2px 0px 0px 2px; - input { - padding: 2px; - border: none; - font-size: @repo-title-fontsize; - } - } +.files-quick-filter { + float: right; + margin: 0 25px; } +.files-filter-box { + display: flex; + padding: 0px; + border-radius: 3px; + border: 1px solid @grey3; + + a { + border: none !important; + } + + li { + list-style-type: none + } +} + + +.files-filter-box-path { + line-height: 28px; + padding: 0 5px; + +} + +.files-filter-box-input { + background-color: @grey3 !important; + margin-right: 0; + + input { + border: none + } +} .browser-result{ td a{ diff --git a/rhodecode/public/js/src/rhodecode/files.js b/rhodecode/public/js/src/rhodecode/files.js index 415b2887..31c3174a 100644 --- a/rhodecode/public/js/src/rhodecode/files.js +++ b/rhodecode/public/js/src/rhodecode/files.js @@ -19,234 +19,254 @@ /** * Search file list */ -// global reference to file-node filter -var _NODEFILTER = {}; -var fileBrowserListeners = function(node_list_url, url_base){ - var n_filter = $('#node_filter').get(0); +var NodeFilter = {}; - _NODEFILTER.filterTimeout = null; - var nodes = null; +var fileBrowserListeners = function (node_list_url, url_base) { + var $filterInput = $('#node_filter'); + var n_filter = $filterInput.get(0); - _NODEFILTER.fetchNodes = function(callback) { - $.ajax({url: node_list_url, headers: {'X-PARTIAL-XHR': true}}) - .done(function(data){ - nodes = data.nodes; - if (callback) { - callback(); + NodeFilter.filterTimeout = null; + var nodes = null; + + NodeFilter.focus = function () { + $filterInput.focus() + }; + + NodeFilter.fetchNodes = function (callback) { + $.ajax( + {url: node_list_url, headers: {'X-PARTIAL-XHR': true}}) + .done(function (data) { + nodes = data.nodes; + if (callback) { + callback(); + } + }) + .fail(function (data) { + console.log('failed to load'); + }); + }; + + NodeFilter.initFilter = function (e) { + if ($filterInput.hasClass('loading')) { + return } - }) - .fail(function(data){ - console.log('failed to load'); - }); - }; - _NODEFILTER.fetchNodesCallback = function() { - $('#node_filter_box_loading').hide(); - $('#node_filter_box').removeClass('hidden').show(); - n_filter.focus(); - if ($('#node_filter').hasClass('init')){ - n_filter.value = ''; - $('#node_filter').removeClass('init'); - } - }; - - _NODEFILTER.initFilter = function(){ - $('#node_filter_box_loading').removeClass('hidden').show(); - $('#search_activate_id').hide(); - $('#search_deactivate_id').removeClass('hidden').show(); - $('#add_node_id').hide(); - _NODEFILTER.fetchNodes(_NODEFILTER.fetchNodesCallback); - }; - - _NODEFILTER.resetFilter = function(){ - $('#node_filter_box_loading').hide(); - $('#node_filter_box').hide(); - $('#search_activate_id').show(); - $('#search_deactivate_id').hide(); - $('#add_node_id').show(); - $('#tbody').show(); - $('#tbody_filtered').hide(); - $('#node_filter').val(''); - }; - - _NODEFILTER.fuzzy_match = function(filepath, query) { - var highlight = []; - var order = 0; - for (var i = 0; i < query.length; i++) { - var match_position = filepath.indexOf(query[i]); - if (match_position !== -1) { - var prev_match_position = highlight[highlight.length-1]; - if (prev_match_position === undefined) { - highlight.push(match_position); - } else { - var current_match_position = prev_match_position + match_position + 1; - highlight.push(current_match_position); - order = order + current_match_position - prev_match_position; + // in case we are already loaded, do nothing + if (!$filterInput.hasClass('init')) { + return NodeFilter.handleKey(e); } - filepath = filepath.substring(match_position+1); - } else { - return false; - } - } - return {'order': order, - 'highlight': highlight}; - }; - _NODEFILTER.sortPredicate = function(a, b) { - if (a.order < b.order) return -1; - if (a.order > b.order) return 1; - if (a.filepath < b.filepath) return -1; - if (a.filepath > b.filepath) return 1; - return 0; - }; + var org = $('.files-filter-box-path .tag').html(); + $('.files-filter-box-path .tag').html('loading...'); + $filterInput.addClass('loading'); + + var callback = function (org) { + return function () { + if ($filterInput.hasClass('init')) { + $filterInput.removeClass('init'); + $filterInput.removeClass('loading'); + } + $('.files-filter-box-path .tag').html(org); + + // auto re-filter if we filled in the input + if (n_filter.value !== "") { + NodeFilter.updateFilter(n_filter, e)() + } - _NODEFILTER.updateFilter = function(elem, e) { - return function(){ - // Reset timeout - _NODEFILTER.filterTimeout = null; - var query = elem.value.toLowerCase(); - var match = []; - var matches_max = 20; - if (query !== ""){ - var results = []; - for(var k=0;k 0){ - var n = results[i].filepath; - var t = results[i].type; - var n_hl = n.split(""); - var pos = results[i].highlight; - for (var j = 0; j < pos.length; j++) { - n_hl[pos[j]] = "" + n_hl[pos[j]] + ""; } - n_hl = n_hl.join(""); - var new_url = url_base.replace('__FPATH__',n); - - var typeObj = { - dir: 'icon-directory browser-dir', - file: 'icon-file-text browser-file' - }; - - var typeIcon = ''.format(typeObj[t]); - match.push('{1}{2}'.format(new_url,typeIcon, n_hl)); - } - } - if(results.length > limit){ - var truncated_count = results.length - matches_max; - if (truncated_count === 1) { - match.push('{0} {1}'.format(truncated_count, _gettext('truncated result'))); - } else { - match.push('{0} {1}'.format(truncated_count, _gettext('truncated results'))); - } - } - } - if (query !== ""){ - $('#tbody').hide(); - $('#tbody_filtered').show(); - - if (match.length === 0){ - match.push('{0}'.format(_gettext('No matching files'))); - } - $('#tbody_filtered').html(match.join("")); - } - else{ - $('#tbody').show(); - $('#tbody_filtered').hide(); - } + }; + // load node data + NodeFilter.fetchNodes(callback(org)); }; - }; - var scrollDown = function(element){ - var elementBottom = element.offset().top + $(element).outerHeight(); - var windowBottom = window.innerHeight + $(window).scrollTop(); - if (elementBottom > windowBottom) { - var offset = elementBottom - window.innerHeight; - $('html,body').scrollTop(offset); - return false; - } - return true; - }; + NodeFilter.resetFilter = function () { + $('#tbody').show(); + $('#tbody_filtered').hide(); + $filterInput.val(''); + }; - var scrollUp = function(element){ - if (element.offset().top < $(window).scrollTop()) { - $('html,body').scrollTop(element.offset().top); - return false; - } - return true; - }; + NodeFilter.handleKey = function (e) { + var scrollDown = function (element) { + var elementBottom = element.offset().top + $(element).outerHeight(); + var windowBottom = window.innerHeight + $(window).scrollTop(); + if (elementBottom > windowBottom) { + var offset = elementBottom - window.innerHeight; + $('html,body').scrollTop(offset); + return false; + } + return true; + }; - $('#filter_activate').click(function() { - _NODEFILTER.initFilter(); - }); + var scrollUp = function (element) { + if (element.offset().top < $(window).scrollTop()) { + $('html,body').scrollTop(element.offset().top); + return false; + } + return true; + }; + var $hlElem = $('.browser-highlight'); - $('#filter_deactivate').click(function() { - _NODEFILTER.resetFilter(); - }); + if (e.keyCode === 40) { // Down + if ($hlElem.length === 0) { + $('.browser-result').first().addClass('browser-highlight'); + } else { + var next = $hlElem.next(); + if (next.length !== 0) { + $hlElem.removeClass('browser-highlight'); + next.addClass('browser-highlight'); + } + } - $(n_filter).click(function() { - if ($('#node_filter').hasClass('init')){ - n_filter.value = ''; - $('#node_filter').removeClass('init'); - } - }); - - $(n_filter).keydown(function(e) { - if (e.keyCode === 40){ // Down - if ($('.browser-highlight').length === 0){ - $('.browser-result').first().addClass('browser-highlight'); - } else { - var next = $('.browser-highlight').next(); - if (next.length !== 0) { - $('.browser-highlight').removeClass('browser-highlight'); - next.addClass('browser-highlight'); + if ($hlElem.get(0) !== undefined){ + scrollDown($hlElem); + } } - } - scrollDown($('.browser-highlight')); - } - if (e.keyCode === 38){ // Up - e.preventDefault(); - if ($('.browser-highlight').length !== 0){ - var next = $('.browser-highlight').prev(); - if (next.length !== 0) { - $('.browser-highlight').removeClass('browser-highlight'); - next.addClass('browser-highlight'); + if (e.keyCode === 38) { // Up + e.preventDefault(); + if ($hlElem.length !== 0) { + var next = $hlElem.prev(); + if (next.length !== 0) { + $('.browser-highlight').removeClass('browser-highlight'); + next.addClass('browser-highlight'); + } + } + + if ($hlElem.get(0) !== undefined){ + scrollUp($hlElem); + } + } - } - scrollUp($('.browser-highlight')); - } - if (e.keyCode === 13){ // Enter - if ($('.browser-highlight').length !== 0){ - var url = $('.browser-highlight').find('.match-link').attr('href'); - window.location = url; - } - } - if (e.keyCode === 27){ // Esc - _NODEFILTER.resetFilter(); - $('html,body').scrollTop(0); - } - }); - var capture_keys = [40, 38, 39, 37, 13, 27]; - $(n_filter).keyup(function(e) { - if ($.inArray(e.keyCode, capture_keys) === -1){ - clearTimeout(_NODEFILTER.filterTimeout); - _NODEFILTER.filterTimeout = setTimeout(_NODEFILTER.updateFilter(n_filter, e),200); - } - }); + if (e.keyCode === 13) { // Enter + if ($('.browser-highlight').length !== 0) { + var url = $('.browser-highlight').find('.match-link').attr('href'); + window.location = url; + } + } + if (e.keyCode === 27) { // Esc + NodeFilter.resetFilter(); + $('html,body').scrollTop(0); + } + + var capture_keys = [ + 40, // ArrowDown + 38, // ArrowUp + 39, // ArrowRight + 37, // ArrowLeft + 13, // Enter + 27 // Esc + ]; + + if ($.inArray(e.keyCode, capture_keys) === -1) { + clearTimeout(NodeFilter.filterTimeout); + NodeFilter.filterTimeout = setTimeout(NodeFilter.updateFilter(n_filter, e), 200); + } + + }; + + NodeFilter.fuzzy_match = function (filepath, query) { + var highlight = []; + var order = 0; + for (var i = 0; i < query.length; i++) { + var match_position = filepath.indexOf(query[i]); + if (match_position !== -1) { + var prev_match_position = highlight[highlight.length - 1]; + if (prev_match_position === undefined) { + highlight.push(match_position); + } else { + var current_match_position = prev_match_position + match_position + 1; + highlight.push(current_match_position); + order = order + current_match_position - prev_match_position; + } + filepath = filepath.substring(match_position + 1); + } else { + return false; + } + } + return { + 'order': order, + 'highlight': highlight + }; + }; + + NodeFilter.sortPredicate = function (a, b) { + if (a.order < b.order) return -1; + if (a.order > b.order) return 1; + if (a.filepath < b.filepath) return -1; + if (a.filepath > b.filepath) return 1; + return 0; + }; + + NodeFilter.updateFilter = function (elem, e) { + return function () { + // Reset timeout + NodeFilter.filterTimeout = null; + var query = elem.value.toLowerCase(); + var match = []; + var matches_max = 20; + if (query !== "") { + var results = []; + for (var k = 0; k < nodes.length; k++) { + var result = NodeFilter.fuzzy_match( + nodes[k].name.toLowerCase(), query); + if (result) { + result.type = nodes[k].type; + result.filepath = nodes[k].name; + results.push(result); + } + } + results = results.sort(NodeFilter.sortPredicate); + var limit = matches_max; + if (results.length < matches_max) { + limit = results.length; + } + for (var i = 0; i < limit; i++) { + if (query && results.length > 0) { + var n = results[i].filepath; + var t = results[i].type; + var n_hl = n.split(""); + var pos = results[i].highlight; + for (var j = 0; j < pos.length; j++) { + n_hl[pos[j]] = "" + n_hl[pos[j]] + ""; + } + n_hl = n_hl.join(""); + var new_url = url_base.replace('__FPATH__', n); + + var typeObj = { + dir: 'icon-directory browser-dir', + file: 'icon-file-text browser-file' + }; + + var typeIcon = ''.format(typeObj[t]); + match.push('{1}{2}'.format(new_url, typeIcon, n_hl)); + } + } + if (results.length > limit) { + var truncated_count = results.length - matches_max; + if (truncated_count === 1) { + match.push('{0} {1}'.format(truncated_count, _gettext('truncated result'))); + } else { + match.push('{0} {1}'.format(truncated_count, _gettext('truncated results'))); + } + } + } + if (query !== "") { + $('#tbody').hide(); + $('#tbody_filtered').show(); + + if (match.length === 0) { + match.push('{0}'.format(_gettext('No matching files'))); + } + $('#tbody_filtered').html(match.join("")); + } else { + $('#tbody').show(); + $('#tbody_filtered').hide(); + } + + }; + }; + }; var getIdentNode = function(n){ diff --git a/rhodecode/templates/files/files.mako b/rhodecode/templates/files/files.mako index bde2c26a..3d1960ea 100644 --- a/rhodecode/templates/files/files.mako +++ b/rhodecode/templates/files/files.mako @@ -383,7 +383,8 @@ callbacks(); var search_GET = "${request.GET.get('search','')}"; if (search_GET === "1") { - _NODEFILTER.initFilter(); + NodeFilter.initFilter(); + NodeFilter.focus(); } }); diff --git a/rhodecode/templates/files/files_browser.mako b/rhodecode/templates/files/files_browser.mako index eb3adf0b..5b97c284 100644 --- a/rhodecode/templates/files/files_browser.mako +++ b/rhodecode/templates/files/files_browser.mako @@ -3,25 +3,37 @@
+
+ +
    + +
  • + + ${h.get_last_path_part(c.file)} + +
  • + +
  • + +
  • + +
+ +
+
${h.hidden('refs_filter')}
- - % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name): % endif +
-
## file tree is computed from caches, and filled in