Skip to content

Hits โ€‹

TIP

Prefer the table-based configuration for managing search form fields.
It centralizes settings and uses the same underlying functions as manual methods.

โš ๏ธ The table-based method may not cover all cases. For advanced customizations, override with dedicated functions as needed.

hits table

Context โ€‹

Set concordance size (concordanceSize) โ€‹

To show more or less of the surrounding document when a hit is expanded.

js
vuexModules.ui.actions.results.shared.concordanceSize(10)

concordance size 10

Set Annotation (concordanceAnnotationId) โ€‹

You can use a different Annotation for searching and displaying, e.g. search for lemmata but show the original text in the results (or even show markup using concordanceAsHtml).

js
vuexModules.ui.actions.results.shared.concordanceAnnotationId('word');

word

Allow users to choose the annotation โ€‹

You can allow users to switch the annotation used for concordances in the hits table. This is useful if you have multiple annotations and want to let users choose which one to display. E.g. one with markup and one without

js
vuexModules.ui.actions.results.shared.concordanceAnnotationIdOptions(['word', 'lemma']);

HTML and markup in Concordances (concordanceAsHtml) โ€‹

You can display concordances (the hit and its context) as HTML in the results table. This is useful if you have indexed snippets of raw XML from your documents (for example, using BlackLab's captureXml mode) and want to render them with custom styling.

js
vuexModules.ui.actions.results.shared.concordanceAsHtml(true)

Example โ€‹

Combined with BlackLab's captureXml mode, you can index raw XML from your documents into an annotation (e.g., word_xml). By enabling concordanceAsHtml, the frontend will render the annotation as HTML in the hits table, allowing you to style it with custom CSS.

xml
<w>
  en<strikethrough>de</strikethrough>
</w>
yaml
- name: word_xml
  valuePath: //w
  captureXml: true
ts
vuexModules.ui.actions.results.shared.concordanceAnnotationId('word_xml')
vuexModules.ui.actions.results.shared.concordanceAsHtml(true)
css
strikethrough {
  text-decoration: line-through;
}

Will result in the following html

ende


Browser support for non-HTML elements is good, so arbitrary XML should work out of the box, as long as it is well-formed.

WARNING

USE THIS FEATURE WITH CARE! It may break your page if the XML contains unexpected or malformed contents.

Columns and Rows โ€‹

By default, up to 3 extra columns (besides the main annotation) are shown. lemma and pos have hardcoded priority, and will show up first if they exist. Remaining spots are filled up in the order you declared your annotations in the .blf.yaml.

js
// Replace with the annotation IDs you want to display.
vuexModules.ui.actions.results.hits.shownAnnotationIds(['lemma', 'pos', 'your_annotation']);

Custom column โ€‹

You can also add a column with custom content, the content can be computed from a function. example of custom hit info column

js
frontend.customize(corpus => {
  // Enable the column
  corpus.results.hasCustomHitInfoColumn = (results, isParallelCorpus) => {
    return true; // Always show the custom column
  };

  // Provide content for the column
  corpus.results.customHitInfo = (hit, annotatedFieldDisplayName, docInfo) => {
    // Example: Show the document title
    return `${docInfo.title}`;
  };
})
ts
/** Should the custom hit info column be shown for this result set?
 *
 * If true, uses the customHitInfo function to determine what to show.
 */
hasCustomHitInfoColumn: (results: BLTypes.BLHitResults|BLTypes.BLHitGroupResults, isParallelCorpus: boolean): boolean => {
	return isParallelCorpus;
},

/**
 * Determine custom hit info for this hit.
 *
 * Shows some custom text (with doc link) left of the hit.
 *
 * Default shows versionPrefix if it's set (i.e. if it's a parallel corpus).
 * Otherwise, nothing extra is shown.
 * @param hit the hit
 * @param annotatedFieldDisplayName the name of the field the hit is in. This is already translated to the user's locale.
 *  In the case of non-parallel corpora, this will always be the main annotated field.
 * @param docInfo document metadata
 */
customHitInfo: (
		hit: BLTypes.BLHit|BLTypes.BLHitSnippet|BLTypes.BLHitInOtherField,
		annotatedFieldDisplayName: string|null,
		docInfo: BLTypes.BLDoc): string|null => {
	return annotatedFieldDisplayName;
}

Expanded Hit Details โ€‹

Annotations in Expanded View (detailedAnnotationIds) โ€‹

Control which annotations are shown in the expanded hit details and in CSV exports:

js
vuexModules.ui.actions.results.shared.detailedAnnotationIds(['word', 'lemma', 'pos_full', 'phonetic']);

Dependency Tree in Expanded View (dependencies) โ€‹

If your corpus has dependency relations, you can configure which annotations are used in the dependency tree shown in hit details. We will try to show all dependencies in the sentence, or shown the explicitly searched dependencies.

dependency tree

Highlighting Concordances โ€‹

Marking parts of your query will highlight the corresponding parts in the hits table. This is useful to visually distinguish different parts of your query, such as the main search term and any modifiers.

We will highlight marked parts of the query, or alternatively, any matched relations when using a relation query.

TIP

See the BlackLab docs on relations for more information on how to use relations in your data and queries.

a:_ --> b:"koe"
i.e. "anything" as parent of "koe" (cow) in the dependency tree. dependency higlighting

You can configure how and what to highlight, if the defauls are not to your liking.

js
/** 
 * @param {HighlightSection} matchInfo
 * @returns {'hover' | 'static' | 'none' | null}
 */
corpus.results.matchInfoHighlightStyle = function (matchInfo) {
  if (matchInfo.isRelation) {
    // Show hover highlight for words
    if (matchInfo.relType === 'word-alignment')
      return 'hover';
    // Don't show other relations
    return 'none';
  }
  // Always highlight any named entities captured by our query
  // (e.g. <named-entity/> containing "dog")
  if (matchInfo.key === 'named-entity')
    return 'static';

  // Default highlighting behaviour
  // ("highlight non-relations if there's explicit captures in the query")
  return null;
};
ts
/** Part of a hit/context to highlight, with a label, display and boolean whether it's a relation or a section of the query/result labelled by the user. */
export type HighlightSection = {
	/** -1 for root */
	sourceStart: number;
	/** -1 for root */
	sourceEnd: number;
	targetStart: number;
	targetEnd: number;
	targetField?: string;

	/** True if this is a relation, false if this is a capture group */
	isRelation: boolean;

	/** Should this be permanently higlighted? (if not, may still be hoverable if this is a parallel corpus) */
	showHighlight: boolean;

	/**
	 * Key of this info as reported by BlackLab.
	 * E.g. for a query "_ -obj-> _" this would be "obj".
	 * For an anonymous relation e.g. _ --> _ this would be something like "dep1" or "rel1"
	 * For a capture group, e.g. "a:[] b:[]" this would be the name of the capture group, "a" or "b".
	 *
	 * Can be used for e.g. grouping results (and we do use this, mind when refactoring.)
	 */
	key: string;

	/** Display string, key if !isRelation, relation value + arrow if isRelation == true */
	display: string;
}

Addons โ€‹

You can inject custom content (e.g., audio players, buttons, extra info) into the expanded hit details using the addons array.

Example Addon: Add an audio player to hit details โ€‹

example of an audio button

Utils โ€‹

Transform Snippets (transformSnippets) โ€‹

Use to replace words, add warnings, or correct data after the fact (e.g. escape sequences), or to do markup in combination with concordanceAsHtml.

ts

/** E.g. {word: ['words', 'in', 'the', 'hit'], lemma: [...], pos: [...]} */
type SnippetPart = Record<string, string[]>;

interface Snippet {
  before: SnippetPart;
  match: SnippetPart;
  after: SnippetPart;
  // There might be more properties! beware of that.
}

type TransformFunction = (snippet: Snippet) => void;

Totals Counter Polling โ€‹

Control how long and how often the totals counter (spinner) refreshes while waiting for results: After the timeout, the user will have to manually start the counter again.

js
vuexModules.ui.actions.results.shared.totalsTimeoutDurationMs(90000); // 90 seconds
vuexModules.ui.actions.results.shared.totalsRefreshIntervalMs(2000);  // 2 seconds

Apache license 2.0