3 <bindings id="openils_bindings"
4 xmlns="http://www.mozilla.org/xbl"
5 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
6 xmlns:xbl="http://www.mozilla.org/xbl">
13 <xul:button label="Help" accesskey="H" xbl:inherits="label,accesskey" />
21 // This widget will try to load help content from various static and dynamic URL's, stopping at the
22 // first one that it finds. Given an example location.href of '/xul/server/patron/display.xul' and
23 // a @src of 'foo.html', it will check these URL's in this order:
26 // /xul/server/patron/display.xul.custom_help.html
27 // /xul/server/patron/display.xul.help.html
28 // /xul/server/patron/custom_help.html
29 // /xul/server/patron/help.html
30 // /xul/server/custom_help.html
31 // /xul/server/help.html
32 // /xul/custom_help.html
37 // If @pathname is specified, it will override the value from location.pathname
38 // If @hostname is specified, it will override the value from location.hostname
39 // If @port is specified, it will override the value from location.port
40 // If @protocol is specified, it will override the value from location.protocol
42 this.addEventListener( 'command', function(ev) { this._open_window(); }, false);
44 alert('Error constructing help widget in bindings.xml: ' + E);
50 <method name="_open_window">
56 var protocol = obj.getAttribute('protocol') || location.protocol;
57 var hostname = obj.getAttribute('hostname') || location.hostname;
58 var port = obj.getAttribute('port') || location.port;
59 var pathname = obj.getAttribute('pathname') || location.pathname;
61 function test_url(loc) {
62 if (loc == '/' || !loc) { return false; }
63 var x = new XMLHttpRequest();
64 var url = protocol + '//' + hostname + ( port ? ':' + port : '' ) + loc;
65 dump('help widget: testing <'+url+'>\n');
66 x.open("HEAD", url, false);
68 return x.status == 200;
71 function open_url(loc) {
72 var url = protocol + '//' + hostname + ( port ? ':' + port : '' ) + loc +'?id='+obj.id;
73 dump('help widget: opening <'+url+'>\n');
74 window.open(url, obj.getAttribute('label'), 'resizable,scrollbars');
77 if (test_url('/'+this.getAttribute('src'))) {
78 open_url('/'+this.getAttribute('src'));
80 if (test_url(pathname + '.custom_help.html')) {
81 open_url(pathname + '.custom_help.html');
83 if (test_url(pathname + '.help.html')) {
84 open_url(pathname + '.help.html');
86 var pathparts = pathname.split('/');
87 var base_url; var url; var test_result;
88 for (var i = pathparts.length - 2; i>0 && !test_result; i--) {
89 base_url = ''; url = '';
90 for ( j = 1; j <= i; j++ ) { base_url += '/' + pathparts[j]; };
91 url = base_url + '/custom_help.html';
92 test_result = test_url(url);
94 url = base_url + '/help.html';
95 test_result = test_url(url);
101 if (test_url("/custom_help.html")) {
102 open_url("/custom_help.html");
104 if (test_url("/help.html")) {
105 open_url("/help.html");
108 alert('No Help Found');
116 alert('Error opening window in help widget in bindings.xml: ' + E);
127 <binding id="messagecatalog">
140 this._load_sprintf();
142 this._load_from_src();
144 alert('Error constructing messagecatalog in bindings.xml: ' + E);
156 alert('Error destroying messagecatalog in bindings.xml: ' + E);
162 <property name="src">
166 return this.getAttribute('src');
168 alert('Error getting @src in messagecatalog in bindings.xml: ' + E);
176 this.setAttribute('src',val);
177 this.load_from_src();
180 alert('Error setting @src in messagecatalog in bindings.xml: ' + E);
187 <method name="_load_from_src">
191 var x = new XMLHttpRequest();
192 x.open("GET",this.src,false);
194 if ((x.status == 0 || x.status == 200) && x.responseText) {
195 var props = this._props2object(x.responseText);
196 for (var i in props) {
197 this._props[i] = props[i];
200 var msg = "messageCatalog: No text from " + this.src;
201 alert(msg); throw(msg);
204 try { // fail silently if no custom properties file exists
205 var custom_src = String(this.src).replace(/\.properties$/,'_custom.properties');
206 var x2 = new XMLHttpRequest();
207 x2.open("GET",custom_src,false);
209 if ((x2.status == 0 || x2.status == 200) && x2.responseText) {
210 var props = this._props2object(x2.responseText);
211 for (var i in props) {
212 this._props[i] = props[i];
218 alert('Error loading properties in messagecatalog in bindings.xml: ' + E);
225 <method name="_props2object">
226 <parameter name="str"/>
230 var lines = str.split("\n");
233 var in_comment = false;
235 for (var l in lines) {
238 // handle multi-line comments
239 if (line.indexOf('/*') >= 0) in_comment = true;
241 if (in_comment && line.indexOf('*/') > 0) {
242 var comment_start = line.indexOf('/*');
243 var comment_end = line.indexOf('*/');
244 line = line.substring(0, comment_start) + line.substring(0, comment_end + 2);
246 } else if (in_comment) continue;
248 // get rid of entire-line comments
249 if (line.indexOf('#') == 0) {
254 // handle end-of-line comments
255 var end_comment = line.indexOf('//');
256 if (end_comment >= 0) line = line.substring(0, end_comment);
258 // and line concatenation
259 if (line.charAt(line.length - 1) == '\\') {
260 line = line.substring(0,line.length - 1);
264 var eq_pos = line.indexOf('=');
265 if (eq_pos < 0) continue;
267 var k = line.substring(0,eq_pos);
268 k = k.replace(/\s+/g,"");
270 var v = line.substring(eq_pos + 1);
275 if (v.indexOf( "{" + current_m + "}" ) >= 0 ) {
276 var mes_bund = new RegExp( "\\\{" + current_m + "\\\}", 'g' );
277 var sprintf_format = "%" + (current_m + 1) + "$s";
279 v = v.replace( mes_bund, sprintf_format );
286 } while ( cont == true );
294 alert('Error in props2object in messagecatalog in bindings.xml: ' + E);
301 <method name="testString">
302 <parameter name="key"/>
306 var str = this._props[key];
307 return (typeof str != 'undefined');
316 <method name="getString">
317 <parameter name="key"/>
321 var str = this._props[key];
322 if (typeof str == 'undefined') throw(str);
325 alert("*** Failed to get string " + key + " in bundle: " + this.src + "\n" + e);
332 <method name="getFormattedString">
333 <parameter name="key"/>
334 <parameter name="params"/>
338 var str = this._props[key];
339 if (typeof str == 'undefined') throw(str);
340 var these = [ str ].concat(params);
341 var v = this.sprintf.apply(this,these);
343 // replace unicode escapes
346 /\\u([0-9a-f]{4})/gi,
347 function (r,s) { return String.fromCharCode(s); }
353 alert("*** Failed to get string " + key + " in bundle: " + this.src + "\n");
360 <method name="_load_sprintf">
364 this.sprintf = function() {
365 // FIXME - is the following license GPL-compatible? seems equivalent to the public domain
367 * JavaScript printf/sprintf functions.
369 * This code is unrestricted: you are free to use it however you like.
371 * The functions should work as expected, performing left or right alignment,
372 * truncating strings, outputting numbers with a required precision etc.
374 * For complex cases, these functions follow the Perl implementations of
375 * (s)printf, allowing arguments to be passed out-of-order, and to set the
376 * precision or length of the output based on arguments instead of fixed
379 * See http://perldoc.perl.org/functions/sprintf.html for more information.
382 * - zero and space-padding
383 * - right and left-alignment,
384 * - base X prefix (binary, octal and hex)
385 * - positive number prefix
387 * - precision / truncation / maximum width
388 * - out of order arguments
390 * Not implemented (yet):
392 * - size (bytes, words, long-words etc.)
394 * Will not implement:
395 * - %n or %p (no pass-by-reference in JavaScript)
397 * @version 2007.04.27
401 function pad(str, len, chr, leftJustify) {
402 var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);
403 return leftJustify ? str + padding : padding + str;
407 function justify(value, prefix, leftJustify, minWidth, zeroPad) {
408 var diff = minWidth - value.length;
410 if (leftJustify || !zeroPad) {
411 value = pad(value, minWidth, ' ', leftJustify);
413 value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
419 function formatBaseX(value, base, prefix, leftJustify, minWidth, precision, zeroPad) {
420 // Note: casts negative numbers to positive ones
421 var number = value >>> 0;
422 prefix = prefix && number && {'2': '0b', '8': '0', '16': '0x'}[base] || '';
423 value = prefix + pad(number.toString(base), precision || 0, '0', false);
424 return justify(value, prefix, leftJustify, minWidth, zeroPad);
427 function formatString(value, leftJustify, minWidth, precision, zeroPad) {
428 if (precision != null) {
429 value = value.slice(0, precision);
431 return justify(value, '', leftJustify, minWidth, zeroPad);
434 var a = arguments, i = 0, format = a[i++];
435 return format.replace(/%%|%(\d+\$)?([-+#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuidfegEGS])/g, function(substring, valueIndex, flags, minWidth, _, precision, type) {
436 if (substring == '%%') return '%';
439 var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false;
440 for (var j = 0; flags && j < flags.length; j++) switch (flags.charAt(j)) {
441 case ' ': positivePrefix = ' '; break;
442 case '+': positivePrefix = '+'; break;
443 case '-': leftJustify = true; break;
444 case '0': zeroPad = true; break;
445 case '#': prefixBaseX = true; break;
448 // parameters may be null, undefined, empty-string or real valued
449 // we want to ignore null, undefined and empty-string values
453 } else if (minWidth == '*') {
455 } else if (minWidth.charAt(0) == '*') {
456 minWidth = +a[minWidth.slice(1, -1)];
458 minWidth = +minWidth;
461 // Note: undocumented perl feature:
463 minWidth = -minWidth;
467 if (!isFinite(minWidth)) {
468 throw new Error('sprintf: (minimum-)width must be finite');
472 precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : void(0);
473 } else if (precision == '*') {
475 } else if (precision.charAt(0) == '*') {
476 precision = +a[precision.slice(1, -1)];
478 precision = +precision;
481 // grab value using valueIndex if required?
482 var value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];
486 case 's': return formatString(String(value), leftJustify, minWidth, precision, zeroPad);
487 case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);
488 case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
489 case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
490 case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
491 case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase();
492 case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
495 var number = parseInt(+value);
496 var prefix = number < 0 ? '-' : positivePrefix;
497 value = prefix + pad(String(Math.abs(number)), precision, '0', false);
498 return justify(value, prefix, leftJustify, minWidth, zeroPad);
508 var prefix = number < 0 ? '-' : positivePrefix;
509 var method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
510 var textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
511 value = prefix + Math.abs(number)[method](precision);
512 return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform]();
514 default: return substring;
519 alert("*** Failed to load sprintf library: " + e + "\n");
528 <binding id="caption" extends="chrome://global/content/bindings/general.xml#basetext">
530 <stylesheet src="chrome://global/skin/groupbox.css"/>
537 var n = document.getAnonymousNodes(parentNode.parentNode)[1];
540 this.setAttribute('src','chrome://open_ils_staff_client/skin/media/images/opentriangle.gif');
543 this.setAttribute('src','chrome://open_ils_staff_client/skin/media/images/triangle.gif');
547 <xul:image class="caption-icon" xbl:inherits="src=image"/>
548 <xul:label class="caption-text" flex="1" xbl:inherits="default,value=label,crop,accesskey" />
555 var n = document.getAnonymousNodes(this)[0];
556 n.setAttribute('src','chrome://open_ils_staff_client/skin/media/images/opentriangle.gif');
561 var n = document.getAnonymousNodes(this)[0];