Here you go.. o)

Now featuring:
- progress dialog
- search dialog
- search only in extension
- search only in stem
- search full filename (if extension/stem checkboxes enabled)
- optionally exclude folder (must be entered in the button code, as there is no way to have 2 text fields right now)
- input validation.. o)
- previously used search parameters will be preserved per tab
<?xml version="1.0"?>
<button backcol="none" display="both" textcol="none">
<label>Folder Selector</label>
<tip>Folder Selector</tip>
<icon1>#newcommand</icon1>
<function type="script">
<instruction>@script jscript</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>// Simple dialog based search to select folders.</instruction>
<instruction>// Folders will be selected if they contain matching files and at the same</instruction>
<instruction>// time do not contain a subfolder (optional).</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>var defaultSearch = new SearchParams(</instruction>
<instruction> /*search string*/ 'iso',</instruction>
<instruction> /*search extension*/ true,</instruction>
<instruction> /*search stem*/ false,</instruction>
<instruction> /*subfolder name*/ 'video_ts',</instruction>
<instruction> /*exclude subfolder*/ true</instruction>
<instruction>);</instruction>
<instruction />
<instruction>var lastSearch = null;</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function OnClick(data){</instruction>
<instruction> DOpus.ClearOutput();</instruction>
<instruction> data.func.command.ClearFiles();</instruction>
<instruction />
<instruction> //get enumerator and count of selected folders or complete list of folders</instruction>
<instruction> var folders = GetFolders(data);</instruction>
<instruction />
<instruction> //get a combination of default, last used and current dialog search params</instruction>
<instruction> var params = GetSearchParams(data); if (!params) return; //dialog cancelled</instruction>
<instruction />
<instruction> //save current search params</instruction>
<instruction> SaveSearchParams(data, params);</instruction>
<instruction />
<instruction> //init, open and return progress dialog</instruction>
<instruction> var progress = OpenProgressDialog( data, "Folder Selector..", folders.count);</instruction>
<instruction />
<instruction> var searchMode = params.GetSearchMode();</instruction>
<instruction> while (!folders.enumerator.atEnd() ) {</instruction>
<instruction> var folder = folders.enumerator.item(); folders.enumerator.moveNext();</instruction>
<instruction> dout("Folder ["+folder.name+"]..");</instruction>
<instruction> progress.SetName(folder.name);</instruction>
<instruction> //if subfolder to exclude is given, search subfolders before looking for matching files</instruction>
<instruction> if (params.excludeFolder && defaultSearch.excludeFolderName!="" && SubFolderExists( folder.path+"\\"+folder.name, defaultSearch.excludeFolderName)){</instruction>
<instruction> dout(" Contains subfolder ["+defaultSearch.excludeFolderName+"], skipping folder.");</instruction>
<instruction> progress.StepFiles(1);</instruction>
<instruction> continue;</instruction>
<instruction> }</instruction>
<instruction> if (exists = FileExists( folder.path+"\\"+folder.name, params.searchMe, searchMode)){</instruction>
<instruction> dout(" Contains at least one matching file.");</instruction>
<instruction> data.func.command.AddFile(folder);</instruction>
<instruction> }</instruction>
<instruction> progress.StepFiles(1);</instruction>
<instruction> }</instruction>
<instruction />
<instruction> data.func.command.RunCommand("Select FROMSCRIPT DESELECTNOMATCH MAKEVISIBLE");</instruction>
<instruction> progress.Hide();</instruction>
<instruction> DOMsgBox("ISO-FolderSelector","Found "+data.func.command.files.count+" folder(s) matching your search.","Ok");</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function ReadFolder( path, recurse, exception){</instruction>
<instruction> if (recurse == undefined) recurse=false;</instruction>
<instruction> if (exception == undefined) exception=true;</instruction>
<instruction> var fEnum = DOpus.FSUtil.ReadDir( path, true);</instruction>
<instruction> if (fEnum.error!=0){</instruction>
<instruction> var error = "ReadFolder(): Error reading folder ["+name+"], code ["+fEnum.error+"].";</instruction>
<instruction> if (exception) throw error;</instruction>
<instruction> dout(error);</instruction>
<instruction> }</instruction>
<instruction> return fEnum;</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function SubFolderExists( folderPath, subFolderName){</instruction>
<instruction> subFolderName = subFolderName.toLowerCase();</instruction>
<instruction> var fEnum = ReadFolder( folderPath, true, true);</instruction>
<instruction> while (!fEnum.complete && (fItem = fEnum.Next()))</instruction>
<instruction> if (fItem.is_dir && (fItem.name.toLowerCase() == subFolderName))</instruction>
<instruction> return true;</instruction>
<instruction> return false;</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function FileExists( folderPath, searchMe, searchMode){</instruction>
<instruction> if (searchMode == undefined) searchMode='full';</instruction>
<instruction> searchMe = searchMe.toLowerCase();</instruction>
<instruction> if (searchMode=='ext') searchMe=searchMe.replace('\.','');</instruction>
<instruction> var fEnum = ReadFolder( folderPath, true, true);</instruction>
<instruction> while (!fEnum.complete && (fItem = fEnum.Next())){</instruction>
<instruction> if (fItem.is_dir) continue;</instruction>
<instruction> switch (searchMode){</instruction>
<instruction> case 'ext':</instruction>
<instruction> if (fItem.ext.toLowerCase()=="."+searchMe)</instruction>
<instruction> return true;</instruction>
<instruction> break;</instruction>
<instruction> case 'stem':</instruction>
<instruction> if (fItem.name_stem.toLowerCase().indexOf(searchMe)!=-1)</instruction>
<instruction> return true;</instruction>
<instruction> break;</instruction>
<instruction> case 'full':</instruction>
<instruction> default:</instruction>
<instruction> if (fItem.name.toLowerCase().indexOf(searchMe)!=-1)</instruction>
<instruction> return true;</instruction>
<instruction> break;</instruction>
<instruction> }</instruction>
<instruction> }</instruction>
<instruction> return false;</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function GetFolders(data){</instruction>
<instruction> if (data.func.sourcetab.selected_dirs.count)</instruction>
<instruction> var dirs = data.func.sourcetab.selected_dirs;</instruction>
<instruction> else</instruction>
<instruction> var dirs = data.func.sourcetab.dirs;</instruction>
<instruction> return { enumerator:new Enumerator(dirs), count:dirs.count};</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function DoDialog( params){</instruction>
<instruction> var dlg = DOpus.Dlg</instruction>
<instruction> dlg.window = DOpus.Listers(0);</instruction>
<instruction> dlg.message = "Please enter string/extension to search for:\n ";</instruction>
<instruction> dlg.title = "Folder Selector..";</instruction>
<instruction> dlg.buttons = "OK|Cancel";</instruction>
<instruction> dlg.icon = "question";</instruction>
<instruction />
<instruction> dlg.max = 128; //enable text field</instruction>
<instruction> dlg['default'] = params.searchMe;</instruction>
<instruction />
<instruction> dlg.options(0).label = "search extension";</instruction>
<instruction> dlg.options(0).state = params.searchExtension;</instruction>
<instruction />
<instruction> dlg.options(1).label = "search stem";</instruction>
<instruction> dlg.options(1).state = params.searchStem;</instruction>
<instruction />
<instruction> if (defaultSearch.excludeFolderName!=""){</instruction>
<instruction> dlg.options(2).label = "may not contain folder ("+defaultSearch.excludeFolderName+")";</instruction>
<instruction> dlg.options(2).state = params.excludeFolder;</instruction>
<instruction> }</instruction>
<instruction> return dlg;</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function OpenProgressDialog( data, title, numFiles){</instruction>
<instruction> var progress = data.func.command.progress;</instruction>
<instruction> progress.delay = false;</instruction>
<instruction> progress.abort = true;</instruction>
<instruction> progress.Init(data.func.sourcetab, title);</instruction>
<instruction> progress.AddFiles(numFiles);</instruction>
<instruction> progress.Show();</instruction>
<instruction> return progress;</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function SearchParams(searchMe, searchExtension, searchStem, excludeFolderName, excludeFolder){</instruction>
<instruction> if (searchMe == undefined) searchMe='iso';</instruction>
<instruction> if (searchExtension == undefined) searchExtension=true;</instruction>
<instruction> if (searchStem == undefined) searchStem=false;</instruction>
<instruction> if (excludeFolderName == undefined) excludeFolderName="";</instruction>
<instruction> if (excludeFolder == undefined) excludeFolder=false;</instruction>
<instruction> this.searchMe=searchMe;</instruction>
<instruction> this.searchExtension=searchExtension;</instruction>
<instruction> this.searchStem=searchStem;</instruction>
<instruction> this.excludeFolderName=excludeFolderName;</instruction>
<instruction> this.excludeFolder=excludeFolder;</instruction>
<instruction> this.GetSearchMode = function(){</instruction>
<instruction> var searchMode='full';</instruction>
<instruction> if (this.searchExtension && !this.searchStem) searchMode='ext';</instruction>
<instruction> if (!this.searchExtension && this.searchStem) searchMode='stem';</instruction>
<instruction> return searchMode;</instruction>
<instruction> }</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function GetSearchParamsFromDialog(dlg){</instruction>
<instruction> var dlgSearchParams = new SearchParams();</instruction>
<instruction> dlgSearchParams.searchMe = dlg.input;</instruction>
<instruction> dlgSearchParams.searchExtension = dlg.options(0).state;</instruction>
<instruction> dlgSearchParams.searchStem = dlg.options(1).state;</instruction>
<instruction> if (defaultSearch.excludeFolderName){ //exclude subfolder name given, so option is present to exclude it</instruction>
<instruction> dlgSearchParams.excludeFolder = dlg.options(2).state;</instruction>
<instruction> }</instruction>
<instruction> return dlgSearchParams;</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function ValidateSearchParams(params){</instruction>
<instruction> if (!params)</instruction>
<instruction> return false;</instruction>
<instruction> if (!params.searchExtension && !params.searchStem){</instruction>
<instruction> DOMsgBox("Folder Selector..", "You need to select stem or extension or both!", "Oops!");</instruction>
<instruction> return false;</instruction>
<instruction> }</instruction>
<instruction> if (params.searchMe==""){</instruction>
<instruction> DOMsgBox("Folder Selector..", "You forgot to enter a string to search for!", "Oops!");</instruction>
<instruction> return false;</instruction>
<instruction> }</instruction>
<instruction> return true;</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function GetDefaultOrLastSearchParams(data){</instruction>
<instruction> var search = defaultSearch;</instruction>
<instruction> if (data.func.sourcetab.vars.exists("lastSearch"))</instruction>
<instruction> search = Vector2Search(data.func.sourcetab.vars.get("lastSearch"));</instruction>
<instruction> return search;</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function GetCombinedSearchParams(data){</instruction>
<instruction> var userSearchParams = GetDefaultOrLastSearchParams(data);</instruction>
<instruction> var dlg = DoDialog(userSearchParams);</instruction>
<instruction> var result=dlg.Show();</instruction>
<instruction> if (result==0){</instruction>
<instruction> dout("Folder Selector dialog cancelled.");</instruction>
<instruction> return null;</instruction>
<instruction> }</instruction>
<instruction> return GetSearchParamsFromDialog(dlg);</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function GetSearchParams(data){</instruction>
<instruction> var params = null;</instruction>
<instruction> while (!ValidateSearchParams(params)){</instruction>
<instruction> params = GetCombinedSearchParams(data);</instruction>
<instruction> if (!params)</instruction>
<instruction> return false; //dialog canceled</instruction>
<instruction> }</instruction>
<instruction> return params;</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function SaveSearchParams(data, params){</instruction>
<instruction> data.func.sourcetab.vars.set("lastSearch", Search2Vector(params));</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function Search2Vector( search){</instruction>
<instruction> var vector = DOpus.NewVector();</instruction>
<instruction> vector.push_back(search.searchMe);</instruction>
<instruction> vector.push_back(search.searchExtension);</instruction>
<instruction> vector.push_back(search.searchStem);</instruction>
<instruction> vector.push_back(search.excludeFolderName);</instruction>
<instruction> vector.push_back(search.excludeFolder);</instruction>
<instruction> return vector;</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function Vector2Search( vector){</instruction>
<instruction> return new SearchParams( vector(0), vector(1), vector(2), vector(3), vector(4));</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function DOMsgBox(title,message,buttons){</instruction>
<instruction> var dlg = DOpus.Dlg</instruction>
<instruction> dlg.window = DOpus.Listers(0);</instruction>
<instruction> dlg.message = message;</instruction>
<instruction> dlg.title = title;</instruction>
<instruction> dlg.buttons = buttons;</instruction>
<instruction> var result = dlg.Show();</instruction>
<instruction> dout(title+" - "+message+" - "+buttons+" -> "+result);</instruction>
<instruction> return result;</instruction>
<instruction>}</instruction>
<instruction>///////////////////////////////////////////////////////////////////////////////</instruction>
<instruction>function dout(text){</instruction>
<instruction> DOpus.Output(text);</instruction>
<instruction>}</instruction>
</function>
</button>