]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/xul/staff_client/chrome/content/main/main.js
Replace deprecated javascript escape() with encodeURIComponent()
[Evergreen.git] / Open-ILS / xul / staff_client / chrome / content / main / main.js
1 dump('entering main/main.js\n');
2 // vim:noet:sw=4:ts=4:
3
4 var xulG;
5 var offlineStrings;
6 var authStrings;
7 var openTabs = new Array();
8 var tempWindow = null;
9 var tempFocusWindow = null;
10
11 function clear_the_cache() {
12     try {
13         var cacheClass         = Components.classes["@mozilla.org/network/cache-service;1"];
14         var cacheService    = cacheClass.getService(Components.interfaces.nsICacheService);
15         cacheService.evictEntries(Components.interfaces.nsICache.STORE_ON_DISK);
16         cacheService.evictEntries(Components.interfaces.nsICache.STORE_IN_MEMORY);
17     } catch(E) {
18         dump(E+'\n');alert(E);
19     }
20 }
21
22 function toOpenWindowByType(inType, uri) { /* for Venkman */
23     try {
24         var winopts = "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar";
25         window.open(uri, "_blank", winopts);
26     } catch(E) {
27         alert(E); throw(E);
28     }
29 }
30
31 function start_debugger() {
32     setTimeout(
33         function() {
34             try { start_venkman(); } catch(E) { alert(E); }
35         }, 0
36     );
37 };
38
39 function start_inspector() {
40     setTimeout(
41         function() {
42             try { inspectDOMDocument(); } catch(E) { alert(E); }
43         }, 0
44     );
45 };
46
47 function start_chrome_list() {
48     setTimeout(
49         function() {
50             try { startChromeList(); } catch(E) { alert(E); }
51         }, 0
52     );
53 };
54
55 function start_js_shell() {
56     setTimeout(
57         function() {
58             try { window.open('chrome://open_ils_staff_client/content/util/shell.html','shell','chrome,resizable,scrollbars'); } catch(E) { alert(E); }
59         }, 0
60     );
61 };
62
63 function new_tabs(aTabList, aContinue) {
64     if(aTabList != null) {
65         openTabs = openTabs.concat(aTabList);
66     }
67     if(G.data.session) { // Just add to the list of stuff to open unless we are logged in
68         var targetwindow = null;
69         var focuswindow = null;
70         var focustab = {'focus' : true};
71         if(aContinue == true && tempWindow.closed == false) {
72             if(tempWindow.g == undefined || tempWindow.g.menu == undefined) {
73                 setTimeout(
74                     function() {
75                         new_tabs(null, true);
76                     }, 300);
77                 return null;
78             }
79             targetwindow = tempWindow;
80             tempWindow = null;
81             focuswindow = tempFocusWindow;
82             tempFocusWindow = null;
83             focustab = {'nofocus' : true};
84         }
85         else if(tempWindow != null) { // In theory, we are waiting on a setTimeout
86             if(tempWindow.closed == true) // But someone closed our window?
87             {
88                 tempWindow = null;
89                 tempFocusWindow = null;
90             }
91             else
92             {
93                 return null;
94             }
95         }
96         var newTab;
97         var firstURL;
98         var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
99             getService(Components.interfaces.nsIWindowMediator);
100             // This may look out of place, but this is so we can continue this loop from down below
101 opentabs:
102             while(openTabs.length > 0) {
103             newTab = openTabs.shift();
104             if(newTab == 'new' || newTab == 'init') {
105                 if(newTab != 'init' && openTabs.length > 0 && openTabs[0] != 'new') {
106                     firstURL = openTabs.shift();
107                     if(firstURL != 'tab') { // 'new' followed by 'tab' should be equal to 'init' in functionality, this should do that
108                         if(urls[firstURL]) {
109                             firstURL = urls[firstURL];
110                         }
111                         firstURL = '&firstURL=' + window.encodeURIComponent(firstURL);
112                     }
113                     else {
114                         firstURL = '';
115                     }
116                 }
117                 else {
118                     firstURL = '';
119                 }
120                 targetwindow = xulG.window.open(urls.XUL_MENU_FRAME
121                     + '?server='+window.encodeURIComponent(G.data.server) + firstURL,
122                     '_blank','chrome,resizable'
123                 );
124                 targetwindow.xulG = xulG;
125                 if (focuswindow == null) {
126                     focuswindow = targetwindow;
127                 }
128                 tempWindow = targetwindow;
129                 tempFocusWindow = focuswindow;
130                 setTimeout(
131                     function() {
132                         new_tabs(null, true);
133                     }, 300);
134                 return null;
135             }
136             else {
137                 if(newTab == 'tab') {
138                     newTab = null;
139                 }
140                 else if(urls[newTab]) {
141                     newTab = urls[newTab];
142                 }
143                 if(targetwindow != null) { // Already have a previous target window? Use it first.
144                     if(targetwindow.g.menu.new_tab(newTab,focustab,null)) {
145                         focustab = {'nofocus' : true};
146                         continue;
147                     }
148                 }
149                 var enumerator = wm.getEnumerator('eg_menu');
150                 while(enumerator.hasMoreElements()) {
151                     targetwindow = enumerator.getNext();
152                     if(targetwindow.g.menu.new_tab(newTab,focustab,null)) {
153                         focustab = {'nofocus' : true};
154                         if (focuswindow == null) {
155                             focuswindow = targetwindow;
156                         }
157                         continue opentabs;
158                     }
159                 }
160                 // No windows found to add the tab to? Make a new one.
161                 if(newTab == null) { // Were we making a "default" tab?
162                     openTabs.unshift('init'); // 'init' does that for us!
163                 }
164                 else {
165                     openTabs.unshift('new',newTab);
166                 }
167             }
168         }
169         if(focuswindow != null) {
170             focuswindow.focus();
171         }
172     }
173 }
174
175 // Returns false if we can't get an actual perm list
176 // Returns an array of perms with boolean has/hasn't flag
177 function get_menu_perms(indocument) {
178     // If we don't have our static perm list, and we have a remote window, go looking.
179     // We never need to look twice unless a dev is manually editing their files.
180     // Shame on them, they can restart the entire client ;)
181     if(typeof(get_menu_perms.perm_list) == 'undefined' && indocument != null)
182     {
183         get_menu_perms.perm_list = [ ];
184         var commands = indocument.getElementById('universal_cmds').getElementsByTagName('command');
185         for (var i = 0; i < commands.length; i++) { 
186             if (commands[i].hasAttribute('perm')) {
187                 get_menu_perms.perm_list = get_menu_perms.perm_list.concat(commands[i].getAttribute('perm').split(' '));
188             }           
189         }
190     }
191     // 
192     if(typeof(get_menu_perms.perm_list) == 'object') {
193         G.data.stash_retrieve();
194         if(!G.data.menu_perms) {
195             JSAN.use('util.network');
196             var network = new util.network();
197             var r = network.simple_request('BATCH_PERM_RETRIEVE_WORK_OU', [ G.data.session.key, get_menu_perms.perm_list ]);
198             for(p in r)
199                 r[p] = (typeof(r[p][0]) == 'number');
200             // Developer-enabled clients override permissions and always allow debugging
201             if(G.data.debug_build) {
202                 r['DEBUG_CLIENT'] = true;
203             }
204             // If we have DEBUG_CLIENT (by force or otherwise) we can use debugging interfaces
205             // Doing this here because this function gets called at least once per login
206             // Including operator change
207             G.data.enable_debug = (r['DEBUG_CLIENT'] == true);
208             G.data.stash('enable_debug');
209             G.data.menu_perms = r;
210             G.data.stash('menu_perms');
211         }
212         return G.data.menu_perms;
213     }
214     return false;
215 }
216
217 // Returns a list (cached or from filesystem) of hotkey sets
218 function load_hotkey_sets() {
219     if(typeof(load_hotkey_sets.set_list) == 'undefined') {
220         load_hotkey_sets.set_list = [];
221         // We can't safely use util.file here because extensions aren't unpacked in Firefox 4+
222         // So instead we will use and parse information from a chrome:// URL
223         var hotkeysBase = 'chrome://open_ils_staff_client/skin/hotkeys/';
224         var ioService=Components.classes["@mozilla.org/network/io-service;1"]
225             .getService(Components.interfaces.nsIIOService);
226         var scriptableStream=Components
227             .classes["@mozilla.org/scriptableinputstream;1"]
228             .getService(Components.interfaces.nsIScriptableInputStream);
229
230         var channel=ioService.newChannel(hotkeysBase,null,null);
231         var input=channel.open();
232         var str = '';
233         scriptableStream.init(input);
234         try {
235             while(input.available()) {
236                 str+=scriptableStream.read(input.available());
237             }
238         } catch (E) {}
239         scriptableStream.close();
240         input.close();
241         // str now, in theory, has a list of files (and metadata) for our base chrome URL.
242         str = str.replace(/^(?!201: ).*$/gm,''); // Remove non-filename result lines
243         str = str.replace(/^(?!.*\.keyset).*$/gm,''); // Remove non-keyset file result lines
244         str = str.replace(/^201: (.*)\.keyset.*$/gm, "$1"); // Reduce keyset matches to just base names
245         // Split into an array
246         var files = str.trim().split(/[\r\n]+/g);
247         for (var i = 0; i < files.length; i++) {
248             if(files[i].length = 0) continue;
249             load_hotkey_sets.set_list.push(files[i]);
250         }
251     }
252     return load_hotkey_sets.set_list;
253 }
254
255 // Returns an array (cached or from filesystem) for a given hotkey set
256 function get_hotkey_array(keyset_name) {
257     if(typeof(get_hotkey_array.keyset_cache) == 'undefined') {
258         get_hotkey_array.keyset_cache = {};
259     }
260     if(get_hotkey_array.keyset_cache[keyset_name])
261         return get_hotkey_array.keyset_cache[keyset_name];
262     // We can't safely use util.file here because extensions aren't unpacked in Firefox 4+
263     // So instead we will use and parse information from a chrome:// URL
264     var hotkeysBase = 'chrome://open_ils_staff_client/skin/hotkeys/' + keyset_name + '.keyset';
265     var ioService=Components.classes["@mozilla.org/network/io-service;1"]
266         .getService(Components.interfaces.nsIIOService);
267     var scriptableStream=Components
268         .classes["@mozilla.org/scriptableinputstream;1"]
269         .getService(Components.interfaces.nsIScriptableInputStream);
270
271     var channel=ioService.newChannel(hotkeysBase,null,null);
272     var input=channel.open();
273     var keyset_raw = '';
274     scriptableStream.init(input);
275     try {
276         while(input.available()) {
277             keyset_raw+=scriptableStream.read(input.available());
278         }
279     } catch (E) {}
280     scriptableStream.close();
281     input.close();
282
283     var tempArray = [];
284
285     var keyset_lines = keyset_raw.trim().split("\n");
286     for(var line = 0; line < keyset_lines.length; line++) {
287         // Grab line, strip comments, strip leading/trailing whitespace
288         var curline = keyset_lines[line].replace(/\s*#.*$/,'').trim();
289         if(curline == "") continue; // Skip empty lines
290         // Split into pieces
291         var split_line = curline.split(',');
292         // We need at least 3 elements. Command, modifiers, keycode.
293         if(split_line.length < 3) continue;
294         // Trim each segment
295         split_line[0] = split_line[0].trim();
296         split_line[1] = split_line[1].trim();
297         split_line[2] = split_line[2].trim();
298         if(split_line.length > 3)
299             split_line[3] = split_line[3].trim();
300         // Skip empty commands
301         if(split_line[0] == "") continue;
302         // Push to array
303         tempArray.push(split_line);
304     }
305     get_hotkey_array.keyset_cache[keyset_name] = tempArray;
306     return tempArray;
307 }
308
309 function main_init() {
310     dump('entering main_init()\n');
311     try {
312         clear_the_cache();
313         if("arguments" in window && window.arguments.length > 0 && window.arguments[0].wrappedJSObject != undefined && window.arguments[0].wrappedJSObject.openTabs != undefined) {
314             openTabs = openTabs.concat(window.arguments[0].wrappedJSObject.openTabs);
315         }
316
317         // Disable commands that we can't do anything with right now
318         if(typeof start_venkman != 'function') {
319             document.getElementById('cmd_debugger').setAttribute('disabled','true');
320         }
321         if(typeof inspectDOMDocument != 'function') {
322             document.getElementById('cmd_inspector').setAttribute('disabled','true');
323         }
324         if(typeof startChromeList != 'function') {
325             document.getElementById('cmd_chrome_list').setAttribute('disabled','true');
326         }
327
328         // Now we can safely load the strings without the cache getting wiped
329         offlineStrings = document.getElementById('offlineStrings');
330         authStrings = document.getElementById('authStrings');
331
332         if (typeof JSAN == 'undefined') {
333             throw(
334                 offlineStrings.getString('common.jsan.missing')
335             );
336         }
337         /////////////////////////////////////////////////////////////////////////////
338
339         JSAN.errorLevel = "die"; // none, warn, or die
340         JSAN.addRepository('..');
341
342         //JSAN.use('test.test'); test.test.hello_world();
343
344         var mw = self;
345         G =  {};
346         
347         G.pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
348         G.pref.QueryInterface(Components.interfaces.nsIPrefBranch2);
349
350         JSAN.use('util.error');
351         G.error = new util.error();
352         G.error.sdump('D_ERROR', offlineStrings.getString('main.testing'));
353
354         JSAN.use('util.window');
355         G.window = new util.window();
356
357         JSAN.use('auth.controller');
358         G.auth = new auth.controller( { 'window' : mw } );
359
360         JSAN.use('OpenILS.data');
361         G.data = new OpenILS.data();
362         G.data.on_error = G.auth.logoff;
363
364         JSAN.use('util.file');
365         G.file = new util.file();
366         try {
367             G.file.get('ws_info');
368             G.ws_info = G.file.get_object(); G.file.close();
369         } catch(E) {
370             G.ws_info = {};
371         }
372         G.data.ws_info = G.ws_info; G.data.stash('ws_info');
373
374         G.auth.on_login = function() {
375
376             var url = G.auth.controller.view.server_prompt.value.match(/^[^\/]*/).toString() || urls.remote;
377
378             G.data.server_unadorned = url; G.data.stash('server_unadorned'); G.data.stash_retrieve();
379             try {
380                 G.data.search_lib = G.pref.getIntPref('open-ils.' + url + '.search_lib');
381             } catch(E) {
382                 G.data.search_lib = null;
383             }
384             try {
385                 G.data.pref_lib = G.pref.getIntPref('open-ils.' + url + '.pref_lib');
386             } catch(E) {
387                 G.data.pref_lib = null;
388             }
389             try {
390                 G.data.adv_pane = G.pref.getCharPref('open-ils.' + url + '.adv_pane');
391             } catch(E) {
392                 G.data.adv_pane = null;
393             }
394             G.data.stash('search_lib');
395             G.data.stash('pref_lib');
396             G.data.stash('adv_pane');
397
398             if (! url.match( '^(http|https)://' ) ) { url = 'http://' + url; }
399
400             G.data.server = url; G.data.stash('server'); 
401             G.data.session = { 'key' : G.auth.session.key, 'auth' : G.auth.session.authtime }; G.data.stash('session');
402             G.data.stash_retrieve();
403             try {
404                 var ios = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
405                 var cookieUriSSL = ios.newURI("https://" + G.data.server_unadorned, null, null);
406                 var cookieSvc = Components.classes["@mozilla.org/cookieService;1"].getService(Components.interfaces.nsICookieService);
407
408                 cookieSvc.setCookieString(cookieUriSSL, null, "ses="+G.data.session.key + "; secure;", null);
409
410             } catch(E) {
411                 alert(offlineStrings.getFormattedString(main.session_cookie.error, [E]));
412             }
413
414             xulG = {
415                 'auth' : G.auth,
416                 'url' : url,
417                 'window' : G.window,
418                 'data' : G.data,
419                 'pref' : G.pref
420             };
421
422             if (G.data.ws_info && G.data.ws_info[G.auth.controller.view.server_prompt.value]) {
423                 JSAN.use('util.widgets');
424                 var deck = document.getElementById('progress_space');
425                 util.widgets.remove_children( deck );
426                 var iframe = document.createElement('iframe'); deck.appendChild(iframe);
427                 iframe.setAttribute( 'src', urls.XUL_LOGIN_DATA );
428                 iframe.contentWindow.xulG = xulG;
429                 G.data_xul = iframe.contentWindow;
430             } else {
431                 xulG.file = G.file;
432                 var deck = G.auth.controller.view.ws_deck;
433                 JSAN.use('util.widgets'); util.widgets.remove_children('ws_deck');
434                 var iframe = document.createElement('iframe'); deck.appendChild(iframe);
435                 iframe.setAttribute( 'src', urls.XUL_WORKSTATION_INFO );
436                 iframe.contentWindow.xulG = xulG;
437                 deck.selectedIndex = deck.childNodes.length - 1;
438             }
439         };
440
441         G.auth.on_standalone = function() {
442             try {
443                 G.window.open(urls.XUL_STANDALONE,'Offline','chrome,resizable');
444             } catch(E) {
445                 alert(E);
446             }
447         };
448
449         G.auth.on_standalone_export = function() {
450             try {
451                 JSAN.use('util.file'); var file = new util.file('pending_xacts');
452                 if (file._file.exists()) {
453                     var file2 = new util.file('');
454                     var f = file2.pick_file( { 'mode' : 'save', 'title' : offlineStrings.getString('main.transaction_export.title') } );
455                     if (f) {
456                         if (f.exists()) {
457                             var r = G.error.yns_alert(
458                                 offlineStrings.getFormattedString('main.transaction_export.prompt', [f.leafName]),
459                                 offlineStrings.getString('main.transaction_export.prompt.title'),
460                                 offlineStrings.getString('common.yes'),
461                                 offlineStrings.getString('common.no'),
462                                 null,
463                                 offlineStrings.getString('common.confirm')
464                             );
465                             if (r != 0) { file.close(); return; }
466                         }
467                         var e_file = new util.file(''); e_file._file = f;
468                         e_file.write_content( 'truncate', file.get_content() );
469                         e_file.close();
470                         var r = G.error.yns_alert(
471                             offlineStrings.getFormattedString('main.transaction_export.success.prompt', [f.leafName]),
472                             offlineStrings.getString('main.transaction_export.success.title'),
473                             offlineStrings.getString('common.yes'),
474                             offlineStrings.getString('common.no'),
475                             null,
476                             offlineStrings.getString('common.confirm')
477                         );
478                         if (r == 0) {
479                             var count = 0;
480                             var filename = 'pending_xacts_exported_' + new Date().getTime();
481                             var t_file = new util.file(filename);
482                             while (t_file._file.exists()) {
483                                 filename = 'pending_xacts_' + new Date().getTime() + '.exported';
484                                 t_file = new util.file(filename);
485                                 if (count++ > 100) {
486                                     throw(offlineStrings.getString('main.transaction_export.filename.error'));
487                                 }
488                             }
489                             file.close(); file = new util.file('pending_xacts'); // prevents a bug with .moveTo below
490                             file._file.moveTo(null,filename);
491                         } else {
492                             alert(offlineStrings.getString('main.transaction_export.duplicate.warning'));
493                         }
494                     } else {
495                         alert(offlineStrings.getString('main.transaction_export.no_filename.error'));
496                     }
497                 } else {
498                     alert(offlineStrings.getString('main.transaction_export.no_transactions.error'));
499                 }
500                 file.close();
501             } catch(E) {
502                 alert(E);
503             }
504         };
505
506         G.auth.on_standalone_import = function() {
507             try {
508                 JSAN.use('util.file'); var file = new util.file('pending_xacts');
509                 if (file._file.exists()) {
510                     alert(offlineStrings.getString('main.transaction_import.outstanding.error'));
511                 } else {
512                     var file2 = new util.file('');
513                     var f = file2.pick_file( { 'mode' : 'open', 'title' : offlineStrings.getString('main.transaction_import.title')} );
514                     if (f && f.exists()) {
515                         var i_file = new util.file(''); i_file._file = f;
516                         file.write_content( 'truncate', i_file.get_content() );
517                         i_file.close();
518                         var r = G.error.yns_alert(
519                             offlineStrings.getFormattedString('main.transaction_import.delete.prompt', [f.leafName]),
520                             offlineStrings.getString('main.transaction_import.success'),
521                             offlineStrings.getString('common.yes'),
522                             offlineStrings.getString('common.no'),
523                             null,
524                             offlineStrings.getString('common.confirm')
525                         );
526                         if (r == 0) {
527                             f.remove(false);
528                         }
529                     }
530                 }
531                 file.close();
532             } catch(E) {
533                 alert(E);
534             }
535         };
536
537         G.auth.on_debug = function(action) {
538             switch(action) {
539                 case 'js_console' :
540                     G.window.open(urls.XUL_DEBUG_CONSOLE,'testconsole','chrome,resizable');
541                 break;
542                 case 'clear_cache' :
543                     clear_the_cache();
544                     alert(offlineStrings.getString('main.on_debug.clear_cache'));
545                 break;
546                 default:
547                     alert(offlineStrings.getString('main.on_debug.debug'));
548                 break;
549             }
550         };
551
552         G.auth.init();
553         // XML_HTTP_SERVER will get reset to G.auth.controller.view.server_prompt.value
554
555         /////////////////////////////////////////////////////////////////////////////
556
557         var version = CLIENT_VERSION;
558         if (CLIENT_STAMP.length == 0) {
559             version = 'versionless debug build';
560             document.getElementById('debug_gb').hidden = false;
561         }
562
563         try {
564             if (G.pref && G.pref.getBoolPref('open-ils.debug_options')) {
565                 document.getElementById('debug_gb').hidden = false;
566             }
567         } catch(E) {
568         }
569
570         // If we are showing the debugging frame then we consider this a debug build
571         // This could be a versionless build, a developer-pref enabled build, or otherwise
572         // If set this will enable all debugging commands, even if you normally don't have permission to use them
573         G.data.debug_build = !document.getElementById('debug_gb').hidden;
574         G.data.stash('debug_build');
575
576         var appInfo = Components.classes["@mozilla.org/xre/app-info;1"] 
577             .getService(Components.interfaces.nsIXULAppInfo); 
578
579         if (appInfo.ID == "staff-client@open-ils.org")
580         {
581             try {
582                 if (G.pref && G.pref.getBoolPref('app.update.enabled')) {
583                     document.getElementById('check_upgrade_sep').hidden = false;
584                     var upgrademenu = document.getElementById('check_upgrade');
585                     upgrademenu.hidden = false;
586                     G.upgradeCheck = function () {
587                         var um = Components.classes["@mozilla.org/updates/update-manager;1"]
588                             .getService(Components.interfaces.nsIUpdateManager);
589                         var prompter = Components.classes["@mozilla.org/updates/update-prompt;1"]
590                             .createInstance(Components.interfaces.nsIUpdatePrompt);
591
592                         if (um.activeUpdate && um.activeUpdate.state == "pending")
593                             prompter.showUpdateDownloaded(um.activeUpdate);
594                         else
595                             prompter.checkForUpdates();
596                     }
597                     upgrademenu.addEventListener(
598                         'command',
599                         G.upgradeCheck,
600                         false
601                     );
602                 }
603             } catch(E) {
604             }
605         }
606
607         window.document.title = authStrings.getFormattedString('staff.auth.titlebar.label', CLIENT_VERSION);
608         var x = document.getElementById('about_btn');
609         x.addEventListener(
610             'command',
611             function() {
612                 try { 
613                     G.window.open('about.html','about','chrome,resizable,width=800,height=600');
614                 } catch(E) { alert(E); }
615             }, 
616             false
617         );
618
619         var y = document.getElementById('new_window_btn');
620         y.addEventListener(
621             'command',
622             function() {
623                 if (G.data.session) {
624                     new_tabs(Array('new'), null, null);
625                 } else {
626                     alert ( offlineStrings.getString('main.new_window_btn.login_first_warning') );
627                 }
628             },
629             false
630         );
631
632         JSAN.use('util.mozilla');
633         var z = document.getElementById('locale_menupopup');
634         if (z) {
635             while (z.lastChild) z.removeChild(z.lastChild);
636             var locales = util.mozilla.chromeRegistry().getLocalesForPackage( String( location.href ).split(/\//)[2] );
637             var current_locale = util.mozilla.prefs().getCharPref('general.useragent.locale');
638             while (locales.hasMore()) {
639                 var locale = locales.getNext();
640                 var parts = locale.split(/-/);
641                 var label;
642                 try {
643                     label = locale + ' : ' + util.mozilla.languages().GetStringFromName(parts[0]);
644                     if (parts.length > 1) {
645                         try {
646                             label += ' (' + util.mozilla.regions().GetStringFromName(parts[1].toLowerCase()) + ')';
647                         } catch(E) {
648                             label += ' (' + parts[1] + ')';
649                         }
650                     }
651                 } catch(E) {
652                     label = locale;
653                 }
654                 var mi = document.createElement('menuitem');
655                 mi.setAttribute('label',label);
656                 mi.setAttribute('value',locale);
657                 if (locale == current_locale) {
658                     if (z.parentNode.tagName == 'menulist') {
659                         mi.setAttribute('selected','true');
660                         z.parentNode.setAttribute('label',label);
661                         z.parentNode.setAttribute('value',locale);
662                     }
663                 }
664                 z.appendChild( mi );
665             }
666         }
667         var xx = document.getElementById('apply_locale_btn');
668         xx.addEventListener(
669             'command',
670             function() {
671                 util.mozilla.change_locale(z.parentNode.value);
672             },
673             false
674         );
675
676         if ( found_ws_info_in_Achrome() && G.pref && G.pref.getBoolPref("open-ils.write_in_user_chrome_directory") ) {
677             //var hbox = x.parentNode; var b = document.createElement('button'); 
678             //b.setAttribute('label','Migrate legacy settings'); hbox.appendChild(b);
679             //b.addEventListener(
680             //    'command',
681             //    function() {
682             //        try {
683             //            handle_migration();
684             //        } catch(E) { alert(E); }
685             //    },
686             //    false
687             //);
688             if (window.confirm(offlineStrings.getString('main.settings.migrate'))) {
689                 setTimeout( function() { handle_migration(); }, 0 );
690             }
691         }
692
693         window.addEventListener(
694             'close',
695             function(ev) {
696
697                 G.data.stash_retrieve();
698                 if (typeof G.data.unsaved_data != 'undefined') {
699                     if (G.data.unsaved_data > 0) {
700                         var confirmation = window.confirm(offlineStrings.getString('menu.shutdown.unsaved_data_warning'));
701                         if (!confirmation) {
702                             ev.preventDefault();
703                             return false;
704                         }
705                     }
706                 }
707                 G.data.unsaved_data = 0;
708                 G.data.stash('unsaved_data');
709
710                 return true;
711
712             },
713             false
714         );
715
716         /**
717             @brief Stats for Offline Files / Transactions
718             @launchpad #797408
719         */
720         var px = new util.file('pending_xacts');
721         document.getElementById('offline_message').setAttribute('style','display:none;');
722         if (px._file.exists()) {
723             document.getElementById('offline_message').setAttribute('style','background-color:red;display:block;font-weight:bold;padding:2px;');
724             document.getElementById('offline_import_btn').disabled = true;
725         }
726
727         var should_test_server = true;
728         // Attempt auto-login, if provided
729         if("arguments" in window && window.arguments.length > 0 && window.arguments[0].wrappedJSObject != undefined && window.arguments[0].wrappedJSObject.loginInfo != undefined) {
730             should_test_server = auto_login(window.arguments[0].wrappedJSObject.loginInfo);
731             // Regardless of success, clear that variable now, so we don't possibly have passwords hanging around.
732             window.arguments[0].wrappedJSObject.loginInfo = null;
733         }
734
735         if (should_test_server) {
736             G.auth.test_server(G.auth.controller.view.server_prompt.value);
737             G.auth.controller.render('ws_deck');
738         }
739         setTimeout(load_init_hostname, 500);
740
741     } catch(E) {
742         var error = offlineStrings.getFormattedString('common.exception', [E, '']);
743         try { G.error.sdump('D_ERROR',error); } catch(E) { dump(error); }
744         alert(error);
745     }
746     dump('exiting main_init()\n');
747 }
748
749 function load_init_hostname() {
750     G.data.stash_retrieve();
751     if(!G.auth.controller.view.server_prompt.value) {
752         try {
753             G.auth.controller.view.server_prompt.value = G.pref.getCharPref('open-ils.initial_hostname');
754             G.auth.test_server(G.pref.getCharPref('open-ils.initial_hostname'));
755             G.auth.controller.render('ws_deck');
756         } catch(E) {
757         }
758     }
759 }
760
761 function found_ws_info_in_Achrome() {
762     JSAN.use('util.file');
763     var f = new util.file();
764     var f_in_chrome = f.get('ws_info','chrome');
765     var path = f_in_chrome.exists() ? f_in_chrome.path : false;
766     f.close();
767     return path;
768 }
769
770 function found_ws_info_in_Uchrome() {
771     JSAN.use('util.file');
772     var f = new util.file();
773     var f_in_uchrome = f.get('ws_info','uchrome');
774     var path = f_in_uchrome.exists() ? f_in_uchrome.path : false;
775     f.close();
776     return path;
777 }
778
779 function handle_migration() {
780     if ( found_ws_info_in_Uchrome() ) {
781         alert(offlineStrings.getFormattedString('main.settings.migrate.failed', [found_ws_info_in_Uchrome(), found_ws_info_in_Achrome()])
782         );
783     } else {
784         var dirService = Components.classes["@mozilla.org/file/directory_service;1"].getService( Components.interfaces.nsIProperties );
785         var f_new = dirService.get( "UChrm", Components.interfaces.nsIFile );
786         var f_old = dirService.get( "AChrom", Components.interfaces.nsIFile );
787         f_old.append(myPackageDir); f_old.append("content"); f_old.append("conf"); 
788         if (window.confirm(offlineStrings.getFormattedString("main.settings.migrate.confirm", [f_old.path, f_new.path]))) {
789             var files = f_old.directoryEntries;
790             while (files.hasMoreElements()) {
791                 var file = files.getNext();
792                 var file2 = file.QueryInterface( Components.interfaces.nsILocalFile );
793                 try {
794                     file2.moveTo( f_new, '' );
795                 } catch(E) {
796                     alert(offlineStrings.getFormattedString('main.settings.migrate.error', [file2.path, f_new.path]) + '\n');
797                 }
798             }
799             location.href = location.href; // huh?
800         }
801     }
802 }
803
804 function auto_login(loginInfo) {
805     G.data.stash_retrieve();
806     var should_test_server = true;
807     if(G.data.session) return; // We are logged in. No auto-logoff supported.
808     if(loginInfo.host) {
809         G.auth.controller.view.server_prompt.value = loginInfo.host;
810         G.auth.test_server(loginInfo.host);
811         G.auth.controller.render('ws_deck');
812         should_test_server = false;
813     }
814     if(loginInfo.user) G.auth.controller.view.name_prompt.value = loginInfo.user;
815     if(loginInfo.passwd) G.auth.controller.view.password_prompt.value = loginInfo.passwd;
816     if(loginInfo.host && loginInfo.user && loginInfo.passwd && G.data.ws_info && G.data.ws_info[loginInfo.host]) {
817         // Give test_server time to finish
818         setTimeout(function() { G.auth.login(); }, 1000);
819     }
820     return should_test_server;
821 }
822
823 dump('exiting main/main.js\n');