mirror of
https://github.com/fluxscape/fluxscape.git
synced 2026-01-12 15:22:54 +01:00
Co-Authored-By: Eric Tuvesson <eric.tuvesson@gmail.com> Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com> Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com> Co-Authored-By: Anders Larsson <64838990+anders-topp@users.noreply.github.com> Co-Authored-By: Johan <4934465+joolsus@users.noreply.github.com> Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com> Co-Authored-By: victoratndl <99176179+victoratndl@users.noreply.github.com>
216 lines
5.7 KiB
JavaScript
216 lines
5.7 KiB
JavaScript
// ------------------------------------------------------------------------------
|
|
// Model
|
|
// ------------------------------------------------------------------------------
|
|
function Model(id, data) {
|
|
this.id = id;
|
|
this.data = data;
|
|
}
|
|
|
|
const models = (Model._models = {});
|
|
const proxies = {};
|
|
|
|
// Get and set proxy
|
|
const _modelProxyHandler = {
|
|
get: function (target, prop, receiver) {
|
|
if (typeof target[prop] === 'function') return target[prop].bind(target);
|
|
else if (prop in target) return Reflect.get(target, prop, receiver);
|
|
else return target.get(prop);
|
|
},
|
|
set: function (obj, prop, value) {
|
|
if (prop === '_class') {
|
|
obj._class = value;
|
|
} else if (prop === 'id') {
|
|
console.log(`Noodl.Object warning: id is readonly (Id is ${obj.id}, trying to set to ${value})`);
|
|
return true; //if a proxy doesn't return true an exception will be thrown
|
|
} else {
|
|
obj.set(prop, value);
|
|
}
|
|
return true;
|
|
},
|
|
ownKeys(target) {
|
|
return Reflect.ownKeys(target.data);
|
|
},
|
|
getOwnPropertyDescriptor(target, prop) {
|
|
return Object.getOwnPropertyDescriptor(target.data, prop);
|
|
}
|
|
};
|
|
|
|
Model.get = function (id) {
|
|
if (id === undefined) id = Model.guid();
|
|
if (!models[id]) {
|
|
models[id] = new Model(id, {});
|
|
proxies[id] = new Proxy(models[id], _modelProxyHandler);
|
|
}
|
|
return proxies[id];
|
|
};
|
|
|
|
Model.create = function (data) {
|
|
var modelData = data ? data : {};
|
|
var m = Model.get(modelData.id);
|
|
for (var key in modelData) {
|
|
if (key === 'id') continue;
|
|
m.set(key, modelData[key]);
|
|
}
|
|
|
|
return m;
|
|
};
|
|
|
|
Model.exists = function (id) {
|
|
return models[id] !== undefined;
|
|
};
|
|
|
|
Model.instanceOf = function (collection) {
|
|
return collection instanceof Model || collection.target instanceof Model;
|
|
};
|
|
|
|
function _randomString(size) {
|
|
if (size === 0) {
|
|
throw new Error('Zero-length randomString is useless.');
|
|
}
|
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz' + '0123456789';
|
|
let objectId = '';
|
|
for (let i = 0; i < size; ++i) {
|
|
objectId += chars[Math.floor((1 + Math.random()) * 0x10000) % chars.length];
|
|
}
|
|
return objectId;
|
|
}
|
|
|
|
Model.guid = function guid() {
|
|
return _randomString(10);
|
|
};
|
|
|
|
Model.prototype.on = function (event, listener) {
|
|
if (!this.listeners) this.listeners = {};
|
|
if (!this.listeners[event]) this.listeners[event] = [];
|
|
this.listeners[event].push(listener);
|
|
};
|
|
|
|
Model.prototype.off = function (event, listener) {
|
|
if (!this.listeners) return;
|
|
if (!this.listeners[event]) return;
|
|
var idx = this.listeners[event].indexOf(listener);
|
|
if (idx !== -1) this.listeners[event].splice(idx, 1);
|
|
};
|
|
|
|
Model.prototype.notify = function (event, args) {
|
|
if (!this.listeners) return;
|
|
if (!this.listeners[event]) return;
|
|
|
|
var l = this.listeners[event].slice(); //clone in case listeners array is modified in the callbacks
|
|
for (var i = 0; i < l.length; i++) {
|
|
l[i](args);
|
|
}
|
|
};
|
|
|
|
Model.prototype.setAll = function (obj) {
|
|
for (var i in obj) {
|
|
if (i === 'id') continue; // Skip id
|
|
if (this.data[i] !== obj[i]) {
|
|
var old = this.data[i];
|
|
this.data[i] = obj[i];
|
|
this.notify('change', { name: i, value: obj[i], old: old });
|
|
}
|
|
}
|
|
};
|
|
|
|
Model.prototype.fill = function (value = null) {
|
|
for (const key in this.data) {
|
|
if (key === 'id') continue; // Skip id
|
|
const temp = this.data[key];
|
|
this.data[key] = value;
|
|
this.notify('change', { name: key, value: this.data[key], old: temp });
|
|
}
|
|
};
|
|
|
|
Model.prototype.set = function (name, value, args) {
|
|
if (args && args.resolve && name.indexOf('.') !== -1) {
|
|
// We should resolve path references
|
|
var path = name.split('.');
|
|
var model = this;
|
|
for (var i = 0; i < path.length - 1; i++) {
|
|
var v = model.get(path[i]);
|
|
if (Model.instanceOf(v)) model = v;
|
|
else return; // Path resolve failed
|
|
}
|
|
model.set(path[path.length - 1], value);
|
|
return;
|
|
}
|
|
|
|
const forceChange = args && args.forceChange;
|
|
|
|
var oldValue = this.data[name];
|
|
this.data[name] = value;
|
|
(forceChange || oldValue !== value) &&
|
|
(!args || !args.silent) &&
|
|
this.notify('change', { name: name, value: value, old: oldValue });
|
|
};
|
|
|
|
Model.prototype.getId = function () {
|
|
return this.id;
|
|
};
|
|
|
|
Model.prototype.get = function (name, args) {
|
|
if (args && args.resolve && name.indexOf('.') !== -1) {
|
|
// We should resolve path references
|
|
var path = name.split('.');
|
|
var model = this;
|
|
for (var i = 0; i < path.length - 1; i++) {
|
|
var v = model.get(path[i]);
|
|
if (Model.instanceOf(v)) model = v;
|
|
else return; // Path resolve failed
|
|
}
|
|
return model.get(path[path.length - 1]);
|
|
}
|
|
|
|
return this.data[name];
|
|
};
|
|
|
|
Model.prototype.toJSON = function () {
|
|
return Object.assign({}, this.data, { id: this.id });
|
|
};
|
|
|
|
Model.Scope = function () {
|
|
this.models = {};
|
|
this.proxies = {};
|
|
};
|
|
|
|
Model.Scope.prototype.get = function (id) {
|
|
if (id === undefined) id = Model.guid();
|
|
if (!this.models[id]) {
|
|
this.models[id] = new Model(id, {});
|
|
this.proxies[id] = new Proxy(this.models[id], _modelProxyHandler);
|
|
}
|
|
return this.proxies[id];
|
|
};
|
|
|
|
Model.Scope.prototype.create = function (data) {
|
|
var modelData = data ? data : {};
|
|
var m = this.get(modelData.id);
|
|
for (var key in modelData) {
|
|
if (key === 'id') continue;
|
|
m.set(key, modelData[key]);
|
|
}
|
|
|
|
return m;
|
|
};
|
|
|
|
Model.Scope.prototype.exists = function (id) {
|
|
return this.models[id] !== undefined;
|
|
};
|
|
|
|
Model.Scope.prototype.instanceOf = function (collection) {
|
|
return collection instanceof Model || collection.target instanceof Model;
|
|
};
|
|
|
|
Model.Scope.prototype.guid = function guid() {
|
|
return _randomString(10);
|
|
};
|
|
|
|
Model.Scope.prototype.reset = function () {
|
|
this.models = {};
|
|
this.proxies = {};
|
|
delete this._cloudStore;
|
|
};
|
|
|
|
module.exports = Model;
|