<?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>