import { parseCss , IStyleAttribute } from "./parsers/nCSSParser" ; import * as accepted from "./FormatterConstants" ; const $get = ( selector , context = document ) => { try { const nodes = context . querySelectorAll ( selector ) ; return Array . prototype . slice . call ( nodes || [ ] ) ; } catch ( ex ) { return [ ] ; } } ; export default class HTMLToFormatterConverter { param htmlInput param cssInput public static generateFormatter ( htmlInput , cssInput = "" , isTest ? ) { const parsedDocument = this . convertToDocument ( htmlInput ) ; const inputStyles = `${ this . getStylesFromInternalTags ( parsedDocument ) }\n${ cssInput }` ; const styleObjectList = parseCss ( inputStyles ) || [ ] ; const styleObjectMap = { } ; styleObjectList . forEach ( ( rule ) => { const matchedNodes = $get ( rule . selector , parsedDocument ) ; styleObjectMap [ rule . selector ] = rule ; matchedNodes . forEach ( ( node ) => { const existing = node . getAttribute ( "inline-css" ) || "" ; const inlineAttribute = parsedDocument . createAttribute ( "inline-css" ) ; inlineAttribute . value = existing + ";" + rule . selector ; node . attributes . setNamedItem ( inlineAttribute ) ; } ) ; } ) ; this . setStyleAttributeRecursively ( parsedDocument . body , styleObjectMap ) ; const generated = this . elementToJSON ( parsedDocument . body . children [ 0 ] as HTMLElement ) ; return { json : generated , html : parsedDocument . body . children [ 0 ] } ; } private static convertToDocument ( htmlString ) { const parser = new DOMParser ( ) ; const doc = parser . parseFromString ( htmlString , "text/html" ) ; return doc ; } private static getStylesFromInternalTags ( parsedDocument ) { const styleTagsList = $get ( "style" , parsedDocument ) ; return styleTagsList . reduce ( ( internalcss , tag ) => `${ internalcss }\n${ tag . innerHTML }` , "" ) ; } private static setComputedStyles ( node , styleObjectMap ) { const allMatchedSelectors = node . getAttribute ( "inline-css" ) ; let stylesToApply = "" ; if ( allMatchedSelectors ) { allMatchedSelectors . split ( ";" ) . forEach ( ( selector ) => { if ( styleObjectMap [ selector ] ) { stylesToApply += styleObjectMap [ selector ] . style + ";" ; } } ) ; } const inlineStyle = node . getAttribute ( "style" ) ; let finalStyleString = stylesToApply && inlineStyle ? stylesToApply + ";" + inlineStyle : inlineStyle || stylesToApply ; node . setAttribute ( "style" , finalStyleString ) ; } public static elementToJSON ( elm , level = 0 ) { const tagName = elm && elm . tagName && elm . tagName . toLowerCase ( ) ; if ( ! tagName || ! accepted . OK_ELMS [ tagName ] ) { return ; } const jsonVal = { ... ( level === 0 ? { $schema : accepted . SCHEMA_URI , debugMode : true } : { } ) , elmType : tagName } ; for ( let index = 0 ; index < elm . attributes . length ; index ++ ) { const element = elm . attributes [ index ] ; if ( ! accepted . OK_ATTRS [ element . nodeName ] ) { continue ; } if ( element . nodeName !== "style" ) { if ( ! jsonVal . attributes ) jsonVal . attributes = { } ; jsonVal . attributes [ element . nodeName ] = element . textContent ; } else if ( element . textContent ) { let styleObj = { } ; element . textContent . split ( ";" ) . forEach ( ( element ) => { let keyValuePair = element . split ( ":" ) ; if ( keyValuePair . length === 2 ) { styleObj [ keyValuePair [ 0 ] ] = keyValuePair [ 1 ] ; } } ) ; jsonVal . style = styleObj ; } } if ( elm . children . length === 0 && ! ! elm . textContent ) { jsonVal . txtContent = elm . textContent . replace ( /\n/g , "" ) ; } for ( let index = 0 ; index < elm . children . length ; index ++ ) { if ( index === 0 ) jsonVal . children = [ ] ; const element = elm . children [ index ] as HTMLElement ; const childNode = this . elementToJSON ( element , level + 1 ) ; if ( childNode ) { jsonVal . children . push ( childNode ) ; } } return jsonVal ; } private static setStyleAttributeRecursively ( node , styleMap ) { [ ] . slice . call ( node . children ) . forEach ( ( childElement ) => { this . setComputedStyles ( childElement , styleMap ) ; this . setStyleAttributeRecursively ( childElement , styleMap ) ; } ) ; } }