source: [view]
hiddenFunctions = hiddenFunctions || {};
onInvoke = onInvoke || function(scope,obj,method,args){
// default implementation for onInvoke, just passes the call through
return obj[method].apply(scope,args);
};
function makeInvoker(scope,wrapped,i){
return function(){
// this is function used for all methods in the wrapper object
return onInvoke(scope,wrapped,i,arguments);
};
}
if(dojox.lang.lettableWin){ // create the vb class
var factory = dojox.lang.makeObservable;
factory.inc = (factory.inc || 0) + 1;
// create globals for the getters and setters so they can be accessed from the vbscript
var getName = "gettable_"+factory.inc;
dojox.lang.lettableWin[getName] = onRead;
var setName = "settable_"+factory.inc;
dojox.lang.lettableWin[setName] = onWrite;
var cache = {};
return function(wrapped){
if(wrapped.__observable){ // if it already has an observable, use that
return wrapped.__observable;
}
if(wrapped.data__){
throw new Error("Can wrap an object that is already wrapped");
}
// create the class
var props = [], i, l;
for(i in hiddenFunctions){
props.push(i);
}
var vbReservedWords = {type:1,event:1};
// find the unique signature for the class so we can reuse it if possible
for(i in wrapped){
if(i.match(/^[a-zA-Z][\w\$_]*$/) && !(i in hiddenFunctions) && !(i in vbReservedWords)){ //can only do properties with valid vb names/tokens and primitive values
props.push(i);
}
}
var signature = props.join(",");
var prop,clazz = cache[signature];
if(!clazz){
var tname = "dj_lettable_"+(factory.inc++);
var gtname = tname+"_dj_getter";
var cParts = [
"Class "+tname,
" Public data__" // this our reference to the original object
];
for(i=0, l=props.length; i prop = props[i];
var type = typeof wrapped[prop];
if(type == 'function' || hiddenFunctions[prop]){ // functions must go in regular properties for delegation:/
cParts.push(" Public " + prop);
}else if(type != 'object'){ // the getters/setters can only be applied to primitives
cParts.push(
" Public Property Let "+prop+"(val)",
" Call "+setName+"(me.data__,\""+prop+"\",val)",
" End Property",
" Public Property Get "+prop,
" "+prop+" = "+getName+"(me.data__,\""+prop+"\")",
" End Property");
}
}
cParts.push("End Class");
cParts.push(
"Function "+gtname+"()",
" Dim tmp",
" Set tmp = New "+tname,
" Set "+gtname+" = tmp",
"End Function");
dojox.lang.lettableWin.vbEval(cParts.join("\n"));
// Put the new class in the cache
cache[signature] = clazz = function(){
return dojox.lang.lettableWin.construct(gtname); // the class can't be accessed, only called, so we have to wrap it with a function
};
}
console.log("starting5");
var newObj = clazz();
newObj.data__ = wrapped;
console.log("starting6");
try {
wrapped.__observable = newObj;
} catch(e){ // some objects are not expando
}
for(i = 0, l = props.length; i < l; i++){
prop = props[i];
try {
var val = wrapped[prop];
}
catch(e){
console.log("error ",prop,e);
}
if(typeof val == 'function' || hiddenFunctions[prop]){ // we can make a delegate function here
newObj[prop] = makeInvoker(newObj,wrapped,prop);
}
}
return newObj;
};
}else{
return function(wrapped){ // do it with getters and setters
if(wrapped.__observable){ // if it already has an observable, use that
return wrapped.__observable;
}
var newObj = wrapped instanceof Array ? [] : {};
newObj.data__ = wrapped;
for(var i in wrapped){
if(i.charAt(0) != '_'){
if(typeof wrapped[i] == 'function'){
newObj[i] = makeInvoker(newObj,wrapped,i); // TODO: setup getters and setters so we can detect when this changes
}else if(typeof wrapped[i] != 'object'){
(function(i){
newObj.__defineGetter__(i,function(){
return onRead(wrapped,i);
});
newObj.__defineSetter__(i,function(value){
return onWrite(wrapped,i,value);
});
})(i);
}
}
}
for(i in hiddenFunctions){
newObj[i] = makeInvoker(newObj,wrapped,i);
}
wrapped.__observable = newObj;
return newObj;
};
}