UNPKG

breeze-client

Version:

Breeze data management for JavaScript clients

249 lines (245 loc) 9.01 kB
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