Mon, 25 Mar 2024 17:14:56 +0100
Brought the retry attempts to read the DHT11 sensors to the main devices loop. The actual read function is now very simple. Called every 30 seconds when all is well, or 2 seconds if something is wrong.
/* tslint:disable */ /* eslint-disable */ (function ($) { class DataAdapter { constructor ( config ) { if ( !config ) { config = {}; } const that = Object.assign( this, config ); const generateKey = function () { const S4 = function () { return ( ( ( 1 + Math.random() ) * 0x10000 ) | 0 ).toString( 16 ).substring( 1 ); }; return S4(); }; that.key = generateKey(); that.boundSource = []; that.dataItemById = []; if ( that.allowAdd === undefined ) { that.allowAdd = true; } if ( that.allowRemove === undefined ) { that.allowRemove = true; } if ( that.allowUpdate === undefined ) { that.allowUpdate = true; } if ( config.observable === undefined ) { that.observable = true; } if ( !config.dataSource ) { that.dataSource = []; } if ( !config.dataFields ) { that.dataFields = []; } else { /* if (config.dataSource && config.dataSource.length > 0) { const keys = Object.keys(config.dataSource[0]); // that.dataFields = []; for (let i = 0; i < keys.length; i++) { } } */ } if ( !config.dataSourceType ) { that.dataSourceType = 'array'; } if ( !config.id ) { that.id = null; } if ( !config.autoFetch ) { that.autoFetch = true; } if ( config.dataFields ) { that.dataFields = config.dataFields; } Object.defineProperty( that, 'groupBy', { configurable: false, enumerable: true, get() { if ( !that._groupBy ) { return []; } return that._groupBy; }, set( value ) { const updateGrouping = () => { that.boundHierarchy = null; that.refreshHierarchy(); if ( that.onGroup ) { that.onGroup(); } } that._groupBy = [].concat(value); if ( that.isInitialized ) { updateGrouping(); } } } ); if ( !config.groupBy ) { that.groupBy = []; } else { if ( config.groupBy.toArray ) { that.groupBy = config.groupBy.toArray(); } else { that.groupBy = config.groupBy; } } if ( config && config.autoBind !== false ) { that.dataBind(); } that.isInitialized = true; } get dataFields() { const that = this; return that._dataFields; } set dataFields( value ) { const that = this; that._dataFields = that._getDataFieldObjects( value ); return that._dataFields; } _getDataFieldObjects( dataFields ) { //const that = this; let dataFieldObjects = []; if ( typeof dataFields === 'number' ) { const charCode = 'A'.charCodeAt( 0 ); let prefix = ''; let index = 0; for ( let i = 0; i < dataFields; i++ ) { const letter = String.fromCharCode( charCode + index ); index++; const label = prefix + letter; dataFieldObjects.push( { name: label, dataType: 'string' } ) if ( index >= 26 ) { index = 0; prefix += 'A'; } } } else if ( dataFields.length > 0 ) { for ( let i = 0; i < dataFields.length; i++ ) { const dataField = dataFields[ i ]; if ( typeof dataField === 'string' ) { const dataFieldParts = dataField.split( ':' ); const name = dataFieldParts[ 0 ].trim(); const dataType = dataFieldParts.length > 1 ? dataFieldParts[ 1 ].trim() : 'string'; dataFieldObjects.push( { name: name, dataType: dataType } ); } else { dataFieldObjects.push( dataField ); } } } return dataFieldObjects; } get dataSource() { const that = this; if ( !that._dataSource ) { that._dataSource = []; } return that._dataSource; } set dataSource( value ) { const that = this; that._dataSource = value; if ( that.isInitialized ) { that.boundSource = false === that.observable ? [] : new JQX.ObservableArray(); that.dataItemById = []; that.bindingCompleted = false; that.dataBind(); } } get canNotify() { const that = this; if ( that._canNotify === undefined ) { that._canNotify = true; } return that._canNotify; } set canNotify( value ) { const that = this; that._canNotify = value; } _notify( changeArgs ) { const that = this; if ( !that.canNotify ) { return; } if ( that.notifyFn ) { that.notifyFn( changeArgs ); } } notify( notifyFn ) { const that = this; if ( notifyFn ) { that.notifyFn = notifyFn; } } toArray() { const that = this; return that.boundSource.toArray(); } dataBind() { const that = this; that.clear(); const completed = () => { that._onBindingComplete(); } if ( typeof that.dataSource === 'string' && ( that.dataSource.indexOf( '.json' ) >= 0 ) ) { that.url = that.dataSource; that.dataSourceType = 'json'; new Ajax( that, ( data/*, status*/ ) => { that.dataSource = data; that._bindToJSON(); } ); } else if ( typeof that.dataSource === 'string' && ( that.dataSource.indexOf( '.xlsx' ) >= 0 ) ) { that.url = that.dataSource; that.dataSourceType = 'xlsx'; new Ajax( that, ( data/*, status*/ ) => { if ( !data[ 0 ] ) { data = []; that._bindToArray(); completed(); return; } const keys = Object.keys( data[ 0 ] ); const dataFieldMap = {}; const dataRows = []; if ( that.exportHeader !== false ) { let index = 0; for ( let key in keys ) { const name = keys[ key ]; dataFieldMap[ name ] = that.dataFields[ index++ ].name; } for ( let i = 1; i < data.length; i++ ) { const row = data[ i ]; const dataRow = {}; for ( let key in keys ) { const name = keys[ key ]; dataRow[ dataFieldMap[ name ] ] = row[ name ]; } dataRows.push( dataRow ); } that.dataSource = dataRows; } that._bindToArray(); completed(); } ); } else if ( typeof that.dataSource === 'string' && ( that.dataSource.indexOf( '.csv' ) >= 0 ) ) { that.dataSourceType = 'csv'; new Ajax( that, (/*data, status*/ ) => { that._bindToArray(); } ); } else if ( typeof that.dataSource === 'string' && ( that.dataSource.indexOf( '.tsv' ) >= 0 ) ) { that.dataSourceType = 'tsv'; new Ajax( that, (/*data, status*/ ) => { } ); } else if ( that.dataSourceType === 'array' ) { that._bindToArray(); completed(); } else if ( that.dataSourceType === 'json' ) { that._bindToJSON(); completed(); } } _onBindingComplete() { const that = this; that._buildHierarchy(); if ( that.onBindingComplete ) { that.onBindingComplete( { data: that.boundSource } ); } if ( that._notify ) { that._notify( { action: 'bindingComplete', data: that.boundSource } ); } that.bindingCompleted = true; } refreshHierarchy() { const that = this; that._buildHierarchy(); } find() { const that = this; return that.boundSource.find.apply( that.boundSource, arguments ); } onVirtualDataSourceRequested( requestCallback, details ) { const that = this; let first = details ? details.first : Infinity; let last = details ? details.last : Infinity; let row = details ? details.row : null; if ( undefined === first ) { first = Infinity; } if ( undefined === last ) { last = Infinity; } that.virtualFirstIndex = first; that.virtualLastIndex = last; if ( that.virtualDataSource ) { const getDataSource = function ( ExcelAdapterSettings ) { if ( ExcelAdapterSettings.virtualDataSourceLength !== undefined ) { that.virtualDataSourceLength = ExcelAdapterSettings.virtualDataSourceLength; } new JQX.ExcelAdapter( { dataSource: ExcelAdapterSettings.dataSource, dataFields: ExcelAdapterSettings.dataFields || that.dataFields, data: details, onBindingComplete( event ) { if ( that.virtualDataSourceOnExpand && row ) { if ( event.data && event.data.length > 0 ) { that.add( event.data, row.$.id ); } else { row.leaf = true; } if ( that.onFilter ) { that.onFilter() } requestCallback(); return; } if ( first === Infinity ) { that.add( event.data ); } else { let items = []; let indexes = []; for ( let i = 0; i < event.data.length; i++ ) { const item = event.data[ i ]; if ( first + i <= last ) { items.push( item ); indexes.push( first + i ); } } that.update( indexes, items ); } if ( that.onFilter ) { that.onFilter() } requestCallback(); } } ); } let hasCache = false; const isEmpty = ( obj ) => Object.entries( obj ).length === 0 && ( obj.constructor === Object || obj.constructor === Array ); const canCache = isEmpty( details.sorting ) && isEmpty( details.filtering ) && isEmpty( details.grouping ) && !details.row && ( details.action !== 'filter' && details.action !== 'sort' && details.action !== 'group' ); if ( that.virtualDataSourceCache && first !== Infinity && canCache ) { let cachedCount = 0; for ( let i = first; i < last; i++ ) { if ( !that[ i ].$.isEmpty ) { cachedCount++; } } if ( cachedCount === last - first ) { hasCache = true; } } if ( hasCache ) { requestCallback(); } else { if ( details.action === 'expand' ) { that.virtualDataSourceOnExpand( getDataSource, { first: first, last: last, row: details.row, sorting: details.sorting, filtering: details.filtering, grouping: details.grouping, action: details.action } ); } else { that.virtualDataSource( getDataSource, { first: first, last: last, sorting: details.sorting, filtering: details.filtering, filterOperator: details.filterOperator || 'and', grouping: details.grouping, action: details.action } ); } } } else { requestCallback(); } } add( item, parentId ) { const that = this; if ( !item ) { return; } let result = true; const addItem = function ( item ) { const itemObject = that._getDataItem( item, that.boundSource.length ); that[ that.boundSource.length ] = itemObject; that.dataItemById[ itemObject.$.id ] = itemObject; const pushResult = that.boundSource.push( itemObject ); if ( parentId !== undefined ) { itemObject.$.parentId = parentId; } if ( !pushResult ) { result = false; } return itemObject; } if ( item.length ) { let itemObjects = []; for ( let i = 0; i < item.length; i++ ) { const itemObject = addItem( item[ i ] ); itemObjects.push( itemObject ); } that._notify( { action: 'add', data: itemObjects } ); } else { const itemObject = addItem( item ); that._notify( { action: 'add', data: itemObject } ); } that.refreshHierarchy(); return result; } refreshIndexes() { const that = this; for (let i = 0; i < that.boundSource.length; i++) { that[i] = that.boundSource[i]; that[i].$.index = i; that.dataItemById[that[i].$.id] = that[i]; } let i = that.boundSource.length; while (that[i]) { delete that[i]; i++; } } removeLast() { const that = this; delete that[that.boundSource.length - 1]; const result = that.boundSource.pop(); delete that.dataItemById[result.$.id]; that._notify({ action: 'removeLast', data: result }); that.refreshHierarchy(); return result; } removeAt(index) { const that = this; const item = that.boundSource[index]; if (!item) { throw new Error('Invalid Item Index'); } that.boundSource.splice(index, 1); delete that.dataItemById[item.$.id]; that.refreshIndexes(); that._notify({ action: 'remove', index: index, data: item }); that.refreshHierarchy(); } update( index, dataSourceItem ) { const that = this; if ( JQX.Utilities.Types.isArray( index ) && JQX.Utilities.Types.isArray( dataSourceItem ) ) { if ( index.length === 0 && dataSourceItem.length === 0 ) { that.refreshHierarchy(); return; } } if ( dataSourceItem.length && index.length ) { let itemObjects = []; for ( let i = 0; i < index.length; i++ ) { const itemObject = that._getDataItem( dataSourceItem[ i ], index[ i ] ); const currentIndex = index[ i ]; itemObjects.push( itemObject ); that.boundSource[ currentIndex ] = itemObject; that[ currentIndex ] = that.boundSource[ currentIndex ]; that.dataItemById[ itemObject.$.id ] = that[ currentIndex ]; } that._notify( { action: 'update', index: index, data: itemObjects } ); that.refreshHierarchy(); return; } const itemObject = that._getDataItem( dataSourceItem, index ); that.boundSource[ index ] = itemObject; that[ index ] = that.boundSource[ index ]; that.dataItemById[ itemObject.$.id ] = that[ index ]; that._notify( { action: 'update', index: index, data: itemObject } ); that.refreshHierarchy(); return itemObject; } insert( index, item ) { const that = this; item = that._getDataItem( item, index ); const result = that.boundSource.splice( index, 0, item ); that.refreshIndexes(); that._notify( { action: 'insert', index: index, data: item } ); that.refreshHierarchy(); return result; } move( from, to ) { if ( to > from && to - from === 1 || from === to ) { return; } const that = this, recordToMove = that.boundSource.splice( from, 1 )[ 0 ]; if ( to > from ) { to--; that.boundSource.splice( to, 0, recordToMove ); } else { that.boundSource.splice( to, 0, recordToMove ); } that.refreshIndexes(); that._notify( { action: 'move', index: to, data: that.boundSource[ to ] } ); that.refreshHierarchy(); } indexOf( item ) { const that = this; const index = that.boundSource.indexOf( item ); return index; } get length() { const that = this; if ( that.virtualDataSourceLength !== undefined ) { return that.virtualDataSourceLength; } if ( that.dataSourceLength ) { return that.dataSourceLength; } if ( typeof ( that.dataSource ) === 'number' ) { return that.dataSource; } if ( that.bindingCompleted ) { return that.boundSource.length; } if ( that.dataSource && typeof that.dataSource !== 'string' && that.dataSource.length ) { return that.dataSource.length; } return that.boundSource.length; } clear() { const that = this; if ( !that.isInitialized ) { that._cachedValues = []; that.dataItemById = []; return; } for ( let i = 0; i < that.boundSource.length; i++ ) { delete that[ i ]; } that._cachedValues = []; that.boundSource = that.observable ? new JQX.ObservableArray() : []; that.dataItemById = []; that.refreshHierarchy(); } _getId( id, item, index ) { if ( id !== null && id.name !== undefined ) { if ( id.name && item.getAttribute ) { let result = item.getAttribute( id.name ); if ( result !== null && result.toString().length > 0 ) { return result; } else if ( id.map ) { try { let result = item.getAttribute( id.map ); if ( result !== null && result.toString().length > 0 ) { return result; } } catch ( error ) { return index; } } return; } } if ( id ) { if ( id.toString().length > 0 && item.getAttribute ) { let result = item.getAttribute( id ); if ( result !== null && result.toString().length > 0 ) { return result.trim().split( ' ' ).join( '' ).replace( /([ #;?%&,.+*~\':'!^$[\]()=>|\/@])/g, '' ); } else { let splitMap = id.split( this.mapChar ); if ( splitMap.length > 1 ) { let d = item; for ( let p = 0; p < splitMap.length; p++ ) { if ( d !== undefined ) { d = d[ splitMap[ p ] ]; } } if ( d !== undefined ) { return d; } } else { if ( item[ id ] !== undefined ) { return item[ id ]; } } } } } return index; } _buildHierarchy() { const that = this; if ( !that.reservedNames ) { that.reservedNames = { leaf: 'leaf', parent: 'parent', expanded: 'expanded', checked: 'checked', selected: 'selected', level: 'level', icon: 'icon', data: 'data' } } else { const names = that.reservedNames; if ( !names.leaf ) { names.leaf = 'leaf'; } if ( !names.parent ) { names.parent = 'parent'; } if ( !names.expanded ) { names.expanded = 'expanded'; } if ( !names.checked ) { names.checked = 'checked'; } if ( !names.selected ) { names.selected = 'selected'; } if ( !names.level ) { names.level = 'level'; } if ( !names.data ) { names.data = 'data'; } } const names = that.reservedNames; if ( that.childrenDataField ) { const hierarchy = []; for ( let i = 0; i < that.boundSource.length; i++ ) { const item = Object.assign( {}, that.boundSource[ i ] ); if ( !item ) { continue; } hierarchy.push( item ); const addItems = function ( item ) { const splitMap = that.childrenDataField.split( that.mapChar ); let children = null; if ( splitMap.length > 1 ) { let data = item; for ( let p = 0; p < splitMap.length; p++ ) { if ( data !== undefined ) { data = data[ splitMap[ p ] ]; } } children = data; } else { children = item[ 'children' ]; } item[ 'children' ] = children; if ( item[ 'children' ] === null || item[ 'children' ] === undefined || ( item[ 'children' ] && item[ 'children' ].length === 0 ) ) { item[ names.leaf ] = true; } } addItems( item ); item[ names.level ] = 0; if ( !item.$ ) { item.$ = {}; } item[ names.parent ] = null; item[ names.data ] = item; if ( item[ names.expanded ] === undefined ) { item[ names.expanded ] = false; } const drillThrough = function ( parent, children ) { if ( !children ) { parent[ 'children' ] = new Array(); return; } for ( let i = 0; i < children.length; i++ ) { let item = that._getDataItem( children[ i ], i ); if ( !item ) { continue; } addItems( item ); item[ names.level ] = parent[ names.level ] + 1; item[ names.parent ] = parent; item[ names.data ] = item; if ( parent ) { parent[ 'children' ][ i ] = item; } if ( item[ names.expanded ] === undefined ) { item[ names.expanded ] = false; } drillThrough( item, item[ 'children' ] ); } } drillThrough( item, item[ 'children' ] ); } that.boundHierarchy = hierarchy; if ( !that._boundSourceUpdate ) { for ( let i = 0; i < that.boundHierarchy.length; i++ ) { const item = that.boundHierarchy[ i ]; if ( item.children ) { const drillThrough = function ( item ) { if ( !that.dataItemById[ item.$.id ] ) { that.boundSource.canNotify = false; that.dataItemById[ item.$.id ] = item; that[ that.boundSource.length ] = item; that.boundSource.push( item ); that.boundSource.canNotify = true; } if ( item.children ) { for ( let i = 0; i < item.children.length; i++ ) { const child = item.children[ i ]; if ( child.children ) { drillThrough( child ); } } } } drillThrough( item ); } } that._boundSourceUpdate = true; } } if ( that.xmlRoot && that.dataSourceType === 'xml' ) { that.boundHierarchy = this._getHierarchy( 'uid', '_parentuid', 'children', null, that.boundSource ); } if ( that.keyDataField && that.parentDataField ) { that.boundHierarchy = this._getHierarchy( that.keyDataField, that.parentDataField, 'children', null, that.boundSource ); } if ( that.groupBy && that.groupBy.length > 0 ) { that.boundHierarchy = this._getGroupHierarchy( that.groupBy, 'children', 'label', null, 'data', null, 'parent', that.boundSource ); } if ( that.virtualDataSourceOnExpand ) { that.boundHierarchy = this._getHierarchy( 'id', 'parentId', 'children', null, that.boundSource ); } } _getGroupHierarchy( groups, collectionName, groupName, mappingFields, itemName, valueName, parentName, data, startIndex ) { let that = this; if ( !startIndex ) { startIndex = 0; } let names = that.reservedNames; const guid = function () { function s4() { return Math.floor( ( 1 + Math.random() ) * 0x10000 ) .toString( 16 ) .substring( 1 ); } return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); } let groupHashCodes = new Array(); for ( let iGroupColumn = 0; iGroupColumn < groups.length; iGroupColumn++ ) { groupHashCodes[ iGroupColumn ] = guid(); } if ( !collectionName ) { collectionName = 'children'; } if ( !groupName ) { groupName = 'group'; } if ( !itemName ) { itemName = 'item'; } if ( !parentName ) { parentName = 'parent'; } if ( undefined === valueName ) { valueName = 'value'; } const groupboundSource = new Array(); const hashItemGroups = new Array(); let groupboundSourceIndex = 0; const getItem = function ( item ) { let itemObj = item; if ( mappingFields ) { for ( let mappingField in mappingFields ) { const mappingObject = mappingFields[ mappingField ]; if ( mappingObject.name && mappingObject.map ) { itemObj[ mappingObject.map ] = itemObj[ mappingObject.name ]; } } } return itemObj; } for ( let obj = 0; obj < data.length; obj++ ) { let item = Object.assign( {}, getItem( data[ obj ] ) ); item[ names.leaf ] = false; let itemKeysHierarchy = new Array(); let keys = 0; for ( let iGroupColumn = 0; iGroupColumn < groups.length; iGroupColumn++ ) { const group = groups[ iGroupColumn ]; const value = item[ group ]; if ( null === value ) { continue; } itemKeysHierarchy[ keys++ ] = { value: value, group: group, hash: groupHashCodes[ iGroupColumn ] }; } if ( itemKeysHierarchy.length !== groups.length ) { break; } let parentItem = null; let lookupKey = ''; for ( let q = 0; q < itemKeysHierarchy.length; q++ ) { const itemKey = itemKeysHierarchy[ q ].value; const groupDataField = itemKeysHierarchy[ q ].group; const columnHash = itemKeysHierarchy[ q ].hash; lookupKey = lookupKey + '_' + columnHash + '_' + itemKey; if ( hashItemGroups[ lookupKey ] !== undefined && hashItemGroups[ lookupKey ] !== null ) { parentItem = hashItemGroups[ lookupKey ]; continue; } if ( parentItem === null ) { parentItem = { $: {} }; parentItem[ names.level ] = 0; parentItem[ names.leaf ] = false; parentItem[ parentName ] = null; parentItem[ groupName ] = itemKey; parentItem[ itemName ] = item; parentItem[ 'groupDataField' ] = groupDataField; if ( !parentItem[ groupDataField ] ) { parentItem[ groupDataField ] = parentItem.data[ groupDataField ]; } if ( item[ names.expanded ] !== undefined ) { parentItem[ names.expanded ] = item[ names.expanded ]; } else { parentItem[ names.expanded ] = false; } if ( valueName ) { parentItem[ valueName ] = item[ valueName ]; } parentItem[ collectionName ] = new Array(); let uid = groupboundSource.length + startIndex; if ( !this.id || typeof item.$.id === 'number' || isFinite( item.$.id ) ) { uid = 'Item' + uid; } if ( parentItem.$.id === undefined ) { parentItem.$.id = uid; } groupboundSource[ groupboundSourceIndex++ ] = parentItem; } else { const subItem = { $: {} }; subItem[ names.level ] = parentItem[ names.level ] + 1; subItem[ parentName ] = parentItem; subItem[ groupName ] = itemKey; subItem[ collectionName ] = new Array(); subItem[ itemName ] = item; subItem[ 'groupDataField' ] = groupDataField; subItem[ names.leaf ] = false; if ( !subItem[ groupDataField ] ) { subItem[ groupDataField ] = subItem.data[ groupDataField ]; } if ( item[ names.expanded ] !== undefined ) { subItem[ names.expanded ] = item[ names.expanded ]; } else { subItem[ names.expanded ] = false; } if ( valueName ) { subItem[ valueName ] = item[ valueName ]; } if ( subItem.$.id === undefined ) { subItem.$.id = parentItem.$.id + '_' + parentItem[ collectionName ].length; } parentItem[ collectionName ][ parentItem[ collectionName ].length ] = subItem; parentItem = subItem; } hashItemGroups[ lookupKey ] = parentItem; } if ( item ) { item[ names.leaf ] = true; } if ( parentItem !== null ) { if ( this.id === null ) { if ( undefined === item.$.id ) { item.$.id = parentItem.$.id + '_' + parentItem[ collectionName ].length; } } else { if ( undefined === item.$.id ) { if ( item.$.id.toString().indexOf( parentItem.$.id ) === -1 ) { item.$.id = parentItem.$.id + '_' + item.$.id; } } } item[ parentName ] = parentItem; item[ names.level ] = parentItem[ names.level ] + 1; parentItem[ collectionName ][ parentItem[ collectionName ].length ] = item; } else { if ( undefined === item.$.id ) { item.$.id = guid(); } } } return groupboundSource; } _getHierarchy( fieldName, parentFieldName, collectionName, mappingFields, boundSource ) { const that = this; const databoundHierarchy = new Array(); let flatData = this.boundSource; if ( boundSource ) { flatData = boundSource; } if ( this.boundSource.length === 0 ) return null; const childrenName = collectionName !== null ? collectionName : 'children'; let items = new Array(); let data = flatData; let dataLength = data.length; let names = that.reservedNames; const getItem = function ( item ) { let itemObj = item; if ( mappingFields ) { for ( let mappingField in mappingFields ) { const mappingObject = mappingFields[ mappingField ]; if ( mappingObject.name && mappingObject.map ) { itemObj[ mappingObject.map ] = itemObj[ mappingObject.name ]; } } } return itemObj; } // build hierarchical source. for ( let i = 0; i < dataLength; i++ ) { let item = data[ i ]; let parentId = item[ parentFieldName ]; let id = item[ fieldName ]; if ( parentFieldName === 'parentId' ) { parentId = item.$.parentId; } if ( fieldName === 'id' ) { id = item.$.id; } item[ childrenName ] = new Array(); items[ id ] = { parentId: parentId, item: item }; } for ( let i = 0; i < dataLength; i++ ) { const item = data[ i ]; let parentId = item[ parentFieldName ]; let id = item[ fieldName ]; if ( parentFieldName === 'parentId' ) { parentId = item.$.parentId; } if ( fieldName === 'id' ) { id = item.$.id; } if ( items[ parentId ] !== undefined ) { let item = { parentId: parentId, item: items[ id ].item }; let parentItem = items[ parentId ].item; if ( !parentItem[ childrenName ] ) { parentItem[ childrenName ] = new Array(); } let length = parentItem[ childrenName ].length; item = item.item; if ( !names ) { if ( item.parent === undefined ) { item.parent = parentItem; } } else { if ( item[ names.parent ] === undefined ) { item[ names.parent ] = parentItem; } } const itemObj = getItem( item ); parentItem[ childrenName ][ length ] = itemObj; items[ parentId ].item = parentItem; items[ id ].item = item; } else { let item = items[ id ].item; if ( !names ) { if ( item.parent === undefined ) { item.parent = null; } } else { if ( item[ names.parent ] === undefined ) { item[ names.parent ] = null; } } const itemObj = getItem( item ); if ( !names ) { itemObj.level = 0; } else { itemObj[ names.level ] = 0; } databoundHierarchy[ databoundHierarchy.length ] = itemObj; } } if ( databoundHierarchy.length !== 0 ) { let updateLevels = function ( level, children ) { for ( let i = 0; i < children.length; i++ ) { const child = children[ i ]; if ( !names ) { child.level = level; } else { child[ names.level ] = level; } const childChildren = child[ childrenName ]; if ( childChildren ) { if ( childChildren.length > 0 ) { updateLevels( level + 1, childChildren ); } else { if ( that.virtualDataSourceOnExpand ) { if ( child.leaf === undefined ) { child.leaf = false; } } else { if ( !names ) { child.leaf = true; } else { child[ names.leaf ] = true; } } } } else { if ( that.virtualDataSourceOnExpand ) { if ( child.leaf === undefined ) { child.leaf = false; } } else { if ( !names ) { child.leaf = true; } else { child[ names.leaf ] = true; } } } } }; updateLevels( 0, databoundHierarchy ); } return databoundHierarchy; } summarize( summaryItems, boundSource ) { const that = this; if ( !Array.isArray( summaryItems ) ) { summaryItems = [ summaryItems ]; } let tempSummaryItems = []; for ( let i = 0; i < summaryItems.length; i++ ) { const summaryItem = summaryItems[ i ]; for ( let name in summaryItem ) { const functions = summaryItem[ name ]; tempSummaryItems.push( { dataField: name, functions: functions } ) } } summaryItems = tempSummaryItems; let data = {}; let summaryByDataField = new Array(); if ( !boundSource ) { boundSource = that.boundSource; } let length = boundSource.length; if ( length === 0 ) { return; } if ( length === undefined ) { return; } for ( let i = 0; i < length; i++ ) { let dataItem = boundSource[ i ]; for ( let j = 0; j < summaryItems.length; j++ ) { const summaryItem = summaryItems[ j ]; let value = dataItem[ summaryItem.dataField ]; if ( summaryItem.functions ) { data[ summaryItem.dataField ] = data[ summaryItem.dataField ] || {}; summaryByDataField[ summaryItem.dataField ] = summaryByDataField[ summaryItem.dataField ] || 0; summaryByDataField[ summaryItem.dataField ]++; const _summaryItemFunction = function ( summaryItemObject ) { for ( let name in summaryItemObject ) { let oldValue = data[ summaryItem.dataField ][ name ]; if ( oldValue === null || oldValue === undefined ) { data[ summaryItem.dataField ][ name ] = 0; oldValue = 0; } if ( typeof summaryItemObject[ name ] === 'function' ) { oldValue = summaryItemObject[ name ]( oldValue, value, summaryItem.dataField, dataItem ); } data[ summaryItem.dataField ][ name ] = oldValue; } } let canParse = parseFloat( value ); if ( isNaN( canParse ) ) { canParse = false; } else { canParse = true; } if ( canParse ) { value = parseFloat( value ); } if ( typeof value === 'number' && isFinite( value ) ) { summaryItem.functions.forEach( function ( summaryItemFunction ) { let oldValue = data[ summaryItem.dataField ][ summaryItemFunction ]; if ( oldValue === null || oldValue === undefined ) { oldValue = 0; if ( summaryItemFunction === 'min' ) { oldValue = 9999999999999; } if ( summaryItemFunction === 'max' ) { oldValue = -9999999999999; } if (summaryItemFunction === 'median') { oldValue = []; } } if ( summaryItemFunction === 'sum' || summaryItemFunction === 'avg' || summaryItemFunction === 'stdev' || summaryItemFunction === 'stdevp' || summaryItemFunction === 'var' || summaryItemFunction === 'varp' ) { oldValue += parseFloat( value ); } else if ( summaryItemFunction === 'product' ) { if ( i === 0 ) oldValue = parseFloat( value ); else oldValue *= parseFloat( value ); } else if ( summaryItemFunction === 'min' ) { oldValue = Math.min( oldValue, parseFloat( value ) ); } else if ( summaryItemFunction === 'max' ) { oldValue = Math.max( oldValue, parseFloat( value ) ); } else if ( summaryItemFunction === 'count' ) { oldValue++; } else if (summaryItemFunction === 'median') { oldValue.push(parseFloat(value)); } else if ( typeof ( summaryItemFunction ) === 'object' ) { _summaryItemFunction( summaryItemFunction ); return; } data[ summaryItem.dataField ][ summaryItemFunction ] = oldValue; } ); } else { summaryItem.functions.forEach( function ( summaryItemFunction ) { if ( summaryItemFunction === 'min' || summaryItemFunction === 'max' || summaryItemFunction === 'count' || summaryItemFunction === 'product' || summaryItemFunction === 'sum' || summaryItemFunction === 'avg' || summaryItemFunction === 'stdev' || summaryItemFunction === 'stdevp' || summaryItemFunction === 'var' || summaryItemFunction === 'varp' ) { if ( value === null ) { return true; } let oldValue = data[ summaryItem.dataField ][ summaryItemFunction ]; if ( oldValue === null || oldValue === undefined ) { oldValue = 0; } data[ summaryItem.dataField ][ summaryItemFunction ] = oldValue; return true; } if ( typeof ( summaryItemFunction ) === 'object' ) { _summaryItemFunction( summaryItemFunction ); } } ); } } } } for ( let j = 0; j < summaryItems.length; j++ ) { const summaryItem = summaryItems[ j ]; if ( !summaryItem.functions ) { continue; } if ( !data[ summaryItem.dataField ] ) { data[ summaryItem.dataField ] = {}; summaryItem.functions.forEach( function ( summaryItemFunction ) { data[ summaryItem.dataField ][ summaryItemFunction ] = 0; } ); } if ( data[ summaryItem.dataField ][ 'avg' ] !== undefined ) { const value = data[ summaryItem.dataField ][ 'avg' ]; const dataValues = summaryByDataField[ summaryItem.dataField ]; if ( dataValues === 0 || dataValues === undefined ) { data[ summaryItem.dataField ][ 'avg' ] = 0; } else { data[ summaryItem.dataField ][ 'avg' ] = value / dataValues; } } else if ( data[ summaryItem.dataField ][ 'count' ] !== undefined ) { data[ summaryItem.dataField ][ 'count' ] = length; } else if (data[summaryItem.dataField]['median'] !== undefined) { let population = data[summaryItem.dataField]['median']; population.sort(function (a, b) { return a - b; }); data[summaryItem.dataField]['median'] = 0.5 * (population[Math.floor((population.length + 1) / 2) - 1] + population[Math.ceil((population.length + 1) / 2) - 1]); } // stdev, stdevp, var, varp. // stdev - Standard deviation on a sample. // varp - Variance on an entire population. // let - Variance on a sample. if ( data[ summaryItem.dataField ][ 'stdev' ] || data[ summaryItem.dataField ][ 'stdevp' ] || data[ summaryItem.dataField ][ 'var' ] || data[ summaryItem.dataField ][ 'varp' ] ) { summaryItem.functions.forEach( function ( summaryItemFunction ) { if ( summaryItemFunction === 'stdev' || summaryItemFunction === 'var' || summaryItemFunction === 'varp' || summaryItemFunction === 'stdevp' ) { const value = data[ summaryItem.dataField ][ summaryItemFunction ]; const count = length; const average = ( value / length ); let sumSq = 0.0; for ( let i = 0; i < length; i++ ) { let dataItem = boundSource[ i ]; let value = dataItem[ summaryItem.dataField ]; sumSq += ( value - average ) * ( value - average ); } let denominator = ( summaryItemFunction === 'stdevp' || summaryItemFunction === 'varp' ) ? count : count - 1; if ( denominator === 0 ) { denominator = 1; } if ( summaryItemFunction === 'var' || summaryItemFunction === 'varp' ) { data[ summaryItem.dataField ][ summaryItemFunction ] = sumSq / denominator; } else if ( summaryItemFunction === 'stdevp' || summaryItemFunction === 'stdev' ) { data[ summaryItem.dataField ][ summaryItemFunction ] = Math.sqrt( sumSq / denominator ); } } } ); } } return data; } deserialize(stringValue, type, nullable) { const nullValue = stringValue === 'null'; if (stringValue === undefined || (nullValue && !nullable)) { return undefined; } if (nullValue && nullable) { return null; } if (type === 'boolean' || type === 'bool') { if (stringValue === null) { return false; } // Boolean properties are set based on the presence of the attribute: if the attribute exists at all, the value is true. return true; } else if (type === 'number' || type === 'float') { if (stringValue === 'NaN') { return NaN; } if (stringValue === 'Infinity') { return Infinity; } if (stringValue === '-Infinity') { return -Infinity; } return parseFloat(stringValue); } else if (type === 'int' || type === 'integer') { if (stringValue === 'NaN') { return NaN; } if (stringValue === 'Infinity') { return Infinity; } if (stringValue === '-Infinity') { return -Infinity; } return parseInt(stringValue); } else if (type === 'string') { return stringValue; } else if (type === 'any') { return stringValue; } else if (type === 'date') { return new Date(stringValue); } else if (type === 'function') { if (typeof window[stringValue] === 'function') { return window[stringValue]; } } else if (type === 'array' || type === 'object') { try { const jsonObject = JSON.parse(stringValue); if (jsonObject) { return jsonObject; } } catch (er) { if (window[stringValue] && (typeof window[stringValue] === 'object')) { return window[stringValue]; } else if (type === 'array' && stringValue.indexOf('[') >= 0) { if (stringValue.indexOf('{') >= 0) { let array = stringValue.replace(/{/ig, '').replace('[', '').replace(']', '').replace(/'/ig, '').replace(/"/ig, '').trim(); array = array.split('},'); for (let i = 0; i < array.length; i++) { let parsedObject = { }; let parts = array[i].trim().split(','); for (let j = 0; j < parts.length; j++) { const key = parts[j].split(':')[0].trim(); const value = parts[j].split(':')[1].trim(); parsedObject[key] = value; } array[i] = parsedObject; } return array; } const array = stringValue.replace('[', '').replace(']', '').replace(/'/ig, '').replace(/"/ig, '').trim().split(','); return array; } } } return undefined; } _getDataItem( dataSourceItem, index ) { const that = this; const itemObject = {}; const unboundMode = typeof ( that.dataSource ) === 'number' || that.dataSourceLength; if ( !dataSourceItem ) { return { $: { id: index, isEmpty: true, index: index } } } if ( typeof dataSourceItem === 'string' ) { dataSourceItem = { '': dataSourceItem }; } if ( unboundMode ) { for ( let j = 0; j < that.dataFields.length; j++ ) { const dataField = that.dataFields ? that.dataFields[ j ] : {}; itemObject[ dataField.name ] = ''; } itemObject.$ = {}; itemObject.$.id = index; itemObject.$.index = index; return itemObject; } const dataItem = dataSourceItem; if ( dataItem.expanded !== undefined ) { itemObject.expanded = dataItem.expanded; if ( dataItem.expanded === 'true' || dataItem.expanded === true || dataItem.expanded === 1 ) { itemObject.expanded = true; } else { itemObject.expanded = false; } } if ( that.childrenDataField ) { if ( dataItem[ that.childrenDataField ] !== undefined ) { itemObject.children = dataItem[ that.childrenDataField ]; } } else { if ( dataItem.children !== undefined ) { itemObject.children = dataItem.children; } else if ( dataItem.items !== undefined ) { itemObject.children = dataItem.items; } } if ( dataItem.leaf !== undefined ) { itemObject.leaf = dataItem.leaf; } if ( dataItem.level !== undefined ) { itemObject.level = dataItem.level; } if ( that.keyDataField ) { if ( dataItem[ that.keyDataField ] !== undefined ) { itemObject[ that.keyDataField ] = dataItem[ that.keyDataField ]; } } if ( that.parentDataField ) { if ( dataItem[ that.parentDataField ] !== undefined ) { itemObject[ that.parentDataField ] = dataItem[ that.parentDataField ]; } } if ( that.dataFields.length === 0 ) { const names = Object.getOwnPropertyNames( dataSourceItem ); for ( let i = 0; i < names.length; i++ ) { if ( names[ i ] === '$' ) { continue; } that.dataFields.push( { name: names[ i ], dataType: 'string' } ); } } for ( let j = 0; j < that.dataFields.length; j++ ) { const dataField = that.dataFields ? that.dataFields[ j ] : {}; let value = ''; dataField.dataType = dataField.type; if ( undefined === dataField || dataField === null ) { continue; } if ( dataSourceItem.length ) { value = dataSourceItem[ j ]; } if ( dataField.map ) { let splitMap = dataField.map.split( that.mapChar ); if ( splitMap.length > 0 ) { let dataMappedItem = dataItem; for ( let p = 0; p < splitMap.length; p++ ) { if ( !dataItem ) { continue; } dataMappedItem = dataMappedItem[ splitMap[ p ] ]; } value = dataMappedItem; } else { value = dataItem[ dataField.map ]; } } if ( value !== undefined && value !== null ) { value = value.toString(); } else { if ( value === undefined && value !== null ) { value = ''; } } let isEmptyString = false; // searches by both selectors when necessary. if ( value === '' ) { isEmptyString = true; value = dataSourceItem[ dataField.name ]; if ( value !== undefined && value !== null ) { if ( dataField.dataType !== 'array' ) { if ( dataField.dataType !== 'date' ) { value = value.toString(); } } } else { value = ''; } } if ( value === '[object Object]' && dataField.map && isEmptyString ) { value = ''; } if ( that._cachedValues[ '' + value + '_' + dataField.dataType ] ) { value = that._cachedValues[ '' + value + '_' + dataField.dataType ]; } else { if ( dataField.dataType === 'bool' || dataField.dataType === 'boolean' ) { if ( value === 'true' || value === '1' ) { value = true; } else if ( value === 'false' || value === '0' ) { value = false; } } else { value = that.deserialize( '' + value, dataField.dataType, true ); } that._cachedValues[ value + '_' + dataField.dataType ] = value; } if ( dataField.dataType !== 'string' && dataField.dataType !== 'boolean' && dataField.dataType !== 'bool' ) { if ( isNaN( value ) || value === -Infinity || value === Infinity ) { value = 0; } } itemObject[ dataField.name ] = value; } let itemObjectId = index; if ( that.id ) { itemObjectId = dataItem[ that.id ]; if ( typeof ( itemObjectId ) === 'object' ) { itemObjectId = index; } } else if ( !that.virtualDataSource && that.dataItemById && that.dataItemById[ itemObjectId ] ) { itemObjectId = that.length; } if ( !itemObject.$ ) { itemObject.$ = {}; } itemObject.$.id = itemObjectId; itemObject.$.index = index; return new Object( itemObject ); } _bindToArray() { const that = this; const unboundMode = typeof ( that.dataSource ) === 'number' || that.dataSourceLength; const dataArray = []; that.boundSource.canNotify = false; for ( let i = 0; i < that.length; i++ ) { const dataSourceItem = unboundMode ? {} : that.dataSource[ i ]; const itemObject = that._getDataItem( dataSourceItem, i ); dataArray.push( itemObject ); } if ( unboundMode && that.dataSourceLength && that.dataSource.length > 0 ) { for ( let i = 0; i < that.dataSource.length; i++ ) { const cell = that.dataSource[ i ].cell; const value = that.dataSource[ i ].value; const row = cell.replace( /[^0-9]/g, '' ); const dataField = cell.replace( /[0-9]/g, '' ); dataArray[ row - 1 ][ dataField ] = value; } } that.boundSource = dataArray; for ( let i = 0; i < that.length; i++ ) { that[ i ] = that.boundSource[ i ]; that.dataItemById[ that[ i ].$.id ] = that[ i ]; } that.boundSource.canNotify = true; } _bindToJSON() { const that = this; const dataArray = []; const dataEntries = Object.entries( that.dataSource ); that.boundSource.canNotify = false; for ( let i = 0; i < dataEntries.length; i++ ) { const dataSourceItem = dataEntries[ i ]; const itemObject = that._getDataItem( dataSourceItem, i ); dataArray.push( itemObject ); } that.boundSource = false === that.observable ? dataArray : new JQX.ObservableArray( dataArray ); for ( let i = 0; i < that.length; i++ ) { that[ i ] = that.boundSource[ i ]; that.dataItemById[ that[ i ].$.id ] = that[ i ]; } that.boundSource.canNotify = true; } sortBy( dataField, dataType, orderBy ) { const that = this; if ( !dataType ) { for ( let i = 0; i < that.dataFields.length; i++ ) { const field = that.dataFields[ i ]; if ( field.name === dataField ) { dataType = field.dataType; break; } } } if ( that.boundHierarchy ) { if ( ( !dataField || dataField.length === 0 ) && that.groupBy.length > 0 ) { that.refreshHierarchy(); return; } const sortBy = function ( hierarchy ) { that._sort( hierarchy, dataField, orderBy, dataType ); for ( let i = 0; i < hierarchy.length; i++ ) { const item = hierarchy[ i ]; if ( item[ 'children' ] ) { sortBy( item[ 'children' ], dataField, orderBy, dataType ); } } } sortBy( that.boundHierarchy ); } else { that._sort( that.boundSource, dataField, orderBy, dataType ); } } _createFilter( dataType, filterExpressions ) { const filterOperators = { '=': 'EQUAL', '<>': 'NOT_EQUAL', '<': 'LESS_THAN', '>': 'GREATER_THAN', '<=': 'LESS_THAN_OR_EQUAL', '>=': 'GREATER_THAN_OR_EQUAL', 'equal': 'EQUAL', 'not equal': 'NOT_EQUAL', 'less than': 'LESS_THAN', 'greater than': 'GREATER_THAN', 'greater than or equal': 'GREATER_THAN_OR_EQUAL', 'less than or equal': 'LESS_THAN_OR_EQUAL', 'starts with': 'STARTS_WITH', 'ends with': 'ENDS_WITH', 'null': 'null', '': 'EMPTY', 'isblank': 'EMPTY', 'isnotblank': 'NOT_EMPTY', 'contains': 'CONTAINS', 'notcontains': 'DOES_NOT_CONTAIN', 'startswith': 'STARTS_WITH', 'endswith': 'ENDS_WITH', 'NULL': 'NULL', 'NOT_NULL': 'NOT_NULL' }; let filterExpressionsArray = []; for ( let i = 0; i < filterExpressions.length; i++ ) { const filterExpression = filterExpressions[ i ]; const filterExpressionParts = filterExpression.indexOf( '"' ) === -1 ? filterExpression.split( ' ' ) : filterExpression.split( '"' ); let filter = []; for ( let j = 0; j < filterExpressionParts.length; j++ ) { const part = filterExpressionParts[ j ]; if ( part !== '' ) { filter.push( part.trim() ); } } filterExpressionsArray.push( filter ); } const filterGroup = new JQX.FilterGroup(); const filterGroupOperators = []; const filterSubGroups = []; for ( let i = 0; i < filterExpressionsArray.length; i++ ) { const filterExpression = filterExpressionsArray[ i ]; if ( filterExpression.length > 1 ) { const filterSubGroup = new JQX.FilterGroup(); let operator = 'and'; let filterExpressionPartsCounter = 0; for ( let j = 0; j < filterExpression.length; j++ ) { const value = filterExpression[ j ]; if ( value === 'and' || value === 'or' ) { operator = value; continue; } filterExpressionPartsCounter++; if ( filterExpressionPartsCounter === 2 ) { const filter = filterSubGroup.createFilter( dataType, value, filterOperators[ filterExpression[ j - 1 ] ] ); filterExpressionPartsCounter = 0; if ( operator ) { filterSubGroup.addFilter( operator, filter ); } } } filterSubGroups.push( filterSubGroup ); } else { const filterGroupOperator = filterExpression[ 0 ]; if ( filterGroupOperator !== 'and' && filterGroupOperator !== 'or' ) { throw new Error( 'Filter Exprresion expects "AND" or "OR", but the token is: ' + filterGroupOperator ); } filterGroupOperators.push( filterGroupOperator ); } } let operatorsCounter = 0; if ( filterSubGroups.length === 1 ) { return filterSubGroups[ 0 ]; } for ( let i = 0; i < filterSubGroups.length; i++ ) { let operator = filterGroupOperators[ operatorsCounter ]; if ( ( i + 1 ) % 2 === 0 ) { operatorsCounter++; } if ( !operator ) { operator = 'and'; } filterGroup.addFilter( operator, filterSubGroups[ i ] ); } return filterGroup; } filterBy( dataField, ...filterExpressions ) { const that = this; const dataType = ( () => { for ( let i = 0; i < that.dataFields.length; i++ ) { const field = that.dataFields[ i ]; if ( field.name === dataField ) { return field.dataType; } } } )(); const filterGroup = that._createFilter( dataType, filterExpressions ); let filteredData = that.boundSource.filter( ( value ) => { const evaluation = filterGroup.evaluate( value[ dataField ] ); return evaluation; } ); return filteredData; } _filter( filters, operator = 'and' ) { const that = this; const filterGroups = []; const dataFields = []; if ( filters.length === 0 ) { that.clearFilter(); return; } const dataType = ( dataField ) => { for ( let i = 0; i < that.dataFields.length; i++ ) { const field = that.dataFields[ i ]; if ( field.name === dataField ) { return field.dataType; } } }; let defaultResult, operatorSpecificEval; if ( operator === 'and' ) { defaultResult = true; operatorSpecificEval = function ( result, filterGroup, row ) { return result && filterGroup.evaluate( row[ filterGroup.dataField ] ); }; } else { defaultResult = false; operatorSpecificEval = function ( result, filterGroup, row ) { return result || filterGroup.evaluate( row[ filterGroup.dataField ] ); }; } for ( let i = 0; i < filters.length; i++ ) { const filter = filters[ i ]; const dataField = filter[ 0 ]; let filterGroup = null; if ( filter[ 1 ] instanceof JQX.FilterGroup ) { filterGroup = filter[ 1 ]; } else { filterGroup = that._createFilter( dataType( dataField ), filter.splice( 1 ) ); } if ( filterGroup ) { dataFields.push( dataField ); filterGroup.dataField = dataField; filterGroups.push( filterGroup ); } } if ( that.boundHierarchy ) { const filter = function ( row ) { let result = defaultResult; for ( let j = 0; j < filterGroups.length; j++ ) { const filterGroup = filterGroups[ j ]; result = operatorSpecificEval( result, filterGroup, row ); } row.$.filtered = result; return result; } const filterBy = function ( hierarchy, parentItem, root ) { let filteredCount = 0; for ( let i = 0; i < hierarchy.length; i++ ) { const item = hierarchy[ i ]; filter( item ); if ( item.$.filtered ) { filteredCount++; } if ( item[ 'children' ] ) { filterBy( item[ 'children' ], item, parentItem ); } } if ( filteredCount > 0 && that.groupBy.length > 0 && parentItem ) { parentItem.$.filtered = true; if ( root && !root.$.filtered ) { root.$.filtered = true; } } else { if ( filteredCount > 0 && filteredCount !== hierarchy.length && parentItem ) { parentItem.$.filtered = null; if ( root && !root.$.filtered ) { root.$.filtered = null; } } } } filterBy( that.boundHierarchy, null, null ); } else { for ( let i = 0; i < that.boundSource.length; i++ ) { const row = that.boundSource[ i ]; let result = defaultResult; for ( let j = 0; j < filterGroups.length; j++ ) { const filterGroup = filterGroups[ j ]; result = operatorSpecificEval( result, filterGroup, row ); } row.$.filtered = result; } } if ( that.onFilter ) { that.onFilter() } } clearGroup() { const that = this; that.groupBy = []; that.boundHierarchy = null; that.refreshHierarchy(); if ( that.onGroup ) { that.onGroup() } } clearFilter() { const that = this; for ( let i = 0; i < that.boundSource.length; i++ ) { const row = that.boundSource[ i ]; row.$.filtered = true; } if ( that.boundHierarchy ) { const filterBy = function ( hierarchy, parentItem, root ) { //let filteredCount = 0; for ( let i = 0; i < hierarchy.length; i++ ) { const item = hierarchy[ i ]; item.$.filtered = true; if ( item.$.filtered ) { //filteredCount++; } if ( item[ 'children' ] ) { filterBy( item[ 'children' ], item, parentItem ); } } if ( parentItem ) { parentItem.$.filtered = true; if ( root && !root.$.filtered ) { root.$.filtered = true; } } } filterBy( that.boundHierarchy, null, null ); } if ( that.onFilter ) { that.onFilter() } } clearSort() { const that = this; that._sort( that.boundSource, [], [], [] ); } _sort( dataSource, sortColumns, directions, dataTypes, customSortingCallback ) { const that = this; let isObservableArray = false; if ( dataSource.length === 0 ) { return; } if ( dataSource && dataSource.constructor && dataSource instanceof JQX.ObservableArray ) { isObservableArray = true; } if ( !dataSource || !( Array.isArray( dataSource ) ) || dataSource.length === 0 || !sortColumns || Array.isArray( sortColumns ) && sortColumns.length === 0 ) { if ( !isObservableArray && !that.boundHierarchy ) { throw new Error( 'sort: Missing or Invalid arguments!' ); } } if ( typeof sortColumns === 'string' ) { sortColumns = [ sortColumns ]; } const directionCoefficients = [], compareFunctions = []; if ( directions === undefined ) { directions = []; } const getCompareFunction = function ( a, knownDataType ) { // gets data type of column (not necessary if the Grid provides this information) const dataType = knownDataType || typeof a; let compareFunction; switch ( dataType ) { case 'string': compareFunction = new Intl.Collator().compare; break; case 'number': compareFunction = function ( a, b ) { return a - b; }; break; case 'boolean': case 'bool': compareFunction = function ( a, b ) { if ( a === b ) { return 0; } else if ( a === false ) { return -1; } else { return 1; } }; break; case 'date': case 'time': case 'dateTime': if ( a instanceof Date ) { compareFunction = function ( a, b ) { return a.getTime() - b.getTime(); }; } else if ( a instanceof JQX.Utilities.DateTime || a instanceof JQX.Utilities.BigNumber ) { compareFunction = function ( a, b ) { return a.compare( b ); }; } break; case 'object': if ( a instanceof Date ) { compareFunction = function ( a, b ) { return a.getTime() - b.getTime(); }; } else if ( a instanceof JQX.Utilities.DateTime || a instanceof JQX.Utilities.BigNumber ) { compareFunction = function ( a, b ) { return a.compare( b ); }; } else if ( a instanceof JQX.Utilities.Complex || ( window.NIComplex && a instanceof window.NIComplex ) ) { const complexNumericProcessor = new JQX.Utilities.ComplexNumericProcessor(); compareFunction = function ( a, b ) { return complexNumericProcessor.compareComplexNumbers( a, b ); } } break; } return compareFunction; } for ( let i = 0; i < sortColumns.length; i++ ) { if ( directions[ i ] === undefined || directions[ i ] === 'asc' || directions[ i ] === 'ascending' ) { directionCoefficients[ i ] = 1; } else { directionCoefficients[ i ] = -1; } const value = dataSource[ 0 ][ sortColumns[ i ] ]; compareFunctions[ i ] = getCompareFunction( value, dataTypes[ i ] ); } if ( customSortingCallback ) { customSortingCallback( dataSource, sortColumns, directions, compareFunctions ); return; } dataSource.sort( function ( a, b ) { for ( let i = 0; i < sortColumns.length; i++ ) { const result = compareFunctions[ i ]( a[ sortColumns[ i ] ], b[ sortColumns[ i ] ] ); if ( result === 0 ) { if ( sortColumns[ i + 1 ] ) { continue; } else if ( a._index !== undefined ) { // makes sorting stable return ( a._index - b._index ) * directionCoefficients[ i ]; } return 0; } return result * directionCoefficients[ i ]; } if ( sortColumns.length === 0 ) { if ( a.$.index < b.$.index ) { return -1; } if ( a.$.index > b.$.index ) { return 1; } return 0; } } ); for ( let i = 0; i < dataSource.length; i++ ) { that[ i ] = dataSource[ i ]; } } static Filter( dataSource, filterColumns, filterGroups, customFilteringCallback, operator = 'and' ) { let defaultResult, operatorSpecificEval; if ( operator === 'and' ) { defaultResult = true; operatorSpecificEval = function ( result, dataItem, filterColumn, filterGroup ) { if ( customFilteringCallback ) { return result && customFilteringCallback( dataItem, filterColumn, filterGroup ); } return result && filterGroup.evaluate( dataItem[ filterColumn ] ); }; } else { defaultResult = false; operatorSpecificEval = function ( result, dataItem, filterColumn, filterGroup ) { if ( customFilteringCallback ) { return result || customFilteringCallback( dataItem, filterColumn, filterGroup ); } return result || filterGroup.evaluate( dataItem[ filterColumn ] ); }; } const filteredData = dataSource.filter( ( dataItem ) => { let result = defaultResult; for ( let i = 0; i < filterGroups.length; i++ ) { const filterGroup = filterGroups[ i ]; const filterColumn = filterColumns[ i ]; result = operatorSpecificEval( result, dataItem, filterColumn, filterGroup ); } return result; } ); return filteredData; } filter( filterColumns, filterGroups, customFilteringCallback ) { JQX.ExcelAdapter.Filter( this.boundSource, filterColumns, filterGroups, customFilteringCallback ); } sort( sortColumns, directions, customSortingCallback ) { JQX.ExcelAdapter.Sort( this.boundSource, sortColumns, directions, customSortingCallback ); } static Sort( dataSource, sortColumns, directions, customSortingCallback ) { const getCompareFunction = function ( a ) { // gets data type of column (not necessary if the Grid provides this information) const dataType = typeof a; let compareFunction; switch ( dataType ) { case 'string': compareFunction = new Intl.Collator().compare; break; case 'number': compareFunction = function ( a, b ) { return a - b; }; break; case 'boolean': compareFunction = function ( a, b ) { if ( a === b ) { return 0; } else if ( a === false ) { return -1; } else { return 1; } }; break; case 'object': if ( a instanceof Date ) { compareFunction = function ( a, b ) { return a.getTime() - b.getTime(); }; } else if ( a instanceof JQX.Utilities.DateTime || a instanceof BigNumberNG ) { compareFunction = function ( a, b ) { return a.compare( b ); }; } else if ( a instanceof JQX.Utilities.Complex || ( window.NIComplex && a instanceof window.NIComplex ) ) { const complexNumericProcessor = new JQX.Utilities.ComplexNumericProcessor(); compareFunction = function ( a, b ) { return complexNumericProcessor.compareComplexNumbers( a, b ); } } break; } return compareFunction; } if ( !dataSource || !( Array.isArray( dataSource ) ) || dataSource.length === 0 || !sortColumns || Array.isArray( sortColumns ) && sortColumns.length === 0 ) { return; } if ( typeof sortColumns === 'string' ) { sortColumns = [ sortColumns ]; } const directionCoefficients = [], compareFunctions = []; if ( directions === undefined ) { directions = []; } for ( let i = 0; i < sortColumns.length; i++ ) { if ( directions[ i ] === undefined || directions[ i ] === 'asc' || directions[ i ] === 'ascending' ) { directionCoefficients[ i ] = 1; } else { directionCoefficients[ i ] = -1; } compareFunctions[ i ] = getCompareFunction( dataSource[ 0 ][ sortColumns[ i ] ] ); } if ( customSortingCallback ) { customSortingCallback( dataSource, sortColumns, directions, compareFunctions ); return; } const sortedData = dataSource.slice( 0 ); sortedData.sort( function ( a, b ) { for ( let i = 0; i < sortColumns.length; i++ ) { const result = compareFunctions[ i ]( a[ sortColumns[ i ] ], b[ sortColumns[ i ] ] ); if ( result === 0 ) { if ( sortColumns[ i + 1 ] ) { continue; } else if ( a._index !== undefined ) { // makes sorting stable return ( a._index - b._index ) * directionCoefficients[ i ]; } return 0; } return result * directionCoefficients[ i ]; } } ); return sortedData; } } window.jqxDataSource = DataAdapter; class Ajax { constructor ( config, callback ) { const that = this; that.config = config; that.callback = callback; if ( config.autoFetch === false ) { return; } that.call( config ); } call( config ) { const that = this; if ( !config ) { config = that.config; } let method = 'GET', url = config.url, body = null, async = true; if ( config.type ) { method = config.type; } if ( config.data ) { if ( method === 'GET' ) { url += '?'; for ( let prop in config.data ) { if ( config.data.hasOwnProperty( prop ) ) { url += encodeURI( prop + '=' + config.data[ prop ] + '&' ); } } if ( url.charAt( url.length - 1 ) === '&' ) { url = url.slice( 0, url.length - 1 ); } } else if ( method === 'POST' ) { body = JSON.stringify( config.data ); } } if ( config && config.async === false && config.dataSourceType !== 'xlsx' ) { async = false; } if ( window.fetch !== undefined && async ) { that.ajaxFetch( config, method, url, body ); } else { that.ajaxXMLHttpRequest( config, method, url, body, async ); } } ajaxFetch( config, method, url, body ) { // prepare fetch config const that = this; const fetchInit = { method: method }; let parseMethod; switch ( config.dataSourceType ) { case 'json': parseMethod = 'json'; break; case 'xlsx': parseMethod = 'arrayBuffer'; break; default: parseMethod = 'text'; } if ( config ) { if ( config.contentType ) { fetchInit.headers = new Headers( { 'Content-Type': config.contentType } ); } } if ( body !== null ) { fetchInit.body = body; } let status, fetchTimeout, timeouted; if ( config.timeout ) { fetchTimeout = setTimeout( function () { timeouted = true; }, config.timeout ); } if ( config.beforeSend ) { const beforeSendResult = config.beforeSend( fetchInit, config ); if ( beforeSendResult === false ) { return; } } // fetch resource fetch( url, fetchInit ) .then( function ( response ) { if ( timeouted ) { status = 408; throw new Error( 'timeout' ); } if ( fetchTimeout ) { clearTimeout( fetchTimeout ); } status = response.status; if ( !response.ok ) { throw new Error( response.statusText ); } return response[ parseMethod ](); } ) .then( function ( data ) { if ( parseMethod === 'arrayBuffer' ) { return JSZip.loadAsync( data ).then( function ( zipData ) { // "data" represents the whole XLSX/ZIP file return zipData.files[ 'xl/worksheets/sheet1.xml' ].async( 'text' ).then( function ( sheet1 ) { return zipData.files[ 'xl/sharedStrings.xml' ].async( 'text' ).then( function ( sharedStrings ) { const parsedData = that.parseXLSXData( sheet1, sharedStrings ); that.ajaxComplete( config, parsedData, status ); } ); } ); } ); } else { that.ajaxComplete( config, data, status ); } } ) .catch( function ( error ) { if ( error.message === 'JSZip is not defined' ) { error.message = 'JSZip is not defined. Please include a reference to JSZip to be able to load data from XLSX files.'; } if ( config && config.loadError ) { config.loadError( status, error ); } if ( that.callback ) { that.callback( error, status ); } } ); } ajaxXMLHttpRequest( config, method, url, body, async ) { const request = new XMLHttpRequest(); const that = this; request.open( method, url, async ); request.ontimeout = function () { if ( config && config.loadError ) { config.loadError( 408, 'timeout' ); } }; request.onload = function () { if ( request.readyState === 4 ) { const status = request.status; let data = request.response; if ( status >= 200 && status <= 299 ) { if ( config.dataSourceType === 'json' ) { data = JSON.parse( data ); } that.ajaxComplete( config, data, status ); } else if ( config && config.loadError ) { config.loadError( status, data ); } } }; request.onerror = function () { if ( config && config.loadError ) { config.loadError( request.status, request.response ); } }; if ( config && config.contentType ) { request.setRequestHeader( 'Content-Type', config.contentType ); } if ( async && config.timeout ) { request.timeout = config.timeout; } if ( config.beforeSend ) { const beforeSendResult = config.beforeSend( request, config ); if ( beforeSendResult === false ) { return; } } request.send( body ); } ajaxComplete( config, data, status ) { if ( !config ) { return; } if ( config.beforeLoadComplete ) { const processedData = config.beforeLoadComplete( data ); if ( processedData ) { data = processedData; } } if ( config.loadComplete ) { config.loadComplete( data, status ); } if ( this.callback ) { this.callback( data, status ); } } parseXLSXData( sheet1, sharedStrings ) { const parser = new DOMParser(), sharedStringsDocument = parser.parseFromString( sharedStrings, 'text/xml' ), sharedStringsContainers = Array.from( sharedStringsDocument.getElementsByTagName( 'si' ) ), sharedStringsCollection = [], sheet1Document = parser.parseFromString( sheet1, 'text/xml' ), rows = Array.from( sheet1Document.getElementsByTagName( 'row' ) ), parsedData = []; sharedStringsContainers.forEach( function ( si ) { let texts = si.getElementsByTagName( 't' ); if ( texts.length === 1 ) { sharedStringsCollection.push( texts[ 0 ].innerHTML ); } else { let text = ''; texts = Array.from( texts ); texts.forEach( function ( t ) { text += t.innerHTML; } ); sharedStringsCollection.push( text ); } } ); rows.forEach( function ( row ) { const rowObject = {}, cells = Array.from( row.getElementsByTagName( 'c' ) ); cells.forEach( function ( cell/*, index*/ ) { const column = cell.getAttribute( 'r' ).match( /\D+/ )[ 0 ], type = cell.getAttribute( 't' ), xmlValue = cell.getElementsByTagName( 'v' )[ 0 ].innerHTML; let value; switch ( type ) { case 's': // string value = sharedStringsCollection[ parseFloat( xmlValue ) ]; break; case 'b': // boolean value = parseFloat( xmlValue ) === 1; break; default: // number or date value = parseFloat( xmlValue ); } rowObject[ column ] = value; } ); parsedData.push( rowObject ); } ); return parsedData; } } if ($.jqx && $.jqx.dataAdapter) { $.jqx.dataAdapter.Importer = DataAdapter; } })(jqxBaseFramework);