Skip to main content
Inspiring
August 12, 2016
Answered

Problem file browsing on OSX - How to use a filter function?

  • August 12, 2016
  • 6 replies
  • 1263 views

I'm working with file browsing atm using the File objects in JSX and the openDlg -method and quite frankly, this is driving me insane.

Did some crazy person decide that it was a good idea to have the filter-flag on the openDlg -method totally different for Win and OSX? On windows you use a string for the filtering, on OSX it want's a function!

I've checked the documentation and also searched this forum and I can't even find an example of how to set this up so that it works for both Windows and OSX?

Ok so I've found the syntax, but it still doesn't make sense.

fileMask = function(file){file.name.match(/\.psd$/i) ? true:false;}


Here we have the psd-extension hardcoded into the regular extension. But what if we want it to be a variable? And what if t he file doesn't exist yet.

Basically what I want is for the user to:
Browse to a folder

set a file name

save.

The extension type should be locked!

Compared to the windows way of doing things, the OSX way of using a filter function is nonsensical, overly complex and downright annoying!

EDIT: I also discovered that you can't write a file name on OSX unless the file already exists. Come on! Is this the wrong dialog type or something???

This topic has been closed for replies.
Correct answer matias.kiviniemi

Here's my script for prompting a file which handles the Win/Mac differences

function isWindows() {

  return app.systemInformation.indexOf("Operating System: Windows") >= 0

}

function isMac() {

  return app.systemInformation.indexOf("Operating System: Mac") >= 0

}

function promptFile(filter_extension) {

  var filter = null

  if (isMac()) {

       if (filter_extension) {

            var filter_regex = new RegExp("[^\.]*\."+filter_extension+"$")

            filter = function (file_entry) {

                 return filter_regex.test(file_entry.name)

            }

       } else {

            filter = function () { return true }

       }

  } else if (isWindows()) {

       if (filter_extension) {

            filter = filter_extension.charAt(0).toUpperCase() + filter_extension.slice(1)+"-files:*."+filter_extension

       } else {

            filter = "All files:*.*"

       }

  } else {

       filter = null

  }

  var f = File.openDialog("Select your file", filter, false)

  if (f) {

       return f.fsName.replace(/\\/g, "/") // sanitize to forward slash

  }

}

}

6 replies

Inspiring
August 18, 2016

Here's how I do it in xtools, You can replace f.strf("%e") with whatever function you use to extract a file extension.

This expects a Windows-style file selection string and returns that or a filter function if it's on a Mac.

isWindows = function() {

  return $.os.match(/windows/i);

};

Stdlib.createFileSelect = function(str) {
  if (isWindows()) {
    return str;
  }

  if (!str.constructor == String) {
    return str;
  }

  var exts = [];
  var rex = /\*\.(\*|[\w]+)(.*)/;
  var m;
  while (m = rex.exec(str)) {
    exts.push(m[1].toLowerCase());
    str = m[2];
  }

  function macSelect(f) {
    var name = decodeURI(f.absoluteURI).toLowerCase();
    var _exts = macSelect.exts;

    // alert(name);

    while (f.alias) {
      try {
        f = f.resolve();
      } catch (e) {
        f = null;
      }

      if (f == null) {
        return false;
      }
    }

    if (f instanceof Folder) {
      return true;
    }
    var fext = f.strf("%e").toLowerCase();

    for (var i = 0; i < _exts.length; i++) {
      var ext = _exts;
      if (ext == '*') {
        return true;
      }
      if (fext == ext) {
        return true;       
      }
  }
    return false;
  }

  macSelect.exts = exts;
  return macSelect;
};

HeimdaalAuthor
Inspiring
August 17, 2016

I'll make a separate thread about the grey-out problem as the original question has been answered already. I marked your response as the correct answer Matias.

HeimdaalAuthor
Inspiring
August 16, 2016

I added an extra parameter to promptFile() - sending in the old path to the file (oldPath variable), then

var path = new File(oldPath);

var f = path.openDialog("Select your file", filter)

openDialog doesn't work so I changed it to openDlg. The old path is opened up and the filter is correct (Windows) but I am not able to actually save a new file. Makes sense since it's the openDlg and not the saveDlg.

But when using saveDlg the starting file name is the filter! Also if I specify a name I get an error message saying: "myName. The file name is not valid" - this is regardless of how I write it!
Also tried saveDialog() - which doesn't allow me to specify a path in advance - and I get exactly the same kind of error. The file name is not valid.

HeimdaalAuthor
Inspiring
August 15, 2016

Thanks.

That looks overly complicated for something that should be so simple.

I did try your code though Matias and it works. But how can I change it to work with old paths?

This is my current code:

