github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ui/src/util/highlightedText.tsx (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  import React from "react";
    12  
    13  export default function getHighlightedText(text: string, highlight: string, isOriginalText?: boolean) {
    14    if (!highlight || highlight.length === 0) {
    15      return text;
    16    }
    17    highlight = highlight.replace(/[°§%()\[\]{}\\?´`'#|;:+-]+/g, "highlightNotDefined");
    18    const search = highlight.split(" ").map(val => {
    19      if (val.length > 0) {
    20        return val.toLowerCase();
    21      }
    22      return "highlightNotDefined";
    23    }).join("|");
    24    const parts = isOriginalText ? text.split(new RegExp(`(${search})`, "gi")) : rebaseText(text, highlight).split(new RegExp(`(${search})`, "gi"));
    25    return parts.map((part, i) => {
    26      if (search.includes(part.toLowerCase())) {
    27        return (
    28          <span key={i} className="_text-bold">
    29            {`${part}`}
    30          </span>
    31        );
    32      } else {
    33        return `${part}`;
    34      }
    35    });
    36  }
    37  
    38  function rebaseText(text: string, highlight: string) {
    39    const search = highlight.split(" ");
    40    const maxLength = 425;
    41    const defaultCropLength = 150;
    42    const defaultBeforeAfterCrop = 20;
    43    const isTextIncludesInTheRange425 = isStringIncludesArrayElement(search, text.slice(0, maxLength));
    44    if (!isTextIncludesInTheRange425) {
    45      let newText = text.slice(0, defaultCropLength) + "...";
    46      let currentPosition = defaultCropLength;
    47      search.forEach(value => {
    48        const wordPosition = getWordAt(value, text);
    49        const isPositionMoreCurrent = wordPosition - defaultBeforeAfterCrop > currentPosition;
    50        const isPositionMoreCurrentCrop = isPositionMoreCurrent ? wordPosition - defaultBeforeAfterCrop : wordPosition;
    51        currentPosition = currentPosition + value.length + (isPositionMoreCurrent ? (defaultBeforeAfterCrop * 2) : defaultBeforeAfterCrop);
    52        newText = `${newText} ${text.slice(isPositionMoreCurrentCrop, wordPosition + (defaultBeforeAfterCrop + value.length))}...`;
    53      });
    54      return newText.length < maxLength ? `${newText} ${text.slice(currentPosition, maxLength)}` : newText.slice(0, maxLength);
    55    }
    56    return text.length > maxLength ? `${text.slice(0, maxLength)}...` : text;
    57  }
    58  
    59  export function isStringIncludesArrayElement(arr: string[], text: string) {
    60    let includes = false;
    61    arr.forEach(val => {
    62      if (text.toLowerCase().includes(val.toLowerCase())) {
    63        includes = true;
    64      }
    65    });
    66    return includes;
    67  }
    68  
    69  export function getWordAt(word: string, text: string) {
    70    const regex = new RegExp("\\b" + word.toLowerCase() + "\\b");
    71    return text.toLowerCase().search(regex);
    72  }