2026-03-07 05:17:50 -08:00
( function ( ) {
"use strict" ;
let config = {
getAlphabets : ( ) => null ,
2026-03-08 22:24:34 -07:00
getGematriaDb : ( ) => null ,
2026-03-07 05:17:50 -08:00
getGematriaElements : ( ) => ( {
cipherEl : null ,
inputEl : null ,
resultEl : null ,
2026-03-09 03:07:02 -07:00
breakdownEl : null ,
2026-03-09 14:43:03 -07:00
modeEls : [ ] ,
2026-03-09 03:07:02 -07:00
matchesEl : null ,
inputLabelEl : null ,
cipherLabelEl : null
2026-03-07 05:17:50 -08:00
} )
} ;
const state = {
loadingPromise : null ,
db : null ,
listenersBound : false ,
activeCipherId : "" ,
2026-03-09 03:07:02 -07:00
forwardInputText : "" ,
reverseInputText : "" ,
2026-03-09 14:43:03 -07:00
anagramInputText : "" ,
2026-03-09 03:07:02 -07:00
activeMode : "forward" ,
scriptCharMap : new Map ( ) ,
reverseLookupCache : new Map ( ) ,
2026-03-09 14:43:03 -07:00
anagramLookupCache : new Map ( ) ,
reverseRequestId : 0 ,
anagramRequestId : 0
2026-03-07 05:17:50 -08:00
} ;
function getAlphabets ( ) {
return config . getAlphabets ? . ( ) || null ;
}
2026-03-08 22:24:34 -07:00
function getConfiguredGematriaDb ( ) {
return config . getGematriaDb ? . ( ) || null ;
}
2026-03-07 05:17:50 -08:00
function getElements ( ) {
return config . getGematriaElements ? . ( ) || {
cipherEl : null ,
inputEl : null ,
resultEl : null ,
2026-03-09 03:07:02 -07:00
breakdownEl : null ,
2026-03-09 14:43:03 -07:00
modeEls : [ ] ,
2026-03-09 03:07:02 -07:00
matchesEl : null ,
inputLabelEl : null ,
cipherLabelEl : null
2026-03-07 05:17:50 -08:00
} ;
}
2026-03-09 03:07:02 -07:00
function isReverseMode ( ) {
return state . activeMode === "reverse" ;
}
2026-03-09 14:43:03 -07:00
function isAnagramMode ( ) {
return state . activeMode === "anagram" ;
}
2026-03-09 03:07:02 -07:00
function getCurrentInputText ( ) {
2026-03-09 14:43:03 -07:00
if ( isReverseMode ( ) ) {
return state . reverseInputText ;
}
if ( isAnagramMode ( ) ) {
return state . anagramInputText ;
}
return state . forwardInputText ;
2026-03-09 03:07:02 -07:00
}
function formatCount ( value ) {
const numericValue = Number ( value ) ;
if ( ! Number . isFinite ( numericValue ) ) {
return "0" ;
}
return numericValue . toLocaleString ( ) ;
}
2026-03-07 05:17:50 -08:00
function getFallbackGematriaDb ( ) {
return {
baseAlphabet : "abcdefghijklmnopqrstuvwxyz" ,
ciphers : [
{
id : "simple-ordinal" ,
name : "Simple Ordinal" ,
description : "A=1 ... Z=26" ,
values : Array . from ( { length : 26 } , ( _ , index ) => index + 1 )
2026-03-09 03:07:02 -07:00
} ,
{
id : "decadic-cipher" ,
name : "Decadic Cipher" ,
description : "A=1 ... I=9, J=10 ... R=90, S=100 ... Z=800" ,
values : [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 20 , 30 , 40 , 50 , 60 , 70 , 80 , 90 , 100 , 200 , 300 , 400 , 500 , 600 , 700 , 800 ]
2026-03-07 05:17:50 -08:00
}
]
} ;
}
function normalizeGematriaText ( value ) {
return String ( value || "" )
. normalize ( "NFD" )
. replace ( /[\u0300-\u036f]/g , "" )
. toLowerCase ( ) ;
}
function transliterationToBaseLetters ( transliteration , baseAlphabet ) {
const normalized = normalizeGematriaText ( transliteration ) ;
if ( ! normalized ) {
return "" ;
}
const primaryVariant = normalized . split ( /[\/,;|]/ ) [ 0 ] || normalized ;
const primaryLetters = [ ... primaryVariant ] . filter ( ( char ) => baseAlphabet . includes ( char ) ) ;
if ( primaryLetters . length ) {
return primaryLetters [ 0 ] ;
}
const allLetters = [ ... normalized ] . filter ( ( char ) => baseAlphabet . includes ( char ) ) ;
return allLetters [ 0 ] || "" ;
}
function addScriptCharMapEntry ( map , scriptChar , mappedLetters ) {
const key = String ( scriptChar || "" ) . trim ( ) ;
const value = String ( mappedLetters || "" ) . trim ( ) ;
if ( ! key || ! value ) {
return ;
}
map . set ( key , value ) ;
}
function buildGematriaScriptMap ( baseAlphabet ) {
const map = new Map ( ) ;
const alphabets = getAlphabets ( ) || { } ;
const hebrewLetters = Array . isArray ( alphabets . hebrew ) ? alphabets . hebrew : [ ] ;
const greekLetters = Array . isArray ( alphabets . greek ) ? alphabets . greek : [ ] ;
hebrewLetters . forEach ( ( entry ) => {
const mapped = transliterationToBaseLetters ( entry ? . transliteration , baseAlphabet ) ;
addScriptCharMapEntry ( map , entry ? . char , mapped ) ;
} ) ;
greekLetters . forEach ( ( entry ) => {
const mapped = transliterationToBaseLetters ( entry ? . transliteration , baseAlphabet ) ;
addScriptCharMapEntry ( map , entry ? . char , mapped ) ;
addScriptCharMapEntry ( map , entry ? . charLower , mapped ) ;
addScriptCharMapEntry ( map , entry ? . charFinal , mapped ) ;
} ) ;
const hebrewFinalForms = {
ך : "k" ,
ם : "m" ,
ן : "n" ,
ף : "p" ,
ץ : "t"
} ;
Object . entries ( hebrewFinalForms ) . forEach ( ( [ char , mapped ] ) => {
if ( ! map . has ( char ) && baseAlphabet . includes ( mapped ) ) {
addScriptCharMapEntry ( map , char , mapped ) ;
}
} ) ;
if ( ! map . has ( "ς" ) && baseAlphabet . includes ( "s" ) ) {
addScriptCharMapEntry ( map , "ς" , "s" ) ;
}
return map ;
}
function refreshScriptMap ( baseAlphabetOverride = "" ) {
const db = state . db || getFallbackGematriaDb ( ) ;
const baseAlphabet = String ( baseAlphabetOverride || db . baseAlphabet || "abcdefghijklmnopqrstuvwxyz" ) . toLowerCase ( ) ;
state . scriptCharMap = buildGematriaScriptMap ( baseAlphabet ) ;
}
function sanitizeGematriaDb ( db ) {
const baseAlphabet = String ( db ? . baseAlphabet || "abcdefghijklmnopqrstuvwxyz" ) . toLowerCase ( ) ;
const ciphers = Array . isArray ( db ? . ciphers )
? db . ciphers
. map ( ( cipher ) => {
const id = String ( cipher ? . id || "" ) . trim ( ) ;
const name = String ( cipher ? . name || "" ) . trim ( ) ;
const values = Array . isArray ( cipher ? . values )
? cipher . values . map ( ( value ) => Number ( value ) )
: [ ] ;
if ( ! id || ! name || values . length !== baseAlphabet . length || values . some ( ( value ) => ! Number . isFinite ( value ) ) ) {
return null ;
}
return {
id ,
name ,
description : String ( cipher ? . description || "" ) . trim ( ) ,
values
} ;
} )
. filter ( Boolean )
: [ ] ;
if ( ! ciphers . length ) {
return getFallbackGematriaDb ( ) ;
}
return {
baseAlphabet ,
ciphers
} ;
}
async function loadGematriaDb ( ) {
if ( state . db ) {
return state . db ;
}
if ( state . loadingPromise ) {
return state . loadingPromise ;
}
2026-03-08 22:24:34 -07:00
state . loadingPromise = Promise . resolve ( )
. then ( async ( ) => {
const configuredDb = getConfiguredGematriaDb ( ) ;
if ( configuredDb ) {
return configuredDb ;
2026-03-07 05:17:50 -08:00
}
2026-03-08 22:24:34 -07:00
const referenceData = await window . TarotDataService ? . loadReferenceData ? . ( ) ;
return referenceData ? . gematriaCiphers || null ;
2026-03-07 05:17:50 -08:00
} )
. then ( ( db ) => {
2026-03-08 22:24:34 -07:00
if ( ! db ) {
throw new Error ( "Gematria cipher data unavailable from API." ) ;
}
2026-03-07 05:17:50 -08:00
state . db = sanitizeGematriaDb ( db ) ;
return state . db ;
} )
. catch ( ( ) => {
state . db = getFallbackGematriaDb ( ) ;
return state . db ;
} )
. finally ( ( ) => {
state . loadingPromise = null ;
} ) ;
return state . loadingPromise ;
}
function getActiveGematriaCipher ( ) {
const db = state . db || getFallbackGematriaDb ( ) ;
const ciphers = Array . isArray ( db . ciphers ) ? db . ciphers : [ ] ;
if ( ! ciphers . length ) {
return null ;
}
const selectedId = state . activeCipherId || ciphers [ 0 ] . id ;
return ciphers . find ( ( cipher ) => cipher . id === selectedId ) || ciphers [ 0 ] ;
}
function renderGematriaCipherOptions ( ) {
const { cipherEl } = getElements ( ) ;
if ( ! cipherEl ) {
return ;
}
const db = state . db || getFallbackGematriaDb ( ) ;
const ciphers = Array . isArray ( db . ciphers ) ? db . ciphers : [ ] ;
cipherEl . innerHTML = "" ;
ciphers . forEach ( ( cipher ) => {
const option = document . createElement ( "option" ) ;
option . value = cipher . id ;
option . textContent = cipher . name ;
if ( cipher . description ) {
option . title = cipher . description ;
}
cipherEl . appendChild ( option ) ;
} ) ;
const activeCipher = getActiveGematriaCipher ( ) ;
state . activeCipherId = activeCipher ? . id || "" ;
cipherEl . value = state . activeCipherId ;
}
2026-03-09 03:07:02 -07:00
function setMatchesMessage ( matchesEl , message ) {
if ( ! matchesEl ) {
return ;
}
matchesEl . replaceChildren ( ) ;
const emptyEl = document . createElement ( "div" ) ;
emptyEl . className = "alpha-gematria-match-empty" ;
emptyEl . textContent = message ;
matchesEl . appendChild ( emptyEl ) ;
}
function clearReverseMatches ( matchesEl ) {
if ( ! matchesEl ) {
return ;
}
matchesEl . replaceChildren ( ) ;
matchesEl . hidden = true ;
}
2026-03-09 14:43:03 -07:00
function getModeElements ( modeEls ) {
return Array . isArray ( modeEls )
? modeEls . filter ( ( element ) => element instanceof HTMLInputElement )
: [ ] ;
}
2026-03-09 03:07:02 -07:00
function updateModeUi ( ) {
const {
cipherEl ,
inputEl ,
2026-03-09 14:43:03 -07:00
modeEls ,
2026-03-09 03:07:02 -07:00
matchesEl ,
inputLabelEl ,
cipherLabelEl
} = getElements ( ) ;
const reverseMode = isReverseMode ( ) ;
2026-03-09 14:43:03 -07:00
const anagramMode = isAnagramMode ( ) ;
const radioEls = getModeElements ( modeEls ) ;
2026-03-09 03:07:02 -07:00
2026-03-09 14:43:03 -07:00
radioEls . forEach ( ( element ) => {
element . checked = String ( element . value || "" ) === state . activeMode ;
} ) ;
2026-03-09 03:07:02 -07:00
if ( inputLabelEl ) {
2026-03-09 14:43:03 -07:00
inputLabelEl . textContent = reverseMode ? "Value" : ( anagramMode ? "Letters" : "Text" ) ;
2026-03-09 03:07:02 -07:00
}
if ( cipherLabelEl ) {
2026-03-09 14:43:03 -07:00
cipherLabelEl . textContent = ( reverseMode || anagramMode ) ? "Cipher (not used in this mode)" : "Cipher" ;
2026-03-09 03:07:02 -07:00
}
if ( cipherEl ) {
2026-03-09 14:43:03 -07:00
const disableCipher = reverseMode || anagramMode ;
cipherEl . disabled = disableCipher ;
cipherEl . closest ( ".alpha-gematria-field" ) ? . classList . toggle ( "is-disabled" , disableCipher ) ;
2026-03-09 03:07:02 -07:00
}
if ( inputEl ) {
2026-03-09 14:43:03 -07:00
inputEl . placeholder = reverseMode
? "Enter a whole number, e.g. 33"
: ( anagramMode ? "Type letters or a word, e.g. listen" : "Type or paste text" ) ;
2026-03-09 03:07:02 -07:00
inputEl . inputMode = reverseMode ? "numeric" : "text" ;
2026-03-09 14:43:03 -07:00
inputEl . spellcheck = ! ( reverseMode || anagramMode ) ;
2026-03-09 03:07:02 -07:00
const nextValue = getCurrentInputText ( ) ;
if ( inputEl . value !== nextValue ) {
inputEl . value = nextValue ;
}
}
2026-03-09 14:43:03 -07:00
if ( ! reverseMode && ! anagramMode ) {
2026-03-09 03:07:02 -07:00
clearReverseMatches ( matchesEl ) ;
}
}
function parseReverseLookupValue ( rawValue ) {
const normalizedValue = String ( rawValue || "" ) . trim ( ) ;
if ( ! normalizedValue ) {
return null ;
}
if ( ! /^\d+$/ . test ( normalizedValue ) ) {
return Number . NaN ;
}
const numericValue = Number ( normalizedValue ) ;
if ( ! Number . isSafeInteger ( numericValue ) ) {
return Number . NaN ;
}
return numericValue ;
}
async function loadReverseLookup ( value ) {
const cacheKey = String ( value ) ;
if ( state . reverseLookupCache . has ( cacheKey ) ) {
return state . reverseLookupCache . get ( cacheKey ) ;
}
const payload = await window . TarotDataService ? . loadGematriaWordsByValue ? . ( value ) ;
state . reverseLookupCache . set ( cacheKey , payload ) ;
return payload ;
}
2026-03-09 14:43:03 -07:00
async function loadAnagramLookup ( text ) {
const cacheKey = String ( text || "" ) . trim ( ) . toLowerCase ( ) ;
if ( state . anagramLookupCache . has ( cacheKey ) ) {
return state . anagramLookupCache . get ( cacheKey ) ;
}
const payload = await window . TarotDataService ? . loadWordAnagrams ? . ( text ) ;
state . anagramLookupCache . set ( cacheKey , payload ) ;
return payload ;
}
2026-03-09 03:07:02 -07:00
function renderReverseLookupMatches ( payload , numericValue ) {
const { resultEl , breakdownEl , matchesEl } = getElements ( ) ;
if ( ! resultEl || ! breakdownEl || ! matchesEl ) {
return ;
}
const matches = Array . isArray ( payload ? . matches ) ? payload . matches : [ ] ;
const count = Number ( payload ? . count ) ;
const displayCount = Number . isFinite ( count ) ? count : matches . length ;
const ciphers = Array . isArray ( payload ? . ciphers ) ? payload . ciphers : [ ] ;
const cipherCount = Number ( payload ? . cipherCount ) ;
const displayCipherCount = Number . isFinite ( cipherCount ) ? cipherCount : ciphers . length ;
const visibleMatches = matches . slice ( 0 , 120 ) ;
resultEl . textContent = ` Value: ${ formatCount ( numericValue ) } ` ;
if ( ! displayCount ) {
breakdownEl . textContent = "No words matched this reverse gematria value." ;
matchesEl . hidden = false ;
setMatchesMessage ( matchesEl , "No matches found in the reverse gematria index." ) ;
return ;
}
const topCipherSummary = ciphers
. slice ( 0 , 6 )
. map ( ( cipher ) => ` ${ String ( cipher ? . name || cipher ? . id || "Unknown" ) } ${ formatCount ( cipher ? . count ) } ` )
. join ( " · " ) ;
breakdownEl . textContent = ` Found ${ formatCount ( displayCount ) } matches across ${ formatCount ( displayCipherCount ) } ciphers. ${ topCipherSummary ? ` Top ciphers: ${ topCipherSummary } . ` : "" } ${ displayCount > visibleMatches . length ? ` Showing first ${ formatCount ( visibleMatches . length ) } . ` : "" } ` ;
const fragment = document . createDocumentFragment ( ) ;
visibleMatches . forEach ( ( match ) => {
const cardEl = document . createElement ( "article" ) ;
cardEl . className = "alpha-gematria-match" ;
const wordEl = document . createElement ( "div" ) ;
wordEl . className = "alpha-gematria-match-word" ;
wordEl . textContent = String ( match ? . word || "--" ) ;
cardEl . appendChild ( wordEl ) ;
const definition = String ( match ? . definition || "" ) . trim ( ) ;
if ( definition ) {
const definitionEl = document . createElement ( "div" ) ;
definitionEl . className = "alpha-gematria-match-definition" ;
definitionEl . textContent = definition ;
cardEl . appendChild ( definitionEl ) ;
}
const ciphersEl = document . createElement ( "div" ) ;
ciphersEl . className = "alpha-gematria-match-ciphers" ;
const matchCiphers = Array . isArray ( match ? . ciphers ) ? match . ciphers : [ ] ;
matchCiphers . slice ( 0 , 6 ) . forEach ( ( cipher ) => {
const chipEl = document . createElement ( "span" ) ;
chipEl . className = "alpha-gematria-match-cipher" ;
chipEl . textContent = String ( cipher ? . name || cipher ? . id || "Unknown" ) ;
ciphersEl . appendChild ( chipEl ) ;
} ) ;
if ( matchCiphers . length > 6 ) {
const extraEl = document . createElement ( "span" ) ;
extraEl . className = "alpha-gematria-match-cipher" ;
extraEl . textContent = ` + ${ matchCiphers . length - 6 } more ` ;
ciphersEl . appendChild ( extraEl ) ;
}
cardEl . appendChild ( ciphersEl ) ;
fragment . appendChild ( cardEl ) ;
} ) ;
matchesEl . replaceChildren ( fragment ) ;
matchesEl . hidden = false ;
}
async function renderReverseLookupResult ( ) {
const { resultEl , breakdownEl , matchesEl } = getElements ( ) ;
if ( ! resultEl || ! breakdownEl || ! matchesEl ) {
return ;
}
const rawValue = state . reverseInputText ;
if ( ! String ( rawValue || "" ) . trim ( ) ) {
resultEl . textContent = "Value: --" ;
breakdownEl . textContent = "Enter a whole number to find words across all available ciphers." ;
matchesEl . hidden = false ;
setMatchesMessage ( matchesEl , "Reverse lookup searches the API-backed gematria word index." ) ;
return ;
}
const numericValue = parseReverseLookupValue ( rawValue ) ;
if ( ! Number . isFinite ( numericValue ) ) {
resultEl . textContent = "Value: --" ;
breakdownEl . textContent = "Enter digits only to search the reverse gematria index." ;
matchesEl . hidden = false ;
setMatchesMessage ( matchesEl , "Use a whole number such as 33 or 418." ) ;
return ;
}
const requestId = state . reverseRequestId + 1 ;
state . reverseRequestId = requestId ;
resultEl . textContent = ` Value: ${ formatCount ( numericValue ) } ` ;
breakdownEl . textContent = "Searching reverse gematria index..." ;
matchesEl . hidden = false ;
setMatchesMessage ( matchesEl , "Loading matching words..." ) ;
try {
const payload = await loadReverseLookup ( numericValue ) ;
if ( requestId !== state . reverseRequestId || ! isReverseMode ( ) ) {
return ;
}
renderReverseLookupMatches ( payload , numericValue ) ;
} catch {
if ( requestId !== state . reverseRequestId || ! isReverseMode ( ) ) {
return ;
}
resultEl . textContent = ` Value: ${ formatCount ( numericValue ) } ` ;
breakdownEl . textContent = "Reverse lookup is unavailable right now." ;
matchesEl . hidden = false ;
setMatchesMessage ( matchesEl , "Unable to load reverse gematria words from the API." ) ;
}
}
2026-03-09 14:43:03 -07:00
function renderAnagramMatches ( payload ) {
const { resultEl , breakdownEl , matchesEl } = getElements ( ) ;
if ( ! resultEl || ! breakdownEl || ! matchesEl ) {
return ;
}
const matches = Array . isArray ( payload ? . matches ) ? payload . matches : [ ] ;
const count = Number ( payload ? . count ) ;
const displayCount = Number . isFinite ( count ) ? count : matches . length ;
const visibleMatches = matches . slice ( 0 , 120 ) ;
const letterCount = Number ( payload ? . letterCount ) ;
resultEl . textContent = ` Anagrams: ${ formatCount ( displayCount ) } ` ;
if ( ! displayCount ) {
breakdownEl . textContent = "No exact dictionary anagrams matched these letters." ;
matchesEl . hidden = false ;
setMatchesMessage ( matchesEl , "Try another letter set or a different spelling." ) ;
return ;
}
breakdownEl . textContent = ` Found ${ formatCount ( displayCount ) } anagrams for ${ formatCount ( letterCount ) } letters. ${ displayCount > visibleMatches . length ? ` Showing first ${ formatCount ( visibleMatches . length ) } . ` : "" } ` ;
const fragment = document . createDocumentFragment ( ) ;
visibleMatches . forEach ( ( match ) => {
const cardEl = document . createElement ( "article" ) ;
cardEl . className = "alpha-gematria-match" ;
const wordEl = document . createElement ( "div" ) ;
wordEl . className = "alpha-gematria-match-word" ;
wordEl . textContent = String ( match ? . word || "--" ) ;
cardEl . appendChild ( wordEl ) ;
const definition = String ( match ? . definition || "" ) . trim ( ) ;
if ( definition ) {
const definitionEl = document . createElement ( "div" ) ;
definitionEl . className = "alpha-gematria-match-definition" ;
definitionEl . textContent = definition ;
cardEl . appendChild ( definitionEl ) ;
}
fragment . appendChild ( cardEl ) ;
} ) ;
matchesEl . replaceChildren ( fragment ) ;
matchesEl . hidden = false ;
}
async function renderAnagramResult ( ) {
const { resultEl , breakdownEl , matchesEl } = getElements ( ) ;
if ( ! resultEl || ! breakdownEl || ! matchesEl ) {
return ;
}
const rawText = state . anagramInputText ;
if ( ! String ( rawText || "" ) . trim ( ) ) {
resultEl . textContent = "Anagrams: --" ;
breakdownEl . textContent = "Enter letters to search for exact dictionary anagrams." ;
matchesEl . hidden = false ;
setMatchesMessage ( matchesEl , "Anagram Maker finds exact word anagrams from the API word index." ) ;
return ;
}
const requestId = state . anagramRequestId + 1 ;
state . anagramRequestId = requestId ;
resultEl . textContent = "Anagrams: --" ;
breakdownEl . textContent = "Searching anagram index..." ;
matchesEl . hidden = false ;
setMatchesMessage ( matchesEl , "Loading anagrams..." ) ;
try {
const payload = await loadAnagramLookup ( rawText ) ;
if ( requestId !== state . anagramRequestId || ! isAnagramMode ( ) ) {
return ;
}
renderAnagramMatches ( payload ) ;
} catch {
if ( requestId !== state . anagramRequestId || ! isAnagramMode ( ) ) {
return ;
}
resultEl . textContent = "Anagrams: --" ;
breakdownEl . textContent = "Anagram lookup is unavailable right now." ;
matchesEl . hidden = false ;
setMatchesMessage ( matchesEl , "Unable to load anagrams from the API." ) ;
}
}
2026-03-07 05:17:50 -08:00
function computeGematria ( text , cipher , baseAlphabet ) {
const normalizedInput = normalizeGematriaText ( text ) ;
const scriptMap = state . scriptCharMap instanceof Map
? state . scriptCharMap
: new Map ( ) ;
const letterParts = [ ] ;
let total = 0 ;
let count = 0 ;
[ ... normalizedInput ] . forEach ( ( char ) => {
const mappedLetters = baseAlphabet . includes ( char )
? char
: ( scriptMap . get ( char ) || "" ) ;
if ( ! mappedLetters ) {
return ;
}
[ ... mappedLetters ] . forEach ( ( mappedChar ) => {
const index = baseAlphabet . indexOf ( mappedChar ) ;
if ( index < 0 ) {
return ;
}
const value = Number ( cipher . values [ index ] ) ;
if ( ! Number . isFinite ( value ) ) {
return ;
}
count += 1 ;
total += value ;
letterParts . push ( ` ${ mappedChar . toUpperCase ( ) } ( ${ value } ) ` ) ;
} ) ;
} ) ;
return {
total ,
count ,
breakdown : letterParts . join ( " + " )
} ;
}
2026-03-09 03:07:02 -07:00
function renderForwardGematriaResult ( ) {
2026-03-07 05:17:50 -08:00
const { resultEl , breakdownEl } = getElements ( ) ;
if ( ! resultEl || ! breakdownEl ) {
return ;
}
const db = state . db || getFallbackGematriaDb ( ) ;
if ( ! ( state . scriptCharMap instanceof Map ) || ! state . scriptCharMap . size ) {
refreshScriptMap ( db . baseAlphabet ) ;
}
const cipher = getActiveGematriaCipher ( ) ;
if ( ! cipher ) {
resultEl . textContent = "Total: --" ;
breakdownEl . textContent = "No ciphers available." ;
return ;
}
2026-03-09 03:07:02 -07:00
const { total , count , breakdown } = computeGematria ( state . forwardInputText , cipher , db . baseAlphabet ) ;
2026-03-07 05:17:50 -08:00
resultEl . textContent = ` Total: ${ total } ` ;
if ( ! count ) {
breakdownEl . textContent = ` Using ${ cipher . name } . Enter English, Greek, or Hebrew letters to calculate. ` ;
return ;
}
breakdownEl . textContent = ` ${ cipher . name } · ${ count } letters · ${ breakdown } = ${ total } ` ;
}
2026-03-09 03:07:02 -07:00
function renderGematriaResult ( ) {
updateModeUi ( ) ;
if ( isReverseMode ( ) ) {
void renderReverseLookupResult ( ) ;
return ;
}
2026-03-09 14:43:03 -07:00
if ( isAnagramMode ( ) ) {
void renderAnagramResult ( ) ;
return ;
}
2026-03-09 03:07:02 -07:00
renderForwardGematriaResult ( ) ;
}
2026-03-07 05:17:50 -08:00
function bindGematriaListeners ( ) {
2026-03-09 14:43:03 -07:00
const { cipherEl , inputEl , modeEls } = getElements ( ) ;
2026-03-07 05:17:50 -08:00
if ( state . listenersBound || ! cipherEl || ! inputEl ) {
return ;
}
cipherEl . addEventListener ( "change" , ( ) => {
state . activeCipherId = String ( cipherEl . value || "" ) . trim ( ) ;
renderGematriaResult ( ) ;
} ) ;
inputEl . addEventListener ( "input" , ( ) => {
2026-03-09 03:07:02 -07:00
if ( isReverseMode ( ) ) {
state . reverseInputText = inputEl . value || "" ;
2026-03-09 14:43:03 -07:00
} else if ( isAnagramMode ( ) ) {
state . anagramInputText = inputEl . value || "" ;
2026-03-09 03:07:02 -07:00
} else {
state . forwardInputText = inputEl . value || "" ;
}
renderGematriaResult ( ) ;
} ) ;
2026-03-09 14:43:03 -07:00
getModeElements ( modeEls ) . forEach ( ( modeEl ) => {
modeEl . addEventListener ( "change" , ( ) => {
if ( ! modeEl . checked ) {
return ;
}
state . activeMode = String ( modeEl . value || "forward" ) . trim ( ) || "forward" ;
updateModeUi ( ) ;
renderGematriaResult ( ) ;
} ) ;
2026-03-07 05:17:50 -08:00
} ) ;
state . listenersBound = true ;
}
function ensureCalculator ( ) {
const { cipherEl , inputEl , resultEl , breakdownEl } = getElements ( ) ;
if ( ! cipherEl || ! inputEl || ! resultEl || ! breakdownEl ) {
return ;
}
bindGematriaListeners ( ) ;
2026-03-09 03:07:02 -07:00
updateModeUi ( ) ;
2026-03-07 05:17:50 -08:00
void loadGematriaDb ( ) . then ( ( ) => {
refreshScriptMap ( ( state . db || getFallbackGematriaDb ( ) ) . baseAlphabet ) ;
renderGematriaCipherOptions ( ) ;
renderGematriaResult ( ) ;
} ) ;
}
function init ( nextConfig = { } ) {
config = {
... config ,
... nextConfig
} ;
2026-03-08 22:24:34 -07:00
const configuredDb = getConfiguredGematriaDb ( ) ;
if ( configuredDb ) {
state . db = sanitizeGematriaDb ( configuredDb ) ;
}
2026-03-07 05:17:50 -08:00
}
window . AlphabetGematriaUi = {
... ( window . AlphabetGematriaUi || { } ) ,
init ,
refreshScriptMap ,
ensureCalculator
} ;
} ) ( ) ;