@ -2,75 +2,27 @@
@@ -2,75 +2,27 @@
requirejs . config ( {
paths : {
'minisearch' : 'https://cdn.jsdelivr.net/npm/minisearch@6.1.0/dist/umd/index.min' ,
'lodash' : 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min' ,
'jquery' : 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min' ,
'jquery' : 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.0/jquery.min' ,
}
} ) ;
////////////////////////////////////////////////////////////////////////////////
require ( [ 'jquery' , 'minisearch' , 'lodash' ] , function ( $ , minisearch , _ ) {
$ ( function ( ) {
// parseUri 1.2.2
// (c) Steven Levithan <stevenlevithan.com>
// MIT License
function parseUri ( str ) {
var o = parseUri . options ,
m = o . parser [ o . strictMode ? "strict" : "loose" ] . exec ( str ) ,
uri = { } ,
i = 14 ;
while ( i -- ) uri [ o . key [ i ] ] = m [ i ] || "" ;
uri [ o . q . name ] = { } ;
uri [ o . key [ 12 ] ] . replace ( o . q . parser , function ( $0 , $1 , $2 ) {
if ( $1 ) uri [ o . q . name ] [ $1 ] = $2 ;
} ) ;
require ( [ 'jquery' , 'minisearch' ] , function ( $ , minisearch ) {
return uri ;
}
parseUri . options = {
strictMode : false ,
key : [
"source" ,
"protocol" ,
"authority" ,
"userInfo" ,
"user" ,
"password" ,
"host" ,
"port" ,
"relative" ,
"path" ,
"directory" ,
"file" ,
"query" ,
"anchor" ,
] ,
q : {
name : "queryKey" ,
parser : /(?:^|&)([^&=]*)=?([^&]*)/g ,
} ,
parser : {
strict :
/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/ ,
loose :
/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ ,
} ,
} ;
// In general, most search related things will have "search" as a prefix.
// To get an in-depth about the thought process you can refer: https://hetarth02.hashnode.dev/series/gsoc
$ ( "#search-form" ) . submit ( function ( e ) {
e . preventDefault ( ) ;
} ) ;
let results = [ ] ;
let timer = undefined ;
let ms _ data = documenterSearchIndex [ "docs" ] . map ( ( x , key ) => {
x [ "id" ] = key ;
let data = documenterSearchIndex [ "docs" ] . map ( ( x , key ) => {
x [ "id" ] = key ; // minisearch requires a unique for each object
return x ;
} ) ;
} ) ;
// list below is the lunr 2.1.3 list minus the intersect with names(Base)
// (all, any, get, in, is, only, which) and (do, else, for, let, where, while, with)
// ideally we'd just filter the original list but it's not available as a variable
const stopWords = new Set ( [
// list below is the lunr 2.1.3 list minus the intersect with names(Base)
// (all, any, get, in, is, only, which) and (do, else, for, let, where, while, with)
// ideally we'd just filter the original list but it's not available as a variable
const stopWords = new Set ( [
"a" ,
"able" ,
"about" ,
@ -176,9 +128,9 @@ $(function () {
@@ -176,9 +128,9 @@ $(function () {
"yet" ,
"you" ,
"your" ,
] ) ;
] ) ;
let index = new minisearch ( {
let index = new minisearch ( {
fields : [ "title" , "text" ] , // fields to index for full-text search
storeFields : [ "location" , "title" , "text" , "category" , "page" ] , // fields to return with search results
processTerm : ( term ) => {
@ -194,6 +146,7 @@ $(function () {
@@ -194,6 +146,7 @@ $(function () {
} ,
// add . as a separator, because otherwise "title": "Documenter.Anchors.add!", would not find anything if searching for "add!", only for the entire qualification
tokenize : ( string ) => string . split ( /[\s\-\.]+/ ) ,
// options which will be applied during the search
searchOptions : {
boost : { title : 100 } ,
fuzzy : 2 ,
@ -209,31 +162,80 @@ $(function () {
@@ -209,31 +162,80 @@ $(function () {
} ,
tokenize : ( string ) => string . split ( /[\s\-\.]+/ ) ,
} ,
} ) ;
} ) ;
index . addAll ( data ) ;
let filters = [ ... new Set ( data . map ( ( x ) => x . category ) ) ] ;
var modal _filters = make _modal _body _filters ( filters ) ;
var filter _results = [ ] ;
$ ( document ) . on ( "keyup" , ".documenter-search-input" , function ( event ) {
// Adding a debounce to prevent disruptions from super-speed typing!
debounce ( ( ) => update _search ( filter _results ) , 300 ) ;
} ) ;
$ ( document ) . on ( "click" , ".search-filter" , function ( ) {
if ( $ ( this ) . hasClass ( "search-filter-selected" ) ) {
$ ( this ) . removeClass ( "search-filter-selected" ) ;
} else {
$ ( this ) . addClass ( "search-filter-selected" ) ;
}
index . addAll ( ms _data ) ;
// Adding a debounce to prevent disruptions from crazy clicking!
debounce ( ( ) => get _filters ( ) , 300 ) ;
} ) ;
/ * *
* A debounce function , takes a function and an optional timeout in milliseconds
*
* @ function callback
* @ param { number } timeout
* /
function debounce ( callback , timeout = 300 ) {
clearTimeout ( timer ) ;
timer = setTimeout ( callback , timeout ) ;
}
/ * *
* Make / Update the search component
*
* @ param { string [ ] } selected _filters
* /
function update _search ( selected _filters = [ ] ) {
let initial _search _body = `
< div class = "has-text-centered my-5 py-5" > Type something to get started ! < / d i v >
` ;
searchresults = $ ( "#documenter-search-results" ) ;
searchinfo = $ ( "#documenter-search-info" ) ;
searchbox = $ ( "#documenter-search-query" ) ;
searchform = $ ( ".docs-search" ) ;
sidebar = $ ( ".docs-sidebar" ) ;
let querystring = $ ( ".documenter-search-input" ) . val ( ) ;
function update _search ( querystring ) {
let results = [ ] ;
if ( querystring . trim ( ) ) {
results = index . search ( querystring , {
filter : ( result ) => result . score >= 1 ,
filter : ( result ) => {
// Filtering results
if ( selected _filters . length === 0 ) {
return result . score >= 1 ;
} else {
return (
result . score >= 1 && selected _filters . includes ( result . category )
) ;
}
} ,
} ) ;
searchresults . empty ( ) ;
let search _result _container = ` ` ;
let search _divider = ` <div class="search-divider w-100"></div> ` ;
if ( results . length ) {
let links = [ ] ;
let count = 0 ;
let search _results = "" ;
results . forEach ( function ( result ) {
if ( result . location ) {
// Checking for duplication of results for the same page
if ( ! links . includes ( result . location ) ) {
searchresults . append ( make _search _result ( result , querystring ) ) ;
search _results += make _search _result ( result , querystring ) ;
count ++ ;
}
@ -241,13 +243,91 @@ $(function () {
@@ -241,13 +243,91 @@ $(function () {
}
} ) ;
searchinfo . text ( "Number of results: " + count ) ;
let result _count = ` <div class="is-size-6"> ${ count } result(s)</div> ` ;
search _result _container = `
< div class = "is-flex is-flex-direction-column gap-2 is-align-items-flex-start" >
$ { modal _filters }
$ { search _divider }
$ { result _count }
< div class = "is-clipped w-100 is-flex is-flex-direction-column gap-2 is-align-items-flex-start has-text-justified mt-1" >
$ { search _results }
< / d i v >
< / d i v >
` ;
} else {
search _result _container = `
< div class = "is-flex is-flex-direction-column gap-2 is-align-items-flex-start" >
$ { modal _filters }
$ { search _divider }
< div class = "is-size-6" > 0 result ( s ) < / d i v >
< / d i v >
< div class = "has-text-centered my-5 py-5" > No result found ! < / d i v >
` ;
}
function make _search _result ( result , querystring ) {
if ( $ ( ".search-modal-card-body" ) . hasClass ( "is-justify-content-center" ) ) {
$ ( ".search-modal-card-body" ) . removeClass ( "is-justify-content-center" ) ;
}
$ ( ".search-modal-card-body" ) . html ( search _result _container ) ;
} else {
filter _results = [ ] ;
modal _filters = make _modal _body _filters ( filters , filter _results ) ;
if ( ! $ ( ".search-modal-card-body" ) . hasClass ( "is-justify-content-center" ) ) {
$ ( ".search-modal-card-body" ) . addClass ( "is-justify-content-center" ) ;
}
$ ( ".search-modal-card-body" ) . html ( initial _search _body ) ;
}
}
/ * *
* Make the modal filter html
*
* @ param { string [ ] } filters
* @ param { string [ ] } selected _filters
* @ returns string
* /
function make _modal _body _filters ( filters , selected _filters = [ ] ) {
let str = ` ` ;
filters . forEach ( ( val ) => {
if ( selected _filters . includes ( val ) ) {
str += ` <a href="javascript:;" class="search-filter search-filter-selected"><span> ${ val } </span></a> ` ;
} else {
str += ` <a href="javascript:;" class="search-filter"><span> ${ val } </span></a> ` ;
}
} ) ;
let filter _html = `
< div class = "is-flex gap-2 is-flex-wrap-wrap is-justify-content-flex-start is-align-items-center search-filters" >
< span class = "is-size-6" > Filters : < / s p a n >
$ { str }
< / d i v >
` ;
return filter _html ;
}
/ * *
* Make the result component given a minisearch result data object and the value of the search input as queryString .
* To view the result object structure , refer : https : //lucaong.github.io/minisearch/modules/_minisearch_.html#searchresult
*
* @ param { object } result
* @ param { string } querystring
* @ returns string
* /
function make _search _result ( result , querystring ) {
let search _divider = ` <div class="search-divider w-100"></div> ` ;
let display _link =
result . location . slice ( Math . max ( 0 ) , Math . min ( 50 , result . location . length ) ) +
( result . location . length > 30 ? "..." : "" ) ;
( result . location . length > 30 ? "..." : "" ) ; // To cut-off the link because it messes with the overflow of the whole div
if ( result . page !== "" ) {
display _link += ` ( ${ result . page } ) ` ;
}
let textindex = new RegExp ( ` \\ b ${ querystring } \\ b ` , "i" ) . exec ( result . text ) ;
let text =
@ -259,7 +339,7 @@ $(function () {
@@ -259,7 +339,7 @@ $(function () {
result . text . length
)
)
: "" ;
: "" ; // cut-off text before and after from the match
let display _result = text . length
? "..." +
@ -268,16 +348,22 @@ $(function () {
@@ -268,16 +348,22 @@ $(function () {
'<span class="search-result-highlight p-1">$&</span>'
) +
"..."
: "" ;
: "" ; // highlights the match
let in _code = false ;
if ( ! [ "page" , "section" ] . includes ( result . category . toLowerCase ( ) ) ) {
in _code = true ;
}
// We encode the full url to escape some special characters which can lead to broken links
let result _div = `
< a href = " $ {
< a href = " $ { encodeURI (
documenterBaseURL + "/" + result . location
} " class=" search - result - link px - 4 py - 2 w - 100 is - flex is - flex - direction - column gap - 2 my - 4 " >
< div class = "w-100 is-flex is-flex-wrap-wrap is-justify-content-space-between is-align-items-center" >
< div class = "search-result-title has-text-weight-semi-bold" > $ {
result . title
} < / d i v >
) } " class=" search - result - link w - 100 is - flex is - flex - direction - column gap - 2 px - 4 py - 2 " >
< div class = "w-100 is-flex is-flex-wrap-wrap is-justify-content-space-between is-align-items-flex-start " >
< div class = " search - result - title has - text - weight - bold $ {
in _code ? "search-result-code-title" : ""
} " > $ { result . title } < / d i v >
< div class = "property-search-result-badge" > $ { result . category } < / d i v >
< / d i v >
< p >
@ -291,39 +377,20 @@ $(function () {
@@ -291,39 +377,20 @@ $(function () {
< i class = "fas fa-link" > < / i > $ { d i s p l a y _ l i n k }
< / d i v >
< / a >
< div class = "search-divider" > < / d i v >
$ { search _divider }
` ;
return result _div ;
}
function update _search _box ( ) {
querystring = searchbox . val ( ) ;
update _search ( querystring ) ;
}
searchbox . keyup ( _ . debounce ( update _search _box , 250 ) ) ;
searchbox . change ( update _search _box ) ;
// Disable enter-key form submission for the searchbox on the search page
// and just re-run search rather than refresh the whole page.
searchform . keypress ( function ( event ) {
if ( event . which == "13" ) {
if ( sidebar . hasClass ( "visible" ) ) {
sidebar . removeClass ( "visible" ) ;
}
update _search _box ( ) ;
event . preventDefault ( ) ;
}
} ) ;
search _query _uri = parseUri ( window . location ) . queryKey [ "q" ] ;
if ( search _query _uri !== undefined ) {
search _query = decodeURIComponent ( search _query _uri . replace ( /\+/g , "%20" ) ) ;
searchbox . val ( search _query ) ;
}
return result _div ;
}
update _search _box ( ) ;
} ) ;
/ * *
* Get selected filters , remake the filter html and lastly update the search modal
* /
function get _filters ( ) {
let ele = $ ( ".search-filters .search-filter-selected" ) . get ( ) ;
filter _results = ele . map ( ( x ) => $ ( x ) . text ( ) . toLowerCase ( ) ) ;
modal _filters = make _modal _body _filters ( filters , filter _results ) ;
update _search ( filter _results ) ;
}
} )