[483] | 1 | dojo.provide("dojox.lang.oo.mixin"); |
---|
| 2 | |
---|
| 3 | dojo.experimental("dojox.lang.oo.mixin"); |
---|
| 4 | |
---|
| 5 | dojo.require("dojox.lang.oo.Filter"); |
---|
| 6 | dojo.require("dojox.lang.oo.Decorator"); |
---|
| 7 | |
---|
| 8 | (function(){ |
---|
| 9 | var oo = dojox.lang.oo, Filter = oo.Filter, Decorator = oo.Decorator, empty = {}, |
---|
| 10 | defaultFilter = function(name){ return name; }, |
---|
| 11 | defaultDecorator = function(name, newValue, oldValue){ return newValue; }, |
---|
| 12 | defaultMixer = function(target, name, newValue, oldValue){ target[name] = newValue; }, |
---|
| 13 | defaults = {}, // for the internal use in the mixin() |
---|
| 14 | extraNames = dojo._extraNames, extraLen = extraNames.length, |
---|
| 15 | |
---|
| 16 | applyDecorator = oo.applyDecorator = function(decorator, name, newValue, oldValue){ |
---|
| 17 | // summary: |
---|
| 18 | // applies a decorator unraveling all embedded decorators |
---|
| 19 | // decorator: Function |
---|
| 20 | // top-level decorator to apply |
---|
| 21 | // name: String |
---|
| 22 | // name of the property |
---|
| 23 | // newValue: Object |
---|
| 24 | // new value of the property |
---|
| 25 | // oldValue: Object |
---|
| 26 | // old value of the property |
---|
| 27 | // returns: Object |
---|
| 28 | // returns the final value of the property |
---|
| 29 | if(newValue instanceof Decorator){ |
---|
| 30 | var d = newValue.decorator; |
---|
| 31 | newValue = applyDecorator(decorator, name, newValue.value, oldValue); |
---|
| 32 | return d(name, newValue, oldValue); |
---|
| 33 | } |
---|
| 34 | return decorator(name, newValue, oldValue); |
---|
| 35 | }; |
---|
| 36 | |
---|
| 37 | /*===== |
---|
| 38 | dojox.lang.oo.__MixinDefaults = { |
---|
| 39 | // summary: |
---|
| 40 | // a dict of default parameters for dojox.lang.oo._mixin |
---|
| 41 | // decorator: Function |
---|
| 42 | // a decorator function to be used in absence of other decorators |
---|
| 43 | // filter: Function |
---|
| 44 | // a filter function to be used in absence of other filters |
---|
| 45 | // mixer: Function |
---|
| 46 | // a mixer function to be used to mix in new properties |
---|
| 47 | }; |
---|
| 48 | =====*/ |
---|
| 49 | |
---|
| 50 | oo.__mixin = function(target, source, decorator, filter, mixer){ |
---|
| 51 | // summary: |
---|
| 52 | // mixes in two objects processing decorators and filters |
---|
| 53 | // target: Object |
---|
| 54 | // target to receive new/updated properties |
---|
| 55 | // source: Object |
---|
| 56 | // source of properties |
---|
| 57 | // defaults: dojox.lang.oo.__MixinDefaults? |
---|
| 58 | // default functions for various aspects of mixing |
---|
| 59 | // returns: Object |
---|
| 60 | // target |
---|
| 61 | |
---|
| 62 | var name, targetName, prop, newValue, oldValue, i; |
---|
| 63 | |
---|
| 64 | // start mixing in properties |
---|
| 65 | for(name in source){ |
---|
| 66 | prop = source[name]; |
---|
| 67 | if(!(name in empty) || empty[name] !== prop){ |
---|
| 68 | targetName = filter(name, target, source, prop); |
---|
| 69 | if(targetName && (!(targetName in target) || !(targetName in empty) || empty[targetName] !== prop)){ |
---|
| 70 | // name is accepted |
---|
| 71 | oldValue = target[targetName]; |
---|
| 72 | newValue = applyDecorator(decorator, targetName, prop, oldValue); |
---|
| 73 | if(oldValue !== newValue){ |
---|
| 74 | mixer(target, targetName, newValue, oldValue); |
---|
| 75 | } |
---|
| 76 | } |
---|
| 77 | } |
---|
| 78 | } |
---|
| 79 | if(extraLen){ |
---|
| 80 | for(i = 0; i < extraLen; ++i){ |
---|
| 81 | name = extraNames[i]; |
---|
| 82 | // repeating the body above |
---|
| 83 | prop = source[name]; |
---|
| 84 | if(!(name in empty) || empty[name] !== prop){ |
---|
| 85 | targetName = filter(name, target, source, prop); |
---|
| 86 | if(targetName && (!(targetName in target) || !(targetName in empty) || empty[targetName] !== prop)){ |
---|
| 87 | // name is accepted |
---|
| 88 | oldValue = target[targetName]; |
---|
| 89 | newValue = applyDecorator(decorator, targetName, prop, oldValue); |
---|
| 90 | if(oldValue !== newValue){ |
---|
| 91 | mixer(target, targetName, newValue, oldValue); |
---|
| 92 | } |
---|
| 93 | } |
---|
| 94 | } |
---|
| 95 | } |
---|
| 96 | } |
---|
| 97 | |
---|
| 98 | return target; // Object |
---|
| 99 | }; |
---|
| 100 | |
---|
| 101 | oo.mixin = function(target, source){ |
---|
| 102 | // summary: |
---|
| 103 | // mixes in two or more objects processing decorators and filters |
---|
| 104 | // using defaults as a fallback |
---|
| 105 | // target: Object |
---|
| 106 | // target to receive new/updated properties |
---|
| 107 | // source: Object... |
---|
| 108 | // source of properties, more than one source is allowed |
---|
| 109 | // returns: Object |
---|
| 110 | // target |
---|
| 111 | |
---|
| 112 | var decorator, filter, i = 1, l = arguments.length; |
---|
| 113 | for(; i < l; ++i){ |
---|
| 114 | source = arguments[i]; |
---|
| 115 | if(source instanceof Filter){ |
---|
| 116 | filter = source.filter; |
---|
| 117 | source = source.bag; |
---|
| 118 | }else{ |
---|
| 119 | filter = defaultFilter; |
---|
| 120 | } |
---|
| 121 | if(source instanceof Decorator){ |
---|
| 122 | decorator = source.decorator; |
---|
| 123 | source = source.value; |
---|
| 124 | }else{ |
---|
| 125 | decorator = defaultDecorator; |
---|
| 126 | } |
---|
| 127 | oo.__mixin(target, source, decorator, filter, defaultMixer); |
---|
| 128 | } |
---|
| 129 | return target; // Object |
---|
| 130 | }; |
---|
| 131 | })(); |
---|