'use strict' ; import type DataEventEmitter from '../DataEventEmitter' ; import type JSON from '../../Core/JSON' ; import DataStore from './DataStore.js' ; import DataTable from '../DataTable.js' ; import H from '../../Core/Globals.js' ; const { win } = H ; import HTMLTableParser from '../Parsers/HTMLTableParser.js' ; import U from '../../Core/Utilities.js' ; const { merge , objectEach } = U ; /** eslint-disable valid-jsdoc */ private class HTMLTableStore extends DataStore < HTMLTableStore . Event > { protected static readonly defaultOptions : HTMLTableStore . Options = { table : '' } ; static readonly defaultExportOptions : HTMLTableStore . ExportOptions = { decimalPoint : null , exportIDColumn : false , useRowspanHeaders : true , useMultiLevelHeaders : true } ; param { DataTable } table param { HTMLTableStore . OptionsType } options param { DataParser } parser public constructor ( table = new DataTable ( ) , options = { } , parser ? ) { super ( table ) ; this . tableElement = null ; this . options = merge ( HTMLTableStore . defaultOptions , options ) ; this . parserOptions = this . options ; this . parser = parser || new HTMLTableParser ( this . options , this . tableElement ) ; } todo public readonly options : ( HTMLTableStore . Options & HTMLTableParser . OptionsType ) ; /**
     * The attached parser, which can be replaced in the constructor
     */ public readonly parser : HTMLTableParser ; /**
     * The table element to create the store from. Is either supplied directly
     * or is fetched by an ID.
     */ public tableElement : ( HTMLElement | null ) ; public tableID ? : string ; /**
     * The options that were passed to the parser.
     */ private parserOptions : HTMLTableParser . OptionsType ; /**
     * Handles retrieving the HTML table by ID if an ID is provided
     */ private fetchTable ( ) { const store = this , { table : tableHTML } = store . options ; let tableElement ; if ( typeof tableHTML === 'string' ) { store . tableID = tableHTML ; tableElement = win . document . getElementById ( tableHTML ) ; } else { tableElement = tableHTML ; store . tableID = tableElement . id ; } store . tableElement = tableElement ; } param { DataEventEmitter . EventDetail } eventDetail emits emits emits public load ( eventDetail ? ) { const store = this ; store . fetchTable ( ) ; store . table . deleteColumns ( ) ; store . emit ( { type : 'load' , detail : eventDetail , table : store . table , tableElement : store . tableElement } ) ; if ( ! store . tableElement ) { store . emit ( { type : 'loadError' , detail : eventDetail , error : 'HTML table not provided, or element with ID not found' , table : store . table } ) ; return ; } store . parser . parse ( merge ( { tableHTML : store . tableElement } , store . options ) , eventDetail ) ; store . table . setColumns ( store . parser . getTable ( ) . getColumns ( ) ) ; store . emit ( { type : 'afterLoad' , detail : eventDetail , table : store . table , tableElement : store . tableElement } ) ; } param { HTMLTableStore . ExportOptions } exportOptions return { string } private getHTMLTableForExport ( exportOptions = { } ) { const options = exportOptions , decimalPoint = options . useLocalDecimalPoint ? ( 1.1 ) . toLocaleString ( ) [ 1 ] : '.' , exportNames = ( this . parserOptions . firstRowAsNames !== false ) , useMultiLevelHeaders = options . useMultiLevelHeaders , useRowspanHeaders = options . useRowspanHeaders ; const isRowEqual = function ( row1 , row2 ) : boolean { let i = row1 . length ; if ( row2 . length === i ) { while ( i -- ) { if ( row1 [ i ] !== row2 [ i ] ) { return false ; } } } else { return false ; } return true ; } ; const getTableHeaderHTML = function ( topheaders , subheaders , rowLength ? ) : string { let html = '<thead>' , i = 0 , len = rowLength || subheaders && subheaders . length , next , cur , curColspan = 0 , rowspan ; if ( useMultiLevelHeaders && topheaders && subheaders && ! isRowEqual ( topheaders , subheaders ) ) { html += '<tr>' ; for ( ; i < len ; ++ i ) { cur = topheaders [ i ] ; next = topheaders [ i + 1 ] ; if ( cur === next ) { ++ curColspan ; } else if ( curColspan ) { html += getCellHTMLFromValue ( 'th' , 'highcharts-table-topheading' , 'scope="col" ' + 'colspan="' + ( curColspan + 1 ) + '"' , cur ) ; curColspan = 0 ; } else { if ( cur === subheaders [ i ] ) { if ( useRowspanHeaders ) { rowspan = 2 ; delete subheaders [ i ] ; } else { rowspan = 1 ; subheaders [ i ] = '' ; } } else { rowspan = 1 ; } html += getCellHTMLFromValue ( 'th' , 'highcharts-table-topheading' , 'scope="col"' + ( rowspan > 1 ? ' valign="top" rowspan="' + rowspan + '"' : '' ) , cur ) ; } } html += '</tr>' ; } if ( subheaders ) { html += '<tr>' ; for ( i = 0 , len = subheaders . length ; i < len ; ++ i ) { if ( typeof subheaders [ i ] !== 'undefined' ) { html += getCellHTMLFromValue ( 'th' , null , 'scope="col"' , subheaders [ i ] ) ; } } html += '</tr>' ; } html += '</thead>' ; return html ; } ; const getCellHTMLFromValue = function ( tag , classes , attrs , value ) : string { let val = value , className = 'text' + ( classes ? ' ' + classes : '' ) ; if ( typeof val === 'number' ) { val = val . toString ( ) ; if ( decimalPoint === ',' ) { val = val . replace ( '.' , decimalPoint ) ; } className = 'number' ; } else if ( ! value ) { val = '' ; className = 'empty' ; } return '<' + tag + ( attrs ? ' ' + attrs : '' ) + ' class="' + className + '">' + val + '</' + tag + '>' ; } ; const { columnNames , columnValues } = this . getColumnsForExport ( options . usePresentationOrder ) , htmlRows = [ ] , columnsCount = columnNames . length ; const rowArray = [ ] ; let tableHead = '' ; if ( exportNames ) { const subcategories = [ ] ; if ( useMultiLevelHeaders ) { columnValues . forEach ( ( column ) : void => { const subhead = ( column . shift ( ) || '' ) . toString ( ) ; subcategories . push ( subhead ) ; } ) ; tableHead = getTableHeaderHTML ( columnNames , subcategories ) ; } else { tableHead = getTableHeaderHTML ( null , columnNames ) ; } } for ( let columnIndex = 0 ; columnIndex < columnsCount ; columnIndex ++ ) { const columnName = columnNames [ columnIndex ] , column = columnValues [ columnIndex ] , columnLength = column . length ; const columnMeta = this . whatIs ( columnName ) ; let columnDataType ; if ( columnMeta ) { columnDataType = columnMeta . dataType ; } for ( let rowIndex = 0 ; rowIndex < columnLength ; rowIndex ++ ) { let cellValue = column [ rowIndex ] ; if ( ! rowArray [ rowIndex ] ) { rowArray [ rowIndex ] = [ ] ; } if ( ! ( typeof cellValue === 'string' || typeof cellValue === 'number' || typeof cellValue === 'undefined' ) ) { cellValue = ( cellValue || '' ) . toString ( ) ; } rowArray [ rowIndex ] [ columnIndex ] = getCellHTMLFromValue ( columnIndex ? 'td' : 'th' , null , columnIndex ? '' : 'scope="row"' , cellValue ) ; if ( columnIndex === columnsCount - 1 ) { htmlRows . push ( '<tr>' + rowArray [ rowIndex ] . join ( '' ) + '</tr>' ) ; } } } let caption = '' ; if ( options . tableCaption ) { caption = '<caption class="highcharts-table-caption">' + options . tableCaption + '</caption>' ; } return ( '<table>' + caption + tableHead + '<tbody>' + htmlRows . join ( '' ) + '</tbody>' + '</table>' ) ; } param { HTMLTableStore . ExportOptions } htmlExportOptions param { DataEventEmitter . EventDetail } eventDetail return { string } public save ( htmlExportOptions , eventDetail ? ) { const exportOptions = HTMLTableStore . defaultExportOptions ; objectEach ( this . parserOptions , function ( value , key ) : void { if ( key in exportOptions ) { exportOptions [ key ] = value ; } } ) ; return this . getHTMLTableForExport ( merge ( exportOptions , htmlExportOptions ) ) ; } } /**
 *
 *  Namespace
 *
 */ /**
 * Types for class-specific options and events
 */ namespace HTMLTableStore { /**
     * Type for event object fired from HTMLTableDataStore
     */ export type Event = ( ErrorEvent | LoadEvent ) ; /**
     * Options used in the constructor of HTMLTableDataStore
     */ export type OptionsType = Partial < ( HTMLTableStore . Options & HTMLTableParser . OptionsType ) > ; /**
     * Options for exporting the store as an HTML table
     */ export interface ExportOptions extends JSON . Object { decimalPoint ? : string | null ; exportIDColumn ? : boolean ; tableCaption ? : string ; useLocalDecimalPoint ? : boolean ; useMultiLevelHeaders ? : boolean ; useRowspanHeaders ? : boolean ; usePresentationOrder ? : boolean ; } /**
     * Provided event object on errors within HTMLTableDataStore
     */ export interface ErrorEvent extends DataStore . Event { type : 'loadError' ; error : ( string | Error ) ; } /**
     * Provided event object on load events within HTMLTableDataStore
     */ export interface LoadEvent extends DataStore . Event { type : ( 'load' | 'afterLoad' ) ; tableElement ? : ( HTMLElement | null ) ; } /**
     * Internal options for the HTMLTableDataStore class
     */ export interface Options { table : ( string | HTMLElement ) ; } } DataStore . addStore ( HTMLTableStore ) ; declare module './StoreType' { interface StoreTypeRegistry { HTMLTable : typeof HTMLTableStore ; } } export default HTMLTableStore ;