@@ -784,17 +784,99 @@ export const missingBrowserMethods = {
784784 return html ;
785785 } ,
786786
787+ patchMissingModelsBrowserElement ( container , html ) {
788+ const currentBrowser = container ?. querySelector ?. ( '.mr-missing-browser' ) ;
789+ if ( ! currentBrowser || typeof document === 'undefined' ) return false ;
790+
791+ const template = document . createElement ( 'template' ) ;
792+ template . innerHTML = String ( html || '' ) . trim ( ) ;
793+ const nextBrowser = template . content . firstElementChild ;
794+ const currentList = currentBrowser . querySelector ( '.mr-missing-list' ) ;
795+ const nextList = nextBrowser ?. querySelector ?. ( '.mr-missing-list' ) ;
796+ if ( ! nextBrowser || ! currentList || ! nextList ) return false ;
797+
798+ currentBrowser . style . cssText = nextBrowser . style . cssText ;
799+ const currentToolbar = currentBrowser . querySelector ( '.mr-missing-list-toolbar' ) ;
800+ const nextToolbar = nextBrowser . querySelector ( '.mr-missing-list-toolbar' ) ;
801+ if ( currentToolbar && nextToolbar ) {
802+ currentToolbar . replaceWith ( nextToolbar ) ;
803+ }
804+
805+ const currentHead = currentList . querySelector ( '.mr-missing-list-head' ) ;
806+ const nextHead = nextList . querySelector ( '.mr-missing-list-head' ) ;
807+ if ( currentHead && nextHead ) {
808+ currentHead . replaceWith ( nextHead ) ;
809+ }
810+
811+ const currentRows = new Map (
812+ Array . from ( currentList . querySelectorAll ( '.mr-missing-list-row' ) )
813+ . map ( row => [ row . dataset . missingKey || '' , row ] )
814+ . filter ( ( [ key ] ) => key )
815+ ) ;
816+ const retainedRows = new Set ( ) ;
817+ nextList . querySelectorAll ( '.mr-missing-list-row' ) . forEach ( ( nextRow ) => {
818+ const currentRow = currentRows . get ( nextRow . dataset . missingKey || '' ) ;
819+ const row = currentRow ?. outerHTML === nextRow . outerHTML
820+ ? currentRow
821+ : nextRow ;
822+ retainedRows . add ( row ) ;
823+ currentList . appendChild ( row ) ;
824+ } ) ;
825+ currentRows . forEach ( ( row ) => {
826+ if ( ! retainedRows . has ( row ) ) row . remove ( ) ;
827+ } ) ;
828+
829+ const currentSplitter = currentBrowser . querySelector ( '.mr-missing-browser-splitter' ) ;
830+ const nextSplitter = nextBrowser . querySelector ( '.mr-missing-browser-splitter' ) ;
831+ if ( currentSplitter && nextSplitter ) {
832+ currentSplitter . replaceWith ( nextSplitter ) ;
833+ }
834+
835+ const currentDetail = currentBrowser . querySelector ( '.mr-missing-detail-pane' ) ;
836+ const nextDetail = nextBrowser . querySelector ( '.mr-missing-detail-pane' ) ;
837+ this . _missingBrowserDetailPreserved = Boolean (
838+ currentDetail
839+ && nextDetail
840+ && currentDetail . outerHTML === nextDetail . outerHTML
841+ ) ;
842+ if ( currentDetail && nextDetail && ! this . _missingBrowserDetailPreserved ) {
843+ currentDetail . innerHTML = nextDetail . innerHTML ;
844+ }
845+ return true ;
846+ } ,
847+
787848 wireMissingModelsBrowser ( container , data , sortedMissingModels ) {
788849 this . wireMissingBrowserSplitter ( container ) ;
789850
790851 const browser = container . querySelector ( '.mr-missing-browser' ) ;
852+ const getCurrentData = ( ) => this . cachedAnalysisData || data ;
853+ const getCurrentMissingModels = ( ) => (
854+ Array . isArray ( this . missingModels )
855+ ? this . missingModels
856+ : sortedMissingModels
857+ ) ;
858+ if ( ! ( this . _wiredMissingModelRows instanceof WeakSet ) ) {
859+ this . _wiredMissingModelRows = new WeakSet ( ) ;
860+ }
861+ if ( ! ( this . _wiredMissingLocateButtons instanceof WeakSet ) ) {
862+ this . _wiredMissingLocateButtons = new WeakSet ( ) ;
863+ }
864+ if ( ! ( this . _wiredMissingBrowsers instanceof WeakSet ) ) {
865+ this . _wiredMissingBrowsers = new WeakSet ( ) ;
866+ }
791867 const typeFilterToggle = browser ?. querySelector ( '[data-missing-type-filter-toggle]' ) ;
792- const typeFilterMenu = browser ?. querySelector ( '.mr-missing-type-filter-menu' ) ;
793868 const setTypeFilterMenuOpen = ( open ) => {
794869 this . missingModelsTypeFilterMenuOpen = Boolean ( open ) ;
795- if ( typeFilterMenu ) typeFilterMenu . hidden = ! this . missingModelsTypeFilterMenuOpen ;
796- if ( typeFilterToggle ) {
797- typeFilterToggle . setAttribute ( 'aria-expanded' , this . missingModelsTypeFilterMenuOpen ? 'true' : 'false' ) ;
870+ const activeMenu = browser ?. querySelector ( '.mr-missing-type-filter-menu' ) ;
871+ const activeToggle = browser ?. querySelector ( '[data-missing-type-filter-toggle]' ) ;
872+ if ( activeMenu ) {
873+ activeMenu . hidden = ! this . missingModelsTypeFilterMenuOpen ;
874+ }
875+ if ( activeToggle ) {
876+ activeToggle . setAttribute (
877+ 'aria-expanded' ,
878+ this . missingModelsTypeFilterMenuOpen ? 'true' : 'false'
879+ ) ;
798880 }
799881 } ;
800882
@@ -814,18 +896,31 @@ export const missingBrowserMethods = {
814896 } ) ;
815897 } ) ;
816898
817- browser ?. addEventListener ( 'click' , ( event ) => {
818- if ( ! this . missingModelsTypeFilterMenuOpen ) return ;
819- if ( event . target instanceof Element && event . target . closest ( '.mr-missing-type-filter-wrap' ) ) return ;
820- setTypeFilterMenuOpen ( false ) ;
821- } ) ;
899+ if ( browser && ! this . _wiredMissingBrowsers . has ( browser ) ) {
900+ this . _wiredMissingBrowsers . add ( browser ) ;
901+ browser . addEventListener ( 'click' , ( event ) => {
902+ if ( ! this . missingModelsTypeFilterMenuOpen ) return ;
903+ if (
904+ event . target instanceof Element
905+ && event . target . closest ( '.mr-missing-type-filter-wrap' )
906+ ) {
907+ return ;
908+ }
909+ setTypeFilterMenuOpen ( false ) ;
910+ } ) ;
822911
823- browser ?. addEventListener ( 'keydown' , ( event ) => {
824- if ( event . key !== 'Escape' || ! this . missingModelsTypeFilterMenuOpen ) return ;
825- event . preventDefault ( ) ;
826- setTypeFilterMenuOpen ( false ) ;
827- typeFilterToggle ?. focus ( ) ;
828- } ) ;
912+ browser . addEventListener ( 'keydown' , ( event ) => {
913+ if (
914+ event . key !== 'Escape'
915+ || ! this . missingModelsTypeFilterMenuOpen
916+ ) {
917+ return ;
918+ }
919+ event . preventDefault ( ) ;
920+ setTypeFilterMenuOpen ( false ) ;
921+ browser . querySelector ( '[data-missing-type-filter-toggle]' ) ?. focus ( ) ;
922+ } ) ;
923+ }
829924
830925 const refreshBtn = container . querySelector ( '#mr-refresh-missing-analysis' ) ;
831926 if ( refreshBtn && refreshBtn . dataset . mlRefreshBound !== 'true' ) {
@@ -861,7 +956,11 @@ export const missingBrowserMethods = {
861956 const key = row . dataset . missingKey ;
862957 if ( ! key || key === this . selectedMissingModelKey ) return ;
863958 this . selectedMissingModelKey = key ;
864- this . displayMissingModels ( container , data , { selectionOnly : true } ) ;
959+ this . displayMissingModels (
960+ container ,
961+ getCurrentData ( ) ,
962+ { selectionOnly : true }
963+ ) ;
865964 } ;
866965
867966 const selectAllCheckbox = container . querySelector ( '.mr-missing-select-all-check' ) ;
@@ -873,7 +972,7 @@ export const missingBrowserMethods = {
873972 selectAllCheckbox . addEventListener ( 'change' , ( ) => {
874973 const shouldSelectAll = selectAllCheckbox . checked ;
875974 this . batchSelectedMissingKeys = shouldSelectAll
876- ? new Set ( ( sortedMissingModels || [ ] ) . map ( missing => this . getMissingModelKey ( missing ) ) )
975+ ? new Set ( getCurrentMissingModels ( ) . map ( missing => this . getMissingModelKey ( missing ) ) )
877976 : new Set ( ) ;
878977 this . lastBatchSelectedMissingKey = null ;
879978 this . refreshBatchSelectionUi ( ) ;
@@ -882,21 +981,24 @@ export const missingBrowserMethods = {
882981 }
883982
884983 container . querySelectorAll ( '.mr-missing-list-row' ) . forEach ( row => {
984+ if ( this . _wiredMissingModelRows . has ( row ) ) return ;
985+ this . _wiredMissingModelRows . add ( row ) ;
885986 const checkbox = row . querySelector ( '.mr-missing-row-check' ) ;
886987 if ( checkbox ) {
887988 checkbox . addEventListener ( 'click' , ( event ) => {
888989 event . stopPropagation ( ) ;
889- checkbox . dataset . shiftClick = event . shiftKey ? '1' : '0' ;
990+ checkbox . _missingShiftClick = event . shiftKey ;
890991 } ) ;
891992 checkbox . addEventListener ( 'change' , ( event ) => {
892993 const key = row . dataset . missingKey ;
893994 if ( ! key ) return ;
894995 const selected = checkbox . checked ;
895- const isShiftRange = event . shiftKey || checkbox . dataset . shiftClick === '1' ;
996+ const isShiftRange = event . shiftKey || checkbox . _missingShiftClick === true ;
997+ const currentMissingModels = getCurrentMissingModels ( ) ;
896998
897999 if ( isShiftRange && this . lastBatchSelectedMissingKey ) {
8981000 this . applyBatchSelectionRange (
899- sortedMissingModels ,
1001+ currentMissingModels ,
9001002 this . lastBatchSelectedMissingKey ,
9011003 key ,
9021004 selected
@@ -925,6 +1027,8 @@ export const missingBrowserMethods = {
9251027 } ) ;
9261028
9271029 container . querySelectorAll ( '.mr-missing-row-locate' ) . forEach ( button => {
1030+ if ( this . _wiredMissingLocateButtons . has ( button ) ) return ;
1031+ this . _wiredMissingLocateButtons . add ( button ) ;
9281032 button . addEventListener ( 'click' , ( event ) => {
9291033 event . preventDefault ( ) ;
9301034 event . stopPropagation ( ) ;
@@ -938,7 +1042,9 @@ export const missingBrowserMethods = {
9381042 } ) ;
9391043
9401044 const selectedMissing = sortedMissingModels . find ( missing => this . getMissingModelKey ( missing ) === this . selectedMissingModelKey ) ;
941- if ( ! selectedMissing ) return ;
1045+ const detailPreserved = this . _missingBrowserDetailPreserved === true ;
1046+ this . _missingBrowserDetailPreserved = false ;
1047+ if ( ! selectedMissing || detailPreserved ) return ;
9421048
9431049 const selectedIndex = sortedMissingModels . indexOf ( selectedMissing ) ;
9441050 this . wireMissingModelDetail ( container , selectedMissing , selectedIndex ) ;
@@ -2244,7 +2350,7 @@ export const missingBrowserMethods = {
22442350 return ;
22452351 }
22462352
2247- container . innerHTML = this . renderMissingModelsBrowser (
2353+ const browserHtml = this . renderMissingModelsBrowser (
22482354 sortedMissingModels ,
22492355 this . selectedMissingModelKey ,
22502356 sortedMissingModels . length ,
@@ -2261,6 +2367,12 @@ export const missingBrowserMethods = {
22612367 activeTypeFilter,
22622368 }
22632369 ) ;
2370+ this . _missingBrowserDetailPreserved = false ;
2371+ const browserPatched = options . preserveBrowser
2372+ && this . patchMissingModelsBrowserElement ( container , browserHtml ) ;
2373+ if ( ! browserPatched ) {
2374+ container . innerHTML = browserHtml ;
2375+ }
22642376 this . wireMissingModelsBrowser ( container , data , sortedMissingModels ) ;
22652377 this . restoreMissingListScroll ( container , listScrollSnapshot ) ;
22662378 this . scheduleInitialUrnLocalMatchRefresh ( sortedMissingModels , container , data ) ;
0 commit comments