toolkit/components/filepicker/content/filepicker.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 const nsIFilePicker       = Components.interfaces.nsIFilePicker;
     8 const nsIProperties       = Components.interfaces.nsIProperties;
     9 const NS_DIRECTORYSERVICE_CONTRACTID = "@mozilla.org/file/directory_service;1";
    10 const NS_IOSERVICE_CONTRACTID = "@mozilla.org/network/io-service;1";
    11 const nsITreeBoxObject = Components.interfaces.nsITreeBoxObject;
    12 const nsIFileView = Components.interfaces.nsIFileView;
    13 const NS_FILEVIEW_CONTRACTID = "@mozilla.org/filepicker/fileview;1";
    14 const nsITreeView = Components.interfaces.nsITreeView;
    15 const nsILocalFile = Components.interfaces.nsILocalFile;
    16 const nsIFile = Components.interfaces.nsIFile;
    17 const NS_LOCAL_FILE_CONTRACTID = "@mozilla.org/file/local;1";
    18 const NS_PROMPTSERVICE_CONTRACTID = "@mozilla.org/embedcomp/prompt-service;1";
    20 var sfile = Components.classes[NS_LOCAL_FILE_CONTRACTID].createInstance(nsILocalFile);
    21 var retvals;
    22 var filePickerMode;
    23 var homeDir;
    24 var treeView;
    25 var allowURLs;
    27 var textInput;
    28 var okButton;
    30 var gFilePickerBundle;
    32 // name of new directory entered by the user to be remembered
    33 // for next call of newDir() in case something goes wrong with creation
    34 var gNewDirName = { value: "" };
    36 function filepickerLoad() {
    37   gFilePickerBundle = document.getElementById("bundle_filepicker");
    39   textInput = document.getElementById("textInput");
    40   okButton = document.documentElement.getButton("accept");
    41   treeView = Components.classes[NS_FILEVIEW_CONTRACTID].createInstance(nsIFileView);
    43   if (window.arguments) {
    44     var o = window.arguments[0];
    45     retvals = o.retvals; /* set this to a global var so we can set return values */
    46     const title = o.title;
    47     filePickerMode = o.mode;
    48     if (o.displayDirectory) {
    49       const directory = o.displayDirectory.path;
    50     }
    52     const initialText = o.defaultString;
    53     const filterTitles = o.filters.titles;
    54     const filterTypes = o.filters.types;
    55     const numFilters = filterTitles.length;
    57     document.title = title;
    58     allowURLs = o.allowURLs;
    60     if (initialText) {
    61       textInput.value = initialText;
    62     }
    63   }
    65   if (filePickerMode != nsIFilePicker.modeOpen && filePickerMode != nsIFilePicker.modeOpenMultiple) {
    66     var newDirButton = document.getElementById("newDirButton");
    67     newDirButton.removeAttribute("hidden");
    68   }
    70   if (filePickerMode == nsIFilePicker.modeGetFolder) {
    71     var textInputLabel = document.getElementById("textInputLabel");
    72     textInputLabel.value = gFilePickerBundle.getString("dirTextInputLabel");
    73     textInputLabel.accessKey = gFilePickerBundle.getString("dirTextInputAccesskey");
    74   }
    76   if ((filePickerMode == nsIFilePicker.modeOpen) ||
    77       (filePickerMode == nsIFilePicker.modeOpenMultiple) ||
    78       (filePickerMode == nsIFilePicker.modeSave)) {
    80     /* build filter popup */
    81     var filterPopup = document.createElement("menupopup");
    83     for (var i = 0; i < numFilters; i++) {
    84       var menuItem = document.createElement("menuitem");
    85       if (filterTypes[i] == "..apps")
    86         menuItem.setAttribute("label", filterTitles[i]);
    87       else
    88         menuItem.setAttribute("label", filterTitles[i] + " (" + filterTypes[i] + ")");
    89       menuItem.setAttribute("filters", filterTypes[i]);
    90       filterPopup.appendChild(menuItem);
    91     }
    93     var filterMenuList = document.getElementById("filterMenuList");
    94     filterMenuList.appendChild(filterPopup);
    95     if (numFilters > 0)
    96       filterMenuList.selectedIndex = 0;
    97     var filterBox = document.getElementById("filterBox");
    98     filterBox.removeAttribute("hidden");
   100     filterMenuList.selectedIndex = o.filterIndex;
   102     treeView.setFilter(filterTypes[o.filterIndex]);
   104   } else if (filePickerMode == nsIFilePicker.modeGetFolder) {
   105     treeView.showOnlyDirectories = true;
   106   }
   108   // The dialog defaults to an "open" icon, change it to "save" if applicable
   109   if (filePickerMode == nsIFilePicker.modeSave)
   110     okButton.setAttribute("icon", "save");
   112   // start out with a filename sort
   113   handleColumnClick("FilenameColumn");
   115   try {
   116     setOKAction();
   117   } catch (exception) {
   118     // keep it set to "OK"
   119   }
   121   // setup the dialogOverlay.xul button handlers
   122   retvals.buttonStatus = nsIFilePicker.returnCancel;
   124   var tree = document.getElementById("directoryTree");
   125   if (filePickerMode == nsIFilePicker.modeOpenMultiple)
   126     tree.removeAttribute("seltype");
   128   tree.treeBoxObject.view = treeView;
   130   // Start out with the ok button disabled since nothing will be
   131   // selected and nothing will be in the text field.
   132   okButton.disabled = filePickerMode != nsIFilePicker.modeGetFolder;
   134   // This allows the window to show onscreen before we begin
   135   // loading the file list
   137   setTimeout(setInitialDirectory, 0, directory);
   138 }
   140 function setInitialDirectory(directory)
   141 {
   142   // Start in the user's home directory
   143   var dirService = Components.classes[NS_DIRECTORYSERVICE_CONTRACTID]
   144                              .getService(nsIProperties);
   145   homeDir = dirService.get("Home", Components.interfaces.nsIFile);
   147   if (directory) {
   148     sfile.initWithPath(directory);
   149     if (!sfile.exists() || !sfile.isDirectory())
   150       directory = false;
   151   }
   152   if (!directory) {
   153     sfile.initWithPath(homeDir.path);
   154   }
   156   gotoDirectory(sfile);
   157 }
   159 function onFilterChanged(target)
   160 {
   161   // Do this on a timeout callback so the filter list can roll up
   162   // and we don't keep the mouse grabbed while we are refiltering.
   164   setTimeout(changeFilter, 0, target.getAttribute("filters"));
   165 }
   167 function changeFilter(filterTypes)
   168 {
   169   window.setCursor("wait");
   170   treeView.setFilter(filterTypes);
   171   window.setCursor("auto");
   172 }
   174 function showErrorDialog(titleStrName, messageStrName, file)
   175 {
   176   var errorTitle =
   177     gFilePickerBundle.getFormattedString(titleStrName, [file.path]);
   178   var errorMessage =
   179     gFilePickerBundle.getFormattedString(messageStrName, [file.path]);
   180   var promptService =
   181     Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService);
   183   promptService.alert(window, errorTitle, errorMessage);
   184 }
   186 function openOnOK()
   187 {
   188   var dir = treeView.selectedFiles.queryElementAt(0, nsIFile);
   189   if (dir)
   190     gotoDirectory(dir);
   192   return false;
   193 }
   195 function selectOnOK()
   196 {
   197   var errorTitle, errorMessage, promptService;
   198   var ret = nsIFilePicker.returnOK;
   200   var isDir = false;
   201   var isFile = false;
   203   retvals.filterIndex = document.getElementById("filterMenuList").selectedIndex;
   204   retvals.fileURL = null;
   206   if (allowURLs) {
   207     try {
   208       var ios = Components.classes[NS_IOSERVICE_CONTRACTID].getService(Components.interfaces.nsIIOService);
   209       retvals.fileURL = ios.newURI(textInput.value, null, null);
   210       var fileList = [];
   211       if (retvals.fileURL instanceof Components.interfaces.nsIFileURL)
   212         fileList.push(retvals.fileURL.file);
   213       gFilesEnumerator.mFiles = fileList;
   214       retvals.files = gFilesEnumerator;
   215       retvals.buttonStatus = ret;
   217       return true;
   218     } catch (e) {
   219     }
   220   }
   222   var fileList = processPath(textInput.value);
   223   if (!fileList) {
   224     // generic error message, should probably never happen
   225     showErrorDialog("errorPathProblemTitle",
   226                     "errorPathProblemMessage",
   227                     textInput.value);
   228     return false;
   229   }
   231   var curFileIndex;
   232   for (curFileIndex = 0; curFileIndex < fileList.length &&
   233          ret != nsIFilePicker.returnCancel; ++curFileIndex) {
   234     var file = fileList[curFileIndex].QueryInterface(nsIFile);
   236     // try to normalize - if this fails we will ignore the error
   237     // because we will notice the
   238     // error later and show a fitting error alert.
   239     try{
   240       file.normalize();
   241     } catch(e) {
   242       //promptService.alert(window, "Problem", "normalize failed, continuing");
   243     }
   245     var fileExists = file.exists();
   247     if (!fileExists && (filePickerMode == nsIFilePicker.modeOpen ||
   248                         filePickerMode == nsIFilePicker.modeOpenMultiple)) {
   249       showErrorDialog("errorOpenFileDoesntExistTitle",
   250                       "errorOpenFileDoesntExistMessage",
   251                       file);
   252       return false;
   253     }
   255     if (!fileExists && filePickerMode == nsIFilePicker.modeGetFolder) {
   256       showErrorDialog("errorDirDoesntExistTitle",
   257                       "errorDirDoesntExistMessage",
   258                       file);
   259       return false;
   260     }
   262     if (fileExists) {
   263       isDir = file.isDirectory();
   264       isFile = file.isFile();
   265     }
   267     switch(filePickerMode) {
   268     case nsIFilePicker.modeOpen:
   269     case nsIFilePicker.modeOpenMultiple:
   270       if (isFile) {
   271         if (file.isReadable()) {
   272           retvals.directory = file.parent.path;
   273         } else {
   274           showErrorDialog("errorOpeningFileTitle",
   275                           "openWithoutPermissionMessage_file",
   276                           file);
   277           ret = nsIFilePicker.returnCancel;
   278         }
   279       } else if (isDir) {
   280         if (!sfile.equals(file)) {
   281           gotoDirectory(file);
   282         }
   283         textInput.value = "";
   284         doEnabling();
   285         ret = nsIFilePicker.returnCancel;
   286       }
   287       break;
   288     case nsIFilePicker.modeSave:
   289       if (isFile) { // can only be true if file.exists()
   290         if (!file.isWritable()) {
   291           showErrorDialog("errorSavingFileTitle",
   292                           "saveWithoutPermissionMessage_file",
   293                           file);
   294           ret = nsIFilePicker.returnCancel;
   295         } else {
   296           // we need to pop up a dialog asking if you want to save
   297           var confirmTitle = gFilePickerBundle.getString("confirmTitle");
   298           var message =
   299             gFilePickerBundle.getFormattedString("confirmFileReplacing",
   300                                                  [file.path]);
   302           promptService = Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService);
   303           var rv = promptService.confirm(window, confirmTitle, message);
   304           if (rv) {
   305             ret = nsIFilePicker.returnReplace;
   306             retvals.directory = file.parent.path;
   307           } else {
   308             ret = nsIFilePicker.returnCancel;
   309           }
   310         }
   311       } else if (isDir) {
   312         if (!sfile.equals(file)) {
   313           gotoDirectory(file);
   314         }
   315         textInput.value = "";
   316         doEnabling();
   317         ret = nsIFilePicker.returnCancel;
   318       } else {
   319         var parent = file.parent;
   320         if (parent.exists() && parent.isDirectory() && parent.isWritable()) {
   321           retvals.directory = parent.path;
   322         } else {
   323           var oldParent = parent;
   324           while (!parent.exists()) {
   325             oldParent = parent;
   326             parent = parent.parent;
   327           }
   328           errorTitle =
   329             gFilePickerBundle.getFormattedString("errorSavingFileTitle",
   330                                                  [file.path]);
   331           if (parent.isFile()) {
   332             errorMessage =
   333               gFilePickerBundle.getFormattedString("saveParentIsFileMessage",
   334                                                    [parent.path, file.path]);
   335           } else {
   336             errorMessage =
   337               gFilePickerBundle.getFormattedString("saveParentDoesntExistMessage",
   338                                                    [oldParent.path, file.path]);
   339           }
   340           if (!parent.isWritable()) {
   341             errorMessage =
   342               gFilePickerBundle.getFormattedString("saveWithoutPermissionMessage_dir", [parent.path]);
   343           }
   344           promptService = Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService);
   345           promptService.alert(window, errorTitle, errorMessage);
   346           ret = nsIFilePicker.returnCancel;
   347         }
   348       }
   349       break;
   350     case nsIFilePicker.modeGetFolder:
   351       if (isDir) {
   352         retvals.directory = file.parent.path;
   353       } else { // if nothing selected, the current directory will be fine
   354         retvals.directory = sfile.path;
   355       }
   356       break;
   357     }
   358   }
   360   gFilesEnumerator.mFiles = fileList;
   362   retvals.files = gFilesEnumerator;
   363   retvals.buttonStatus = ret;
   365   return (ret != nsIFilePicker.returnCancel);
   366 }
   368 var gFilesEnumerator = {
   369   mFiles: null,
   370   mIndex: 0,
   372   hasMoreElements: function()
   373   {
   374     return (this.mIndex < this.mFiles.length);
   375   },
   376   getNext: function()
   377   {
   378     if (this.mIndex >= this.mFiles.length)
   379       throw Components.results.NS_ERROR_FAILURE;
   380     return this.mFiles[this.mIndex++];
   381   }
   382 };
   384 function onCancel()
   385 {
   386   // Close the window.
   387   retvals.buttonStatus = nsIFilePicker.returnCancel;
   388   retvals.file = null;
   389   retvals.files = null;
   390   return true;
   391 }
   393 function onDblClick(e) {
   394   // we only care about button 0 (left click) events
   395   if (e.button != 0) return;
   397   var t = e.originalTarget;
   398   if (t.localName != "treechildren")
   399     return;
   401   openSelectedFile();
   402 }
   404 function openSelectedFile() {
   405   var fileList = treeView.selectedFiles;
   406   if (fileList.length == 0)
   407     return;
   409   var file = fileList.queryElementAt(0, nsIFile);
   410   if (file.isDirectory())
   411     gotoDirectory(file);
   412   else if (file.isFile())
   413     document.documentElement.acceptDialog();
   414 }
   416 function onClick(e) {
   417   var t = e.originalTarget;
   418   if (t.localName == "treecol")
   419     handleColumnClick(t.id);
   420 }
   422 function convertColumnIDtoSortType(columnID) {
   423   var sortKey;
   425   switch (columnID) {
   426   case "FilenameColumn":
   427     sortKey = nsIFileView.sortName;
   428     break;
   429   case "FileSizeColumn":
   430     sortKey = nsIFileView.sortSize;
   431     break;
   432   case "LastModifiedColumn":
   433     sortKey = nsIFileView.sortDate;
   434     break;
   435   default:
   436     dump("unsupported sort column: " + columnID + "\n");
   437     sortKey = 0;
   438     break;
   439   }
   441   return sortKey;
   442 }
   444 function handleColumnClick(columnID) {
   445   var sortType = convertColumnIDtoSortType(columnID);
   446   var sortOrder = (treeView.sortType == sortType) ? !treeView.reverseSort : false;
   447   treeView.sort(sortType, sortOrder);
   449   // set the sort indicator on the column we are sorted by
   450   var sortedColumn = document.getElementById(columnID);
   451   if (treeView.reverseSort) {
   452     sortedColumn.setAttribute("sortDirection", "descending");
   453   } else {
   454     sortedColumn.setAttribute("sortDirection", "ascending");
   455   }
   457   // remove the sort indicator from the rest of the columns
   458   var currCol = sortedColumn.parentNode.firstChild;
   459   while (currCol) {
   460     if (currCol != sortedColumn && currCol.localName == "treecol")
   461       currCol.removeAttribute("sortDirection");
   462     currCol = currCol.nextSibling;
   463   }
   464 }
   466 function onKeypress(e) {
   467   if (e.keyCode == 8) /* backspace */
   468     goUp();
   470   /* enter is handled by the ondialogaccept handler */
   471 }
   473 function doEnabling() {
   474   if (filePickerMode != nsIFilePicker.modeGetFolder)
   475   // Maybe add check if textInput.value would resolve to an existing
   476   // file or directory in .modeOpen. Too costly I think.
   477     okButton.disabled = (textInput.value == "")
   478 }
   480 function onTreeFocus(event) {
   481   // Reset the button label and enabled/disabled state.
   482   onFileSelected(treeView.selectedFiles);
   483 }
   485 function setOKAction(file) {
   486   var buttonLabel;
   487   var buttonIcon = "open"; // used in all but one case
   489   if (file && file.isDirectory()) {
   490     document.documentElement.setAttribute("ondialogaccept", "return openOnOK();");
   491     buttonLabel = gFilePickerBundle.getString("openButtonLabel");
   492   }
   493   else {
   494     document.documentElement.setAttribute("ondialogaccept", "return selectOnOK();");
   495     switch(filePickerMode) {
   496     case nsIFilePicker.modeGetFolder:
   497       buttonLabel = gFilePickerBundle.getString("selectFolderButtonLabel");
   498       break;
   499     case nsIFilePicker.modeOpen:
   500     case nsIFilePicker.modeOpenMultiple:
   501       buttonLabel = gFilePickerBundle.getString("openButtonLabel");
   502       break;
   503     case nsIFilePicker.modeSave:
   504       buttonLabel = gFilePickerBundle.getString("saveButtonLabel");
   505       buttonIcon = "save";
   506       break;
   507     }
   508   }
   509   okButton.setAttribute("label", buttonLabel);
   510   okButton.setAttribute("icon", buttonIcon);
   511 }
   513 function onSelect(event) {
   514   onFileSelected(treeView.selectedFiles);
   515 }
   517 function onFileSelected(/* nsIArray */ selectedFileList) {
   518   var validFileSelected = false;
   519   var invalidSelection = false;
   520   var file;
   521   var fileCount = selectedFileList.length;
   523   for (var index = 0; index < fileCount; ++index) {
   524     file = selectedFileList.queryElementAt(index, nsIFile);
   525     if (file) {
   526       var path = file.leafName;
   528       if (path) {
   529         var isDir = file.isDirectory();
   530         if ((filePickerMode == nsIFilePicker.modeGetFolder) || !isDir) {
   531           if (!validFileSelected)
   532             textInput.value = "";
   533           addToTextFieldValue(path);
   534         }
   536         if (isDir && fileCount > 1) {
   537           // The user has selected multiple items, and one of them is
   538           // a directory.  This is not a valid state, so we'll disable
   539           // the ok button.
   540           invalidSelection = true;
   541         }
   543         validFileSelected = true;
   544       }
   545     }
   546   }
   548   if (validFileSelected) {
   549     setOKAction(file);
   550     okButton.disabled = invalidSelection;
   551   } else if (filePickerMode != nsIFilePicker.modeGetFolder)
   552     okButton.disabled = (textInput.value == "");
   553 }
   555 function addToTextFieldValue(path)
   556 {
   557   var newValue = "";
   559   if (textInput.value == "")
   560     newValue = path.replace(/\"/g, "\\\"");
   561   else {
   562     // Quote the existing text if needed,
   563     // then append the new filename (quoted and escaped)
   564     if (textInput.value[0] != '"')
   565       newValue = '"' + textInput.value.replace(/\"/g, "\\\"") + '"';
   566     else
   567       newValue = textInput.value;
   569     newValue = newValue + ' "' + path.replace(/\"/g, "\\\"") + '"';
   570   }
   572   textInput.value = newValue;
   573 }
   575 function onTextFieldFocus() {
   576   setOKAction(null);
   577   doEnabling();
   578 }
   580 function onDirectoryChanged(target)
   581 {
   582   var path = target.getAttribute("label");
   584   var file = Components.classes[NS_LOCAL_FILE_CONTRACTID].createInstance(nsILocalFile);
   585   file.initWithPath(path);
   587   if (!sfile.equals(file)) {
   588     // Do this on a timeout callback so the directory list can roll up
   589     // and we don't keep the mouse grabbed while we are loading.
   591     setTimeout(gotoDirectory, 0, file);
   592   }
   593 }
   595 function populateAncestorList(directory) {
   596   var menu = document.getElementById("lookInMenu");
   598   while (menu.hasChildNodes()) {
   599     menu.removeChild(menu.firstChild);
   600   }
   602   var menuItem = document.createElement("menuitem");
   603   menuItem.setAttribute("label", directory.path);
   604   menuItem.setAttribute("crop", "start");
   605   menu.appendChild(menuItem);
   607   // .parent is _sometimes_ null, see bug 121489.  Do a dance around that.
   608   var parent = directory.parent;
   609   while (parent && !parent.equals(directory)) {
   610     menuItem = document.createElement("menuitem");
   611     menuItem.setAttribute("label", parent.path);
   612     menuItem.setAttribute("crop", "start");
   613     menu.appendChild(menuItem);
   614     directory = parent;
   615     parent = directory.parent;
   616   }
   618   var menuList = document.getElementById("lookInMenuList");
   619   menuList.selectedIndex = 0;
   620 }
   622 function goUp() {
   623   try {
   624     var parent = sfile.parent;
   625   } catch(ex) { dump("can't get parent directory\n"); }
   627   if (parent) {
   628     gotoDirectory(parent);
   629   }
   630 }
   632 function goHome() {
   633   gotoDirectory(homeDir);
   634 }
   636 function newDir() {
   637   var file;
   638   var promptService =
   639     Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService);
   640   var dialogTitle =
   641     gFilePickerBundle.getString("promptNewDirTitle");
   642   var dialogMsg =
   643     gFilePickerBundle.getString("promptNewDirMessage");
   644   var ret = promptService.prompt(window, dialogTitle, dialogMsg, gNewDirName, null, {value:0});
   646   if (ret) {
   647     file = processPath(gNewDirName.value);
   648     if (!file) {
   649       showErrorDialog("errorCreateNewDirTitle",
   650                       "errorCreateNewDirMessage",
   651                       file);
   652       return false;
   653     }
   655     file = file[0].QueryInterface(nsIFile);
   656     if (file.exists()) {
   657       showErrorDialog("errorNewDirDoesExistTitle",
   658                       "errorNewDirDoesExistMessage",
   659                       file);
   660       return false;
   661     }
   663     var parent = file.parent;
   664     if (!(parent.exists() && parent.isDirectory() && parent.isWritable())) {
   665       var oldParent = parent;
   666       while (!parent.exists()) {
   667         oldParent = parent;
   668         parent = parent.parent;
   669       }
   670       if (parent.isFile()) {
   671         showErrorDialog("errorCreateNewDirTitle",
   672                         "errorCreateNewDirIsFileMessage",
   673                         parent);
   674         return false;
   675       }
   676       if (!parent.isWritable()) {
   677         showErrorDialog("errorCreateNewDirTitle",
   678                         "errorCreateNewDirPermissionMessage",
   679                         parent);
   680         return false;
   681       }
   682     }
   684     try {
   685       file.create(nsIFile.DIRECTORY_TYPE, 0755); 
   686     } catch (e) {
   687       showErrorDialog("errorCreateNewDirTitle",
   688                       "errorCreateNewDirMessage",
   689                       file);
   690       return false;
   691     }
   692     file.normalize(); // ... in case ".." was used in the path
   693     gotoDirectory(file);
   694     // we remember and reshow a dirname if something goes wrong
   695     // so that errors can be corrected more easily. If all went well,
   696     // reset the default value to blank
   697     gNewDirName = { value: "" }; 
   698   }
   699   return true;
   700 }
   702 function gotoDirectory(directory) {
   703   window.setCursor("wait");
   704   try {
   705     populateAncestorList(directory);
   706     treeView.setDirectory(directory);
   707     document.getElementById("errorShower").selectedIndex = 0;
   708   } catch(ex) {
   709     document.getElementById("errorShower").selectedIndex = 1;
   710   }
   712   window.setCursor("auto");
   714   if (filePickerMode == nsIFilePicker.modeGetFolder) {
   715     textInput.value = "";
   716   }
   717   textInput.focus();
   718   textInput.setAttribute("autocompletesearchparam", directory.path);
   719   sfile = directory;
   720 }
   722 function toggleShowHidden(event) {
   723   treeView.showHiddenFiles = !treeView.showHiddenFiles;
   724 }
   726 // from the current directory and whatever was entered
   727 // in the entry field, try to make a new path. This
   728 // uses "/" as the directory separator, "~" as a shortcut
   729 // for the home directory (but only when seen at the start
   730 // of a path), and ".." to denote the parent directory.
   731 // returns an array of the files listed,
   732 // or false if an error occurred.
   733 function processPath(path)
   734 {
   735   var fileArray = new Array();
   736   var strLength = path.length;
   738   if (path[0] == '"' && filePickerMode == nsIFilePicker.modeOpenMultiple &&
   739       strLength > 1) {
   740     // we have a quoted list of filenames, separated by spaces.
   741     // iterate the list and process each file.
   743     var curFileStart = 1;
   745     while (1) {
   746       var nextQuote;
   748       // Look for an unescaped quote
   749       var quoteSearchStart = curFileStart + 1;
   750       do {
   751         nextQuote = path.indexOf('"', quoteSearchStart);
   752         quoteSearchStart = nextQuote + 1;
   753       } while (nextQuote != -1 && path[nextQuote - 1] == '\\');
   755       if (nextQuote == -1) {
   756         // we have a filename with no trailing quote.
   757         // just assume that the filename ends at the end of the string.
   759         if (!processPathEntry(path.substring(curFileStart), fileArray))
   760           return false;
   761         break;
   762       }
   764       if (!processPathEntry(path.substring(curFileStart, nextQuote), fileArray))
   765         return false;
   767       curFileStart = path.indexOf('"', nextQuote + 1);
   768       if (curFileStart == -1) {
   769         // no more quotes, but if we're not at the end of the string,
   770         // go ahead and process the remaining text.
   772         if (nextQuote < strLength - 1)
   773           if (!processPathEntry(path.substring(nextQuote + 1), fileArray))
   774             return false;
   775         break;
   776       }
   777       ++curFileStart;
   778     }
   779   } else {
   780     // If we didn't start with a quote, assume we just have a single file.
   781     if (!processPathEntry(path, fileArray))
   782       return false;
   783   }
   785   return fileArray;
   786 }
   788 function processPathEntry(path, fileArray)
   789 {
   790   var filePath;
   791   var file;
   793   try {
   794     file = sfile.clone().QueryInterface(nsILocalFile);
   795   } catch(e) {
   796     dump("Couldn't clone\n"+e);
   797     return false;
   798   }
   800   var tilde_file = file.clone();
   801   tilde_file.append("~");
   802   if (path[0] == '~' &&                        // Expand ~ to $HOME, except:
   803       !(path == "~" && tilde_file.exists()) && // If ~ was entered and such a file exists, don't expand
   804       (path.length == 1 || path[1] == "/"))    // We don't want to expand ~file to ${HOME}file
   805     filePath = homeDir.path + path.substring(1);
   806   else
   807     filePath = path;
   809   // Unescape quotes
   810   filePath = filePath.replace(/\\\"/g, "\"");
   812   if (filePath[0] == '/')   /* an absolute path was entered */
   813     file.initWithPath(filePath);
   814   else if ((filePath.indexOf("/../") > 0) ||
   815            (filePath.substr(-3) == "/..") ||
   816            (filePath.substr(0,3) == "../") ||
   817            (filePath == "..")) {
   818     /* appendRelativePath doesn't allow .. */
   819     try{
   820       file.initWithPath(file.path + "/" + filePath);
   821     } catch (e) {
   822       dump("Couldn't init path\n"+e);
   823       return false;
   824     }
   825   }
   826   else {
   827     try {
   828       file.appendRelativePath(filePath);
   829     } catch (e) {
   830       dump("Couldn't append path\n"+e);
   831       return false;
   832     }
   833   }
   835   fileArray[fileArray.length] = file;
   836   return true;
   837 }

mercurial