This library gives you the tools you need to mark and highlight text according to one or multiple search terms. You can use the defaults or configure the search with options.
mark : String -> String -> List (Html msg)
Highlight search terms within text.
import String.Mark as Mark
main =
Html.p [] <| Mark.mark "ness" "Tennessee"
-- will render <p>Ten<mark>ness</mark>ee</p>
mark
uses sensible defaults. Check out
what they are in detail here.
It is simply defined as:
mark : String -> String -> List (Html msg)
mark =
markWith defaultOptions
If you need more flexibility, use markWith
for custom options.
markWith : Options a -> String -> String -> List a
Customize how marking works. Check out the options
for what can be configured.
import String.Mark as Mark exposing (defaultOptions, normalSearch, matchCase)
-- for example make searching case sensitive
let
options = { defaultOptions | searchType = normalSearch matchCase }
in p [] <| Mark.markWith options "iss" "MissISSippi"
-- will render <p>M<mark>iss</mark>ISSippi</p>
{ searchType : SearchType
, whitespace : Whitespace
, minTermLength : Basics.Int
, mapHit : String -> a
, mapMiss : String -> a
}
The options you have for configuring the search behavior.
searchType
is explained here and whitespace
is explained here.
minTermLength
sets a threshold at which search is performed. As your typing
you may not want to show hits for 1 or 2 letters so the default is 3, but you
can set it to whatever you want.
You want to mark your hits and misses somehow. mapHit
and mapMiss
let you
do just that. By default misses are plain text and hits will be put into
<mark>
tags. Customize it, if you want to.
defaultOptions : Options (Html msg)
The options used for mark
. The defaults should
work for most simple use cases. If you only want to slightly
tweak these options, you can use them with the record update syntax. The default values
are the following:
defaultOptions : Options (Html msg)
defaultOptions =
{ searchType = normalSearch ignoreCase
, whitespace = singleWord
, minTermLength = 3
, mapHit = \hit -> Html.mark [] [ Html.text hit ]
, mapMiss = Html.text
}
This means that search will ignore case, the search term will be treated as
a single word (including whitespace) and no matches will be generated if the
search term is under three characters. Also, hits will be transformed into
into <mark>
tags misses into plain HTML text.
Which search type are you using? Pick between ease of use and custom
flexibility. You probably wanna start with normalSearch
.
normalSearch : Case -> SearchType
Normal search is the easiest to start with. You can configure case
sensitivity. If you need lots of flexibility, use customSearch
.
customSearch : (String -> String -> List ( Basics.Int, Basics.Int )) -> SearchType
Custom search will let you pass your own searching logic. Check first if the provided options for case sensitivity, minimum search term length and single/multi line search are enough for you. But maybe you need glob search, or quoting like Google has, etc. If so, you can provide a function, which gets the search term and the text to search as arguments. Your function needs to return a list of index pairs where each marks the start and end index of a match. You need to make sure the returned indexes are sane. Sane in this case means the index pairs are ...
sorted ascendingly: Meaning for every index pair, the end index is always smaller than the start index of the next pair.
For example: [(3, 4), (0, 2)]
is not sorted, [(0, 2), (3, 4)]
is sorted.
You can verify
non-overlapping: The ranges expressed by the pairs don't overlap.
For example: [(1, 3), (2, 4)]
overlap at 2-3, [(1, 3), (5, 6)]
don't.
You can use funtions like String.indexes
, Regex.find
or all the good stuff
in elm/parser
for your implementation. You can find an example for a basic
glob search in the tests for this package.
Hints for usage with Whitespace
Say your search term is "typed functional programming"
. When using
singleWord
your custom function is called once and passed the
entire search term "typed functional programming"
. However, when using
multiWord
your custom search function is called 3 times:
With "typed"
, "functional"
and "programming
" as search terms respectively.
The results will be combined. When using multiWord
the result
will be sorted and filtered for overlaps automatically.
Match or ignore case. Use with normalSearch
.
ignoreCase : Case
Search will ignore case (case insensitive).
matchCase : Case
Search will match case (case sensitive).
This option lets you configure how whitespace in search terms is treated. In some cases you may want to search for the string "functional programming" and want results to have both of those words in them, in that order. Other times you may wanna search for "Leonardo Raphael Donatello" and search for occurances of either one of those.
singleWord : Whitespace
Will treat the search term as ONE. This means "Peter Parker" will match occurances of "Peter Parker" or "peter parker" in the content(depending on your case settings). You can also search for whole sentences with this option, like "To infinity and beyond" and the entire sentence will be marked as a hit if it occurs in the text you're searching.
multiWord : Whitespace
Will treat the searchterm as MULTIPLE. This means "Peter Parker" would be split into the words "Peter" and "Parker". This will run a search for each word in your search term separately. If hits are overlapping then the one that starts later in the text will be ignored and not marked.