2006-07-29 09:38:04 +04:00
|
|
|
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
2006-07-29 09:33:03 +04:00
|
|
|
*
|
2006-07-29 09:38:04 +04:00
|
|
|
* The contents of this file are subject to the Netscape Public License
|
|
|
|
* Version 1.1 (the "License"); you may not use this file except in
|
|
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/NPL/
|
2006-07-29 09:33:03 +04:00
|
|
|
*
|
2006-07-29 09:38:04 +04:00
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
2006-07-29 09:33:03 +04:00
|
|
|
*
|
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
2006-07-29 09:38:04 +04:00
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
2006-07-29 09:33:03 +04:00
|
|
|
*
|
2006-07-29 09:38:04 +04:00
|
|
|
* Contributor(s):
|
2006-07-29 09:39:02 +04:00
|
|
|
* Ben Goodger <ben@netscape.com> (Save File)
|
2006-07-29 09:38:04 +04:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the NPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the NPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
2006-07-29 09:33:03 +04:00
|
|
|
|
2006-07-29 09:33:17 +04:00
|
|
|
/**
|
|
|
|
* Determine whether or not a given focused DOMWindow is in the content
|
|
|
|
* area.
|
|
|
|
**/
|
2006-07-29 09:39:02 +04:00
|
|
|
function isDocumentFrame(aFocusedWindow)
|
|
|
|
{
|
|
|
|
var contentFrames = _content.frames;
|
|
|
|
if (contentFrames.length) {
|
|
|
|
for (var i = 0; i < contentFrames.length; ++i) {
|
|
|
|
if (aFocusedWindow == contentFrames[i])
|
|
|
|
return true;
|
2006-07-29 09:33:17 +04:00
|
|
|
}
|
|
|
|
}
|
2006-07-29 09:39:02 +04:00
|
|
|
return false;
|
|
|
|
}
|
2006-07-29 09:33:17 +04:00
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
function urlSecurityCheck(url, doc)
|
|
|
|
{
|
|
|
|
// URL Loading Security Check
|
|
|
|
var focusedWindow = doc.commandDispatcher.focusedWindow;
|
|
|
|
var sourceWin = isDocumentFrame(focusedWindow) ? focusedWindow.location.href : focusedWindow._content.location.href;
|
|
|
|
const nsIScriptSecurityManager = Components.interfaces.nsIScriptSecurityManager;
|
|
|
|
var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"].getService().
|
|
|
|
QueryInterface(nsIScriptSecurityManager);
|
|
|
|
try {
|
|
|
|
secMan.checkLoadURIStr(sourceWin, url, nsIScriptSecurityManager.STANDARD);
|
|
|
|
} catch (e) {
|
|
|
|
throw "Load of " + url + " denied.";
|
2006-07-29 09:37:09 +04:00
|
|
|
}
|
2006-07-29 09:39:02 +04:00
|
|
|
}
|
2006-07-29 09:37:09 +04:00
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
function openNewWindowWith(url)
|
|
|
|
{
|
|
|
|
urlSecurityCheck(url, document);
|
|
|
|
var newWin;
|
|
|
|
var wintype = document.firstChild.getAttribute('windowtype');
|
2006-07-29 09:37:09 +04:00
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
// if and only if the current window is a browser window and it has a document with a character
|
|
|
|
// set, then extract the current charset menu setting from the current document and use it to
|
|
|
|
// initialize the new browser window...
|
|
|
|
if (window && (wintype == "navigator:browser") &&
|
|
|
|
window._content && window._content.document) {
|
|
|
|
var DocCharset = window._content.document.characterSet;
|
|
|
|
var charsetArg = "charset="+DocCharset;
|
2006-07-29 09:37:09 +04:00
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
//we should "inherit" the charset menu setting in a new window
|
|
|
|
newWin = window.openDialog( getBrowserURL(), "_blank", "chrome,all,dialog=no", url, charsetArg, true );
|
|
|
|
}
|
|
|
|
else { // forget about the charset information.
|
|
|
|
newWin = window.openDialog( getBrowserURL(), "_blank", "chrome,all,dialog=no", url, null, true );
|
2006-07-29 09:33:12 +04:00
|
|
|
}
|
2006-07-29 09:39:02 +04:00
|
|
|
}
|
2006-07-29 09:37:42 +04:00
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
function openNewTabWith(url)
|
|
|
|
{
|
2006-07-29 09:39:05 +04:00
|
|
|
urlSecurityCheck(url, document);
|
2006-07-29 09:39:02 +04:00
|
|
|
var wintype = document.firstChild.getAttribute('windowtype');
|
2006-07-29 09:37:42 +04:00
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
if (window && (wintype == "navigator:browser")) {
|
2006-07-29 09:39:05 +04:00
|
|
|
var browser = getBrowser();
|
|
|
|
var t = browser.addTab(url); // open link in new tab
|
2006-07-29 09:39:02 +04:00
|
|
|
if (pref && !pref.getBoolPref("browser.tabs.loadInBackground"))
|
|
|
|
browser.selectedTab = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function findParentNode(node, parentNode)
|
|
|
|
{
|
|
|
|
if (node && node.nodeType == Node.TEXT_NODE) {
|
|
|
|
node = node.parentNode;
|
2006-07-29 09:37:42 +04:00
|
|
|
}
|
2006-07-29 09:39:02 +04:00
|
|
|
while (node) {
|
|
|
|
var nodeName = node.localName;
|
|
|
|
if (!nodeName)
|
|
|
|
return null;
|
|
|
|
nodeName = nodeName.toLowerCase();
|
|
|
|
if (nodeName == "body" || nodeName == "html" ||
|
|
|
|
nodeName == "#document") {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
if (nodeName == parentNode)
|
|
|
|
return node;
|
|
|
|
node = node.parentNode;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clientelle: (Make sure you don't break any of these)
|
|
|
|
// - File -> Save Page/Frame As...
|
|
|
|
// - Context -> Save Page/Frame As...
|
|
|
|
// - Context -> Save Link As...
|
|
|
|
// - Context -> Save Image As...
|
|
|
|
// - Shift-Click Save Link As
|
|
|
|
//
|
|
|
|
// Try saving each of these types:
|
|
|
|
// - A complete webpage using File->Save Page As, and Context->Save Page As
|
|
|
|
// - A webpage as HTML only using the above methods
|
|
|
|
// - A webpage as Text only using the above methods
|
|
|
|
// - An image with an extension (e.g. .jpg) in its file name, using
|
|
|
|
// Context->Save Image As...
|
|
|
|
// - An image without an extension (e.g. a banner ad on cnn.com) using
|
|
|
|
// the above method.
|
|
|
|
// - A linked document using Save Link As...
|
|
|
|
// - A linked document using shift-click Save Link As...
|
|
|
|
//
|
2006-07-29 09:39:15 +04:00
|
|
|
function saveURL(aURL, aFileName, aFilePickerTitleKey, aShouldBypassCache)
|
2006-07-29 09:39:04 +04:00
|
|
|
{
|
2006-07-29 09:39:15 +04:00
|
|
|
saveInternal(aURL, null, aFileName, aFilePickerTitleKey, aShouldBypassCache);
|
2006-07-29 09:39:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
function saveDocument(aDocument)
|
|
|
|
{
|
2006-07-29 09:39:15 +04:00
|
|
|
// In both cases here, we want to use cached data because the
|
|
|
|
// document is currently visible.
|
|
|
|
if (aDocument)
|
|
|
|
saveInternal(aDocument.location.href, aDocument, false);
|
|
|
|
else
|
|
|
|
saveInternal(_content.location.href, null, false);
|
2006-07-29 09:39:04 +04:00
|
|
|
}
|
|
|
|
|
2006-07-29 09:39:15 +04:00
|
|
|
function saveInternal(aURL, aDocument,
|
|
|
|
aFileName, aFilePickerTitleKey,
|
|
|
|
aShouldBypassCache)
|
2006-07-29 09:39:02 +04:00
|
|
|
{
|
|
|
|
var data = {
|
|
|
|
fileName: aFileName,
|
2006-07-29 09:39:04 +04:00
|
|
|
filePickerTitle: aFilePickerTitleKey,
|
2006-07-29 09:39:15 +04:00
|
|
|
document: aDocument,
|
|
|
|
bypassCache: aShouldBypassCache
|
2006-07-29 09:39:02 +04:00
|
|
|
};
|
|
|
|
var sniffer = new nsHeaderSniffer(aURL, foundHeaderInfo, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
function foundHeaderInfo(aSniffer, aData)
|
|
|
|
{
|
|
|
|
var contentType = aSniffer.contentType;
|
2006-07-29 09:37:42 +04:00
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
var fp = makeFilePicker();
|
|
|
|
var titleKey = aData.filePickerTitle || "SaveLinkTitle";
|
|
|
|
var bundle = getStringBundle();
|
|
|
|
fp.init(window, bundle.GetStringFromName(titleKey),
|
|
|
|
Components.interfaces.nsIFilePicker.modeSave);
|
|
|
|
|
2006-07-29 09:39:15 +04:00
|
|
|
|
|
|
|
var isDocument = aData.document != null && isDocumentType(contentType);
|
2006-07-29 09:39:04 +04:00
|
|
|
appendFiltersForContentType(fp, aSniffer.contentType,
|
2006-07-29 09:39:15 +04:00
|
|
|
isDocument ? MODE_COMPLETE : MODE_FILEONLY);
|
|
|
|
|
|
|
|
const prefSvcContractID = "@mozilla.org/preferences-service;1";
|
|
|
|
const prefSvcIID = Components.interfaces.nsIPrefService;
|
|
|
|
var prefs = Components.classes[prefSvcContractID].getService(prefSvcIID).getBranch("browser.download");
|
|
|
|
|
|
|
|
const nsILocalFile = Components.interfaces.nsILocalFile;
|
|
|
|
try {
|
|
|
|
fp.displayDirectory = prefs.getComplexValue("dir", nsILocalFile);
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
}
|
2006-07-29 09:39:02 +04:00
|
|
|
|
2006-07-29 09:39:15 +04:00
|
|
|
if (isDocument) {
|
|
|
|
try {
|
|
|
|
fp.filterIndex = prefs.getIntPref("save_converter_index");
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
// Determine what the 'default' string to display in the File Picker dialog
|
|
|
|
// should be.
|
2006-07-29 09:39:08 +04:00
|
|
|
var defaultFileName = getDefaultFileName(aData.fileName,
|
|
|
|
aSniffer.suggestedFileName,
|
|
|
|
aSniffer.uri);
|
|
|
|
fp.defaultString = getNormalizedLeafName(defaultFileName, contentType);
|
2006-07-29 09:39:02 +04:00
|
|
|
|
|
|
|
if (fp.show() == Components.interfaces.nsIFilePicker.returnCancel || !fp.file)
|
|
|
|
return;
|
|
|
|
|
2006-07-29 09:39:15 +04:00
|
|
|
if (isDocument)
|
|
|
|
prefs.setIntPref("save_converter_index", fp.filterIndex);
|
|
|
|
var directory = fp.file.parent.QueryInterface(nsILocalFile);
|
|
|
|
prefs.setComplexValue("dir", nsILocalFile, directory);
|
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
fp.file.leafName = validateFileName(fp.file.leafName);
|
2006-07-29 09:39:08 +04:00
|
|
|
fp.file.leafName = getNormalizedLeafName(fp.file.leafName, contentType);
|
2006-07-29 09:39:04 +04:00
|
|
|
|
2006-07-29 09:39:15 +04:00
|
|
|
// If we're saving a document, and are saving either in complete mode or
|
|
|
|
// as converted text, pass the document to the web browser persist component.
|
|
|
|
// If we're just saving the HTML (second option in the list), send only the URI.
|
|
|
|
var source = (isDocument && fp.filterIndex != 1) ? aData.document : aSniffer.uri;
|
2006-07-29 09:39:04 +04:00
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
var persistArgs = {
|
2006-07-29 09:39:15 +04:00
|
|
|
source : source,
|
|
|
|
contentType : (isDocument && fp.filterIndex == 2) ? "text/plain" : contentType,
|
|
|
|
target : fp.file,
|
|
|
|
postData : isDocument ? getPostData() : null,
|
|
|
|
bypassCache : aData.bypassCache
|
2006-07-29 09:39:02 +04:00
|
|
|
};
|
|
|
|
|
2006-07-29 09:39:03 +04:00
|
|
|
openDialog("chrome://global/content/nsProgressDlg.xul", "",
|
2006-07-29 09:39:02 +04:00
|
|
|
"chrome,titlebar,minizable,dialog=yes",
|
|
|
|
makeWebBrowserPersist(), persistArgs);
|
|
|
|
}
|
|
|
|
|
|
|
|
function nsHeaderSniffer(aURL, aCallback, aData)
|
|
|
|
{
|
|
|
|
this.mPersist = makeWebBrowserPersist();
|
|
|
|
this.mCallback = aCallback;
|
|
|
|
this.mData = aData;
|
|
|
|
|
|
|
|
this.mPersist.progressListener = this;
|
|
|
|
|
|
|
|
this.mTempFile = makeTempFile();
|
|
|
|
while (this.mTempFile.exists())
|
|
|
|
this.mTempFile = makeTempFile();
|
|
|
|
|
|
|
|
const stdURLContractID = "@mozilla.org/network/standard-url;1";
|
|
|
|
const stdURLIID = Components.interfaces.nsIURI;
|
|
|
|
this.uri = Components.classes[stdURLContractID].createInstance(stdURLIID);
|
|
|
|
this.uri.spec = aURL;
|
|
|
|
|
|
|
|
this.mPersist.saveURI(this.uri, null, this.mTempFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsHeaderSniffer.prototype = {
|
|
|
|
onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus)
|
|
|
|
{
|
|
|
|
if (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_START) {
|
|
|
|
try {
|
|
|
|
var channel = aRequest.QueryInterface(Components.interfaces.nsIChannel);
|
|
|
|
this.contentType = channel.contentType;
|
|
|
|
try {
|
|
|
|
var httpChannel = aRequest.QueryInterface(Components.interfaces.nsIHttpChannel);
|
|
|
|
this.mContentDisposition = httpChannel.getResponseHeader("content-disposition");
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
}
|
|
|
|
this.mPersist.cancelSave();
|
|
|
|
if (this.mTempFile.exists())
|
|
|
|
this.mTempFile.remove(false);
|
|
|
|
this.mCallback(this, this.mData);
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onLocationChange: function (aWebProgress, aRequest, aLocation) { },
|
|
|
|
onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) { },
|
|
|
|
onSecurityChange: function (aWebProgress, aRequest, aState) { },
|
|
|
|
onProgressChange: function (aWebProgress, aRequest, aCurSelfProgress,
|
|
|
|
aMaxSelfProgress, aCurTotalProgress,
|
|
|
|
aMaxTotalProgress) { },
|
|
|
|
|
|
|
|
get suggestedFileName()
|
2006-07-29 09:33:03 +04:00
|
|
|
{
|
2006-07-29 09:39:02 +04:00
|
|
|
var filename = "";
|
|
|
|
var name = this.mContentDisposition;
|
|
|
|
if (name) {
|
2006-07-29 09:39:16 +04:00
|
|
|
const filenamePrefix = "filename=";
|
|
|
|
var ix = name.indexOf(filenamePrefix);
|
2006-07-29 09:39:02 +04:00
|
|
|
if (ix > 0) {
|
2006-07-29 09:39:16 +04:00
|
|
|
// Adjust ix to point to start of actual name
|
|
|
|
ix += filenamePrefix.length;
|
2006-07-29 09:39:02 +04:00
|
|
|
filename = name.substr(ix, name.length);
|
|
|
|
if (filename != "") {
|
|
|
|
ix = filename.lastIndexOf(";");
|
|
|
|
if (ix > 0)
|
|
|
|
filename = filename.substr(0, ix);
|
|
|
|
// XXX strip out quotes;
|
|
|
|
}
|
|
|
|
}
|
2006-07-29 09:33:03 +04:00
|
|
|
}
|
2006-07-29 09:39:02 +04:00
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
const MODE_COMPLETE = 0;
|
2006-07-29 09:39:04 +04:00
|
|
|
const MODE_FILEONLY = 1;
|
2006-07-29 09:39:02 +04:00
|
|
|
|
|
|
|
function appendFiltersForContentType(aFilePicker, aContentType, aSaveMode)
|
|
|
|
{
|
|
|
|
var bundle = getStringBundle();
|
|
|
|
|
|
|
|
switch (aContentType) {
|
|
|
|
case "text/html":
|
|
|
|
if (aSaveMode == MODE_COMPLETE)
|
|
|
|
aFilePicker.appendFilter(bundle.GetStringFromName("WebPageCompleteFilter"), "*.htm; *.html");
|
|
|
|
aFilePicker.appendFilter(bundle.GetStringFromName("WebPageHTMLOnlyFilter"), "*.htm; *.html");
|
2006-07-29 09:39:15 +04:00
|
|
|
aFilePicker.appendFilter(bundle.GetStringFromName("TextOnlyFilter"), "*.txt");
|
2006-07-29 09:39:02 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
var mimeInfo = getMIMEInfoForType(aContentType);
|
|
|
|
if (mimeInfo) {
|
|
|
|
var extCount = { };
|
|
|
|
var extList = { };
|
|
|
|
mimeInfo.GetFileExtensions(extCount, extList);
|
|
|
|
|
|
|
|
var extString = "";
|
|
|
|
for (var i = 0; i < extCount.value; ++i) {
|
|
|
|
if (i > 0)
|
|
|
|
extString += "; "; // If adding more than one extension, separate by semi-colon
|
|
|
|
extString += "*." + extList.value[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
aFilePicker.appendFilter(mimeInfo.Description, extString);
|
2006-07-29 09:33:03 +04:00
|
|
|
}
|
2006-07-29 09:39:08 +04:00
|
|
|
else
|
|
|
|
aFilePicker.appendFilter(bundle.GetStringFromName("AllFilesFilter"), "*.*");
|
2006-07-29 09:39:02 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-07-29 09:33:03 +04:00
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
function getPostData()
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
var sessionHistory = getWebNavigation().sessionHistory;
|
|
|
|
entry = sessionHistory.getEntryAtIndex(sessionHistory.index, false);
|
|
|
|
entry = entry.QueryInterface(Components.interfaces.nsISHEntry);
|
|
|
|
return entry.postData;
|
|
|
|
}
|
|
|
|
catch (e) {
|
2006-07-29 09:33:12 +04:00
|
|
|
}
|
2006-07-29 09:39:02 +04:00
|
|
|
return null;
|
|
|
|
}
|
2006-07-29 09:33:12 +04:00
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
function getStringBundle()
|
|
|
|
{
|
|
|
|
const bundleURL = "chrome://communicator/locale/contentAreaCommands.properties";
|
|
|
|
|
|
|
|
const sbsContractID = "@mozilla.org/intl/stringbundle;1";
|
|
|
|
const sbsIID = Components.interfaces.nsIStringBundleService;
|
|
|
|
const sbs = Components.classes[sbsContractID].getService(sbsIID);
|
|
|
|
|
|
|
|
const lsContractID = "@mozilla.org/intl/nslocaleservice;1";
|
|
|
|
const lsIID = Components.interfaces.nsILocaleService;
|
|
|
|
const ls = Components.classes[lsContractID].getService(lsIID);
|
|
|
|
var appLocale = ls.GetApplicationLocale();
|
|
|
|
return sbs.createBundle(bundleURL, appLocale);
|
|
|
|
}
|
2006-07-29 09:33:12 +04:00
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
function makeWebBrowserPersist()
|
|
|
|
{
|
|
|
|
const persistContractID = "@mozilla.org/embedding/browser/nsWebBrowserPersist;1";
|
|
|
|
const persistIID = Components.interfaces.nsIWebBrowserPersist;
|
|
|
|
return Components.classes[persistContractID].createInstance(persistIID);
|
|
|
|
}
|
|
|
|
|
|
|
|
function makeFilePicker()
|
|
|
|
{
|
|
|
|
const fpContractID = "@mozilla.org/filepicker;1";
|
|
|
|
const fpIID = Components.interfaces.nsIFilePicker;
|
|
|
|
return Components.classes[fpContractID].createInstance(fpIID);
|
|
|
|
}
|
|
|
|
|
|
|
|
function makeTempFile()
|
|
|
|
{
|
|
|
|
const mimeTypes = "TmpD";
|
|
|
|
const flContractID = "@mozilla.org/file/directory_service;1";
|
|
|
|
const flIID = Components.interfaces.nsIProperties;
|
|
|
|
var fileLocator = Components.classes[flContractID].getService(flIID);
|
|
|
|
var tempFile = fileLocator.get(mimeTypes, Components.interfaces.nsIFile);
|
|
|
|
tempFile.append("~sav" + Math.floor(Math.random() * 1000) + ".tmp");
|
|
|
|
return tempFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getMIMEInfoForType(aMIMEType)
|
|
|
|
{
|
|
|
|
const mimeSvcCID = "{03af31da-3109-11d3-8cd0-0060b0fc14a3}";
|
|
|
|
const mimeSvcIID = Components.interfaces.nsIMIMEService;
|
|
|
|
const mimeSvc = Components.classesByID[mimeSvcCID].getService(mimeSvcIID);
|
|
|
|
|
|
|
|
try {
|
|
|
|
return mimeSvc.GetFromMIMEType(aMIMEType);
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getDefaultFileName(aDefaultFileName, aNameFromHeaders, aDocumentURI, aDocument)
|
|
|
|
{
|
|
|
|
if (aNameFromHeaders)
|
2006-07-29 09:39:15 +04:00
|
|
|
return validateFileName(aNameFromHeaders); // 1) Use the name suggested by the HTTP headers
|
2006-07-29 09:39:02 +04:00
|
|
|
|
|
|
|
var url = aDocumentURI.QueryInterface(Components.interfaces.nsIURL);
|
|
|
|
if (url.fileName != "")
|
2006-07-29 09:39:15 +04:00
|
|
|
return url.fileName; // 2) Use the actual file name, if present
|
2006-07-29 09:39:02 +04:00
|
|
|
|
2006-07-29 09:39:15 +04:00
|
|
|
if (aDocument && aDocument.title != "")
|
|
|
|
return validateFileName(aDocument.title) // 3) Use the document title
|
|
|
|
|
|
|
|
if (aDefaultFileName)
|
|
|
|
return validateFileName(aDefaultFileName); // 4) Use the caller-provided name, if any
|
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
return aDocumentURI.host; // 5) Use the host.
|
|
|
|
}
|
|
|
|
|
|
|
|
function validateFileName(aFileName)
|
|
|
|
{
|
|
|
|
var re = /[\/]+/g;
|
|
|
|
if (navigator.appVersion.indexOf("Windows") != -1) {
|
|
|
|
re = /[\\\/\|]+/g;
|
|
|
|
aFileName = aFileName.replace(/[\"]+/g, "'");
|
|
|
|
aFileName = aFileName.replace(/[\*\:\?]+/g, " ");
|
|
|
|
aFileName = aFileName.replace(/[\<]+/g, "(");
|
|
|
|
aFileName = aFileName.replace(/[\>]+/g, ")");
|
|
|
|
}
|
|
|
|
else if (navigator.appVersion.indexOf("Macintosh") != -1)
|
|
|
|
re = /[\:\/]+/g;
|
|
|
|
|
|
|
|
return aFileName.replace(re, "_");
|
|
|
|
}
|
|
|
|
|
|
|
|
function getNormalizedLeafName(aFile, aContentType)
|
|
|
|
{
|
|
|
|
// Fix up the file name we're saving to so that if the user enters
|
|
|
|
// no extension, an appropriate one is appended.
|
|
|
|
var leafName = aFile;
|
|
|
|
|
|
|
|
var mimeInfo = getMIMEInfoForType(aContentType);
|
|
|
|
if (mimeInfo) {
|
|
|
|
var extCount = { };
|
|
|
|
var extList = { };
|
|
|
|
mimeInfo.GetFileExtensions(extCount, extList);
|
|
|
|
|
|
|
|
const stdURLContractID = "@mozilla.org/network/standard-url;1";
|
|
|
|
const stdURLIID = Components.interfaces.nsIURI;
|
|
|
|
var uri = Components.classes[stdURLContractID].createInstance(stdURLIID);
|
|
|
|
var url = uri.QueryInterface(Components.interfaces.nsIURL);
|
2006-07-29 09:39:04 +04:00
|
|
|
url.filePath = aFile;
|
|
|
|
|
2006-07-29 09:39:02 +04:00
|
|
|
if (aContentType == "text/html") {
|
|
|
|
if ((url.fileExtension &&
|
|
|
|
url.fileExtension != "htm" && url.fileExtension != "html") ||
|
|
|
|
(!url.fileExtension))
|
|
|
|
return leafName + ".html";
|
2006-07-29 09:33:12 +04:00
|
|
|
}
|
2006-07-29 09:39:02 +04:00
|
|
|
|
|
|
|
if (!url.fileExtension)
|
|
|
|
return leafName + "." + extList.value[0];
|
2006-07-29 09:33:12 +04:00
|
|
|
}
|
2006-07-29 09:39:02 +04:00
|
|
|
|
|
|
|
return leafName;
|
|
|
|
}
|
2006-07-29 09:33:14 +04:00
|
|
|
|
2006-07-29 09:39:15 +04:00
|
|
|
function isDocumentType(aContentType)
|
|
|
|
{
|
|
|
|
switch (aContentType) {
|
|
|
|
case "text/html":
|
|
|
|
case "text/xml":
|
|
|
|
case "application/xhtml+xml":
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|