]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/xul/staff_client/chrome/content/main/bindings.xml
35f179e1651c77d18a7f0d32ecc38e4be128e0e3
[working/Evergreen.git] / Open-ILS / xul / staff_client / chrome / content / main / bindings.xml
1 <?xml version="1.0"?>
2
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">
7
8     <binding id="help">
9         <resources/>
10
11         <content>
12             <!-- FIXME: I18N -->
13             <xul:button label="Help" accesskey="H" xbl:inherits="label,accesskey" />
14         </content>
15
16         <implementation>
17
18             <constructor>
19                 <![CDATA[
20                 try {
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:
24                     //
25                     // foo.html
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
33                     // /xul/help.html
34                     // /custom_help.html
35                     // /help.html
36                     //
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
41
42                     this.addEventListener( 'command', function(ev) { this._open_window(); }, false);
43                 } catch(E) {
44                     alert('Error constructing help widget in bindings.xml: ' + E);
45                     throw(E);
46                 }
47                 ]]>
48             </constructor>
49
50             <method name="_open_window">
51                 <body>
52                     <![CDATA[
53                     try {
54
55                             var obj = this;
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;
60
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);
67                                 x.send(null);
68                                 return x.status == 200;
69                             }
70
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');
75                             }
76
77                             if (test_url('/'+this.getAttribute('src'))) {
78                                 open_url('/'+this.getAttribute('src'));
79                             } else {
80                                 if (test_url(pathname + '.custom_help.html')) {
81                                     open_url(pathname + '.custom_help.html');
82                                 } else {
83                                     if (test_url(pathname + '.help.html')) {
84                                         open_url(pathname + '.help.html');
85                                     } else {
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);
93                                             if (!test_result) {
94                                                 url = base_url + '/help.html';
95                                                 test_result = test_url(url);
96                                             }
97                                         }
98                                         if (test_result) {
99                                             open_url(url);
100                                         } else {
101                                             if (test_url("/custom_help.html")) {
102                                                 open_url("/custom_help.html");
103                                             } else {
104                                                 if (test_url("/help.html")) {
105                                                     open_url("/help.html");
106                                                 } else {
107                                                     /* FIXME - I18N */
108                                                     alert('No Help Found');
109                                                 }
110                                             }
111                                         }
112                                     }
113                                 }
114                             }
115                     } catch(E) {
116                         alert('Error opening window in help widget in bindings.xml: ' + E);
117                         throw(E);
118                     }
119                     ]]>
120                 </body>
121             </method>
122
123         </implementation>
124     </binding>
125
126
127         <binding id="messagecatalog">
128                 <resources/>
129
130                 <content>
131                         <children>
132                         </children>
133                 </content>
134
135                 <implementation>
136
137                         <constructor>
138                                 <![CDATA[
139                 try {
140                         this._load_sprintf();
141                         this._props = {};
142                         this._load_from_src();
143                 } catch(E) {
144                     alert('Error constructing messagecatalog in bindings.xml: ' + E);
145                     throw(E);
146                 }
147                                 ]]>
148                         </constructor>
149
150                         <property name="src">
151                                 <getter>
152                                         <![CDATA[
153                     try {
154                                         return this.getAttribute('src');
155                     } catch(E) {
156                         alert('Error getting @src in messagecatalog in bindings.xml: ' + E);
157                         throw(E);
158                     }
159                                         ]]>
160                                 </getter>
161                                 <setter>
162                                         <![CDATA[
163                     try {
164                                             this.setAttribute('src',val);
165                                         this.load_from_src();
166                                         return val;
167                     } catch(E) {
168                         alert('Error setting @src in messagecatalog in bindings.xml: ' + E);
169                         throw(E);
170                     }
171                                         ]]>
172                                 </setter>
173                         </property>
174
175                         <method name="_load_from_src">
176                                 <body>
177                                         <![CDATA[
178                     try {
179                             var x = new XMLHttpRequest();
180                             x.open("GET",this.src,false);
181                             x.send(null);
182                             if ((x.status == 0 || x.status == 200) && x.responseText) {
183                                 var props = this._props2object(x.responseText);
184                                 for (var i in props) {
185                                     this._props[i] = props[i];
186                                 }
187                             } else {
188                                 var msg = "messageCatalog: No text from " + this.src;
189                                 alert(msg); throw(msg);
190                             }
191                            
192                             try { // fail silently if no custom properties file exists
193                                 var custom_src = String(this.src).replace(/\.properties$/,'_custom.properties'); 
194                                 var x2 = new XMLHttpRequest();
195                                 x2.open("GET",custom_src,false);
196                                 x2.send(null);
197                                 if ((x2.status == 0 || x2.status == 200) && x2.responseText) {
198                                     var props = this._props2object(x2.responseText);
199                                     for (var i in props) {
200                                         this._props[i] = props[i];
201                                     }
202                                 }
203                             } catch(EE) {}
204
205                     } catch(E) {
206                         alert('Error loading properties in messagecatalog in bindings.xml: ' + E);
207                         throw(E);
208                     }
209                                         ]]>
210                                 </body>
211                         </method>
212
213                         <method name="_props2object">
214                                 <parameter name="str"/>
215                                 <body>
216                                         <![CDATA[
217                         try {
218                             var lines = str.split("\n");
219                             var props = {};
220                             var line = '';
221                             var in_comment = false;
222
223                             for (var l in lines) {
224                                 line += lines[l];
225
226                                 // handle multi-line comments
227                                 if (line.indexOf('/*') >= 0) in_comment = true;
228
229                                 if (in_comment && line.indexOf('*/') > 0) {
230                                     var comment_start = line.indexOf('/*');
231                                     var comment_end = line.indexOf('*/');
232                                     line = line.substring(0, comment_start) + line.substring(0, comment_end + 2);
233                                     in_comment = false;
234                                 } else if (in_comment) continue;
235                                     
236                                 // get rid of entire-line comments
237                                 if (line.indexOf('#') == 0) {
238                                     line = '';
239                                     continue;
240                                 }
241
242                                 // handle end-of-line comments
243                                 var end_comment = line.indexOf('//');
244                                 if (end_comment >= 0) line = line.substring(0, end_comment);
245
246                                 // and line concatenation
247                                 if (line.charAt(line.length - 1) == '\\') {
248                                     line = line.substring(0,line.length - 1);
249                                     continue;
250                                 }
251
252                                 var eq_pos = line.indexOf('=');
253                                 if (eq_pos < 0) continue;
254
255                                 var k = line.substring(0,eq_pos);
256                                 k = k.replace(/\s+/g,"");
257
258                                 var v = line.substring(eq_pos + 1);
259
260                                 var current_m = 0;
261                                 var cont = false;
262                                 do {    
263                                     if (v.indexOf( "{" + current_m + "}" ) >= 0 ) {
264                                         var mes_bund = new RegExp( "\\\{" + current_m + "\\\}", 'g' );
265                                         var sprintf_format = "%" + (current_m + 1) + "$s";
266
267                                         v = v.replace( mes_bund, sprintf_format );
268
269                                         cont = true;
270                                         current_m++;
271                                     } else {
272                                         cont = false;
273                                     }
274                                 } while ( cont == true );
275
276                                 props[k] = v;
277                                 line = '';
278                                 }
279
280                             return props;
281                         } catch(E) {
282                             alert('Error in props2object in messagecatalog in bindings.xml: ' + E);
283                             throw(E);
284                         }
285                                         ]]>
286                                 </body>
287                         </method>
288
289                         <method name="testString">
290                                 <parameter name="key"/>
291                                 <body>
292                                         <![CDATA[
293                                                 try {
294                             var str = this._props[key];
295                             return (typeof str != 'undefined');
296                                                 } catch(e) {
297                             return false;
298                                                 }
299                                         ]]>
300                                 </body>
301                         </method>
302
303
304                         <method name="getString">
305                                 <parameter name="key"/>
306                                 <body>
307                                         <![CDATA[
308                                                 try {
309                             var str = this._props[key];
310                             if (typeof str == 'undefined') throw(str);
311                                                         return str;
312                                                 } catch(e) {
313                                                         alert("*** Failed to get string " + key + " in bundle: " + this.src + "\n" + e);
314                                                         throw(e);
315                                                 }
316                                         ]]>
317                                 </body>
318                         </method>
319
320                         <method name="getFormattedString">
321                                 <parameter name="key"/>
322                                 <parameter name="params"/>
323                                 <body>
324                                         <![CDATA[
325                                                 try {
326                                                         var str = this._props[key]; 
327                             if (typeof str == 'undefined') throw(str);
328                                                         var these = [ str ].concat(params);
329                                                         var v = this.sprintf.apply(this,these);
330
331                                                         // replace unicode escapes
332 /*
333                                                         v = v.replace(
334                                                                 /\\u([0-9a-f]{4})/gi,
335                                                                 function (r,s) { return String.fromCharCode(s); }
336                                                         );
337 */
338
339                                                         return v;
340                                                 } catch(e) {
341                                                         alert("*** Failed to get string " + key + " in bundle: " + this.src + "\n");
342                                                         throw(e);
343                                                 }
344                                         ]]>
345                                 </body>
346                         </method>
347
348                         <method name="_load_sprintf">
349                                 <body>
350                                         <![CDATA[
351                                         try { 
352                                                 this.sprintf = function() {
353                                                                 // FIXME - is the following license GPL-compatible? seems equivalent to the public domain
354                                                                 /**
355                                                                  * JavaScript printf/sprintf functions.
356                                                                  *
357                                                                  * This code is unrestricted: you are free to use it however you like.
358                                                                  * 
359                                                                  * The functions should work as expected, performing left or right alignment,
360                                                                  * truncating strings, outputting numbers with a required precision etc.
361                                                                  *
362                                                                  * For complex cases, these functions follow the Perl implementations of
363                                                                  * (s)printf, allowing arguments to be passed out-of-order, and to set the
364                                                                  * precision or length of the output based on arguments instead of fixed
365                                                                  * numbers.
366                                                                  *
367                                                                  * See http://perldoc.perl.org/functions/sprintf.html for more information.
368                                                                  *
369                                                                  * Implemented:
370                                                                  * - zero and space-padding
371                                                                  * - right and left-alignment,
372                                                                  * - base X prefix (binary, octal and hex)
373                                                                  * - positive number prefix
374                                                                  * - (minimum) width
375                                                                  * - precision / truncation / maximum width
376                                                                  * - out of order arguments
377                                                                  *
378                                                                  * Not implemented (yet):
379                                                                  * - vector flag
380                                                                  * - size (bytes, words, long-words etc.)
381                                                                  * 
382                                                                  * Will not implement:
383                                                                  * - %n or %p (no pass-by-reference in JavaScript)
384                                                                  *
385                                                                  * @version 2007.04.27
386                                                                  * @author Ash Searle
387                                                                  */
388
389                                                         function pad(str, len, chr, leftJustify) {
390                                                         var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);
391                                                         return leftJustify ? str + padding : padding + str;
392
393                                                         }
394
395                                                         function justify(value, prefix, leftJustify, minWidth, zeroPad) {
396                                                         var diff = minWidth - value.length;
397                                                         if (diff > 0) {
398                                                                 if (leftJustify || !zeroPad) {
399                                                                 value = pad(value, minWidth, ' ', leftJustify);
400                                                                 } else {
401                                                                 value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
402                                                                 }
403                                                         }
404                                                         return value;
405                                                         }
406
407                                                         function formatBaseX(value, base, prefix, leftJustify, minWidth, precision, zeroPad) {
408                                                         // Note: casts negative numbers to positive ones
409                                                         var number = value >>> 0;
410                                                         prefix = prefix && number && {'2': '0b', '8': '0', '16': '0x'}[base] || '';
411                                                         value = prefix + pad(number.toString(base), precision || 0, '0', false);
412                                                         return justify(value, prefix, leftJustify, minWidth, zeroPad);
413                                                         }
414
415                                                         function formatString(value, leftJustify, minWidth, precision, zeroPad) {
416                                                         if (precision != null) {
417                                                                 value = value.slice(0, precision);
418                                                         }
419                                                         return justify(value, '', leftJustify, minWidth, zeroPad);
420                                                         }
421
422                                                         var a = arguments, i = 0, format = a[i++];
423                                                         return format.replace(/%%|%(\d+\$)?([-+#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuidfegEGS])/g, function(substring, valueIndex, flags, minWidth, _, precision, type) {
424                                                                 if (substring == '%%') return '%';
425
426                                                                 // parse flags
427                                                                 var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false;
428                                                                 for (var j = 0; flags && j < flags.length; j++) switch (flags.charAt(j)) {
429                                                                 case ' ': positivePrefix = ' '; break;
430                                                                 case '+': positivePrefix = '+'; break;
431                                                                 case '-': leftJustify = true; break;
432                                                                 case '0': zeroPad = true; break;
433                                                                 case '#': prefixBaseX = true; break;
434                                                                 }
435
436                                                                 // parameters may be null, undefined, empty-string or real valued
437                                                                 // we want to ignore null, undefined and empty-string values
438
439                                                                 if (!minWidth) {
440                                                                 minWidth = 0;
441                                                                 } else if (minWidth == '*') {
442                                                                 minWidth = +a[i++];
443                                                                 } else if (minWidth.charAt(0) == '*') {
444                                                                 minWidth = +a[minWidth.slice(1, -1)];
445                                                                 } else {
446                                                                 minWidth = +minWidth;
447                                                                 }
448
449                                                                 // Note: undocumented perl feature:
450                                                                 if (minWidth < 0) {
451                                                                 minWidth = -minWidth;
452                                                                 leftJustify = true;
453                                                                 }
454
455                                                                 if (!isFinite(minWidth)) {
456                                                                 throw new Error('sprintf: (minimum-)width must be finite');
457                                                                 }
458
459                                                                 if (!precision) {
460                                                                 precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : void(0);
461                                                                 } else if (precision == '*') {
462                                                                 precision = +a[i++];
463                                                                 } else if (precision.charAt(0) == '*') {
464                                                                 precision = +a[precision.slice(1, -1)];
465                                                                 } else {
466                                                                 precision = +precision;
467                                                                 }
468
469                                                                 // grab value using valueIndex if required?
470                                                                 var value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];
471
472                                                                 switch (type) {
473                                                                 case 'S':
474                                                                 case 's': return formatString(String(value), leftJustify, minWidth, precision, zeroPad);
475                                                                 case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);
476                                                                 case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
477                                                                 case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
478                                                                 case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
479                                                                 case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase();
480                                                                 case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
481                                                                 case 'i':
482                                                                 case 'd': {
483                                                                                   var number = parseInt(+value);
484                                                                                   var prefix = number < 0 ? '-' : positivePrefix;
485                                                                                   value = prefix + pad(String(Math.abs(number)), precision, '0', false);
486                                                                                   return justify(value, prefix, leftJustify, minWidth, zeroPad);
487                                                                           }
488                                                                 case 'e':
489                                                                 case 'E':
490                                                                 case 'f':
491                                                                 case 'F':
492                                                                 case 'g':
493                                                                 case 'G':
494                                                                                   {
495                                                                                   var number = +value;
496                                                                                   var prefix = number < 0 ? '-' : positivePrefix;
497                                                                                   var method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
498                                                                                   var textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
499                                                                                   value = prefix + Math.abs(number)[method](precision);
500                                                                                   return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform]();
501                                                                           }
502                                                                 default: return substring;
503                                                                 }
504                                                                 });
505                                                 }
506                                         } catch(e) {
507                                                 alert("*** Failed to load sprintf library: " + e + "\n");
508                                                 throw(e);
509                                         }
510                                         ]]>
511                                 </body>
512                         </method>
513                 </implementation>
514         </binding>
515
516         <binding id="caption" extends="chrome://global/content/bindings/general.xml#basetext">
517                 <resources>
518                         <stylesheet src="chrome://global/skin/groupbox.css"/>
519                 </resources>
520
521                 <content>
522                         <children>
523                                 <xul:image
524                                         onclick="
525                                                 var n = document.getAnonymousNodes(parentNode.parentNode)[1];
526                                                 if (n.hidden) {
527                                                         n.hidden = false;
528                                                         this.setAttribute('src','chrome://open_ils_staff_client/skin/media/images/opentriangle.gif');
529                                                 } else {
530                                                         n.hidden = true;
531                                                         this.setAttribute('src','chrome://open_ils_staff_client/skin/media/images/triangle.gif');
532                                                 }
533                                         "
534                                 />
535                                 <xul:image class="caption-icon" xbl:inherits="src=image"/>
536                                 <xul:label class="caption-text" flex="1" xbl:inherits="default,value=label,crop,accesskey" />
537                         </children>
538                 </content>
539
540                 <implementation>
541                         <constructor>
542                                 <![CDATA[
543                                         var n = document.getAnonymousNodes(this)[0];
544                                         n.setAttribute('src','chrome://open_ils_staff_client/skin/media/images/opentriangle.gif');
545                                 ]]>
546                         </constructor>
547                 </implementation>
548         </binding>
549
550 </bindings>