1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/content/widgets/text.xml Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,380 @@ 1.4 +<?xml version="1.0"?> 1.5 +<!-- This Source Code Form is subject to the terms of the Mozilla Public 1.6 + - License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> 1.8 + 1.9 + 1.10 +<bindings id="textBindings" 1.11 + xmlns="http://www.mozilla.org/xbl" 1.12 + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 1.13 + xmlns:html="http://www.w3.org/1999/xhtml"> 1.14 + 1.15 + <!-- bound to <description>s --> 1.16 + <binding id="text-base" role="xul:text"> 1.17 + <implementation implements="nsIDOMXULDescriptionElement"> 1.18 + <property name="disabled" onset="if (val) this.setAttribute('disabled', 'true'); 1.19 + else this.removeAttribute('disabled'); 1.20 + return val;" 1.21 + onget="return this.getAttribute('disabled') == 'true';"/> 1.22 + <property name="value" onget="return this.getAttribute('value');" 1.23 + onset="this.setAttribute('value', val); return val;"/> 1.24 + <property name="crop" onget="return this.getAttribute('crop');" 1.25 + onset="this.setAttribute('crop', val); return val;"/> 1.26 + </implementation> 1.27 + </binding> 1.28 + 1.29 + <binding id="text-label" extends="chrome://global/content/bindings/text.xml#text-base"> 1.30 + <implementation implements="nsIDOMXULLabelElement"> 1.31 + <property name="accessKey"> 1.32 + <getter> 1.33 + <![CDATA[ 1.34 + var accessKey = this.getAttribute('accesskey'); 1.35 + return accessKey ? accessKey[0] : null; 1.36 + ]]> 1.37 + </getter> 1.38 + <setter> 1.39 + <![CDATA[ 1.40 + this.setAttribute('accesskey', val); 1.41 + return val; 1.42 + ]]> 1.43 + </setter> 1.44 + </property> 1.45 + 1.46 + <property name="control" onget="return getAttribute('control');"> 1.47 + <setter> 1.48 + <![CDATA[ 1.49 + // After this gets set, the label will use the binding #label-control 1.50 + this.setAttribute('control', val); 1.51 + return val; 1.52 + ]]> 1.53 + </setter> 1.54 + </property> 1.55 + </implementation> 1.56 + </binding> 1.57 + 1.58 + <binding id="label-control" extends="chrome://global/content/bindings/text.xml#text-label"> 1.59 + <content> 1.60 + <children/><html:span anonid="accessKeyParens"></html:span> 1.61 + </content> 1.62 + <implementation implements="nsIDOMXULLabelElement"> 1.63 + <constructor> 1.64 + <![CDATA[ 1.65 + this.formatAccessKey(true); 1.66 + ]]> 1.67 + </constructor> 1.68 + 1.69 + <method name="formatAccessKey"> 1.70 + <parameter name="firstTime"/> 1.71 + <body> 1.72 + <![CDATA[ 1.73 + var control = this.labeledControlElement; 1.74 + if (!control) { 1.75 + var bindingParent = document.getBindingParent(this); 1.76 + if (bindingParent instanceof Components.interfaces.nsIDOMXULLabeledControlElement) { 1.77 + control = bindingParent; // For controls that make the <label> an anon child 1.78 + } 1.79 + } 1.80 + if (control) { 1.81 + control.labelElement = this; 1.82 + } 1.83 + 1.84 + var accessKey = this.accessKey; 1.85 + // No need to remove existing formatting the first time. 1.86 + if (firstTime && !accessKey) 1.87 + return; 1.88 + 1.89 + if (this.mInsertSeparator === undefined) { 1.90 + try { 1.91 + var prefs = Components.classes["@mozilla.org/preferences-service;1"]. 1.92 + getService(Components.interfaces.nsIPrefBranch); 1.93 + this.mUnderlineAccesskey = (prefs.getIntPref("ui.key.menuAccessKey") != 0); 1.94 + 1.95 + const nsIPrefLocalizedString = 1.96 + Components.interfaces.nsIPrefLocalizedString; 1.97 + 1.98 + const prefNameInsertSeparator = 1.99 + "intl.menuitems.insertseparatorbeforeaccesskeys"; 1.100 + const prefNameAlwaysAppendAccessKey = 1.101 + "intl.menuitems.alwaysappendaccesskeys"; 1.102 + 1.103 + var val = prefs.getComplexValue(prefNameInsertSeparator, 1.104 + nsIPrefLocalizedString).data; 1.105 + this.mInsertSeparator = (val == "true"); 1.106 + 1.107 + val = prefs.getComplexValue(prefNameAlwaysAppendAccessKey, 1.108 + nsIPrefLocalizedString).data; 1.109 + this.mAlwaysAppendAccessKey = (val == "true"); 1.110 + } 1.111 + catch (e) { 1.112 + this.mInsertSeparator = true; 1.113 + } 1.114 + } 1.115 + 1.116 + if (!this.mUnderlineAccesskey) 1.117 + return; 1.118 + 1.119 + var afterLabel = document.getAnonymousElementByAttribute(this, "anonid", "accessKeyParens"); 1.120 + afterLabel.textContent = ""; 1.121 + 1.122 + var oldAccessKey = this.getElementsByAttribute('class', 'accesskey').item(0); 1.123 + if (oldAccessKey) { // Clear old accesskey 1.124 + this.mergeElement(oldAccessKey); 1.125 + } 1.126 + 1.127 + var oldHiddenSpan = 1.128 + this.getElementsByAttribute('class', 'hiddenColon').item(0); 1.129 + if (oldHiddenSpan) { 1.130 + this.mergeElement(oldHiddenSpan); 1.131 + } 1.132 + 1.133 + var labelText = this.textContent; 1.134 + if (!accessKey || !labelText || !control) { 1.135 + return; 1.136 + } 1.137 + var accessKeyIndex = -1; 1.138 + if (!this.mAlwaysAppendAccessKey) { 1.139 + accessKeyIndex = labelText.indexOf(accessKey); 1.140 + if (accessKeyIndex < 0) { // Try again in upper case 1.141 + accessKeyIndex = 1.142 + labelText.toUpperCase().indexOf(accessKey.toUpperCase()); 1.143 + } 1.144 + } 1.145 + 1.146 + const HTML_NS = "http://www.w3.org/1999/xhtml"; 1.147 + var span = document.createElementNS(HTML_NS, "span"); 1.148 + span.className = "accesskey"; 1.149 + 1.150 + // Note that if you change the following code, see the comment of 1.151 + // nsTextBoxFrame::UpdateAccessTitle. 1.152 + 1.153 + // If accesskey is not in string, append in parentheses 1.154 + if (accessKeyIndex < 0) { 1.155 + // If end is colon, we should insert before colon. 1.156 + // i.e., "label:" -> "label(X):" 1.157 + var colonHidden = false; 1.158 + if (/:$/.test(labelText)) { 1.159 + labelText = labelText.slice(0, -1); 1.160 + var hiddenSpan = document.createElementNS(HTML_NS, "span"); 1.161 + hiddenSpan.className = "hiddenColon"; 1.162 + hiddenSpan.style.display = "none"; 1.163 + // Hide the last colon by using span element. 1.164 + // I.e., label<span style="display:none;">:</span> 1.165 + this.wrapChar(hiddenSpan, labelText.length); 1.166 + colonHidden = true; 1.167 + } 1.168 + // If end is space(U+20), 1.169 + // we should not add space before parentheses. 1.170 + var endIsSpace = false; 1.171 + if (/ $/.test(labelText)) { 1.172 + endIsSpace = true; 1.173 + } 1.174 + if (this.mInsertSeparator && !endIsSpace) 1.175 + afterLabel.textContent = " ("; 1.176 + else 1.177 + afterLabel.textContent = "("; 1.178 + span.textContent = accessKey.toUpperCase(); 1.179 + afterLabel.appendChild(span); 1.180 + if (!colonHidden) 1.181 + afterLabel.appendChild(document.createTextNode(")")); 1.182 + else 1.183 + afterLabel.appendChild(document.createTextNode("):")); 1.184 + return; 1.185 + } 1.186 + this.wrapChar(span, accessKeyIndex); 1.187 + ]]> 1.188 + </body> 1.189 + </method> 1.190 + 1.191 + <method name="wrapChar"> 1.192 + <parameter name="element"/> 1.193 + <parameter name="index"/> 1.194 + <body> 1.195 + <![CDATA[ 1.196 + var treeWalker = document.createTreeWalker(this, 1.197 + NodeFilter.SHOW_TEXT, 1.198 + null); 1.199 + var node = treeWalker.nextNode(); 1.200 + while (index >= node.length) { 1.201 + index -= node.length; 1.202 + node = treeWalker.nextNode(); 1.203 + } 1.204 + if (index) { 1.205 + node = node.splitText(index); 1.206 + } 1.207 + node.parentNode.insertBefore(element, node); 1.208 + if (node.length > 1) { 1.209 + node.splitText(1); 1.210 + } 1.211 + element.appendChild(node); 1.212 + ]]> 1.213 + </body> 1.214 + </method> 1.215 + 1.216 + <method name="mergeElement"> 1.217 + <parameter name="element"/> 1.218 + <body> 1.219 + <![CDATA[ 1.220 + if (element.previousSibling instanceof Text) { 1.221 + element.previousSibling.appendData(element.textContent) 1.222 + } 1.223 + else { 1.224 + element.parentNode.insertBefore(element.firstChild, element); 1.225 + } 1.226 + element.parentNode.removeChild(element); 1.227 + ]]> 1.228 + </body> 1.229 + </method> 1.230 + 1.231 + <field name="mUnderlineAccesskey"> 1.232 + !/Mac/.test(navigator.platform) 1.233 + </field> 1.234 + <field name="mInsertSeparator"/> 1.235 + <field name="mAlwaysAppendAccessKey">false</field> 1.236 + 1.237 + <property name="accessKey"> 1.238 + <getter> 1.239 + <![CDATA[ 1.240 + var accessKey = null; 1.241 + var labeledEl = this.labeledControlElement; 1.242 + if (labeledEl) { 1.243 + accessKey = labeledEl.getAttribute('accesskey'); 1.244 + } 1.245 + if (!accessKey) { 1.246 + accessKey = this.getAttribute('accesskey'); 1.247 + } 1.248 + return accessKey ? accessKey[0] : null; 1.249 + ]]> 1.250 + </getter> 1.251 + <setter> 1.252 + <![CDATA[ 1.253 + // If this label already has an accesskey attribute store it here as well 1.254 + if (this.hasAttribute('accesskey')) { 1.255 + this.setAttribute('accesskey', val); 1.256 + } 1.257 + var control = this.labeledControlElement; 1.258 + if (control) { 1.259 + control.setAttribute('accesskey', val); 1.260 + } 1.261 + this.formatAccessKey(false); 1.262 + return val; 1.263 + ]]> 1.264 + </setter> 1.265 + </property> 1.266 + 1.267 + <property name="labeledControlElement" readonly="true" 1.268 + onget="var control = this.control; return control ? document.getElementById(control) : null;" /> 1.269 + 1.270 + <property name="control" onget="return this.getAttribute('control');"> 1.271 + <setter> 1.272 + <![CDATA[ 1.273 + var control = this.labeledControlElement; 1.274 + if (control) { 1.275 + control.labelElement = null; // No longer pointed to be this label 1.276 + } 1.277 + this.setAttribute('control', val); 1.278 + this.formatAccessKey(false); 1.279 + return val; 1.280 + ]]> 1.281 + </setter> 1.282 + </property> 1.283 + 1.284 + </implementation> 1.285 + 1.286 + <handlers> 1.287 + <handler event="click" action="if (this.disabled) return; 1.288 + var controlElement = this.labeledControlElement; 1.289 + if(controlElement) 1.290 + controlElement.focus(); 1.291 + "/> 1.292 + </handlers> 1.293 + </binding> 1.294 + 1.295 + <binding id="text-link" extends="chrome://global/content/bindings/text.xml#text-label" role="xul:link"> 1.296 + <implementation> 1.297 + <property name="href" onget="return this.getAttribute('href');" 1.298 + onset="this.setAttribute('href', val); return val;" /> 1.299 + <method name="open"> 1.300 + <parameter name="aEvent"/> 1.301 + <body> 1.302 + <![CDATA[ 1.303 + var href = this.href; 1.304 + if (!href || this.disabled || aEvent.defaultPrevented) 1.305 + return; 1.306 + 1.307 + var uri = null; 1.308 + try { 1.309 + const nsISSM = Components.interfaces.nsIScriptSecurityManager; 1.310 + const secMan = 1.311 + Components.classes["@mozilla.org/scriptsecuritymanager;1"] 1.312 + .getService(nsISSM); 1.313 + 1.314 + const ioService = 1.315 + Components.classes["@mozilla.org/network/io-service;1"] 1.316 + .getService(Components.interfaces.nsIIOService); 1.317 + 1.318 + uri = ioService.newURI(href, null, null); 1.319 + 1.320 + var nullPrincipal = 1.321 + Components.classes["@mozilla.org/nullprincipal;1"] 1.322 + .createInstance(Components.interfaces.nsIPrincipal); 1.323 + try { 1.324 + secMan.checkLoadURIWithPrincipal(nullPrincipal, uri, 1.325 + nsISSM.DISALLOW_INHERIT_PRINCIPAL) 1.326 + } 1.327 + catch (ex) { 1.328 + var msg = "Error: Cannot open a " + uri.scheme + ": link using \ 1.329 + the text-link binding."; 1.330 + Components.utils.reportError(msg); 1.331 + return; 1.332 + } 1.333 + 1.334 + const cID = "@mozilla.org/uriloader/external-protocol-service;1"; 1.335 + const nsIEPS = Components.interfaces.nsIExternalProtocolService; 1.336 + var protocolSvc = Components.classes[cID].getService(nsIEPS); 1.337 + 1.338 + // if the scheme is not an exposed protocol, then opening this link 1.339 + // should be deferred to the system's external protocol handler 1.340 + if (!protocolSvc.isExposedProtocol(uri.scheme)) { 1.341 + protocolSvc.loadUrl(uri); 1.342 + aEvent.preventDefault() 1.343 + return; 1.344 + } 1.345 + 1.346 + } 1.347 + catch (ex) { 1.348 + Components.utils.reportError(ex); 1.349 + } 1.350 + 1.351 + aEvent.preventDefault(); 1.352 + href = uri ? uri.spec : href; 1.353 + 1.354 + // Try handing off the link to the host application, e.g. for 1.355 + // opening it in a tabbed browser. 1.356 + var linkHandled = Components.classes["@mozilla.org/supports-PRBool;1"] 1.357 + .createInstance(Components.interfaces.nsISupportsPRBool); 1.358 + linkHandled.data = false; 1.359 + Components.classes["@mozilla.org/observer-service;1"] 1.360 + .getService(Components.interfaces.nsIObserverService) 1.361 + .notifyObservers(linkHandled, "handle-xul-text-link", href); 1.362 + if (linkHandled.data) 1.363 + return; 1.364 + 1.365 + // otherwise, fall back to opening the anchor directly 1.366 + var win = window; 1.367 + if (window instanceof Components.interfaces.nsIDOMChromeWindow) { 1.368 + while (win.opener && !win.opener.closed) 1.369 + win = win.opener; 1.370 + } 1.371 + win.open(href); 1.372 + ]]> 1.373 + </body> 1.374 + </method> 1.375 + </implementation> 1.376 + 1.377 + <handlers> 1.378 + <handler event="click" phase="capturing" button="0" action="this.open(event)"/> 1.379 + <handler event="keypress" preventdefault="true" keycode="VK_RETURN" action="this.click()" /> 1.380 + </handlers> 1.381 + </binding> 1.382 + 1.383 +</bindings>