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