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