Skip to content

Commit

Permalink
feat(search): integrate with unified search
Browse files Browse the repository at this point in the history
This ensures we build upon the new search abstraction, built via bpmn-io/diagram-js#916.
  • Loading branch information
nikku committed Sep 13, 2024
1 parent ee1370e commit 7c7ae48
Showing 1 changed file with 50 additions and 149 deletions.
199 changes: 50 additions & 149 deletions lib/features/search/BpmnSearchProvider.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { omit } from 'min-dash';
import { map } from 'min-dash';

import {
getLabel,
Expand All @@ -11,7 +11,11 @@ import {
* @typedef {import('diagram-js/lib/features/search-pad/SearchPad').default} SearchPad
*
* @typedef {import('diagram-js/lib/features/search-pad/SearchPadProvider').default} SearchPadProvider
* @typedef {import('diagram-js/lib/features/search-pad/SearchPadProvider').SearchResult} SearchResult
* @typedef {import('diagram-js/lib/features/search-pad/SearchPadProvider').SearchResult} SearchPadResult
* @typedef {import('diagram-js/lib/features/search-pad/SearchPadProvider').Token} SearchPadToken
* @typedef {import('diagram-js/lib/features/search/search').default} Search
* @typedef {import('diagram-js/lib/features/search/search').SearchResult} SearchResult
* @typedef {import('diagram-js/lib/features/search/search').Token} SearchToken
*/

/**
Expand All @@ -22,24 +26,27 @@ import {
* @param {ElementRegistry} elementRegistry
* @param {SearchPad} searchPad
* @param {Canvas} canvas
* @param {Search} search
*/
export default function BpmnSearchProvider(elementRegistry, searchPad, canvas) {
export default function BpmnSearchProvider(elementRegistry, searchPad, canvas, search) {
this._elementRegistry = elementRegistry;
this._canvas = canvas;
this._search = search;

searchPad.registerProvider(this);
}

BpmnSearchProvider.$inject = [
'elementRegistry',
'searchPad',
'canvas'
'canvas',
'search'
];

/**
* @param {string} pattern
*
* @return {SearchResult[]}
* @return {SearchPadResult[]}
*/
BpmnSearchProvider.prototype.find = function(pattern) {
var rootElements = this._canvas.getRootElements();
Expand All @@ -48,157 +55,51 @@ BpmnSearchProvider.prototype.find = function(pattern) {
return !isLabel(element) && !rootElements.includes(element);
});

return elements
.reduce(function(results, element) {
var label = getLabel(element);

var primaryTokens = findMatches(label, pattern),
secondaryTokens = findMatches(element.id, pattern);

if (hasMatch(primaryTokens) || hasMatch(secondaryTokens)) {
return [
...results,
{
primaryTokens,
secondaryTokens,
element
}
];
}

return results;
}, [])
.sort(function(a, b) {
return compareTokens(a.primaryTokens, b.primaryTokens)
|| compareTokens(a.secondaryTokens, b.secondaryTokens)
|| compareStrings(getLabel(a.element), getLabel(b.element))
|| compareStrings(a.element.id, b.element.id);
})
.map(function(result) {
return this._search(
elements.map(element => {
return {
element: result.element,
primaryTokens: result.primaryTokens.map(function(token) {
return omit(token, [ 'index' ]);
}),
secondaryTokens: result.secondaryTokens.map(function(token) {
return omit(token, [ 'index' ]);
})
element,
label: getLabel(element),
id: element.id
};
});
}),
pattern, {
keys: [
'label',
'id'
]
}
).map(toSearchPadResult);
};

/**
* @param {Token} token
*
* @return {boolean}
*/
function isMatch(token) {
return 'matched' in token;
}

/**
* @param {Token[]} tokens
*
* @return {boolean}
*/
function hasMatch(tokens) {
return tokens.find(isMatch);
}

/**
* Compares two token arrays.
*
* @param {Token[]} tokensA
* @param {Token[]} tokensB
*
* @returns {number}
*/
function compareTokens(tokensA, tokensB) {
const tokensAHasMatch = hasMatch(tokensA),
tokensBHasMatch = hasMatch(tokensB);

if (tokensAHasMatch && !tokensBHasMatch) {
return -1;
}

if (!tokensAHasMatch && tokensBHasMatch) {
return 1;
}

if (!tokensAHasMatch && !tokensBHasMatch) {
return 0;
}

const tokensAFirstMatch = tokensA.find(isMatch),
tokensBFirstMatch = tokensB.find(isMatch);

if (tokensAFirstMatch.index < tokensBFirstMatch.index) {
return -1;
}

if (tokensAFirstMatch.index > tokensBFirstMatch.index) {
return 1;
}

return 0;
}

/**
* Compares two strings.
*
* @param {string} a
* @param {string} b
*
* @returns {number}
*/
function compareStrings(a, b) {
return a.localeCompare(b);
}

/**
* @param {string} text
* @param {string} pattern
* @param {SearchResult} token
*
* @return {Token[]}
* @return {SearchPadResult}
*/
function findMatches(text, pattern) {
var tokens = [],
originalText = text;

if (!text) {
return tokens;
}

text = text.toLowerCase();
pattern = pattern.toLowerCase();

var index = text.indexOf(pattern);

if (index > -1) {
if (index !== 0) {
tokens.push({
normal: originalText.slice(0, index),
index: 0
});
}

tokens.push({
matched: originalText.slice(index, index + pattern.length),
index: index
});

if (pattern.length + index < text.length) {
tokens.push({
normal: originalText.slice(index + pattern.length),
index: index + pattern.length
});
}
} else {
tokens.push({
normal: originalText,
index: 0
});
function toSearchPadResult(result) {

/**
* @param {SearchToken} token
*
* @return {SearchPadToken}
*/
function toSearchPadToken(token) {
return {
[ token.match ? 'matched' : 'normal' ]: token.value
};
}

return tokens;
const {
item: {
element
},
tokens
} = result;

return {
element,
primaryTokens: map(tokens.label, toSearchPadToken),
secondaryTokens: map(tokens.id, toSearchPadToken)
};
}

0 comments on commit 7c7ae48

Please sign in to comment.