home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2006 May / PCWMAY06.iso / Software / Toolkit / Songbird 0.1 / Songbird_0_1_0.exe / chrome / content / sbIDataRemote.js < prev    next >
Encoding:
JavaScript  |  2006-02-07  |  14.2 KB  |  531 lines

  1. /*
  2. //
  3. // BEGIN SONGBIRD GPL
  4. // 
  5. // This file is part of the Songbird web player.
  6. //
  7. // Copyright⌐ 2006 Pioneers of the Inevitable LLC
  8. // http://songbirdnest.com
  9. // 
  10. // This file may be licensed under the terms of of the
  11. // GNU General Public License Version 2 (the ôGPLö).
  12. // 
  13. // Software distributed under the License is distributed 
  14. // on an ôAS ISö basis, WITHOUT WARRANTY OF ANY KIND, either 
  15. // express or implied. See the GPL for the specific language 
  16. // governing rights and limitations.
  17. //
  18. // You should have received a copy of the GPL along with this 
  19. // program. If not, go to http://www.gnu.org/licenses/gpl.html
  20. // or write to the Free Software Foundation, Inc., 
  21. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. // 
  23. // END SONGBIRD GPL
  24. //
  25.  */
  26.  
  27. //
  28. // sbIDataRemote wrapper
  29. //
  30. //  This object provides the ability to set key-value pairs
  31. //  into a global "data store," and to have various callback
  32. //  effects occur when anyone changes an observed value.
  33. //
  34. //  The callback binding can be placed on a dom element to
  35. //  change its properties or attributes based upon the value
  36. //  (either directly, or as a boolean, and/or as the result
  37. //  of a given evaluation expression).
  38. //
  39. //  The mozilla preferences system is used as the underlying
  40. //  data storage layer to power this interface.  Because the
  41. //  preferences are available to all open windows in xulrunner,
  42. //  these data remotes should will function as globals across 
  43. //  the application.  This is both powerful and dangerous, and
  44. //  while this interface is available to all, everyone should
  45. //  be very careful to properly namespace their data strings.
  46. //
  47. //  SBDataBindElementProperty Param List:
  48. //   key  - The data ID to bind upon
  49. //   elem - The element ID to be bound
  50. //   attr - The name of the property or attribute to change
  51. //   bool - Optionally assign the data as BOOLEAN data (true/false props, "true"/"false" attrs)
  52. //   not  - Optionally assign the data as a boolean NOT of the value
  53. //   eval - Optionally apply an eval string where `value = eval( eval_string );`
  54.  
  55. function sbIDataRemote( key, root )
  56. {
  57.   try
  58.   {
  59.     //
  60.     // Data
  61.     //
  62.  
  63.     // Set the strings
  64.     if ( root = null )
  65.     {
  66.       this.m_Root = "songbird.dataremotes." + key; // Use key in root string, makes unique observer lists per key (big but fast?).
  67.       this.m_Key = key;
  68.     }
  69.     else
  70.     {
  71.       // If we're specifying a root, just obey what's asked for.
  72.       this.m_Root = root;
  73.       this.m_Key = key;
  74.     }
  75.     
  76.     // Set the callbacks
  77.     this.m_CallbackFunction = null;
  78.     this.m_CallbackObject = null;
  79.     this.m_CallbackPropery = null;
  80.     this.m_CallbackAttribute = null;
  81.     this.m_CallbackBool = false;
  82.     this.m_CallbackNot = false;
  83.     this.m_CallbackEval = "";
  84.     
  85.     // Go connect to the prefs object acting as the data representation of the key.
  86.     prefs_service = SBBindInterface( null, "@mozilla.org/preferences;1", Components.interfaces.nsIPrefService, true );
  87.     if ( prefs_service )
  88.     {
  89.       // Ask for the branch.
  90.       this.m_Prefs = prefs_service.getBranch( this.m_Root );
  91.       if ( this.m_Prefs )
  92.       {
  93.         this.m_Prefs = this.m_Prefs.QueryInterface( Components.interfaces.nsIPrefBranch2 );
  94.       }
  95.     }
  96.     
  97.     //
  98.     // Methods
  99.     //
  100.  
  101.     // Query Interface - So we can act as an observer object.
  102.     this.QueryInterface = function( aIID )
  103.     {
  104.       if (!aIID.equals(Components.interfaces.nsIObserver) &&
  105.           !aIID.equals(Components.interfaces.nsISupportsWeakReference) &&
  106.           !aIID.equals(Components.interfaces.nsISupports)) 
  107.       {
  108.         throw Components.results.NS_ERROR_NO_INTERFACE;
  109.       }
  110.       
  111.       return this;
  112.     };
  113.     
  114.     // observe - Called when someone updates the remote data
  115.     this.observe = function( subject, topic, data )
  116.     { 
  117.       try
  118.       {
  119.         if ( this.m_Prefs )
  120.         {
  121.           if ( data == this.m_Key )
  122.           {
  123.             if ( this.m_SuppressFirst )
  124.             {
  125.               this.m_SuppressFirst = false;
  126.               return;
  127.             }
  128.             // Get the value (why isn't this a param?)
  129.             var value = this.GetValue();
  130.             
  131.             // Run the optional evaluation
  132.             if ( this.m_CallbackEval.length )
  133.             {
  134.               value = eval( this.m_CallbackEval );
  135.             }
  136.             
  137.             // Handle boolean and not states
  138.             if ( this.m_CallbackBool )
  139.             {
  140.               // If we're not bool before,
  141.               if( typeof( value ) != "boolean" )
  142.               {
  143.                 if ( value == "true" )
  144.                 {
  145.                   value = true;
  146.                 }
  147.                 else if ( value == "false" )
  148.                 {
  149.                   value = false;
  150.                 }
  151.                 else
  152.                 {
  153.                   value = ( this.MakeIntValue( value ) != 0 );
  154.                 }
  155.               }
  156.               // ...we are now!
  157.               if ( this.m_CallbackNot )
  158.               {
  159.                 value = ! value;
  160.               }
  161.             }
  162.             
  163. /*            
  164.             if ( this.m_Key == "playlist.repeat" )
  165.             {
  166.               var obj = "No object";
  167.               if ( this.m_CallbackObject )
  168.               {
  169.                 obj = this.m_CallbackObject.id;
  170.               }
  171.               alert( obj + " - " + this.m_CallbackPropery + " - " + this.m_CallbackAttribtue + " - " + value );
  172.             }  
  173. */
  174.             
  175.             // Handle callback states
  176.             if ( this.m_CallbackFunction )
  177.             {
  178.               // Call the callback function
  179.               this.m_CallbackFunction( value );
  180.             }
  181.             else if ( this.m_CallbackObject && this.m_CallbackPropery )
  182.             {
  183.               // Set the callback object's property
  184.               this.m_CallbackObject[ this.m_CallbackPropery ] = value;
  185.             }
  186.             else if ( this.m_CallbackObject && this.m_CallbackAttribute )
  187.             {
  188.               var val_str = value;
  189.               // If bool-type, convert to string.
  190.               if ( this.m_CallbackBool )
  191.               {
  192.                 if ( value )
  193.                 {
  194.                   val_str = "true";
  195.                 }
  196.                 else
  197.                 {
  198.                   val_str = "false";
  199.                 }
  200.               }
  201.               // Set the callback object's attribute
  202.               this.m_CallbackObject.setAttribute( this.m_CallbackAttribute, val_str );
  203.             }
  204.           }
  205.         }
  206.       }
  207.       catch( err ) 
  208.       {
  209.         alert( err );
  210.       }
  211.     };
  212.     
  213.     this.Unbind = function()
  214.     {
  215.       try
  216.       {
  217.         if ( this.m_Prefs )
  218.         {
  219.           // Clear ourselves as an observer.
  220.           this.m_Prefs.removeObserver( this.m_Key, this );
  221.         }
  222.       }
  223.       catch ( err )
  224.       {
  225.         alert( err );
  226.       }
  227.     }
  228.     
  229.     this.BindEventFunction = function( func )
  230.     {
  231.       this.BindCallbackFunction( func, true );
  232.     }
  233.     
  234.     this.BindCallbackFunction = function( func, suppress_first )
  235.     {
  236.       try
  237.       {
  238.         if ( this.m_Prefs )
  239.         {
  240.           // Don't call the function the first time it is bound
  241.           this.m_SuppressFirst = suppress_first;
  242.         
  243.           // Clear and reinsert ourselves as an observer.
  244.           this.m_Prefs.removeObserver( this.m_Key, this );
  245.           this.m_Prefs.addObserver( this.m_Key, this, true );
  246.  
  247.           // Now we're observing for a function.        
  248.           this.m_CallbackFunction = func;
  249.           this.m_CallbackObject = null;
  250.           this.m_CallbackPropery = null;
  251.           this.m_CallbackAttribute = null;
  252.           this.m_CallbackBool = false;
  253.           this.m_CallbackNot = false;
  254.           this.m_CallbackEval = "";
  255.           
  256.           // Set the value once
  257.           this.observe( null, null, this.m_Key );
  258.             
  259. /*            
  260.           if ( this.m_Key == "playlist.repeat" )
  261.           {
  262.             var obj = "No object";
  263.             if ( this.m_CallbackObject )
  264.             {
  265.               obj = this.m_CallbackObject.id;
  266.             }
  267.             alert( obj + " - " + this.m_CallbackPropery + " - " + this.m_CallbackAttribtue + " - " + value );
  268.           }  
  269. */          
  270.         }
  271.       }
  272.       catch ( err )
  273.       {
  274.         alert( err );
  275.       }
  276.     };
  277.     
  278.     this.BindCallbackProperty = function( obj, prop, bool, not, eval )
  279.     {
  280.       try
  281.       {
  282.         if ( ! bool )
  283.         {
  284.           bool = false;
  285.         }
  286.         if ( ! not )
  287.         {
  288.           not = false;
  289.         }
  290.         if ( ! eval )
  291.         {
  292.           eval = "";
  293.         }
  294.         if ( this.m_Prefs )
  295.         {
  296.           // Clear and reinsert ourselves as an observer.
  297.           this.m_Prefs.removeObserver( this.m_Key, this );
  298.           this.m_Prefs.addObserver( this.m_Key, this, true );
  299.           
  300.           // Now we're observing for an object's property.        
  301.           this.m_CallbackFunction = null;
  302.           this.m_CallbackObject = obj;
  303.           this.m_CallbackPropery = prop;
  304.           this.m_CallbackAttribute = null;
  305.           this.m_CallbackBool = bool;
  306.           this.m_CallbackNot = not;
  307.           this.m_CallbackEval = eval;
  308.           
  309.           // Set the value once
  310.           this.observe( null, null, this.m_Key );
  311.  
  312. /*            
  313.           if ( this.m_Key == "playlist.repeat" )
  314.           {
  315.             var obj = "No object";
  316.             if ( this.m_CallbackObject )
  317.             {
  318.               obj = this.m_CallbackObject.id;
  319.             }
  320.             alert( obj + " - " + this.m_CallbackPropery + " - " + this.m_CallbackAttribtue + " - " + value );
  321.           }  
  322. */          
  323.         }
  324.       }
  325.       catch ( err )
  326.       {
  327.         alert( err );
  328.       }
  329.     };
  330.     
  331.     this.BindCallbackAttribute = function( obj, attr, bool, not, eval )
  332.     {
  333.       try
  334.       {
  335.         if ( ! bool )
  336.         {
  337.           bool = false;
  338.         }
  339.         if ( ! not )
  340.         {
  341.           not = false;
  342.         }
  343.         if ( ! eval )
  344.         {
  345.           eval = "";
  346.         }
  347.         if ( this.m_Prefs )
  348.         {
  349.           // Clear and reinsert ourselves as an observer.
  350.           this.m_Prefs.removeObserver( this.m_Key, this );
  351.           this.m_Prefs.addObserver( this.m_Key, this, true );
  352.           
  353.           // Now we're observing for an object's attribute.        
  354.           this.m_CallbackFunction = null;
  355.           this.m_CallbackObject = obj;
  356.           this.m_CallbackPropery = null;
  357.           this.m_CallbackAttribute = attr;
  358.           this.m_CallbackBool = bool;
  359.           this.m_CallbackNot = not;
  360.           this.m_CallbackEval = eval;
  361.           
  362.           // Set the value once
  363.           this.observe( null, null, this.m_Key );
  364.         }
  365.       }
  366.       catch ( err )
  367.       {
  368.         alert( err );
  369.       }
  370.     };
  371.  
  372.     // SetValue - Put the value into the data store, alert everyone watching this data    
  373.     this.SetValue = function( value )
  374.     {
  375.       // Clear the value
  376.       if ( value == null )
  377.       {
  378.         value = "";
  379.       }
  380.       // Convert from boolean to intstring.
  381.       if( typeof( value ) == "boolean" )
  382.       {
  383.         if ( value )
  384.         {
  385.           value = "1";
  386.         }
  387.         else
  388.         {
  389.           value = "0";
  390.         }
  391.       }
  392.       try
  393.       {
  394.         if ( this.m_Prefs )
  395.         {
  396.           // Make a unicode string, assign the value, set it into the preferences.
  397.           var sString = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
  398.           sString.data = value;
  399.           this.m_Prefs.setComplexValue( this.m_Key, Components.interfaces.nsISupportsString, sString );
  400.         }
  401.       }
  402.       catch ( err )
  403.       {
  404.         alert( err );
  405.       }
  406.     };
  407.  
  408.     // GetValue - Get the value from the data store
  409.     this.GetValue = function()
  410.     {
  411.       var retval = "";
  412.       try
  413.       {
  414.         if ( this.m_Prefs )
  415.         {
  416.           if ( this.m_Prefs.prefHasUserValue( this.m_Key ) )
  417.           {
  418.             retval = this.m_Prefs.getComplexValue( this.m_Key, Components.interfaces.nsISupportsString ).data;
  419.           }
  420.         }
  421.       }
  422.       catch ( err )
  423.       {
  424.         alert( err );
  425.       }
  426.       return retval;
  427.     };
  428.     
  429.     // GetIntValue - Get the value from the data store as an int
  430.     this.GetIntValue = function()
  431.     {
  432.       return this.MakeIntValue( this.GetValue() );
  433.     }
  434.     
  435.     // MakeIntValue - Get the value from the data store as an int
  436.     this.MakeIntValue = function( value )
  437.     {
  438.       var retval = 0;
  439.       try
  440.       {
  441.         if ( value && value.length )
  442.         {
  443.           retval = parseInt( value );
  444.         }
  445.       }
  446.       catch ( err )
  447.       {
  448.         alert( err );
  449.       }
  450.       return retval;
  451.     };
  452.  
  453.   }
  454.   catch ( err )
  455.   {
  456.     alert( err );
  457.   }
  458.  
  459.   return this;
  460. }
  461.  
  462. function SBDataBindElementProperty( key, elem, prop, bool, not, eval )
  463. {
  464.   var retval = null;
  465.   try
  466.   {
  467.     var obj = document.getElementById( elem );
  468.     if ( obj )
  469.     {
  470.       retval = new sbIDataRemote( key );
  471.       retval.BindCallbackProperty( obj, prop, bool, not, eval );
  472.     }
  473.     else
  474.     {
  475.       alert( "Can't find " + elem );
  476.     }
  477.   }
  478.   catch ( err )
  479.   {
  480.     alert( err );
  481.   }
  482.   return retval;  
  483. }
  484. function SBDataBindElementAttribute( key, elem, attr, bool, not, eval )
  485. {
  486.   var retval = null;
  487.   try
  488.   {
  489.     var obj = document.getElementById( elem );
  490.     if ( obj )
  491.     {
  492.       retval = new sbIDataRemote( key );
  493.       retval.BindCallbackAttribute( obj, attr, bool, not, eval );
  494.     }
  495.     else
  496.     {
  497.       alert( "Can't find " + elem );
  498.     }
  499.   }
  500.   catch ( err )
  501.   {
  502.     alert( err );
  503.   }
  504.   return retval;  
  505. }
  506.  
  507. // Some XBL contexts don't create an object properly outside this script.
  508. function SBDataGetValue( key )
  509. {
  510.   var data = new sbIDataRemote( key );
  511.   return data.GetValue();
  512. }
  513.  
  514. function SBDataGetIntValue( key )
  515. {
  516.   var data = new sbIDataRemote( key );
  517.   return data.GetIntValue();
  518. }
  519.  
  520. function SBDataSetValue( key, value )
  521. {
  522.   var data = new sbIDataRemote( key );
  523.   return data.SetValue( value );
  524. }
  525.  
  526. function SBDataFireEvent( key )
  527. {
  528.   var data = new sbIDataRemote( key );
  529.   return data.SetValue( data.GetIntValue() + 1 );
  530. }
  531.