import { classes } from '../dom' ; import { Rule } from '../rules/Rule' ; import Split from '../rules/Split' ; import dedupe from './dedupeRules' ; import recoverFromRule from './recoverFromRule' ; import { Book , Page } from '../book' ; import { RegionGetter } from 'regionize/dist/types/types' ; import { PageMaker } from '../types' ; const giveUp = ( rule , el ) => { console . warn ( `Couldn't apply ${ rule . name }, caused overflows twice when adding: ` , el ) ; } ; interface PageRule extends Rule { eachPage : ( pg : Page , book : Book ) => void ; } interface BeforeAddRule extends Rule { selector : string ; beforeAdd : ( ... args : any ) => HTMLElement ; } interface AfterAddRule extends Rule { selector : string ; afterAdd : ( ... args : any ) => HTMLElement ; } interface OffsetRule extends Rule { pageNumberOffset : number ; } interface AvoidSplitRule extends Rule { avoidSplit : boolean ; } interface DidSplitRule extends Rule { didSplit : ( a : HTMLElement , b : HTMLElement ) => void ; } function isPageRule ( rule ) { return rule . eachPage ; } function isBeforeAddRule ( rule ) { return ! ! rule . selector && rule . beforeAdd ; } function isAfterAddRule ( rule ) { return ! ! rule . selector && rule . afterAdd ; } function isOffsetRule ( rule ) { return rule . pageNumberOffset ; } function isDidSplitRule ( rule ) { return ! ! rule . selector && rule . didSplit ; } function isAvoidSplitRule ( rule ) { return ! ! rule . selector && rule . avoidSplit ; } class RuleSet { pageNumberOffset : number ; pageRules : PageRule [ ] ; beforeAddRules : BeforeAddRule [ ] ; afterAddRules : AfterAddRule [ ] ; didSplitRules : DidSplitRule [ ] ; selectorsNotToSplit : string [ ] ; shouldTraverse : ( el : HTMLElement ) => boolean ; constructor ( rules ) { const offsetRule = rules . find ( isOffsetRule ) ; this . pageNumberOffset = offsetRule ?. pageNumberOffset ?? 0 ; this . pageRules = rules . filter ( isPageRule ) ; this . beforeAddRules = rules . filter ( isBeforeAddRule ) ; this . afterAddRules = rules . filter ( isAfterAddRule ) ; this . selectorsNotToSplit = rules . filter ( isAvoidSplitRule ) . map ( r => r . selector ) ; this . didSplitRules = rules . filter ( isDidSplitRule ) ; rules . filter ( r => r . setup ) . forEach ( r => r . setup ( ) ) ; this . applySplitRules = this . applySplitRules . bind ( this ) ; const allSelectors = rules . map ( r => r . selector ) . filter ( sel => ! ! sel ) . join ( ', ' ) ; if ( allSelectors ) { const shouldTraverse = ( el ) => ! ! el . querySelector ( allSelectors ) ; this . shouldTraverse = shouldTraverse . bind ( this ) ; } else { this . shouldTraverse = ( ) => false ; } } applySplitRules ( original , clone ) { original . classList . add ( classes . toNext ) ; clone . classList . add ( classes . fromPrev ) ; this . didSplitRules . filter ( r => original . matches ( r . selector ) ) . forEach ( rule => { rule . didSplit ( original , clone ) ; } ) ; } applyPageDoneRules ( pg , book ) { this . pageRules . forEach ( rule => rule . eachPage ( pg , book ) ) ; } finishEveryPage ( book ) { this . pageRules . forEach ( rule => book . pages . forEach ( pg => rule . eachPage ( pg , book ) ) ) ; } applyBeforeAddRules ( element , book , continueOnNewPage , makeNewPage ) { let addedElement = element ; const matchingRules = this . beforeAddRules . filter ( rule => addedElement . matches ( rule . selector ) ) ; matchingRules . forEach ( rule => { addedElement = rule . beforeAdd ( addedElement , book , continueOnNewPage , makeNewPage ) ; } ) ; return addedElement ; } applyAfterAddRules ( originalElement , book , continueOnNewPage , makeNewPage ) { let addedElement = originalElement ; const attemptRecovery = ( el ) => recoverFromRule ( el , book , continueOnNewPage ) ; const matchingRules = this . afterAddRules . filter ( rule => addedElement . matches ( rule . selector ) ) ; const uniqueRules = dedupe ( matchingRules ) as AfterAddRule [ ] ; uniqueRules . forEach ( rule => { const retry = ( el ) => { attemptRecovery ( el ) ; return rule . afterAdd ( el , book , continueOnNewPage , makeNewPage , ( ) => giveUp ( rule , el ) ) ; } ; addedElement = rule . afterAdd ( addedElement , book , continueOnNewPage , makeNewPage , retry ) ; } ) ; return addedElement ; } } export default RuleSet ;