2020-06-26 11:59:13 +00:00
import { registerSearchEntries } from "../search" ;
2020-06-26 12:05:17 +00:00
import { findParent } from "../utils" ;
2020-06-26 11:59:13 +00:00
2020-06-26 12:05:17 +00:00
export function processChemistry ( root : HTMLElement ) : void {
// Fix inconsistencies with <p> on random parts
// Ideally I'd like a <p> or something on every part, wrapping it completely, but for now let's just kill 'em
root
. querySelectorAll (
"table.wikitable > tbody > tr:not(:first-child) > td:nth-child(2), .tooltiptext"
)
. forEach ( ( td ) = > {
const tmp = td . cloneNode ( ) as HTMLElement ;
// The cast to Array is necessary because, while childNodes's NodeList technically has a forEach method, it's a live list and operations mess with its lenght in the middle of the loop.
// Nodes can only have one parent so append removes them from the original NodeList and shifts the following one back into the wrong index.
Array . from ( td . childNodes ) . forEach ( ( el ) = > {
if ( el instanceof HTMLParagraphElement ) {
tmp . append ( . . . el . childNodes ) ;
} else {
tmp . append ( el ) ;
}
} ) ;
td . parentNode . replaceChild ( tmp , td ) ;
} ) ;
// Enrich "x part" with checkboxes and parts
Array . from ( root . querySelectorAll ( "td" ) )
. filter ( ( el ) = > el . textContent . indexOf ( " part" ) >= 0 )
. forEach ( ( el ) = > {
el . innerHTML = el . innerHTML . replace (
/((\d+)\s+(?:parts?|units?))(.*?(?:<\/a>|\n|$))/gi ,
( match , . . . m ) = >
` <label class="bgus_part ${
m [ 2 ] . includes ( "</a>" ) ? "bgus_part_tooltip" : ""
} " data-amount=" $ {
m [ 1 ]
} "><input type=" checkbox " class='bgus_checkbox bgus_hidden'/> <span class=" bgus_part_label " data-src=" $ {
m [ 0 ]
} " > $ { m [ 0 ] } < / span > < / label > $ { m [ 2 ] . replace (
/(<a .+?<\/a>)/gi ,
'<span class="bgus_nobreak bgus_nested_element">$1<span class="bgus_twistie"></span></span>'
) } `
) ;
} ) ;
// Wrap every recipe with extra metadata
root . querySelectorAll < HTMLElement > ( ".bgus_part" ) . forEach ( ( el ) = > {
if ( "parts" in el . parentElement . dataset ) {
el . parentElement . dataset . parts = (
parseInt ( el . parentElement . dataset . parts , 10 ) +
parseInt ( el . dataset . amount , 10 )
) . toString ( ) ;
} else {
el . parentElement . dataset . parts = el . dataset . amount ;
}
} ) ;
// Restructure recipes to work in a narrow window
root
. querySelectorAll < HTMLElement > ( "div[data-name] .wikitable.sortable tr" )
. forEach ( ( row ) = > {
const sectionEl = findParent (
row ,
( sel ) = > "name" in sel . dataset && sel . dataset . name !== ""
) ;
const section = sectionEl . dataset . name ;
if ( row . querySelector ( "td" ) === null ) {
// Remove unused rows if found
const headers = row . querySelectorAll ( "th" ) ;
headers . forEach ( ( th , i ) = > {
if ( i < 2 ) {
th . classList . add ( "table-head" ) ;
return ;
}
th . parentElement . removeChild ( th ) ;
} ) ;
return ;
}
const rows = Array . from ( row . querySelectorAll ( "td" ) ) . slice ( 1 ) ;
2021-08-20 14:33:54 +00:00
let conditions : HTMLTableCellElement = null ;
let explosive : HTMLTableCellElement = null ;
2021-02-12 09:28:39 +00:00
let ph : HTMLTableCellElement = null ;
2020-06-30 11:48:47 +00:00
let treatment : HTMLTableCellElement = null ;
let desc : HTMLTableCellElement = null ;
let metabolism : HTMLTableCellElement = null ;
let overdose : HTMLTableCellElement = null ;
let addiction : HTMLTableCellElement = null ;
2020-06-26 12:05:17 +00:00
// Handle special cases
switch ( section ) {
case "Components" :
2021-02-12 09:28:39 +00:00
[ ph , desc ] = rows ;
break ;
2020-06-26 12:05:17 +00:00
case "Virology Recipes" :
[ desc ] = rows ;
break ;
case "Narcotics" :
2021-02-12 09:28:39 +00:00
[ ph , desc , metabolism , overdose , addiction ] = rows ;
2020-06-26 12:05:17 +00:00
break ;
case "Other Reagents" :
2021-02-12 09:28:39 +00:00
[ ph , desc , metabolism ] = rows ;
break ;
case "Explosive Strength" :
2021-08-20 14:33:54 +00:00
[ conditions , desc , explosive ] = rows ;
break ;
2020-06-26 12:05:17 +00:00
case "Mutation Toxins" :
[ desc , metabolism ] = rows ;
break ;
default :
// All fields
2021-02-12 09:28:39 +00:00
[ ph , treatment , desc , metabolism , overdose , addiction ] = rows ;
2020-06-26 12:05:17 +00:00
}
const title = row . querySelector ( "th" ) ;
let content = ` <div class="reagent-header"> ${ title . innerHTML } </div> ` ;
if ( treatment ) {
content += ` <p class="treatment"> ${ treatment . innerHTML } </p> ` ;
}
if ( metabolism ) {
content += ` <p class="metabolism"> ${ metabolism . innerHTML } </p> ` ;
}
2021-08-20 14:33:54 +00:00
if ( conditions ) {
content += ` <p class="conditions"> ${ conditions . innerHTML } </p> ` ;
}
if ( explosive ) {
content += ` <p class="explosive"> ${ explosive . innerHTML } </p> ` ;
}
2020-06-26 12:05:17 +00:00
if ( addiction && addiction . innerHTML . trim ( ) !== "N/A" ) {
content += ` <p class="addiction"> ${ addiction . innerHTML } </p> ` ;
}
if ( overdose && overdose . innerHTML . trim ( ) !== "N/A" ) {
content += ` <p class="overdose"> ${ overdose . innerHTML } </p> ` ;
}
if ( desc ) {
content += ` <p> ${ desc . innerHTML } </p> ` ;
}
2021-02-12 09:28:39 +00:00
if ( ph ) {
2021-02-12 10:05:40 +00:00
content += ` <div class="ph"> ${ ph . innerHTML } </div> ` ;
2021-02-12 09:28:39 +00:00
}
2020-06-26 12:05:17 +00:00
title . classList . add ( "reagent-ext" ) ;
title . innerHTML = content ;
if ( desc ) desc . parentElement . removeChild ( desc ) ;
if ( treatment ) treatment . parentElement . removeChild ( treatment ) ;
if ( metabolism ) metabolism . parentElement . removeChild ( metabolism ) ;
2021-08-20 14:33:54 +00:00
if ( conditions ) conditions . parentElement . removeChild ( conditions ) ;
if ( explosive ) explosive . parentElement . removeChild ( explosive ) ;
2020-06-26 12:05:17 +00:00
if ( overdose ) overdose . parentElement . removeChild ( overdose ) ;
if ( addiction ) addiction . parentElement . removeChild ( addiction ) ;
2021-02-12 09:28:39 +00:00
if ( ph ) ph . parentElement . removeChild ( ph ) ;
2020-06-26 12:05:17 +00:00
} ) ;
}
export function chemistryScript ( root : HTMLElement ) : void {
2020-06-26 11:59:13 +00:00
// Add event to autofill child checkboxes
root
. querySelectorAll ( ".bgus_part_tooltip > .bgus_checkbox" )
. forEach ( ( box : HTMLInputElement ) = > {
const tooltip = box . parentElement . nextElementSibling ;
box . addEventListener ( "click" , ( ) = > {
tooltip
. querySelectorAll ( ".bgus_checkbox" )
. forEach ( ( el : HTMLInputElement ) = > {
el . checked = box . checked ;
} ) ;
} ) ;
} ) ;
// Add event to collapse subsections
root . querySelectorAll ( ".bgus_nested_element" ) . forEach ( ( twistie ) = > {
twistie . addEventListener ( "click" , ( ) = > {
twistie . classList . toggle ( "bgus_collapsed" ) ;
} ) ;
} ) ;
const setPartSize = ( labels , ml ) = > {
labels . forEach ( ( el ) = > {
const part = el . parentElement . dataset . amount ;
const total = el . parentElement . parentElement . dataset . parts ;
const amt = Math . ceil ( ml * ( part / total ) ) ;
el . innerHTML = ` ${ amt } ml ` ;
// Lookup tooltips
let next = el . parentElement . nextElementSibling ;
while ( next ) {
if ( next . classList . contains ( "tooltip" ) ) {
const sublabels = [ ] ;
next . querySelector ( ".tooltiptext" ) . childNodes . forEach ( ( ch ) = > {
if ( ch . classList && ch . classList . contains ( "bgus_part" ) ) {
sublabels . push ( ch . querySelector ( ".bgus_part_label" ) ) ;
}
} ) ;
setPartSize ( sublabels , amt ) ;
}
if ( next . classList . contains ( "bgus_part" ) ) {
// Done searching
break ;
}
next = next . nextElementSibling ;
}
} ) ;
} ;
// Init fuzzy search with elements
const el = Array . from (
root . querySelectorAll < HTMLElement > (
2020-06-27 13:06:14 +00:00
"table.wikitable > tbody > tr:not(:first-child)"
2020-06-26 11:59:13 +00:00
)
) ;
2021-02-12 10:05:40 +00:00
2020-06-26 11:59:13 +00:00
registerSearchEntries (
2021-11-17 16:19:15 +00:00
Array . from (
root . querySelectorAll < HTMLElement > (
"table.wikitable > tbody > tr:not(:first-child) th .reagent-header"
)
) . map ( ( element , id ) = > ( {
2020-06-26 11:59:13 +00:00
page : "Guide_to_chemistry" ,
2021-11-17 16:19:15 +00:00
name : element.textContent.trim ( ) . replace ( /\n.+$/gm , "" ) . replace ( "▮" , "" ) ,
2020-06-26 11:59:13 +00:00
element ,
alignment : "center" ,
id ,
} ) )
) ;
document . body . addEventListener ( "keydown" , ( ev ) = > {
if ( ev . shiftKey ) {
switch ( ev . keyCode ) {
// SHIFT+C = Toggle checkboxes
case 67 : {
root . classList . toggle ( "bgus_cbox" ) ;
root
. querySelectorAll ( ".bgus_checkbox:checked" )
. forEach ( ( sel : HTMLInputElement ) = > {
sel . checked = false ;
} ) ;
break ;
}
// SHIFT+B = Set whole size (beaker?) for parts/units
case 66 : {
const size = parseInt (
prompt ( "Write target ml (0 to reset)" , "90" ) ,
10
) ;
if ( Number . isNaN ( size ) || size <= 0 ) {
// Reset to parts/unit
root
. querySelectorAll ( ".bgus_part_label" )
. forEach ( ( sel : HTMLElement ) = > {
sel . innerHTML = sel . dataset . src ;
} ) ;
return ;
}
setPartSize (
root . querySelectorAll ( "td > .bgus_part > .bgus_part_label" ) ,
+ size
) ;
break ;
}
default :
// Do nothing
}
}
} ) ;
2021-02-12 10:05:40 +00:00
// Prettify reaction conditions
const reactionPropertyRegexp = /<b>(.+):<\/b>(.+)/i ;
el . forEach ( ( element , id ) = > {
element . querySelectorAll < HTMLElement > ( ".ph" ) . forEach ( ( ph ) = > {
// Prepare table
const extras = [ ] ;
const table = document . createElement ( "table" ) ;
const tableHeaderRow = document . createElement ( "tr" ) ;
const tableValueRow = document . createElement ( "tr" ) ;
table . appendChild ( tableHeaderRow ) ;
table . appendChild ( tableValueRow ) ;
// Parse parameters
ph . innerHTML . split ( "<br>" ) . forEach ( ( prop ) = > {
if ( prop . trim ( ) === "N/A" ) {
return ;
}
const matcher = reactionPropertyRegexp . exec ( prop ) ;
if ( ! matcher ) {
extras . push ( prop ) ;
return ;
}
const [ reactionProperty , propValue ] = matcher
. slice ( 1 )
. map ( ( s ) = > s . trim ( ) ) ;
const header = document . createElement ( "th" ) ;
header . appendChild ( document . createTextNode ( reactionProperty ) ) ;
tableHeaderRow . appendChild ( header ) ;
const value = document . createElement ( "td" ) ;
value . appendChild ( document . createTextNode ( propValue ) ) ;
tableValueRow . append ( value ) ;
} ) ;
// Clear and re-add prettified data
ph . innerHTML = "" ;
if ( tableHeaderRow . children . length > 0 ) {
ph . appendChild ( table ) ;
}
ph . innerHTML += ` <p> ${ extras . join ( "<br>" ) } </p> ` ;
ph . classList . add ( "ph-ext" ) ;
} ) ;
} ) ;
2020-06-26 11:59:13 +00:00
}
2020-06-26 12:05:17 +00:00
export default { chemistryScript , processChemistry } ;