import ko , { Observable } from "knockout" ; import urlParameters from "../stores/url-parameters" ; import PageStyle from "./page-style" ; import stringUtil from "../utils/string-util" ; function getDocumentOptionsFromURL ( ) { const bookUrl = urlParameters . getParameter ( "b" ) ; const xUrl = urlParameters . getParameter ( "x" ) ; const fragment = urlParameters . getParameter ( "f" ) ; const style = urlParameters . getParameter ( "style" ) ; const userStyle = urlParameters . getParameter ( "userStyle" ) ; return { bookUrl : bookUrl [ 0 ] || null , xUrl : ! bookUrl [ 0 ] && xUrl . length && xUrl [ 0 ] ? xUrl : null , fragment : fragment [ 0 ] || null , authorStyleSheet : style . length ? style : [ ] , userStyleSheet : userStyle . length ? userStyle : [ ] } ; } class DocumentOptions { pageStyle : PageStyle ; dataUserStyleIndex : number ; bookUrl ? : Observable < string > ; xUrl ? : Observable < Array < string > | null > ; fragment ? : Observable < string > ; authorStyleSheet ? : Observable < Array < unknown > > ; userStyleSheet ? : Observable < Array < unknown > > ; constructor ( ) { const urlOptions = getDocumentOptionsFromURL ( ) ; this . bookUrl = ko . observable ( urlOptions . bookUrl || "" ) ; this . xUrl = ko . observable ( urlOptions . xUrl || null ) ; this . fragment = ko . observable ( urlOptions . fragment || "" ) ; this . authorStyleSheet = ko . observable ( urlOptions . authorStyleSheet ) ; this . userStyleSheet = ko . observable ( urlOptions . userStyleSheet ) ; this . pageStyle = new PageStyle ( ) ; this . dataUserStyleIndex = - 1 ; this . fragment . subscribe ( fragment => { if ( /^epubcfi\(\/([246]\/)?2!\)/ . test ( fragment ) ) { urlParameters . removeParameter ( "f" ) ; } else { const encoded = fragment . replace ( /[\s+&?=#\u007F-\uFFFF]+/g , encodeURIComponent ) ; urlParameters . setParameter ( "f" , encoded ) ; } } ) ; urlOptions . userStyleSheet . find ( ( userStyle , index ) => { if ( /^data:,.*?\/\*(?:<|%3C)viewer(?:>|%3E)\*\// . test ( userStyle ) ) { this . dataUserStyleIndex = index ; const data = userStyle . replace ( /^data:,/ , "" ) . replace ( /%(?![0-9A-Fa-f]{2})/g , "%25" ) ; const cssText = decodeURIComponent ( data ) ; this . pageStyle . cssText ( cssText ) ; return true ; } else { return false ; } } ) ; this . pageStyle . cssText . subscribe ( cssText => { this . updateUserStyleSheetFromCSSText ( cssText ) ; } ) ; } toObject ( ) { function convertStyleSheetArray ( arr ) { return arr . map ( url => ( { url } ) ) ; } const userStyleSheetArray = convertStyleSheetArray ( this . userStyleSheet ( ) ) ; if ( this . pageStyle . pageSizeMode ( ) == PageStyle . Mode . Default ) { userStyleSheetArray . unshift ( { text : "@page{size:auto}" } ) ; } return { fragment : this . fragment ( ) , authorStyleSheet : convertStyleSheetArray ( this . authorStyleSheet ( ) ) , userStyleSheet : userStyleSheetArray } ; } updateUserStyleSheetFromCSSText ( cssText ? ) { if ( cssText == undefined ) { cssText = this . pageStyle . toCSSText ( ) ; } const userStyleSheet = this . userStyleSheet ( ) ; if ( ! cssText || /^\s*(\/\*.*?\*\/\s*)*$/ . test ( cssText ) ) { if ( userStyleSheet . length <= ( this . dataUserStyleIndex == - 1 ? 0 : 1 ) ) { userStyleSheet . pop ( ) ; this . dataUserStyleIndex = - 1 ; this . userStyleSheet ( userStyleSheet ) ; urlParameters . removeParameter ( "userStyle" ) ; return ; } } const dataUserStyle = "data:," + stringUtil . percentEncodeForDataURI ( cssText . trim ( ) ) ; if ( this . dataUserStyleIndex == - 1 ) { userStyleSheet . push ( dataUserStyle ) ; this . dataUserStyleIndex = userStyleSheet . length - 1 ; } else { userStyleSheet [ this . dataUserStyleIndex ] = dataUserStyle ; } this . userStyleSheet ( userStyleSheet ) ; urlParameters . setParameter ( "userStyle" , dataUserStyle , this . dataUserStyleIndex ) ; } } export default DocumentOptions ;