Wire.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. if (!dojo._hasResource["dojox.wire.Wire"]) { // _hasResource checks added by
  2. // build. Do not use
  3. // _hasResource directly in your
  4. // code.
  5. dojo._hasResource["dojox.wire.Wire"] = true;
  6. dojo.provide("dojox.wire.Wire");
  7. dojo.require("dojox.wire._base");
  8. dojo.declare("dojox.wire.Wire", null, {
  9. // summary:
  10. // A default and base Wire to access an object property
  11. // description:
  12. // This class accesses a property of an object with a dotted notation
  13. // specified to 'property' property, such as "a.b.c", which identifies
  14. // a descendant property, "object.a.b.c".
  15. // Property names in the dotted notation may have an array index, such
  16. // as "a[0]", to identify an array element, literally, "object.a[0]".
  17. // When a notation start with an array index, such as "[0].a", it
  18. // specifies an array element of the root object (array),
  19. // "object[0].a".
  20. // This class also serves as a base class for other Wire classes,
  21. // preparing a root object and converting a return value, so that
  22. // sub-classes just can implement _getValue() and _setValue() called
  23. // from getValue() and setValue() implemented by this calss.
  24. _wireClass : "dojox.wire.Wire",
  25. constructor : function(/* Object */args) {
  26. // summary:
  27. // Initialize properties
  28. // description:
  29. // If 'converter' property is specified and is a string for
  30. // a converter class, an instanceof the converter class is
  31. // created.
  32. // args:
  33. // Arguments to initialize properties
  34. // object:
  35. // A root object (or another Wire to access a root object)
  36. // property:
  37. // A dotted notation to a descendant property
  38. // type:
  39. // A type of the return value (for the source Wire)
  40. // converter:
  41. // A converter object (or class name) to convert the return
  42. // value (for the source Wire)
  43. dojo.mixin(this, args);
  44. if (this.converter) {
  45. if (dojo.isString(this.converter)) {
  46. // First check the object tree for it. Might be defined
  47. // variable
  48. // name/global function (like a jsId, or just a function
  49. // name).
  50. var convertObject = dojo.getObject(this.converter);
  51. if (dojo.isFunction(convertObject)) {
  52. // We need to see if this is a pure function or an
  53. // object constructor...
  54. try {
  55. var testObj = new convertObject();
  56. if (testObj && !dojo.isFunction(testObj["convert"])) {
  57. // Looks like a 'pure' function...
  58. this.converter = {
  59. convert : convertObject
  60. };
  61. } else {
  62. this.converter = testObj;
  63. }
  64. } catch (e) {
  65. // Do if this fails.
  66. }
  67. } else if (dojo.isObject(convertObject)) {
  68. // It's an object, like a jsId ... see if it has a
  69. // convert function
  70. if (dojo.isFunction(convertObject["convert"])) {
  71. this.converter = convertObject;
  72. }
  73. }
  74. // No object with that name (Converter is still a string),
  75. // then look for a class that needs to be dynamically
  76. // loaded...
  77. if (dojo.isString(this.converter)) {
  78. var converterClass = dojox.wire
  79. ._getClass(this.converter);
  80. if (converterClass) {
  81. this.converter = new converterClass();
  82. } else {
  83. this.converter = undefined;
  84. }
  85. }
  86. } else if (dojo.isFunction(this.converter)) {
  87. this.converter = {
  88. convert : this.converter
  89. };
  90. }
  91. }
  92. },
  93. getValue : function(/* Object||Array */defaultObject) {
  94. // summary:
  95. // Return a value of an object
  96. // description:
  97. // This method first determins a root object as follows:
  98. // 1. If 'object' property specified,
  99. // 1.1 If 'object' is a Wire, its getValue() method is called to
  100. // obtain a root object.
  101. // 1.2 Otherwise, use 'object' as a root object.
  102. // 2. Otherwise, use 'defaultObject' argument.
  103. // 3. If 'property' is specified, it is used to get a property
  104. // value.
  105. // Then, if a sub-class implements _getValue() method, it is
  106. // called with the root object to get the return value.
  107. // Otherwise, the root object (typically, a property valye) is
  108. // used for the return value.
  109. // Finally, if 'type' property is specified, the return value is
  110. // converted to the specified primitive type ("string", "number",
  111. // "boolean" and "array").
  112. // If 'converter' property is specified, its convert() method is
  113. // called to convert the value.
  114. // defaultObject:
  115. // A default root object
  116. // returns:
  117. // A value found
  118. var object = undefined;
  119. if (dojox.wire.isWire(this.object)) {
  120. object = this.object.getValue(defaultObject);
  121. } else {
  122. object = (this.object || defaultObject);
  123. }
  124. if (this.property) {
  125. var list = this.property.split('.');
  126. for (var i in list) {
  127. if (!object) {
  128. return object; // anything (null, undefined, etc)
  129. }
  130. object = this._getPropertyValue(object, list[i]);
  131. }
  132. }
  133. var value = undefined;
  134. if (this._getValue) {
  135. value = this._getValue(object);
  136. } else {
  137. value = object;
  138. }
  139. if (value) {
  140. if (this.type) {
  141. if (this.type == "string") {
  142. value = value.toString();
  143. } else if (this.type == "number") {
  144. value = parseInt(value);
  145. } else if (this.type == "boolean") {
  146. value = (value != "false");
  147. } else if (this.type == "array") {
  148. if (!dojo.isArray(value)) {
  149. value = [value];
  150. }
  151. }
  152. }
  153. if (this.converter && this.converter.convert) {
  154. value = this.converter.convert(value, this); // optional
  155. // "this"
  156. // context
  157. }
  158. }
  159. return value; // anything
  160. },
  161. setValue : function(/* anything */value, /* Object||Array */defaultObject) {
  162. // summary:
  163. // Set a value to an object
  164. // description:
  165. // This method first determins a root object as follows:
  166. // 1. If 'object' property specified,
  167. // 1.1 If 'object' is a Wire, its getValue() method is called to
  168. // obtain a root object.
  169. // 1.2 Otherwise, use 'object' as a root object.
  170. // 2. Otherwise, use 'defaultObject' argument.
  171. // 3. If 'property' is specified, it is used to get a property
  172. // value.
  173. // Then, if a sub-class implements _setValue() method, it is
  174. // called with the root object and 'value' argument to set
  175. // the value.
  176. // Otherwise, 'value' is set to a property specified with
  177. // 'property' property.
  178. // If the root object is undefined and 'object' property is a Wire
  179. // and a new object is created and returned by _setValue() it is
  180. // set through 'object' (setValue() method).
  181. // value:
  182. // A value to set
  183. // defaultObject:
  184. // A default root object
  185. var object = undefined;
  186. if (dojox.wire.isWire(this.object)) {
  187. object = this.object.getValue(defaultObject);
  188. } else {
  189. object = (this.object || defaultObject);
  190. }
  191. var property = undefined;
  192. if (this.property) {
  193. if (!object) {
  194. if (dojox.wire.isWire(this.object)) {
  195. object = {};
  196. this.object.setValue(object, defaultObject);
  197. } else {
  198. throw new Error(this._wireClass
  199. + ".setValue(): invalid object");
  200. }
  201. }
  202. var list = this.property.split('.');
  203. var last = list.length - 1;
  204. for (var i = 0; i < last; i++) {
  205. var p = list[i];
  206. var o = this._getPropertyValue(object, p);
  207. if (!o) {
  208. o = {};
  209. this._setPropertyValue(object, p, o);
  210. }
  211. object = o;
  212. }
  213. property = list[last];
  214. }
  215. if (this._setValue) {
  216. if (property) {
  217. var o = this._getPropertyValue(object, property);
  218. if (!o) {
  219. o = {};
  220. this._setPropertyValue(object, property, o);
  221. }
  222. object = o;
  223. }
  224. var newObject = this._setValue(object, value);
  225. if (!object && newObject) {
  226. if (dojox.wire.isWire(this.object)) {
  227. this.object.setValue(newObject, defaultObject);
  228. } else {
  229. throw new Error(this._wireClass
  230. + ".setValue(): invalid object");
  231. }
  232. }
  233. } else {
  234. if (property) {
  235. this._setPropertyValue(object, property, value);
  236. } else {
  237. if (dojox.wire.isWire(this.object)) {
  238. this.object.setValue(value, defaultObject);
  239. } else {
  240. throw new Error(this._wireClass
  241. + ".setValue(): invalid property");
  242. }
  243. }
  244. }
  245. },
  246. _getPropertyValue : function(/* Object||Array */object, /* String */
  247. property) {
  248. // summary:
  249. // Return a property value of an object
  250. // description:
  251. // A value for 'property' of 'object' is returned.
  252. // If 'property' ends with an array index, it is used to indentify
  253. // an element of an array property.
  254. // If 'object' implements getPropertyValue(), it is called with
  255. // 'property' to obtain the property value.
  256. // If 'object' implements a getter for the property, it is called
  257. // to obtain the property value.
  258. // object:
  259. // A default root object
  260. // property:
  261. // A property name
  262. // returns:
  263. // A value found, otherwise 'undefined'
  264. var value = undefined;
  265. var i1 = property.indexOf('[');
  266. if (i1 >= 0) {
  267. var i2 = property.indexOf(']');
  268. var index = property.substring(i1 + 1, i2);
  269. var array = null;
  270. if (i1 === 0) { // object is array
  271. array = object;
  272. } else {
  273. property = property.substring(0, i1);
  274. array = this._getPropertyValue(object, property);
  275. if (array && !dojo.isArray(array)) {
  276. array = [array];
  277. }
  278. }
  279. if (array) {
  280. value = array[index];
  281. }
  282. } else if (object.getPropertyValue) {
  283. value = object.getPropertyValue(property);
  284. } else {
  285. var getter = "get" + property.charAt(0).toUpperCase()
  286. + property.substring(1);
  287. if (object[getter]) {
  288. value = object[getter]();
  289. } else {
  290. value = object[property];
  291. }
  292. }
  293. return value; // anything
  294. },
  295. _setPropertyValue : function(/* Object||Array */object, /* String */
  296. property, /* anything */value) {
  297. // summary:
  298. // Set a property value to an object
  299. // description:
  300. // 'value' is set to 'property' of 'object'.
  301. // If 'property' ends with an array index, it is used to indentify
  302. // an element of an array property to set the value.
  303. // If 'object' implements setPropertyValue(), it is called with
  304. // 'property' and 'value' to set the property value.
  305. // If 'object' implements a setter for the property, it is called
  306. // with 'value' to set the property value.
  307. // object:
  308. // An object
  309. // property:
  310. // A property name
  311. // value:
  312. // A value to set
  313. var i1 = property.indexOf('[');
  314. if (i1 >= 0) {
  315. var i2 = property.indexOf(']');
  316. var index = property.substring(i1 + 1, i2);
  317. var array = null;
  318. if (i1 === 0) { // object is array
  319. array = object;
  320. } else {
  321. property = property.substring(0, i1);
  322. array = this._getPropertyValue(object, property);
  323. if (!array) {
  324. array = [];
  325. this._setPropertyValue(object, property, array);
  326. }
  327. }
  328. array[index] = value;
  329. } else if (object.setPropertyValue) {
  330. object.setPropertyValue(property, value);
  331. } else {
  332. var setter = "set" + property.charAt(0).toUpperCase()
  333. + property.substring(1);
  334. if (object[setter]) {
  335. object[setter](value);
  336. } else {
  337. object[property] = value;
  338. }
  339. }
  340. }
  341. });
  342. }