kasper / phoenix

A lightweight macOS window and app manager scriptable with JavaScript
https://kasper.github.io/phoenix/
Other
4.36k stars 129 forks source link

Ensuring input modals stay in focus and able to fire change events #326

Closed fabiospampinato closed 1 year ago

fabiospampinato commented 1 year ago

With the following code I see two problems:

  const APPS = ['1Password', 'Xcode'];

  function fuzzyMatch(needle, haystack) {
    if(needle === "" || haystack === "") return true;
    needle = needle.toLowerCase().replace(/ /g, "");
    haystack = haystack.toLowerCase();
    // All characters in needle must be present in haystack
    var j = 0; // haystack position
    for(var i = 0; i < needle.length; i++) {
        // Go down the haystack until we find the current needle character
        while(needle[i] !== haystack[j]) {
            j++;
            // If we reached the end of the haystack, then this is not a match
            if(j === haystack.length) {
                return false;
            }
        }
        // Here, needle character is same as haystack character
        //console.log(needle + ":" + i + " === " + haystack + ":" + j);
    }
    // At this point, we have matched every single letter in the needle without returning false
    return true;
  }

  const modal = Modal.build ({
    origin: {
      x: 300,
      y: 300
    },
    weight: 25,
    animationDuration: .2,
    appearance: 'dark',
    text: 'Search...',
    isInput: true,
    icon: App.get ( 'Phoenix' ).icon (),
    textDidChange ( text ) {
      // appendFile ( '/Users/fabio/Desktop/output.txt', `[${text}]\n` );
      const app = APPS.find ( app => fuzzyMatch ( text, app ) );
      // appendFile ( '/Users/fabio/Desktop/output.txt', `${text} - ${app}\n` );
    }
  });

  modal.show ();
fabiospampinato commented 1 year ago

Somehow one of these input modals survived restarting Phoenix for me, so I can't close it anymore 🤔


Edit: it seems to survive a reload if Phoenix reloads itself, but it seems to close itself correctly if I call Phoenix.reload manually myself. Though it doesn't behave consistently, so maybe I'm seeing a pattern that doesn't exist.


Edit: also each time I open a new modal at the same coordinates it opens slightly offset from the point I set, which seems symptomatic of some other, possibly related, bug.

kasper commented 1 year ago

@fabiospampinato Hi, thanks for the report! After debugging this looks to me as a memory management issue. I clarified the documentation that you must always keep a reference for the modal to stay active. Otherwise the callback for text changes will not get called once it gets released in the background.

To avoid mistakes, I also changed it so that Modal#show() will return the modal itself for chaining. Finally, there was an issue that the window was not getting closed properly when it got deallocated from the JavaScript context. This should also now be fixed.