summaryrefslogtreecommitdiff
path: root/components/bindings/content/text.xml
diff options
context:
space:
mode:
Diffstat (limited to 'components/bindings/content/text.xml')
-rw-r--r--components/bindings/content/text.xml386
1 files changed, 386 insertions, 0 deletions
diff --git a/components/bindings/content/text.xml b/components/bindings/content/text.xml
new file mode 100644
index 000000000..ed998cee4
--- /dev/null
+++ b/components/bindings/content/text.xml
@@ -0,0 +1,386 @@
+<?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="textBindings"
+ xmlns="http://www.mozilla.org/xbl"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml">
+
+ <!-- bound to <description>s -->
+ <binding id="text-base" role="xul:text">
+ <implementation implements="nsIDOMXULDescriptionElement">
+ <property name="disabled" onset="if (val) this.setAttribute('disabled', 'true');
+ else this.removeAttribute('disabled');
+ return val;"
+ onget="return this.getAttribute('disabled') == 'true';"/>
+ <property name="value" onget="return this.getAttribute('value');"
+ onset="this.setAttribute('value', val); return val;"/>
+ <property name="crop" onget="return this.getAttribute('crop');"
+ onset="this.setAttribute('crop', val); return val;"/>
+ </implementation>
+ </binding>
+
+ <binding id="text-label" extends="chrome://global/content/bindings/text.xml#text-base">
+ <implementation implements="nsIDOMXULLabelElement">
+ <property name="accessKey">
+ <getter>
+ <![CDATA[
+ var accessKey = this.getAttribute('accesskey');
+ return accessKey ? accessKey[0] : null;
+ ]]>
+ </getter>
+ <setter>
+ <![CDATA[
+ this.setAttribute('accesskey', val);
+ return val;
+ ]]>
+ </setter>
+ </property>
+
+ <property name="control" onget="return getAttribute('control');">
+ <setter>
+ <![CDATA[
+ // After this gets set, the label will use the binding #label-control
+ this.setAttribute('control', val);
+ return val;
+ ]]>
+ </setter>
+ </property>
+ </implementation>
+ </binding>
+
+ <binding id="label-control" extends="chrome://global/content/bindings/text.xml#text-label">
+ <content>
+ <children/><html:span anonid="accessKeyParens"></html:span>
+ </content>
+ <implementation implements="nsIDOMXULLabelElement">
+ <constructor>
+ <![CDATA[
+ this.formatAccessKey(true);
+ ]]>
+ </constructor>
+
+ <method name="formatAccessKey">
+ <parameter name="firstTime"/>
+ <body>
+ <![CDATA[
+ var control = this.labeledControlElement;
+ if (!control) {
+ var bindingParent = document.getBindingParent(this);
+ if (bindingParent instanceof Components.interfaces.nsIDOMXULLabeledControlElement) {
+ control = bindingParent; // For controls that make the <label> an anon child
+ }
+ }
+ if (control) {
+ control.labelElement = this;
+ }
+
+ var accessKey = this.accessKey;
+ // No need to remove existing formatting the first time.
+ if (firstTime && !accessKey)
+ return;
+
+ if (this.mInsertSeparator === undefined) {
+ try {
+ var prefs = Components.classes["@mozilla.org/preferences-service;1"].
+ getService(Components.interfaces.nsIPrefBranch);
+ this.mUnderlineAccesskey = (prefs.getIntPref("ui.key.menuAccessKey") != 0);
+
+ const nsIPrefLocalizedString =
+ Components.interfaces.nsIPrefLocalizedString;
+
+ const prefNameInsertSeparator =
+ "intl.menuitems.insertseparatorbeforeaccesskeys";
+ const prefNameAlwaysAppendAccessKey =
+ "intl.menuitems.alwaysappendaccesskeys";
+
+ var val = prefs.getComplexValue(prefNameInsertSeparator,
+ nsIPrefLocalizedString).data;
+ this.mInsertSeparator = (val == "true");
+
+ val = prefs.getComplexValue(prefNameAlwaysAppendAccessKey,
+ nsIPrefLocalizedString).data;
+ this.mAlwaysAppendAccessKey = (val == "true");
+ }
+ catch (e) {
+ this.mInsertSeparator = true;
+ }
+ }
+
+ if (!this.mUnderlineAccesskey)
+ return;
+
+ var afterLabel = document.getAnonymousElementByAttribute(this, "anonid", "accessKeyParens");
+ afterLabel.textContent = "";
+
+ var oldAccessKey = this.getElementsByAttribute('class', 'accesskey').item(0);
+ if (oldAccessKey) { // Clear old accesskey
+ this.mergeElement(oldAccessKey);
+ }
+
+ var oldHiddenSpan =
+ this.getElementsByAttribute('class', 'hiddenColon').item(0);
+ if (oldHiddenSpan) {
+ this.mergeElement(oldHiddenSpan);
+ }
+
+ var labelText = this.textContent;
+ if (!accessKey || !labelText || !control) {
+ return;
+ }
+ var accessKeyIndex = -1;
+ if (!this.mAlwaysAppendAccessKey) {
+ accessKeyIndex = labelText.indexOf(accessKey);
+ if (accessKeyIndex < 0) { // Try again in upper case
+ accessKeyIndex =
+ labelText.toUpperCase().indexOf(accessKey.toUpperCase());
+ }
+ }
+
+ const HTML_NS = "http://www.w3.org/1999/xhtml";
+ var span = document.createElementNS(HTML_NS, "span");
+ span.className = "accesskey";
+
+ // Note that if you change the following code, see the comment of
+ // nsTextBoxFrame::UpdateAccessTitle.
+
+ // If accesskey is not in string, append in parentheses
+ if (accessKeyIndex < 0) {
+ // If end is colon, we should insert before colon.
+ // i.e., "label:" -> "label(X):"
+ var colonHidden = false;
+ if (/:$/.test(labelText)) {
+ labelText = labelText.slice(0, -1);
+ var hiddenSpan = document.createElementNS(HTML_NS, "span");
+ hiddenSpan.className = "hiddenColon";
+ hiddenSpan.style.display = "none";
+ // Hide the last colon by using span element.
+ // I.e., label<span style="display:none;">:</span>
+ this.wrapChar(hiddenSpan, labelText.length);
+ colonHidden = true;
+ }
+ // If end is space(U+20),
+ // we should not add space before parentheses.
+ var endIsSpace = false;
+ if (/ $/.test(labelText)) {
+ endIsSpace = true;
+ }
+ if (this.mInsertSeparator && !endIsSpace)
+ afterLabel.textContent = " (";
+ else
+ afterLabel.textContent = "(";
+ span.textContent = accessKey.toUpperCase();
+ afterLabel.appendChild(span);
+ if (!colonHidden)
+ afterLabel.appendChild(document.createTextNode(")"));
+ else
+ afterLabel.appendChild(document.createTextNode("):"));
+ return;
+ }
+ this.wrapChar(span, accessKeyIndex);
+ ]]>
+ </body>
+ </method>
+
+ <method name="wrapChar">
+ <parameter name="element"/>
+ <parameter name="index"/>
+ <body>
+ <![CDATA[
+ var treeWalker = document.createTreeWalker(this,
+ NodeFilter.SHOW_TEXT,
+ null);
+ var node = treeWalker.nextNode();
+ while (index >= node.length) {
+ index -= node.length;
+ node = treeWalker.nextNode();
+ }
+ if (index) {
+ node = node.splitText(index);
+ }
+ node.parentNode.insertBefore(element, node);
+ if (node.length > 1) {
+ node.splitText(1);
+ }
+ element.appendChild(node);
+ ]]>
+ </body>
+ </method>
+
+ <method name="mergeElement">
+ <parameter name="element"/>
+ <body>
+ <![CDATA[
+ if (element.previousSibling instanceof Text) {
+ element.previousSibling.appendData(element.textContent)
+ }
+ else {
+ element.parentNode.insertBefore(element.firstChild, element);
+ }
+ element.parentNode.removeChild(element);
+ ]]>
+ </body>
+ </method>
+
+ <field name="mUnderlineAccesskey">
+ !/Mac/.test(navigator.platform)
+ </field>
+ <field name="mInsertSeparator"/>
+ <field name="mAlwaysAppendAccessKey">false</field>
+
+ <property name="accessKey">
+ <getter>
+ <![CDATA[
+ var accessKey = null;
+ var labeledEl = this.labeledControlElement;
+ if (labeledEl) {
+ accessKey = labeledEl.getAttribute('accesskey');
+ }
+ if (!accessKey) {
+ accessKey = this.getAttribute('accesskey');
+ }
+ return accessKey ? accessKey[0] : null;
+ ]]>
+ </getter>
+ <setter>
+ <![CDATA[
+ // If this label already has an accesskey attribute store it here as well
+ if (this.hasAttribute('accesskey')) {
+ this.setAttribute('accesskey', val);
+ }
+ var control = this.labeledControlElement;
+ if (control) {
+ control.setAttribute('accesskey', val);
+ }
+ this.formatAccessKey(false);
+ return val;
+ ]]>
+ </setter>
+ </property>
+
+ <property name="labeledControlElement" readonly="true"
+ onget="var control = this.control; return control ? document.getElementById(control) : null;" />
+
+ <property name="control" onget="return this.getAttribute('control');">
+ <setter>
+ <![CDATA[
+ var control = this.labeledControlElement;
+ if (control) {
+ control.labelElement = null; // No longer pointed to be this label
+ }
+ this.setAttribute('control', val);
+ this.formatAccessKey(false);
+ return val;
+ ]]>
+ </setter>
+ </property>
+
+ </implementation>
+
+ <handlers>
+ <handler event="click" action="if (this.disabled) return;
+ var controlElement = this.labeledControlElement;
+ if(controlElement)
+ controlElement.focus();
+ "/>
+ </handlers>
+ </binding>
+
+ <binding id="text-link" extends="chrome://global/content/bindings/text.xml#text-label" role="xul:link">
+ <implementation>
+ <property name="href" onget="return this.getAttribute('href');"
+ onset="this.setAttribute('href', val); return val;" />
+ <method name="open">
+ <parameter name="aEvent"/>
+ <body>
+ <![CDATA[
+ var href = this.href;
+ if (!href || this.disabled || aEvent.defaultPrevented)
+ return;
+
+ var uri = null;
+ try {
+ const nsISSM = Components.interfaces.nsIScriptSecurityManager;
+ const secMan =
+ Components.classes["@mozilla.org/scriptsecuritymanager;1"]
+ .getService(nsISSM);
+
+ const ioService =
+ Components.classes["@mozilla.org/network/io-service;1"]
+ .getService(Components.interfaces.nsIIOService);
+
+ uri = ioService.newURI(href, null, null);
+
+ let principal;
+ if (this.getAttribute("useoriginprincipal") == "true") {
+ principal = this.nodePrincipal;
+ } else {
+ principal = secMan.createNullPrincipal({});
+ }
+ try {
+ secMan.checkLoadURIWithPrincipal(principal, uri,
+ nsISSM.DISALLOW_INHERIT_PRINCIPAL);
+ }
+ catch (ex) {
+ var msg = "Error: Cannot open a " + uri.scheme + ": link using \
+ the text-link binding.";
+ Components.utils.reportError(msg);
+ return;
+ }
+
+ const cID = "@mozilla.org/uriloader/external-protocol-service;1";
+ const nsIEPS = Components.interfaces.nsIExternalProtocolService;
+ var protocolSvc = Components.classes[cID].getService(nsIEPS);
+
+ // if the scheme is not an exposed protocol, then opening this link
+ // should be deferred to the system's external protocol handler
+ if (!protocolSvc.isExposedProtocol(uri.scheme)) {
+ protocolSvc.loadUrl(uri);
+ aEvent.preventDefault()
+ return;
+ }
+
+ }
+ catch (ex) {
+ Components.utils.reportError(ex);
+ }
+
+ aEvent.preventDefault();
+ href = uri ? uri.spec : href;
+
+ // Try handing off the link to the host application, e.g. for
+ // opening it in a tabbed browser.
+ var linkHandled = Components.classes["@mozilla.org/supports-PRBool;1"]
+ .createInstance(Components.interfaces.nsISupportsPRBool);
+ linkHandled.data = false;
+ let {shiftKey, ctrlKey, metaKey, altKey, button} = aEvent;
+ let data = {shiftKey, ctrlKey, metaKey, altKey, button, href};
+ Components.classes["@mozilla.org/observer-service;1"]
+ .getService(Components.interfaces.nsIObserverService)
+ .notifyObservers(linkHandled, "handle-xul-text-link", JSON.stringify(data));
+ if (linkHandled.data)
+ return;
+
+ // otherwise, fall back to opening the anchor directly
+ var win = window;
+ if (window instanceof Components.interfaces.nsIDOMChromeWindow) {
+ while (win.opener && !win.opener.closed)
+ win = win.opener;
+ }
+ win.open(href);
+ ]]>
+ </body>
+ </method>
+ </implementation>
+
+ <handlers>
+ <handler event="click" phase="capturing" button="0" action="this.open(event)"/>
+ <handler event="click" phase="capturing" button="1" action="this.open(event)"/>
+ <handler event="keypress" preventdefault="true" keycode="VK_RETURN" action="this.click()" />
+ </handlers>
+ </binding>
+
+</bindings>