Wire.js 12 KB

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