How to force a File-Save on the current tab from an XUL extension

I’ve created a JavaScript function as part of XUL dialog that can find the name of the user’s current file from the open tab, and check whether any changes have been saved. I would also like it to re-save the file if it is dirty before it goes on to process the file.

I thought using the nsIObserverService to tell Komodo to do a ‘cmd_save’ would do it, but with no luck. The function runs with errors, and correctly identifies a dirty file, but the cmd_save doesn’t save the current file.

The GetPg6() function below runs when XUL dialog loads…

<script type="application/x-javascript" >
<![CDATA[
var Pg6 = "";
var CompileOption = "-htm";

function GetPg6() {
    // Get Komodo koViewService 
    var viewSvc = Components.classes["@activestate.com/koViewService;1"]
    .getService(Components.interfaces.koIViewService);
    
    // Get editor window (scintilla) object view = ko.views.manager.currentView object
    var view = viewSvc.currentView.QueryInterface(Components.interfaces.koIScintillaView);

    // Get koDoc object for manipulation of documents in memory  
    var ko = view.koDoc;    

    // Get scimoz option for manipulation of code buffers
    var scimoz = view.scimoz;
  
    var obsvc = Components.classes["@mozilla.org/observer-service;1"]
    .getService(Components.interfaces.nsIObserverService); 

    view.setFocus();
    //scimoz.beginUndoAction();
    Pg6 = ko.displayPath;
    
    if (/\.pg6/.test(Pg6) ) {
    document.getElementById('qpl_project_name').value = Pg6;
    if (ko.isDirty) {
        qplLog("Saving " + Pg6 + "...", false);
        
        try {
            obsvc.notifyObservers(null, 'command-docommand', 'cmd_save');
        } catch (e) {
            qplLog(e, true);
        }
    }
    
    } else {
    document.getElementById('qpl_build').disabled = true;
    qplLog(Pg6 +  " is not a QPL source program.", false);
    }
    //scimoz.endUndoAction();
    
    return;
}

Any suggestions would be appreciated!

How did you land on observers to send a command? It’s much simpler than that -

ko.commands.doCommand("cmd_save")

I’m building a Komodo Add-on, not a macro, so the ‘ko’ object isn’t available in my JavaScript unless I first get it from Components.classes, no?

It sure is, the only namespace unique to macros (that I’m aware of) is the komodo namespace.

I’m not able to get that to work from a JavaScript function that I launch from an extension overlay in the Tools menu.

For example, this works to launch an alert box to show the path and name of the file in the current editor tab…

<menuitem id="whoami" label="Who am I?" oncommand="WhoAmI();" />

    function WhoAmI() {
        // Get Komodo koViewService 
        var viewSvc = Components.classes["@activestate.com/koViewService;1"]
        .getService(Components.interfaces.koIViewService);
        
        // Get editor window (scintilla) object 
        var view = viewSvc.currentView.QueryInterface(Components.interfaces.koIScintillaView);
    
        // Get koDoc object for manipulation of documents in memory  
        // ko.file object corresponding to files on disk
        var ko = view.koDoc;    
    
        view.setFocus();
        alert(ko.displayPath);
        
        return;
    }

But this fails with the alert message, “TypeError: ko.views.currentView is undefined”…

...
<menuitem id="whoami2" label="Who am I2?" oncommand="WhoAmI2();" />
...
    function WhoAmI2() {
       try{ ko.views.currentView.setFocus(); } catch(e) {alert(e);}
       alert(ko.views.manager.currentView.document.displayPath);
  
       return;

}

I would like the second method to work. Any idea where I’m going wrong?

You want ko.views.manager.currentView, you left out the manager part.

Also keep in mind that if this code loads in a sub-window (eg. a element) you will need to obtain the ko object from the parent window.

Good eye! I’m now traveling out if town but will give this a try when I’m back next week!

Thanks!

BTW - it’s currentView.koDoc … not currentView.document:

       alert(ko.views.manager.currentView.koDoc.displayPath);

Note if you want to make your extension compatible with old versions of Komodo (lol, I think it’s not needed, who use old Komodo builds like Komodo 5.0? :D), you can use this:
var komodo = ko.views.manager.currentView; var koDoc = (komodo.koDoc === undefined ? komodo.document : komodo.koDoc);
I’m take it here: http://docs.activestate.com/komodo/8.5/macroapi.html#macroapi_koDoc

Aha! That’s what wasn’t clear: how to access the ko object!

I’m overlaying the Tools menu and then launching my various extension windows from submenus there. So if I include ko as an argument the menuitem oncommand, and catch it in my function, then I’m in business…

overlay.xul…

<menuitem id="whoami2" label="Who am I2?" oncommand="WhoAmI2(ko);" />

overlay.js…

function WhoAmI2(ko) {
       try{ ko.views.manager.currentView.setFocus(); } catch(e) {alert(e);}
       alert(ko.views.manager.currentView.document.displayPath);

       return;
}

And the same thing works for dialogs by adding ko as an optional argument in the window.openDialog…

window.openDialog("chrome://qplwrapper/content/" + target.id + ".xul", "QPL6", "chrome", ko);

Yea!

Thanks for the tip!