Copy link to clipboard
Copied
Hi, can there be a feature or any script which allows to select and open-all files in one click.
Currently I have manually goto File>Open recent files and select one by one.
Hi @StarAGā, here's my solution. Run this script and it will show you a list of recent documents to open. Initially they are all selected, but you may choose a subset before clicking "Open".
- Mark
/**
* Shows list of recent documents.
* Click "Open" button to open selected documents.
* Note: will only list documents *that exist*.
* @author m1b
* @discussion https://community.adobe.com/t5/illustrator-discussions/select-and-open-multiple-recent-files-are-once/td-p/13717506
*/
(functio
...
Copy link to clipboard
Copied
Hi @StarAGā, here's my solution. Run this script and it will show you a list of recent documents to open. Initially they are all selected, but you may choose a subset before clicking "Open".
- Mark
/**
* Shows list of recent documents.
* Click "Open" button to open selected documents.
* Note: will only list documents *that exist*.
* @author m1b
* @discussion https://community.adobe.com/t5/illustrator-discussions/select-and-open-multiple-recent-files-are-once/td-p/13717506
*/
(function () {
var settings = {
showUI: true,
pathsToOpen: getRecentFilePaths(true),
openDocumentsWithFitAll: false,
};
if (settings.showUI) {
var result = showUI(settings);
if (result == 2)
// user cancelled UI
return;
}
for (var i = 0; i < settings.pathsToOpen.length; i++) {
app.open(File(settings.pathsToOpen[i]));
app.selection = null;
if (settings.openDocumentsWithFitAll)
app.executeMenuCommand("fitall");
}
})();
/**
* Returns paths of open documents.
* If `paths` array is supplied,
* will add open document paths to it.
* @author m1b
* @version 2023-04-24
* @param {Array<String>} [paths] - array of paths to add to (default: empty).
* @returns {Array<String>} - array of paths.
*/
function getOpenDocumentsPaths(paths) {
paths = path || [];
var unquifier = {};
for (var i = 0; i < paths.length; i++)
unquifier[paths[i]] = true;
for (var i = 0; i < app.documents.length; i++) {
if (!app.documents[i].saved)
continue;
var path = app.documents[i].fullName.fsName;
if (!unquifier[path])
paths.push(path);
}
};
/**
* Returns array of recent files paths.
* @author m1b
* @version 2023-04-24
* @returns {Array<String>}
*/
function getRecentFilePaths(onlyIfFileExists) {
var fileCount = app.preferences.getIntegerPreference("RecentFileNumber");
var recentFilePaths = [];
for (var i = 0; i < fileCount; i++) {
var path;
/*
// recent files might be stored in FileList:
if (app.preferences.getStringPreference('plugin/FileList/file' + i + '/name') != '')
path = app.preferences.getStringPreference('plugin/FileList/file' + i + '/path');
// or in MixedFileList:
else */
if (
app.preferences.getStringPreference('plugin/MixedFileList/file' + i + '/name') != ''
&& app.preferences.getIntegerPreference('plugin/MixedFileList/file' + i + '/type') == 0
)
path = app.preferences.getStringPreference('plugin/MixedFileList/file' + i + '/path');
else
continue;
recentFilePaths.push(path);
}
if (onlyIfFileExists)
recentFilePaths = getPathsThatExist(recentFilePaths);
return recentFilePaths;
};
/**
* Returns subset of paths that
* resolve to actual files.
* @param {Array<String} paths
* @returns {Array<String}
*/
function getPathsThatExist(paths) {
paths = paths || [];
var pathsThatExist = [];
for (var i = 0; i < paths.length; i++) {
var f = File(paths[i]);
if (f.exists)
pathsThatExist.push(paths[i]);
}
return pathsThatExist;
};
/**
* Shows UI for the various divide functions.
* @author m1b
* @version 2023-04-07
* @param {Object} settings - the settings associated with the UI.
*/
function showUI(settings) {
if (settings == undefined)
throw Error('showUI: bad `settings` parameter.');
settings.allPaths = settings.pathsToOpen.slice();
var suppressEvents = false,
columnWidth = 480,
// set up the window
w = new Window("dialog { text:'Open Recent', properties:{ resizeable:true } }"),
// user input view
fileListBox = w.add('listBox', undefined, '', { numberOfColumns: 1, multiselect: true }),
bottomUI = w.add("group {orientation:'row', alignment:['fill','fill'], margins:[0,1,0,0] }"),
buttons = bottomUI.add("group {orientation:'row', alignment:['right','center'], alignChildren:'right' }"),
cancelButton = buttons.add("Button { text: 'Cancel', properties: {name:'cancel'} }"),
okayButton = buttons.add("Button { text:'Open', enabled: true, properties: {name:'ok'} }");
buildListBox(fileListBox, getFileNames(settings.allPaths));
// event handling
fileListBox.addEventListener('change', updateUI);
okayButton.onClick = function () { w.close(1) };
cancelButton.onClick = function () { w.close(2) };
updateUI();
fileListBox.active = true;
// Explr.init(fileListBox);
fileListBox.maximumSize.height = 100;
// show dialog
w.center();
return w.show();
/**
* Updates the UI when controls have changed.
*/
function updateUI() {
if (suppressEvents)
return;
suppressEvents = true;
// update paths to open
var s = fileListBox.selection || [];
if (s != null) {
settings.pathsToOpen = [];
for (var i = 0; i < s.length; i++)
settings.pathsToOpen.push(settings.allPaths[s[i].index]);
}
// update enabled
okayButton.enabled = settings.pathsToOpen.length > 0;
suppressEvents = false;
};
/**
* Builds listbox items.
*/
function buildListBox(listbox, arr, index) {
for (var i = 0; i < arr.length; i++)
listbox.add('item', arr[i]);
if (index == undefined)
listbox.selection = selectAllItems(listbox);
else
listbox.selection = index;
};
/**
* Returns a full selection array.
*/
function selectAllItems(obj) {
var sel = [];
for (var i = 0; i < obj.items.length; i++)
sel[i] = i;
return sel;
}
/**
* Returns array of file names.
* @param {Array<String>} paths - the paths to files.
* @returns {Array<String>} - the file names.
*/
function getFileNames(paths) {
paths = paths || [];
var names = [];
for (var i = 0; i < paths.length; i++)
names.push(decodeURI(File(paths[i]).name));
return names;
};
};
Edit 2023-04-25: removed the step that first looks in the `FileList` dictionary, because it seemed to cause problems. So now script just looks directly in the `MixedFileList` dictionary. Also commented out the "fitall" menu command for OP.
Copy link to clipboard
Copied
Oh, and I've only just written this and only tested on MacOS, AI 27.4.1. If you are on Windows, please let me know if this works correctly. @CarlosCanto would you mind giving a quick test on Windows?
- Mark
Copy link to clipboard
Copied
Works great for me on Windows 10. Only part I'd probably change is that I noticed some files opened with artwork selected and artboards far outside the viewport, so I'd probably add these lines after each document opens:
app.selection = null;
app.executeMenuCommand("fitall");
Copy link to clipboard
Copied
Thanks @Inventsable, great feedback! I'll adjust script. That's interesting about the selection thing. On MacOS the selection isn't preserved between close/open.
- Mark
Copy link to clipboard
Copied
Hi,
Thanks a lot.
Can you please provide it in jsx script format with addition of these lines?
app.selection = null; app.executeMenuCommand("fitall");
Thanks a lot. I needed it badly š
Copy link to clipboard
Copied
It's already edited in the original answer in lines 22 - 23
Copy link to clipboard
Copied
The script is working but not accurately. From the list of recent files, it is skipping some of the latest opened files...
Is it only showing list of last saves? As I have only opened (not saved) some recent files and those are not visible in the list.
Additionally, what is the way to increase this numbers list? And can I see preview thumbnails of it?
Copy link to clipboard
Copied
Thanks @StarAGā, for trying out the script.
1. The list is designed to show the first N recent files (where N is Preferences>File Handling>Number of Recent Files to Display (0-30).
2. Technically, the script shows entries from what you see under File>Open Recent Files menu when Illustrator was last launched (except script excludes files that don't exist anymore). If you open a new file, it will be saved in an sqlite database (RecentDataCache.log) but it won't update the recent files menu until the Illustrator is re-launched. It is possible to get the data out of this database file, eg. something like
sqlite3 [yourPathToDatabaseFile] 'select PROP_NAME FROM RecentThumbnailDataGroup'
So to fix this shortcoming, the script could execute an applescript or vbscript script to write these to a text file (I've done a proof-of-concept in applescript) and then use that, but it's fiddly to pass on to the end user, because they'd have to save the applescript in an executable form and at the same time grant it the necessary permissions.
3. As for thumbnailsāthey are in the RecentDataCache.log file, too, but I won't be doing getting those, sorryāit is a lot more work.
- Mark
P.S. here is the AppleScript proof of concept. This will create a RecentDocuments.log file next to the RecentDataCache.log file.
property localeString : "en_us"
set prefsFolder to POSIX path of (path to preferences folder)
tell application "Adobe Illustrator" to set v to (version)
set text item delimiters to "."
set v to item 1 of (text items of v)
set text item delimiters to ""
set pathToAIPrefs to prefsFolder & "Adobe Illustrator " & v & " Settings/" & localeString & "/"
set pathToRecentDB to pathToAIPrefs & "RecentDataCache.log"
set pathToRecentDocsTextFile to pathToAIPrefs & "RecentDocuments.log"
-- shell command
set cmd to "sqlite3 " & quoted form of pathToRecentDB & " 'select PROP_NAME FROM RecentThumbnailDataGroup'"
do shell script cmd
set _result to (the result as string)
-- write to text file
write_to_file(_result, POSIX file pathToRecentDocsTextFile, false)
on write_to_file(this_data, target_file, append_data) -- (string, file path as string, boolean)
-- try
set the target_file to the target_file as text
log target_file
set the open_target_file to Ā¬
open for access file target_file with write permission
if append_data is false then Ā¬
set eof of the open_target_file to 0
write this_data to the open_target_file starting at eof as Ā«class utf8Ā»
close access the open_target_file
return true
try
close access file target_file
end try
return false
end write_to_file
Copy link to clipboard
Copied
Hi, I am using win10
For some reason script is not displaying whole list of recent files.
The list from 4th to 30th are getting matched and the script is skipping taking numbers 1,2,3\
All recent files are available locally.
Copy link to clipboard
Copied
Hi @StarAGā, if you change the Preferences>File Handling>Number of Recent Files to Display (0-30) to 10, what does it show? If there is a bug in the preference getting, then it should show files 4-10. If there is a bug in the UI, then it will show 1-10. Let me know. My guess is that I didn't set up the UI right to scroll long lists. - Mark
Copy link to clipboard
Copied
Getting the same issue with 10 recent files, using Illustrator 25.4.8
Copy link to clipboard
Copied
Can you try this: in the settings object
var settings = {
showUI: true,
pathsToOpen: getRecentFilePaths(true),
};
try changing "getRecentFilePaths(true)," to "getRecentFilePaths(false)". That will turn off the File.exists checking. Maybe that is giving a false result.
- Mark
Copy link to clipboard
Copied
I can see the skipped files, but now they are named as tmp000000001 and when loading it gives an error
Copy link to clipboard
Copied
Hi @StarAGā, let's try to get to the bottom of this problem. As I mentioned to @jduncan below, I think the issue most likely revolves around my lack of understanding of the FileList vs MixedFileList dictionaries. Is there any chance you could have a look at your prefs file and give me some feedback about which is best to use in your case? It is a plain text file called "Adobe Illustrator Prefs" and it is probably located here:
c:\Users\<UserName>\AppData\Roaming\Adobe\Adobe Illustrator 25 Settings\en_US\x64\Adobe Illustrator Prefs
(just add your username and locale code if not "en_US".
The question I'm asking is, looking at FileList versus MixedFileList elements' children, which list gives the accurate paths to your recent files?
- Mark
Copy link to clipboard
Copied
@StarAGā, another thing to try: make a copy of the script and delete the part that looks first in `FileList` and just use `MixedFileList` (which would work perfectly on my machine). Here's exactly what to delete:
Copy link to clipboard
Copied
Deleting the code worked correctly. Thanks for the correction.
Only small issue is that when it loads the file, the file opens are "Fit to Arboard" criteria. While the saved files are have their own zoom at any particular area. Is this something can be fixed?
I wish Adobe add this feature by default in their coming versions.
Copy link to clipboard
Copied
Do you mean that you want the opened files to keep their saved view? Sure! The script deliberately did the "fitall" menu command. I've added a setting for it out now and set it to false.
And, based on your testing, I've decided to comment out the use of `FileList` dictionary altogether, and we'll see if that is the right way now. Also if, in the previous testing, you turned off the check to see if files exist, you should probably turn that back on.
I've updated script above.
- Mark
Copy link to clipboard
Copied
This did the job. Thanks.
Copy link to clipboard
Copied
it works great on Windows 11 too
Copy link to clipboard
Copied
@m1b, I've been trying to work on something similar for AiCommand Palette but I can't determine the difference between `FileList` and `MixedFileList`. On my Mac, `MixedFileList` seems to be accurate with `File > Open Recent Files` but `FileList` seems to only show files open a long time ago (>1 year). Wasn't sure if you knew the difference between the two lists? Thanks!
Copy link to clipboard
Copied
Hi @jduncan, great question! But unfortunately I probably know less about it than you.
Here's my working out:
1. On my Mac, the `FileList` is completely empty (actually it has elements, with children, but every child is empty, like this:
/FileList {
/file0 {
/name [ 0
]
/size 0L
/lastOpentime [ 0
]
}
/file1 {
/name [ 0
]
/size 0L
/lastOpentime [ 0
]
}
2. The `MixedFileList` matches the recent opened documents at launch time exactly. Same as for you.
3. However, I read an old answer by @Silly-V that used FileList to get the info, so I guessed that they are both used in different environments. This guess might be wrong, or wrongly applied, and is probably causing the OP's issue.
( @Silly-V, if you are around, do you know the answer?)
- Mark
Copy link to clipboard
Copied
Hi @jduncan, based on OP's testing, I'm working on the hypothesis that `MixedFileList` is the way to go and I have commented out the check in `FileList`. We'll see how that goes I guess. - Mark
Copy link to clipboard
Copied
Worked amazing with V2021 and now I updated to V22 / 23, I am seeing issue with the script.
This is not functioning properly. I am not able to click-seclect recent items.
Though, I am able to drag and select many items but not individual.
So with drag select it also selects many items which I don't need and deselection don't work.