diff options
Diffstat (limited to 'toolkit/mozapps/handling')
-rw-r--r-- | toolkit/mozapps/handling/content/dialog.js | 278 | ||||
-rw-r--r-- | toolkit/mozapps/handling/content/dialog.xul | 52 | ||||
-rw-r--r-- | toolkit/mozapps/handling/content/handler.css | 11 | ||||
-rw-r--r-- | toolkit/mozapps/handling/content/handler.xml | 28 | ||||
-rw-r--r-- | toolkit/mozapps/handling/jar.mn | 10 | ||||
-rw-r--r-- | toolkit/mozapps/handling/moz.build | 12 | ||||
-rw-r--r-- | toolkit/mozapps/handling/nsContentDispatchChooser.js | 85 | ||||
-rw-r--r-- | toolkit/mozapps/handling/nsContentDispatchChooser.manifest | 2 |
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} |