      1 if (!pockets) {
      2   /**
      3    * @namespace
      4    */
      5   var pockets = {};
      6 }
      7
      8 /**
      9  * @deprecated Pockets is deprecated, use pockets (all lowercase) instead.
     10  */
     11 var Pockets = pockets;
     12
     13 // @ignore
     14 pockets.inTestRunner = function() {
     15   return false;
     16 };
     17
     18 /**
     19  * It's a little Crockford to help with #inheritsFrom
     20  *  @ignore
     21  * @private
     22  */
     23 pockets.inherit = function(childClass, parentClass) {
     24   var subclass = function() {
     25   };
     26   subclass.prototype = parentClass.prototype;
     27   childClass.prototype = new subclass;
     28 };
     29
     30 /**
     31  * @ignore
     32  * @private
     33  */
     34 pockets.inject = function(target, contextFn, name) {
     35   target.__defineGetter__(name, function() {
     36     var context = contextFn.call(this);
     37     if (!context) {
     38       throw new Error('no injection context while calling getter for ' + name);
     39     }
     40     return context[name];
     41   });
     42   target.__defineSetter__(name, function(value) {
     43     if (pockets.inTestRunner()) {
     44       var valueHolder = value;
     45       this.__defineGetter__(name, function() {
     46         return valueHolder;
     47       });
     48
     49       this.__defineSetter__(name, function(value) {
     50         valueHolder = value;
     51       });
     52     } else {
     53       throw "Please use setInjectable to add or replace properties on the injectionContext.";
     54     }
     55     ;
     56   });
     57 };
     58
     59 /**
     60  * @ignore
     61  * @private
     62  */
     63 pockets.setInjectable = function(contextFn, name, value) {
     64   contextFn()[name] = value;
     65 };
     66
     67 /**
     68  * Register Pockets globals and extend JavaScript global objects.  Needed so that Pockets works.
     69  */
     70 pockets.registerGlobals = function() {
     71   /**
     72    * Sets the parent/child relationship between classes for applications that choose not to use
     73    * Prototype.js's Class.create() to define classes.
     74    *
     75    * Used after you declare the child class's constructor like this:
     76    *
     77    * in foo.js:
     78    *
     79    *   function Foo() { this.baz = 'quux';}
     80    *
     81    * in bar.js:
     82    *
     83    *   function Bar() { this.baz = 'corge';}
     84    *   Bar.inheritsFrom(Foo);
     85    *
     86    * @param parentClass
     87    */
     88   Function.prototype.inheritsFrom = function(parentClass) {
     89     pockets.inherit(this, parentClass);
     90   };
     91
     92   /**
     93    *  Returns a Pockets application 'injection context', an object that is used in lieu of polluting the global namespace.
     94    *
     95    *  Applications need "global" data - specifically, your Mojo Scene Assistants will want/need to get access to top-level/app-wide
     96    *  data.  Pockets offers a way to make this data available via the technique of the injecttion context.  The app defines
     97    *  the location of this data once, and then other classes can declare they want access to it with #inject method.
     98    *
     99    *  The complicated, less common case is that you need to use something other than your AppAssistant to store your
    100    *  injectables.  If this applies, then let Pockets know about your context by calling Function#injectionContext with a
    101    *  function that returns this object.  You can then use Function#inject and Function#setInjectible to declare access
    102    *  to properties & set properties respectively.
    103    *
    104    *  @example
    105    *  // Simple example definition
    106    *
    107    *  // Delcare in your AppAssistant
    108    *  function AppAssistant() {
    109    *    ...
    110    *    this.injectionContext = {
    111    *      foo: 1,
    112    *      bar: 2
    113    *    };
    114    *    ...
    115    *   }
    116    *
    117    *  @example
    118    *  // Complex definition (noted contrived example)
    119    *
    120    *  var myGlobals() {
    121    *    this.foo = 1;
    122    *    this.bar = 2;
    123    *  }
    124    *
    125    *  maybeStageAssistant.injectionContext(function() {return myGlobals;}
    126    *
    127    *   @example
    128    *   // How to use your injection context
    129    *   function Foo() {}
    130    *   Foo.inject('bar');
    131    *
    132    *   Foo.prototype.someFunc = function() {
    133    *     ...
    134    *     var globalVar = this.bar;       // get the 'global' value
    135    *     this.setInjectible('bar', 17);  // set the 'global' value
    136    *     ...
    137    *
    138    * @see Function#inject, Function#setInjectable
    139    * @param contextFn
    140    */
    141   Function.prototype.injectionContext = function(contextFn) {
    142     this.prototype.__pockets__injectionContextFn__ = contextFn;
    143     return this;
    144   };
    145
    146   /**
    147    * When using Pockets' Injection Context, gives a class access to a property of the injection context as if it were
    148    *  a property on the current class.
    149    *
    150    * @example
    151    * function Foo() { }
    152    * Foo.inject('bar');
    153    *
    154    * Foo.prototype.someFunc = function() {
    155    *   ...
    156    *   console.log(this.bar); // returns bar from the Injection Context
    157    *   ...
    158    * }
    159    *
    160    * @param fieldName
    161    */
    162   Function.prototype.inject = function(fieldName) {
    163     this.ensureInjectionContext();
    164     pockets.inject(this.prototype, this.prototype.__pockets__injectionContextFn__, fieldName);
    165     return this;
    166   };
    167
    168   /**
    169    * @ignore
    170    * @private
    171    */
    172   Function.prototype.ensureInjectionContext = function() {
    173     if (!this.prototype.__pockets__injectionContextFn__) {
    174       this.prototype.__pockets__injectionContextFn__ = function() {
    175         return Mojo.Controller.getAppController().assistant.injectionContext;
    176       };
    177     }
    178   };
    179
    180   /**
    181    * When using a Pockets injection context for 'app-global' data, you must use this setter function
    182    * in order to set the value of the injected property.
    183    *
    184    * @example
    185    * function Foo() { }
    186    * Foo.inject('bar');
    187    *
    188    * Foo.prototype.anotherFunc = function() {
    189    *   ...
    190    *   this.bar = 'baz'; // FAIL
    191    *   ...
    192    *   this.setInjectable('bar', 'baz'); // correctly set the injected property
    193    *   ...
    194    * }
    195    *
    196    * @param fieldName property of the injection context to set
    197    * @param value new value
    198    */
    199   Function.prototype.setInjectable = function(fieldName, value) {
    200     this.ensureInjectionContext();
    201     pockets.setInjectable(this.prototype.__pockets__injectionContextFn__, fieldName, value);
    202     return this;
    203   };
    204
    205   /**
    206    * Acts like Protoype.js's each() function on an Array, but allows for asynchronous actions.
    207    *
    208    * @param {Function} doer the function which is passed each element in turn; this function can contain asynchronous calls, say to Mojo apis
    209    * @param {Function} onComplete  a function that will be called only after *all* of the calls to doer are done
    210    */
    211   Array.prototype.eachAsync = function(doer, onComplete) {
    212     return pockets.collections.eachAsync(this, doer, onComplete);
    213   };
    214
    215   /**
    216    * Acts like Protoype.js's collect() function on an Array, but allows for asynchronous actions.
    217    *
    218    * @param doer {Function} the function which is passed each element in turn; this function can contain asynchronous calls, say to Mojo apis;
    219    *                  expected to return a resultant value
    220    * @param onComplete {Function} a function that will be called only after *all* of the calls to doer are done; is called with an Array that is the collected return values, in correct position order
    221    */
    222   Array.prototype.collectAsync = function(doer, onComplete) {
    223     return pockets.collections.collectAsync(this, doer, onComplete);
    224   };
    225
    226   /**
    227    * replace all items in an Array with the items from the Array passed in
    228    *
    229    * @param newContents {Array} the Array of replacement values
    230    * @returns {Array} transformed Array, now containing only the new values
    231    */
    232   Array.prototype.replaceAll = function(newContents) {
    233     return pockets.collections.array.replaceAll(this, newContents);
    234   };
    235
    236   /**
    237    * Removes the given item from the Array, if it exists
    238    *
    239    * @param item {Object} to remove
    240    * @returns {Array} the transformed Array
    241    */
    242    Array.prototype.remove = function(item) {
    243     return pockets.collections.array.remove(this, item);
    244   };
    245 };
    246
    247 // todo: should this really be called here, or should it be at the discretion of the app? [xw 20090312]
    248 // @ignore
    249 pockets.registerGlobals();
    250
    251 pockets.listWidget = function(options) {
    252   return new pockets.ui.ListWidget(options);
    253 };
    254
    255 pockets.nestedPropertyExists = function(o, expression) {
    256   var nodes = expression.split('.');
    257   for (var i = 0; i < nodes.length; i++) {
    258     if (o === null) return false;
    259     o = o[nodes[i]];
    260     if (o === undefined) return false;
    261   }
    262   return true;
    263 };
    264
    265 pockets.readFile = function(filePath) {
    266   var contents;
    267   contents = Mojo.View._renderNamedTemplate('../../' + filePath, {});
    268   if (contents.match(/template load failed/)) {
    269     throw new Error("couldn't read file " + Mojo.appPath + filePath);
    270   }
    271   return contents;
    272 };
    273
    274 /**
    275  * @ignore
    276  * @private
    277  */
    278 pockets.getVersionString = function () {
    279   return window.PalmSystem.version;
    280 };
    281
    282 /**
    283  * Returns true if your application is currently running in Palm Host
    284  */
    285 pockets.inPalmHost = function() {
    286   return !!pockets.getVersionString().match('mojo-host');
    287 };
    288
    289 /**
    290  * Returns true if your application is currently running in the emulator
    291  */
    292 pockets.inEmulator = function() {
    293   return !!pockets.getVersionString().match('desktop');
    294 };
    295
    296 /**
    297  * Returns true if your application is currently running on device
    298  */
    299 pockets.inDevice = function() {
    300   return !!pockets.getVersionString().match('device');
    301 };