summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/handling
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/handling')
-rw-r--r--toolkit/mozapps/handling/content/dialog.js278
-rw-r--r--toolkit/mozapps/handling/content/dialog.xul52
-rw-r--r--toolkit/mozapps/handling/content/handler.css11
-rw-r--r--toolkit/mozapps/handling/content/handler.xml28
-rw-r--r--toolkit/mozapps/handling/jar.mn10
-rw-r--r--toolkit/mozapps/handling/moz.build12
-rw-r--r--toolkit/mozapps/handling/nsContentDispatchChooser.js85
-rw-r--r--toolkit/mozapps/handling/nsContentDispatchChooser.manifest2
8 files changed, 478 insertions, 0 deletions
diff --git a/toolkit/mozapps/handling/content/dialog.js b/toolkit/mozapps/handling/content/dialog.js
new file mode 100644
index 000000000..98a788201
--- /dev/null
+++ b/toolkit/mozapps/handling/content/dialog.js
@@ -0,0 +1,278 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * This dialog builds its content based on arguments passed into it.
+ * window.arguments[0]:
+ * The title of the dialog.
+ * window.arguments[1]:
+ * The url of the image that appears to the left of the description text
+ * window.arguments[2]:
+ * The text of the description that will appear above the choices the user
+ * can choose from.
+ * window.arguments[3]:
+ * The text of the label directly above the choices the user can choose from.
+ * window.arguments[4]:
+ * This is the text to be placed in the label for the checkbox. If no text is
+ * passed (ie, it's an empty string), the checkbox will be hidden.
+ * window.arguments[5]:
+ * The accesskey for the checkbox
+ * window.arguments[6]:
+ * This is the text that is displayed below the checkbox when it is checked.
+ * window.arguments[7]:
+ * This is the nsIHandlerInfo that gives us all our precious information.
+ * window.arguments[8]:
+ * This is the nsIURI that we are being brought up for in the first place.
+ * window.arguments[9]:
+ * The nsIInterfaceRequestor of the parent window; may be null
+ */
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cr = Components.results;
+var Cu = Components.utils;
+
+Cu.import("resource://gre/modules/SharedPromptUtils.jsm");
+
+
+var dialog = {
+ // Member Variables
+
+ _handlerInfo: null,
+ _URI: null,
+ _itemChoose: null,
+ _okButton: null,
+ _windowCtxt: null,
+ _buttonDisabled: true,
+
+ // Methods
+
+ /**
+ * This function initializes the content of the dialog.
+ */
+ initialize: function initialize()
+ {
+ this._handlerInfo = window.arguments[7].QueryInterface(Ci.nsIHandlerInfo);
+ this._URI = window.arguments[8].QueryInterface(Ci.nsIURI);
+ this._windowCtxt = window.arguments[9];
+ if (this._windowCtxt)
+ this._windowCtxt.QueryInterface(Ci.nsIInterfaceRequestor);
+ this._itemChoose = document.getElementById("item-choose");
+ this._okButton = document.documentElement.getButton("accept");
+
+ var description = {
+ image: document.getElementById("description-image"),
+ text: document.getElementById("description-text")
+ };
+ var options = document.getElementById("item-action-text");
+ var checkbox = {
+ desc: document.getElementById("remember"),
+ text: document.getElementById("remember-text")
+ };
+
+ // Setting values
+ document.title = window.arguments[0];
+ description.image.src = window.arguments[1];
+ description.text.textContent = window.arguments[2];
+ options.value = window.arguments[3];
+ checkbox.desc.label = window.arguments[4];
+ checkbox.desc.accessKey = window.arguments[5];
+ checkbox.text.textContent = window.arguments[6];
+
+ // Hide stuff that needs to be hidden
+ if (!checkbox.desc.label)
+ checkbox.desc.hidden = true;
+
+ // UI is ready, lets populate our list
+ this.populateList();
+
+ this._delayHelper = new EnableDelayHelper({
+ disableDialog: () => {
+ this._buttonDisabled = true;
+ this.updateOKButton();
+ },
+ enableDialog: () => {
+ this._buttonDisabled = false;
+ this.updateOKButton();
+ },
+ focusTarget: window
+ });
+ },
+
+ /**
+ * Populates the list that a user can choose from.
+ */
+ populateList: function populateList()
+ {
+ var items = document.getElementById("items");
+ var possibleHandlers = this._handlerInfo.possibleApplicationHandlers;
+ var preferredHandler = this._handlerInfo.preferredApplicationHandler;
+ var ios = Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService);
+ for (let i = possibleHandlers.length - 1; i >= 0; --i) {
+ let app = possibleHandlers.queryElementAt(i, Ci.nsIHandlerApp);
+ let elm = document.createElement("richlistitem");
+ elm.setAttribute("type", "handler");
+ elm.setAttribute("name", app.name);
+ elm.obj = app;
+
+ if (app instanceof Ci.nsILocalHandlerApp) {
+ // See if we have an nsILocalHandlerApp and set the icon
+ let uri = ios.newFileURI(app.executable);
+ elm.setAttribute("image", "moz-icon://" + uri.spec + "?size=32");
+ }
+ else if (app instanceof Ci.nsIWebHandlerApp) {
+ let uri = ios.newURI(app.uriTemplate, null, null);
+ if (/^https?/.test(uri.scheme)) {
+ // Unfortunately we can't use the favicon service to get the favicon,
+ // because the service looks for a record with the exact URL we give
+ // it, and users won't have such records for URLs they don't visit,
+ // and users won't visit the handler's URL template, they'll only
+ // visit URLs derived from that template (i.e. with %s in the template
+ // replaced by the URL of the content being handled).
+ elm.setAttribute("image", uri.prePath + "/favicon.ico");
+ }
+ elm.setAttribute("description", uri.prePath);
+ }
+ else if (app instanceof Ci.nsIDBusHandlerApp) {
+ elm.setAttribute("description", app.method);
+ }
+ else
+ throw "unknown handler type";
+
+ items.insertBefore(elm, this._itemChoose);
+ if (preferredHandler && app == preferredHandler)
+ this.selectedItem = elm;
+ }
+
+ if (this._handlerInfo.hasDefaultHandler) {
+ let elm = document.createElement("richlistitem");
+ elm.setAttribute("type", "handler");
+ elm.id = "os-default-handler";
+ elm.setAttribute("name", this._handlerInfo.defaultDescription);
+
+ items.insertBefore(elm, items.firstChild);
+ if (this._handlerInfo.preferredAction ==
+ Ci.nsIHandlerInfo.useSystemDefault)
+ this.selectedItem = elm;
+ }
+ items.ensureSelectedElementIsVisible();
+ },
+
+ /**
+ * Brings up a filepicker and allows a user to choose an application.
+ */
+ chooseApplication: function chooseApplication()
+ {
+ var bundle = document.getElementById("base-strings");
+ var title = bundle.getString("choose.application.title");
+
+ var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+ fp.init(window, title, Ci.nsIFilePicker.modeOpen);
+ fp.appendFilters(Ci.nsIFilePicker.filterApps);
+
+ if (fp.show() == Ci.nsIFilePicker.returnOK && fp.file) {
+ let uri = Cc["@mozilla.org/network/util;1"].
+ getService(Ci.nsIIOService).
+ newFileURI(fp.file);
+
+ let handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
+ createInstance(Ci.nsILocalHandlerApp);
+ handlerApp.executable = fp.file;
+
+ // if this application is already in the list, select it and don't add it again
+ let parent = document.getElementById("items");
+ for (let i = 0; i < parent.childNodes.length; ++i) {
+ let elm = parent.childNodes[i];
+ if (elm.obj instanceof Ci.nsILocalHandlerApp && elm.obj.equals(handlerApp)) {
+ parent.selectedItem = elm;
+ parent.ensureSelectedElementIsVisible();
+ return;
+ }
+ }
+
+ let elm = document.createElement("richlistitem");
+ elm.setAttribute("type", "handler");
+ elm.setAttribute("name", fp.file.leafName);
+ elm.setAttribute("image", "moz-icon://" + uri.spec + "?size=32");
+ elm.obj = handlerApp;
+
+ parent.selectedItem = parent.insertBefore(elm, parent.firstChild);
+ parent.ensureSelectedElementIsVisible();
+ }
+ },
+
+ /**
+ * Function called when the OK button is pressed.
+ */
+ onAccept: function onAccept()
+ {
+ var checkbox = document.getElementById("remember");
+ if (!checkbox.hidden) {
+ // We need to make sure that the default is properly set now
+ if (this.selectedItem.obj) {
+ // default OS handler doesn't have this property
+ this._handlerInfo.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
+ this._handlerInfo.preferredApplicationHandler = this.selectedItem.obj;
+ }
+ else
+ this._handlerInfo.preferredAction = Ci.nsIHandlerInfo.useSystemDefault;
+ }
+ this._handlerInfo.alwaysAskBeforeHandling = !checkbox.checked;
+
+ var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
+ getService(Ci.nsIHandlerService);
+ hs.store(this._handlerInfo);
+
+ this._handlerInfo.launchWithURI(this._URI, this._windowCtxt);
+
+ return true;
+ },
+
+ /**
+ * Determines if the OK button should be disabled or not
+ */
+ updateOKButton: function updateOKButton()
+ {
+ this._okButton.disabled = this._itemChoose.selected ||
+ this._buttonDisabled;
+ },
+
+ /**
+ * Updates the UI based on the checkbox being checked or not.
+ */
+ onCheck: function onCheck()
+ {
+ if (document.getElementById("remember").checked)
+ document.getElementById("remember-text").setAttribute("visible", "true");
+ else
+ document.getElementById("remember-text").removeAttribute("visible");
+ },
+
+ /**
+ * Function called when the user double clicks on an item of the list
+ */
+ onDblClick: function onDblClick()
+ {
+ if (this.selectedItem == this._itemChoose)
+ this.chooseApplication();
+ else
+ document.documentElement.acceptDialog();
+ },
+
+ // Getters / Setters
+
+ /**
+ * Returns/sets the selected element in the richlistbox
+ */
+ get selectedItem()
+ {
+ return document.getElementById("items").selectedItem;
+ },
+ set selectedItem(aItem)
+ {
+ return document.getElementById("items").selectedItem = aItem;
+ }
+
+};
diff --git a/toolkit/mozapps/handling/content/dialog.xul b/toolkit/mozapps/handling/content/dialog.xul
new file mode 100644
index 000000000..f73ce6d7f
--- /dev/null
+++ b/toolkit/mozapps/handling/content/dialog.xul
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/global.css"?>
+<?xml-stylesheet href="chrome://mozapps/content/handling/handler.css"?>
+<?xml-stylesheet href="chrome://mozapps/skin/handling/handling.css"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE dialog SYSTEM "chrome://mozapps/locale/handling/handling.dtd">
+
+<dialog id="handling"
+ ondialogaccept="return dialog.onAccept();"
+ onload="dialog.initialize();"
+ style="min-width: &window.emWidth;; min-height: &window.emHeight;;"
+ persist="width height screenX screenY"
+ aria-describedby="description-text"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script src="chrome://mozapps/content/handling/dialog.js" type="application/javascript"/>
+
+ <stringbundleset id="strings">
+ <stringbundle id="base-strings"
+ src="chrome://mozapps/locale/handling/handling.properties"/>
+ </stringbundleset>
+
+ <hbox>
+ <image id="description-image"/>
+ <description id="description-text"/>
+ </hbox>
+
+ <vbox flex="1">
+ <label id="item-action-text" control="items"/>
+ <richlistbox id="items" flex="1"
+ ondblclick="dialog.onDblClick();"
+ onselect="dialog.updateOKButton();">
+ <richlistitem id="item-choose" orient="horizontal" selected="true">
+ <label value="&ChooseOtherApp.description;" flex="1"/>
+ <button oncommand="dialog.chooseApplication();"
+ label="&ChooseApp.label;" accesskey="&ChooseApp.accessKey;"/>
+ </richlistitem>
+ </richlistbox>
+ </vbox>
+
+ <checkbox id="remember" aria-describedby="remember-text" oncommand="dialog.onCheck();"/>
+ <description id="remember-text"/>
+
+ <hbox class="dialog-button-box" pack="end">
+ <button dlgtype="cancel" icon="cancel" class="dialog-button"/>
+ <button dlgtype="accept" label="&accept;" icon="open" class="dialog-button"/>
+ </hbox>
+
+</dialog>
diff --git a/toolkit/mozapps/handling/content/handler.css b/toolkit/mozapps/handling/content/handler.css
new file mode 100644
index 000000000..438ab296d
--- /dev/null
+++ b/toolkit/mozapps/handling/content/handler.css
@@ -0,0 +1,11 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+richlistitem[type="handler"] {
+ -moz-binding: url('chrome://mozapps/content/handling/handler.xml#handler');
+}
+
+#remember-text:not([visible]) {
+ visibility: hidden;
+}
diff --git a/toolkit/mozapps/handling/content/handler.xml b/toolkit/mozapps/handling/content/handler.xml
new file mode 100644
index 000000000..3fd907b45
--- /dev/null
+++ b/toolkit/mozapps/handling/content/handler.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<bindings id="hanlder-bindings"
+ xmlns="http://www.mozilla.org/xbl"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:xbl="http://www.mozilla.org/xbl">
+
+ <binding id="handler"
+ extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
+
+ <content>
+ <xul:vbox pack="center">
+ <xul:image xbl:inherits="src=image" height="32" width="32"/>
+ </xul:vbox>
+ <xul:vbox flex="1">
+ <xul:label class="name" xbl:inherits="value=name"/>
+ <xul:label class="description" xbl:inherits="value=description"/>
+ </xul:vbox>
+ </content>
+ <implementation>
+ <property name="label" onget="return this.getAttribute('name') + ' ' + this.getAttribute('description');"/>
+ </implementation>
+ </binding>
+
+</bindings>
diff --git a/toolkit/mozapps/handling/jar.mn b/toolkit/mozapps/handling/jar.mn
new file mode 100644
index 000000000..d6225ecca
--- /dev/null
+++ b/toolkit/mozapps/handling/jar.mn
@@ -0,0 +1,10 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+toolkit.jar:
+% content mozapps %content/mozapps/
+ content/mozapps/handling/handler.css (content/handler.css)
+ content/mozapps/handling/handler.xml (content/handler.xml)
+ content/mozapps/handling/dialog.xul (content/dialog.xul)
+ content/mozapps/handling/dialog.js (content/dialog.js)
diff --git a/toolkit/mozapps/handling/moz.build b/toolkit/mozapps/handling/moz.build
new file mode 100644
index 000000000..19730db2f
--- /dev/null
+++ b/toolkit/mozapps/handling/moz.build
@@ -0,0 +1,12 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXTRA_COMPONENTS += [
+ 'nsContentDispatchChooser.js',
+ 'nsContentDispatchChooser.manifest',
+]
+
+JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file
diff --git a/toolkit/mozapps/handling/nsContentDispatchChooser.js b/toolkit/mozapps/handling/nsContentDispatchChooser.js
new file mode 100644
index 000000000..e02545594
--- /dev/null
+++ b/toolkit/mozapps/handling/nsContentDispatchChooser.js
@@ -0,0 +1,85 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+// Constants
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cr = Components.results;
+
+const CONTENT_HANDLING_URL = "chrome://mozapps/content/handling/dialog.xul";
+const STRINGBUNDLE_URL = "chrome://mozapps/locale/handling/handling.properties";
+
+// nsContentDispatchChooser class
+
+function nsContentDispatchChooser()
+{
+}
+
+nsContentDispatchChooser.prototype =
+{
+ classID: Components.ID("e35d5067-95bc-4029-8432-e8f1e431148d"),
+
+ // nsIContentDispatchChooser
+
+ ask: function ask(aHandler, aWindowContext, aURI, aReason)
+ {
+ var window = null;
+ try {
+ if (aWindowContext)
+ window = aWindowContext.getInterface(Ci.nsIDOMWindow);
+ } catch (e) { /* it's OK to not have a window */ }
+
+ var sbs = Cc["@mozilla.org/intl/stringbundle;1"].
+ getService(Ci.nsIStringBundleService);
+ var bundle = sbs.createBundle(STRINGBUNDLE_URL);
+
+ var xai = Cc["@mozilla.org/xre/app-info;1"].
+ getService(Ci.nsIXULAppInfo);
+ // TODO when this is hooked up for content, we will need different strings
+ // for most of these
+ var arr = [bundle.GetStringFromName("protocol.title"),
+ "",
+ bundle.GetStringFromName("protocol.description"),
+ bundle.GetStringFromName("protocol.choices.label"),
+ bundle.formatStringFromName("protocol.checkbox.label",
+ [aURI.scheme], 1),
+ bundle.GetStringFromName("protocol.checkbox.accesskey"),
+ bundle.formatStringFromName("protocol.checkbox.extra",
+ [xai.name], 1)];
+
+ var params = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
+ let SupportsString = Components.Constructor(
+ "@mozilla.org/supports-string;1",
+ "nsISupportsString");
+ for (let text of arr) {
+ let string = new SupportsString;
+ string.data = text;
+ params.appendElement(string, false);
+ }
+ params.appendElement(aHandler, false);
+ params.appendElement(aURI, false);
+ params.appendElement(aWindowContext, false);
+
+ var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
+ getService(Ci.nsIWindowWatcher);
+ ww.openWindow(window,
+ CONTENT_HANDLING_URL,
+ null,
+ "chrome,dialog=yes,resizable,centerscreen",
+ params);
+ },
+
+ // nsISupports
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentDispatchChooser])
+};
+
+// Module
+
+var components = [nsContentDispatchChooser];
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
diff --git a/toolkit/mozapps/handling/nsContentDispatchChooser.manifest b/toolkit/mozapps/handling/nsContentDispatchChooser.manifest
new file mode 100644
index 000000000..fcc76a410
--- /dev/null
+++ b/toolkit/mozapps/handling/nsContentDispatchChooser.manifest
@@ -0,0 +1,2 @@
+component {e35d5067-95bc-4029-8432-e8f1e431148d} nsContentDispatchChooser.js
+contract @mozilla.org/content-dispatch-chooser;1 {e35d5067-95bc-4029-8432-e8f1e431148d}