export function capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); }
function isA(publicAPI, model = {}, name = null) { if (!model.isA) { model.isA = []; }
if (name) { model.isA.push(name); }
if (!publicAPI.isA) { publicAPI.isA = (className) => model.isA.indexOf(className) !== -1; } }
function set(publicAPI, model = {}, names = []) { names.forEach((name) => { publicAPI[`set${capitalize(name)}`] = (value) => { model[name] = value; }; }); }
function get(publicAPI, model = {}, names = []) { names.forEach((name) => { publicAPI[`get${capitalize(name)}`] = () => model[name]; }); }
function destroy(publicAPI, model = {}) { const previousDestroy = publicAPI.destroy;
if (!model.subscriptions) { model.subscriptions = []; }
publicAPI.destroy = () => { if (previousDestroy) { previousDestroy(); } while (model.subscriptions && model.subscriptions.length) { model.subscriptions.pop().unsubscribe(); } Object.keys(model).forEach((field) => { delete model[field]; });
model.deleted = true; }; }
function event(publicAPI, model, eventName, asynchrounous = true) { const callbacks = []; const previousDestroy = publicAPI.destroy;
function off(index) { callbacks[index] = null; }
function on(index) { function unsubscribe() { off(index); } return Object.freeze({ unsubscribe }); }
publicAPI[`fire${capitalize(eventName)}`] = (...args) => { if (model.deleted) { console.log('instance deleted - can not call any method'); return; }
function processCallbacks() { callbacks.forEach((callback) => { if (callback) { try { callback.apply(publicAPI, args); } catch (errObj) { console.log('Error event:', eventName, errObj); } } }); }
if (asynchrounous) { setTimeout(processCallbacks, 0); } else { processCallbacks(); } };
publicAPI[`on${capitalize(eventName)}`] = (callback) => { if (model.deleted) { console.log('instance deleted - can not call any method'); return null; }
const index = callbacks.length; callbacks.push(callback); return on(index); };
publicAPI.destroy = () => { previousDestroy(); callbacks.forEach((el, index) => off(index)); }; }
function fetch(publicAPI, model, name) { let fetchCallback = null; const requestQueue = [];
publicAPI[`set${capitalize(name)}FetchCallback`] = (fetchMethod) => { if (requestQueue.length) { fetchMethod(requestQueue); } fetchCallback = fetchMethod; };
return { addRequest(request) { requestQueue.push(request); if (fetchCallback) { fetchCallback(requestQueue); } }, resetRequests(requestList) { while (requestQueue.length) { requestQueue.pop(); } if (requestList) { requestList.forEach((req) => { requestQueue.push(req); }); if (fetchCallback) { fetchCallback(requestQueue); } } }, }; }
function dynamicArray(publicAPI, model, name) { if (!model[name]) { model[name] = []; }
publicAPI[`set${capitalize(name)}`] = (items) => { model[name] = [].concat(items); };
publicAPI[`add${capitalize(name)}`] = (item) => { model[name].push(item); };
publicAPI[`remove${capitalize(name)}`] = (item) => { const index = model[name].indexOf(item); model[name].splice(index, 1); };
publicAPI[`get${capitalize(name)}`] = () => model[name];
publicAPI[`removeAll${capitalize(name)}`] = () => { model[name] = []; return model[name]; }; }
function chain(...fn) { return (...args) => fn.filter((i) => !!i).forEach((i) => i(...args)); }
function dataSubscriber(publicAPI, model, dataName, dataHandler) { const dataSubscriptions = []; let forceFlushRequests = 0; const eventName = `${dataName}SubscriptionChange`; const fireMethodName = `fire${capitalize(eventName)}`; const dataContainerName = `${dataName}_storage`;
if (!model[dataContainerName]) { model[dataContainerName] = {}; }
event(publicAPI, model, eventName);
function off() { let count = dataSubscriptions.length; while (count) { count -= 1; dataSubscriptions[count] = null; } }
function flushDataToListener(dataListener, dataChanged) { try { if (dataListener) { const dataToForward = dataHandler.get( model[dataContainerName], dataListener.request, dataChanged ); if ( dataToForward && (JSON.stringify(dataToForward) !== dataListener.request.lastPush || dataListener.request.metadata.forceFlush) ) { dataListener.request.lastPush = JSON.stringify(dataToForward); dataListener.onDataReady(dataToForward); } } } catch (err) { console.log(`flush ${dataName} error caught:`, err); } }
publicAPI[`subscribeTo${capitalize(dataName)}`] = ( onDataReady, variables = [], metadata = {} ) => { const id = dataSubscriptions.length; const request = { id, variables, metadata: Object.assign({}, dataHandler.defaultMetadata, metadata), }; if (request.metadata.forceFlush) { forceFlushRequests += 1; } const dataListener = { onDataReady, request }; dataSubscriptions.push(dataListener); publicAPI[fireMethodName](request); flushDataToListener(dataListener, null); return { unsubscribe() { request.action = 'unsubscribe'; if (request.metadata.forceFlush) { forceFlushRequests -= 1; } publicAPI[fireMethodName](request); dataSubscriptions[id] = null; }, update(vars, meta) { request.variables = [].concat(vars); if (meta && meta.forceFlush !== request.metadata.forceFlush) { forceFlushRequests += meta.forceFlush ? 1 : -1; } request.metadata = Object.assign({}, request.metadata, meta); publicAPI[fireMethodName](request); flushDataToListener(dataListener, null); }, }; };
publicAPI[`set${capitalize(dataName)}`] = (data) => { if ( !dataHandler.set(model[dataContainerName], data) || forceFlushRequests > 0 ) { dataSubscriptions.forEach((dataListener) => flushDataToListener(dataListener, data) ); } };
publicAPI[`has${capitalize(dataName)}`] = (inRequest, variable) => { try { if (inRequest) { const request = Object.assign({}, inRequest, { variables: [variable] }); const dataToForward = dataHandler.get( model[dataContainerName], request, null ); if (dataToForward) { return true; } } } catch (err) { console.log(`has ${dataName} error caught:`, err); } return false; };
publicAPI.destroy = chain(off, publicAPI.destroy); }
function newInstance(extend) { return (initialValues = {}) => { const model = {}; const publicAPI = {}; extend(publicAPI, model, initialValues); return Object.freeze(publicAPI); }; }
export default { chain, dataSubscriber, destroy, dynamicArray, event, fetch, get, isA, newInstance, set, };
|