{"version":3,"file":"taxonpicker.min.umd.js","sources":["../../src/utils/exceptions/TaxonError.js","../../src/utils/escapeHTML.js","../../src/models/Taxon.js","../../src/utils/TaxonSearch.js","../../src/framework/EventHarness.js","../../src/views/FormField.js","../../src/views/TaxonPickerField.js","../../src/utils/stopDoubleClick.js"],"sourcesContent":["export class TaxonError extends Error {\n\n}","/**\n *\n * @param text\n * @returns {string}\n */\nexport function escapeHTML(text) {\n try {\n // IE (even v 11) sometimes fails here with 'Unknown runtime error', see http://blog.rakeshpai.me/2007/02/ies-unknown-runtime-error-when-using.html\n const textArea = document.createElement('textarea');\n textArea.innerHTML = text;\n return textArea.innerHTML.replace(/\"/g, '"');\n } catch (e) {\n const pre = document.createElement('pre');\n pre.appendChild(document.createTextNode(text));\n return pre.innerHTML.replace(/\"/g, '"');\n }\n}\n","import {TaxonError} from \"../utils/exceptions/TaxonError\";\nimport {escapeHTML} from \"../utils/escapeHTML\";\n\nexport class Taxon {\n /**\n * @typedef RawTaxon\n * @type {array}\n * @property {string} 0 - nameString\n * @property {(string|number)} 1 - canonical\n * @property {string} 2 hybridCanonical, raw entry is 0 if canonical == hybridCanonical\n * @property {(string|number)} 3 acceptedEntityId or 0 if name is accepted\n * @property {string} 4 qualifier\n * @property {string} 5 authority\n * @property {string} 6 vernacular\n * @property {string} 7 vernacularRoot\n * @property {number} 8 used\n * @property {number} 9 sortOrder\n * @property {Array.} 10 parentIds\n */\n\n /**\n *\n * @type {Object.}\n */\n static rawTaxa;\n\n /**\n * @type {string}\n */\n id;\n\n /**\n *\n * @type {string}\n */\n nameString = '';\n\n /**\n *\n * @type {string}\n */\n canonical = '';\n\n /**\n *\n * @type {string}\n */\n hybridCanonical = '';\n\n /**\n *\n * @type {string}\n */\n acceptedEntityId = '';\n\n /**\n *\n * @type {string}\n */\n qualifier = '';\n\n /**\n *\n * @type {string}\n */\n authority = '';\n\n /**\n *\n * @type {string}\n */\n vernacular = '';\n\n /**\n *\n * @type {string}\n */\n vernacularRoot = '';\n\n /**\n * if set then the vernacular name should not be allowed for data entry\n *\n * @type {boolean}\n */\n badVernacular = false;\n\n /**\n * @type {boolean}\n */\n used;\n\n /**\n * @type {number}\n */\n sortOrder;\n\n /**\n *\n * @type {Array.}\n */\n parentIds = [];\n\n /**\n *\n * @type {boolean}\n */\n static showVernacular = true;\n\n static setTaxa(taxa) {\n Taxon.rawTaxa = taxa;\n }\n\n /**\n *\n * @param {string} id\n * @returns {Taxon}\n * @throws {TaxonError}\n */\n static fromId (id) {\n if (!Taxon.rawTaxa) {\n throw new TaxonError(`Taxon.fromId() called before taxon list has been initialized.`);\n }\n\n if (!Taxon.rawTaxa.hasOwnProperty(id)) {\n throw new TaxonError(`Taxon id '${id}' not found.`);\n }\n\n const raw = Taxon.rawTaxa[id];\n\n const taxon = new Taxon;\n\n taxon.id = id;\n taxon.nameString = raw[0];\n taxon.canonical = raw[1] || raw[0]; // raw entry is blank if namesString == canonical\n taxon.hybridCanonical = raw[2] || taxon.canonical; // raw entry is blank if canonical == hybridCanonical\n taxon.acceptedEntityId = raw[3] || id;\n taxon.qualifier = raw[4];\n taxon.authority = raw[5];\n taxon.vernacular = raw[6];\n taxon.vernacularRoot = raw[7];\n taxon.used = raw[8];\n taxon.sortOrder = raw[9];\n taxon.parentIds = raw[10];\n\n if (raw[11]) {\n taxon.badVernacular = true\n }\n\n return taxon;\n }\n\n /**\n *\n * @param {boolean} vernacularMatched\n * @returns {string}\n */\n formattedHTML(vernacularMatched) {\n let acceptedTaxon;\n if (this.id !== this.acceptedEntityId) {\n acceptedTaxon = Taxon.fromId(this.acceptedEntityId);\n }\n\n if (Taxon.showVernacular) {\n if (vernacularMatched) {\n return (acceptedTaxon) ?\n `${escapeHTML(this.vernacular)} ${this.nameString}${this.qualifier ? ` ${this.qualifier}` : ''} ${escapeHTML(this.authority)}` +\n ` = ${acceptedTaxon.nameString}${acceptedTaxon.qualifier ? ` ${acceptedTaxon.qualifier}` : ''} ${escapeHTML(acceptedTaxon.authority)}`\n :\n `${escapeHTML(this.vernacular)} ${this.nameString}${this.qualifier ? ` ${this.qualifier}` : ''} ${escapeHTML(this.authority)}`\n ;\n } else {\n return (acceptedTaxon) ?\n `${this.nameString}${this.qualifier ? ` ${this.qualifier}` : ''} ${this.authority}${this.vernacular ? ` ${escapeHTML(this.vernacular)}` : ''\n } = ${acceptedTaxon.nameString}${acceptedTaxon.qualifier ? ` ${acceptedTaxon.qualifier}` : ''} ${escapeHTML(acceptedTaxon.authority)}`\n :\n `${this.nameString}${this.qualifier ? ` ${this.qualifier}` : ''} ${escapeHTML(this.authority)}${this.vernacular ? ` ${escapeHTML(this.vernacular)}` : ''}`\n ;\n }\n } else {\n return (acceptedTaxon) ?\n `${this.nameString}${this.qualifier ? ` ${this.qualifier}` : ''} ${this.authority}` +\n ` = ${acceptedTaxon.nameString}${acceptedTaxon.qualifier ? ` ${acceptedTaxon.qualifier}` : ''} ${escapeHTML(acceptedTaxon.authority)}`\n :\n `${this.nameString}${this.qualifier ? ` ${this.qualifier}` : ''} ${escapeHTML(this.authority)}`\n ;\n }\n }\n}\n","/******************************************************************************\n * Generates taxon list suggestions.\n *****************************************************************************/\n\nimport {Taxon} from '../models/Taxon';\n\nconst RANK_DISPLAY_NAMES = /\\b(subg\\.|sect\\.|subsect\\.|ser\\.|group|subsp\\.|morph\\.|var\\.|nothovar\\.|f\\.|nothosubsp\\.|pv\\.)/g;\n\n/**\n * well-formed ranks, used for stripping rank from name for results table sorting\n *\n * @type RegExp\n */\nconst CLEAN_RANK_NAMES_REGEX = /\\s(subfam\\.|subg\\.|sect\\.|subsect\\.|ser\\.|subser\\.|subsp\\.|nothosubsp\\.|microsp\\.|praesp\\.|agsp\\.|race|convar\\.|nm\\.|microgene|f\\.|subvar\\.|var\\.|nothovar\\.|cv\\.|sublusus|taxon|morph\\.|group|sp\\.)\\s/g;\n\nconst collator = new Intl.Collator('en', {sensitivity : 'base', ignorePunctuation : true});\n\n/**\n * from https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions\n *\n * @param {string} literal\n * @return string\n */\nconst escapeRegExp = (literal) => literal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\nexport class TaxonSearch {\n\n /**\n * see TaxonRank::sort\n *\n * @type int|null\n */\n minimumRankSort = null;\n\n /**\n * if set then only taxa with records are returned\n *\n * @type boolean\n */\n requireExtantDDbRecords = false;\n\n // /**\n // * if set then only taxa with records present in the specified status scheme (scheme id code)\n // * (default null)\n // *\n // * @type string|null\n // */\n // requiredStatusSchemeId = null;\n\n // /**\n // * if set then require that returned taxon names are >= 3 letters\n // * and don't contain numerals\n // *\n // * @type boolean\n // */\n // skipJunk = true;\n\n /**\n * (static config setting)\n *\n * @type {boolean}\n */\n static showVernacular = true;\n\n static MIN_SEARCH_LENGTH = 1;\n\n static MAXIMUM_RESULTS = 20;\n\n constructor() {\n if (!Taxon.rawTaxa) {\n throw new Error('Taxon.rawTaxa must be initialised before TaxonSearch');\n }\n }\n\n /**\n *\n * @param {{uname: string, qualifier: string, authority: string, vernacular: string, acceptedEntityId: string=, acceptedNameString: string=, acceptedQualifier: string=, acceptedAuthority:string=, vernacularMatched: boolean=}} taxonResult\n * @param {string} queryString\n * @returns {string}\n */\n static formatter(taxonResult, queryString = '') {\n const uname = taxonResult.uname\n .replace(/\\bx\\b/g, '×')\n .replace(RANK_DISPLAY_NAMES, '$1')\n ;\n\n const qualifier = `${taxonResult.qualifier}`;\n\n if (TaxonSearch.showVernacular) {\n if (taxonResult.vernacularMatched) {\n if (taxonResult.acceptedEntityId) {\n return `${taxonResult.vernacular} ${uname}${taxonResult.qualifier ? ` ${qualifier}` : ''} ${taxonResult.authority}` +\n ` = ${taxonResult.acceptedNameString}${taxonResult.acceptedQualifier ? ` ${taxonResult.acceptedQualifier}` : ''} ${taxonResult.acceptedAuthority}`;\n }\n return `${taxonResult.vernacular} ${uname}${taxonResult.qualifier ? ` ${qualifier}` : ''} ${taxonResult.authority}`;\n }\n if (taxonResult.acceptedEntityId) {\n const acceptedNameString = taxonResult.acceptedNameString\n .replace('/\\bx\\b/', '×')\n .replace(RANK_DISPLAY_NAMES, '$1')\n ;\n\n return `${uname}${taxonResult.qualifier ? ` ${qualifier}` : ''} ${taxonResult.authority}${taxonResult.vernacular ? ` ${taxonResult.vernacular}` : ''\n } = ${acceptedNameString}${taxonResult.acceptedQualifier ? ` ${taxonResult.acceptedQualifier}` : ''} ${taxonResult.acceptedAuthority}`;\n }\n return `${uname}${taxonResult.qualifier ? ` ${qualifier}` : ''} ${taxonResult.authority}${taxonResult.vernacular ? ` ${taxonResult.vernacular}` : ''}`;\n }\n if (taxonResult.acceptedEntityId) {\n const acceptedNameString = taxonResult.acceptedNameString\n .replace('/\\bx\\b/', '×')\n .replace(RANK_DISPLAY_NAMES, '$1')\n ;\n\n return `${uname}${taxonResult.qualifier ? ` ${qualifier}` : ''} ${taxonResult.authority}` +\n ` = ${acceptedNameString}${taxonResult.acceptedQualifier ? ` ${taxonResult.acceptedQualifier}` : ''} ${taxonResult.acceptedAuthority}`;\n }\n return `${uname}${taxonResult.qualifier ? ` ${qualifier}` : ''} ${taxonResult.authority}`;\n }\n\n static abbreviatedGenusRegex = /^(X\\s+)?([a-z])[.\\s]+(.*?)$/i;\n\n static nameStringColumn = 0;\n static canonicalColumn = 1;\n static hybridCanonicalColumn = 2;\n static acceptedEntityIdColumn = 3;\n static qualifierColumn = 4;\n static authorityColumn = 5;\n static vernacularColumn = 6;\n static vernacularRootColumn = 7;\n static usedColumn = 8;\n static minRankColumn = 9;\n static badVernacularColumn = 11;\n\n static taxonRankNameSearchRegex = [\n /\\s+sub-?g(?:en(?:us)?)?[.\\s]+/i,\n /\\s+sect(?:ion)?[.\\s]+/i,\n /\\s+subsect(?:ion)?[.\\s]+/i,\n /\\s+ser(?:ies)?[.\\s]+/i,\n /\\s+gp[.\\s]+/i,\n /\\s+s(?:ub)?-?sp(?:ecies)?[.\\s]+/i,\n /\\s+morphotype\\s+/i,\n /\\s+var[.\\s]+/i,\n /\\s+cv[.\\s]+/i,\n /\\s+n(?:otho)?v(?:ar)?[.\\s]+/i,\n /\\s+f[.\\s]+|\\s+forma?\\s+/i,\n /\\s+n(?:otho)?ssp[.\\s]+/i,\n ];\n\n static taxonRankNameReplacement = [\n ' subg. ',\n ' sect. ',\n ' subsect. ',\n ' ser. ',\n ' group ',\n ' subsp. ',\n ' morph. ',\n ' var. ',\n ' cv. ', // ddb preference is for single quotes for cultivars\n ' nothovar. ',\n ' f. ',\n ' nothosubsp. ',\n ];\n\n /**\n *\n * @type Array *DON'T COPY THESE YET, AS THEY ARE AN UNOPTIMIZED MESS!*\n */\n static taxonQualifierSearchRegex = [\n /\\s*\\(?\\bf\\s*x\\s*m or m\\s*x\\s*f\\)?\\s*$/i,\n /\\s*\\(?\\bm\\s*x\\s*f or f\\s*x\\s*m\\)?\\s*$/i,\n\n /\\s*\\(?\\bf\\s*x\\s*m\\)?\\s*$/i,\n /\\s*\\(?\\bm\\s*x\\s*f\\)?\\s*$/i,\n\n /\\s*\\(?\\bfemale\\s*x\\s*male\\)?\\s*$/i,\n /\\s*\\(?\\bmale\\s*x\\s*female\\)?\\s*$/i,\n\n // stand-alone male/female qualifier (e.g. applied to Petasites hybridus)\n // removes single quotes\n /\\s*'male'\\s*$/i,\n /\\s*'female'\\s*$/i,\n\n // mid-string ss/sl qualifiers\n /\\b\\s*sens\\.?\\s*lat[.\\s]+/i,\n /\\b\\s*s\\.\\s*lat\\.?\\s*\\b/i,\n /\\b\\s*s\\.?\\s*l\\.?\\s+\\b/i,\n /\\b\\s*sensu\\s*lato\\s+\\b|\\(\\s*sensu\\s*lato\\s*\\)/i,\n\n /\\b\\s*sensu\\s*stricto\\s+\\b|\\(\\s*sensu\\s*stricto\\s*\\)/i,\n /\\b\\s*sens\\.?\\s*strict[.\\s]+/i,\n\n // '/\\b\\s*sens\\.?\\s*str\\.?\\s*(?=\\))|\\b\\s*sens\\.?\\s*str\\.?\\s*\\b/i', // the first look-ahead option matches before a closing-paren (\\b fails between '.)' )\n /\\b\\s*sens\\.?\\s*str\\.?\\s*(?=\\))|\\b\\s*sens\\.?\\s*str[.\\s]+/i,\n // '/\\b\\s*s\\.\\s*str\\.?\\s*\\b/i',\n /\\b\\s*s\\.\\s*str[.\\s]+/i,\n /\\b\\s*s\\.?\\s*s\\.?\\s+\\b/i,\n\n // end-of-string ss/sl qualifiers\n /\\b\\s*sens\\.?\\s*lat\\.?\\s*$/i,\n /\\b\\s*s\\.\\s*lat\\.?\\s*$/i,\n /\\b\\s*s\\.?\\s*l\\.?\\s*$/i,\n /\\b\\s*sensu\\s*lato\\s*$/i,\n\n /\\b\\s*sensu\\s*stricto\\s*$/i,\n /\\b\\s*sens\\.?\\s*strict\\.?\\s*$/i,\n /\\b\\s*sens\\.?\\s*str\\.?\\s*$/i,\n /\\b\\s*s\\.\\s*str\\.?\\s*$/i,\n /\\b\\s*s\\.?\\s*s\\.?\\s*$/i,\n\n /\\b\\s*agg\\.?\\s*$/i,\n /\\b\\s*aggregate\\s*$/i,\n\n /\\b\\s*sp\\.?\\s*cultivar\\s*$/i,\n /\\b\\s*sp\\.?\\s*cv\\.?\\s*$/i,\n /\\b\\s*cultivars?\\s*$/i,\n /\\b\\s*cv\\s+$/i,\n /\\b\\s*cv$/i,\n\n /\\b\\s*cf\\s*$/i,\n /\\b\\s*aff\\s*$/i,\n /\\b\\s*s\\.?n\\.?\\s*$/i,\n /\\b\\s*sp\\.?\\s*nov\\.?\\s*$/i,\n\n /\\b\\s*auct[.\\s]*$/i,\n\n /\\b\\s*ined[.\\s]*$/i,\n\n /\\b\\s*nom\\.?\\snud[.\\s]*$/i,\n\n /\\b\\s*p\\.p[.\\s?]*$/i,\n\n /\\b\\s*spp?\\.?[\\s?]*$/i,\n /\\b\\s*species\\s*$/i,\n /\\b\\s*spp?\\.?\\s*\\(/i, // catch e.g. Ulmus sp. (excluding Ulmus glabra)\n /\\b\\s*species\\s*\\(/i,\n ];\n\n static taxonQualifierReplacement = [\n ' ', // (f x m or m x f) is the default so an explicit qualifier isn't used\n ' ', // (m x f or f x m) is the default so an explicit qualifier isn't used\n\n ' (f x m)',\n ' (m x f)',\n\n ' (f x m)',\n ' (m x f)',\n\n // stand-alone male/female qualifier (e.g. applied to Petasites hybridus)\n // removed single quotes\n ' male',\n ' female',\n\n // mid-string ss/sl qualifiers\n ' s.l. ',\n ' s.l. ',\n ' s.l. ',\n ' s.l. ',\n\n ' s.s. ',\n ' s.s. ',\n ' s.s. ',\n ' s.s. ',\n ' s.s. ',\n\n // end-of-string ss/sl qualifiers\n ' s.l.',\n ' s.l.',\n ' s.l.',\n ' s.l.',\n\n ' s.s.',\n ' s.s.',\n ' s.s.',\n ' s.s.',\n ' s.s.',\n\n ' agg.',\n ' agg.',\n\n ' cv. ',\n ' cv. ',\n ' cv. ',\n ' cv. ',\n ' cv. ',\n\n ' cf.',\n ' aff.',\n\n ' sp.nov.',\n ' sp.nov.',\n\n ' auct.',\n\n ' ined.',\n\n ' nom. nud.',\n\n ' pro parte',\n\n '',\n '',\n ' (',\n ' (',\n ];\n\n /**\n *\n * @param {string} taxonString\n * @returns {string}\n */\n static normaliseTaxonName(taxonString) {\n taxonString = taxonString\n .replace(/[×✕]/ug, ' x ')\n .replace(/\\s+/ug, ' ')\n .trim()\n ;\n\n for (let i = 0, l = TaxonSearch.taxonRankNameSearchRegex.length; i < l; i++) {\n taxonString = taxonString.replace(TaxonSearch.taxonRankNameSearchRegex[i], TaxonSearch.taxonRankNameReplacement[i]);\n }\n\n for (let i = 0, l = TaxonSearch.taxonQualifierSearchRegex.length; i < l; i++) {\n taxonString = taxonString.replace(TaxonSearch.taxonQualifierSearchRegex[i], TaxonSearch.taxonQualifierReplacement[i]);\n }\n\n return taxonString;\n }\n\n /**\n * generate hybrid name permutations\n *\n * @param {string} names unescaped series of species e.g. \"glandulifera\" or \"carex x nigra\"\n * @returns {string} name permutations formatted as a regular expression\n */\n static generate_hybrid_combinations_regex(names) {\n const splitParts = escapeRegExp(names).split(/\\s+x\\s+/i);\n if (splitParts.length < 2) {\n return splitParts[0];\n }\n\n const hybridPermutations = [];\n\n /**\n * generate hybrid name permutations\n *\n * modified from O'Reilly PHP Cookbook\n * http://docstore.mik.ua/orelly/webprog/pcook/ch04_26.htm\n *\n * @param {Array.} items\n * @param {Array.} perms\n */\n const permutate = (items, perms) => {\n if (items.length === 0) {\n hybridPermutations[hybridPermutations.length] = perms.join('[a-zA-Z]* x ');\n } else {\n for (let i = items.length - 1; i >= 0; --i) {\n const newItems = items.slice(0);\n const newPerms = perms.slice(0); // take copies of the array\n\n newPerms.unshift(newItems.splice(i, 1)[0]);\n permutate(newItems, newPerms);\n }\n }\n };\n\n permutate(splitParts, []);\n\n return `(?:${hybridPermutations.join('|')})`;\n }\n\n /**\n *\n * @param {string} taxonId\n * @param {boolean} useVernacular\n * @returns {Array.<{entityId: string,\n * vernacular: string,\n * qname: string,\n * name: string,\n * qualifier: string,\n * authority: string,\n * uname: string,\n * vernacularMatched: boolean,\n * exact: boolean,\n * near: boolean,\n * formatted: string,\n * acceptedEntityId: string,\n * acceptedNameString: string,\n * acceptedQualifier: string,\n * acceptedAuthority: string\n * }>}\n */\n lookup_parent_results(taxonId, useVernacular) {\n const referenceTaxon = Taxon.fromId(taxonId);\n\n if (referenceTaxon.parentIds.length) {\n const parentIdsSet = new Set(referenceTaxon.parentIds);\n const matchedIds = {};\n\n if (useVernacular) {\n for (let id in Taxon.rawTaxa) {\n // noinspection JSUnfilteredForInLoop (assume is safe for rawTaxa object)\n let testTaxon = Taxon.rawTaxa[id];\n\n // test that has vernacular name and that parent ids intersect\n if (testTaxon[6] && testTaxon[10].filter(Set.prototype.has, parentIdsSet).length) {\n matchedIds[id] = {\n exact : false,\n near : false,\n vernacular : true\n };\n }\n }\n } else {\n for (let id in Taxon.rawTaxa) {\n // noinspection JSUnfilteredForInLoop (assume is safe for rawTaxa object)\n let testTaxon = Taxon.rawTaxa[id];\n\n // test that name is accepted and that parent ids intersect\n if (!testTaxon[3] && testTaxon[10].filter(Set.prototype.has, parentIdsSet).length) {\n matchedIds[id] = {\n exact : false,\n near : false\n };\n }\n }\n }\n return this.compile_results(matchedIds, false, []);\n } else {\n return [];\n }\n }\n\n /**\n *\n * @param {string} query\n * @param {array} previous\n * @param {boolean} allowExact default true, (if false then never mark results as exact match)\n * @returns {Array.<{entityId: string,\n vernacular: string,\n qname: string,\n name: string,\n qualifier: string,\n authority: string,\n uname: string,\n vernacularMatched: boolean,\n exact: boolean,\n near: boolean,\n formatted: string,\n acceptedEntityId: string,\n acceptedNameString: string,\n acceptedQualifier: string,\n acceptedAuthority: string\n }>}\n */\n lookup(query, previous = [], allowExact = true) {\n let results,\n taxonString,\n canonical,\n matchedIds = {},\n preferHybrids\n ;\n\n const decodedString = decodeURIComponent(query).trim();\n\n taxonString = TaxonSearch.normaliseTaxonName(decodedString);\n preferHybrids = / x\\b/.test(taxonString);\n\n // ignore trailing ' x' from string which would just muck up result matching\n taxonString = taxonString.replace(/\\s+x$/i, '');\n\n if (taxonString !== '') {\n const abbreviatedMatches = taxonString.match(TaxonSearch.abbreviatedGenusRegex);\n if (abbreviatedMatches) {\n // matched an abbreviated genus name (or an abbreviated hybrid genus)\n\n let exp,\n nearMatchExp;\n if (abbreviatedMatches[2] === 'X' || abbreviatedMatches[2] === 'x') {\n // either have a genus name beginning 'X' or a hybrid genus\n\n exp = new RegExp(`^(X\\\\s|X[a-z]+\\\\s+)(x )?\\\\b${TaxonSearch.generate_hybrid_combinations_regex(abbreviatedMatches[3])}.*`, 'i');\n nearMatchExp = exp;\n } else {\n exp = new RegExp(`^(X )?${escapeRegExp(abbreviatedMatches[2])}[a-z]+ (x )?.*\\\\b${TaxonSearch.generate_hybrid_combinations_regex(abbreviatedMatches[3])}.*`, 'i');\n\n /**\n * Similar to exp but without flexibility (.*) after genus part\n * used only for result ranking (exact>near>vague)\n */\n nearMatchExp = new RegExp(`^(X )?${escapeRegExp(abbreviatedMatches[2])}[a-z]+ (x )?\\\\b${TaxonSearch.generate_hybrid_combinations_regex(abbreviatedMatches[3])}.*`, 'i');\n }\n\n for (let id in Taxon.rawTaxa) {\n // noinspection JSUnfilteredForInLoop (assume is safe for rawTaxa object)\n let testTaxon = Taxon.rawTaxa[id];\n\n /**\n * The canonical name may be identical to the nameString in which case JSON taxon list stores\n * zero instead to save file space (and to mark that canonical name should be ignored)\n */\n canonical = testTaxon[TaxonSearch.canonicalColumn] === 0 ?\n testTaxon[TaxonSearch.nameStringColumn]\n :\n testTaxon[TaxonSearch.canonicalColumn];\n\n if (exp.test(canonical) ||\n ((testTaxon[TaxonSearch.hybridCanonicalColumn] !== '') && exp.test(testTaxon[TaxonSearch.hybridCanonicalColumn]))\n ) {\n matchedIds[id] = {\n exact: allowExact && (testTaxon[TaxonSearch.nameStringColumn] === taxonString),\n near: (nearMatchExp.test(testTaxon[TaxonSearch.nameStringColumn])),\n };\n }\n }\n\n results = this.compile_results(matchedIds, preferHybrids, previous);\n } else {\n // genus is not abbreviated\n\n let canonicalQuery,\n nearMatchRegex;\n const escapedTaxonString = escapeRegExp(taxonString);\n const escapedVernacularString = escapeRegExp(decodedString);\n\n if (taxonString.includes(' ')) {\n // hybrids of the form Species x nothoname or Species nothoname should be seen as equivalent\n\n canonicalQuery = `${escapeRegExp(taxonString.substring(0, taxonString.indexOf(' ')))\n } (x )?.*\\\\b${TaxonSearch.generate_hybrid_combinations_regex(taxonString.substring(taxonString.indexOf(' ') + 1))}.*`;\n\n /**\n * Similar to canonicalQuery/hybridCanonicalQuery but without flexibility (.*) after genus part\n * used only for result ranking (exact>near>vague)\n */\n nearMatchRegex = new RegExp(`^(?:X\\s+)?${escapeRegExp(taxonString.substring(0, taxonString.indexOf(' ')))\n } (x )?\\\\b${TaxonSearch.generate_hybrid_combinations_regex(taxonString.substring(taxonString.indexOf(' ') + 1))}.*`, 'i');\n } else {\n canonicalQuery = `${escapedTaxonString}.*`;\n nearMatchRegex = new RegExp(`^${escapedTaxonString}.*`);\n }\n\n const strictEscapedVernacularString = `^${escapedVernacularString}.*`;\n const canonicalQueryRegExp = new RegExp(`^(?:X\\s+)?${canonicalQuery}`, 'i');\n\n if (!TaxonSearch.showVernacular) {\n // no vernacular\n\n for (let id in Taxon.rawTaxa) {\n // noinspection JSUnfilteredForInLoop (assume is safe for rawTaxa object)\n let testTaxon = Taxon.rawTaxa[id];\n\n canonical = testTaxon[TaxonSearch.canonicalColumn] === 0 ?\n testTaxon[TaxonSearch.nameStringColumn]\n :\n testTaxon[TaxonSearch.canonicalColumn];\n\n if (\n canonicalQueryRegExp.test(testTaxon[TaxonSearch.nameStringColumn]) ||\n ((canonical !== testTaxon[TaxonSearch.nameStringColumn]) && canonicalQueryRegExp.test(canonical))\n ) {\n matchedIds[id] = {\n exact: allowExact && (collator.compare(testTaxon[TaxonSearch.nameStringColumn], taxonString) === 0)\n };\n }\n }\n\n results = this.compile_results(matchedIds, preferHybrids, previous);\n } else {\n // strictVernacularRegex allows flexible string and hyphen interchange\n\n // Safari doesn't support look-behind so need substitute\n //const strictVernacularRegex = new RegExp(strictEscapedVernacularString.replace(/(?<=\\p{L})[\\s-]+(?=\\p{L})/gu, '[\\\\s-]*'), 'i');\n const strictVernacularRegex = new RegExp(strictEscapedVernacularString.replace(/(\\p{L})[\\s-]+(?=\\p{L})/gu, '$1[\\\\s-]*'), 'i');\n\n for (let id in Taxon.rawTaxa) {\n // noinspection JSUnfilteredForInLoop (assume is safe for rawTaxa object)\n let testTaxon = Taxon.rawTaxa[id];\n\n canonical = testTaxon[TaxonSearch.canonicalColumn] === 0 ?\n testTaxon[TaxonSearch.nameStringColumn]\n :\n testTaxon[TaxonSearch.canonicalColumn];\n\n if (\n canonicalQueryRegExp.test(testTaxon[TaxonSearch.nameStringColumn]) ||\n ((canonical !== testTaxon[TaxonSearch.nameStringColumn]) && canonicalQueryRegExp.test(canonical))\n ) {\n matchedIds[id] = {\n exact: allowExact && (collator.compare(testTaxon[TaxonSearch.nameStringColumn], taxonString) === 0),\n near: (nearMatchRegex.test(testTaxon[TaxonSearch.nameStringColumn]) ||\n nearMatchRegex.test(canonical)),\n };\n } else if (\n !testTaxon[TaxonSearch.badVernacularColumn] &&\n (strictVernacularRegex.test(testTaxon[TaxonSearch.vernacularColumn]) ||\n strictVernacularRegex.test(testTaxon[TaxonSearch.vernacularRootColumn]))\n ) {\n matchedIds[id] = {\n exact: allowExact && (collator.compare(testTaxon[TaxonSearch.vernacularColumn], taxonString) === 0),\n vernacular: true,\n };\n }\n }\n\n results = this.compile_results(matchedIds, preferHybrids, previous);\n\n /**\n * if very few matches then retry searching using much fuzzier matching\n */\n if (results.length < 5) {\n // Safari doesn't support look-behind so need substitute\n //const spaceTolerantTaxonString = escapedTaxonString.replace(/(?<=\\p{L})[\\s-]+(?=\\p{L})/gu, '[\\\\s-]*');\n const spaceTolerantTaxonString = escapedTaxonString.replace(/(\\p{L})[\\s-]+(?=\\p{L})/gu, '$1[\\\\s-]*');\n\n // Safari doesn't support look-behind so need substitute\n //const spaceTolerantVernacularString = escapedVernacularString.replace(/(?<=\\p{L})[\\s-]+(?=\\p{L})/gu, '[\\\\s-]*');\n const spaceTolerantVernacularString = escapedVernacularString.replace(/(\\p{L})[\\s-]+(?=\\p{L})/gu, '$1[\\\\s-]*');\n\n const broadRegExp = new RegExp(`\\\\b${spaceTolerantTaxonString}.*`, 'i'); // match anywhere in string\n const broadVernacularRegExp = new RegExp(`\\\\b${spaceTolerantVernacularString}.*`, 'i'); // match anywhere in string\n\n for (let id in Taxon.rawTaxa) {\n // noinspection JSUnfilteredForInLoop (assume is safe for rawTaxa object)\n if (!matchedIds.hasOwnProperty(id)) {\n let testTaxon = Taxon.rawTaxa[id];\n\n if (broadRegExp.test(testTaxon[TaxonSearch.nameStringColumn])) {\n matchedIds[id] = {\n exact: allowExact && (testTaxon[TaxonSearch.nameStringColumn] === taxonString)\n };\n } else if (\n (testTaxon[TaxonSearch.canonicalColumn] !== 0 && broadRegExp.test(testTaxon[TaxonSearch.canonicalColumn])) ||\n (!testTaxon[TaxonSearch.badVernacularColumn] && broadVernacularRegExp.test(testTaxon[TaxonSearch.vernacularColumn]))\n ) {\n matchedIds[id] = {\n exact: allowExact && (testTaxon[TaxonSearch.nameStringColumn] === taxonString),\n vernacular: true\n };\n }\n }\n }\n\n results = this.compile_results(matchedIds, preferHybrids, previous);\n }\n }\n }\n\n // if only single result and first-pass then try to expand list of matches\n if (results.length === 1 && previous.length === 0) {\n let doUpdate = false;\n\n if (taxonString.indexOf(' ') > 0 && !results[0].vernacularMatched) {\n if (results[0].exact) {\n // exact scientific match, try broadening to parent level\n results = results.concat(this.lookup_parent_results(results[0].entityId, false));\n }\n\n // try broadening result of match on latin name to genus level\n const subString = taxonString.substring(0, query.indexOf(' '));\n\n results = results.concat(this.lookup(subString, results, false));\n doUpdate = true;\n } else if (results[0].vernacularMatched && results[0].exact) {\n // exact vernacular match, try broadening to parent level\n\n results = results.concat(this.lookup_parent_results(results[0].entityId, true));\n doUpdate = true;\n }\n\n if (doUpdate) {\n const entityList = [];\n\n // de-duplicate results\n for (let n = 0; n < results.length; n++) {\n if (results.hasOwnProperty(n) && entityList.indexOf(results[n].entityId) !== -1) {\n delete results[n];\n } else {\n entityList.push(results[n].entityId);\n }\n }\n\n // reindex results;\n results = results.filter(_ => true);\n }\n }\n } else {\n results = [];\n }\n\n return results;\n }\n\n compile_results(matchedIds, preferHybrids, previous = []) {\n const results = [].concat(previous);\n\n for (const id in matchedIds) {\n if (matchedIds.hasOwnProperty(id)) {\n const taxon = Taxon.rawTaxa[id];\n\n if (\n (!this.requireExtantDDbRecords || (this.requireExtantDDbRecords && taxon[TaxonSearch.usedColumn] === 1)) &&\n (!this.minimumRankSort || (this.minimumRankSort > 0 && taxon[TaxonSearch.minRankColumn] >= this.minimumRankSort))\n ) {\n const qname = taxon[TaxonSearch.nameStringColumn] + (taxon[TaxonSearch.qualifierColumn] ? (` ${taxon[TaxonSearch.qualifierColumn]}`) : '');\n\n const row = {\n entityId: id,\n vernacular: taxon[TaxonSearch.vernacularColumn],\n qname,\n name: qname, // use qualified name for the generic name field\n qualifier: taxon[TaxonSearch.qualifierColumn],\n authority: taxon[TaxonSearch.authorityColumn],\n uname: taxon[TaxonSearch.nameStringColumn],\n vernacularMatched: matchedIds[id].hasOwnProperty('vernacular') && matchedIds[id].vernacular,\n exact: matchedIds[id].hasOwnProperty('exact') && matchedIds[id].exact,\n near: matchedIds[id].hasOwnProperty('near') && matchedIds[id].near,\n };\n\n row.formatted = TaxonSearch.formatter(row);\n\n if (taxon[TaxonSearch.acceptedEntityIdColumn]) {\n const acceptedTaxon = Taxon.rawTaxa[taxon[TaxonSearch.acceptedEntityIdColumn]];\n\n if (!acceptedTaxon) {\n if (!Taxon.rawTaxa) {\n throw new Error(`Taxon.rawTaxa set is undefined, when trying to find taxon for accepted entity id ${taxon[TaxonSearch.acceptedEntityIdColumn]}`);\n } else {\n throw new Error(`Failed to find taxon for accepted entity id ${taxon[TaxonSearch.acceptedEntityIdColumn]}`);\n }\n }\n\n row.acceptedEntityId = taxon[TaxonSearch.acceptedEntityIdColumn];\n row.acceptedNameString = acceptedTaxon[TaxonSearch.nameStringColumn];\n row.acceptedQualifier = acceptedTaxon[TaxonSearch.qualifierColumn];\n row.acceptedAuthority = acceptedTaxon[TaxonSearch.authorityColumn];\n row.acceptedQname = row.acceptedNameString + (row.acceptedQualifier ? (` ${row.acceptedQualifier}`) : '');\n }\n\n results.push(row);\n }\n }\n }\n\n if (results.length) {\n results.sort((a, b) => {\n // if (a.uname == 'Taraxacum \\'Irish cambricum\\'' || b.uname == 'Taraxacum \\'Irish cambricum\\'') {\n // console.log(a.uname + \" with \" + b.uname);\n // }\n\n if (a.exact) {\n // logger('exact test a: ' + a.uname + ' vs ' + b.uname);\n // logger(b);\n if (b.exact) {\n return a.acceptedEntityId ? 1 : -1; // prefer accepted name\n }\n return -1;\n\n // return b.exact ? 0 : -1;\n } else if (b.exact) {\n // logger('exact test b: ' + b.uname);\n return 1;\n }\n\n if (a.near) {\n if (!b.near) {\n return -1;\n }\n } else if (b.near) {\n // logger('exact test b: ' + b.uname);\n return 1;\n }\n\n let aIsHybrid = a.uname.match(/\\bx\\b/i) !== null;\n let bIsHybrid = b.uname.match(/\\bx\\b/i) !== null;\n\n if (aIsHybrid) {\n // logger('hybrid test: ' + a.qname + ' vs ' + b.qname);\n // logger('hybrid test: ' + a.uname + ' vs ' + b.uname);\n if (bIsHybrid) {\n if (a.uname === b.uname) {\n return a.acceptedEntityId ? 1 : 0; // prefer accepted name\n }\n return a.qname < b.qname ? -1 : 1;\n }\n return preferHybrids ? -1 : 1;\n } else if (bIsHybrid) {\n return preferHybrids ? 1 : -1;\n } else if (a.uname === b.uname) {\n if ((a.acceptedEntityId || b.acceptedEntityId) &&\n !(a.acceptedEntityId && b.acceptedEntityId)) {\n // one of the pair is not an accepted name\n\n return a.acceptedEntityId ? 1 : -1; // prefer accepted name\n } else {\n // for NYPH purposes agg. and s.l. should be prioritised over\n // agg., s.l., empty, s.s.\n\n let aQIndex = ['s.s.', '', null, 's.l.', 'agg.'].indexOf(a.qualifier);\n let bQIndex = ['s.s.', '', null, 's.l.', 'agg.'].indexOf(b.qualifier);\n\n return (aQIndex === bQIndex) ? 0 : (\n (aQIndex < bQIndex) ? 1 : -1\n );\n }\n } else if (a.vernacularMatched && b.vernacularMatched) {\n // matching both names using vernacular\n // so sort by this\n\n if (a.vernacular !== b.vernacular) {\n if (a.vernacular.length === b.vernacular.length) {\n return collator.compare(a.vernacular, b.vernacular);\n }\n\n return a.vernacular.length < b.vernacular.length ? -1 : 1;\n }\n }\n\n // prefer accepted (n.b. acceptedEntityId is only set for synonyms)\n if (a.acceptedEntityId && !b.acceptedEntityId) {\n return 1;\n }\n\n if (b.acceptedEntityId && !a.acceptedEntityId) {\n return -1;\n }\n\n const strippedUnameA = a.uname.replaceAll(CLEAN_RANK_NAMES_REGEX, ' ').replaceAll(\"'\", '').replaceAll(/\\bx /ig, '');\n const strippedUnameB = b.uname.replaceAll(CLEAN_RANK_NAMES_REGEX, ' ').replaceAll(\"'\", '').replaceAll(/\\bx /ig, '');\n\n return collator.compare(strippedUnameA, strippedUnameB);\n //return strippedUnameA < strippedUnameB ? -1 : 1;\n });\n\n // truncate results\n if (results.length > TaxonSearch.MAXIMUM_RESULTS) {\n results.length = TaxonSearch.MAXIMUM_RESULTS;\n }\n }\n\n return results;\n }\n}\n\n","export class EventHarness {\n /**\n *\n * @type {*[]}\n */\n #eventListeners = [];\n\n static STOP_PROPAGATION = 'STOP_PROPAGATION';\n\n /**\n *\n * @param {string} eventName\n * @param {Object} obj\n * @param {Function} method\n * @param {*=} constructionParam\n * @deprecated use addListener instead\n * @return {number} handle\n */\n bindListener (eventName, obj, method, constructionParam) {\n this.#eventListeners = this.#eventListeners || [];\n\n const handlerFunction =\n function(context, eventName, invocationParam) {\n return method.call(obj, context, eventName, invocationParam, constructionParam);\n };\n\n if (this.#eventListeners[eventName]) {\n return (this.#eventListeners[eventName].push(handlerFunction))-1;\n } else {\n this.#eventListeners[eventName] = [handlerFunction];\n return 0; // first element in array\n }\n };\n\n /**\n *\n * @param {string} eventName\n * @param {Function} handler\n * @param {*=} constructionParam\n * @return {number} handle\n */\n addListener (eventName, handler, constructionParam = {}) {\n this.#eventListeners = this.#eventListeners || [];\n\n const handlerFunction =\n function(context, eventName, invocationParam = {}) {\n return handler({context, eventName, ...invocationParam, ...constructionParam});\n };\n\n if (this.#eventListeners[eventName]) {\n return (this.#eventListeners[eventName].push(handlerFunction)) - 1;\n } else {\n this.#eventListeners[eventName] = [handlerFunction];\n return 0; // first element in array\n }\n };\n\n /**\n *\n * @param {string} eventName\n * @param {number} handle\n * @returns undefined\n */\n removeListener(eventName, handle) {\n if (this.#eventListeners[eventName] && this.#eventListeners[eventName][handle]) {\n delete this.#eventListeners[eventName][handle];\n } else {\n console.log('trying to remove non-existent event handler, event = ' + eventName + ' handle = ' + handle);\n }\n return undefined;\n };\n\n /**\n *\n */\n destructor() {\n this.#eventListeners = null;\n };\n\n /**\n *\n * @param {string} eventName\n * @param {Object=} param optional parameter to pass on to listener\n * @return void\n */\n fireEvent (eventName, param) {\n //console.log('fire event \"' + eventName + '\" called by '+this.fire_event.caller.caller+' invoked by '+this.fire_event.caller.caller.caller+' instigated by '+this.fire_event.caller.caller.caller.caller);\n\n if (this.#eventListeners) {\n for (let f in this.#eventListeners[eventName]) {\n if (this.#eventListeners[eventName].hasOwnProperty(f)) {\n if (this.#eventListeners[eventName][f](this, eventName, arguments[1]) === EventHarness.STOP_PROPAGATION) {\n break;\n }\n }\n }\n }\n };\n}\n","import {EventHarness} from '../framework/EventHarness';\n\nexport class FormField extends EventHarness {\n\n _value = null;\n\n /**\n * overall wrapped field element (not necessarily the form element itself)\n *\n * @type {HTMLElement}\n */\n _fieldEl;\n\n /**\n *\n * @type {string}\n */\n label = '';\n\n /**\n *\n * @type {string}\n */\n helpText = '';\n\n /**\n * validation message - displayed if field is not valid\n * HTML string\n *\n * @type {string}\n */\n validationMessage = '';\n\n /**\n *\n * @type {string}\n */\n static COMPLETION_COMPULSORY = 'compulsory';\n static COMPLETION_DESIRED = 'desired';\n static COMPLETION_OPTIONAL = 'optional';\n\n /**\n *\n * @type {string}\n */\n completion = FormField.COMPLETION_OPTIONAL;\n\n static #fieldIdIndex = 1;\n\n static EVENT_CHANGE = 'fieldChange';\n\n /**\n *\n *\n */\n constructor () {\n super();\n\n // if (params) {\n // if (params.label) {\n // this.label = params.label;\n // }\n //\n // if (params.helpText) {\n // this.helpText = params.helpText;\n // }\n //\n // if (params.validationMessage) {\n // this.validationMessage = params.validationMessage;\n // }\n //\n // if (params.completion) {\n // // @see COMPLETION_COMPULSORY, COMPLETION_DESIRED, COMPLETION_OPTIONAL\n // this.completion = params.completion;\n // }\n // }\n }\n\n setParams(params) {\n if (params.label) {\n this.label = params.label;\n }\n\n if (params.helpText) {\n this.helpText = params.helpText;\n }\n\n if (params.validationMessage) {\n this.validationMessage = params.validationMessage;\n }\n }\n\n static get nextId() {\n return `field${FormField.#fieldIdIndex++}_${Date.now()}`; // use stamp for unique id generation to break spurious autocomplete\n }\n\n /**\n *\n * @returns {null|any}\n */\n get value() {\n return this._value;\n }\n\n /**\n * @abstract\n * @param value\n */\n set value(value) {\n\n }\n\n get fieldElement() {\n if (!this._fieldEl) {\n this.buildField();\n }\n\n return this._fieldEl;\n }\n\n\n\n /**\n * @type {string}\n */\n attributeName;\n\n /**\n *\n * @param {HTMLElement} contentContainer\n */\n addField(contentContainer) {\n contentContainer.appendChild(this.fieldElement);\n }\n\n /**\n *\n * @param {boolean} isValid\n */\n markValidity(isValid) {\n\n }\n\n /**\n *\n * @param {HTMLInputElement} inputElement\n * @returns {string}\n */\n static cleanRawInput(inputElement) {\n return inputElement.value.trim().replace(/\\s\\s+/g, ' ');\n }\n\n /**\n *\n * @param {string} text\n * @returns {string}\n */\n static cleanRawString(text) {\n return text.trim().replace(/\\s\\s+/g, ' ');\n }\n\n /**\n *\n * @param value\n * @returns {boolean}\n */\n static isEmpty(value) {\n return value === '' || value === undefined || value === null;\n }\n\n /**\n *\n * @param {string} key\n * @param property properties of the form descriptor\n * @param attributes attributes of the model object\n * @return {(boolean|null)} returns null if validity was not assessed\n */\n static isValid(key, property, attributes) {\n //console.log(`FormField isValid for '${key}'`);\n\n if (property.attributes.completion &&\n (property.attributes.completion === FormField.COMPLETION_COMPULSORY || property.attributes.completion === FormField.COMPLETION_DESIRED)\n ) {\n // test whether required field is missing\n return !(!attributes.hasOwnProperty(key) ||\n property.field.isEmpty(attributes[key])\n );\n }\n // field is present or optional\n // report as valid unless content is corrupt\n\n return null; // field not assessed\n }\n\n /**\n *\n * @param {string} key\n * @param {{field : typeof FormField, [summary] : {}, [summarise] : function}} property properties of the form descriptor\n * @param attributes attributes of the model object\n * @return {string}\n */\n static summarise(key, property, attributes) {\n if (property.summary && (!property.summary.hasOwnProperty('summarise') || true === property.summary.summarise)) {\n // test is that summary spec object exists and doesn't have the 'summarise' flag set to false\n\n if (property.summarise) {\n return property.summarise(key, property, attributes);\n } else {\n return property.field.summariseImpl(key, property, attributes);\n }\n } else {\n return '';\n }\n }\n\n /**\n * by the time summariseImpl has been called have already checked that summary is wanted\n *\n * @param {string} key\n * @param {{field : typeof FormField, [attributes]: {}, summary : Object.}} property properties of the form descriptor\n * @param {Object.} attributes attributes of the model object\n * @returns {string}\n */\n static summariseImpl(key, property, attributes) {\n return '';\n }\n\n /**\n * @abstract\n */\n buildField() {\n\n }\n}\n","import {FormField} from \"./FormField\";\nimport {TaxonSearch} from \"../utils/TaxonSearch\";\nimport {Taxon} from \"../models/Taxon\";\nimport {doubleClickIntercepted} from \"../utils/stopDoubleClick\";\n\nconst CSS_UNRECOGNIZED_TAXON_CLASS = 'taxon-invalid';\nconst CSS_UNRECOGNIZED_TAXON_CONTAINER_CLASS = 'taxon-unrecognized-container';\nconst CSS_DROPDOWN_FOCUSED = 'dropdown-focused';\nconst CSS_DROPDOWN_SELECTED = 'taxon-selected';\n\nexport class TaxonPickerField extends FormField {\n /**\n * @type {TaxonSearch}\n */\n taxonSearch;\n\n /**\n * @type {string}\n */\n #inputFieldId;\n\n /**\n * @type {string}\n */\n #dropDownListDivId;\n\n /**\n * @type {string}\n */\n #dropDownListUlId;\n\n /**\n * @type {string}\n */\n #wrapperDivId;\n\n /**\n * @type {string}\n */\n #containerId;\n\n /**\n * @type {string}\n */\n #unrecognizedWarningElId;\n\n #taxonLookupTimeoutHandle = null;\n\n #changeEventTimeout = null;\n\n /**\n *\n * @type {null|number}\n */\n #selectedIndex = null;\n\n /**\n *\n * @type {string}\n * @private\n */\n _lastInputValue = '';\n\n unrecognizedWarningText = \"\" // was \"The name that you have typed hasn't been matched. If possible please pick an entry from the drop-down list of suggestions.\";\n\n /**\n *\n * @type {boolean}\n */\n alwaysUseAcceptedName = true;\n\n /**\n *\n * @type {boolean}\n */\n allowTaxonMismatches = false;\n\n /**\n * If set (default false) then fire change event, even if the taxon hasn't apparently changed\n * (used if a page navigation should occur if the selection is activated)\n *\n * @type {boolean}\n */\n alwaysFireChangeEvent = false;\n\n // /**\n // *\n // * @type {boolean}\n // */\n // hideSensuStricto = true;\n\n hangLeft = false;\n\n /**\n * @type {Array.<{entityId: string,\n vernacular: string,\n qname: string,\n name: string,\n qualifier: string,\n authority: string,\n uname: string,\n vernacularMatched: boolean,\n exact: boolean,\n near: boolean,\n formatted: string,\n acceptedEntityId: string=,\n acceptedNameString: string=,\n acceptedQualifier: string=,\n acceptedAuthority: string=,\n acceptedQname: string=,\n }>}\n */\n #searchResults = [];\n\n /**\n *\n * @type {{taxonName: string, taxonId: string, vernacularMatch: boolean|null}}\n * @private\n */\n _value = {\n taxonId: '',\n taxonName: '',\n vernacularMatch: false\n };\n\n /**\n *\n * @type {string}\n */\n #previousId = '';\n\n static timeoutDelay = 50;\n\n /**\n *\n */\n constructor () {\n super();\n\n this.taxonSearch = new TaxonSearch();\n }\n\n /**\n *\n * @param {({taxonName: string, taxonId: string, vernacularMatch: boolean|null}|null)} taxonSpec\n */\n set value(taxonSpec) {\n let taxon;\n\n if (taxonSpec && taxonSpec.taxonId) {\n // this will trigger an error if somehow an invalid id was supplied\n taxon = Taxon.fromId(taxonSpec.taxonId);\n\n const qname = taxon.nameString + (taxon.qualifier ? (` ${taxon.qualifier}`) : '');\n\n // build the saved values from the dictionary rather than from the literal user entry (which may use different formatting)\n this._value = {\n taxonId: taxon.id,\n taxonName: taxonSpec.vernacularMatch ? taxon.vernacular : qname,\n vernacularMatch: taxonSpec.vernacularMatch\n };\n } else {\n this._value = {\n taxonId: '',\n taxonName: taxonSpec && taxonSpec.taxonName ? taxonSpec.taxonName : '',\n vernacularMatch: null\n };\n }\n\n this.updateView();\n }\n\n /**\n *\n * @returns {({taxonName: string, taxonId: string, vernacularMatch: boolean}|null)}\n */\n get value() {\n return this._value;\n }\n\n /**\n *\n * @param {({taxonName: string, taxonId: string, vernacularMatch: boolean}|null)} value\n * @returns {boolean}\n */\n static isEmpty(value) {\n return !value || (value && !value.taxonName);\n }\n\n updateView() {\n if (this._fieldEl) {\n // do nothing until the view has been constructed\n\n const inputEl = document.getElementById(this.#inputFieldId);\n inputEl.value = this._value.taxonName;\n\n if (this._value.taxonId) {\n const taxon = Taxon.fromId(this._value.taxonId);\n\n inputEl.title = taxon.nameString +\n (taxon.qualifier ? (` ${taxon.qualifier}`) : '') +\n (taxon.authority ? (` ${taxon.authority}`) : '') +\n (taxon.vernacular ? ` “${taxon.vernacular}”` : '');\n } else {\n inputEl.title = \"Search for a taxon.\";\n }\n\n this._lastInputValue = this._value.taxonName; // probably not necessary\n\n const unrecognizedWarningEl = document.getElementById(this.#unrecognizedWarningElId);\n\n if (unrecognizedWarningEl) {\n if (this._value.taxonName) {\n if (this._value.taxonId) {\n unrecognizedWarningEl.classList.remove(CSS_UNRECOGNIZED_TAXON_CLASS);\n } else {\n unrecognizedWarningEl.classList.add(CSS_UNRECOGNIZED_TAXON_CLASS);\n }\n } else {\n unrecognizedWarningEl.classList.remove(CSS_UNRECOGNIZED_TAXON_CLASS);\n }\n }\n }\n }\n\n /**\n *\n * @param {(boolean|null)} isValid\n */\n markValidity(isValid) {\n const el = document.getElementById(this.#inputFieldId);\n\n if (null === isValid) {\n el.classList.remove('is-invalid', 'is-valid');\n } else {\n el.classList.remove(isValid ? 'is-invalid' : 'is-valid');\n el.classList.add(isValid ? 'is-valid' : 'is-invalid');\n }\n }\n\n /**\n * initialises this._fieldEl\n *\n * @returns {void}\n */\n buildField() {\n const container = document.createElement('div');\n container.className = 'form-group mb-3';\n this.#containerId = container.id = FormField.nextId;\n\n this.#inputFieldId = FormField.nextId;\n\n if (this.unrecognizedWarningText) {\n const unrecognizedWarningEl = container.appendChild(document.createElement('p'));\n unrecognizedWarningEl.id = this.#unrecognizedWarningElId = FormField.nextId;\n unrecognizedWarningEl.className = CSS_UNRECOGNIZED_TAXON_CONTAINER_CLASS;\n unrecognizedWarningEl.textContent = this.unrecognizedWarningText;\n }\n\n if (this.label) {\n const labelEl = container.appendChild(document.createElement('label'));\n labelEl.htmlFor = this.#inputFieldId;\n labelEl.textContent = this.label;\n }\n\n const wrapperEl = container.appendChild(document.createElement('div'));\n wrapperEl.className = 'dropdown-wrapper';\n this.#wrapperDivId = wrapperEl.id = FormField.nextId;\n\n const inputField = wrapperEl.appendChild(document.createElement('input'));\n inputField.className = \"form-control dropdown-input\";\n inputField.id = this.#inputFieldId;\n inputField.autocomplete = 'off';\n inputField.spellcheck = false;\n inputField.type = 'search';\n inputField.placeholder = 'Search for a taxon';\n inputField.setAttribute('aria-autocomplete', 'list');\n inputField.setAttribute('role', 'combobox');\n inputField.setAttribute('aria-expanded', 'false');\n inputField.setAttribute('aria-activedescendant', '');\n\n if (this.validationMessage) {\n // unfortunately the validation message has to be placed immediately after the input field\n const validationMessageElement = wrapperEl.appendChild(document.createElement('div'));\n validationMessageElement.className = 'invalid-feedback';\n validationMessageElement.innerHTML = this.validationMessage;\n }\n\n const dropDownList = wrapperEl.appendChild(document.createElement('div'));\n dropDownList.className = 'dropdown-list';\n this.#dropDownListDivId = dropDownList.id = FormField.nextId;\n dropDownList.setAttribute('role', 'listbox');\n\n inputField.setAttribute('aria-controls', this.#dropDownListDivId);\n\n this.#dropDownListUlId = FormField.nextId;\n\n if (this.helpText) {\n const helpTextField = container.appendChild(document.createElement('small'));\n helpTextField.innerHTML = this.helpText;\n }\n\n inputField.addEventListener('keydown', this.keydownHandler.bind(this));\n //inputField.addEventListener('keyup', this.keyupHandler.bind(this));\n inputField.addEventListener('input', this.inputHandler.bind(this));\n inputField.addEventListener('change', this.inputChangeHandler.bind(this));\n\n container.addEventListener('focusin', this.focusHandler.bind(this));\n container.addEventListener('focusout', this.blurHandler.bind(this));\n dropDownList.addEventListener('click', this.dropboxClickHandler.bind(this));\n\n\n this._fieldEl = container;\n }\n\n /**\n *\n * @param {number} tabIndex\n */\n setTabIndex(tabIndex) {\n const inputEl = document.getElementById(this.#inputFieldId);\n\n if (inputEl) {\n inputEl.tabIndex = tabIndex;\n }\n }\n\n /**\n *\n * @param {KeyboardEvent} event\n * @param {HTMLInputElement} event.target\n * @return {boolean}\n */\n keydownHandler(event) {\n this._lastInputValue = event.target.value.trimStart(); // save value for testing in InputEvent handler\n\n switch (event.key) {\n case 'Enter':\n event.preventDefault();\n\n this._applyResult(event);\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n\n if (this.#selectedIndex > 0) {\n this.setSelectedIndex(this.#selectedIndex - 1);\n }\n break;\n\n case 'ArrowDown':\n event.preventDefault();\n\n if (this.#searchResults.length) {\n if (this.#selectedIndex === null) {\n this.setSelectedIndex(0);\n } else if (this.#selectedIndex < this.#searchResults.length - 1) {\n this.setSelectedIndex(this.#selectedIndex + 1);\n }\n }\n break;\n\n case 'ArrowRight':\n if (this.#searchResults.length && this.#selectedIndex === null) {\n let caretPosition\n if (event.target.selectionDirection === 'backward') {\n caretPosition = event.target.selectionStart;\n } else {\n caretPosition = event.target.selectionEnd;\n }\n\n if (caretPosition === event.target.value.length) {\n // keypress right while at end of input\n // indicating a desire for auto-completion wih the best suggestion\n\n this._setResult(0);\n this._triggerQuery(event.target);\n event.preventDefault();\n }\n }\n event.stopPropagation(); // on Atlas pages the image gallery mistakenly captures this and blocks default action\n break;\n\n case 'ArrowLeft':\n event.stopPropagation(); // on Atlas pages the image gallery mistakenly captures this and blocks default action\n break;\n\n case 'Escape':\n // see https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-list/#kbd_label_textbox\n\n // expected aria behaviour for combo box\n // If the list-box is displayed, closes it.\n // If the list-box is not displayed, clears the text-box.\n\n event.preventDefault();\n if (this.#searchResults.length && this.#selectedIndex !== null) {\n this._applyResult(event);\n } else {\n const inputEl = document.getElementById(this.#inputFieldId);\n inputEl.value = '';\n this.#searchResults.length = 0;\n inputEl.blur();\n }\n break;\n }\n }\n\n /**\n * called after enter pressed or escape pressed with a selected match\n *\n * @param {KeyboardEvent} event\n */\n _applyResult(event) {\n if (this.#taxonLookupTimeoutHandle) {\n clearTimeout(this.#taxonLookupTimeoutHandle);\n this.#taxonLookupTimeoutHandle = null;\n }\n\n this.inputChangeHandler(event);\n\n const dropDownEl = document.getElementById(this.#wrapperDivId);\n dropDownEl.classList.remove(CSS_DROPDOWN_FOCUSED);\n\n document.body.classList.remove('hide-controls');\n document.getElementById(this.#inputFieldId).blur();\n\n // setting of result will be handled during blur instead\n }\n\n /**\n *\n * @param {InputEvent} event\n */\n inputHandler(event) {\n const currentValue = event.target.value.trimStart(); // save value for testing in InputEvent handler\n\n if (currentValue !== this._lastInputValue) {\n this._triggerQuery(event.target);\n }\n }\n\n /**\n *\n * @param {HTMLInputElement} inputEl\n */\n _triggerQuery(inputEl) {\n let text = FormField.cleanRawInput(inputEl);\n\n // Clear previous timeout\n if (this.#taxonLookupTimeoutHandle) {\n clearTimeout(this.#taxonLookupTimeoutHandle);\n }\n\n // proceed if minimum length phrase was provided\n if ((text.length) >= TaxonSearch.MIN_SEARCH_LENGTH) {\n\n // Set new timeout - don't run if user is typing\n this.#taxonLookupTimeoutHandle = setTimeout(() => {\n this.#searchResults = this.taxonSearch.lookup(\n FormField.cleanRawInput(document.getElementById(this.#inputFieldId))\n );\n\n this.refreshSearchResultsList();\n\n this.#taxonLookupTimeoutHandle = null;\n }, TaxonPickerField.timeoutDelay);\n } else {\n // clear the results list\n this.#searchResults = [];\n this.refreshSearchResultsList();\n }\n }\n\n /**\n *\n * @param {Event} event\n */\n focusHandler(event) {\n const dropDownWrapperEl = document.getElementById(this.#wrapperDivId);\n\n if (!dropDownWrapperEl.classList.contains(CSS_DROPDOWN_FOCUSED)) {\n // Refresh dropdown list when first focused.\n // The focus event will re-fire after click on link in dropdown potentially disrupting subsequent click\n // it is important that the query is not re-run if already focused.\n const inputEl = document.getElementById(this.#inputFieldId);\n this._triggerQuery(inputEl);\n\n dropDownWrapperEl.classList.add(CSS_DROPDOWN_FOCUSED);\n\n // kludgy work-around for a z-index problem on mobile\n // buttons pop-through the dropdown list, so temporarily hide them all\n document.body.classList.add('hide-controls');\n\n if (this.hangLeft) {\n const dropDownEl = document.getElementById(this.#dropDownListDivId);\n\n dropDownEl.style.right = '0';\n dropDownEl.style.position = 'absolute';\n dropDownEl.style.width = '24em';\n }\n\n if (this._value.taxonId && this._value.taxonName === inputEl.value && !this._value.vernacularMatch) {\n const firstSpace = this._value.taxonName.indexOf(' ');\n\n if (firstSpace > -1) {\n inputEl.setSelectionRange(firstSpace + 1, inputEl.value.length, 'backward');\n }\n }\n }\n }\n\n /**\n *\n * @param {Event} event\n */\n blurHandler(event) {\n // clear taxon result lookup timeout\n if (this.#taxonLookupTimeoutHandle) {\n clearTimeout(this.#taxonLookupTimeoutHandle);\n this.#taxonLookupTimeoutHandle = null;\n }\n\n // to avoid blurring before a link click has been processed, introduce a delay\n setTimeout(() => {\n const dropDownEl = document.getElementById(this.#wrapperDivId);\n dropDownEl.classList.remove(CSS_DROPDOWN_FOCUSED);\n\n const inputEl = document.getElementById(this.#inputFieldId);\n inputEl.setAttribute('aria-expanded', 'false');\n inputEl.setAttribute('aria-activedescendant', '');\n\n document.body.classList.remove('hide-controls');\n\n }, 500);\n }\n\n refreshSearchResultsList() {\n const dropdownListEl = document.getElementById(this.#dropDownListDivId);\n const inputEl = document.getElementById(this.#inputFieldId);\n\n this.#selectedIndex = null;\n if (this.#searchResults.length) {\n const htmlResults = [];\n\n let n = 0;\n for (let result of this.#searchResults) {\n let itemId = `taxonitem${this.#dropDownListDivId}_${result.entityId}`;\n htmlResults[htmlResults.length] = `${TaxonSearch.formatter(result)}`;\n ++n;\n }\n\n dropdownListEl.innerHTML = `
${htmlResults.join('')}
`;\n\n if (this.#searchResults[0].exact) {\n this.setSelectedIndex(0);\n }\n\n inputEl.setAttribute('aria-expanded', 'true');\n } else {\n dropdownListEl.innerHTML = `

Start typing the name of a taxon.

`;\n inputEl.setAttribute('aria-expanded', 'false');\n inputEl.setAttribute('aria-activedescendant', '');\n }\n }\n\n /**\n *\n * @param {number|null} n\n */\n setSelectedIndex(n) {\n if (n !== this.#selectedIndex) {\n if (null !== this.#selectedIndex) {\n // clear existing selection\n\n const selectedEl = document.querySelector(`div#${this.#dropDownListDivId} a[data-resultnumber=\"${this.#selectedIndex}\"]`);\n if (selectedEl) {\n selectedEl.classList.remove(CSS_DROPDOWN_SELECTED);\n selectedEl.setAttribute('aria-selected', 'false');\n }\n }\n\n const selectedEl = document.querySelector(`div#${this.#dropDownListDivId} a[data-resultnumber=\"${n}\"]`);\n if (selectedEl) {\n selectedEl.classList.add(CSS_DROPDOWN_SELECTED);\n this.#selectedIndex = n;\n selectedEl.setAttribute('aria-selected', 'true');\n\n const inputEl = document.getElementById(this.#inputFieldId);\n inputEl.setAttribute('aria-activedescendant', selectedEl.id);\n } else {\n this.#selectedIndex = null; // something's gone wrong\n }\n }\n }\n\n static cleanRawInput(inputElement) {\n return inputElement.value.trim().replace(/\\s\\s+/g, ' ');\n }\n\n /**\n *\n * @param {MouseEvent} event\n */\n dropboxClickHandler(event) {\n if (doubleClickIntercepted(event)) {\n return;\n }\n\n const targetEl = event.target.closest('a');\n\n if (this.#changeEventTimeout) {\n clearTimeout(this.#changeEventTimeout);\n this.#changeEventTimeout = null;\n }\n\n if (targetEl && targetEl.dataset.occurrenceid) {\n event.preventDefault();\n\n this._setResult(parseInt(targetEl.dataset.resultnumber));\n }\n }\n\n\n /**\n *\n * @param {number} n\n */\n _setResult(n) {\n const result = this.#searchResults[n];\n\n if (result.acceptedEntityId && this.alwaysUseAcceptedName) {\n // have a non-accepted result\n\n this.value = {\n taxonId: result.acceptedEntityId,\n taxonName: result.acceptedQname,\n vernacularMatch: false\n };\n } else {\n this.value = {\n taxonId: result.entityId,\n taxonName: result.vernacularMatched ? result.vernacular : result.qname,\n vernacularMatch: result.vernacularMatched\n };\n }\n\n\n if (this.#previousId !== this._value.taxonId || this.alwaysFireChangeEvent) {\n this.#previousId = this._value.taxonId;\n this.fireEvent(FormField.EVENT_CHANGE);\n }\n }\n\n /**\n * Sets taxon picker value using a taxon entity id\n * refreshes view\n * *does not* trigger change event\n *\n * @param {string} taxonId\n * @throws TaxonError\n */\n setTaxonFromId(taxonId) {\n if (taxonId) {\n let taxon = Taxon.fromId(taxonId);\n if (taxon.acceptedEntityId) {\n taxon = Taxon.fromId(taxon.acceptedEntityId);\n }\n\n const qname = taxon.nameString + (taxon.qualifier ? (` ${taxon.qualifier}`) : '');\n\n this.value = {\n taxonId: taxon.id,\n taxonName: qname,\n vernacularMatch: false\n };\n } else {\n this.value = {\n taxonId: '',\n taxonName: '',\n vernacularMatch: null\n };\n }\n\n this.#previousId = this._value.taxonId;\n this.updateView();\n }\n\n inputChangeHandler (event) {\n // need to prevent race-conditions between clicks and change events\n // i.e. a click event on the dropdown list might come after a change event on the input field\n\n event.stopPropagation();\n\n if (this.#changeEventTimeout) {\n clearTimeout(this.#changeEventTimeout);\n }\n\n // avoid acting on a change immediately, in case there is a click event following\n this.#changeEventTimeout = setTimeout(() => {\n //console.log('processing taxon field input change event');\n\n const rawValue = document.getElementById(this.#inputFieldId).value;\n if (rawValue === '') {\n // value is blank, probably after x button clicked\n\n // clear taxon result lookup timeout\n if (this.#taxonLookupTimeoutHandle) {\n clearTimeout(this.#taxonLookupTimeoutHandle);\n this.#taxonLookupTimeoutHandle = null;\n }\n\n // apply immediate blur\n const dropDownEl = document.getElementById(this.#wrapperDivId);\n dropDownEl.classList.remove(CSS_DROPDOWN_FOCUSED);\n } else {\n let exactMatch;\n if (this.#selectedIndex !== null) {\n exactMatch = this.#searchResults[this.#selectedIndex];\n } else {\n // check if the dropdown list has an exact match, if so then use it\n exactMatch = this.#searchResults.find((result) => {\n return result.exact;\n });\n }\n\n if (exactMatch) {\n //console.log('exact match');\n\n if (exactMatch.acceptedEntityId && this.alwaysUseAcceptedName) {\n // have a non-accepted result\n\n this.value = {\n taxonId: exactMatch.acceptedEntityId,\n taxonName: exactMatch.acceptedQname,\n vernacularMatch: false\n };\n } else {\n this.value = {\n taxonId: exactMatch.entityId,\n taxonName: exactMatch.vernacularMatched ? exactMatch.vernacular : exactMatch.qname,\n vernacularMatch: exactMatch.vernacularMatched\n }; // setter will refresh the field but not fire a change event\n }\n } else {\n //console.log('no match');\n\n this.value = {\n taxonId: '',\n taxonName: this.allowTaxonMismatches ? document.getElementById(this.#inputFieldId).value.trim() : '',\n vernacularMatch: null\n };\n }\n }\n\n if (this.#previousId !== this._value.taxonId || this.alwaysFireChangeEvent) {\n this.#previousId = this._value.taxonId;\n this.fireEvent(FormField.EVENT_CHANGE);\n }\n }, 500);\n }\n}\n","/**\n *\n * @param {MouseEvent} event\n * @returns {boolean}\n */\nexport function doubleClickIntercepted(event) {\n if (event.detail && event.detail > 1) {\n event.preventDefault();\n event.stopPropagation();\n return true;\n }\n\n return false;\n}\n"],"names":["TaxonError","Error","escapeHTML","text","textArea","document","createElement","innerHTML","replace","e","pre","appendChild","createTextNode","Taxon","static","id","nameString","canonical","hybridCanonical","acceptedEntityId","qualifier","authority","vernacular","vernacularRoot","badVernacular","used","sortOrder","parentIds","taxa","rawTaxa","hasOwnProperty","raw","taxon","formattedHTML","vernacularMatched","acceptedTaxon","this","fromId","showVernacular","RANK_DISPLAY_NAMES","CLEAN_RANK_NAMES_REGEX","collator","Intl","Collator","sensitivity","ignorePunctuation","escapeRegExp","literal","TaxonSearch","minimumRankSort","requireExtantDDbRecords","constructor","taxonResult","queryString","uname","acceptedNameString","acceptedQualifier","acceptedAuthority","taxonString","trim","i","l","taxonRankNameSearchRegex","length","taxonRankNameReplacement","taxonQualifierSearchRegex","taxonQualifierReplacement","names","splitParts","split","hybridPermutations","permutate","items","perms","join","newItems","slice","newPerms","unshift","splice","lookup_parent_results","taxonId","useVernacular","referenceTaxon","parentIdsSet","Set","matchedIds","testTaxon","filter","prototype","has","exact","near","compile_results","lookup","query","previous","allowExact","results","preferHybrids","decodedString","decodeURIComponent","normaliseTaxonName","test","abbreviatedMatches","match","abbreviatedGenusRegex","exp","nearMatchExp","RegExp","generate_hybrid_combinations_regex","canonicalColumn","nameStringColumn","hybridCanonicalColumn","canonicalQuery","nearMatchRegex","escapedTaxonString","escapedVernacularString","includes","substring","indexOf","strictEscapedVernacularString","canonicalQueryRegExp","strictVernacularRegex","compare","badVernacularColumn","vernacularColumn","vernacularRootColumn","spaceTolerantTaxonString","spaceTolerantVernacularString","broadRegExp","broadVernacularRegExp","doUpdate","concat","entityId","subString","entityList","n","push","_","usedColumn","minRankColumn","qname","qualifierColumn","row","name","authorityColumn","formatted","formatter","acceptedEntityIdColumn","acceptedQname","sort","a","b","aIsHybrid","bIsHybrid","aQIndex","bQIndex","strippedUnameA","replaceAll","strippedUnameB","MAXIMUM_RESULTS","EventHarness","eventListeners","bindListener","eventName","obj","method","constructionParam","handlerFunction","context","invocationParam","call","addListener","handler","removeListener","handle","console","log","destructor","fireEvent","param","f","arguments","STOP_PROPAGATION","FormField","_value","_fieldEl","label","helpText","validationMessage","completion","COMPLETION_OPTIONAL","super","setParams","params","nextId","fieldIdIndex","Date","now","value","fieldElement","buildField","attributeName","addField","contentContainer","markValidity","isValid","inputElement","key","property","attributes","COMPLETION_COMPULSORY","COMPLETION_DESIRED","field","isEmpty","summary","summarise","summariseImpl","CSS_UNRECOGNIZED_TAXON_CLASS","CSS_DROPDOWN_FOCUSED","CSS_DROPDOWN_SELECTED","TaxonPickerField","taxonSearch","inputFieldId","dropDownListDivId","dropDownListUlId","wrapperDivId","containerId","unrecognizedWarningElId","taxonLookupTimeoutHandle","changeEventTimeout","selectedIndex","_lastInputValue","unrecognizedWarningText","alwaysUseAcceptedName","allowTaxonMismatches","alwaysFireChangeEvent","hangLeft","searchResults","taxonName","vernacularMatch","previousId","taxonSpec","updateView","inputEl","getElementById","title","unrecognizedWarningEl","classList","remove","add","el","container","className","textContent","labelEl","htmlFor","wrapperEl","inputField","autocomplete","spellcheck","type","placeholder","setAttribute","validationMessageElement","dropDownList","addEventListener","keydownHandler","bind","inputHandler","inputChangeHandler","focusHandler","blurHandler","dropboxClickHandler","setTabIndex","tabIndex","event","target","trimStart","preventDefault","_applyResult","setSelectedIndex","caretPosition","selectionDirection","selectionStart","selectionEnd","_setResult","_triggerQuery","stopPropagation","blur","clearTimeout","body","cleanRawInput","MIN_SEARCH_LENGTH","setTimeout","refreshSearchResultsList","timeoutDelay","dropDownWrapperEl","contains","dropDownEl","style","right","position","width","firstSpace","setSelectionRange","dropdownListEl","htmlResults","result","itemId","selectedEl","querySelector","detail","doubleClickIntercepted","targetEl","closest","dataset","occurrenceid","parseInt","resultnumber","EVENT_CHANGE","setTaxonFromId","exactMatch","find"],"mappings":"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"}