зеркало из https://github.com/mozilla/pjs.git
The Mother Of All Download Landings, Phase I
http://bugzilla.mozilla.org/show_bug.cgi?id=214259 Firebird Download System Upgrades. components/downloads/Makefile.in components/downloads/content/nsHelperAppDlg.js components/downloads/content/unknownContentType.xul components/downloads/locale/unknownContentType.dtd components/downloads/locale/unknownContentType.properties components/downloads/skin/unknownContentType.css - Initial implementation of new Unknown Content Type Handler dialog and nsIHelperAppLauncherDialog implementation.
This commit is contained in:
Родитель
b871a98ab4
Коммит
a3f8f7df53
|
@ -28,5 +28,11 @@ include $(DEPTH)/config/autoconf.mk
|
|||
|
||||
DIRS = public src
|
||||
|
||||
MODULE = helperAppDlg
|
||||
|
||||
EXTRA_COMPONENTS = \
|
||||
content/nsHelperAppDlg.js \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
|
|
@ -0,0 +1,795 @@
|
|||
/*
|
||||
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla 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/MPL/
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The Original Code is Mozilla.org Code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Doron Rosenberg.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2001
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Bill Law <law@netscape.com>
|
||||
# Scott MacGregor <mscott@netscape.com>
|
||||
# Ben Goodger <ben@bengoodger.com> (2.0)
|
||||
#
|
||||
# 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 MPL, 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 MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/* This file implements the nsIHelperAppLauncherDialog interface.
|
||||
*
|
||||
* The implementation consists of a JavaScript "class" named nsUnknownContentTypeDialog,
|
||||
* comprised of:
|
||||
* - a JS constructor function
|
||||
* - a prototype providing all the interface methods and implementation stuff
|
||||
*
|
||||
* In addition, this file implements an nsIModule object that registers the
|
||||
* nsUnknownContentTypeDialog component.
|
||||
*/
|
||||
|
||||
|
||||
/* ctor
|
||||
*/
|
||||
function nsUnknownContentTypeDialog() {
|
||||
// Initialize data properties.
|
||||
this.mLauncher = null;
|
||||
this.mContext = null;
|
||||
this.mSourcePath = null;
|
||||
this.chosenApp = null;
|
||||
this.givenDefaultApp = false;
|
||||
this.updateSelf = true;
|
||||
this.mTitle = "";
|
||||
}
|
||||
|
||||
nsUnknownContentTypeDialog.prototype = {
|
||||
nsIMIMEInfo : Components.interfaces.nsIMIMEInfo,
|
||||
|
||||
// This "class" supports nsIHelperAppLauncherDialog, and nsISupports.
|
||||
QueryInterface: function (iid) {
|
||||
if (!iid.equals(Components.interfaces.nsIHelperAppLauncherDialog) &&
|
||||
!iid.equals(Components.interfaces.nsISupports)) {
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// ---------- nsIHelperAppLauncherDialog methods ----------
|
||||
|
||||
// show: Open XUL dialog using window watcher. Since the dialog is not
|
||||
// modal, it needs to be a top level window and the way to open
|
||||
// one of those is via that route).
|
||||
show: function(aLauncher, aContext) {
|
||||
this.mLauncher = aLauncher;
|
||||
this.mContext = aContext;
|
||||
// Display the dialog using the Window Watcher interface.
|
||||
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
||||
.getService(Components.interfaces.nsIWindowWatcher);
|
||||
this.mDialog = ww.openWindow(null, // no parent
|
||||
"chrome://browser/content/downloads/unknownContentType.xul",
|
||||
null,
|
||||
"chrome,titlebar,dialog=yes",
|
||||
null);
|
||||
// Hook this object to the dialog.
|
||||
this.mDialog.dialog = this;
|
||||
|
||||
// Hook up utility functions.
|
||||
// XXXben these lines can disappear if we can get XULPP to run on stuff not
|
||||
// thus referenced in jar.mns.
|
||||
this.getSpecialFolderKey = this.mDialog.getSpecialFolderKey;
|
||||
|
||||
this.mIsMac = (this.mDialog.navigator.platform.indexOf("Mac") != -1);
|
||||
this.mIsWin = (this.mDialog.navigator.platform.indexOf("Win") != -1);
|
||||
|
||||
// Watch for error notifications.
|
||||
this.progressListener.helperAppDlg = this;
|
||||
this.mLauncher.setWebProgressListener(this.progressListener);
|
||||
},
|
||||
|
||||
// promptForSaveToFile: Display file picker dialog and return selected file.
|
||||
// This is called by the External Helper App Service
|
||||
// after the ucth dialog calls |saveToDisk| with a null
|
||||
// target filename (no target, therefore user must pick).
|
||||
//
|
||||
// Alternatively, if the user has selected to have all
|
||||
// files download to a specific location, return that
|
||||
// location and don't ask via the dialog.
|
||||
//
|
||||
// Note - this function is called without a dialog, so it cannot access any part
|
||||
// of the dialog XUL as other functions on this object do.
|
||||
promptForSaveToFile: function(aLauncher, aContext, aDefaultFile, aSuggestedFileExtension) {
|
||||
var result = "";
|
||||
|
||||
this.mLauncher = aLauncher;
|
||||
|
||||
// If the user is always downloading to the same location, the default download
|
||||
// folder is stored in preferences. If a value is found stored, use that
|
||||
// automatically and don't ask via a dialog.
|
||||
const kDownloadFolderPref = "browser.download.defaultFolder";
|
||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
|
||||
try {
|
||||
result = prefs.getComplexValue(kDownloadFolderPref, Components.interfaces.nsILocalFile);
|
||||
result.append(aDefaultFile);
|
||||
}
|
||||
catch (e) { }
|
||||
|
||||
if (!result) {
|
||||
// Use file picker to show dialog.
|
||||
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var picker = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
|
||||
|
||||
var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService);
|
||||
bundle = bundle.createBundle("chrome://browser/locale/downloads/unknownContentType.properties");
|
||||
|
||||
var windowTitle = bundle.GetStringFromName("saveDialogTitle");
|
||||
var parent = aContext.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowInternal);
|
||||
picker.init(parent, windowTitle, nsIFilePicker.modeSave);
|
||||
picker.defaultString = aDefaultFile;
|
||||
|
||||
if (aSuggestedFileExtension) {
|
||||
// aSuggestedFileExtension includes the period, so strip it
|
||||
picker.defaultExtension = aSuggestedFileExtension.substring(1);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
picker.defaultExtension = this.mLauncher.MIMEInfo.primaryExtension;
|
||||
}
|
||||
catch (ex) { }
|
||||
}
|
||||
|
||||
var wildCardExtension = "*";
|
||||
if (aSuggestedFileExtension) {
|
||||
wildCardExtension += aSuggestedFileExtension;
|
||||
picker.appendFilter(this.mLauncher.MIMEInfo.Description, wildCardExtension);
|
||||
}
|
||||
|
||||
picker.appendFilters( nsIFilePicker.filterAll );
|
||||
|
||||
// Pull in the user's preferences and get the default download directory.
|
||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
|
||||
try {
|
||||
var startDir = prefs.getComplexValue("browser.download.dir", Components.interfaces.nsILocalFile);
|
||||
if (startDir.exists()) {
|
||||
picker.displayDirectory = startDir;
|
||||
}
|
||||
}
|
||||
catch(exception) { }
|
||||
|
||||
var dlgResult = picker.show();
|
||||
|
||||
if (dlgResult == nsIFilePicker.returnCancel) {
|
||||
// null result means user cancelled.
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Be sure to save the directory the user chose as the new browser.download.dir
|
||||
result = picker.file;
|
||||
|
||||
if (result) {
|
||||
var newDir = result.parent;
|
||||
prefs.setComplexValue("browser.download.dir", Components.interfaces.nsILocalFile, newDir);
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
// ---------- implementation methods ----------
|
||||
|
||||
// Web progress listener so we can detect errors while mLauncher is
|
||||
// streaming the data to a temporary file.
|
||||
progressListener: {
|
||||
// Implementation properties.
|
||||
helperAppDlg: null,
|
||||
|
||||
// nsIWebProgressListener methods.
|
||||
// Look for error notifications and display alert to user.
|
||||
onStatusChange: function( aWebProgress, aRequest, aStatus, aMessage ) {
|
||||
if ( aStatus != Components.results.NS_OK ) {
|
||||
// Get prompt service.
|
||||
var prompter = Components.classes[ "@mozilla.org/embedcomp/prompt-service;1" ]
|
||||
.getService( Components.interfaces.nsIPromptService );
|
||||
// Display error alert (using text supplied by back-end).
|
||||
prompter.alert( this.dialog, this.helperAppDlg.mTitle, aMessage );
|
||||
|
||||
// Close the dialog.
|
||||
this.helperAppDlg.onCancel();
|
||||
if ( this.helperAppDlg.mDialog ) {
|
||||
this.helperAppDlg.mDialog.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Ignore onProgressChange, onStateChange, onLocationChange, and onSecurityChange notifications.
|
||||
onProgressChange: function( aWebProgress,
|
||||
aRequest,
|
||||
aCurSelfProgress,
|
||||
aMaxSelfProgress,
|
||||
aCurTotalProgress,
|
||||
aMaxTotalProgress ) {
|
||||
},
|
||||
|
||||
onStateChange: function( aWebProgress, aRequest, aStateFlags, aStatus ) {
|
||||
},
|
||||
|
||||
onLocationChange: function( aWebProgress, aRequest, aLocation ) {
|
||||
},
|
||||
|
||||
onSecurityChange: function( aWebProgress, aRequest, state ) {
|
||||
}
|
||||
},
|
||||
|
||||
// initDialog: Fill various dialog fields with initial content.
|
||||
initDialog : function() {
|
||||
// Put file name in window title.
|
||||
var win = this.dialogElement( "unknownContentType" );
|
||||
var suggestedFileName = this.mLauncher.suggestedFileName;
|
||||
|
||||
// Some URIs do not implement nsIURL, so we can't just QI.
|
||||
var url = this.mLauncher.source;
|
||||
var fname = "";
|
||||
this.mSourcePath = url.prePath;
|
||||
try {
|
||||
url = url.QueryInterface( Components.interfaces.nsIURL );
|
||||
// A url, use file name from it.
|
||||
fname = url.fileName;
|
||||
this.mSourcePath += url.directory;
|
||||
} catch (ex) {
|
||||
// A generic uri, use path.
|
||||
fname = url.path;
|
||||
this.mSourcePath += url.path;
|
||||
}
|
||||
|
||||
if (suggestedFileName)
|
||||
fname = suggestedFileName;
|
||||
|
||||
|
||||
this.mTitle = this.dialogElement("strings").getFormattedString("title", [fname]);
|
||||
win.setAttribute( "title", this.mTitle );
|
||||
|
||||
// Put content type, filename and location into intro.
|
||||
this.initIntro(url, fname);
|
||||
|
||||
var iconString = "moz-icon://" + fname + "?size=16&contentType=" + this.mLauncher.MIMEInfo.MIMEType;
|
||||
this.dialogElement("contentTypeImage").setAttribute("src", iconString);
|
||||
|
||||
this.initAppAndSaveToDiskValues();
|
||||
|
||||
// Initialize "always ask me" box. This should always be disabled
|
||||
// and set to true for the ambiguous type application/octet-stream.
|
||||
// We don't also check for application/x-msdownload here since we
|
||||
// want users to be able to autodownload .exe files.
|
||||
var rememberChoice = this.dialogElement("rememberChoice");
|
||||
if (this.mLauncher.MIMEInfo.MIMEType == "application/octet-stream") {
|
||||
rememberChoice.checked = false;
|
||||
rememberChoice.disabled = true;
|
||||
}
|
||||
else {
|
||||
rememberChoice.checked = !this.mLauncher.MIMEInfo.alwaysAskBeforeHandling;
|
||||
}
|
||||
this.toggleRememberChoice(rememberChoice);
|
||||
|
||||
|
||||
// XXXben - menulist won't init properly, hack.
|
||||
var openHandler = this.dialogElement("openHandler");
|
||||
openHandler.parentNode.removeChild(openHandler);
|
||||
var openParent = this.dialogElement("open").parentNode;
|
||||
openParent.appendChild(openHandler);
|
||||
|
||||
this.mDialog.setTimeout("dialog.postShowCallback()", 0);
|
||||
},
|
||||
|
||||
postShowCallback: function () {
|
||||
// Position the window if it has never been positioned before (i.e.
|
||||
// before XUL persistence has picked up anything to fill the screenX/
|
||||
// screenY attributes with. Assume if one is unset, the other will be too).
|
||||
if (this.mDialog.document.documentElement.getAttribute("screenX") == "") {
|
||||
if (this.mDialog.opener) {
|
||||
this.mDialog.moveToAlertPosition();
|
||||
}
|
||||
else {
|
||||
this.mDialog.centerWindowOnScreen();
|
||||
}
|
||||
}
|
||||
|
||||
this.mDialog.sizeToContent();
|
||||
|
||||
// Set initial focus
|
||||
this.dialogElement("mode").focus();
|
||||
},
|
||||
|
||||
// initIntro:
|
||||
initIntro: function(url, filename) {
|
||||
this.dialogElement( "location" ).value = filename;
|
||||
|
||||
// if mSourcePath is a local file, then let's use the pretty path name instead of an ugly
|
||||
// url...
|
||||
var pathString = this.mSourcePath;
|
||||
try
|
||||
{
|
||||
var fileURL = url.QueryInterface(Components.interfaces.nsIFileURL);
|
||||
if (fileURL)
|
||||
{
|
||||
var fileObject = fileURL.file;
|
||||
if (fileObject)
|
||||
{
|
||||
var parentObject = fileObject.parent;
|
||||
if (parentObject)
|
||||
{
|
||||
pathString = parentObject.path;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(ex) {}
|
||||
|
||||
// Set the location text, which is separate from the intro text so it can be cropped
|
||||
var location = this.dialogElement( "source" );
|
||||
location.value = pathString;
|
||||
},
|
||||
|
||||
// Returns true if opening the default application makes sense.
|
||||
openWithDefaultOK: function() {
|
||||
var result;
|
||||
|
||||
// The checking is different on Windows...
|
||||
if ( this.mIsWin ) {
|
||||
// Windows presents some special cases.
|
||||
// We need to prevent use of "system default" when the file is
|
||||
// executable (so the user doesn't launch nasty programs downloaded
|
||||
// from the web), and, enable use of "system default" if it isn't
|
||||
// executable (because we will prompt the user for the default app
|
||||
// in that case).
|
||||
|
||||
// Need to get temporary file and check for executable-ness.
|
||||
var ignore1 = new Object;
|
||||
var ignore2 = new Object;
|
||||
var tmpFile = this.mLauncher.getDownloadInfo( ignore1, ignore2 );
|
||||
|
||||
// Default is Ok if the file isn't executable (and vice-versa).
|
||||
result = !tmpFile.isExecutable();
|
||||
} else {
|
||||
// On other platforms, default is Ok if there is a default app.
|
||||
// Note that nsIMIMEInfo providers need to ensure that this holds true
|
||||
// on each platform.
|
||||
result = this.mLauncher.MIMEInfo.defaultApplicationHandler;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
// Set "default" application description field.
|
||||
initDefaultApp: function() {
|
||||
// Use description, if we can get one.
|
||||
var desc = this.mLauncher.MIMEInfo.defaultDescription;
|
||||
if (desc) {
|
||||
var defaultApp = this.dialogElement("strings").getFormattedString("defaultApp", [desc]);
|
||||
this.dialogElement("defaultHandler").label = defaultApp;
|
||||
}
|
||||
},
|
||||
|
||||
// getPath:
|
||||
getPath: function (aFile) {
|
||||
if (this.mIsMac)
|
||||
return aFile.leafName || aFile.path;
|
||||
return aFile.path;
|
||||
},
|
||||
|
||||
// initAppAndSaveToDiskValues:
|
||||
initAppAndSaveToDiskValues: function() {
|
||||
var modeGroup = this.dialogElement("mode");
|
||||
|
||||
// We don't let users open .exe files or random binary data directly
|
||||
// from the browser at the moment because of security concerns.
|
||||
var mimeType = this.mLauncher.MIMEInfo.MIMEType;
|
||||
if (mimeType == "application/octet-stream" ||
|
||||
mimeType == "application/x-msdownload") {
|
||||
this.dialogElement("open").disabled = true;
|
||||
var openHandler = this.dialogElement("openHandler");
|
||||
openHandler.disabled = true;
|
||||
openHandler.label = "";
|
||||
modeGroup.selectedItem = this.dialogElement("save");
|
||||
return;
|
||||
}
|
||||
|
||||
// Fill in helper app info, if there is any.
|
||||
this.chosenApp = this.mLauncher.MIMEInfo.preferredApplicationHandler;
|
||||
// Initialize "default application" field.
|
||||
this.initDefaultApp();
|
||||
|
||||
var otherHandler = this.dialogElement("otherHandler");
|
||||
|
||||
// Fill application name textbox.
|
||||
if (this.chosenApp && this.chosenApp.path) {
|
||||
otherHandler.setAttribute("path", this.getPath(this.chosenApp));
|
||||
otherHandler.label = this.chosenApp.leafName;
|
||||
otherHandler.hidden = false;
|
||||
}
|
||||
|
||||
var useDefault = this.dialogElement("useSystemDefault");
|
||||
var openHandler = this.dialogElement("openHandler");
|
||||
openHandler.selectedIndex = 0;
|
||||
|
||||
if (this.mLauncher.MIMEInfo.preferredAction == this.nsIMIMEInfo.useSystemDefault) {
|
||||
// Open (using system default).
|
||||
modeGroup.selectedItem = this.dialogElement("open");
|
||||
} else if (this.mLauncher.MIMEInfo.preferredAction == this.nsIMIMEInfo.useHelperApp) {
|
||||
// Open with given helper app.
|
||||
modeGroup.selectedItem = this.dialogElement("open");
|
||||
openHandler.selectedIndex = 1;
|
||||
} else {
|
||||
// Save to disk.
|
||||
modeGroup.selectedItem = this.dialogElement("save");
|
||||
}
|
||||
|
||||
// If we don't have a "default app" then disable that choice.
|
||||
if (!this.openWithDefaultOK()) {
|
||||
var useDefault = this.dialogElement("defaultHandler");
|
||||
var isSelected = useDefault.selected;
|
||||
|
||||
// Disable that choice.
|
||||
useDefault.hidden = true;
|
||||
// If that's the default, then switch to "save to disk."
|
||||
if (isSelected) {
|
||||
openHandler.selectedIndex = 1;
|
||||
modeGroup.selectedItem = this.dialogElement("save");
|
||||
}
|
||||
}
|
||||
|
||||
// otherHandler is always disabled on Mac
|
||||
if (this.mIsMac)
|
||||
otherHandler.hidden = true;
|
||||
|
||||
otherHandler.nextSibling.hidden = otherHandler.nextSibling.nextSibling.hidden = this.isMac;
|
||||
this.updateOKButton();
|
||||
},
|
||||
|
||||
// Returns the user-selected application
|
||||
helperAppChoice: function() {
|
||||
return this.chosenApp;
|
||||
},
|
||||
|
||||
get saveToDisk() {
|
||||
return this.dialogElement("save").selected;
|
||||
},
|
||||
|
||||
get useOtherHandler() {
|
||||
return this.dialogElement("open").selected && this.dialogElement("openHandler").selectedIndex == 1;
|
||||
},
|
||||
|
||||
get useSystemDefault() {
|
||||
return this.dialogElement("open").selected && this.dialogElement("openHandler").selectedIndex == 0;
|
||||
},
|
||||
|
||||
toggleRememberChoice: function (aCheckbox) {
|
||||
this.dialogElement("settingsChange").hidden = !aCheckbox.checked;
|
||||
this.mDialog.sizeToContent();
|
||||
},
|
||||
|
||||
openHandlerCommand: function () {
|
||||
if (this.dialogElement("openHandler").selectedItem.id == "choose")
|
||||
this.chooseApp();
|
||||
},
|
||||
|
||||
updateOKButton: function() {
|
||||
var ok = false;
|
||||
if (this.dialogElement("save").selected) {
|
||||
// This is always OK.
|
||||
ok = true;
|
||||
}
|
||||
else if (this.dialogElement("open").selected) {
|
||||
switch (this.dialogElement("openHandler").selectedIndex) {
|
||||
case 0:
|
||||
// No app need be specified in this case.
|
||||
ok = true;
|
||||
break;
|
||||
case 1:
|
||||
// only enable the OK button if we have a default app to use or if
|
||||
// the user chose an app....
|
||||
ok = this.chosenApp || /\S/.test(this.dialogElement("otherHandler").getAttribute("path"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Enable Ok button if ok to press.
|
||||
this.mDialog.document.documentElement.getButton("accept").disabled = !ok;
|
||||
},
|
||||
|
||||
// Returns true iff the user-specified helper app has been modified.
|
||||
appChanged: function() {
|
||||
return this.helperAppChoice() != this.mLauncher.MIMEInfo.preferredApplicationHandler;
|
||||
},
|
||||
|
||||
updateMIMEInfo: function() {
|
||||
var needUpdate = false;
|
||||
// If current selection differs from what's in the mime info object,
|
||||
// then we need to update.
|
||||
if (this.saveToDisk) {
|
||||
needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.saveToDisk;
|
||||
if (needUpdate)
|
||||
this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.saveToDisk;
|
||||
}
|
||||
else if (this.useSystemDefault) {
|
||||
needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.useSystemDefault;
|
||||
if (needUpdate)
|
||||
this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.useSystemDefault;
|
||||
}
|
||||
else {
|
||||
// For "open with", we need to check both preferred action and whether the user chose
|
||||
// a new app.
|
||||
needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.useHelperApp || this.appChanged();
|
||||
if (needUpdate) {
|
||||
this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.useHelperApp;
|
||||
// App may have changed - Update application and description
|
||||
var app = this.helperAppChoice();
|
||||
this.mLauncher.MIMEInfo.preferredApplicationHandler = app;
|
||||
this.mLauncher.MIMEInfo.applicationDescription = "";
|
||||
}
|
||||
}
|
||||
// We will also need to update if the "always ask" flag has changed.
|
||||
needUpdate = needUpdate || this.mLauncher.MIMEInfo.alwaysAskBeforeHandling != (!this.dialogElement("rememberChoice").checked);
|
||||
|
||||
// One last special case: If the input "always ask" flag was false, then we always
|
||||
// update. In that case we are displaying the helper app dialog for the first
|
||||
// time for this mime type and we need to store the user's action in the mimeTypes.rdf
|
||||
// data source (whether that action has changed or not; if it didn't change, then we need
|
||||
// to store the "always ask" flag so the helper app dialog will or won't display
|
||||
// next time, per the user's selection).
|
||||
needUpdate = needUpdate || !this.mLauncher.MIMEInfo.alwaysAskBeforeHandling;
|
||||
|
||||
// Make sure mime info has updated setting for the "always ask" flag.
|
||||
this.mLauncher.MIMEInfo.alwaysAskBeforeHandling = !this.dialogElement("rememberChoice").checked;
|
||||
|
||||
return needUpdate;
|
||||
},
|
||||
|
||||
// See if the user changed things, and if so, update the
|
||||
// mimeTypes.rdf entry for this mime type.
|
||||
updateHelperAppPref: function() {
|
||||
var ha = new this.mDialog.HelperApps();
|
||||
ha.updateTypeInfo(this.mLauncher.MIMEInfo);
|
||||
},
|
||||
|
||||
// onOK:
|
||||
onOK: function() {
|
||||
// Verify typed app path, if necessary.
|
||||
if (this.useOtherHandler) {
|
||||
var helperApp = this.helperAppChoice();
|
||||
if (!helperApp || !helperApp.exists()) {
|
||||
// Show alert and try again.
|
||||
var bundle = this.dialogElement("strings");
|
||||
var msg = bundle.getFormattedString("badApp", [this.dialogElement("otherHandler").path]);
|
||||
var svc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
|
||||
svc.alert(this.mDialog, bundle.getString("badApp.title"), msg);
|
||||
|
||||
// Disable the OK button.
|
||||
this.mDialog.document.documentElement.getButton("accept").disabled = true;
|
||||
this.dialogElement("mode").focus();
|
||||
|
||||
// Clear chosen application.
|
||||
this.chosenApp = null;
|
||||
|
||||
// Leave dialog up.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove our web progress listener (a progress dialog will be
|
||||
// taking over).
|
||||
this.mLauncher.setWebProgressListener(null);
|
||||
|
||||
// saveToDisk and launchWithApplication can return errors in
|
||||
// certain circumstances (e.g. The user clicks cancel in the
|
||||
// "Save to Disk" dialog. In those cases, we don't want to
|
||||
// update the helper application preferences in the RDF file.
|
||||
try {
|
||||
var needUpdate = this.updateMIMEInfo();
|
||||
|
||||
if (this.dialogElement("save").selected) {
|
||||
// If we're using a default download location, create a path
|
||||
// for the file to be saved to to pass to |saveToDisk| - otherwise
|
||||
// we must ask the user to pick a save name.
|
||||
|
||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
|
||||
var targetFile = null;
|
||||
try {
|
||||
targetFile = prefs.getComplexValue("browser.download.defaultFolder",
|
||||
Components.interfaces.nsILocalFile);
|
||||
targetFile.append(this.dialogElement("location").value);
|
||||
}
|
||||
catch(e) {}
|
||||
|
||||
this.mLauncher.saveToDisk(targetFile, false);
|
||||
}
|
||||
else
|
||||
this.mLauncher.launchWithApplication(null, false);
|
||||
|
||||
// Update user pref for this mime type (if necessary). We do not
|
||||
// store anything in the mime type preferences for the ambiguous
|
||||
// type application/octet-stream. We do NOT do this for
|
||||
// application/x-msdownload since we want users to be able to
|
||||
// autodownload these to disk.
|
||||
if (needUpdate && this.mLauncher.MIMEInfo.MIMEType != "application/octet-stream")
|
||||
this.updateHelperAppPref();
|
||||
} catch(e) { }
|
||||
|
||||
// Unhook dialog from this object.
|
||||
this.mDialog.dialog = null;
|
||||
|
||||
// Close up dialog by returning true.
|
||||
return true;
|
||||
},
|
||||
|
||||
// onCancel:
|
||||
onCancel: function() {
|
||||
// Remove our web progress listener.
|
||||
this.mLauncher.setWebProgressListener(null);
|
||||
|
||||
// Cancel app launcher.
|
||||
try {
|
||||
this.mLauncher.Cancel();
|
||||
} catch(exception) {
|
||||
}
|
||||
|
||||
// Unhook dialog from this object.
|
||||
this.mDialog.dialog = null;
|
||||
|
||||
// Close up dialog by returning true.
|
||||
return true;
|
||||
},
|
||||
|
||||
// dialogElement: Convenience.
|
||||
dialogElement: function(id) {
|
||||
return this.mDialog.document.getElementById(id);
|
||||
},
|
||||
|
||||
// chooseApp: Open file picker and prompt user for application.
|
||||
chooseApp: function() {
|
||||
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
|
||||
fp.init(this.mDialog,
|
||||
this.dialogElement("strings").getString("chooseAppFilePickerTitle"),
|
||||
nsIFilePicker.modeOpen);
|
||||
|
||||
fp.appendFilters(nsIFilePicker.filterApps);
|
||||
|
||||
if (fp.show() == nsIFilePicker.returnOK && fp.file) {
|
||||
// Remember the file they chose to run.
|
||||
this.chosenApp = fp.file;
|
||||
// Update dialog.
|
||||
var otherHandler = this.dialogElement("otherHandler");
|
||||
otherHandler.removeAttribute("hidden");
|
||||
otherHandler.setAttribute("path", this.getPath(this.chosenApp));
|
||||
otherHandler.label = this.chosenApp.leafName;
|
||||
this.dialogElement("openHandler").selectedIndex = 1;
|
||||
|
||||
this.dialogElement("mode").selectedItem = this.dialogElement("open");
|
||||
}
|
||||
},
|
||||
|
||||
// Turn this on to get debugging messages.
|
||||
debug: false,
|
||||
|
||||
// Dump text (if debug is on).
|
||||
dump: function( text ) {
|
||||
if ( this.debug ) {
|
||||
dump( text );
|
||||
}
|
||||
},
|
||||
|
||||
// dumpInfo:
|
||||
doDebug: function() {
|
||||
const nsIProgressDialog = Components.interfaces.nsIProgressDialog;
|
||||
// Open new progress dialog.
|
||||
var progress = Components.classes[ "@mozilla.org/progressdialog;1" ]
|
||||
.createInstance( nsIProgressDialog );
|
||||
// Show it.
|
||||
progress.open( this.mDialog );
|
||||
},
|
||||
|
||||
// dumpObj:
|
||||
dumpObj: function( spec ) {
|
||||
var val = "<undefined>";
|
||||
try {
|
||||
val = eval( "this."+spec ).toString();
|
||||
} catch( exception ) {
|
||||
}
|
||||
this.dump( spec + "=" + val + "\n" );
|
||||
},
|
||||
|
||||
// dumpObjectProperties
|
||||
dumpObjectProperties: function( desc, obj ) {
|
||||
for( prop in obj ) {
|
||||
this.dump( desc + "." + prop + "=" );
|
||||
var val = "<undefined>";
|
||||
try {
|
||||
val = obj[ prop ];
|
||||
} catch ( exception ) {
|
||||
}
|
||||
this.dump( val + "\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This Component's module implementation. All the code below is used to get this
|
||||
// component registered and accessible via XPCOM.
|
||||
var module = {
|
||||
firstTime: true,
|
||||
|
||||
// registerSelf: Register this component.
|
||||
registerSelf: function (compMgr, fileSpec, location, type) {
|
||||
if (this.firstTime) {
|
||||
this.firstTime = false;
|
||||
throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
|
||||
}
|
||||
compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
|
||||
|
||||
compMgr.registerFactoryLocation( this.cid,
|
||||
"Unknown Content Type Dialog",
|
||||
this.contractId,
|
||||
fileSpec,
|
||||
location,
|
||||
type );
|
||||
},
|
||||
|
||||
// getClassObject: Return this component's factory object.
|
||||
getClassObject: function (compMgr, cid, iid) {
|
||||
if (!cid.equals(this.cid)) {
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
if (!iid.equals(Components.interfaces.nsIFactory)) {
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
return this.factory;
|
||||
},
|
||||
|
||||
/* CID for this class */
|
||||
cid: Components.ID("{F68578EB-6EC2-4169-AE19-8C6243F0ABE1}"),
|
||||
|
||||
/* Contract ID for this class */
|
||||
contractId: "@mozilla.org/helperapplauncherdialog;1",
|
||||
|
||||
/* factory object */
|
||||
factory: {
|
||||
// createInstance: Return a new nsProgressDialog object.
|
||||
createInstance: function (outer, iid) {
|
||||
if (outer != null)
|
||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
|
||||
return (new nsUnknownContentTypeDialog()).QueryInterface(iid);
|
||||
}
|
||||
},
|
||||
|
||||
// canUnload: n/a (returns true)
|
||||
canUnload: function(compMgr) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// NSGetModule: Return the nsIModule object.
|
||||
function NSGetModule(compMgr, fileSpec) {
|
||||
return module;
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
<?xml version="1.0"?>
|
||||
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla 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/MPL/
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The Original Code is Mozilla.org Code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Doron Rosenberg.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2001
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Ben Goodger <ben@bengoodger.com> (v2.0)
|
||||
# Bill Law <law@netscape.com>
|
||||
#
|
||||
# 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 MPL, 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 MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/downloads/unknownContentType.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE dialog [
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://global/locale/brand.dtd" >
|
||||
%brandDTD;
|
||||
<!ENTITY % uctDTD SYSTEM "chrome://browser/locale/downloads/unknownContentType.dtd" >
|
||||
%uctDTD;
|
||||
]>
|
||||
|
||||
<dialog id="unknownContentType"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="dialog.initDialog();" onunload="if (dialog) dialog.onCancel();"
|
||||
style="width: 34em;"
|
||||
screenX="" screenY=""
|
||||
persist="screenX screenY"
|
||||
ondialogaccept="return dialog.onOK()"
|
||||
ondialogcancel="return dialog.onCancel()">
|
||||
|
||||
<script type="application/x-javascript" src="chrome://browser/content/downloads/helperApps.js"/>
|
||||
|
||||
<stringbundle id="strings" src="chrome://browser/locale/downloads/unknownContentType.properties"/>
|
||||
|
||||
<vbox flex="1" id="container">
|
||||
<description>&intro.label;</description>
|
||||
<separator class="thin"/>
|
||||
<hbox align="center" class="small-indent">
|
||||
<image id="contentTypeImage"/>
|
||||
<textbox id="location" class="plain" readonly="true" flex="1"/>
|
||||
</hbox>
|
||||
<separator class="thin"/>
|
||||
<hbox align="center">
|
||||
<label value="&from.label;" id="from"/>
|
||||
<textbox id="source" class="plain" readonly="true" flex="1"/>
|
||||
</hbox>
|
||||
|
||||
<separator class="thin"/>
|
||||
|
||||
<groupbox flex="1">
|
||||
<caption label="&actionQuestion.label;"/>
|
||||
<separator class="thin"/>
|
||||
<radiogroup id="mode" class="small-indent">
|
||||
<hbox>
|
||||
<radio id="open" label="&openWith.label;" accesskey="&openWith.accesskey;"/>
|
||||
</hbox>
|
||||
|
||||
<radio id="save" label="&save.label;" accesskey="&save.label;"/>
|
||||
</radiogroup>
|
||||
<separator class="thin"/>
|
||||
<hbox class="small-indent">
|
||||
<checkbox id="rememberChoice" label="&rememberChoice.label;"
|
||||
accesskey="&rememberChoice.accesskey;"
|
||||
oncommand="dialog.toggleRememberChoice(event.target);"/>
|
||||
</hbox>
|
||||
|
||||
<separator/>
|
||||
<description id="settingsChange" hidden="true">&settingsChange.label;</description>
|
||||
<separator class="thin"/>
|
||||
</groupbox>
|
||||
</vbox>
|
||||
|
||||
<menulist id="openHandler" flex="1">
|
||||
<menupopup id="openHandlerPopup" oncommand="dialog.openHandlerCommand();">
|
||||
<menuitem id="defaultHandler" default="true" crop="right"/>
|
||||
<menuitem id="otherHandler" hidden="true" crop="left"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="choose" label="&other.label;"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</dialog>
|
|
@ -1,16 +1,21 @@
|
|||
browser.jar:
|
||||
* content/browser/downloads/downloadPanel.js (content/downloadPanel.js)
|
||||
content/browser/downloads/downloadPanel.xul (content/downloadPanel.xul)
|
||||
* content/browser/downloads/download-bindings.xml (content/download-bindings.xml)
|
||||
content/browser/downloads/downloadmanager.css (content/downloadmanager.css)
|
||||
content/browser/downloads/downloadProperties.xul (content/downloadProperties.xul)
|
||||
content/browser/downloads/downloadProperties.js (content/downloadProperties.js)
|
||||
* content/browser/downloads/downloadPanel.js (content/downloadPanel.js)
|
||||
content/browser/downloads/downloadPanel.xul (content/downloadPanel.xul)
|
||||
* content/browser/downloads/download-bindings.xml (content/download-bindings.xml)
|
||||
content/browser/downloads/downloadmanager.css (content/downloadmanager.css)
|
||||
content/browser/downloads/downloadProperties.xul (content/downloadProperties.xul)
|
||||
content/browser/downloads/downloadProperties.js (content/downloadProperties.js)
|
||||
* content/browser/downloads/helperApps.js (content/helperApps.js)
|
||||
* content/browser/downloads/unknownContentType.xul (content/unknownContentType.xul)
|
||||
|
||||
classic.jar:
|
||||
skin/classic/browser/downloads/downloadmanager.css (skin/downloadmanager.css)
|
||||
skin/classic/browser/downloads/unknownContentType.css (skin/unknownContentType.css)
|
||||
|
||||
en-US.jar:
|
||||
locale/en-US/browser/downloads/downloadmanager.dtd (locale/downloadmanager.dtd)
|
||||
locale/en-US/browser/downloads/downloadmanager.properties (locale/downloadmanager.properties)
|
||||
locale/en-US/browser/downloads/downloadProperties.dtd (locale/downloadProperties.dtd)
|
||||
locale/en-US/browser/downloads/downloadProperties.dtd (locale/downloadProperties.dtd)
|
||||
locale/en-US/browser/downloads/unknownContentType.properties (locale/unknownContentType.properties)
|
||||
locale/en-US/browser/downloads/unknownContentType.dtd (locale/unknownContentType.dtd)
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<!ENTITY intro.label "You have chosen to open">
|
||||
<!ENTITY from.label "from:">
|
||||
<!ENTITY actionQuestion.label "What should &brandShortName; do with this file?">
|
||||
|
||||
<!ENTITY openWith.label "Open with">
|
||||
<!ENTITY openWith.accesskey "o">
|
||||
<!ENTITY other.label "Other...">
|
||||
|
||||
<!ENTITY save.label "Save to Disk">
|
||||
<!ENTITY save.accesskey "s">
|
||||
|
||||
<!ENTITY rememberChoice.label "Do this automatically for files like this from now on.">
|
||||
<!ENTITY rememberChoice.accesskey "a">
|
||||
|
||||
<!ENTITY settingsChange.label "Settings can be changed in the Downloads section of Tools, Options.">
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
title=Opening %S
|
||||
saveDialogTitle=Enter name of file to save to...
|
||||
defaultApp=%S (default)
|
||||
chooseAppFilePickerTitle=Choose Helper Application
|
||||
badApp=The application you chose ("%S") could not be found. Check the file name or choose another application.
|
||||
badApp.title=Application not found
|
Загрузка…
Ссылка в новой задаче