gitlab-org--gitlab-foss/app/assets/javascripts/project_find_file.js

185 lines
5.3 KiB
JavaScript
Raw Normal View History

/* eslint-disable func-names, no-var, consistent-return, one-var, no-cond-assign, no-return-assign */
import $ from 'jquery';
import fuzzaldrinPlus from 'fuzzaldrin-plus';
2018-01-31 22:27:03 +00:00
import axios from '~/lib/utils/axios_utils';
import flash from '~/flash';
import { __ } from '~/locale';
2019-09-27 20:59:41 +00:00
import sanitize from 'sanitize-html';
2017-12-13 09:26:44 +00:00
// highlight text(awefwbwgtc -> <b>a</b>wefw<b>b</b>wgt<b>c</b> )
const highlighter = function(element, text, matches) {
var j, lastIndex, len, matchIndex, matchedChars, unmatched;
2017-12-13 09:26:44 +00:00
lastIndex = 0;
matchedChars = [];
for (j = 0, len = matches.length; j < len; j += 1) {
matchIndex = matches[j];
unmatched = text.substring(lastIndex, matchIndex);
if (unmatched) {
if (matchedChars.length) {
element.append(matchedChars.join('').bold());
2017-12-13 09:26:44 +00:00
}
matchedChars = [];
element.append(document.createTextNode(unmatched));
2016-07-24 20:45:11 +00:00
}
2017-12-13 09:26:44 +00:00
matchedChars.push(text[matchIndex]);
lastIndex = matchIndex + 1;
}
if (matchedChars.length) {
element.append(matchedChars.join('').bold());
2017-12-13 09:26:44 +00:00
}
return element.append(document.createTextNode(text.substring(lastIndex)));
};
export default class ProjectFindFile {
constructor(element1, options) {
this.element = element1;
this.options = options;
this.goToBlob = this.goToBlob.bind(this);
this.goToTree = this.goToTree.bind(this);
this.selectRowDown = this.selectRowDown.bind(this);
this.selectRowUp = this.selectRowUp.bind(this);
this.filePaths = {};
this.inputElement = this.element.find('.file-finder-input');
2017-12-13 09:26:44 +00:00
// init event
this.initEvent();
// focus text input box
this.inputElement.focus();
// load file list
this.load(this.options.url);
}
initEvent() {
this.inputElement.off('keyup');
this.inputElement.on(
'keyup',
(function(_this) {
return function(event) {
var oldValue, ref, target, value;
target = $(event.target);
value = target.val();
oldValue = (ref = target.data('oldValue')) != null ? ref : '';
if (value !== oldValue) {
target.data('oldValue', value);
_this.findFile();
return _this.element
.find('tr.tree-item')
.eq(0)
.addClass('selected')
.focus();
}
};
})(this),
);
2017-12-13 09:26:44 +00:00
}
findFile() {
var result, searchText;
2019-09-27 20:59:41 +00:00
searchText = sanitize(this.inputElement.val());
result =
searchText.length > 0 ? fuzzaldrinPlus.filter(this.filePaths, searchText) : this.filePaths;
2017-12-13 09:26:44 +00:00
return this.renderList(result, searchText);
// find file
2017-12-13 09:26:44 +00:00
}
2016-07-24 20:45:11 +00:00
// files paths load
2017-12-13 09:26:44 +00:00
load(url) {
axios
.get(url)
2018-01-31 22:27:03 +00:00
.then(({ data }) => {
this.element.find('.loading').hide();
this.filePaths = data;
this.findFile();
this.element
.find('.files-slider tr.tree-item')
.eq(0)
.addClass('selected')
.focus();
2018-01-31 22:27:03 +00:00
})
.catch(() => flash(__('An error occurred while loading filenames')));
2017-12-13 09:26:44 +00:00
}
2016-07-24 20:45:11 +00:00
// render result
2017-12-13 09:26:44 +00:00
renderList(filePaths, searchText) {
var blobItemUrl, filePath, html, i, len, matches, results;
this.element.find('.tree-table > tbody').empty();
2017-12-13 09:26:44 +00:00
results = [];
for (i = 0, len = filePaths.length; i < len; i += 1) {
2017-12-13 09:26:44 +00:00
filePath = filePaths[i];
if (i === 20) {
break;
2016-07-24 20:45:11 +00:00
}
2017-12-13 09:26:44 +00:00
if (searchText) {
matches = fuzzaldrinPlus.match(filePath, searchText);
2016-07-24 20:45:11 +00:00
}
blobItemUrl = `${this.options.blobUrlTemplate}/${encodeURIComponent(filePath)}`;
2017-12-13 09:26:44 +00:00
html = ProjectFindFile.makeHtml(filePath, matches, blobItemUrl);
results.push(this.element.find('.tree-table > tbody').append(html));
2017-12-13 09:26:44 +00:00
}
this.element.find('.empty-state').toggleClass('hidden', Boolean(results.length));
2017-12-13 09:26:44 +00:00
return results;
}
// make tbody row html
static makeHtml(filePath, matches, blobItemUrl) {
var $tr;
$tr = $(
"<tr class='tree-item'><td class='tree-item-file-name link-container'><a><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'></span></a></td></tr>",
);
2017-12-13 09:26:44 +00:00
if (matches) {
$tr
.find('a')
.replaceWith(highlighter($tr.find('a'), filePath, matches).attr('href', blobItemUrl));
2017-12-13 09:26:44 +00:00
} else {
$tr.find('a').attr('href', blobItemUrl);
$tr.find('.str-truncated').text(filePath);
2017-12-13 09:26:44 +00:00
}
return $tr;
}
selectRow(type) {
var next, rows, selectedRow;
rows = this.element.find('.files-slider tr.tree-item');
selectedRow = this.element.find('.files-slider tr.tree-item.selected');
2017-12-13 09:26:44 +00:00
if (rows && rows.length > 0) {
if (selectedRow && selectedRow.length > 0) {
if (type === 'UP') {
2017-12-13 09:26:44 +00:00
next = selectedRow.prev();
} else if (type === 'DOWN') {
2017-12-13 09:26:44 +00:00
next = selectedRow.next();
}
if (next.length > 0) {
selectedRow.removeClass('selected');
2017-12-13 09:26:44 +00:00
selectedRow = next;
2016-07-24 20:45:11 +00:00
}
2017-12-13 09:26:44 +00:00
} else {
selectedRow = rows.eq(0);
2016-07-24 20:45:11 +00:00
}
return selectedRow.addClass('selected').focus();
2017-12-13 09:26:44 +00:00
}
}
2016-07-24 20:45:11 +00:00
2017-12-13 09:26:44 +00:00
selectRowUp() {
return this.selectRow('UP');
2017-12-13 09:26:44 +00:00
}
2016-07-24 20:45:11 +00:00
2017-12-13 09:26:44 +00:00
selectRowDown() {
return this.selectRow('DOWN');
2017-12-13 09:26:44 +00:00
}
2016-07-24 20:45:11 +00:00
2017-12-13 09:26:44 +00:00
goToTree() {
return (window.location.href = this.options.treeUrl);
2017-12-13 09:26:44 +00:00
}
2017-12-13 09:26:44 +00:00
goToBlob() {
var $link = this.element.find('.tree-item.selected .tree-item-file-name a');
2017-12-13 09:26:44 +00:00
if ($link.length) {
$link.get(0).click();
}
}
}