breeze-client
Version:
Breeze data management for JavaScript clients
249 lines (245 loc) • 9.01 kB
JavaScript
import * as breeze from 'breeze-client';
let core = breeze.core;
let canIsolateES5Props = core.isES5Supported;
let ko;
class ModelLibraryKnockoutAdapter {
name;
constructor() {
this.name = "ko";
}
static register(config) {
config = config || breeze.config;
config.registerAdapter("modelLibrary", ModelLibraryKnockoutAdapter);
return config.initializeAdapterInstance("modelLibrary", "ko", true);
}
initialize() {
ko = core.requireLib("ko;knockout", "The Knockout library");
ko.extenders.intercept = function (target, interceptorOptions) {
let instance = interceptorOptions.instance;
let property = interceptorOptions.property;
// create a computed observable to intercept writes to our observable
let result;
if (target.splice) {
result = ko.computed({
read: target //always return the original observables value
});
}
else {
result = ko.computed({
read: target,
write: function (newValue) {
instance._$interceptor(property, newValue, target);
return instance;
}
});
}
//return the new computed observable
return result;
};
}
getTrackablePropertyNames(entity) {
let names = [];
for (let p in entity) {
if (p === "entityType")
continue;
if (p === "_$typeName")
continue;
let propDescr = getES5PropDescriptor(entity, p);
if (propDescr && propDescr.get) {
names.push(p);
}
else {
let val = entity[p];
if (ko.isObservable(val)) {
names.push(p);
}
else if (!core.isFunction(val)) {
names.push(p);
}
}
}
return names;
}
initializeEntityPrototype(proto) {
proto.getProperty = function (propertyName) {
return this[propertyName]();
};
proto.setProperty = function (propertyName, value) {
this[propertyName](value);
// allow set property chaining.
return this;
};
if (canIsolateES5Props) {
isolateES5Props(proto);
}
}
startTracking(entity, proto) {
// create ko's for each property and assign defaultValues
let stype = (entity.entityType || entity.complexType);
let es5Descriptors = stype._extra.es5Descriptors || {};
// sort unmapped properties to the end
stype.getProperties().sort(function (p1, p2) {
let v1 = p1.isUnmapped ? 1 : 0;
let v2 = p2.isUnmapped ? 1 : 0;
return v1 - v2;
}).forEach(function (prop) {
let propName = prop.name;
let val = entity[propName];
let propDescr = es5Descriptors[propName];
let koObj;
// check if property is an ES5 property
if (propDescr) {
let getFn = propDescr.get.bind(entity);
if (propDescr.set) {
let setFn = propDescr.set.bind(entity);
let rawAccessorFn = function (newValue) {
if (arguments.length === 0) {
getFn();
return;
}
else {
setFn(newValue);
}
};
koObj = ko.computed({
read: function () {
stype._koDummy();
return getFn();
},
write: function (newValue) {
entity._$interceptor(prop, newValue, rawAccessorFn);
stype._koDummy.valueHasMutated();
return entity;
}
});
}
else {
koObj = ko.computed({
read: getFn,
write: function () {
}
});
}
// check if property is already exposed as a ko object
}
else if (ko.isObservable(val)) {
if (prop.isNavigationProperty) {
throw new Error("Cannot assign a navigation property in an entity ctor.: " + propName);
}
koObj = val;
// otherwise
}
else {
val = initializeValueForProp(entity, prop, val);
koObj = prop.isScalar ? ko.observable(val) : ko.observableArray(val);
}
if (prop.isScalar) {
if (propDescr) {
Object.defineProperty(entity, propName, {
enumerable: true,
configurable: true,
writable: true,
value: koObj
});
}
else {
let koExt = koObj.extend({ intercept: { instance: entity, property: prop } });
entity[propName] = koExt;
}
}
else {
val._koObj = koObj;
// code to suppress extra breeze notification when
// ko's array methods are called.
koObj.subscribe(onBeforeChange, null, "beforeChange");
// code to insure that any direct breeze changes notify ko
val.arrayChanged.subscribe(onArrayChanged);
koObj.equalityComparer = function () {
throw new Error("Collection navigation properties may NOT be set.");
};
entity[propName] = koObj;
}
});
}
}
breeze.config.registerAdapter("modelLibrary", ModelLibraryKnockoutAdapter);
// private fns
function getES5PropDescriptor(proto, propName) {
if (!canIsolateES5Props) {
return null;
}
if (proto.hasOwnProperty(propName)) {
return Object.getOwnPropertyDescriptor && Object.getOwnPropertyDescriptor(proto, propName);
}
else {
let nextProto = Object.getPrototypeOf(proto);
return nextProto ? getES5PropDescriptor(nextProto, propName) : null;
}
}
function initializeValueForProp(entity, prop, val) {
if (prop instanceof breeze.DataProperty) {
if (prop.isComplexProperty) {
// TODO: right now we create Empty complexObjects here - these should actually come from the entity
if (prop.isScalar) {
val = prop.dataType._createInstanceCore(entity, prop);
}
else {
val = breeze.makeComplexArray([], entity, prop);
}
}
else if (!prop.isScalar) {
val = breeze.makePrimitiveArray([], entity, prop);
}
else if (val === undefined) {
val = prop.defaultValue;
}
}
else if (prop instanceof breeze.NavigationProperty) {
if (val !== undefined) {
throw new Error("Cannot assign a navigation property in an entity ctor.: " + prop.name);
}
if (prop.isScalar) {
// TODO: change this to nullEntity later.
val = null;
}
else {
val = breeze.makeRelationArray([], entity, prop);
}
}
else {
throw new Error("unknown property: " + prop.name);
}
return val;
}
function onBeforeChange(args) {
args._koObj._suppressBreeze = true;
}
function onArrayChanged(args) {
let koObj = args.array._koObj;
if (koObj._suppressBreeze) {
koObj._suppressBreeze = false;
}
else {
koObj.valueHasMutated();
}
}
function isolateES5Props(proto) {
let stype = (proto.entityType || proto.complexType);
let es5Descriptors = {};
stype.getProperties().forEach(function (prop) {
let propDescr = getES5PropDescriptor(proto, prop.name);
if (propDescr) {
es5Descriptors[prop.name] = propDescr;
}
});
if (!core.isEmpty(es5Descriptors)) {
let extra = stype._extra;
extra.es5Descriptors = es5Descriptors;
stype._koDummy = ko.observable(null);
}
}
/**
* Generated bundle index. Do not edit.
*/
export { ModelLibraryKnockoutAdapter };
//# sourceMappingURL=breeze-client-adapter-model-library-ko.mjs.map