]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/xul/staff_client/chrome/content/main/bindings.xml
internal: an alternative to default_focus
[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                         <destructor>                                                                                              
151                                 <![CDATA[                                                                                         
152                                 try {                                                                                                            
153                                         delete this._props;                                                                                      
154                                         delete this.sprintf;                                                                                     
155                                 } catch(E) {                                                                                                     
156                                         alert('Error destroying messagecatalog in bindings.xml: ' + E);                                             
157                                         throw(E);                                                                                                    
158                                 }                                                                                                                
159                                 ]]>                                                                                               
160                         </destructor>  
161
162                         <property name="src">
163                                 <getter>
164                                         <![CDATA[
165                     try {
166                                         return this.getAttribute('src');
167                     } catch(E) {
168                         alert('Error getting @src in messagecatalog in bindings.xml: ' + E);
169                         throw(E);
170                     }
171                                         ]]>
172                                 </getter>
173                                 <setter>
174                                         <![CDATA[
175                     try {
176                                             this.setAttribute('src',val);
177                                         this.load_from_src();
178                                         return val;
179                     } catch(E) {
180                         alert('Error setting @src in messagecatalog in bindings.xml: ' + E);
181                         throw(E);
182                     }
183                                         ]]>
184                                 </setter>
185                         </property>
186
187                         <method name="_load_from_src">
188                                 <body>
189                                         <![CDATA[
190                     try {
191                             var x = new XMLHttpRequest();
192                             x.open("GET",this.src,false);
193                             x.send(null);
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];
198                                 }
199                             } else {
200                                 var msg = "messageCatalog: No text from " + this.src;
201                                 alert(msg); throw(msg);
202                             }
203                            
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);
208                                 x2.send(null);
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];
213                                     }
214                                 }
215                             } catch(EE) {}
216
217                     } catch(E) {
218                         alert('Error loading properties in messagecatalog in bindings.xml: ' + E);
219                         throw(E);
220                     }
221                                         ]]>
222                                 </body>
223                         </method>
224
225                         <method name="_props2object">
226                                 <parameter name="str"/>
227                                 <body>
228                                         <![CDATA[
229                         try {
230                             var lines = str.split("\n");
231                             var props = {};
232                             var line = '';
233                             var in_comment = false;
234
235                             for (var l in lines) {
236                                 line += lines[l];
237
238                                 // handle multi-line comments
239                                 if (line.indexOf('/*') >= 0) in_comment = true;
240
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);
245                                     in_comment = false;
246                                 } else if (in_comment) continue;
247                                     
248                                 // get rid of entire-line comments
249                                 if (line.indexOf('#') == 0) {
250                                     line = '';
251                                     continue;
252                                 }
253
254                                 // handle end-of-line comments
255                                 var end_comment = line.indexOf('//');
256                                 if (end_comment >= 0) line = line.substring(0, end_comment);
257
258                                 // and line concatenation
259                                 if (line.charAt(line.length - 1) == '\\') {
260                                     line = line.substring(0,line.length - 1);
261                                     continue;
262                                 }
263
264                                 var eq_pos = line.indexOf('=');
265                                 if (eq_pos < 0) continue;
266
267                                 var k = line.substring(0,eq_pos);
268                                 k = k.replace(/\s+/g,"");
269
270                                 var v = line.substring(eq_pos + 1);
271
272                                 var current_m = 0;
273                                 var cont = false;
274                                 do {    
275                                     if (v.indexOf( "{" + current_m + "}" ) >= 0 ) {
276                                         var mes_bund = new RegExp( "\\\{" + current_m + "\\\}", 'g' );
277                                         var sprintf_format = "%" + (current_m + 1) + "$s";
278
279                                         v = v.replace( mes_bund, sprintf_format );
280
281                                         cont = true;
282                                         current_m++;
283                                     } else {
284                                         cont = false;
285                                     }
286                                 } while ( cont == true );
287
288                                 props[k] = v;
289                                 line = '';
290                                 }
291
292                             return props;
293                         } catch(E) {
294                             alert('Error in props2object in messagecatalog in bindings.xml: ' + E);
295                             throw(E);
296                         }
297                                         ]]>
298                                 </body>
299                         </method>
300
301                         <method name="testString">
302                                 <parameter name="key"/>
303                                 <body>
304                                         <![CDATA[
305                                                 try {
306                             var str = this._props[key];
307                             return (typeof str != 'undefined');
308                                                 } catch(e) {
309                             return false;
310                                                 }
311                                         ]]>
312                                 </body>
313                         </method>
314
315
316                         <method name="getString">
317                                 <parameter name="key"/>
318                                 <body>
319                                         <![CDATA[
320                                                 try {
321                             var str = this._props[key];
322                             if (typeof str == 'undefined') throw(str);
323                                                         return str;
324                                                 } catch(e) {
325                                                         alert("*** Failed to get string " + key + " in bundle: " + this.src + "\n" + e);
326                                                         throw(e);
327                                                 }
328                                         ]]>
329                                 </body>
330                         </method>
331
332                         <method name="getFormattedString">
333                                 <parameter name="key"/>
334                                 <parameter name="params"/>
335                                 <body>
336                                         <![CDATA[
337                                                 try {
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);
342
343                                                         // replace unicode escapes
344 /*
345                                                         v = v.replace(
346                                                                 /\\u([0-9a-f]{4})/gi,
347                                                                 function (r,s) { return String.fromCharCode(s); }
348                                                         );
349 */
350
351                                                         return v;
352                                                 } catch(e) {
353                                                         alert("*** Failed to get string " + key + " in bundle: " + this.src + "\n");
354                                                         throw(e);
355                                                 }
356                                         ]]>
357                                 </body>
358                         </method>
359
360                         <method name="_load_sprintf">
361                                 <body>
362                                         <![CDATA[
363                                         try { 
364                                                 this.sprintf = function() {
365                                                                 // FIXME - is the following license GPL-compatible? seems equivalent to the public domain
366                                                                 /**
367                                                                  * JavaScript printf/sprintf functions.
368                                                                  *
369                                                                  * This code is unrestricted: you are free to use it however you like.
370                                                                  * 
371                                                                  * The functions should work as expected, performing left or right alignment,
372                                                                  * truncating strings, outputting numbers with a required precision etc.
373                                                                  *
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
377                                                                  * numbers.
378                                                                  *
379                                                                  * See http://perldoc.perl.org/functions/sprintf.html for more information.
380                                                                  *
381                                                                  * Implemented:
382                                                                  * - zero and space-padding
383                                                                  * - right and left-alignment,
384                                                                  * - base X prefix (binary, octal and hex)
385                                                                  * - positive number prefix
386                                                                  * - (minimum) width
387                                                                  * - precision / truncation / maximum width
388                                                                  * - out of order arguments
389                                                                  *
390                                                                  * Not implemented (yet):
391                                                                  * - vector flag
392                                                                  * - size (bytes, words, long-words etc.)
393                                                                  * 
394                                                                  * Will not implement:
395                                                                  * - %n or %p (no pass-by-reference in JavaScript)
396                                                                  *
397                                                                  * @version 2007.04.27
398                                                                  * @author Ash Searle
399                                                                  */
400
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;
404
405                                                         }
406
407                                                         function justify(value, prefix, leftJustify, minWidth, zeroPad) {
408                                                         var diff = minWidth - value.length;
409                                                         if (diff > 0) {
410                                                                 if (leftJustify || !zeroPad) {
411                                                                 value = pad(value, minWidth, ' ', leftJustify);
412                                                                 } else {
413                                                                 value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
414                                                                 }
415                                                         }
416                                                         return value;
417                                                         }
418
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);
425                                                         }
426
427                                                         function formatString(value, leftJustify, minWidth, precision, zeroPad) {
428                                                         if (precision != null) {
429                                                                 value = value.slice(0, precision);
430                                                         }
431                                                         return justify(value, '', leftJustify, minWidth, zeroPad);
432                                                         }
433
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 '%';
437
438                                                                 // parse flags
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;
446                                                                 }
447
448                                                                 // parameters may be null, undefined, empty-string or real valued
449                                                                 // we want to ignore null, undefined and empty-string values
450
451                                                                 if (!minWidth) {
452                                                                 minWidth = 0;
453                                                                 } else if (minWidth == '*') {
454                                                                 minWidth = +a[i++];
455                                                                 } else if (minWidth.charAt(0) == '*') {
456                                                                 minWidth = +a[minWidth.slice(1, -1)];
457                                                                 } else {
458                                                                 minWidth = +minWidth;
459                                                                 }
460
461                                                                 // Note: undocumented perl feature:
462                                                                 if (minWidth < 0) {
463                                                                 minWidth = -minWidth;
464                                                                 leftJustify = true;
465                                                                 }
466
467                                                                 if (!isFinite(minWidth)) {
468                                                                 throw new Error('sprintf: (minimum-)width must be finite');
469                                                                 }
470
471                                                                 if (!precision) {
472                                                                 precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : void(0);
473                                                                 } else if (precision == '*') {
474                                                                 precision = +a[i++];
475                                                                 } else if (precision.charAt(0) == '*') {
476                                                                 precision = +a[precision.slice(1, -1)];
477                                                                 } else {
478                                                                 precision = +precision;
479                                                                 }
480
481                                                                 // grab value using valueIndex if required?
482                                                                 var value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];
483
484                                                                 switch (type) {
485                                                                 case 'S':
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);
493                                                                 case 'i':
494                                                                 case 'd': {
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);
499                                                                           }
500                                                                 case 'e':
501                                                                 case 'E':
502                                                                 case 'f':
503                                                                 case 'F':
504                                                                 case 'g':
505                                                                 case 'G':
506                                                                                   {
507                                                                                   var number = +value;
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]();
513                                                                           }
514                                                                 default: return substring;
515                                                                 }
516                                                                 });
517                                                 }
518                                         } catch(e) {
519                                                 alert("*** Failed to load sprintf library: " + e + "\n");
520                                                 throw(e);
521                                         }
522                                         ]]>
523                                 </body>
524                         </method>
525                 </implementation>
526         </binding>
527
528         <binding id="caption" extends="chrome://global/content/bindings/general.xml#basetext">
529                 <resources>
530                         <stylesheet src="chrome://global/skin/groupbox.css"/>
531                 </resources>
532
533                 <content>
534                         <children>
535                                 <xul:image
536                                         onclick="
537                                                 var n = document.getAnonymousNodes(parentNode.parentNode)[1];
538                                                 if (n.hidden) {
539                                                         n.hidden = false;
540                                                         this.setAttribute('src','chrome://open_ils_staff_client/skin/media/images/opentriangle.gif');
541                                                 } else {
542                                                         n.hidden = true;
543                                                         this.setAttribute('src','chrome://open_ils_staff_client/skin/media/images/triangle.gif');
544                                                 }
545                                         "
546                                 />
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" />
549                         </children>
550                 </content>
551
552                 <implementation>
553                         <constructor>
554                                 <![CDATA[
555                                         var n = document.getAnonymousNodes(this)[0];
556                                         n.setAttribute('src','chrome://open_ils_staff_client/skin/media/images/opentriangle.gif');
557                                 ]]>
558                         </constructor>
559                         <destructor>
560                                 <![CDATA[
561                                         var n = document.getAnonymousNodes(this)[0];
562                                         n.onclick = null;
563                                 ]]>
564                         </destructor>
565                 </implementation>
566         </binding>
567
568 </bindings>