function browser2(objType, ext, fullPath){

    if (objType == "file"){

        var path = new File(fullPath);

        if(File.fs != "Windows") ext = function(){return true}; // OSX wai u do diz?

        var dialog = path.openDlg(dialogMessage, ext);

        while (dialog.alias){

            dialog = dialog.resolve().saveDlg(dialogMessage);

        }

    }else if (objType == "folder"){

        var path = new Folder(fullPath);

        var dialog = path.selectDlg(dialogMessage);

        while (dialog.alias){

            dialog = dialog.resolve.selectDlg(dialogMessage);

        }

    }

}

On Windows this works exactly as it should. I tell the function if I want to browse for a file or a folder. I can also provide an old path and the dialog will start browsing from that point. The openDlg and selectDlg -methods respects the path to the object.


On OSX the dialog ALWAYS browser for folders ONLY and always from the last browsing point made on the system. The path to the object doesn't even seem to matter for the openDlg and selectDlg methods - Why?

matias.kiviniemi
Legend
August 16, 2016

In Mac the filter is a function that gets called for every file in a folder and you are supposed to return true/false depending if you are interested of it. That's why if it's null (basically assuming false for every file), you just get the folders. The Win version is simpler (and less powerfull) just specifying a set of file extensions as a specially formatted string.

My script is intended that you can just give the extension you are looking for or null for all files.

HeimdaalAuthor
Inspiring
August 16, 2016

I see.

Well there seems to be something wrong: I modified your script so that I send in an extra parameter with the old path, and then I use saveDialog. Filter works, but the starting location when browsing is incorrect. Additionally I am unable to actually save the file (error says the file name is not valid!).

// Doesn't work at all. Opens up browsing starting from the user's desktop. Has the filter as a name.

var path = new File(oldPath);

var f = path.saveDialog("Select your file", filter, false);

// Doesn't work at all. Opens up browsing starting from the user's desktop. Has the filter as a name.

var path = new File(oldPath);

var f = path.saveDlg("Select your file", filter, false);

// Opens up the correct file path - but doesn't allow saving

var path = new File(oldPath);

var f = path.openDlg("Select your file", filter, false);

// Doesn't open up dialog

var path = new File(oldPath);

var f = path.openDialog("Select your file", filter, false);

Inspiring
August 13, 2016

In xtools, I do it like this:

Stdlib.createFileSelect = function(str) {
  if (isWindows()) {
    return str;
  }

  if (!str.constructor == String) {
    return str;
  }

  var exts = [];
  var rex = /\*\.(\*|[\w]+)(.*)/;
  var m;
  while (m = rex.exec(str)) {
    exts.push(m[1].toLowerCase());
    str = m[2];
  }

  function macSelect(f) {
    var name = decodeURI(f.absoluteURI).toLowerCase();
    var _exts = macSelect.exts;

    // alert(name);

    while (f.alias) {
      try {
        f = f.resolve();
      } catch (e) {
        f = null;
      }

      if (f == null) {
        return false;
      }
    }

    if (f instanceof Folder) {
      return true;
    }
    var fext = f.strf("%e").toLowerCase();

    for (var i = 0; i < _exts.length; i++) {
      var ext = _exts;
      if (ext == '*') {
        return true;
      }
      if (fext == ext) {
        return true;       
      }
      // if (name.match(RegExp("\\." + ext + "$", "i")) != null) {
      //   return true;
      // }
    }
    return false;
  }

  macSelect.exts = exts;
  return macSelect;
};

This way, you can use a Windows file filter and it converts it to a Mac file filter. I've used this for years in multiple projects.

matias.kiviniemi
matias.kiviniemiCorrect answer
Legend
August 13, 2016

Here's my script for prompting a file which handles the Win/Mac differences

function isWindows() {

  return app.systemInformation.indexOf("Operating System: Windows") >= 0

}

function isMac() {

  return app.systemInformation.indexOf("Operating System: Mac") >= 0

}

function promptFile(filter_extension) {

  var filter = null

  if (isMac()) {

       if (filter_extension) {

            var filter_regex = new RegExp("[^\.]*\."+filter_extension+"$")

            filter = function (file_entry) {

                 return filter_regex.test(file_entry.name)

            }

       } else {

            filter = function () { return true }

       }

  } else if (isWindows()) {

       if (filter_extension) {

            filter = filter_extension.charAt(0).toUpperCase() + filter_extension.slice(1)+"-files:*."+filter_extension

       } else {

            filter = "All files:*.*"

       }

  } else {

       filter = null

  }

  var f = File.openDialog("Select your file", filter, false)

  if (f) {

       return f.fsName.replace(/\\/g, "/") // sanitize to forward slash

  }

}

}