toolkit/content/widgets/text.xml

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:3b8c09fb361c
1 <?xml version="1.0"?>
2 <!-- This Source Code Form is subject to the terms of the Mozilla Public
3 - License, v. 2.0. If a copy of the MPL was not distributed with this
4 - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
5
6
7 <bindings id="textBindings"
8 xmlns="http://www.mozilla.org/xbl"
9 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
10 xmlns:html="http://www.w3.org/1999/xhtml">
11
12 <!-- bound to <description>s -->
13 <binding id="text-base" role="xul:text">
14 <implementation implements="nsIDOMXULDescriptionElement">
15 <property name="disabled" onset="if (val) this.setAttribute('disabled', 'true');
16 else this.removeAttribute('disabled');
17 return val;"
18 onget="return this.getAttribute('disabled') == 'true';"/>
19 <property name="value" onget="return this.getAttribute('value');"
20 onset="this.setAttribute('value', val); return val;"/>
21 <property name="crop" onget="return this.getAttribute('crop');"
22 onset="this.setAttribute('crop', val); return val;"/>
23 </implementation>
24 </binding>
25
26 <binding id="text-label" extends="chrome://global/content/bindings/text.xml#text-base">
27 <implementation implements="nsIDOMXULLabelElement">
28 <property name="accessKey">
29 <getter>
30 <![CDATA[
31 var accessKey = this.getAttribute('accesskey');
32 return accessKey ? accessKey[0] : null;
33 ]]>
34 </getter>
35 <setter>
36 <![CDATA[
37 this.setAttribute('accesskey', val);
38 return val;
39 ]]>
40 </setter>
41 </property>
42
43 <property name="control" onget="return getAttribute('control');">
44 <setter>
45 <![CDATA[
46 // After this gets set, the label will use the binding #label-control
47 this.setAttribute('control', val);
48 return val;
49 ]]>
50 </setter>
51 </property>
52 </implementation>
53 </binding>
54
55 <binding id="label-control" extends="chrome://global/content/bindings/text.xml#text-label">
56 <content>
57 <children/><html:span anonid="accessKeyParens"></html:span>
58 </content>
59 <implementation implements="nsIDOMXULLabelElement">
60 <constructor>
61 <![CDATA[
62 this.formatAccessKey(true);
63 ]]>
64 </constructor>
65
66 <method name="formatAccessKey">
67 <parameter name="firstTime"/>
68 <body>
69 <![CDATA[
70 var control = this.labeledControlElement;
71 if (!control) {
72 var bindingParent = document.getBindingParent(this);
73 if (bindingParent instanceof Components.interfaces.nsIDOMXULLabeledControlElement) {
74 control = bindingParent; // For controls that make the <label> an anon child
75 }
76 }
77 if (control) {
78 control.labelElement = this;
79 }
80
81 var accessKey = this.accessKey;
82 // No need to remove existing formatting the first time.
83 if (firstTime && !accessKey)
84 return;
85
86 if (this.mInsertSeparator === undefined) {
87 try {
88 var prefs = Components.classes["@mozilla.org/preferences-service;1"].
89 getService(Components.interfaces.nsIPrefBranch);
90 this.mUnderlineAccesskey = (prefs.getIntPref("ui.key.menuAccessKey") != 0);
91
92 const nsIPrefLocalizedString =
93 Components.interfaces.nsIPrefLocalizedString;
94
95 const prefNameInsertSeparator =
96 "intl.menuitems.insertseparatorbeforeaccesskeys";
97 const prefNameAlwaysAppendAccessKey =
98 "intl.menuitems.alwaysappendaccesskeys";
99
100 var val = prefs.getComplexValue(prefNameInsertSeparator,
101 nsIPrefLocalizedString).data;
102 this.mInsertSeparator = (val == "true");
103
104 val = prefs.getComplexValue(prefNameAlwaysAppendAccessKey,
105 nsIPrefLocalizedString).data;
106 this.mAlwaysAppendAccessKey = (val == "true");
107 }
108 catch (e) {
109 this.mInsertSeparator = true;
110 }
111 }
112
113 if (!this.mUnderlineAccesskey)
114 return;
115
116 var afterLabel = document.getAnonymousElementByAttribute(this, "anonid", "accessKeyParens");
117 afterLabel.textContent = "";
118
119 var oldAccessKey = this.getElementsByAttribute('class', 'accesskey').item(0);
120 if (oldAccessKey) { // Clear old accesskey
121 this.mergeElement(oldAccessKey);
122 }
123
124 var oldHiddenSpan =
125 this.getElementsByAttribute('class', 'hiddenColon').item(0);
126 if (oldHiddenSpan) {
127 this.mergeElement(oldHiddenSpan);
128 }
129
130 var labelText = this.textContent;
131 if (!accessKey || !labelText || !control) {
132 return;
133 }
134 var accessKeyIndex = -1;
135 if (!this.mAlwaysAppendAccessKey) {
136 accessKeyIndex = labelText.indexOf(accessKey);
137 if (accessKeyIndex < 0) { // Try again in upper case
138 accessKeyIndex =
139 labelText.toUpperCase().indexOf(accessKey.toUpperCase());
140 }
141 }
142
143 const HTML_NS = "http://www.w3.org/1999/xhtml";
144 var span = document.createElementNS(HTML_NS, "span");
145 span.className = "accesskey";
146
147 // Note that if you change the following code, see the comment of
148 // nsTextBoxFrame::UpdateAccessTitle.
149
150 // If accesskey is not in string, append in parentheses
151 if (accessKeyIndex < 0) {
152 // If end is colon, we should insert before colon.
153 // i.e., "label:" -> "label(X):"
154 var colonHidden = false;
155 if (/:$/.test(labelText)) {
156 labelText = labelText.slice(0, -1);
157 var hiddenSpan = document.createElementNS(HTML_NS, "span");
158 hiddenSpan.className = "hiddenColon";
159 hiddenSpan.style.display = "none";
160 // Hide the last colon by using span element.
161 // I.e., label<span style="display:none;">:</span>
162 this.wrapChar(hiddenSpan, labelText.length);
163 colonHidden = true;
164 }
165 // If end is space(U+20),
166 // we should not add space before parentheses.
167 var endIsSpace = false;
168 if (/ $/.test(labelText)) {
169 endIsSpace = true;
170 }
171 if (this.mInsertSeparator && !endIsSpace)
172 afterLabel.textContent = " (";
173 else
174 afterLabel.textContent = "(";
175 span.textContent = accessKey.toUpperCase();
176 afterLabel.appendChild(span);
177 if (!colonHidden)
178 afterLabel.appendChild(document.createTextNode(")"));
179 else
180 afterLabel.appendChild(document.createTextNode("):"));
181 return;
182 }
183 this.wrapChar(span, accessKeyIndex);
184 ]]>
185 </body>
186 </method>
187
188 <method name="wrapChar">
189 <parameter name="element"/>
190 <parameter name="index"/>
191 <body>
192 <![CDATA[
193 var treeWalker = document.createTreeWalker(this,
194 NodeFilter.SHOW_TEXT,
195 null);
196 var node = treeWalker.nextNode();
197 while (index >= node.length) {
198 index -= node.length;
199 node = treeWalker.nextNode();
200 }
201 if (index) {
202 node = node.splitText(index);
203 }
204 node.parentNode.insertBefore(element, node);
205 if (node.length > 1) {
206 node.splitText(1);
207 }
208 element.appendChild(node);
209 ]]>
210 </body>
211 </method>
212
213 <method name="mergeElement">
214 <parameter name="element"/>
215 <body>
216 <![CDATA[
217 if (element.previousSibling instanceof Text) {
218 element.previousSibling.appendData(element.textContent)
219 }
220 else {
221 element.parentNode.insertBefore(element.firstChild, element);
222 }
223 element.parentNode.removeChild(element);
224 ]]>
225 </body>
226 </method>
227
228 <field name="mUnderlineAccesskey">
229 !/Mac/.test(navigator.platform)
230 </field>
231 <field name="mInsertSeparator"/>
232 <field name="mAlwaysAppendAccessKey">false</field>
233
234 <property name="accessKey">
235 <getter>
236 <![CDATA[
237 var accessKey = null;
238 var labeledEl = this.labeledControlElement;
239 if (labeledEl) {
240 accessKey = labeledEl.getAttribute('accesskey');
241 }
242 if (!accessKey) {
243 accessKey = this.getAttribute('accesskey');
244 }
245 return accessKey ? accessKey[0] : null;
246 ]]>
247 </getter>
248 <setter>
249 <![CDATA[
250 // If this label already has an accesskey attribute store it here as well
251 if (this.hasAttribute('accesskey')) {
252 this.setAttribute('accesskey', val);
253 }
254 var control = this.labeledControlElement;
255 if (control) {
256 control.setAttribute('accesskey', val);
257 }
258 this.formatAccessKey(false);
259 return val;
260 ]]>
261 </setter>
262 </property>
263
264 <property name="labeledControlElement" readonly="true"
265 onget="var control = this.control; return control ? document.getElementById(control) : null;" />
266
267 <property name="control" onget="return this.getAttribute('control');">
268 <setter>
269 <![CDATA[
270 var control = this.labeledControlElement;
271 if (control) {
272 control.labelElement = null; // No longer pointed to be this label
273 }
274 this.setAttribute('control', val);
275 this.formatAccessKey(false);
276 return val;
277 ]]>
278 </setter>
279 </property>
280
281 </implementation>
282
283 <handlers>
284 <handler event="click" action="if (this.disabled) return;
285 var controlElement = this.labeledControlElement;
286 if(controlElement)
287 controlElement.focus();
288 "/>
289 </handlers>
290 </binding>
291
292 <binding id="text-link" extends="chrome://global/content/bindings/text.xml#text-label" role="xul:link">
293 <implementation>
294 <property name="href" onget="return this.getAttribute('href');"
295 onset="this.setAttribute('href', val); return val;" />
296 <method name="open">
297 <parameter name="aEvent"/>
298 <body>
299 <![CDATA[
300 var href = this.href;
301 if (!href || this.disabled || aEvent.defaultPrevented)
302 return;
303
304 var uri = null;
305 try {
306 const nsISSM = Components.interfaces.nsIScriptSecurityManager;
307 const secMan =
308 Components.classes["@mozilla.org/scriptsecuritymanager;1"]
309 .getService(nsISSM);
310
311 const ioService =
312 Components.classes["@mozilla.org/network/io-service;1"]
313 .getService(Components.interfaces.nsIIOService);
314
315 uri = ioService.newURI(href, null, null);
316
317 var nullPrincipal =
318 Components.classes["@mozilla.org/nullprincipal;1"]
319 .createInstance(Components.interfaces.nsIPrincipal);
320 try {
321 secMan.checkLoadURIWithPrincipal(nullPrincipal, uri,
322 nsISSM.DISALLOW_INHERIT_PRINCIPAL)
323 }
324 catch (ex) {
325 var msg = "Error: Cannot open a " + uri.scheme + ": link using \
326 the text-link binding.";
327 Components.utils.reportError(msg);
328 return;
329 }
330
331 const cID = "@mozilla.org/uriloader/external-protocol-service;1";
332 const nsIEPS = Components.interfaces.nsIExternalProtocolService;
333 var protocolSvc = Components.classes[cID].getService(nsIEPS);
334
335 // if the scheme is not an exposed protocol, then opening this link
336 // should be deferred to the system's external protocol handler
337 if (!protocolSvc.isExposedProtocol(uri.scheme)) {
338 protocolSvc.loadUrl(uri);
339 aEvent.preventDefault()
340 return;
341 }
342
343 }
344 catch (ex) {
345 Components.utils.reportError(ex);
346 }
347
348 aEvent.preventDefault();
349 href = uri ? uri.spec : href;
350
351 // Try handing off the link to the host application, e.g. for
352 // opening it in a tabbed browser.
353 var linkHandled = Components.classes["@mozilla.org/supports-PRBool;1"]
354 .createInstance(Components.interfaces.nsISupportsPRBool);
355 linkHandled.data = false;
356 Components.classes["@mozilla.org/observer-service;1"]
357 .getService(Components.interfaces.nsIObserverService)
358 .notifyObservers(linkHandled, "handle-xul-text-link", href);
359 if (linkHandled.data)
360 return;
361
362 // otherwise, fall back to opening the anchor directly
363 var win = window;
364 if (window instanceof Components.interfaces.nsIDOMChromeWindow) {
365 while (win.opener && !win.opener.closed)
366 win = win.opener;
367 }
368 win.open(href);
369 ]]>
370 </body>
371 </method>
372 </implementation>
373
374 <handlers>
375 <handler event="click" phase="capturing" button="0" action="this.open(event)"/>
376 <handler event="keypress" preventdefault="true" keycode="VK_RETURN" action="this.click()" />
377 </handlers>
378 </binding>
379
380 </bindings>

mercurial