@stratusjs/angularjs
Version:
This is the AngularJS package for StratusJS.
2,141 lines • 108 kB
JavaScript
System.register(['angular', 'lodash', '@stratusjs/runtime/stratus', '@stratusjs/core/environment', 'angular-sanitize', '@stratusjs/core/errors/errorBase', '@stratusjs/core/datastore/modelBase', '@stratusjs/core/events/eventManager', '@stratusjs/core/misc', '@stratusjs/core/datastore/xhr', 'toastify-js', 'angular-material', '@stratusjs/core/conversion'], (function (exports) {
'use strict';
var element, throttle, extend, isObject, isEmpty, cloneDeep, once, forEach, get, isUndefined, set, isArray, isString, unset, isNumber, clone, head, has, filter, map, isEqual, find, reduce, isFunction, _, isDate, isElement, union, kebabCase, size, Stratus, cookie, ErrorBase, ModelBase, EventManager, isJSON, ucfirst, setUrlParams, getAnchorParams, getUrlParams, serializeUrlParams, patch, strcmp, safeUniqueId, poll, flatten, XHR, Toastify, sanitize;
return {
setters: [function (module) {
element = module.element;
}, function (module) {
throttle = module.throttle;
extend = module.extend;
isObject = module.isObject;
isEmpty = module.isEmpty;
cloneDeep = module.cloneDeep;
once = module.once;
forEach = module.forEach;
get = module.get;
isUndefined = module.isUndefined;
set = module.set;
isArray = module.isArray;
isString = module.isString;
unset = module.unset;
isNumber = module.isNumber;
clone = module.clone;
head = module.head;
has = module.has;
filter = module.filter;
map = module.map;
isEqual = module.isEqual;
find = module.find;
reduce = module.reduce;
isFunction = module.isFunction;
_ = module.default;
isDate = module.isDate;
isElement = module.isElement;
union = module.union;
kebabCase = module.kebabCase;
size = module.size;
}, function (module) {
Stratus = module.Stratus;
}, function (module) {
cookie = module.cookie;
}, null, function (module) {
ErrorBase = module.ErrorBase;
}, function (module) {
ModelBase = module.ModelBase;
}, function (module) {
EventManager = module.EventManager;
}, function (module) {
isJSON = module.isJSON;
ucfirst = module.ucfirst;
setUrlParams = module.setUrlParams;
getAnchorParams = module.getAnchorParams;
getUrlParams = module.getUrlParams;
serializeUrlParams = module.serializeUrlParams;
patch = module.patch;
strcmp = module.strcmp;
safeUniqueId = module.safeUniqueId;
poll = module.poll;
flatten = module.flatten;
}, function (module) {
XHR = module.XHR;
}, function (module) {
Toastify = module.default;
}, null, function (module) {
sanitize = module.sanitize;
}],
execute: (function () {
const getInjector = exports('getInjector', () => {
const $root = element(document.documentElement);
return (!$root || !$root.injector) ? null : $root.injector();
});
var __awaiter$3 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
let injector$1 = getInjector();
let $rootScope;
const genericValidationMessages = [
'There were validation errors.'
];
const transientWriteFailureCode = 'API_TRANSIENT_WRITE_FAILURE';
const retryableWriteMethods = ['POST', 'PUT', 'PATCH', 'DELETE'];
const transientWriteRetryBackoff = [250, 750, 1500];
const transientWriteRetryMaxAttempts = 3;
function normalizeStatusList(source) {
const status = get(source, 'meta.status') ||
get(source, 'payload.meta.status') ||
get(source, 'payload.status') ||
get(source, 'status') ||
source;
if (isArray(status)) {
return status.filter((entry) => isObject(entry));
}
if (isObject(status) &&
(isString(get(status, 'code')) ||
isString(get(status, 'message')) ||
isString(get(status, 'type')))) {
return [status];
}
return [];
}
function parseXHRPayload(error) {
if (error instanceof ErrorBase) {
return get(error, 'payload') || error;
}
if (isObject(error) && !isUndefined(get(error, 'response'))) {
return get(error, 'response');
}
const responseText = get(error, 'responseText');
return isString(responseText) && isJSON(responseText) ? JSON.parse(responseText) : null;
}
function isGenericValidationMessage(message) {
return genericValidationMessages.indexOf(message.trim()) !== -1;
}
function hasStatusCode(source, code) {
return normalizeStatusList(source).some((status) => status.code === code);
}
function isRetryableTransientWritePayload(action, payload) {
const method = (action || 'GET').toUpperCase();
if (retryableWriteMethods.indexOf(method) === -1) {
return false;
}
if (!payload) {
return false;
}
return !!(get(payload, 'code') === transientWriteFailureCode ||
hasStatusCode(payload, transientWriteFailureCode));
}
function isRetryableTransientWrite(action, error) {
const payload = parseXHRPayload(error);
if (!payload) {
return false;
}
return isRetryableTransientWritePayload(action, payload);
}
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
function getPreferredStatusMessage(source) {
const statuses = normalizeStatusList(source);
if (!statuses.length) {
return null;
}
const messages = statuses
.map((status) => isString(status.message) ? status.message.trim() : '')
.filter((message) => !!message);
if (!messages.length) {
return null;
}
const specificMessage = messages.find((message) => !isGenericValidationMessage(message));
return specificMessage || messages[0];
}
function hasNotableStatus(source) {
return normalizeStatusList(source).some((status) => {
const type = isString(status.type) ? status.type.toLowerCase() : '';
return type === 'warning' || type === 'error' || status.code === 'VALIDATION';
});
}
function hasUsablePayload(payload) {
return (isArray(payload) && !!payload.length) || (isObject(payload) && !isArray(payload));
}
function isSoftStatusFailure(meta, payload) {
return !!(get(meta, 'success') === false &&
hasUsablePayload(payload) &&
getPreferredStatusMessage(meta) &&
hasNotableStatus(meta));
}
const serviceVerify$1 = () => __awaiter$3(void 0, void 0, void 0, function* () {
return new Promise((resolve, _reject) => __awaiter$3(void 0, void 0, void 0, function* () {
if ($rootScope) {
resolve(true);
return;
}
if (!injector$1) {
injector$1 = getInjector();
}
if (injector$1) {
$rootScope = injector$1.get('$rootScope');
}
if ($rootScope) {
resolve(true);
return;
}
setTimeout(() => {
if (cookie('env')) {
console.log('wait for $rootScope service:', {
$rootScope
});
}
serviceVerify$1().then(resolve);
}, 250);
}));
});
const ModelOptionKeys = exports('ModelOptionKeys', ["autoSave", "autoSaveInterval", "autoSaveHalt", "collection", "completed", "manifest", "serviceId", "stagger", "target", "targetSuffix", "toast", "type", "urlRoot", "urlSync", "watch", "withCredentials", "payload", "convoy", "headers", "ignoreKeys", "received"]);
class Model extends ModelBase {
constructor(options = {}, attributes) {
super(attributes);
this.name = 'Model';
this.target = null;
this.type = null;
this.manifest = false;
this.stagger = false;
this.toast = true;
this.identifier = null;
this.urlRoot = '/Api';
this.targetSuffix = null;
this.serviceId = null;
this.header = new ModelBase();
this.meta = new ModelBase();
this.route = new ModelBase();
this.collection = null;
this.withCredentials = false;
this.headers = {};
this.pending = false;
this.error = false;
this.completed = false;
this.saving = false;
this.changedExternal = false;
this.watch = true;
this.status = null;
this.autoSave = false;
this.autoSaveInterval = 4000;
this.autoSaveHalt = true;
this.autoSaveTimeout = null;
this.urlSync = false;
this.bracket = {
match: /\[[\d+]]/,
search: /\[([\d+])]/g,
attr: /(^[^[]+)/
};
this.throttle = throttle(this.fetch, 1000);
this.initialize = null;
options = typeof options !== 'object' ? {} : options;
options.received = options.received || false;
extend(this, this.sanitizeOptions(options));
if (options.convoy) {
const convoy = isJSON(options.convoy) ? JSON.parse(options.convoy) : options.convoy;
if (isObject(convoy)) {
this.meta.set(convoy.meta || {});
const payload = convoy.payload;
if (isObject(payload)) {
extend(this.data, payload);
this.completed = true;
options.received = true;
}
else {
console.error('malformed payload:', payload);
}
}
else {
console.error('malformed convoy:', convoy);
}
}
if (options.payload) {
const payload = isJSON(options.payload) ? JSON.parse(options.payload) : options.payload;
if (isObject(payload)) {
extend(this.data, payload);
this.completed = true;
options.received = true;
}
else {
console.error('malformed payload:', payload);
}
}
this.header = new ModelBase();
this.meta = new ModelBase();
this.route = new ModelBase();
if (!isEmpty(this.collection)) {
if (this.collection.target) {
this.target = this.collection.target;
}
if (this.collection.meta.has('api')) {
this.meta.set('api', this.collection.meta.get('api'));
}
}
this.recv = options.received ? cloneDeep(this.data) : {};
this.sent = {};
this.ignoreKeys = options.ignoreKeys || ['$$hashKey'];
if (this.target) {
this.urlRoot += '/' + ucfirst(this.target);
}
const that = this;
this.initialize = once(this.initialize || function defaultInitializer() {
if (that.completed && (that.watch || that.autoSave)) {
that.watcher().then();
}
if (that.manifest && !that.getIdentifier()) {
that.sync('POST', that.meta.has('api') ? {
meta: that.meta.get('api'),
payload: {}
} : {}).catch((error) => __awaiter$3(this, void 0, void 0, function* () {
console.error('MANIFEST:', error);
if (!that.toast) {
return;
}
const errorMessage = that.errorMessage(error);
const formatMessage = errorMessage ? `: ${errorMessage}` : '.';
Toastify({
text: `Unable to Manifest ${that.target}${formatMessage}`,
duration: 12000,
close: true,
stopOnFocus: true,
style: {
background: '#E14D45',
}
}).showToast();
that.errorMessage(error);
}));
}
});
if (!this.stagger) {
this.initialize();
}
}
resetXHRFlags() {
this.pending = false;
this.saving = false;
}
sanitizeOptions(options) {
const sanitizedOptions = {};
forEach(ModelOptionKeys, (key) => {
const data = get(options, key);
if (isUndefined(data)) {
return;
}
set(sanitizedOptions, key, data);
});
return sanitizedOptions;
}
getReadOnlyFields() {
const fields = this.meta.get('readOnlyFields');
return isArray(fields) ? fields.filter((field) => isString(field) && !!field) : [];
}
deletePath(obj, path) {
if (!obj || !isString(path)) {
return;
}
unset(obj, path);
}
pruneEmptyBranches(obj) {
if (!isObject(obj) || isArray(obj)) {
return isEmpty(obj);
}
const target = obj;
for (const key of Object.keys(target)) {
const value = target[key];
if (isObject(value) && !isArray(value)) {
const emptyChild = this.pruneEmptyBranches(value);
if (emptyChild) {
delete target[key];
}
continue;
}
if (isUndefined(value)) {
delete target[key];
}
}
return isEmpty(target);
}
sanitizeReadOnlyPatchPayload(payload) {
if (!isObject(payload)) {
return payload;
}
const sanitized = cloneDeep(payload);
const readOnlyFields = this.getReadOnlyFields();
if (!readOnlyFields.length) {
return sanitized;
}
forEach(readOnlyFields, (path) => {
this.deletePath(sanitized, path);
});
this.pruneEmptyBranches(sanitized);
return sanitized;
}
getSavablePatch() {
return this.sanitizeReadOnlyPatchPayload(cloneDeep(this.toPatch()));
}
watcher() {
return __awaiter$3(this, void 0, void 0, function* () {
if (this.watching) {
return true;
}
this.watching = true;
if (!$rootScope) {
yield serviceVerify$1();
}
$rootScope.$watch(() => this.data, (_newData, _priorData) => this.handleChanges(), true);
});
}
handleChanges(changeSet) {
const isUserChangeSet = isUndefined(changeSet);
if (isUserChangeSet) {
changeSet = super.handleChanges();
changeSet = this.sanitizeReadOnlyPatchPayload(changeSet);
if (!isEmpty(this.patch)) {
this.patch = this.sanitizeReadOnlyPatchPayload(this.patch);
}
this.changed = !isEmpty(this.patch);
}
if (!changeSet || isEmpty(changeSet)) {
return changeSet;
}
if (this.error && !this.completed && this.getIdentifier()) {
const action = isUserChangeSet ? 'save' : 'sync url for';
console.warn(`Blocked attempt to ${action} a persisted model that has not been fetched successfully.`);
return;
}
if (!isUserChangeSet) {
if (cookie('env')) {
console.info('Attempting URL Sync for non-User ChangeSet:', changeSet);
}
}
if (this.urlSync) {
if (get(changeSet, 'id')) {
const newUrl = setUrlParams({
id: get(changeSet, 'id') || this.getIdentifier()
});
if (newUrl !== document.location.href) {
window.location.replace(newUrl);
}
}
const version = getAnchorParams('version');
const versionId = !isEmpty(version) ? parseInt(version, 10) : 0;
if (versionId && versionId !== get(changeSet, 'version.id')) {
if (cookie('env')) {
console.warn('replacing version:', versionId);
}
}
}
if (!isUserChangeSet) {
return;
}
this.saveIdle();
this.throttleTrigger('change', this);
if (this.collection) {
this.collection.throttleTrigger('change', this);
}
return changeSet;
}
getIdentifier() {
return (this.identifier = this.get('id') || this.route.get('identifier') || this.identifier);
}
getType() {
return (this.type = this.type || this.target || 'orphan');
}
getHash() {
return this.getType() + (isNumber(this.getIdentifier()) ? this.getIdentifier().toString() : this.getIdentifier());
}
isNew() {
return !this.getIdentifier();
}
url() {
let url = this.getIdentifier() ? `${this.urlRoot}/${this.getIdentifier()}` : `${this.urlRoot}${this.targetSuffix || ''}`;
if (getUrlParams('version')) {
url += url.includes('?') ? '&' : '?';
url += 'options[version]=' + getUrlParams('version');
}
return url;
}
serialize(obj, chain) { return serializeUrlParams(obj, chain); }
sync(action, data, options) {
this.pending = true;
this.trigger('change', this);
if (this.collection) {
this.collection.pending = true;
this.collection.throttleTrigger('change');
}
this.sent = cloneDeep(this.data);
return new Promise((resolve, reject) => __awaiter$3(this, void 0, void 0, function* () {
let successfulResponseMeta = null;
action = action || 'GET';
options = options || {};
const request = {
method: action,
url: this.url(),
headers: clone(this.headers),
withCredentials: this.withCredentials,
};
if (!isUndefined(data)) {
if (['GET', 'DELETE'].includes(action)) {
if (isObject(data) && Object.keys(data).length) {
request.url += request.url.includes('?') ? '&' : '?';
request.url += this.serialize(data);
}
}
else {
request.headers['Content-Type'] = 'application/json';
request.data = data;
}
}
if (cookie('env')) {
console.log('Prototype:', request);
}
if (Object.prototype.hasOwnProperty.call(options, 'headers') && typeof options.headers === 'object') {
Object.keys(options.headers).forEach((headerKey) => {
request.headers[headerKey] = options.headers[headerKey];
});
}
const sendRequest = (attempt = 1) => __awaiter$3(this, void 0, void 0, function* () {
this.xhr = new XHR(request);
try {
const response = yield this.xhr.send();
if (attempt < transientWriteRetryMaxAttempts &&
isRetryableTransientWritePayload(request.method, response)) {
const nextAttempt = attempt + 1;
console.warn(`XHR: ${request.method} ${request.url} returned ${transientWriteFailureCode}; retrying ${nextAttempt} of ${transientWriteRetryMaxAttempts}.`, response);
if (this.toast) {
Toastify({
text: `The server was busy saving. Retrying ${nextAttempt} of ${transientWriteRetryMaxAttempts}...`,
duration: 4000,
close: true,
stopOnFocus: true,
style: {
background: '#D9902F',
}
}).showToast();
}
yield delay(transientWriteRetryBackoff[attempt - 1] || transientWriteRetryBackoff[transientWriteRetryBackoff.length - 1]);
return sendRequest(nextAttempt);
}
return response;
}
catch (error) {
if (attempt < transientWriteRetryMaxAttempts &&
isRetryableTransientWrite(request.method, error)) {
const nextAttempt = attempt + 1;
console.warn(`XHR: ${request.method} ${request.url} returned ${transientWriteFailureCode}; retrying ${nextAttempt} of ${transientWriteRetryMaxAttempts}.`, error);
if (this.toast) {
Toastify({
text: `The server was busy saving. Retrying ${nextAttempt} of ${transientWriteRetryMaxAttempts}...`,
duration: 4000,
close: true,
stopOnFocus: true,
style: {
background: '#D9902F',
}
}).showToast();
}
yield delay(transientWriteRetryBackoff[attempt - 1] || transientWriteRetryBackoff[transientWriteRetryBackoff.length - 1]);
return sendRequest(nextAttempt);
}
throw error;
}
});
sendRequest().then((response) => {
this.status = this.xhr.status;
if (this.watch || this.autoSave) {
this.watcher();
}
const propagateError = () => {
this.error = true;
this.resetXHRFlags();
if (this.collection) {
this.collection.pending = false;
}
this.trigger('error', this);
this.trigger('complete', this);
if (this.collection instanceof Collection) {
this.collection.throttleTrigger('change');
}
};
if (!isObject(response) && !isArray(response)) {
const error = new ErrorBase({
payload: response,
message: `Invalid Payload: ${request.method} ${request.url}`
}, {});
propagateError();
reject(error);
return;
}
this.header.set(this.xhr.getAllResponseHeaders() || {});
successfulResponseMeta = response.meta || null;
const responseMeta = successfulResponseMeta || {};
this.meta.set(responseMeta);
this.route.set(response.route || {});
const payload = response.payload || response;
this.error = false;
if ((this.meta.has('success') && !this.meta.get('success') && !isSoftStatusFailure(responseMeta, payload))) {
this.error = true;
}
else if (isArray(payload) && payload.length) {
this.recv = head(payload);
}
else if (isObject(payload) && !isArray(payload)) {
this.recv = payload;
}
else {
if (!this.meta.has('status') && !this.meta.has('success')) {
this.error = true;
}
console.warn(`Invalid Payload: ${request.method} ${request.url}`);
}
if (this.error) {
const error = new ErrorBase({
payload: response,
message: `Invalid Payload: ${request.method} ${request.url}`
}, {});
propagateError();
reject(error);
return;
}
const incomingChangeSet = this.completed ? cloneDeep(patch(this.recv, this.sent)) : {};
if (!isEmpty(incomingChangeSet)) {
if (cookie('env')) {
console.log('Incoming ChangeSet detected:', cookie('debug_change_set')
? JSON.stringify(incomingChangeSet)
: incomingChangeSet);
}
this.handleChanges(incomingChangeSet);
}
const intermediateData = cloneDeep(this.recv);
const intermediateChangeSet = cloneDeep(patch(this.data, this.sent));
if (!isEmpty(intermediateChangeSet)) {
if (cookie('env')) {
console.log('Intermediate ChangeSet detected:', cookie('debug_change_set')
? JSON.stringify(intermediateChangeSet)
: intermediateChangeSet);
}
forEach(intermediateChangeSet, (element, key) => {
set(intermediateData, key, element);
});
}
this.data = cloneDeep(intermediateData);
this.changed = false;
this.changedExternal = false;
this.saving = false;
this.handleChanges();
this.patch = {};
this.resetXHRFlags();
this.completed = true;
if (this.collection) {
this.collection.pending = false;
}
this.meta.clearTemp();
const statusMessage = getPreferredStatusMessage(response.meta || {});
if (this.toast && statusMessage && hasNotableStatus(response.meta || {})) {
Toastify({
text: statusMessage,
duration: 12000,
close: true,
stopOnFocus: true,
style: {
background: '#D9902F',
}
}).showToast();
}
this.trigger('success', this);
this.trigger('change', this);
this.trigger('complete', this);
if (this.collection instanceof Collection) {
this.collection.throttleTrigger('change');
}
resolve(this.data);
return;
})
.catch((error) => {
if (successfulResponseMeta && get(successfulResponseMeta, 'success') === true) {
console.warn(`XHR: ${request.method} ${request.url} completed with API success but post-save handling failed.`, error);
this.error = false;
this.resetXHRFlags();
this.completed = true;
if (this.collection) {
this.collection.pending = false;
}
const statusMessage = getPreferredStatusMessage(successfulResponseMeta);
if (this.toast && statusMessage && hasNotableStatus(successfulResponseMeta)) {
Toastify({
text: statusMessage,
duration: 12000,
close: true,
stopOnFocus: true,
style: {
background: '#D9902F',
}
}).showToast();
}
this.trigger('success', this);
this.trigger('change', this);
this.trigger('complete', this);
if (this.collection instanceof Collection) {
this.collection.throttleTrigger('change');
}
resolve(this.data);
return;
}
this.status = 500;
this.error = true;
this.resetXHRFlags();
console.error(`XHR: ${request.method} ${request.url}`, error);
reject(error);
return;
});
}));
}
fetch(action, data, options) {
return new Promise((resolve, reject) => __awaiter$3(this, void 0, void 0, function* () {
this.sync(action, data || this.meta.get('api'), options)
.then(resolve)
.catch((error) => __awaiter$3(this, void 0, void 0, function* () {
this.status = 500;
this.error = true;
this.resetXHRFlags();
console.error('FETCH:', error);
if (!this.toast) {
reject(error);
return;
}
const errorMessage = this.errorMessage(error);
const formatMessage = errorMessage ? `: ${errorMessage}` : '.';
Toastify({
text: `Unable to Fetch ${this.target}${formatMessage}`,
duration: 12000,
close: true,
stopOnFocus: true,
style: {
background: '#E14D45',
}
}).showToast();
reject(error);
return;
}));
}));
}
save(options) {
this.saving = true;
options = options || {};
if (!isObject(options)) {
console.warn('invalid options supplied:', options);
options = {};
}
if (has(options, 'force') && options.force) {
options.patch = has(options, 'patch') ? options.patch : false;
return this.doSave(options);
}
if (!this.isNew() && (this.pending || !this.completed || isEmpty(this.getSavablePatch()))) {
console.warn(`Blocked attempt to save ${isEmpty(this.toPatch()) ? 'an empty payload' : 'a duplicate XHR'} to a persisted model.`);
return new Promise((resolve, _reject) => {
this.saving = false;
resolve(this.data);
});
}
return this.doSave(options);
}
doSave(options) {
options = options || {};
if (!isObject(options)) {
console.warn('invalid options supplied:', options);
options = {};
}
options.patch = has(options, 'patch') ? options.patch : true;
return new Promise((resolve, reject) => __awaiter$3(this, void 0, void 0, function* () {
this.sync(this.getIdentifier() ? 'PUT' : 'POST', this.toJSON({
patch: options.patch
}))
.then(resolve)
.catch((error) => __awaiter$3(this, void 0, void 0, function* () {
this.error = true;
this.resetXHRFlags();
console.error('SAVE:', error);
if (!this.toast) {
reject(error);
return;
}
const errorMessage = this.errorMessage(error) || getPreferredStatusMessage(this.meta.data);
Toastify({
text: errorMessage || `Unable to Save ${this.target}.`,
duration: 12000,
close: true,
stopOnFocus: true,
style: {
background: '#E14D45',
}
}).showToast();
reject(error);
return;
}));
}));
}
saveIdle() {
if (this.autoSaveTimeout) {
clearTimeout(this.autoSaveTimeout);
}
if (this.pending || !this.completed || this.isNew() || isEmpty(this.getSavablePatch())) {
return;
}
if (this.autoSaveHalt && !this.autoSave) {
return;
}
this.autoSaveTimeout = setTimeout(() => {
if (!this.autoSaveHalt && !this.autoSave) {
this.saveIdle();
return;
}
this.save().then();
}, this.autoSaveInterval);
}
throttleSave() {
return new Promise((resolve, reject) => {
const request = this.throttle();
console.log('throttle request:', request);
request.then((data) => {
console.log('throttle received:', data);
resolve(data);
}).catch(reject);
});
}
toJSON(options) {
options = options || {};
if (!isObject(options)) {
options = {};
}
options.patch = (options.patch && !this.isNew());
let data = super.toJSON(options);
if (options.patch) {
data = this.sanitizeReadOnlyPatchPayload(data);
}
const metaData = this.meta.get('api');
if (metaData) {
data = {
meta: metaData,
payload: data
};
}
return data;
}
buildPath(path) {
const acc = [];
if (!isString(path)) {
return acc;
}
let cur;
let search;
forEach(path.split('.'), (link) => {
if (link.match(this.bracket.match)) {
cur = this.bracket.attr.exec(link);
if (cur !== null) {
acc.push(cur[1]);
cur = null;
}
else {
cur = false;
}
search = this.bracket.search.exec(link);
while (search !== null) {
if (cur !== false) {
cur = parseInt(search[1], 10);
if (!isNaN(cur)) {
acc.push(cur);
}
else {
cur = false;
}
}
search = this.bracket.search.exec(link);
}
}
else {
acc.push(link);
}
});
return acc;
}
get(attr) {
if (typeof attr !== 'string' || !this.data || typeof this.data !== 'object') {
return undefined;
}
return get(this.data, attr);
}
find(attr, key, value) {
if (typeof attr === 'string') {
attr = this.get(attr);
}
return !isArray(attr) ? attr : attr.find((obj) => obj[key] === value);
}
set(attr, value) {
if (!attr) {
console.warn('No attr for model.set()!');
return this;
}
if (typeof attr === 'object') {
forEach(attr, (v, k) => this.setAttribute(k, v));
return this;
}
this.setAttribute(attr, value);
return this;
}
setAttribute(attr, value) {
if (typeof attr !== 'string') {
console.warn('Malformed attr for model.setAttribute()!');
return false;
}
set(this.data, attr, value);
this.throttleTrigger('change', this);
this.throttleTrigger(`change:${attr}`, value);
}
toggle(attribute, item, options) {
if (typeof options === 'object' &&
!isUndefined(options.multiple) &&
isUndefined(options.strict)) {
options.strict = true;
}
options = extend({
multiple: true
}, isObject(options) ? options : {});
const request = attribute.split('[].');
let target = this.get(request.length > 1 ? request[0] : attribute);
if (isUndefined(target) ||
(options.strict && isArray(target) !==
options.multiple)) {
target = options.multiple ? [] : null;
this.set(request.length > 1 ? request[0] : attribute, target);
}
if (isArray(target)) {
if (isUndefined(item)) {
this.set(attribute, null);
}
else if (!this.exists(attribute, item)) {
target.push(item);
}
else {
forEach(target, (element, key) => {
const child = (request.length > 1 &&
typeof element === 'object' && request[1] in element)
? element[request[1]]
: element;
const childId = (typeof child === 'object' && child.id)
? child.id
: child;
const itemId = (typeof item === 'object' && item.id)
? item.id
: item;
if (childId === itemId || (isString(childId) && isString(itemId) && strcmp(childId, itemId) === 0)) {
target.splice(key, 1);
}
});
}
}
else if (typeof target === 'object' || typeof target === 'number') {
this.set(attribute, !this.exists(attribute, item) ? item : null);
}
else if (isUndefined(item)) {
this.set(attribute, !target);
}
return this.get(attribute);
}
pluck(attr) {
if (typeof attr !== 'string' || attr.indexOf('[].') === -1) {
return this.get(attr);
}
const request = attr.split('[].');
if (request.length <= 1) {
return undefined;
}
attr = this.get(request[0]);
if (!attr || !isArray(attr)) {
return undefined;
}
const list = filter(map(attr, (element) => get(element, request[1])));
return list.length ? list : undefined;
}
exists(attribute, item) {
if (!item) {
attribute = this.get(attribute);
return typeof attribute !== 'undefined' && attribute;
}
if (typeof attribute === 'string' && item) {
attribute = this.pluck(attribute);
if (isArray(attribute)) {
return typeof attribute.find((element) => element === item || ((typeof element === 'object' && element.id && element.id === item) || isEqual(element, item))) !== 'undefined';
}
return attribute === item || (typeof attribute === 'object' && attribute.id && (isEqual(attribute, item) || attribute.id === item));
}
return false;
}
destroy() {
if (this.isNew()) {
return new Promise((resolve, _reject) => {
this.throttleTrigger('change');
if (this.collection) {
this.collection.remove(this);
}
resolve(this.data);
});
}
return new Promise((_resolve, reject) => __awaiter$3(this, void 0, void 0, function* () {
let deleteData = {};
if (!isEmpty(this.meta.get('api'))) {
deleteData = this.meta.get('api');
}
this.sync('DELETE', deleteData)
.then((_data) => {
if (this.error) {
reject(this.error);
return;
}
this.throttleTrigger('change');
if (this.collection) {
this.collection.remove(this);
}
_resolve(this.data);
})
.catch((error) => __awaiter$3(this, void 0, void 0, function* () {
this.error = true;
this.resetXHRFlags();
console.error('DESTROY:', error);
if (!this.toast) {
reject(error);
return;
}
const errorMessage = this.errorMessage(error);
const formatMessage = errorMessage ? `: ${errorMessage}` : '.';
Toastify({
text: `Unable to Delete ${this.target}${formatMessage}`,
duration: 12000,
close: true,
stopOnFocus: true,
style: {
background: '#E14D45',
}
}).showToast();
reject(error);
return;
}));
}));
}
errorMessage(error) {
if (error instanceof ErrorBase) {
console.error(`[${error.code}] ${error.message}`, error);
const message = getPreferredStatusMessage(error);
if (message) {
return message;
}
return error.code !== 'Internal' ? error.message : null;
}
const digest = (error.responseText && isJSON(error.responseText)) ? JSON.parse(error.responseText) : null;
if (!digest) {
return null;
}
const message = getPreferredStatusMessage(digest) || get(digest, 'error.exception[0].message') || null;
if (!message) {
return null;
}
if (!cookie('env') && has(digest, 'error.exception[0].message')) {
console.error('[xhr] server:', message);
return null;
}
return message;
}
} exports('Model', Model);
Stratus.Services.Model = [
'$provide', ($provide) => {
$provide.factory('Model', [
() => {
return Model;
}
]);
}
];
Stratus.Data.Model = Model;
var __awaiter$2 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const CollectionOptionKeys = exports('CollectionOptionKeys', ["autoSave", "autoSaveInterval", "cache", "direct", "target", "targetSuffix", "urlRoot", "watch", "payload", "convoy", "headers"]);
class Collection extends EventManager {
constructor(options = {}) {
super();
this.name = 'Collection';
this.direct = false;
this.target = null;
this.targetSuffix = null;
this.urlRoot = '/Api';
this.toast = true;
this.qualifier = '';
this.serviceId = null;
this.infinite = false;
this.threshold = 0.5;
this.decay = 0;
this.header = new ModelBase();
this.meta = new ModelBase();
this.model = Model;
this.models = [];
this.types = [];
this.withCredentials = false;
this.headers = {};
this.cacheResponse = {};
this.cacheHeaders = {};
this.cache = false;
this.pending = false;
this.error = false;
this.completed = false;
this.filtering = false;
this.paginate = false;
this.collectionApiHydratedFromUrl = false;
this.watch = false;
this.autoSave = false;
this.autoSaveInterval = 2500;
this.throttle = throttle(this.fetch, 1000);
options = (!options || typeof options !== 'object') ? {} : options;
extend(this, options);
if (this.target) {
this.urlRoot += '/' + ucfirst(this.target);
}
if (options.convoy) {
const convoy = isJSON(options.convoy) ? JSON.parse(options.convoy) : options.convoy;
if (isObject(convoy)) {
this.meta.set(convoy.meta || {});
const models = convoy.payload;
if (isArray(models)) {
this.inject(models);
this.completed = true;
}
else {
console.error('malformed payload:', models);
}
}
else {
console.error('malformed convoy:', convoy);
}
}
if (options.payload) {
const models = isJSON(options.payload) ? JSON.parse(options.payload) : options.payload;
if (isArray(models)) {
this.inject(models);
this.completed = true;
}
else {
console.error('malformed payload:', models);
}
}
}
sanitizeOptions(options) {
const sanitizedOptions = {};
forEach(CollectionOptionKeys, (key) => {
const data = get(options, key);
if (isUndefined(data)) {
return;
}
set(sanitizedOptions, key, data);
});
return sanitizedOptions;
}
serialize(obj, chain) {
const str = [];
obj = obj || {};
forEach(obj, (value, key) => {
if (isObject(value)) {
if (chain) {
key = chain + '[' + key + ']';
}
const serialized = this.serialize(value, key);
if (serialized) {
str.push(serialized);
}
}
else {
let encoded = '';
if (chain) {
encoded += chain + '[';
}
encoded += key;
if (chain) {
encoded += ']';
}
str.push(encoded + '=' + value);
}
});
return str.join('&');
}
url() {
return this.urlRoot + (this.targetSuffix || '');
}
inject(data, type) {
if (!isArray(data)) {
return;
}
if (this.types && this.types.indexOf(type) === -1) {
this.types.push(type);
}
if (!this.direct) {
data.forEach((target) => {
this.models.push(new Model({
autoSave: this.autoSave,
autoSaveInterval: this.autoSaveInterval,
collection: this,
completed: true,
received: true,
toast: this.toast,
type: type || null,
watch: this.watch
}, target));
});
}
}
sync(action, data, options) {
this.pending = true;
return new Promise((resolve, reject) => __awaiter$2(this, void 0, void 0, function* () {
action = action || 'GET';
options = options || {};
const request = {
method: action,
url: this.url(),
headers: clone(this.headers),
withCredentials: this.withCredentials,
};
if (!isUndefined(data)) {
if (isObject(data) && Object.prototype.hasOwnProperty.call(data, 'p')) {
const validPage = this.normalizePositiveWholeNumber(data.p);
if (isUndefined(validPage)) {
delete data.p;
}
else {
data.p = validPage;
}
}
if (action === 'GET') {
if (isObject(data) && Object.keys(data).length) {
request.url += request.url.includes('?') ? '&' : '?';
request.url += this.serialize(data);
}
}
else {
request.headers['Content-Type'] = 'application/json';
request.data = JSON.stringify(data);
}
}
if (Object.prototype.hasOwnProperty.call(options, 'headers') && typeof options.headers === 'object') {
Object.keys(options.headers).forEach((headerKey) => {
request.headers[headerKey] = options.headers[headerKey];
});
}
const queryHash = `${request.method}:${request.url}`;
if (options.nocache) {
if (queryHash in this.cacheResponse) {
delete this.cacheResponse[queryHash];
}
if (queryHash in this.cacheHeaders) {
delete this.cacheHeaders[queryHash];
}
}
const xhr = new XHR(request);
this.xhr = xhr;
const handler = (response, responseXhr = xhr) => {
if (!isObject(response) && !isArray(response)) {
const error = new ErrorBase({
payload: response,
message: `Invalid Payload: ${request.method} ${request.url}`
}, {});
this.error = true;
this.pending = false;
this.throttleTrigger('change');
this.trigger('error', error);
reject(error);
return;
}
let responseHeaders = null;
if (this.cache && request.method === 'GET') {
if (!(queryHash in this.cacheResponse)) {
this.cacheResponse[queryHash] = cloneDeep(response);
}
if (!(queryHash in this.cacheHeaders)) {
this.cacheHeaders[queryHash] = responseXhr.getAllResponseHeaders();
}
else {
responseHeaders = this.cacheHeaders[queryHash];
}
}
this.header.set(responseHeaders || responseXhr.getAllResponseHeaders());
this.meta.set(response.meta || {});
this.models = [];
const payload = response.payload || response;
this.error = false;
if ((this.meta.has('success') && !this.meta.get('success'))) {
this.error = true;
}
else if (this.direct) {
this.models = payload;
}
else if (isArray(payload)) {
this.inject(payload);
}
else if (isObject(payload)) {
forEach(payload, (value, key) => {
this.inject(value, key);
});
}
else {
if (!this.meta.has('status') && !this.meta.has('success')) {
this.error = true;
}
console.warn(`Invalid Payload: ${request.method} ${request.url}`);
}
this.pending = false;
this.completed = true;
this.filtering = !isEmpty(this.meta.get('api.q'));
this.paginate = !isEmpty(this.meta.get('api.p'));
this.meta.clearTemp();
this.throttleTrigger('change');
this.trigger('complete');
resolve(this.models);
};
if (this.cache && request.method === 'GET' && queryHash in this.cacheResponse) {
handler(this.cacheResponse[queryHash]);
return;
}
const prewarmRequest = typeof window !== 'undefined' && window.StratusApiPrewarm
? window.StratusApiPrewarm[request.url]
: null;
const prewarm = request.method === 'GET'
&& prewarmRequest
&& typeof prewarmRequest.then === 'function'
? prewarmRequest
: null;
if (prewarm) {
prewarm
.then((response) => {
if (response && typeof response.clone === 'function') {
return response.clone().json();
}
return response;
})
.then((response) => {
const prewarmXhr = {
getAllResponseHeaders: () => ({})
};
this.xhr = prewarmXhr;
handler(response, prewarmXhr);
})
.catch(() => {
const retryXhr = new XHR(request);
this.xhr = retryXhr;
const xhrPromise = retryXhr.send();
if (request.method === 'GET' && typeof window !== 'undefined') {
window.StratusApiPrewarm = window.StratusApiPrewarm || {};
window.StratusApiPrewarm[request.url] = xhrPromise;
}
xhrPromise.then((response) => handler(response, retryXhr))
.catch((error) => {
console.error(`XHR: ${request.method} ${request.url}`);
this.throttleTrigger('change');
this.trigger('error', error);
reject(error);
});
});
return;
}
const xhrPromise = this.xhr.send();
if (request.method === 'GET' && typeof window !== 'undefined') {
window.StratusApiPrewarm = window.StratusApiPrewarm || {};
window.StratusApiPrewarm[request.url] = xhrPromise;
}
xhrPromise.then((response) => handler(response, xhr))
.catch((error) => {
console.error(`XHR: ${request.method} ${request.url}`);
this.throttleTrigger('change');
this.trigger('error', error);
reject(error);
return;
});
}));
}
fetch(action, data, options) {
return new Promise((resolve, reject) => __awaiter$2(this, void 0, void 0, function* () {
this.hydrateCollectionApiFromUrl();
this.sync(action, data || this.meta.get('api'), options)
.then(resolve)
.catch((error) => __awaiter$2(this, void 0, void 0, function* () {
console.error('FETCH:', error);
if (!this.toast) {
reject(error);
return;
}
const errorMessage = this.errorMessage(error);
const formatMessage = errorMessage ? `: ${errorMessage}` : '.';
Toastify({
text: `Unable to Fetch ${this.target}${formatMessage}`,
duration: 12000,
close: true,
stopOnFocus: true,
style: {
background: '#E14D45',
}
}).showToast();
reject(error);
return;
}));
}));
}
hydrateCollectionApiFromUrl(force = false) {
if ((!force && this.collectionApiHydratedFromUrl) || typeof window === 'undefined') {
return;
}
const url = new URL(window.location.href);
const urlApi = this.getUrlSearchObject(url);
let filterApplied = false;
let rawPage = null;
if (typeof this.target === 'string' && this.target.length) {
rawPage = this.getUrlSearchValue(url, [`page[${this.target}]`, `p[${this.target}]`]);
}
if (!rawPage) {
rawPage = this.getUrlSearchValue(url, ['p', 'page']);
}
const page = this.normalizePositiveWholeNumber(rawPage);
if (!isUndefined(page)) {
this.meta.set('api.p', page);
this.meta.set('pagination.pageCurrent', page);
this.paginate = true;
}
const query = this.getUrlSearchValue(url, ['q', 'query', 'keyword', 'search']);
if (!isUndefined(query) && query !== null && query !== '') {
this.meta.set('api.q', query);
this.filtering = true;
filterApplied = true;
}
const tags = this.getUrlSearchArray(url, ['tags', 'tag']);
if (!isEmpty(tags)) {
this.meta.set('api.tags', map(tags, this.parseNumberLikeValue));
filterApplied = true;
}
const contentTypes = this.getUrlSearchArray(url, ['contentType', 'contentTypes']);
if (!isEmpty(contentTypes)) {
this.meta.set('api.contentType', map(contentTypes, this.parseNumberLikeValue));
filterApplied = true;
}
forEach([
'authorId',
'status',
'filterPublished',
'filterTimeField',
'filterTimeMin',
'filterTimeMax',
'filterTimeRange',
'sort',
'sortOrder',
'filter'
], (apiKey) => {
if (!has(urlApi, apiKey)) {
return;
}
const value = get(urlApi, apiKey);
if (isUndefined(value) || value === null || value === '') {
return;
}
this.meta.set(`api.${apiKey}`, this.parseUrlValue(value));
filterApplied = true;
});
if (filterApplied) {
this.meta.set('filterApplied', true);
}
this.collectionApiHydratedFromUrl = true;
}
getUrlSearchValue(url, keys) {
for (const key of keys) {
const value = url.searchParams.get(key);
if (!isUndefined(value) && value !== null && value !== '') {
return this.parseUrlValue(value);
}
}
return undefined;
}
getUrlSearchArray(url, keys) {
const values = [];
url.searchParams.forEach((value, key) => {
if (!find(keys, (name) => key === name || key === `${name}[]` || new RegExp(`^${name}\\[\\d+\\]$`).test(key))) {
return;
}
const parsedValue = this.parseUrlValue(value);
if (isArray(parsedValue)) {
values.push(...parsedValue);
return;
}
if (typeof parsedValue === 'string' && parsedValue.indexOf(',') !== -1) {
values.push(...parsedValue.split(',').map((item) => item.trim()).filter((item) => item !== ''));
return;
}
values.push(parsedValue);
});
return values;
}
getUrlSearchObject(url) {
const output = {};
url.searchParams.forEach((value, key) => {
this.assignUrlSearchValue(output, this.getUrlSearchParts(key), value);
});
return output;
}
getUrlSearchParts(key) {
const parts = [];
const pattern = /([^\[\]]+)|\[(.*?)\]/g;
let match;
while ((match = pattern.exec(key)) !== null) {
parts.push(match[1] || match[2] || '');
}
return parts;
}
assignUrlSearchValue(output, parts, rawValue) {
if (!parts.length) {
return;
}
let cursor = output;
forEach(parts, (part, index) => {
const last = index === parts.length - 1;
const key = part === '' ? this.nextArrayKey(cursor) : part;
if (last) {
if (isUndefined(cursor[key])) {
cursor[key] = rawValue;
}
else if (isArray(cursor[key])) {
cursor[key].push(rawValue);
}
else {
cursor[key] = [cursor[key], rawValue];
}
return;
}
if (!isObject(cursor[key])) {
cursor[key] = parts[index + 1] === '' || /^\d+$/.test(parts[index + 1]) ? [] : {};
}
cursor = cursor[key];
});
}
nextArrayKey(value) {
return isArray(value) ? value.length : Object.keys(value).length;
}
parseUrlValue(value) {
if (isArray(value)) {
return map(value, (item) => this.parseUrlValue(item));
}
if (isObject(value)) {
return reduce(value, (result, item, key) => {
result[key] = this.parseUrlValue(item);
return result;
}, {});
}
if (typeof value !== 'string') {
return value;
}
if (isJSON(value)) {
return JSON.parse(value);
}
return this.parseNumberLikeValue(value);
}
parseNumberLikeValue(value) {
if (typeof value !== 'string') {
return value;
}
if (/^-?\d+(\.\d+)?$/.test(value)) {
return Number(value);
}
return value;
}
filter(query) {
this.filtering = !isEmpty(query);
this.meta.set('api.q', !isUndefined(query) ? query : '');
this.meta.set('api.p', 1);
return this.fetch();
}
throttleFilter(query) {
this.meta.set('api.q', !isUndefined(query) ? query : '');
return new Promise((resolve, reject) => {
const request = this.throttle();
if (cookie('env')) {
console.log('request:', request);
}
request.then((models) => {
if (cookie('env')) ;
resolve(models);
}).catch(reject);
});
}
page(page) {
const validPage = this.normalizePositiveWholeNumber(page);
this.paginate = !isUndefined(validPage);
if (isUndefined(validPage)) {
this.clearApiPage();
return;
}
this.meta.set('api.p', validPage);
this.fetch().then();
this.clearApiPage();
}
clearApiPage() {
const collectionApi = this.meta.get('api');
if (isObject(collectionApi) && Object.prototype.hasOwnProperty.call(collectionApi, 'p')) {
delete collectionApi.p;
}
}
normalizePositiveWholeNumber(value) {
const page = Number(value);
return Number.isFinite(page) && Number.isInteger(page) && page >= 1 ? page : undefined;
}
toJSON() {
return !this.direct ? this.models.map((model) => model.toJSON()) : this.models;
}
add(target, options) {
if (!isObject(target)) {
console.error('collection.add: target object not set!');
return;
}
if (!options || typeof options !== 'object') {
options = {};
}
if (target instanceof Model) {
target.collection = this;
}
else {
options.collection = this;
target = new Model(options, target);
target.initialize();
if (options.autoSave || options.watch) {
if (target.isNew()) {
target.save();
}
else if (!target.completed) {
target.fetch();
}
}
}
if (options.save) {
target.save();
}
if (options.prepend) {
this.models.unshift(target);
}
else {
this.models.push(target);
}
if (options.trigger) {
this.trigger('add', target);
}
this.throttleTrigger('change');
return target;
}
remove(target) {
if (!this.direct) {
this.models.splice(this.models.indexOf(target), 1);
this.throttleTrigger('change');
}
return this;
}
find(predicate) {
return find(this.models, isFunction(predicate) ? predicate : (model) => model.get('id') === predicate);
}
map(predicate) {
return map(this.models, model => model instanceof Model ? model.get(predicate) : null);
}
pluck(attribute) {
return map(this.models, model => model instanceof Model ? model.pluck(attribute) : null);
}
exists(attribute) {
return !!reduce(this.pluck(attribute) || [], (memo, data) => memo || !isUndefined(data));
}
errorMessage(error) {
if (error instanceof ErrorBase) {
console.error(`[${error.code}] ${error.message}`, error);
return error.code !== 'Internal' ? error.message : null;
}
const digest = (error.responseText && isJSON(error.responseText)) ? JSON.parse(error.responseText) : null;
if (!digest) {
return null;
}
const message = get(digest, 'meta.status[0].message') || get(digest, 'error.exception[0].message') || null;
if (!message) {
return null;
}
if (!cookie('env') && has(digest, 'error.exception[0].message')) {
console.error('[xhr] server:', message);
return null;
}
return message;
}
} exports('Collection', Collection);
Stratus.Services.Collection = [
'$provide',
($provide) => {
$provide.factory('Collection', [() => Collection]);
}
];
Stratus.Data.Collection = Collection;
var __awaiter$1 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Stratus.Modules.ngSanitize = true;
Stratus.Controllers.Generic = [
'$scope',
'$element',
'$log',
'$sce',
'$parse',
'$window',
'Registry',
($scope, $element, $log, $sce, $parse, $window, R) => __awaiter$1(void 0, void 0, void 0, function* () {
$scope.uid = safeUniqueId('controller_generic_');
Stratus.Instances[$scope.uid] = $scope;
yield R.fetch($element, $scope);
$scope.ctrlParent = $scope.$parent;
$scope.Stratus = Stratus;
$scope._ = _;
$scope.cookie = cookie;
$scope.$window = $window;
$scope.getUrlParams = getUrlParams;
$scope.setUrlParams = setUrlParams;
$scope.$log = $log;
$scope.Math = Math;
$scope.isArray = isArray;
$scope.isDate = isDate;
$scope.isDefined = (value) => !isUndefined(value);
$scope.isElement = isElement;
$scope.isFunction = isFunction;
$scope.isNumber = isNumber;
$scope.isObject = isObject;
$scope.isString = isString;
$scope.isUndefined = isUndefined;
$scope.getHTML = $sce.trustAsHtml;
$scope.getURL = $sce.trustAsResourceUrl;
$scope.getAnchor = () => {
const url = window.location.href;
if (!url || !url.length) {
return false;
}
const anchor = url.indexOf('#');
if (anchor < 0) {
return false;
}
if ((anchor + 1) >= url.length) {
return false;
}
return url.substring(anchor + 1, url.length);
};
$scope.scrollToAnchor = (anchor, inUrl, delay) => {
if (!anchor || isEmpty(anchor)) {
$log.warn('anchor id not set!');
return false;
}
if (isUndefined(inUrl)) {
inUrl = false;
}
if (inUrl && anchor !== $scope.getAnchor()) {
return false;
}
const el = $window.document.getElementById(anchor);
if (!el) {
$log.warn(`element not found: ${anchor}`);
return false;
}
if (!delay) {
el.scrollIntoView({ behavior: 'smooth' });
return true;
}
return setTimeout(() => {
$scope.scrollToAnchor(anchor, inUrl, --delay);
}, 1);
};
if ($scope.data && isFunction($scope.data.on)) {
$scope.data.on('change', () => $scope.$applyAsync());
}
if (!$scope.collection || !($scope.collection instanceof Collection)) {
return;
}
const selected = {
id: $element.attr('data-selected'),
raw: $element.attr('data-raw')
};
if (!selected.id || !isString(selected.id)) {
return;
}
if (isJSON(selected.id)) {
selected.id = JSON.parse(selected.id);
$scope.$watch('collection.models', (models) => {
if ($scope.selected || $scope.selectedInit) {
return;
}
forEach(models, (model) => {
if (selected.id !== model.getIdentifier()) {
return;
}
$scope.selected = selected.raw ? model.data : model;
$scope.selectedInit = true;
});
});
}
else {
selected.model = $parse(selected.id);
selected.value = selected.model($scope.$parent);
if (!isArray(selected.value)) {
return;
}
selected.value = selected.value.filter((n) => n);
if (selected.value.length) {
return;
}
$scope.selected = head(selected.value);
}
})
];
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
let injector = getInjector();
let $interpolate;
const serviceVerify = () => __awaiter(void 0, void 0, void 0, function* () {
return new Promise((resolve, _reject) => __awaiter(void 0, void 0, void 0, function* () {
if ($interpolate) {
resolve(true);
return;
}
if (!injector) {
injector = getInjector();
}
if (injector) {
$interpolate = injector.get('$interpolate');
}
if ($interpolate) {
resolve(true);
return;
}
setTimeout(() => {
if (cookie('env')) {
console.log('wait for $interpolate service:', $interpolate);
}
serviceVerify().then(resolve);
}, 250);
}));
});
class Registry {
constructor() {
}
fetch($element, $scope) {
return new Promise((resolve, _reject) => __awaiter(this, void 0, void 0, function* () {
if (typeof $element === 'string') {
$element = {
target: $element
};
}
const inputs = {};
const baseInputs = [
'id',
'api',
'temp',
'decouple',
'fetch'
];
forEach(union(ModelOptionKeys, CollectionOptionKeys, baseInputs), (option) => set(inputs, option, 'data-' + kebabCase(option)));
const options = forEach(inputs, (value, key, list) => {
list[key] = $element.attr ? $element.attr(value) : $element[key];
if (!isJSON(list[key])) {
return;
}
list[key] = JSON.parse(list[key]);
});
options.api = sanitize(options.api);
options.temp = sanitize(options.temp);
let completed = 0;
const verify = () => {
if (!isNumber(completed) || completed !== size(options)) {
return;
}
resolve(this.build(options, $scope));
};
if (!$interpolate) {
yield serviceVerify();
}
forEach(options, (element, key) => __awaiter(this, void 0, void 0, function* () {
if (!element || typeof element !== 'string' || !$scope || !$scope.$parent) {
completed++;
verify();
return;
}
const interpreter = $interpolate(element, false, null, true);
const initial = interpreter($scope.$parent);
if (typeof initial !== 'undefined') {
options[key] = initial;
completed++;
verify();
return;
}
if (cookie('env')) {
console.log(`poll (${key}): start`);
}
let value;
try {
value = yield poll(() => interpreter($scope.$parent), 1500, 250);
}
catch (err) {
if (cookie('env') ||
err.name !== 'Timeout') {
console.error(err);
}
}
if (cookie('env')) {
console.log(`poll (${key}):`, value);
}
options[key] = value;
completed++;
verify();
}));
}));
}
build(options, $scope) {
let data;
if (options.payload || options.convoy) {
options.fetch = false;
}
if (options.target) {
options.target = ucfirst(options.target);
if (options.manifest || options.id) {
if (!Stratus.Catalog[options.target]) {
Stratus.Catalog[options.target] = {};
}
const id = options.id || 'manifest';
if (options.decouple || !Stratus.Catalog[options.target][id]) {
const modelOptions = {
stagger: true
};
forEach(ModelOptionKeys, (element) => {
const optionValue = get(options, element);
if (isUndefined(optionValue)) {
return;
}
set(modelOptions, element, optionValue);
});
data = new Model(modelOptions, {
id: options.id
});
if (!options.decouple) {
Stratus.Catalog[options.target][id] = data;
}
}
else if (Stratus.Catalog[options.target][id]) {
data = Stratus.Catalog[options.target][id];
}
}
else {
const registry = !options.direct ? 'Catalog' : 'Compendium';
if (!Stratus[registry][options.target]) {
Stratus[registry][options.target] = {};
}
if (options.decouple ||
!Stratus[registry][options.target].collection) {
const collectionOptions = {};
forEach(CollectionOptionKeys, (element) => {
const optionValue = get(options, element);
if (isUndefined(optionValue)) {
return;
}
set(collectionOptions, element, optionValue);
});
data = new Collection(collectionOptions);
if (!options.decouple) {
Stratus[registry][options.target].collection = data;
}
}
else if (Stratus[registry][options.target].collection) {
data = Stratus[registry][options.target].collection;
}
}
if (options.api) {
data.meta.set('api', isJSON(options.api) ? JSON.parse(options.api) : options.api);
}
if (options.temp && isObject(options.temp) && !data.completed) {
forEach(flatten(options.temp), (v, k) => {
console.log('setting temp:', `api.${k}`, v);
data.meta.temp(`api.${k}`, v);
});
}
if (data instanceof Model && data.stagger && typeof data.initialize === 'function') {
data.initialize();
}
}
if (typeof data === 'object' && data !== null) {
if (typeof $scope !== 'undefined') {
$scope.data = data;
if (data instanceof Model) {
$scope.model = data;
}
else if (data instanceof Collection) {
$scope.collection = data;
}
if (data instanceof EventManager && typeof $scope.$applyAsync === 'function') {
data.on('change', () => {
$scope.$applyAsync();
});
data.on('error', () => {
$scope.$applyAsync();
});
if (data.completed) {
$scope.$applyAsync();
}
}
}
if (!data.pending
&& !data.completed
&& (isUndefined(options.fetch) || options.fetch)) {
data.fetch().then();
}
}
return data;
}
} exports('Registry', Registry);
Stratus.Services.Registry = [
'$provide',
($provide) => {
$provide.factory('Registry', [
() => {
return new Registry();
}
]);
}
];
Stratus.Data.Registry = Registry;
const min$1 = !cookie('env') ? '.min' : '';
const name$1 = 'base';
const localPath$1 = '@stratusjs/angularjs/src/components';
Stratus.Components.Base = {
transclude: {
model: '?stratusBaseModel'
},
bindings: {
elementId: '@',
ngModel: '=',
property: '@',
target: '@',
id: '@',
manifest: '@',
decouple: '@',
direct: '@',
api: '@',
urlRoot: '@',
limit: '@',
options: '<'
},
controller($scope, $attrs) {
$scope.uid = safeUniqueId(name$1);
Stratus.Instances[$scope.uid] = $scope;
$scope.elementId = $attrs.elementId || $scope.uid;
Stratus.Internals.CssLoader(`${Stratus.BaseUrl + Stratus.BundlePath + localPath$1}/${name$1}${min$1}.css`).then();
$scope.initialized = false;
$scope.property = $attrs.property || null;
$scope.data = null;
$scope.model = null;
$scope.collection = null;
if ($attrs.target) {
$scope.registry = $scope.registry || new Registry();
$scope.registry.fetch($attrs, $scope).then();
}
$scope.$watch('$ctrl.ngModel', (data) => {
if (data instanceof Model && data !== $scope.model) {
$scope.model = data;
}
else if (data instanceof Collection && data !== $scope.collection) {
$scope.collection = data;
}
});
$scope.initialize = () => {
if ($scope.initialized) {
return;
}
if ($scope.model) {
$scope.initialized = true;
$scope.model.on('change', () => {
console.log('model changed:', $scope.model.patch);
});
}
if ($scope.collection) {
$scope.initialized = true;
console.log('collection available');
}
};
$scope.$watch('$scope.model.completed', (newVal, oldVal) => {
if (!newVal || isEqual(newVal, oldVal)) {
return;
}
$scope.initialize();
});
$scope.$watch('$scope.collection.completed', (newVal, oldVal) => {
if (!newVal || isEqual(newVal, oldVal)) {
return;
}
$scope.initialize();
});
if (cookie('env')) {
console.log(name$1, 'component:', $scope, $attrs);
}
},
templateUrl: `${Stratus.BaseUrl}${Stratus.DeploymentPath}${localPath$1}/${name$1}${min$1}.html`
};
const min = !cookie('env') ? '.min' : '';
const name = 'base';
const localPath = '@stratusjs/angularjs/src/directives';
Stratus.Directives.Base = function () {
return {
restrict: 'A',
scope: {
ngModel: '='
},
link: ($scope, $element, $attrs) => {
const $ctrl = this;
$scope.uid = safeUniqueId(name);
Stratus.Instances[$scope.uid] = $scope;
$scope.elementId = $element.elementId || $scope.uid;
Stratus.Internals.CssLoader(Stratus.BaseUrl + Stratus.BundlePath + localPath + name + min + '.css').then();
$scope.initialized = false;
console.log('directive:', $ctrl, $scope, $element, $attrs);
},
templateUrl: Stratus.BaseUrl + Stratus.BundlePath + localPath + name + min + '.html'
};
};
})
};
}));
//# sourceMappingURL=angularjs.bundle.js.map