12 new, 4 updated for 1.3.5
[webos-internals:modifications.git] / universal-search / universal-search-command-line.patch
1 Index: /usr/lib/luna/system/luna-applauncher/app/controllers/calculator.js
2 ===================================================================
3 --- .orig/usr/lib/luna/system/luna-applauncher/app/controllers/calculator.js
4 +++ /usr/lib/luna/system/luna-applauncher/app/controllers/calculator.js
5 @@ -0,0 +1,50 @@
6 +/*jslint browser: true, eqeqeq: true, undef: true */
7 +/******************************************************************************
8 +Lines above are for jslint, the JavaScript verifier.
9 +http://www.jslint.com/
10 +******************************************************************************/
11 +
12 +var Calculator = function () {
13 +       var abs         = Math.abs;
14 +       var max         = Math.max;
15 +       var min         = Math.min;
16 +       var random      = Math.random;
17 +       var ceil        = Math.ceil;
18 +       var round       = Math.round;
19 +       var floor       = Math.floor;
20 +       var E           = Math.E;
21 +       var LN10        = Math.LN10;
22 +       var LN2         = Math.LN2;
23 +       var LOG10E      = Math.LOG10E;
24 +       var LOG2E       = Math.LOG2E;
25 +       var PI          = Math.PI;
26 +       var SQRT1_2     = Math.SQRT1_2;
27 +       var SQRT2       = Math.SQRT2;
28 +       var acos        = Math.acos;
29 +       var asin        = Math.asin;
30 +       var atan        = Math.atan;
31 +       var atan2       = Math.atan2;
32 +       var cos         = Math.cos;
33 +       var exp         = Math.exp;
34 +       var log         = Math.log;
35 +       var pow         = Math.pow;
36 +       var sin         = Math.sin;
37 +       var sqrt        = Math.sqrt;
38 +       var tan         = Math.tan;
39 +       var cot         = function (x) { return 1 / tan(x); }; // cotangent
40 +       var sec         = function (x) { return 1 / cos(x); }; // secant
41 +       var csc         = function (x) { return 1 / sin(x); }; // cosecant
42 +       var log2        = function (x) { return log(x) / LN2; };
43 +       var log10       = function (x) { return log(x) / LN10; };
44 +
45 +       // I really wish we could provide a true global context
46 +       // independent from Mojo or whatever environment we happen
47 +       // to be in.
48 +       var a, b, c, d, e, f, g, h, i, j, k, l, m;
49 +       var n, o, p, q, r, s, t, u, v, w, x, y, z;
50 +       
51 +       this.calculate = function (string) {
52 +               return eval(string);
53 +       };
54 +};
55 +
56 Index: /usr/lib/luna/system/luna-applauncher/app/controllers/global-search-assistant.js
57 ===================================================================
58 --- .orig/usr/lib/luna/system/luna-applauncher/app/controllers/global-search-assistant.js
59 +++ /usr/lib/luna/system/luna-applauncher/app/controllers/global-search-assistant.js
60 @@ -125,6 +125,7 @@
61                 searchesDiv.update(Mojo.View.render({template: 'global-search/expanded-searches-div' }));
62                 this.expandedSearchDrawer = { showExpanded: false };
63                 this.controller.setupWidget('expanded_searches_drawer', {unstyled:true, property:'showExpanded'}, this.expandedSearchDrawer);
64 +
65                 this.webDrawer = { showWeb: false };
66                 this.controller.setupWidget('web_drawer', {unstyled:true, property:'showWeb'}, this.webDrawer);
67                 
68 @@ -160,9 +161,47 @@
69                 
70                 this.controller.listen(this.controller.document, 'paste', this.onPaste.bindAsEventListener(this), true);
71                 
72 +               this.uscl = new USCL();
73 +               
74 +               var searchesDivUSCL = this.controller.get('searches-list-uscl');
75 +               searchesDivUSCL.update(Mojo.View.render({template: 'global-search/expanded-searches-div-uscl' }));
76 +               this.expandedSearchDrawerUSCL = { showExpanded: false };
77 +               this.controller.setupWidget('expanded_searches_drawer_uscl',
78 +                                           { unstyled:true, property:'showExpanded', 
79 +                                             scrollDisabled: true},
80 +                                           this.expandedSearchDrawerUSCL);
81 +
82 +               this.usclDrawer = { showUSCL: false };
83 +               this.controller.setupWidget('command_line_drawer', {unstyled: true, property: 'showUSCL'}, this.usclDrawer);
84 +
85 +               this.usclSearchesAttrs = {
86 +                       listTemplate: "global-search/templates/uscl-searches-list",
87 +                       itemTemplate: "global-search/templates/uscl-searches-item",
88 +                       swipeToDelete: false,
89 +                       reorderable: false,
90 +                       renderLimit: 500
91 +               };
92 +               this.usclSearchesModel = { 
93 +                       items: this.uscl.universalSearchList 
94 +               };
95 +               this.controller.setupWidget("usclSearches",
96 +                                           this.usclSearchesAttrs,
97 +                                           this.usclSearchesModel);
98 +
99 +               this.onTapUSCLHandler = this.onTapUSCL.bindAsEventListener(this);
100 +               this.controller.listen("usclSearches",
101 +                                      Mojo.Event.listTap,
102 +                                      this.onTapUSCLHandler);
103 +               
104                 this.initOnServerStart("com.palm.systemservice");
105         },
106    
107 +       onTapUSCL: function (event) {
108 +               var entry = this.usclSearchesModel.items[event.index];
109 +               this.runUSCL({ entry: entry,
110 +                                     arg: this.currentFilter });
111 +       },
112 +  
113         ready: function() {
114                 // try to force our input field to always have focus (there are some exceptions)
115                 var input = this.searchField.querySelector('[name=searchtermInput]');
116 @@ -170,6 +209,21 @@
117                         input.blur = function() { this.focus(); }
118                 }
119                 this.enable(true);
120 +               this.monkeyPatch1();
121 +       },
122 +
123 +       /* allows one to disable the scrollIntoView behavior of Mojo.Widget.Drawer. */
124 +       /* WARNING: THIS MONKEY-PATCHES A PRIVATE API */
125 +       monkeyPatch1: function () {
126 +               if (this.monkeyPatched) { return; }
127 +               var monkey = Mojo.Widget.Drawer.prototype.scrollIntoView;
128 +               if (!monkey) { return; }
129 +               Mojo.Widget.Drawer.prototype.scrollIntoView = function () {
130 +                       if (this.controller.attributes.scrollDisabled) {
131 +                               return;
132 +                       }
133 +                       monkey.apply(this, arguments);
134 +               };
135         },
136         
137         isEnabled: function() {
138 @@ -1353,6 +1407,80 @@
139                 ApplicationService.launch('com.palm.app.browser', params);              
140         },      
141         
142 +       deactivateWithError: function (message) {
143 +               this.controller.showAlertDialog({
144 +                       onChoose: (function () { this.deactivate(); }).bind(this),
145 +                       title: "Error",
146 +                       message: message,
147 +                       choices: [ { label: "OK", value: "ok" } ]
148 +               });
149 +       },
150 +
151 +       deactivateWithWarning: function (message) {
152 +               this.controller.showAlertDialog({
153 +                       onChoose: (function () { this.deactivate(); }).bind(this),
154 +                       title: "Warning",
155 +                       message: message,
156 +                       choices: [ { label: "OK", value: "ok" } ]
157 +               });
158 +       },
159 +
160 +       runUSCL: function (o) {
161 +               if (!this.uscl) {
162 +                       this.deactivate();
163 +               }
164 +               var result;
165 +               try {
166 +                       if (o instanceof Object) {
167 +                               result = this.uscl.run(o.entry, o.arg);
168 +                       }
169 +                       else {
170 +                               result = this.uscl.runString(o);
171 +                       }
172 +               }
173 +               catch (e) {
174 +                       if (e instanceof USCLError) {
175 +                               this.deactivateWithError(e.message);
176 +                               /* remember, kids, don't deactivate right away! */
177 +                               return;
178 +                       }
179 +                       else {
180 +                               throw e;
181 +                       }
182 +               }
183 +               if (result === false) {
184 +                       /* don't deactivate; let something else do it */
185 +               }
186 +               else if (!result) {
187 +                       this.deactivate();
188 +               }
189 +               else if (result instanceof Function) {
190 +                       if (!result.noDeactivate) {
191 +                               this.deactivate();
192 +                       }
193 +                       result.apply(this);
194 +               }
195 +               else if (result instanceof Object) {
196 +                       this.controller.showAlertDialog({
197 +                               onChoose: (function () { this.deactivate(); }).bind(this),
198 +                               title: result.title,
199 +                               message: result.message,
200 +                               choices: [ { label: "OK", value: "ok" } ]
201 +                       });
202 +               }
203 +               else if (result.constructor && result.constructor === String) {
204 +                       this.controller.showAlertDialog({
205 +                               onChoose: (function () { this.deactivate(); }).bind(this),
206 +                               title: "Result",
207 +                               message: result,
208 +                               choices: [ { label: "OK", value: "ok" } ]
209 +                       });
210 +               }
211 +               else {
212 +                       this.deactivate();
213 +               }
214 +       },
215 +
216         toggleSearchListDivs: function() {
217                 if(!this.enterKeyActionItem){
218                         this.enterKeyActionItem = 'search'
219 @@ -1363,16 +1491,40 @@
220                                         $('webtext').innerHTML = this.currentFilter;
221                                         this.webDrawer.showWeb = true;
222                                         this.controller.modelChanged(this.webDrawer);
223 +                                       this.usclDrawer.showUSCL = false;
224 +                                       this.controller.modelChanged(this.usclDrawer);
225 +                               }
226 +                               else if (this.uscl.isCommandString(this.currentFilter)) {
227 +                                       $('uscl-text').innerHTML = this.currentFilter;
228 +                                       this.webDrawer.showWeb = false;
229 +                                       this.controller.modelChanged(this.webDrawer);
230 +                                       this.usclDrawer.showUSCL = true;
231 +                                       this.controller.modelChanged(this.usclDrawer);
232                                 }
233                                 else {
234                                         this.webDrawer.showWeb =  false ;
235                                         this.controller.modelChanged(this.webDrawer);
236 +                                       this.usclDrawer.showUSCL = false;
237 +                                       this.controller.modelChanged(this.usclDrawer);
238                                 }
239                                 $('find').removeClassName('single');
240                                 $('find').addClassName('first');
241                                 this.searchField.removeClassName('text-hidden');
242                                 this.expandedSearchDrawer.showExpanded = true;
243                                 this.controller.modelChanged(this.expandedSearchDrawer);
244 +
245 +                               if (this.uscl.show) {
246 +                                       this.usclSearchesModel.items = 
247 +                                               this.uscl.getUniversalSearchCommandList();
248 +                                       this.controller.modelChanged(this.usclSearchesModel);
249 +                                       this.controller.get('searchesDivUSCL').show();
250 +                                       this.expandedSearchDrawerUSCL.showExpanded = true;
251 +                               }
252 +                               else {
253 +                                       this.controller.get('searchesDivUSCL').hide();
254 +                                       this.expandedSearchDrawerUSCL.showExpanded = false;
255 +                               }
256 +                               this.controller.modelChanged(this.expandedSearchDrawerUSCL);
257                         } else {//find...
258                                 if (this.dialDiv.visible() || this.numberDiv.visible()) {
259                                         this.searchField.addClassName('text-hidden');
260 @@ -1382,6 +1534,11 @@
261                                 }
262                                 this.expandedSearchDrawer.showExpanded = false;
263                                 this.controller.modelChanged(this.expandedSearchDrawer);
264 +
265 +                               this.controller.get('searchesDivUSCL').hide();
266 +                               this.expandedSearchDrawerUSCL.showExpanded = false;
267 +                               this.controller.modelChanged(this.expandedSearchDrawerUSCL);
268 +
269                                 $('find').removeClassName('first');
270                                 $('find').addClassName('single');
271                         }
272 @@ -1396,16 +1553,39 @@
273                                         $('webtext').innerHTML = this.currentFilter;
274                                         this.webDrawer.showWeb = true;
275                                         this.controller.modelChanged(this.webDrawer);
276 +                                       this.usclDrawer.showUSCL = false;
277 +                                       this.controller.modelChanged(this.usclDrawer);
278 +                               }
279 +                               else if (this.uscl.isCommandString(this.currentFilter)) {
280 +                                       $('uscl-text').innerHTML = this.currentFilter;
281 +                                       this.webDrawer.showWeb = false;
282 +                                       this.controller.modelChanged(this.webDrawer);
283 +                                       this.usclDrawer.showUSCL = true;
284 +                                       this.controller.modelChanged(this.usclDrawer);
285                                 }
286                                 else {
287                                         this.webDrawer.showWeb = false;
288                                         this.controller.modelChanged(this.webDrawer);
289 +                                       this.usclDrawer.showUSCL = false;
290 +                                       this.controller.modelChanged(this.usclDrawer);
291                                 }
292                                 $('find').removeClassName('single');
293                                 $('find').addClassName('first');
294                                 this.searchField.removeClassName('text-hidden');
295                                 this.expandedSearchDrawer.showExpanded = true;
296                                 this.controller.modelChanged(this.expandedSearchDrawer);
297 +
298 +                               if (this.uscl.show) {
299 +                                       this.usclSearchesModel.items = this.uscl.getUniversalSearchCommandList();
300 +                                       this.controller.modelChanged(this.usclSearchesModel);
301 +                                       this.controller.get('searchesDivUSCL').show();
302 +                                       this.expandedSearchDrawerUSCL.showExpanded = true;
303 +                               }
304 +                               else {
305 +                                       this.controller.get('searchesDivUSCL').hide();
306 +                                       this.expandedSearchDrawerUSCL.showExpanded = false;
307 +                               }
308 +                               this.controller.modelChanged(this.expandedSearchDrawerUSCL);
309                         } else {//find...
310                                 if (this.dialDiv.visible() || this.numberDiv.visible()) {
311                                         this.searchField.addClassName('text-hidden');
312 @@ -1415,6 +1595,11 @@
313                                 }
314                                 this.expandedSearchDrawer.showExpanded = false;
315                                 this.controller.modelChanged(this.expandedSearchDrawer);
316 +
317 +                               this.controller.get('searchesDivUSCL').hide();
318 +                               this.expandedSearchDrawerUSCL.showExpanded = false;
319 +                               this.controller.modelChanged(this.expandedSearchDrawerUSCL);
320 +
321                                 $('find').removeClassName('first');
322                                 $('find').addClassName('single');
323                         }
324 @@ -1434,6 +1619,11 @@
325                                 this.searchExplicitlyExpanded = false;
326                                 this.expandedSearchDrawer.showExpanded = false;
327                                 this.controller.modelChanged(this.expandedSearchDrawer);
328 +
329 +                               this.controller.get('searchesDivUSCL').hide();
330 +                               this.expandedSearchDrawerUSCL.showExpanded = false;
331 +                               this.controller.modelChanged(this.expandedSearchDrawerUSCL);
332 +
333                                 $('find').removeClassName('first');
334                                 $('find').addClassName('single');
335                                 if (this.dialDiv.visible() || this.numberDiv.visible()) {
336 @@ -1449,21 +1639,46 @@
337                                         $('webtext').innerHTML = this.currentFilter;
338                                         this.webDrawer.showWeb = true;
339                                         this.controller.modelChanged(this.webDrawer);
340 +                                       this.usclDrawer.showUSCL = false;
341 +                                       this.controller.modelChanged(this.usclDrawer);
342 +                               }
343 +                               else if (this.uscl.isCommandString(this.currentFilter)) {
344 +                                       $('uscl-text').innerHTML = this.currentFilter;
345 +                                       this.webDrawer.showWeb = false;
346 +                                       this.controller.modelChanged(this.webDrawer);
347 +                                       this.usclDrawer.showUSCL = true;
348 +                                       this.controller.modelChanged(this.usclDrawer);
349                                 }
350                                 else {
351                                         this.webDrawer.showWeb = false;
352                                         this.controller.modelChanged(this.webDrawer);
353 +                                       this.usclDrawer.showUSCL = false;
354 +                                       this.controller.modelChanged(this.usclDrawer);
355                                 }
356                                 $('find').removeClassName('single');
357                                 $('find').addClassName('first');
358                                 this.searchField.removeClassName('text-hidden');
359                                 this.expandedSearchDrawer.showExpanded = true;
360                                 this.controller.modelChanged(this.expandedSearchDrawer);
361 +
362 +                               if (this.uscl.show) {
363 +                                       this.usclSearchesModel.items = this.uscl.getUniversalSearchCommandList();
364 +                                       this.controller.modelChanged(this.usclSearchesModel);
365 +                                       this.controller.get('searchesDivUSCL').show();
366 +                                       this.expandedSearchDrawerUSCL.showExpanded = true;
367 +                               }
368 +                               else {
369 +                                       this.controller.get('searchesDivUSCL').hide();
370 +                                       this.expandedSearchDrawerUSCL.showExpanded = false;
371 +                               }
372 +                               this.controller.modelChanged(this.expandedSearchDrawerUSCL);
373                         }
374                 } else {
375                         var url = target.id;
376                         if (url == "web")
377                                 this.launchBrowser(this.currentFilter);
378 +                       else if (url == "uscl")
379 +                               this.runUSCL(this.currentFilter);
380                 }
381         },
382         
383 @@ -1716,6 +1931,13 @@
384                 this.gpsInfo = undefined;
385                 if(this.highlightTarget != null)
386                         this.highlightTarget.removeClassName('selected');
387 +
388 +               this.usclDrawer.showUSCL =  false ;
389 +               this.controller.modelChanged(this.usclDrawer);
390 +               this.controller.get('searchesDivUSCL').hide();
391 +               this.expandedSearchDrawerUSCL.showExpanded = false;
392 +               this.controller.modelChanged(this.expandedSearchDrawerUSCL);
393 +               $('uscl').removeClassName('selected');
394         },
395         
396    webSiteString: function(s){
397 @@ -1815,6 +2037,7 @@
398         //clear search':
399         $(this.defaultSearchEngine).removeClassName('palm-focus');
400         $('web').removeClassName('palm-focus');
401 +       $('uscl').removeClassName('palm-focus');
402    },
403    highlightSelection: function() {
404         
405 @@ -1888,6 +2111,24 @@
406                 $(this.defaultSearchEngine).removeClassName('palm-focus');
407                 $('web').removeClassName('palm-focus');
408         }
409 +
410 +       if (this.enterKeyActionItem === "search") {
411 +               if (this.webDrawer.showWeb == true) {
412 +                       $('uscl').removeClassName('palm-focus');
413 +               }
414 +               else if (this.usclDrawer.showUSCL == true) {
415 +                       $(this.defaultSearchEngine).removeClassName('palm-focus');
416 +                       $('web').removeClassName('palm-focus');
417 +                       this.highlightTarget = $('uscl');
418 +                       $('uscl').addClassName('palm-focus');
419 +               }
420 +               else if (this.expandedSearchDrawer.showExpanded == true) {
421 +                       $('uscl').removeClassName('palm-focus');
422 +               }
423 +       }
424 +       else {
425 +               $('uscl').removeClassName('palm-focus');
426 +       }
427    },
428    
429    enterKeyAction: function(){
430 @@ -1976,6 +2217,8 @@
431                         }
432                         if (this.webDrawer.showWeb == true)
433                                 this.launchBrowser(this.currentFilter);
434 +                       else if (this.usclDrawer.showUSCL == true)
435 +                               this.runUSCL(this.currentFilter);
436                         else {
437                                 this.launchBrowser(this.URLs[this.defaultSearchEngine] + encodeURIComponent(this.currentFilter));
438                         }
439 Index: /usr/lib/luna/system/luna-applauncher/app/controllers/uscl-help-command-list.js
440 ===================================================================
441 --- .orig/usr/lib/luna/system/luna-applauncher/app/controllers/uscl-help-command-list.js
442 +++ /usr/lib/luna/system/luna-applauncher/app/controllers/uscl-help-command-list.js
443 @@ -0,0 +1,41 @@
444 +/*jslint browser: true, eqeqeq: true, undef: true */
445 +/*global Mojo */
446 +/******************************************************************************
447 +Lines above are for jslint, the JavaScript verifier.
448 +http://www.jslint.com/
449 +******************************************************************************/
450 +
451 +function UsclHelpCommandListAssistant (uscl) {
452 +       this.uscl = uscl;
453 +}
454 +
455 +UsclHelpCommandListAssistant.prototype.setup = function () {
456 +       this.stageController = this.controller.stageController;
457 +       this.items = this.uscl.getHelpCommandList();
458 +       this.controller.setupWidget("command-list", {
459 +               listTemplate: "uscl-help-command-list/templates/list",
460 +               itemTemplate: "uscl-help-command-list/templates/item",
461 +               swipeToDelete: false,
462 +               reorderable: false,
463 +               renderLimit: this.items.length
464 +       }, this.itemsModel = {
465 +               items: this.items
466 +       });
467 +       this.showCommandHandler = this.showCommand.bindAsEventListener(this);
468 +       this.controller.listen("command-list", Mojo.Event.listTap,
469 +                              this.showCommandHandler);
470 +
471 +       var body = this.stageController.document.getElementsByTagName("body");
472 +       body[0].addClassName("uscl-body");
473 +};
474 +
475 +UsclHelpCommandListAssistant.prototype.showCommand = function (event) {
476 +       this.stageController.pushScene("uscl-help-command-view",
477 +                                      this.items, event.index);
478 +};
479 +
480 +UsclHelpCommandListAssistant.prototype.cleanup = function () {
481 +       this.controller.stopListening("command-list", Mojo.Event.listTap,
482 +                                     this.showCommandHandler);
483 +};
484 +
485 Index: /usr/lib/luna/system/luna-applauncher/app/controllers/uscl-help-command-view.js
486 ===================================================================
487 --- .orig/usr/lib/luna/system/luna-applauncher/app/controllers/uscl-help-command-view.js
488 +++ /usr/lib/luna/system/luna-applauncher/app/controllers/uscl-help-command-view.js
489 @@ -0,0 +1,70 @@
490 +/*jslint browser: true, eqeqeq: true, undef: true */
491 +/*global Mojo */
492 +/******************************************************************************
493 +Lines above are for jslint, the JavaScript verifier.
494 +http://www.jslint.com/
495 +******************************************************************************/
496 +
497 +function UsclHelpCommandViewAssistant (items, index) {
498 +       this.items = items;
499 +       this.item = this.items[index];
500 +}
501 +
502 +UsclHelpCommandViewAssistant.prototype.setup = function () {
503 +       this.stageController = this.controller.stageController;
504 +       this.controller.get("title").innerHTML =
505 +               this.item.title;
506 +       this.controller.get("description").innerHTML =
507 +               this.item.description;
508 +
509 +       if (this.item.aka && this.item.aka.length) {
510 +               this.controller.get("aka").innerHTML =
511 +                       this.item.aka.map(function (s) {
512 +                               return "<kbd class='alias'>." + s + "</kbd>";
513 +                       }).joinAnd();
514 +       }
515 +       else {
516 +               this.controller.get("akaDiv").hide();
517 +       }
518 +
519 +       if ("usage" in this.item) {
520 +               if (typeof(this.item.usage) === "object" &&
521 +                   this.item.usage.constructor === Array) {
522 +                       this.controller.get("usage").innerHTML =
523 +                               "<br />" +
524 +                               this.item.usage.join("<br />");
525 +               }
526 +               else {
527 +                       this.controller.get("usage").innerHTML =
528 +                               "." + this.item.commandName + " " +
529 +                               this.item.usage;
530 +               }
531 +       }
532 +       else {
533 +               this.controller.get("usage").innerHTML = 
534 +                       "." + this.item.commandName;
535 +       }
536 +
537 +       if ("example" in this.item) {
538 +               if (typeof(this.item.example) === "object" &&
539 +                   this.item.example.constructor === Array) {
540 +                       this.controller.get("example-title").innerHTML =
541 +                               "Examples";
542 +                       this.controller.get("example").innerHTML =
543 +                               "<br />" +
544 +                               this.item.example.join("<br />");
545 +               }
546 +               else {
547 +                       this.controller.get("example").innerHTML =
548 +                               "." + this.item.commandName + " " +
549 +                               this.item.example;
550 +               }
551 +       }
552 +       else {
553 +               this.controller.get("exampleDiv").hide();
554 +       }
555 +
556 +       var body = this.stageController.document.getElementsByTagName("body");
557 +       body[0].addClassName("uscl-body");
558 +};
559 +
560 Index: /usr/lib/luna/system/luna-applauncher/app/controllers/uscl.js
561 ===================================================================
562 --- .orig/usr/lib/luna/system/luna-applauncher/app/controllers/uscl.js
563 +++ /usr/lib/luna/system/luna-applauncher/app/controllers/uscl.js
564 @@ -0,0 +1,1374 @@
565 +/*jslint browser: true, eqeqeq: true, undef: true, evil: true */
566 +/*global Mojo, Class, Ajax, Calculator, $H, PalmSystem */
567 +/******************************************************************************
568 +Lines above are for jslint, the JavaScript verifier.
569 +http://www.jslint.com/
570 +******************************************************************************/
571 +
572 +//-----------------------------------------------------------------------------
573 +// Additional String Methods
574 +//-----------------------------------------------------------------------------
575 +
576 +if (!String.prototype.trim) {
577 +       String.prototype.trim = function () {
578 +               return this.replace(/^\s+/, "").replace(/\s+$/, "");
579 +       };
580 +}
581 +if (!String.prototype.normalizeSpace) {
582 +       String.prototype.normalizeSpace = function () {
583 +               return this.trim().replace(/\s+/g, " ");
584 +       };
585 +}
586 +if (!String.prototype.toBoolean) {
587 +       String.prototype.toBoolean = function () {
588 +               var s = this.toLowerCase().normalizeSpace();
589 +               var i = parseInt(s, 10);
590 +               if (!isNaN(i)) {
591 +                       return (i !== 0);
592 +               }
593 +               switch (s) {
594 +               case "yes":
595 +               case "y":
596 +               case "true":
597 +               case "t":
598 +               case "on":
599 +               case "enable":
600 +               case "enabled":
601 +                       return true;
602 +               case "no":
603 +               case "n":
604 +               case "false":
605 +               case "f":
606 +               case "off":
607 +               case "disable":
608 +               case "disabled":
609 +                       return false;
610 +               default:
611 +                       return undefined;
612 +               }
613 +       };
614 +}
615 +if (!String.prototype.format) {
616 +       /* Implements Mojo.Log.xxx-ish formatting. */
617 +       String.prototype.format = function () {
618 +               var args = Array.prototype.slice.call(arguments, 0);
619 +               var result = this.replace(/%[%jsoidf]/g, function (str) {
620 +                       switch (str) {
621 +                       case "%o":
622 +                               return Object.inspect(args.shift());
623 +                       case "%j":
624 +                               return Object.toJSON(args.shift());
625 +                       case "%%":
626 +                               return "%";
627 +                       }
628 +                       return args.shift();
629 +               });
630 +               return result;
631 +       };
632 +}
633 +if (!Array.prototype.forEach2) {
634 +       // A version of Array#forEach that stops the loop if the
635 +       // specified function returns false.  This special behavior is
636 +       // influenced by jQuery's each() methods.  Based on MIT-licensed
637 +       // code from: http://tinyurl.com/yh9nvwb
638 +       // (https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array/ForEach)
639 +       Array.prototype.forEach2 = function(fun /*, thisp*/) {
640 +               var len = this.length >>> 0;
641 +               if (typeof fun !== "function") {
642 +                       throw new TypeError();
643 +               }
644 +               var thisp = arguments[1];
645 +               for (var i = 0; i < len; i++) {
646 +                       if (i in this) {
647 +                               var ret = fun.call(thisp, this[i], i, this);
648 +                               if (ret === false) {
649 +                                       return;
650 +                               }
651 +                       }
652 +               }
653 +       };              
654 +}
655 +if (!Array.prototype.joinAnd) {
656 +       Array.prototype.joinAnd = function () {
657 +               if (this.length <= 2) {
658 +                       return this.join(" and ");
659 +               }
660 +               else {
661 +                       return this.slice(0, this.length - 1).join(", ") +
662 +                               ", and " + this[this.length - 1];
663 +               }
664 +       };
665 +}
666 +
667 +//-----------------------------------------------------------------------------
668 +// A special exception class for errors.
669 +//-----------------------------------------------------------------------------
670 +
671 +var USCLError = function (message) {
672 +       Error.apply(this, arguments);
673 +       this.message = message; // ugh, why on Earth do I have to do this?
674 +};
675 +USCLError.prototype = new Error();
676 +USCLError.prototype.constructor = USCLError;
677 +USCLError.prototype.name = "USCLError";
678 +
679 +//*****************************************************************************
680 +// The good stuff lies here.
681 +//*****************************************************************************
682 +
683 +var USCL = Class.create({
684 +
685 +       //---------------------------------------------------------------------
686 +       // Initialization
687 +       //---------------------------------------------------------------------
688 +
689 +       initialize: function () {
690 +               this.inEmulator = /desktop/.test(PalmSystem.version);
691 +               this.initBuiltinFlags();
692 +               this.build();
693 +               this.show = false;
694 +               this.loadPreferences();
695 +               this.hiddenFlags = {};
696 +               this.updateFromLocalFile();
697 +       },
698 +
699 +       loadPreferences: function () {
700 +               this.db = new Mojo.Depot({ name: "uscl", replace: false },
701 +                                        this.onLoadDatabase.bind(this),
702 +                                        function () { /* don't care */ });
703 +       },
704 +       
705 +       onLoadDatabase: function () {
706 +               var that = this;
707 +               this.db.get("show", 
708 +                           function (o) { that.show = o; },
709 +                           function () { that.show = false; });
710 +               this.db.get("hiddenFlags", 
711 +                           function (o) { that.hiddenFlags = o || {}; },
712 +                           function () { that.hiddenFlags = {}; });
713 +       },
714 +
715 +       setShow: function (flag) {
716 +               this.show = flag;
717 +               this.db.add("show", this.show, 
718 +                           function () { /* don't care */ },
719 +                           function () { /* don't care */ });
720 +       },
721 +
722 +       saveHiddenFlags: function () {
723 +               this.db.add("hiddenFlags", this.hiddenFlags,
724 +                           function () { /* don't care */ },
725 +                           function () { /* don't care */ });
726 +       },
727 +       
728 +       build: function () {
729 +               this.fixTitles();
730 +               this.buildSupportingAppList();
731 +       },
732 +
733 +       fixTitles: function () {
734 +               var commandName;
735 +               var entry;
736 +               for (commandName in this.entries) {
737 +                       if (this.entries.hasOwnProperty(commandName)) {
738 +                               entry = this.entries[commandName];
739 +                               if (typeof(entry) === "object") {
740 +                                       if (!("title" in entry)) {
741 +                                               entry.title = commandName;
742 +                                       }
743 +                                       entry.titleSort = entry.title.toLowerCase();
744 +                               }
745 +                       }
746 +               }
747 +       },
748 +
749 +       buildSupportingAppList: function () {
750 +               this.apps = {};
751 +               this.appListRequest = 
752 +                       new Mojo.Service.Request("palm://com.palm.applicationManager", {
753 +                               method: 'searchApps',
754 +                               parameters: {'keyword': 'iGrokTheCommandLine'},
755 +                               onSuccess: this.handleSupportingAppResults.bind(this, "iGrokTheCommandLine"),
756 +                               onFailure: this.handleSupportingAppResults.bind(this, "iGrokTheCommandLine")
757 +                       });
758 +               this.appListRequest2 = 
759 +                       new Mojo.Service.Request("palm://com.palm.applicationManager", {
760 +                               method: 'searchApps',
761 +                               parameters: {'keyword': 'iCanBeRefreshed'},
762 +                               onSuccess: this.handleSupportingAppResults.bind(this, "iCanBeRefreshed"),
763 +                               onFailure: this.handleSupportingAppResults.bind(this, "iCanBeRefreshed")
764 +                       });
765 +       },
766 +
767 +       handleSupportingAppResults: function (keyword, response) {
768 +               var that = this;
769 +               var apps = response.apps;
770 +               if (!apps) {
771 +                       return;
772 +               }
773 +               this.apps[keyword] = {};
774 +               apps.forEach(function (app) {
775 +                       var launchPoint = app.launchPoint;
776 +                       that.apps[keyword][launchPoint] = true;
777 +               });
778 +       },
779 +
780 +       //---------------------------------------------------------------------
781 +       // hidden flags
782 +       //---------------------------------------------------------------------
783 +
784 +       clearAllHiddenFlags: function () {
785 +               this.hiddenFlags = {};
786 +               this.saveHiddenFlags();
787 +       },
788 +       
789 +       setHiddenFlags: function (a) {
790 +               var that = this;
791 +               a.forEach(function (command) {
792 +                       command = command.replace(/^\./, "");
793 +                       command = that.unalias(command.toLowerCase());
794 +                       if (command) {
795 +                               that.hiddenFlags[command] = true;
796 +                       }
797 +               });
798 +               this.saveHiddenFlags();
799 +       },
800 +
801 +       clearHiddenFlags: function (a) {
802 +               var that = this;
803 +               a.forEach(function (command) {
804 +                       command = command.replace(/^\./, "");
805 +                       command = that.unalias(command.toLowerCase());
806 +                       if (command) {
807 +                               delete that.hiddenFlags[command];
808 +                       }
809 +               });
810 +               this.saveHiddenFlags();
811 +       },
812 +
813 +       //---------------------------------------------------------------------
814 +       // .quickNote functionality
815 +       //---------------------------------------------------------------------
816 +
817 +       noteColors: ["pink", "yellow", "green", "blue"],
818 +
819 +       randomNoteColor: function () {
820 +               return this.noteColors[Math.floor(Math.random() * this.noteColors.length)];
821 +       },
822 +
823 +       newNoteTimestamp: function () {
824 +               return Mojo.Format.formatDate(new Date(), "short").replace(/ /, "\n");
825 +       },
826 +
827 +       quickNoteCommand: function (text) {
828 +               var that = this;
829 +               var fun = function () {
830 +                       var globalSearch = this;
831 +                       var cookie = new Mojo.Model.Cookie("notesWarningDisplayedTEST");
832 +                       var checkIfNotesIsRunning = function (event) {
833 +                               var notesIsRunning = false;
834 +                               event.documents.forEach2(function (d) {
835 +                                       var a = d.appId.split(/\s+/);
836 +                                       if (a && a.length && a[0] === "com.palm.app.notes") {
837 +                                               notesIsRunning = true;
838 +                                               return false; // break the forEach2 loop.
839 +                                       }
840 +                               });
841 +                               if (notesIsRunning) {
842 +                                       if (that.apps &&
843 +                                           that.apps.iCanBeRefreshed &&
844 +                                           that.apps.iCanBeRefreshed["com.palm.app.notes_default"]) {
845 +                                               globalSearch.controller.serviceRequest(
846 +                                                       "palm://com.palm.applicationManager", {
847 +                                                               method: "launch",
848 +                                                               parameters: {
849 +                                                                       id: "com.palm.app.notes",
850 +                                                                       params: { refresh: true }
851 +                                                               }
852 +                                                       }
853 +                                               );
854 +                                               globalSearch.deactivate();
855 +                                       }
856 +                                       else {
857 +                                               globalSearch.deactivateWithWarning("Because you are running Notes and " + 
858 +                                                                                  "do not have the latest version " + 
859 +                                                                                  "of the USCL Notes Patch installed, " + 
860 +                                                                                  "please close and reopen Notes.  " + 
861 +                                                                                  "Your quicknote has been entered, " + 
862 +                                                                                  "but *may* not be shown until " + 
863 +                                                                                  "you close and reopen Notes.");
864 +                                       }
865 +                               }
866 +                               else {
867 +                                       globalSearch.deactivate();
868 +                               }
869 +                       };
870 +                       var getStats = function () {
871 +                               var request = new Mojo.Service.Request("palm://com.palm.lunastats", {
872 +                                       method: 'getStats',
873 +                                       parameters: {},
874 +                                       onSuccess: checkIfNotesIsRunning,
875 +                                       onFailure: function (event) {
876 +                                               if (event.documents) {
877 +                                                       checkIfNotesIsRunning(event);
878 +                                               }
879 +                                       }
880 +                               });
881 +                       };
882 +                       var noteText = text + "\n\n" + that.newNoteTimestamp() + "\n";
883 +                       var request = new Mojo.Service.Request("palm://com.palm.notes", {
884 +                               method: "saveNote",
885 +                               parameters: {
886 +                                       text: noteText,
887 +                                       color: that.randomNoteColor()
888 +                               },
889 +                               onComplete: getStats
890 +                       });
891 +               };
892 +               fun.noDeactivate = true;
893 +               return fun;
894 +       },
895 +
896 +       //---------------------------------------------------------------------
897 +       // .calc
898 +       //---------------------------------------------------------------------
899 +
900 +       calcCommand: function (s) {
901 +               // Yes, I'm aware that eval is usually evil.  The user
902 +               // chooses to use 'calc' at their own risk.  I'm only
903 +               // using it here because I'm too lazy at the moment to
904 +               // write an infix expression calculator.
905 +               if (!this.calculator) {
906 +                       this.calculator = new Calculator();
907 +               }
908 +               var result;
909 +               try {
910 +                       result = this.calculator.calculate(s);
911 +               }
912 +               catch (e) {
913 +                       return {
914 +                               title: "Error",
915 +                               message: e
916 +                       };
917 +               }
918 +               return {
919 +                       title: "Calculator",
920 +                       message: s + " \u2192 " + Object.toJSON(result)
921 +               };
922 +       },
923 +
924 +       //---------------------------------------------------------------------
925 +       // .restart, .rescan
926 +       //---------------------------------------------------------------------
927 +
928 +       restartCommand: function (arg) {
929 +               var r;
930 +               switch (arg) {
931 +               case "luna":
932 +                       try {
933 +                               r = new Mojo.Service.Request(
934 +                                       'luna://org.webosinternals.ipkgservice',
935 +                                       { method: 'restartluna' }
936 +                               );
937 +                       }
938 +                       catch (e1) {
939 +                               throw new USCLError('Error Restarting Luna: ' + e1.message);
940 +                       }
941 +                       break;
942 +               case "java":
943 +                       try {
944 +                               r = new Mojo.Service.Request(
945 +                                       'palm://org.webosinternals.ipkgservice',
946 +                                       { method: 'restartjava' }
947 +                               );
948 +                       }
949 +                       catch (e2) {
950 +                               throw new USCLError('Error restarting Java: ' + e2.message);
951 +                       }
952 +                       break;
953 +               }
954 +       },
955 +
956 +       rescanCommand: function () {
957 +               try {
958 +                       var r = new Mojo.Service.Request(
959 +                               'palm://com.palm.applicationManager',
960 +                               { method: 'rescan' }
961 +                       );
962 +               }
963 +               catch (e) {
964 +                       throw new USCLError('Error Rescanning: ' + e.message);
965 +               }
966 +       },
967 +
968 +       //---------------------------------------------------------------------
969 +       // .show; .hide
970 +       //---------------------------------------------------------------------
971 +
972 +       showCommand: function (args) {
973 +               if (args && args.length === 1 && args[0] === "all") {
974 +                       this.clearAllHiddenFlags();
975 +                       return undefined;
976 +               }
977 +               else if (args && args.length) {
978 +                       this.clearHiddenFlags(args);
979 +                       return undefined;
980 +               }
981 +               else {
982 +                       this.setShow(true);
983 +                       return {
984 +                               title: "Show Additional Searches",
985 +                               message: "Additional searches will now appear in Universal Search."
986 +                       };
987 +               }
988 +       },
989 +
990 +       hideCommand: function (args) {
991 +               if (args && args.length) {
992 +                       this.setHiddenFlags(args);
993 +                       return undefined;
994 +               }
995 +               else {
996 +                       this.setShow(false);
997 +                       return {
998 +                               title: "Hide Additional Searches",
999 +                               message: "Additional searches will no longer appear in Universal Search."
1000 +                       };
1001 +               }
1002 +       },
1003 +
1004 +       //---------------------------------------------------------------------
1005 +       // .update
1006 +       //---------------------------------------------------------------------
1007 +
1008 +       updateCommand: function () {
1009 +               var fun = function () {
1010 +                       var that = this;
1011 +                       this.uscl.updateFromLocalFile({
1012 +                               onFailure: function (response) {
1013 +                                       if (response.status === 404) {
1014 +                                               that.deactivateWithError("uscl.json not found.");
1015 +                                       }
1016 +                                       else {
1017 +                                               that.deactivateWithError("Unexpected error updating from uscl.json.");
1018 +                                       }
1019 +                               },
1020 +                               onParseFailure: function (response) {
1021 +                                       that.deactivateWithError("Syntax error in uscl.json.");
1022 +                               },
1023 +                               onParseSuccess: function (response) {
1024 +                                       that.deactivate();
1025 +                               }
1026 +                       });
1027 +               };
1028 +               fun.noDeactivate = true;
1029 +               return fun;
1030 +       },
1031 +
1032 +       //---------------------------------------------------------------------
1033 +       // Builtin Commands
1034 +       //---------------------------------------------------------------------
1035 +
1036 +       categories: [
1037 +               // not in use yet
1038 +               { name: "search", title: "Search" },
1039 +               { name: "reference", title: "Reference" },
1040 +               { name: "utilities", title: "Utilities" },
1041 +               { name: "location", title: "Location" },
1042 +               { name: "system", title: "System" }
1043 +       ],
1044 +
1045 +       entries: {
1046 +               "calc": {       // BUILTIN
1047 +                       title: "Calculator",
1048 +                       usage: "<var>expression</var>",
1049 +                       example: [
1050 +                               ".calc (37 * 1.8) + 32",
1051 +                               ".calc sin(PI / 2)",
1052 +                               ".calc Math.sin(Math.PI / 2)"
1053 +                       ],
1054 +                       description: ("Perform a calculation.  " + 
1055 +                                     "Can also evaluate other JavaScript expressions.  " +
1056 +                                     "Use at your own risk.  " +
1057 +                                     "Functions and constants in the core Math object " +
1058 +                                     "can be used with or without the 'Math.' prefix.  " +
1059 +                                     "More complex calculations (such as unit conversions) " +
1060 +                                     "can be sent to Google (see .google) " +
1061 +                                     "or Wolfram Alpha (see .wolfram)."),
1062 +                       method: function (s) {
1063 +                               return this.calcCommand(s);
1064 +                       },
1065 +                       noArguments: {
1066 +                               appId: "com.palm.app.calculator"
1067 +                       }
1068 +               },
1069 +               "c": "calc",
1070 +               "eval": "calc",
1071 +
1072 +               "imdb": {       // BASICS
1073 +                       title: "IMDB.com",
1074 +                       usage: "<var>query</var>",
1075 +                       example: "the big lebowski",
1076 +                       description: ("Search movies, TV shows, actors, directors, " + 
1077 +                                     "producers, and more on IMDB.com."),
1078 +                       url: "http://www.imdb.com/find?s=all&q=",
1079 +                       noArguments: {
1080 +                               url: "http://www.imdb.com/"
1081 +                       }
1082 +               },
1083 +               "i": "imdb", // keytoss alias
1084 +
1085 +               "dict": {       // BASICS
1086 +                       title: "Dictionary.com",
1087 +                       usage: "<var>word</var>",
1088 +                       example: "ebullient",
1089 +                       description: "Find a word on Dictionary.com.",
1090 +                       url: "http://m.reference.com/d/search.html?q=",
1091 +                       noArguments: {
1092 +                               url: "http://m.reference.com/d/"
1093 +                       }
1094 +               },
1095 +               "d": "dict",
1096 +
1097 +               "thes": {       // BASICS
1098 +                       title: "Thesaurus.com",
1099 +                       usage: "<var>word</var>",
1100 +                       example: "ebullient",
1101 +                       description: "Find a word on Thesaurus.com.",
1102 +                       url: "http://m.reference.com/t/search.html?q=",
1103 +                       noArguments: {
1104 +                               url: "http://m.reference.com/t/"
1105 +                       }
1106 +               },
1107 +               "th": "thes",
1108 +
1109 +               "beer": {       // EXTRAS
1110 +                       title: "BeerAdvocate",
1111 +                       usage: "<var>beer</var>",
1112 +                       example: "leine's sunset wheat",
1113 +                       description: "Find a beer on BeerAdvocate.com.  See also RateBeer (.ratebeer).",
1114 +                       url: "http://www.google.com/m/search?client=ms-palm-webOS&channel=iss&q=site:beeradvocate.com%20",
1115 +                       noArguments: {
1116 +                               url: "http://www.beeradvocate.com/"
1117 +                       }
1118 +               },
1119 +               "ba": "beer",
1120 +
1121 +               "ratebeer": {   // EXTRAS
1122 +                       title: "RateBeer",
1123 +                       usage: "<var>beer</var>",
1124 +                       example: "schlenkerla urbock",
1125 +                       description: "Find a beer on RateBeer.com.  See also BeerAdvocate (.beer).",
1126 +                       url: "http://www.google.com/m/search?client=ms-palm-webOS&channel=iss&q=site:ratebeer.com%20",
1127 +                       noArguments: {
1128 +                               url: "http://www.ratebeer.com/"
1129 +                       }
1130 +               },
1131 +               "rb": "ratebeer",
1132 +
1133 +               "ebay": {       // BASICS
1134 +                       title: "eBay",
1135 +                       usage: "<var>item</var>",
1136 +                       example: "mp3 player",
1137 +                       description: "Find something on eBay.com.",
1138 +                       url: "http://m.ebay.com/Pages/SearchResults.aspx?emvAD=320x320&emvcc=0&sv=",
1139 +                       noArguments: {
1140 +                               url: "http://m.ebay.com/"
1141 +                       }
1142 +               },
1143 +               "e": "ebay", // keytoss alias
1144 +
1145 +               "yahoo": {      // BASICS
1146 +                       title: "Yahoo!",
1147 +                       usage: "<var>keywords</var>",
1148 +                       example: "laptop reviews",
1149 +                       description: "Search Yahoo!",
1150 +                       url: "http://m.yahoo.com/w/search/oneSearch?p=",
1151 +                       noArguments: {
1152 +                               url: "http://m.yahoo.com/search"
1153 +                       }
1154 +               },
1155 +               "y": "yahoo",
1156 +
1157 +               "gis": {        // BASICS
1158 +                       title: "Google Images",
1159 +                       usage: "<var>keywords</var>",
1160 +                       example: "pirate hat",
1161 +                       description: "Search Google Images.",
1162 +                       url: "http://www.google.com/m/search?client=ms-palm-webOS&channel=iss&site=images&q=",
1163 +                       noArguments: {
1164 +                               url: "http://images.google.com/m/"
1165 +                       }
1166 +               },
1167 +               "gi": "gis", // keytoss alias
1168 +               
1169 +               "shop": {       // BASICS
1170 +                       title: "Google Product Search",
1171 +                       usage: "<var>keywords</var>",
1172 +                       example: "palm pre",
1173 +                       description: "Search for prices on Google Products.",
1174 +                       url: "http://www.google.com/m/search?client=ms-palm-webOS&channel=iss&site=products&q=",
1175 +                       noArguments: {
1176 +                               url: "http://products.google.com/m/"
1177 +                       }
1178 +               },
1179 +               "froogle": "shop",
1180 +               "gp": "shop", // keytoss alias
1181 +
1182 +               "news": {       // BASICS
1183 +                       title: "Google News Search",
1184 +                       usage: "<var>keywords</var>",
1185 +                       example: "obama",
1186 +                       description: "Search Google News.",
1187 +                       url: "http://www.google.com/m/search?client=ms-palm-webOS&channel=iss&site=news&q=",
1188 +                       noArguments: {
1189 +                               url: "http://news.google.com/m/"
1190 +                       }
1191 +               },
1192 +               "gn": "news", // keytoss alias
1193 +               
1194 +               "google": {     // BUILTIN FOR COMPLETENESS
1195 +                       excludeFromUniversalSearch: true,
1196 +                       title: "Google",
1197 +                       usage: "<var>keywords</var>",
1198 +                       example: "hummus recipe",
1199 +                       description: "Search Google.",
1200 +                       url: "www.google.com/m/search?client=ms-palm-webOS&channel=iss&q=",
1201 +                       noArguments: {
1202 +                               url: "http://www.google.com/m/"
1203 +                       }
1204 +               },
1205 +               "g": "google",
1206 +
1207 +               "amazon": {     // BASICS
1208 +                       title: "Amazon",
1209 +                       usage: "<var>keywords</var>",
1210 +                       example: "i am america and so can you",
1211 +                       description: "Search for products on Amazon.com.",
1212 +                       url: "http://www.amazon.com/gp/aw/s/ref=is_box_?k=",
1213 +                       noArguments: {
1214 +                               url: "http://www.amazon.com/gp/aw"
1215 +                       }
1216 +               },
1217 +               "az": "amazon",
1218 +               "am": "amazon", // keytoss alias
1219 +
1220 +               "wikipedia": {  // BUILTIN FOR COMPLETENESS
1221 +                       excludeFromUniversalSearch: true,
1222 +                       title: "Wikipedia",
1223 +                       usage: "<var>keywords</var>",
1224 +                       example: "isaac newton",
1225 +                       description: "Search Wikipedia, the online encyclopedia that anyone can edit.",
1226 +                       url: "http://en.m.wikipedia.org/wiki/Special:Search?search=",
1227 +                       noArguments: {
1228 +                               url: "http://en.m.wikipedia.org/"
1229 +                       }
1230 +               },
1231 +               "wiki": "wikipedia",
1232 +               "w": "wikipedia",
1233 +
1234 +               "wolfram": {    // EXTRAS
1235 +                       title: "Wolfram Alpha",
1236 +                       usage: "<var>keywords</var>",
1237 +                       example: [
1238 +                               ".wa June 23, 1988",
1239 +                               ".wa new york",
1240 +                               ".wa IBM Apple",
1241 +                               ".wa $250 + 15%",
1242 +                               ".wa x**2 sin(x)"
1243 +                       ],
1244 +                       description: "Query something on Wolfram Alpha.  Dates, cities, stocks, and equations.  Go nuts!",
1245 +                       url: "http://www.wolframalpha.com/input/?i=",
1246 +                       noArguments: {
1247 +                               url: "http://www.wolframalpha.com/"
1248 +                       }
1249 +               },
1250 +               "wa": "wolfram",
1251 +       
1252 +               "snopes": {     // EXTRAS
1253 +                       title: "Snopes",
1254 +                       usage: "<var>keywords</var>",
1255 +                       example: "jerry rivers",
1256 +                       description: "Debunk or confirm urban legends.  Win bets and embarrass your friends!",
1257 +                       url: "http://www.google.com/m/search?client=ms-palm-webOS&channel=iss&q=site:www.snopes.com%20",
1258 +                       noArguments: {
1259 +                               url: "http://www.snopes.com/"
1260 +                       }
1261 +               },
1262 +               "sn": "snopes",
1263 +
1264 +               "keytoss": {    // BUILTIN
1265 +                       title: "KeyToss",
1266 +                       usage: [
1267 +                               ".keytoss <var>command</var> <var>keywords</var>",
1268 +                               ".kt <var>command</var> <var>keywords</var>",
1269 +                               "..<var>command</var> <var>keywords</var>"
1270 +                       ],
1271 +                       example: [
1272 +                               ".keytoss af wtf",
1273 +                               ".kt af omg",
1274 +                               "..af bbq"
1275 +                       ],
1276 +                       description: ("Perform a search via the KeyToss mobile portal.<br />" + 
1277 +                                     "You do not need to type the at sign (<kbd>@</kbd>) before the <i>command</i>.<br />" + 
1278 +                                     "Use <nobr><kbd>.keywords|.kt kt list</kbd></nobr> or <nobr><kbd>..kt list</kbd></nobr> " + 
1279 +                                     "to get a list of commands to pass to KeyToss."),
1280 +                       preprocess: function (s) {
1281 +                               return s.replace(/^\s*@\s*/, "");
1282 +                       },
1283 +                       url: "http://pre.keytoss.com/parse.php5?pv=131&term=%40",
1284 +                       noArguments: {
1285 +                               url: "http://pre.keytoss.com/"
1286 +                       }
1287 +               },
1288 +               "kt": "keytoss",
1289 +
1290 +               "note": {       // BUILTIN
1291 +                       title: "New Note",
1292 +                       usage: "<var>text</var>",
1293 +                       example: "I like pie.",
1294 +                       description: "Quickly create a new note.",
1295 +                       appId: "com.palm.app.notes",
1296 +                       param: "newNoteText",
1297 +                       noArguments: {
1298 +                               appId: "com.palm.app.notes"
1299 +                       }
1300 +               },
1301 +               "memo": "note",
1302 +               "m": "note",
1303 +               "n": "note",
1304 +
1305 +               "quicknote": {  // BUILTIN
1306 +                       title: "New Note (without launch)",
1307 +                       usage: "<var>text</var>",
1308 +                       example: "I like pie.",
1309 +                       description: "Quickly create a new note, without launching the Notes application.",
1310 +                       method: function (text) {
1311 +                               return this.quickNoteCommand(text);
1312 +                       }
1313 +               },
1314 +               "quickmemo": "quicknote",
1315 +               "qmemo": "quicknote",
1316 +               "qnote": "quicknote",
1317 +               "qm": "quicknote",
1318 +               "qn": "quicknote",
1319 +
1320 +               "restart": {    // BUILTIN
1321 +                       excludeFromUniversalSearch: true,
1322 +                       title: "Restart Luna or Java",
1323 +                       usage: "<b>luna</b>|<b>java</b>",
1324 +                       description: "Restarts the Luna system manager or Java services.",
1325 +                       method: function (arg) {
1326 +                               return this.restartCommand(arg);
1327 +                       }
1328 +               },
1329 +
1330 +               "rescan": {     // BUILTIN
1331 +                       excludeFromUniversalSearch: true,
1332 +                       argumentsOptional: true,
1333 +                       title: "Rescan Applications",
1334 +                       description: "Rescans the list of applications on your device.",
1335 +                       method: function () {
1336 +                               return this.rescanCommand();
1337 +                       }
1338 +               },
1339 +
1340 +               "show": {       // BUILTIN
1341 +                       excludeFromUniversalSearch: true,
1342 +                       argumentsOptional: true,
1343 +                       takesMultipleArguments: true,
1344 +                       title: "Show Additional Searches",
1345 +                       usage: [
1346 +                               "<kbd>.show</kbd>",
1347 +                               "<kbd>.show</kbd> <var>cmd</var> ...",
1348 +                               "<kbd>.show all</kbd>"
1349 +                       ],
1350 +                       description: ("Use <kbd>.show</kbd> without arguments to show additional searches on the Universal Search screen.<br />" +
1351 +                                     "Use <kbd>.show <var>cmd</var> ...</kbd> to un-hide the specified commands when additional searches are shown " +
1352 +                                     "(does not apply when <kbd>.hide</kbd> without arguments is used to hide all searches).<br />" +
1353 +                                     "Use <kbd>.show all</kbd> to un-hide all commands when additional searches are shown.<br />" +
1354 +                                     "See also <kbd>.hide</kbd>."),
1355 +                       method: function (args) {
1356 +                               return this.showCommand(args);
1357 +                       }
1358 +               },
1359 +
1360 +               "hide": {       // BUILTIN
1361 +                       excludeFromUniversalSearch: true,
1362 +                       argumentsOptional: true,
1363 +                       takesMultipleArguments: true,
1364 +                       title: "Hide Additional Searches",
1365 +                       usage: [
1366 +                               "<kbd>.hide</kbd>",
1367 +                               "<kbd>.hide</kbd> <var>cmd</var> <var>cmd</var> ..."
1368 +                       ],
1369 +                       description: ("Use <kbd>.hide</kbd> without arguments to hide additional searches from the Universal Search screen.<br />" + 
1370 +                                     "Use <kbd>.hide <var>cmd</var> ...</kbd> to hide the specified commands when additional searches are shown.<br />" +
1371 +                                     "See also <kbd>.show</kbd>."),
1372 +                       method: function (args) {
1373 +                               return this.hideCommand(args);
1374 +                       }
1375 +               },
1376 +
1377 +               "gps": {        // BUILTIN
1378 +                       excludeFromUniversalSearch: true,
1379 +                       title: "GPS On/Off",
1380 +                       usage: "on|off",
1381 +                       description: "Turns location using GPS on/off.",
1382 +                       takesBooleanArgument: true,
1383 +                       method: function (flag) {
1384 +                               this.setUseGps(flag);
1385 +                       }
1386 +               },
1387 +
1388 +               "usegoogle": {  // BUILTIN
1389 +                       excludeFromUniversalSearch: true,
1390 +                       title: "Google Location Services On/Off",
1391 +                       usage: "on|off",
1392 +                       description: ("Turns location using Google Services on/off.  " +
1393 +                                     "This uses cell towers to roughly pinpoint your general location.  " + 
1394 +                                     "Accuracy will vary."),
1395 +                       takesBooleanArgument: true,
1396 +                       method: function (flag) {
1397 +                               this.setUseGoogle(flag);
1398 +                       }
1399 +               },
1400 +
1401 +               "autolocate": { // BUILTIN
1402 +                       excludeFromUniversalSearch: true,
1403 +                       title: "Auto Locate On/Off",
1404 +                       usage: "on|off",
1405 +                       description: ("Turns auto location on/off.  " +
1406 +                                     "When Auto Locate is on, applications can automatically identify your location.  " +
1407 +                                     "When off, applications that use location data will ask if it's okay " + 
1408 +                                     "to identify your location for that particular session only."),
1409 +                       takesBooleanArgument: true,
1410 +                       method: function (flag) {
1411 +                               this.setAutoLocate(flag);
1412 +                       }
1413 +               },
1414 +
1415 +               "geotag": {     // BUILTIN
1416 +                       excludeFromUniversalSearch: true,
1417 +                       title: "Geotagging On/Off",
1418 +                       usage: "on|off",
1419 +                       description: ("Turns geotagging of photos on/off.  " + 
1420 +                                     "This only applies when Auto Locate is on."),
1421 +                       takesBooleanArgument: true,
1422 +                       method: function (flag) {
1423 +                               this.setGeotagPhotos(flag);
1424 +                       }
1425 +               },
1426 +
1427 +               "bgdata": {     // BUILTIN
1428 +                       excludeFromUniversalSearch: true,
1429 +                       title: "Background Data Collection On/Off",
1430 +                       usage: "on|off",
1431 +                       description: ("Turns background collection of data on/off.  " + 
1432 +                                     "This allows Google to collect anonymous location data " + 
1433 +                                     "to improve the quality of location services."),
1434 +                       takesBooleanArgument: true,
1435 +                       method: function (flag) {
1436 +                               this.setUseBackgroundDataCollection(flag);
1437 +                       }
1438 +               },
1439 +
1440 +               "maps": {       // BUILTIN FOR COMPLETENESS
1441 +                       excludeFromUniversalSearch: true,
1442 +                       title: "Google Maps",
1443 +                       argumentsOptional: true,
1444 +                       usage: "<var>keywords</var>",
1445 +                       description: "Opens the Google Maps application and searches for what you specify.",
1446 +                       method: function (arg) {
1447 +                               // must be run from within global search.
1448 +                               return function () {
1449 +                                       this.launchMap(arg);
1450 +                               };
1451 +                       }
1452 +               },
1453 +
1454 +               "update": {     // BUILTIN
1455 +                       excludeFromUniversalSearch: true,
1456 +                       title: "Update User-Defined Commands",
1457 +                       argumentsOptional: true,
1458 +                       description: ("If <tt>uscl.json</tt> on the root directory of the USB Drive partition " + 
1459 +                                     "on this device is modified, added, or removed, use this command to update Universal Search Command Line."),
1460 +                       method: function () {
1461 +                               return this.updateCommand();
1462 +                       }
1463 +               },
1464 +
1465 +               "help": {       // BUILTIN
1466 +                       excludeFromUniversalSearch: true,
1467 +                       title: "Help",
1468 +                       excludeFromHelp: true,
1469 +                       argumentsOptional: true,
1470 +                       method: function () {
1471 +                               this.showHelp();
1472 +                       }
1473 +               }
1474 +       },
1475 +
1476 +       //---------------------------------------------------------------------
1477 +       // Builtin flags populated on initialization.
1478 +       //---------------------------------------------------------------------
1479 +
1480 +       isBuiltin: {},
1481 +
1482 +       /* This must be done as early as possible upon initialization. */
1483 +       initBuiltinFlags: function () {
1484 +               var command;
1485 +               for (command in this.entries) {
1486 +                       if (this.entries.hasOwnProperty(command)) {
1487 +                               this.isBuiltin[command] = true;
1488 +                       }
1489 +               }
1490 +       },
1491 +
1492 +       //---------------------------------------------------------------------
1493 +       // /media/internal/uscl.json
1494 +       //---------------------------------------------------------------------
1495 +
1496 +       updateFromLocalFile: function (options) {
1497 +               var that = this;
1498 +               var request = new Ajax.Request("/media/internal/uscl.json", {
1499 +                       method: "get",
1500 +                       onSuccess: function (response) {
1501 +                               that.localFileSuccess(response, options);
1502 +                               if (options && options.onSuccess) {
1503 +                                       options.onSuccess(response);
1504 +                               }
1505 +                       },
1506 +                       onFailure: function (response) {
1507 +                               that.localFileFailure(response, options);
1508 +                               if (options && options.onFailure) {
1509 +                                       options.onFailure(response);
1510 +                               }
1511 +                       },
1512 +                       onComplete: function (response) {
1513 +                               that.fixTitles();
1514 +                               if (options && options.onComplete) {
1515 +                                       options.onComplete(response);
1516 +                               }
1517 +                       }
1518 +               });
1519 +       },
1520 +
1521 +       localFileSuccess: function (response, options) {
1522 +               var o;
1523 +               this.deleteLocalCommands();
1524 +               try {
1525 +                       o = response.responseText.evalJSON({
1526 +                               sanitize: true
1527 +                       });
1528 +               }
1529 +               catch (e) {
1530 +                       this.deleteLocalCommands();
1531 +                       options.onParseFailure(response);
1532 +               }
1533 +               if (o) {
1534 +                       this.mergeLocalCommands(o);
1535 +               }
1536 +               options.onParseSuccess(response);
1537 +       },
1538 +
1539 +       localFileFailure: function (response, options) {
1540 +               this.deleteLocalCommands();
1541 +       },
1542 +
1543 +       deleteLocalCommands: function () {
1544 +               var nonBuiltins = [];
1545 +               var command;
1546 +               for (command in this.entries) {
1547 +                       if (this.entries.hasOwnProperty(command)) {
1548 +                               if (!this.isBuiltin[command]) {
1549 +                                       nonBuiltins.push(command);
1550 +                               }
1551 +                       }
1552 +               }
1553 +               nonBuiltins.forEach(function (command) {
1554 +                       delete this.entries[command];
1555 +               }, this);
1556 +       },
1557 +
1558 +       mergeLocalCommands: function (o) {
1559 +               if (!o.entries) { return; }
1560 +               for (var command in o.entries) {
1561 +                       if (o.entries.hasOwnProperty(command)) {
1562 +                               if (!(command in this.entries)) {
1563 +                                       this.entries[command] = o.entries[command];
1564 +                               }
1565 +                       }
1566 +               }
1567 +               this.fixTitles();
1568 +       },
1569 +
1570 +       //---------------------------------------------------------------------
1571 +       // Command Interpretation
1572 +       //---------------------------------------------------------------------
1573 +
1574 +       rawGetEntry: function (commandName) {
1575 +               if (commandName in this.entries) {
1576 +                       return this.entries[commandName];
1577 +               }
1578 +               return undefined;
1579 +       },
1580 +
1581 +       getEntry: function (commandName) {
1582 +               var entry = this.rawGetEntry(commandName);
1583 +               while (entry && entry.constructor === String) {
1584 +                       entry = this.entries[entry];
1585 +               }
1586 +               if (!entry) {
1587 +                       return undefined;
1588 +               }
1589 +               return entry;
1590 +       },
1591 +
1592 +       unalias: function (commandName) {
1593 +               var entry = this.rawGetEntry(commandName);
1594 +               while (entry && entry.constructor === String) {
1595 +                       commandName = entry;
1596 +                       entry = this.entries[entry];
1597 +               }
1598 +               if (!entry) {
1599 +                       return undefined;
1600 +               }
1601 +               return commandName;
1602 +       },
1603 +
1604 +       appWorksWithUSCL: function (appId) {
1605 +               return (this.apps &&
1606 +                       this.apps.iGrokTheCommandLine &&
1607 +                       this.apps.iGrokTheCommandLine[appId + "_default"]);
1608 +       },
1609 +
1610 +       runEntry: function (entry, arg) {
1611 +               if (entry.preprocess) {
1612 +                       arg = entry.preprocess.apply(this, [arg]);
1613 +               }
1614 +               if (!/\S/.test(arg) && !entry.argumentsOptional) {
1615 +                       throw new USCLError("No arguments specified.");
1616 +               }
1617 +               if (entry.method) {
1618 +                       var args = [arg];
1619 +                       if (entry.takesMultipleArguments) {
1620 +                               if (/\S/.test(arg)) {
1621 +                                       args = [arg.normalizeSpace().split(" ")];
1622 +                               }
1623 +                               else {
1624 +                                       args = [];
1625 +                               }
1626 +                       }
1627 +                       else if (entry.takesBooleanArgument) {
1628 +                               var flag = arg.toBoolean();
1629 +                               if (flag !== undefined) {
1630 +                                       args = [flag];
1631 +                               }
1632 +                               else {
1633 +                                       throw new USCLError("Invalid argument");
1634 +                               }
1635 +                       }
1636 +                       var result = entry.method.apply(this, args);
1637 +                       return result;
1638 +               }
1639 +               else if (entry.appId) {
1640 +                       if (!this.appWorksWithUSCL(entry.appId)) {
1641 +                               var message =
1642 +                                       "The application " + entry.appId +
1643 +                                       " is not installed or" +
1644 +                                       " has not been patched to work with the " + 
1645 +                                       "Universal Search Command Line.";
1646 +                               if (entry.appId === "com.palm.app.notes") {
1647 +                                       message += "  Please install the USCL Memos Patch" +
1648 +                                               " via Preware (or by other means).";
1649 +                               }
1650 +                               throw new USCLError(message);
1651 +                       }
1652 +                       var params = { };
1653 +                       params[entry.param] = arg;
1654 +                       // We return a function, which will be called
1655 +                       // with this set to the global search assistant
1656 +                       // object.  I don't remember why we can't just
1657 +                       // start the serviceRequest here.
1658 +                       return function () {
1659 +                               this.controller.serviceRequest(
1660 +                                       "palm://com.palm.applicationManager", {
1661 +                                               method: "launch",
1662 +                                               parameters: {
1663 +                                                       id: entry.appId,
1664 +                                                       params: params
1665 +                                               }
1666 +                                       }
1667 +                               );
1668 +                       };
1669 +               }
1670 +               else if (entry.url) {
1671 +                       // We returns a function, which will be called
1672 +                       // with this set to the global search assistant
1673 +                       // object.
1674 +                       return function () {
1675 +                               this.launchBrowser(entry.url + encodeURIComponent(arg.trim()));
1676 +                       };
1677 +               }
1678 +               else {
1679 +                       throw new USCLError("Command not implemented.");
1680 +               }
1681 +       },
1682 +       
1683 +       run: function (what, arg) {
1684 +               var commandName;
1685 +               var entry;
1686 +               try {
1687 +                       if (typeof(what) === "object") {
1688 +                               commandName = what.commandName;
1689 +                               return this.runEntry(what, arg);
1690 +                       }
1691 +                       else {
1692 +                               commandName = what;
1693 +                               entry = this.getEntry(commandName);
1694 +                               if (!entry) {
1695 +                                       throw new USCLError("Command not found.");
1696 +                               }
1697 +                               else {
1698 +                                       return this.runEntry(entry, arg);
1699 +                               }
1700 +                       }
1701 +               }
1702 +               catch (error) {
1703 +                       if (error instanceof USCLError) {
1704 +                               throw new USCLError("." + commandName + ": " +
1705 +                                                   error.message);
1706 +                       }
1707 +                       else {
1708 +                               throw error;
1709 +                       }
1710 +               }
1711 +       },
1712 +
1713 +       runString: function (s, /* optional */ justCheck) {
1714 +               var arg, commandName;
1715 +               if (/^\s*\.\.(\S.*)$/.test(s)) { // ..<keytoss-command> <args>
1716 +                       if (justCheck) {
1717 +                               return true;
1718 +                       }
1719 +                       arg = RegExp.$1;
1720 +                       return this.run("keytoss", arg);
1721 +               }
1722 +               else if (/^\s*\.(\S+)\s*(.*)$/.test(s)) { // .<uscl-command> <args>
1723 +                       if (justCheck) {
1724 +                               return true;
1725 +                       }
1726 +                       commandName = RegExp.$1;
1727 +                       arg         = RegExp.$2;
1728 +                       return this.run(commandName, arg);
1729 +               }
1730 +               else if (/^(.*?)\s+\.\.(\S+)\s*$/.test(s)) { // <args> ..<keytoss-command>
1731 +                       if (justCheck) {
1732 +                               return true;
1733 +                       }
1734 +                       arg = RegExp.$2 + " " + RegExp.$1;
1735 +                       return this.run("keytoss", arg);
1736 +               }
1737 +               else if (/^(.*?)\s+\.(\S+)\s*$/.test(s)) { // <args> .<uscl-command>
1738 +                       if (justCheck) {
1739 +                               return true;
1740 +                       }
1741 +                       commandName = RegExp.$2;
1742 +                       arg         = RegExp.$1;
1743 +                       return this.run(commandName, arg);
1744 +               }
1745 +               else {
1746 +                       if (justCheck) {
1747 +                               return false;
1748 +                       }
1749 +                       throw new USCLError("No command supplied.");
1750 +               }
1751 +       },
1752 +       
1753 +       isCommandString: function (s) {
1754 +               return this.runString(s, /* justCheck */ true);
1755 +       },
1756 +
1757 +       //---------------------------------------------------------------------
1758 +       // Help
1759 +       //---------------------------------------------------------------------
1760 +
1761 +       getHelpCommandList: function () {
1762 +               var commandName;
1763 +               var entry;
1764 +               var realEntry;
1765 +               var result = [];
1766 +               for (commandName in this.entries) {
1767 +                       if (this.entries.hasOwnProperty(commandName)) {
1768 +                               entry = this.entries[commandName];
1769 +                               
1770 +                               if (typeof(entry) !== "object") { continue; }
1771 +                               if (entry.excludeFromHelp) { continue; }
1772 +                               if (entry.emulatorOnly && !this.inEmulator) { continue; }
1773 +                               
1774 +                               result.push(entry);
1775 +                               entry.aka = [];
1776 +                               entry.commandName = commandName;
1777 +                       }
1778 +               }
1779 +               for (commandName in this.entries) {
1780 +                       if (this.entries.hasOwnProperty(commandName)) {
1781 +                               entry = this.entries[commandName];
1782 +                               if (entry.constructor === String) {
1783 +                                       realEntry = this.getEntry(commandName);
1784 +                                       realEntry.aka.push(commandName);
1785 +                               }
1786 +                       }
1787 +               }
1788 +               result.forEach(function (entry) {
1789 +                       entry.aka.sort();
1790 +               });
1791 +               result.sort(function (a, b) {
1792 +                       return ((a.titleSort < b.titleSort) ? -1 : 
1793 +                               (a.titleSort > b.titleSort) ? 1 : 0);
1794 +               });
1795 +               return result;
1796 +       },
1797 +
1798 +       showHelp: function () {
1799 +               var that = this;
1800 +               var sc = Mojo.Controller.appController.getStageController("uscl-help");
1801 +               if (sc) {
1802 +                       var scenes = sc.getScenes();
1803 +                       if (!(scenes && scenes.length === 1)) {
1804 +                               // doing this if the top scene is
1805 +                               // already the one we want causes an
1806 +                               // unwanted transition effect.
1807 +                               sc.popScenesTo("uscl-help-command-list");
1808 +                       }
1809 +                       sc.activate();
1810 +               }
1811 +               else {
1812 +                       var stageArguments = {
1813 +                               name: "uscl-help",
1814 +                               lightweight: true
1815 +                       };
1816 +                       var pushScene = function (sc) {
1817 +                               sc.pushScene("uscl-help-command-list", that);
1818 +                       };
1819 +                       Mojo.Controller.appController.createStageWithCallback(
1820 +                               stageArguments, pushScene, "card");
1821 +               }
1822 +       },
1823 +
1824 +       //---------------------------------------------------------------------
1825 +       // Additional Universal Search Options
1826 +       //---------------------------------------------------------------------
1827 +
1828 +       getUniversalSearchCommandList: function () {
1829 +               var commandName;
1830 +               var entry;
1831 +               var result = [];
1832 +               for (commandName in this.entries) {
1833 +                       if (this.entries.hasOwnProperty(commandName)) {
1834 +                               entry = this.entries[commandName];
1835 +
1836 +                               if (typeof(entry) !== "object") { continue; }
1837 +                               if (entry.excludeFromUniversalSearch) { continue; }
1838 +                               if (entry.emulatorOnly && !this.inEmulator) { continue; }
1839 +                               if (this.hiddenFlags[commandName]) { continue; } /* .hide <cmd> */
1840 +
1841 +                               result.push(entry);
1842 +                       }
1843 +               }
1844 +               result.sort(function (a, b) {
1845 +                       return ((a.titleSort < b.titleSort) ? -1 : 
1846 +                               (a.titleSort > b.titleSort) ? 1 : 0);
1847 +               });
1848 +               return result;
1849 +       },
1850 +
1851 +       //---------------------------------------------------------------------
1852 +       // .gps, etc.
1853 +       //---------------------------------------------------------------------
1854 +
1855 +       setUseGps: function (flag) {
1856 +               this.setLocationServiceFlag({
1857 +                       method: "setUseGps",
1858 +                       parameter: "useGps",
1859 +                       name: "GPS",
1860 +                       flag: flag
1861 +               });
1862 +       },
1863 +
1864 +       setUseBackgroundDataCollection: function (flag) {
1865 +               this.setLocationServiceFlag({
1866 +                       method: "setUseBackgroundDataCollection",
1867 +                       parameter: "useBackgroundDataCollection",
1868 +                       name: "Background Data Collection",
1869 +                       flag: flag
1870 +               });
1871 +       },
1872 +
1873 +       setGeotagPhotos: function (flag) {
1874 +               this.setLocationServiceFlag({
1875 +                       method: "setGeotagPhotos",
1876 +                       parameter: "geotagPhotos",
1877 +                       name: "Geotagging",
1878 +                       flag: flag
1879 +               });
1880 +       },
1881 +
1882 +       setAutoLocate: function (flag) {
1883 +               this.setLocationServiceFlag({
1884 +                       method: "setAutoLocate",
1885 +                       parameter: "autoLocate",
1886 +                       name: "Auto-Locate",
1887 +                       flag: flag
1888 +               });
1889 +       },
1890 +
1891 +       setUseGoogle: function (flag) {
1892 +               this.setLocationServiceFlag({
1893 +                       method: "setUseGoogle",
1894 +                       parameter: "useGoogle",
1895 +                       name: "Google Location Services",
1896 +                       flag: flag
1897 +               });
1898 +       },
1899 +
1900 +       setLocationServiceFlag: function (options) {
1901 +               var that = this;
1902 +
1903 +               var flag = options.flag;
1904 +
1905 +               var parameters = {};
1906 +               parameters[options.parameter] = flag;
1907 +
1908 +               var request = new Mojo.Service.Request("palm://com.palm.location", {
1909 +                       method: options.method,
1910 +                       parameters: parameters,
1911 +                       onSuccess: function () {
1912 +                               that.bannerNotify("Successfully %s %s.".format(
1913 +                                       flag ? "enabled" : "disabled",
1914 +                                       options.name
1915 +                               ));
1916 +                       },
1917 +                       onFailure: function (response) {
1918 +                               that.bannerNotify("Error %s %s: %j".format(
1919 +                                       flag ? "enabling" : "disabling",
1920 +                                       options.name,
1921 +                                       $H(response)
1922 +                               ));
1923 +                       }
1924 +               });
1925 +       },
1926 +
1927 +       //---------------------------------------------------------------------
1928 +       // Utilities
1929 +       //---------------------------------------------------------------------
1930 +
1931 +       bannerNotify: function (message) {
1932 +               Mojo.Controller.appController.showBanner({
1933 +                       messageText: message
1934 +               }, "", "uscl");
1935 +       }
1936 +
1937 +});
1938 +
1939 Index: /usr/lib/luna/system/luna-applauncher/app/views/global-search/expanded-searches-div.html
1940 ===================================================================
1941 --- .orig/usr/lib/luna/system/luna-applauncher/app/views/global-search/expanded-searches-div.html
1942 +++ /usr/lib/luna/system/luna-applauncher/app/views/global-search/expanded-searches-div.html
1943 @@ -17,4 +17,14 @@
1944                         </div>
1945                 </div> 
1946         </div>  
1947 +       <div id='command_line_drawer' x-mojo-element="Drawer">
1948 +               <div class="palm-row last" id="uscl" name="search-identifier" x-mojo-tap-highlight="persistent">
1949 +                       <div class="palm-row-wrapper">
1950 +                               <div class="title search-command-line truncating-text">
1951 +                                       <span class="prefix">cmd:</span>
1952 +                                       <kbd id="uscl-text">#{filterText}</kbd>
1953 +                               </div>
1954 +                       </div>
1955 +               </div> 
1956 +       </div>
1957  </div>
1958 Index: /usr/lib/luna/system/luna-applauncher/app/views/global-search/expanded-searches-div-uscl.html
1959 ===================================================================
1960 --- .orig/usr/lib/luna/system/luna-applauncher/app/views/global-search/expanded-searches-div-uscl.html
1961 +++ /usr/lib/luna/system/luna-applauncher/app/views/global-search/expanded-searches-div-uscl.html
1962 @@ -0,0 +1,3 @@
1963 +<div id='expanded_searches_drawer_uscl' x-mojo-element="Drawer">
1964 +       <div id="usclSearches" class="palm-list" x-mojo-element="List"></div>
1965 +</div>
1966 Index: /usr/lib/luna/system/luna-applauncher/app/views/global-search/templates/uscl-searches-item.html
1967 ===================================================================
1968 --- .orig/usr/lib/luna/system/luna-applauncher/app/views/global-search/templates/uscl-searches-item.html
1969 +++ /usr/lib/luna/system/luna-applauncher/app/views/global-search/templates/uscl-searches-item.html
1970 @@ -0,0 +1,5 @@
1971 +<div class="palm-row" name="search-identifier" x-mojo-tap-highlight="momentary">
1972 +       <div class="palm-row-wrapper">
1973 +               <div class="search-uscl">#{title}</div>
1974 +       </div>
1975 +</div>
1976 Index: /usr/lib/luna/system/luna-applauncher/app/views/global-search/templates/uscl-searches-list.html
1977 ===================================================================
1978 --- .orig/usr/lib/luna/system/luna-applauncher/app/views/global-search/templates/uscl-searches-list.html
1979 +++ /usr/lib/luna/system/luna-applauncher/app/views/global-search/templates/uscl-searches-list.html
1980 @@ -0,0 +1,3 @@
1981 +<div class="palm-list">
1982 +       #{-listElements}
1983 +</div>
1984 Index: /usr/lib/luna/system/luna-applauncher/app/views/launcher/launcher-scene.html
1985 ===================================================================
1986 --- .orig/usr/lib/luna/system/luna-applauncher/app/views/launcher/launcher-scene.html
1987 +++ /usr/lib/luna/system/luna-applauncher/app/views/launcher/launcher-scene.html
1988 @@ -10,6 +10,10 @@
1989                 \r
1990                 <div class="palm-group solid" id="launcherIconsDiv"></div>\r
1991                 \r
1992 +               <div class="palm-group unlabeled search" id="searchesDivUSCL">\r
1993 +                       <div class="palm-list" id="searches-list-uscl"></div>\r
1994 +               </div>\r
1995 +               \r
1996                 <div id="contactsDiv"></div>\r
1997                 \r
1998                 <div class="palm-group search" id="singleContactsDiv"></div>\r
1999 Index: /usr/lib/luna/system/luna-applauncher/app/views/uscl-help-command-list/templates/item.html
2000 ===================================================================
2001 --- .orig/usr/lib/luna/system/luna-applauncher/app/views/uscl-help-command-list/templates/item.html
2002 +++ /usr/lib/luna/system/luna-applauncher/app/views/uscl-help-command-list/templates/item.html
2003 @@ -0,0 +1,6 @@
2004 +<div class="palm-row" x-mojo-tap-highlight="momentary">
2005 +       <div class="palm-row-wrapper">
2006 +               <div class="uscl-help-command-name"  id="command-name"><kbd>.#{commandName}</kbd></div>
2007 +               <div class="uscl-help-command-title" id="title"       >#{title}</div>
2008 +       </div>
2009 +</div>
2010 Index: /usr/lib/luna/system/luna-applauncher/app/views/uscl-help-command-list/templates/list.html
2011 ===================================================================
2012 --- .orig/usr/lib/luna/system/luna-applauncher/app/views/uscl-help-command-list/templates/list.html
2013 +++ /usr/lib/luna/system/luna-applauncher/app/views/uscl-help-command-list/templates/list.html
2014 @@ -0,0 +1,3 @@
2015 +<div class="palm-list">
2016 +       #{-listElements}
2017 +</div>
2018 Index: /usr/lib/luna/system/luna-applauncher/app/views/uscl-help-command-list/uscl-help-command-list-scene.html
2019 ===================================================================
2020 --- .orig/usr/lib/luna/system/luna-applauncher/app/views/uscl-help-command-list/uscl-help-command-list-scene.html
2021 +++ /usr/lib/luna/system/luna-applauncher/app/views/uscl-help-command-list/uscl-help-command-list-scene.html
2022 @@ -0,0 +1,11 @@
2023 +<div id="uscl-help-command-list" class="uscl-help uscl-help-command-list">
2024 +       <div class="palm-page-header multi-line">
2025 +               <div class="palm-page-header-wrapper">
2026 +                       <div class="title left">
2027 +                               Universal Search Command Line Help
2028 +                       </div>
2029 +               </div>
2030 +       </div>
2031 +       <div id="command-list" x-mojo-element="List">
2032 +       </div>
2033 +</div>
2034 Index: /usr/lib/luna/system/luna-applauncher/app/views/uscl-help-command-view/uscl-help-command-view-scene.html
2035 ===================================================================
2036 --- .orig/usr/lib/luna/system/luna-applauncher/app/views/uscl-help-command-view/uscl-help-command-view-scene.html
2037 +++ /usr/lib/luna/system/luna-applauncher/app/views/uscl-help-command-view/uscl-help-command-view-scene.html
2038 @@ -0,0 +1,23 @@
2039 +<div id="uscl-help-command-view" class="uscl-help uscl-help-command-view">
2040 +       <div class="palm-page-header multi-line">
2041 +               <div class="palm-page-header-wrapper">
2042 +                       <div class="title left un-capitalize" id="title">
2043 +                       </div>
2044 +               </div>
2045 +       </div>
2046 +       <div class="contents">
2047 +               <div class="uscl-help-usage" id="usageDiv">
2048 +                       Usage:
2049 +                       <kbd class="usage" id="usage"></kbd>
2050 +               </div>
2051 +               <div class="uscl-help-aka" id="akaDiv">
2052 +                       Also known as:
2053 +                       <span class="aka" id="aka"></span>
2054 +               </div>
2055 +               <div class="uscl-help-description" id="description"></div>
2056 +               <div class="uscl-help-example" id="exampleDiv">
2057 +                       <span class="example-title" id="example-title">Example</span>:
2058 +                       <kbd class="example" id="example"></kbd>
2059 +               </div>
2060 +       </div>
2061 +</div>
2062 Index: /usr/lib/luna/system/luna-applauncher/index.html
2063 ===================================================================
2064 --- .orig/usr/lib/luna/system/luna-applauncher/index.html
2065 +++ /usr/lib/luna/system/luna-applauncher/index.html
2066 @@ -9,6 +9,7 @@
2067         
2068         <link href="stylesheets/launcher.css" media="screen" rel="stylesheet" type="text/css" title="standard" />
2069         <link href="stylesheets/global-search.css" media="screen" rel="stylesheet" type="text/css" title="standard" />
2070 +       <link href="stylesheets/uscl.css" media="screen" rel="stylesheet" type="text/css" title="standard" />
2071  </head>
2072  <body>
2073  </body>
2074 Index: /usr/lib/luna/system/luna-applauncher/sources.json
2075 ===================================================================
2076 --- .orig/usr/lib/luna/system/luna-applauncher/sources.json
2077 +++ /usr/lib/luna/system/luna-applauncher/sources.json
2078 @@ -13,6 +13,24 @@
2079         },
2080         
2081         {
2082 +               "source": "app\/controllers\/uscl.js"
2083 +       },
2084 +
2085 +       {
2086 +               "source": "app\/controllers\/calculator.js"
2087 +       },
2088 +       
2089 +       {
2090 +               "source": "app\/controllers\/uscl-help-command-list.js",
2091 +               "scenes": "uscl-help-command-list"