Stateful.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. define("dojo/Stateful", ["./_base/declare", "./_base/lang", "./_base/array"], function(declare, lang, array) {
  2. // module:
  3. // dojo/Stateful
  4. // summary:
  5. // TODOC
  6. return declare("dojo.Stateful", null, {
  7. // summary:
  8. // Base class for objects that provide named properties with optional getter/setter
  9. // control and the ability to watch for property changes
  10. // example:
  11. // | var obj = new dojo.Stateful();
  12. // | obj.watch("foo", function(){
  13. // | console.log("foo changed to " + this.get("foo"));
  14. // | });
  15. // | obj.set("foo","bar");
  16. postscript: function(mixin){
  17. if(mixin){
  18. lang.mixin(this, mixin);
  19. }
  20. },
  21. get: function(/*String*/name){
  22. // summary:
  23. // Get a property on a Stateful instance.
  24. // name:
  25. // The property to get.
  26. // returns:
  27. // The property value on this Stateful instance.
  28. // description:
  29. // Get a named property on a Stateful object. The property may
  30. // potentially be retrieved via a getter method in subclasses. In the base class
  31. // this just retrieves the object's property.
  32. // For example:
  33. // | stateful = new dojo.Stateful({foo: 3});
  34. // | stateful.get("foo") // returns 3
  35. // | stateful.foo // returns 3
  36. return this[name]; //Any
  37. },
  38. set: function(/*String*/name, /*Object*/value){
  39. // summary:
  40. // Set a property on a Stateful instance
  41. // name:
  42. // The property to set.
  43. // value:
  44. // The value to set in the property.
  45. // returns:
  46. // The function returns this dojo.Stateful instance.
  47. // description:
  48. // Sets named properties on a stateful object and notifies any watchers of
  49. // the property. A programmatic setter may be defined in subclasses.
  50. // For example:
  51. // | stateful = new dojo.Stateful();
  52. // | stateful.watch(function(name, oldValue, value){
  53. // | // this will be called on the set below
  54. // | }
  55. // | stateful.set(foo, 5);
  56. //
  57. // set() may also be called with a hash of name/value pairs, ex:
  58. // | myObj.set({
  59. // | foo: "Howdy",
  60. // | bar: 3
  61. // | })
  62. // This is equivalent to calling set(foo, "Howdy") and set(bar, 3)
  63. if(typeof name === "object"){
  64. for(var x in name){
  65. if(name.hasOwnProperty(x) && x !="_watchCallbacks"){
  66. this.set(x, name[x]);
  67. }
  68. }
  69. return this;
  70. }
  71. var oldValue = this[name];
  72. this[name] = value;
  73. if(this._watchCallbacks){
  74. this._watchCallbacks(name, oldValue, value);
  75. }
  76. return this; //dojo.Stateful
  77. },
  78. watch: function(/*String?*/name, /*Function*/callback){
  79. // summary:
  80. // Watches a property for changes
  81. // name:
  82. // Indicates the property to watch. This is optional (the callback may be the
  83. // only parameter), and if omitted, all the properties will be watched
  84. // returns:
  85. // An object handle for the watch. The unwatch method of this object
  86. // can be used to discontinue watching this property:
  87. // | var watchHandle = obj.watch("foo", callback);
  88. // | watchHandle.unwatch(); // callback won't be called now
  89. // callback:
  90. // The function to execute when the property changes. This will be called after
  91. // the property has been changed. The callback will be called with the |this|
  92. // set to the instance, the first argument as the name of the property, the
  93. // second argument as the old value and the third argument as the new value.
  94. var callbacks = this._watchCallbacks;
  95. if(!callbacks){
  96. var self = this;
  97. callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){
  98. var notify = function(propertyCallbacks){
  99. if(propertyCallbacks){
  100. propertyCallbacks = propertyCallbacks.slice();
  101. for(var i = 0, l = propertyCallbacks.length; i < l; i++){
  102. propertyCallbacks[i].call(self, name, oldValue, value);
  103. }
  104. }
  105. };
  106. notify(callbacks['_' + name]);
  107. if(!ignoreCatchall){
  108. notify(callbacks["*"]); // the catch-all
  109. }
  110. }; // we use a function instead of an object so it will be ignored by JSON conversion
  111. }
  112. if(!callback && typeof name === "function"){
  113. callback = name;
  114. name = "*";
  115. }else{
  116. // prepend with dash to prevent name conflicts with function (like "name" property)
  117. name = '_' + name;
  118. }
  119. var propertyCallbacks = callbacks[name];
  120. if(typeof propertyCallbacks !== "object"){
  121. propertyCallbacks = callbacks[name] = [];
  122. }
  123. propertyCallbacks.push(callback);
  124. return {
  125. unwatch: function(){
  126. propertyCallbacks.splice(array.indexOf(propertyCallbacks, callback), 1);
  127. }
  128. }; //Object
  129. }
  130. });
  131. });