• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

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

Contributor ,
Aug 12, 2016 Aug 12, 2016

Copy link to clipboard

Copied

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???

TOPICS
Actions and scripting

Views

923

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Enthusiast , Aug 13, 2016 Aug 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) {

                 retu

...

Votes

Translate

Translate
Adobe
Enthusiast ,
Aug 13, 2016 Aug 13, 2016

Copy link to clipboard

Copied

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

  }

}

}

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Advisor ,
Aug 13, 2016 Aug 13, 2016

Copy link to clipboard

Copied

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Aug 15, 2016 Aug 15, 2016

Copy link to clipboard

Copied

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?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Aug 16, 2016 Aug 16, 2016

Copy link to clipboard

Copied

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Aug 16, 2016 Aug 16, 2016

Copy link to clipboard

Copied

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);

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Aug 16, 2016 Aug 16, 2016

Copy link to clipboard

Copied

Current code - Problems mentioned in the comments

function isWindows(){

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

}

function isMac(){

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

}

function promptFile(filter_extension, oldPath){

    var filter = null

    if (isMac()){

        if (filter_extension){

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

            filter = function (oldPath){

                return filter_regex.test(oldPath.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

    }

    // alert("oldPath is: " + oldPath);

    // Starts browsing where it is supposed to start browsing (oldPath) and allows me to overwrite existing files.

    // However, when starting the dialog the file name is always oldFileName.atlas.*.atlas

    // Also, when trying to save a new file I get an error saying that the file name is invalid!

    var path = new File(oldPath);

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

    if (f){

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

    }

}

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Aug 16, 2016 Aug 16, 2016

Copy link to clipboard

Copied

To be honest, I've never used saveDlg so not sure if that changes something. But at least one problem, you had replaced "file_entry" with "oldPath" in the filter function. What below means is you create a dynamic function that get's called with every file in the dialog window and it tests if the filename is suitable (has proper prefix). Variable file_entry is the parameter (of type File) of the function, using oldPath might confuse it with the higher level variable.

filter = function (file_entry){ 

  return filter_regex.test(file_entry.name) 

Also make sure you call the function with extension only, i.e. "atlas", not ".atlas" or "*.atlas". And try debugging with ESTK, very easy to make a small text parsing error

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Aug 16, 2016 Aug 16, 2016

Copy link to clipboard

Copied

I checked the docs (javascript tools guide) and saveDlg takes a filter only in Windows, which allows you to set type like *.*, *.atlas. So you can try leaving it out.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Aug 16, 2016 Aug 16, 2016

Copy link to clipboard

Copied

Thanks.

I changed back the file_entry variable and also provided promptFile() with a proper extension.
I had given the function an incorrect string - setting it to "atlas" made things working.

File browsing works on Windows but I get some other weird problem on OSX now:

Every single folder is greyed out.

function isWindows(){

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

}

function isMac(){

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

}

function promptFile(dialogMessage, extFilter, oldPath){

    var filter = null

    if (isMac()){

        if (extFilter){

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

            filter = function (fileEntry){

                return filter_regex.test(fileEntry.name)

            }

        }else{

            filter = function(){ return true }

        }

    }else if (isWindows()){

        if (extFilter){

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

        }else{

            filter = "All files:*.*"

        }

    }else{

        filter = null

    }

    var path = new File(oldPath);

    var f = path.saveDlg(dialogMessage, filter, false);

    if (f){

        return f.fsName.replace(/\\/g, "/")

    }

}

// Start browsing:

promptFile(dialogMessage, extension, fullPath)

The weird thing is that even though the documentation says that the second parameter to saveDlg() is only used by windows, it still appears as if the filter function is working. Sure, ALL folders are greyed out and I am unable to browse, but under "Save As" I have proper extension specified!

Another clue: I get the same problem on OSX with greyed out folders when using openDlg()

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Aug 16, 2016 Aug 16, 2016

Copy link to clipboard

Copied

Heh, this is getting confusing

There seems to be _SEVERAL_ versions of the save dialogs

  • file_entry.saveDlg(): Content of file_entry is the default value but not sure if it's locked to it
  • File.saveDialog(): same as file_entry.saveDlg, but no preselect value. Maybe it's not locked to original dir
  • folder_entry.saveDlg(): seems identical to file_entry.saveDlg, not sure if there is a difference.
  • Folder.selectDialog: seems most general purpose, "just pick a file"

You probably have to just do some trial and error to pick the best one, what rules each has. As far as I see Mac has no option to "create a new file, but only this extension". Extension filter only seems to apply to opening existing and Win (although even there it's just hiding, you can actually set different extension by typing it).

Confusing part is that the "all folders grayed" would implicate it actually wants the filter even though docs say it does not. I.e. youd have to make a filter function that accepts either folders or files with right extension like below (not tested)

filter = function (fileSystemEntry){ 

  if (fileSystemEntry instanceof Folder) {

  return true

  } else {

  return filter_regex.test(fileSystemEntry.name) 

  }

}

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Aug 16, 2016 Aug 16, 2016

Copy link to clipboard

Copied

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Aug 16, 2016 Aug 16, 2016

Copy link to clipboard

Copied

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Advisor ,
Aug 18, 2016 Aug 18, 2016

Copy link to clipboard

Copied

LATEST

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;
};

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines