@@ -13478,58 +13478,90 @@ function RefreshHeaderBar () {
1347813478 }
1347913479
1348013480 if ( data . sensors != undefined ) {
13481- var nonFanSensors = data . sensors . filter ( function ( s ) {
13481+ var nonFanSensors = data . sensors . filter ( function ( s ) {
1348213482 return s . valueType !== 'FanSpeed' ;
1348313483 } ) ;
13484- var sensors = [ ] ;
1348513484 var tooltip = '' ;
1348613485 // Tooltip shows all sensors (including fans)
1348713486 data . sensors . forEach ( function ( e ) {
1348813487 var tv = e . formatted ;
13489- if ( e . valueType === 'Temperature' && typeof temperatureUnit !== 'undefined' && temperatureUnit ) {
13488+ if (
13489+ e . valueType === 'Temperature' &&
13490+ typeof temperatureUnit !== 'undefined' &&
13491+ temperatureUnit
13492+ ) {
1349013493 tv = ( parseFloat ( e . value ) * 1.8 + 32 ) . toFixed ( 2 ) + '°F' ;
1349113494 }
1349213495 tooltip += '<b>' + e . label + '</b>' + tv + '<br/>' ;
1349313496 } ) ;
13497+ // The tooltip text changes on every refresh. Bootstrap resolves a
13498+ // function title at show time, so stash the current text here and the
13499+ // tooltip objects never have to be recreated. Recreating them is what
13500+ // used to make an open tooltip blink away and back once a second.
13501+ headerCache . SensorTooltip = tooltip ;
13502+
1349413503 // Header rotating display excludes fan speed sensors
13504+ var sensorIcons = [ ] ;
13505+ var sensorLabels = [ ] ;
13506+ var sensorValues = [ ] ;
1349513507 nonFanSensors . forEach ( function ( e ) {
1349613508 var icon = 'bolt' ;
1349713509 var val = e . formatted ;
1349813510 if ( e . valueType == 'Temperature' ) {
1349913511 icon = 'thermometer-half' ;
1350013512 if ( typeof temperatureUnit !== 'undefined' && temperatureUnit ) {
13501- val = val * 1.8 + 32 ;
13502- val = parseFloat ( val ) . toFixed ( 2 ) ;
13513+ val = parseFloat ( val * 1.8 + 32 ) . toFixed ( 2 ) ;
1350313514 val += '°F' ;
1350413515 } else {
1350513516 val += '°C' ;
1350613517 }
1350713518 }
13508- row =
13509- '<span class="sensorSpan hiddenSensor" onclick="RotateHeaderSensor(' +
13510- ( sensors . length + 1 ) +
13511- ')" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-html="true" data-sensorcount="' +
13512- sensors . length +
13513- '" class="hiddenSensor" data-bs-title="TOOLTIP_DETAILS"><i class="fas fa-' +
13514- icon +
13515- '"></i><small>' +
13516- e . label +
13517- val +
13518- '</small></span>' ;
13519- sensors . push ( row ) ;
13519+ sensorIcons . push ( icon ) ;
13520+ sensorLabels . push ( e . label ) ;
13521+ sensorValues . push ( e . label + val ) ;
1352013522 } ) ;
13521- var sensorsJoined = sensors . join ( '' ) ;
13522- sensorsJoined = sensorsJoined . replace ( / T O O L T I P _ D E T A I L S / g, tooltip ) ;
13523- if ( headerCache . Sensors != sensorsJoined ) {
13524- $ ( '.sensorSpan' ) . each ( function ( ) {
13525- $ ( this ) . tooltip ( 'hide' ) ;
13526- } ) ;
13527- $ ( '#header_sensors' ) . html ( sensorsJoined ) ;
13528- $ ( '.sensorSpan' ) . each ( function ( ) {
13529- $ ( this ) . tooltip ( ) ;
13530- } ) ;
13531- headerCache . Sensors = sensorsJoined ;
13532- if ( sensors . length > 1 ) $ ( '#header_sensors' ) . css ( 'cursor' , 'pointer' ) ;
13523+
13524+ // Only the readings change from one refresh to the next, so rebuild the
13525+ // spans (and the tooltips attached to them) only when the set of
13526+ // sensors itself changes.
13527+ var structure = sensorIcons . join ( '|' ) + '||' + sensorLabels . join ( '|' ) ;
13528+ var values = sensorValues . join ( '|' ) ;
13529+ if ( headerCache . Sensors != structure ) {
13530+ $ ( '#header_sensors' )
13531+ . find ( '.sensorSpan' )
13532+ . each ( function ( ) {
13533+ var tip = bootstrap . Tooltip . getInstance ( this ) ;
13534+ if ( tip ) tip . dispose ( ) ;
13535+ } ) ;
13536+ var spans = '' ;
13537+ for ( var i = 0 ; i < sensorValues . length ; i ++ ) {
13538+ spans +=
13539+ '<span class="sensorSpan hiddenSensor" onclick="RotateHeaderSensor(' +
13540+ ( i + 1 ) +
13541+ ')" data-sensorcount="' +
13542+ i +
13543+ '"><i class="fas fa-' +
13544+ sensorIcons [ i ] +
13545+ '"></i><small>' +
13546+ sensorValues [ i ] +
13547+ '</small></span>' ;
13548+ }
13549+ $ ( '#header_sensors' ) . html ( spans ) ;
13550+ $ ( '#header_sensors' )
13551+ . find ( '.sensorSpan' )
13552+ . each ( function ( ) {
13553+ new bootstrap . Tooltip ( this , {
13554+ placement : 'bottom' ,
13555+ html : true ,
13556+ title : function ( ) {
13557+ return headerCache . SensorTooltip ;
13558+ }
13559+ } ) ;
13560+ } ) ;
13561+ headerCache . Sensors = structure ;
13562+ headerCache . SensorValues = values ;
13563+ if ( sensorValues . length > 1 )
13564+ $ ( '#header_sensors' ) . css ( 'cursor' , 'pointer' ) ;
1353313565 if (
1353413566 $ ( '#header_sensors' ) . data ( 'defaultsensor' ) != undefined &&
1353513567 Number . isInteger ( $ ( '#header_sensors' ) . data ( 'defaultsensor' ) )
@@ -13538,7 +13570,33 @@ function RefreshHeaderBar () {
1353813570 } else {
1353913571 RotateHeaderSensor ( 0 ) ;
1354013572 }
13573+ } else if ( headerCache . SensorValues != values ) {
13574+ // Same sensors, new readings. Update the text in place so the
13575+ // tooltips (and which sensor is currently rotated into view) are
13576+ // left alone.
13577+ $ ( '#header_sensors' )
13578+ . find ( '.sensorSpan' )
13579+ . each ( function ( i ) {
13580+ if ( i < sensorValues . length ) {
13581+ $ ( this ) . find ( 'small' ) . html ( sensorValues [ i ] ) ;
13582+ }
13583+ } ) ;
13584+ headerCache . SensorValues = values ;
1354113585 }
13586+
13587+ // If a tooltip is open right now, refresh its text in place rather than
13588+ // letting it close and reopen.
13589+ $ ( '#header_sensors' )
13590+ . find ( '.sensorSpan[aria-describedby]' )
13591+ . each ( function ( ) {
13592+ var tip = document . getElementById (
13593+ this . getAttribute ( 'aria-describedby' )
13594+ ) ;
13595+ var inner = tip ? tip . querySelector ( '.tooltip-inner' ) : null ;
13596+ if ( inner && inner . innerHTML != tooltip ) {
13597+ inner . innerHTML = tooltip ;
13598+ }
13599+ } ) ;
1354213600 }
1354313601
1354413602 if ( data . timeStr != undefined && data . dateStr != undefined ) {
0 commit comments