@@ -22,6 +22,7 @@ export class JSONEditorDialog {
2222 async show ( ) {
2323 // Get current JSON
2424 const currentJSON = this . parentDialog . manager . exportToJSON ( ) ;
25+ let stopEditorTooltips = ( ) => { } ;
2526 log . debug ( 'Opening JSON editor dialog' , {
2627 jsonLength : currentJSON . length
2728 } ) ;
@@ -51,6 +52,7 @@ export class JSONEditorDialog {
5152 this . editor . destroy ( ) ;
5253 this . editor = null ;
5354 }
55+ stopEditorTooltips ( ) ;
5456 tooltipManager . destroy ( ) ;
5557 wrapper . close ( ) ;
5658 } ) ;
@@ -139,6 +141,7 @@ export class JSONEditorDialog {
139141
140142 // Add drag-and-drop functionality for JSON files
141143 this . setupDragAndDrop ( editorContainer , validationMsg ) ;
144+ stopEditorTooltips = this . replaceNativeEditorTooltips ( editorContainer , tooltipManager ) ;
142145
143146 content . appendChild ( editorContainer ) ;
144147 dialog . appendChild ( content ) ;
@@ -151,6 +154,7 @@ export class JSONEditorDialog {
151154 this . editor . destroy ( ) ;
152155 this . editor = null ;
153156 }
157+ stopEditorTooltips ( ) ;
154158 tooltipManager . destroy ( ) ;
155159 wrapper . close ( ) ;
156160 } ) ;
@@ -180,6 +184,63 @@ export class JSONEditorDialog {
180184 } ) ;
181185 }
182186
187+ /**
188+ * Routes JSONEditor/Ace title tooltips through the dialog tooltip manager.
189+ * Ace recreates controls while editing, so new and updated title attributes
190+ * must be handled continuously to avoid native and managed tooltips overlapping.
191+ *
192+ * @param {HTMLElement } container - JSONEditor root element
193+ * @param {TooltipManager } tooltipManager - Dialog tooltip manager
194+ * @returns {Function } Cleanup callback
195+ */
196+ replaceNativeEditorTooltips ( container , tooltipManager ) {
197+ const attachedElements = new WeakSet ( ) ;
198+
199+ const replaceTitle = ( element ) => {
200+ const tooltipText = element ?. getAttribute ?. ( 'title' ) ;
201+ if ( ! tooltipText ) return ;
202+
203+ element . dataset . tooltipText = tooltipText ;
204+ element . removeAttribute ( 'title' ) ;
205+
206+ if ( ! attachedElements . has ( element ) ) {
207+ tooltipManager . attach ( element ) ;
208+ attachedElements . add ( element ) ;
209+ }
210+ } ;
211+
212+ const replaceTitlesInTree = ( root ) => {
213+ replaceTitle ( root ) ;
214+ root ?. querySelectorAll ?. ( '[title]' ) . forEach ( replaceTitle ) ;
215+ } ;
216+
217+ replaceTitlesInTree ( container ) ;
218+
219+ if ( typeof MutationObserver === 'undefined' ) {
220+ return ( ) => { } ;
221+ }
222+
223+ const observer = new MutationObserver ( ( mutations ) => {
224+ mutations . forEach ( ( mutation ) => {
225+ if ( mutation . type === 'attributes' ) {
226+ replaceTitle ( mutation . target ) ;
227+ return ;
228+ }
229+
230+ mutation . addedNodes . forEach ( replaceTitlesInTree ) ;
231+ } ) ;
232+ } ) ;
233+
234+ observer . observe ( container , {
235+ subtree : true ,
236+ childList : true ,
237+ attributes : true ,
238+ attributeFilter : [ 'title' ]
239+ } ) ;
240+
241+ return ( ) => observer . disconnect ( ) ;
242+ }
243+
183244 /**
184245 * Sets up drag-and-drop functionality for JSON files
185246 * @param {HTMLElement } container - Container element to attach drag-and-drop
@@ -296,16 +357,25 @@ export class JSONEditorDialog {
296357 * @returns {HTMLElement } Info element
297358 */
298359 createInfoMessage ( ) {
299- const infoDiv = document . createElement ( 'div' ) ;
300- infoDiv . className = 'resolution-master-json-editor-info' ;
301- infoDiv . innerHTML = `
302- 💡 <strong>Direct JSON editing</strong><br>
360+ const infoDetails = document . createElement ( 'details' ) ;
361+ infoDetails . className = 'resolution-master-json-editor-info' ;
362+
363+ const summary = document . createElement ( 'summary' ) ;
364+ summary . className = 'resolution-master-json-editor-info-summary' ;
365+ summary . innerHTML = '💡 <strong>Direct JSON editing</strong>' ;
366+
367+ const content = document . createElement ( 'div' ) ;
368+ content . className = 'resolution-master-json-editor-info-content' ;
369+ content . innerHTML = `
303370 Edit the JSON below to modify custom presets and hidden built-in presets.<br>
304371 You can also drag & drop a .json file onto the editor to load it.<br>
305372 Changes will replace current configuration when you click "Apply Changes".
306373 ` ;
307-
308- return infoDiv ;
374+
375+ infoDetails . appendChild ( summary ) ;
376+ infoDetails . appendChild ( content ) ;
377+
378+ return infoDetails ;
309379 }
310380
311381 /**
0 commit comments