chrome-devtools-frontend
Version:
Chrome DevTools UI
284 lines (254 loc) • 8.69 kB
JavaScript
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Common from '../common/common.js'; // eslint-disable-line no-unused-vars
import * as i18n from '../i18n/i18n.js';
import * as Persistence from '../persistence/persistence.js';
import * as QuickOpen from '../quick_open/quick_open.js';
import * as UI from '../ui/ui.js';
import * as Workspace from '../workspace/workspace.js';
import {FilePathScoreFunction} from './FilePathScoreFunction.js';
export const UIStrings = {
/**
*@description Text in Filtered UISource Code List Provider of the Sources panel
*/
noFilesFound: 'No files found',
};
const str_ = i18n.i18n.registerUIStrings('sources/FilteredUISourceCodeListProvider.js', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
export class FilteredUISourceCodeListProvider extends QuickOpen.FilteredListWidget.Provider {
constructor() {
super();
this._queryLineNumberAndColumnNumber = '';
this._defaultScores = null;
this._scorer = new FilePathScoreFunction('');
/** @type {!Array<!Workspace.UISourceCode.UISourceCode>} */
this._uiSourceCodes = [];
/** @type {!Set<string>} */
this._uiSourceCodeUrls = new Set();
/** @type {string} */
this._query;
}
/**
* @param {!Common.EventTarget.EventTargetEvent} event
*/
_projectRemoved(event) {
const project = /** @type {!Workspace.Workspace.Project} */ (event.data);
this._populate(project);
this.refresh();
}
/**
* @param {!Workspace.Workspace.Project=} skipProject
*/
_populate(skipProject) {
this._uiSourceCodes = [];
this._uiSourceCodeUrls.clear();
for (const project of Workspace.Workspace.WorkspaceImpl.instance().projects()) {
if (project !== skipProject && this.filterProject(project)) {
for (const uiSourceCode of project.uiSourceCodes()) {
if (this._filterUISourceCode(uiSourceCode)) {
this._uiSourceCodes.push(uiSourceCode);
this._uiSourceCodeUrls.add(uiSourceCode.url());
}
}
}
}
}
/**
* @param {!Workspace.UISourceCode.UISourceCode} uiSourceCode
* @return {boolean}
*/
_filterUISourceCode(uiSourceCode) {
if (this._uiSourceCodeUrls.has(uiSourceCode.url())) {
return false;
}
const binding = Persistence.Persistence.PersistenceImpl.instance().binding(uiSourceCode);
return !binding || binding.fileSystem === uiSourceCode;
}
/**
* @param {?Workspace.UISourceCode.UISourceCode} uiSourceCode
* @param {number=} lineNumber
* @param {number=} columnNumber
*/
uiSourceCodeSelected(uiSourceCode, lineNumber, columnNumber) {
// Overridden by subclasses
}
/**
* @param {!Workspace.Workspace.Project} project
* @return {boolean}
*/
filterProject(project) {
return true;
// Overridden by subclasses
}
/**
* @override
* @return {number}
*/
itemCount() {
return this._uiSourceCodes.length;
}
/**
* @override
* @param {number} itemIndex
* @return {string}
*/
itemKeyAt(itemIndex) {
return this._uiSourceCodes[itemIndex].url();
}
/**
* @protected
* @param {?Map.<!Workspace.UISourceCode.UISourceCode, number>} defaultScores
*/
setDefaultScores(defaultScores) {
this._defaultScores = defaultScores;
}
/**
* @override
* @param {number} itemIndex
* @param {string} query
* @return {number}
*/
itemScoreAt(itemIndex, query) {
const uiSourceCode = this._uiSourceCodes[itemIndex];
const score = this._defaultScores ? (this._defaultScores.get(uiSourceCode) || 0) : 0;
if (!query || query.length < 2) {
return score;
}
if (this._query !== query) {
this._query = query;
this._scorer = new FilePathScoreFunction(query);
}
let multiplier = 10;
if (uiSourceCode.project().type() === Workspace.Workspace.projectTypes.FileSystem &&
!Persistence.Persistence.PersistenceImpl.instance().binding(uiSourceCode)) {
multiplier = 5;
}
const fullDisplayName = uiSourceCode.fullDisplayName();
return score + multiplier * this._scorer.score(fullDisplayName, null);
}
/**
* @override
* @param {number} itemIndex
* @param {string} query
* @param {!Element} titleElement
* @param {!Element} subtitleElement
*/
renderItem(itemIndex, query, titleElement, subtitleElement) {
query = this.rewriteQuery(query);
const uiSourceCode = this._uiSourceCodes[itemIndex];
const fullDisplayName = uiSourceCode.fullDisplayName();
/** @type {!Array<number>} */
const indexes = [];
new FilePathScoreFunction(query).score(fullDisplayName, indexes);
const fileNameIndex = fullDisplayName.lastIndexOf('/');
titleElement.classList.add('monospace');
subtitleElement.classList.add('monospace');
titleElement.textContent = uiSourceCode.displayName() + (this._queryLineNumberAndColumnNumber || '');
this._renderSubtitleElement(subtitleElement, fullDisplayName);
/** @type {!HTMLElement} */ UI.Tooltip.Tooltip.install((subtitleElement), fullDisplayName);
const ranges = [];
for (let i = 0; i < indexes.length; ++i) {
ranges.push({offset: indexes[i], length: 1});
}
if (indexes[0] > fileNameIndex) {
for (let i = 0; i < ranges.length; ++i) {
ranges[i].offset -= fileNameIndex + 1;
}
UI.UIUtils.highlightRangesWithStyleClass(titleElement, ranges, 'highlight');
} else {
UI.UIUtils.highlightRangesWithStyleClass(subtitleElement, ranges, 'highlight');
}
}
/**
* @param {!Element} element
* @param {string} text
*/
_renderSubtitleElement(element, text) {
element.removeChildren();
let splitPosition = text.lastIndexOf('/');
if (text.length > 55) {
splitPosition = text.length - 55;
}
const first = element.createChild('div', 'first-part');
first.textContent = text.substring(0, splitPosition);
const second = element.createChild('div', 'second-part');
second.textContent = text.substring(splitPosition);
/** @type {!HTMLElement} */ UI.Tooltip.Tooltip.install((element), text);
}
/**
* @override
* @param {?number} itemIndex
* @param {string} promptValue
*/
selectItem(itemIndex, promptValue) {
const parsedExpression = promptValue.trim().match(/^([^:]*)(:\d+)?(:\d+)?$/);
if (!parsedExpression) {
return;
}
let lineNumber;
let columnNumber;
if (parsedExpression[2]) {
lineNumber = parseInt(parsedExpression[2].substr(1), 10) - 1;
}
if (parsedExpression[3]) {
columnNumber = parseInt(parsedExpression[3].substr(1), 10) - 1;
}
const uiSourceCode = itemIndex !== null ? this._uiSourceCodes[itemIndex] : null;
this.uiSourceCodeSelected(uiSourceCode, lineNumber, columnNumber);
}
/**
* @override
* @param {string} query
* @return {string}
*/
rewriteQuery(query) {
query = query ? query.trim() : '';
if (!query || query === ':') {
return '';
}
const lineNumberMatch = query.match(/^([^:]+)((?::[^:]*){0,2})$/);
this._queryLineNumberAndColumnNumber = lineNumberMatch ? lineNumberMatch[2] : '';
return lineNumberMatch ? lineNumberMatch[1] : query;
}
/**
* @param {!Common.EventTarget.EventTargetEvent} event
*/
_uiSourceCodeAdded(event) {
const uiSourceCode = /** @type {!Workspace.UISourceCode.UISourceCode} */ (event.data);
if (!this._filterUISourceCode(uiSourceCode) || !this.filterProject(uiSourceCode.project())) {
return;
}
this._uiSourceCodes.push(uiSourceCode);
this._uiSourceCodeUrls.add(uiSourceCode.url());
this.refresh();
}
/**
* @override
* @return {string}
*/
notFoundText() {
return i18nString(UIStrings.noFilesFound);
}
/**
* @override
*/
attach() {
Workspace.Workspace.WorkspaceImpl.instance().addEventListener(
Workspace.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this);
Workspace.Workspace.WorkspaceImpl.instance().addEventListener(
Workspace.Workspace.Events.ProjectRemoved, this._projectRemoved, this);
this._populate();
}
/**
* @override
*/
detach() {
Workspace.Workspace.WorkspaceImpl.instance().removeEventListener(
Workspace.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this);
Workspace.Workspace.WorkspaceImpl.instance().removeEventListener(
Workspace.Workspace.Events.ProjectRemoved, this._projectRemoved, this);
this._queryLineNumberAndColumnNumber = '';
this._defaultScores = null;
}
}