home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 October / maximum-cd-2009-10.iso / DiscContents / Firefox Setup 3.5.exe / nonlocalized / chrome / toolkit.jar / content / global / viewSourceUtils.js < prev    next >
Encoding:
JavaScript  |  2009-06-24  |  11.6 KB  |  281 lines

  1. //@line 38 "e:\builds\moz2_slave\win32_build\build\toolkit\components\viewsource\content\viewSourceUtils.js"
  2.  
  3. /*
  4.  * To keep the global namespace safe, don't define global variables and 
  5.  * functions in this file.
  6.  *
  7.  * This file silently depends on contentAreaUtils.js for
  8.  * getDefaultFileName, getNormalizedLeafName and getDefaultExtension
  9.  */
  10.  
  11. var gViewSourceUtils = {
  12.  
  13.   mnsIWebBrowserPersist: Components.interfaces.nsIWebBrowserPersist,
  14.   mnsIWebProgress: Components.interfaces.nsIWebProgress,
  15.   mnsIWebPageDescriptor: Components.interfaces.nsIWebPageDescriptor,
  16.  
  17.   // Opens view source
  18.   viewSource: function(aURL, aPageDescriptor, aDocument, aLineNumber)
  19.   {
  20.     var prefs = Components.classes["@mozilla.org/preferences-service;1"]
  21.                           .getService(Components.interfaces.nsIPrefBranch);
  22.     if (prefs.getBoolPref("view_source.editor.external"))
  23.       this.openInExternalEditor(aURL, aPageDescriptor, aDocument, aLineNumber);
  24.     else
  25.       this.openInInternalViewer(aURL, aPageDescriptor, aDocument, aLineNumber);
  26.   },
  27.  
  28.   // Opens the interval view source viewer
  29.   openInInternalViewer: function(aURL, aPageDescriptor, aDocument, aLineNumber)
  30.   {
  31.     // try to open a view-source window while inheriting the charset (if any)
  32.     var charset = null;
  33.     var isForcedCharset = false;
  34.     if (aDocument) {
  35.       charset = "charset=" + aDocument.characterSet;
  36.       try { 
  37.         isForcedCharset =
  38.           aDocument.defaultView
  39.                    .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  40.                    .getInterface(Components.interfaces.nsIDOMWindowUtils)
  41.                    .docCharsetIsForced;
  42.       } catch (ex) {
  43.       }
  44.     }
  45.     openDialog("chrome://global/content/viewSource.xul",
  46.                "_blank",
  47.                "all,dialog=no",
  48.                aURL, charset, aPageDescriptor, aLineNumber, isForcedCharset);
  49.   },
  50.  
  51.   // aCallBack is a function accepting two arguments - result (true=success) and a data object
  52.   // It defaults to openInInternalViewer if undefined.
  53.   openInExternalEditor: function(aURL, aPageDescriptor, aDocument, aLineNumber, aCallBack)
  54.   {
  55.     var data = {url: aURL, pageDescriptor: aPageDescriptor, doc: aDocument,
  56.                 lineNumber: aLineNumber};
  57.  
  58.     try {
  59.       var editor = this.getExternalViewSourceEditor();    
  60.       if (!editor) {
  61.         this.handleCallBack(aCallBack, false, data);
  62.         return;
  63.       }
  64.  
  65.       // make a uri
  66.       var ios = Components.classes["@mozilla.org/network/io-service;1"]
  67.                           .getService(Components.interfaces.nsIIOService);
  68.       var charset = aDocument ? aDocument.characterSet : null;
  69.       var uri = ios.newURI(aURL, charset, null);
  70.       data.uri = uri;
  71.  
  72.       var path;
  73.       var contentType = aDocument ? aDocument.contentType : null;
  74.       if (uri.scheme == "file") {    
  75.         // it's a local file; we can open it directly
  76.         path = uri.QueryInterface(Components.interfaces.nsIFileURL).file.path;
  77.         editor.run(false, [path], 1);
  78.         this.handleCallBack(aCallBack, true, data);
  79.       } else {
  80.         // set up the progress listener with what we know so far
  81.         this.viewSourceProgressListener.editor = editor;
  82.         this.viewSourceProgressListener.callBack = aCallBack;
  83.         this.viewSourceProgressListener.data = data;      
  84.         if (!aPageDescriptor) {
  85.           // without a page descriptor, loadPage has no chance of working. download the file.
  86.           var file = this.getTemporaryFile(uri, aDocument, contentType);
  87.           this.viewSourceProgressListener.file = file;
  88.  
  89.           var webBrowserPersist = Components
  90.                                   .classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
  91.                                   .createInstance(this.mnsIWebBrowserPersist);
  92.           // the default setting is to not decode. we need to decode.
  93.           webBrowserPersist.persistFlags = this.mnsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
  94.           webBrowserPersist.progressListener = this.viewSourceProgressListener;
  95.           webBrowserPersist.saveURI(uri, null, null, null, null, file);
  96.  
  97.           // register the file to be deleted on app exit
  98.           Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"]
  99.                     .getService(Components.interfaces.nsPIExternalAppLauncher)
  100.                     .deleteTemporaryFileOnExit(file);
  101.         } else {
  102.           // we'll use nsIWebPageDescriptor to get the source because it may not have to refetch
  103.           // the file from the server
  104.           var webShell = Components.classes["@mozilla.org/webshell;1"].createInstance();
  105.           this.viewSourceProgressListener.webShell = webShell;
  106.           var progress = webShell.QueryInterface(this.mnsIWebProgress);
  107.           progress.addProgressListener(this.viewSourceProgressListener,
  108.                                        this.mnsIWebProgress.NOTIFY_STATE_DOCUMENT);
  109.           var pageLoader = webShell.QueryInterface(this.mnsIWebPageDescriptor);    
  110.           pageLoader.loadPage(aPageDescriptor, this.mnsIWebPageDescriptor.DISPLAY_AS_SOURCE);
  111.         }
  112.       }
  113.     } catch (ex) {
  114.       // we failed loading it with the external editor.
  115.       Components.utils.reportError(ex);
  116.       this.handleCallBack(aCallBack, false, data);
  117.       return;
  118.     }
  119.   },
  120.  
  121.   // Default callback - opens the internal viewer if the external editor failed
  122.   internalViewerFallback: function(result, data)
  123.   {
  124.     if (!result) {
  125.       this.openInInternalViewer(data.url, data.pageDescriptor, data.doc, data.lineNumber);
  126.     }
  127.   },
  128.  
  129.   // Calls the callback, keeping in mind undefined or null values.
  130.   handleCallBack: function(aCallBack, result, data)
  131.   {
  132.     // ifcallback is undefined, default to the internal viewer
  133.     if (aCallBack === undefined) {
  134.       this.internalViewerFallback(result, data);
  135.     } else if (aCallBack) {
  136.       aCallBack(result, data);
  137.     }
  138.   },
  139.  
  140.   // Returns nsIProcess of the external view source editor or null
  141.   getExternalViewSourceEditor: function()
  142.   {
  143.     try {
  144.       let prefPath =
  145.           Components.classes["@mozilla.org/preferences-service;1"]
  146.                     .getService(Components.interfaces.nsIPrefBranch)
  147.                     .getCharPref("view_source.editor.path");
  148.       let viewSourceAppPath =
  149.               Components.classes["@mozilla.org/file/local;1"]
  150.                         .createInstance(Components.interfaces.nsILocalFile);
  151.       viewSourceAppPath.initWithPath(prefPath);
  152.       let editor = Components.classes['@mozilla.org/process/util;1']
  153.                              .createInstance(Components.interfaces.nsIProcess);
  154.       editor.init(viewSourceAppPath);
  155.  
  156.       return editor;
  157.     }
  158.     catch (ex) {
  159.       Components.utils.reportError(ex);
  160.     }
  161.  
  162.     return null;
  163.   },
  164.  
  165.   viewSourceProgressListener: {
  166.  
  167.     mnsIWebProgressListener: Components.interfaces.nsIWebProgressListener,
  168.  
  169.     QueryInterface: function(aIID) {
  170.      if (aIID.equals(this.mnsIWebProgressListener) ||
  171.          aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
  172.          aIID.equals(Components.interfaces.nsISupports))
  173.        return this;
  174.      throw Components.results.NS_NOINTERFACE;
  175.     },
  176.  
  177.     destroy: function() {
  178.         this.webShell = null;
  179.         this.editor = null;
  180.         this.callBack = null;
  181.         this.data = null;
  182.         this.file = null;
  183.     },
  184.  
  185.     onStateChange: function(aProgress, aRequest, aFlag, aStatus) {
  186.       // once it's done loading...
  187.       if ((aFlag & this.mnsIWebProgressListener.STATE_STOP) && aStatus == 0) {
  188.         try {
  189.           if (!this.file) {
  190.             // it's not saved to file yet, it's in the webshell
  191.  
  192.             // get a temporary filename using the attributes from the data object that
  193.             // openInExternalEditor gave us
  194.             this.file = gViewSourceUtils.getTemporaryFile(this.data.uri, this.data.doc, 
  195.                                                           this.data.doc.contentType);
  196.  
  197.             // we have to convert from the source charset.
  198.             var webNavigation = this.webShell.QueryInterface(Components.interfaces.nsIWebNavigation);
  199.             var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
  200.                                      .createInstance(Components.interfaces.nsIFileOutputStream);
  201.             foStream.init(this.file, 0x02 | 0x08 | 0x20, 0664, 0); // write | create | truncate
  202.             var coStream = Components.classes["@mozilla.org/intl/converter-output-stream;1"]
  203.                                      .createInstance(Components.interfaces.nsIConverterOutputStream);
  204.             coStream.init(foStream, this.data.doc.characterSet, 0, null);
  205.  
  206.             // write the source to the file
  207.             coStream.writeString(webNavigation.document.body.textContent);
  208.           
  209.             // clean up
  210.             coStream.close();
  211.             foStream.close();
  212.  
  213.             // register the file to be deleted on app exit
  214.             Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"]
  215.                       .getService(Components.interfaces.nsPIExternalAppLauncher)
  216.                       .deleteTemporaryFileOnExit(this.file);
  217.           }
  218.  
  219.           // Determine the command line arguments to pass to the editor.
  220.           // We currently support a %LINE% placeholder which is set to the passed
  221.           // line number (or to 0 if there's none)
  222.           var editorArgs = [];
  223.           var prefs = Components.classes["@mozilla.org/preferences-service;1"]
  224.                                 .getService(Components.interfaces.nsIPrefBranch);
  225.           var args = prefs.getCharPref("view_source.editor.args");
  226.           if (args) {
  227.             args = args.replace("%LINE%", this.data.lineNumber || "0");
  228.             // add the arguments to the array (keeping quoted strings intact)
  229.             const argumentRE = /"([^"]+)"|(\S+)/g;
  230.             while (argumentRE.test(args))
  231.               editorArgs.push(RegExp.$1 || RegExp.$2);
  232.           }
  233.           editorArgs.push(this.file.path);
  234.           this.editor.run(false, editorArgs, editorArgs.length);
  235.  
  236.           gViewSourceUtils.handleCallBack(this.callBack, true, this.data);
  237.         } catch (ex) {
  238.           // we failed loading it with the external editor.
  239.           Components.utils.reportError(ex);
  240.           gViewSourceUtils.handleCallBack(this.callBack, false, this.data);
  241.         } finally {
  242.           this.destroy();
  243.         }
  244.       }
  245.       return 0;
  246.     },
  247.  
  248.     onLocationChange: function() {return 0;},
  249.     onProgressChange: function() {return 0;},
  250.     onStatusChange: function() {return 0;},
  251.     onSecurityChange: function() {return 0;},
  252.     onLinkIconAvailable: function() {return 0;},
  253.  
  254.     webShell: null,
  255.     editor: null,
  256.     callBack: null,
  257.     data: null,
  258.     file: null
  259.   },
  260.  
  261.   // returns an nsIFile for the passed document in the system temp directory
  262.   getTemporaryFile: function(aURI, aDocument, aContentType) {
  263.     // include contentAreaUtils.js in our own context when we first need it
  264.     if (!this._caUtils) {
  265.       var scriptLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
  266.                                    .getService(Components.interfaces.mozIJSSubScriptLoader);
  267.       this._caUtils = {};
  268.       scriptLoader.loadSubScript("chrome://global/content/contentAreaUtils.js", this._caUtils);
  269.     }
  270.  
  271.     var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"]
  272.                                 .getService(Components.interfaces.nsIProperties);
  273.     var tempFile = fileLocator.get("TmpD", Components.interfaces.nsIFile);
  274.     var fileName = this._caUtils.getDefaultFileName(null, aURI, aDocument, aContentType);
  275.     var extension = this._caUtils.getDefaultExtension(fileName, aURI, aContentType);
  276.     var leafName = this._caUtils.getNormalizedLeafName(fileName, extension);
  277.     tempFile.append(leafName);
  278.     return tempFile;
  279.   }
  280. }
  281.