elation
Version:
Elation Javascript Component Framework
186 lines (177 loc) • 7.02 kB
JavaScript
elation.require(['utils.events'], function() {
elation.define('proxy', {
_proxytarget: null,
_proxydefs: {},
_proxyobj: null,
_proxypassthrough: true,
_scriptprops: {},
_construct: function(target, defs, passthrough) {
this._proxytarget = target;
if (defs) this._proxydefs = defs;
var self = this;
var proxydefs = this._proxydefs,
scriptprops = {};//this._scriptprops;
var changetimer = false,
proxyobj = this._proxyobj;
function setProxyChangeTimer(data) {
// FIXME - it seems like we're not actually using this, and it's incredibly expensive
// to throw this many events, especially since many properties tend to change
// at the same time. Disabling for now, we'll see if anything breaks...
//elation.events.fire({element: proxyobj, type: 'proxy_change', data: data});
}
function executeCallback(fn, target, args) {
try {
if (elation.utils.isString(fn)) {
(function(fn) {
var event = args[0];
return eval(fn);
}).call(self._proxyobj, fn);
} else if (fn instanceof Function) {
fn.apply(target, args);
}
} catch (e) {
console.log(e.stack);
}
}
var getProxyValue = function(target, name) {
if (name == '_proxydefs') return proxydefs;
if (proxydefs && proxydefs.hasOwnProperty(name)) {
var def = proxydefs[name];
var value;
if (def[1] && def[1].split) {
value = elation.utils.arrayget(target, def[1]);
} else {
console.log('wtf d00d', name, def, defs);
}
if (def[0] == 'property') {
return value;
} else if (def[0] == 'accessor') {
var bindobj = target;
if (def[1].indexOf('.') != -1) {
var parts = def[1].split('.');
parts.pop();
bindobj = elation.utils.arrayget(target, parts.join('.'));
}
return (value ? value.call(bindobj) : null);
} else if (def[0] == 'function') {
if (!value.hasOwnProperty('prototype')) {
// If the function has no prototype, it's a bound function, and we don't need to rebind
return value;
}
var bindobj = target;
if (def[1].indexOf('.') != -1) {
var parts = def[1].split('.');
parts.pop();
bindobj = elation.utils.arrayget(target, parts.join('.'));
}
return elation.bind(bindobj, value);
}
} else if (name in scriptprops) {
return scriptprops[name];
} else if (name == '_target') {
return target;
} else {
scriptprops[name] = target[name];
return scriptprops[name];
}
if (passthrough) {
return target[name];
}
}
var proxyhandler = {
construct: target.constructor,
get: getProxyValue,
set: function(target, name, value) {
if (proxydefs && proxydefs[name]) {
var def = proxydefs[name],
deftype = def[0],
defname = def[1],
defargs = def[2];
if (deftype == 'property') {
var propargs = defargs || {};
if (!propargs.readonly) {
elation.utils.arrayset(target, defname, value);
//elation.events.fire({element: this._proxyobj, type: 'proxy_change', data: {key: defname, value: value}});
//setProxyChangeTimer({key: defname, value: value});
return true;
}
} else if (deftype == 'callback') {
var evobj = target;
if (defargs) {
evobj = elation.utils.arrayget(target, defargs);
}
elation.utils.arrayset(target, name, value);
if (evobj) {
var bindargs = def[3] || [];
//elation.events.add(evobj, def[1], elation.bind.apply(null, bindargs));
elation.events.add(evobj, def[1], elation.bind(target, function(ev) {
var funcargs = [];
for (var i = 0; i < bindargs.length; i++) {
funcargs.push(bindargs[i]);
}
for (var i = 0; i < arguments.length; i++) {
funcargs.push(arguments[i]);
}
executeCallback(value, target, funcargs);
}));
}
//elation.events.fire({element: this._proxyobj, type: 'proxy_change', data: {key: defname, value: value}});
//setProxyChangeTimer({key: defname, value: value});
return true;
} else {
//console.log('why set function?', target, name, def);
}
} else if (name == '_proxydefs') {
var keys = Object.keys(value);
for (var i = 0; i < keys.length; i++) {
if (proxydefs[keys[i]]) {
delete proxydefs[keys[i]];
}
}
elation.utils.merge(value, proxydefs);
} else {
scriptprops[name] = value;
target[name] = value;
//elation.events.fire({element: target, type: 'proxy_change', data: {key: name, value: value}});
//setProxyChangeTimer({key: name, value: value});
}
return true;
},
has: function(key) {
return (proxydefs && (key in proxydefs || key in self._scriptprops));
},
getOwnPropertyDescriptor: function(target, prop) {
if (prop in proxydefs || prop in self._scriptprops) {
return {enumerable: true, configurable: true, value: getProxyValue(target, prop)};
}
},
enumerate: function(target) {
var scriptkeys = (self._scriptprops ? Object.keys(self._scriptprops) : []);
var proxykeys = [];//(self._proxydefs ? Object.keys(self._proxydefs) : []);
for (var k in self._proxydefs) {
if (self._proxydefs[0] == 'property') {
proxykeys.push(k);
}
}
return proxykeys.concat(scriptkeys);
},
ownKeys: function(target) {
var scriptkeys = (self._scriptprops ? Object.keys(self._scriptprops) : []);
var proxykeys = [];//(self._proxydefs ? Object.keys(self._proxydefs) : []);
for (var k in self._proxydefs) {
if (self._proxydefs[k][0] == 'property') {
proxykeys.push(k);
}
}
var ret = proxykeys.concat(scriptkeys);
return ret;
}
};
if (typeof Proxy != 'undefined') {
this._proxyobj = new Proxy(this._proxytarget, proxyhandler);
return this._proxyobj;
}
return target;
}
});
});