@nent/core
Version:
233 lines (226 loc) • 8.43 kB
JavaScript
/*!
* NENT 2022
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const index = require('./index-1829aebc.js');
const logging = require('./logging-37c154cf.js');
const remote = require('./remote-d40ac61b.js');
const interfaces = require('./interfaces-95d0415a.js');
const state$1 = require('./state-246c735d.js');
const state = require('./state-f97ff0e6.js');
const visits = require('./visits-81507e28.js');
const strings = require('./strings-fe5a8e44.js');
const stateSubscriber = require('./state-subscriber-0ded559f.js');
require('./tokens-4f8bcd42.js');
require('./factory-0d7ddff9.js');
require('./index-637e8c28.js');
require('./index-96f3ab3f.js');
require('./values-b2399e33.js');
require('./promises-463f4e01.js');
require('./mutex-7ae5ebad.js');
require('./memory-33fe6263.js');
/**
* It takes a view prompt, and returns a view prompt with the `visited` and `visit` properties set
* @param {IViewPrompt} viewPrompt - IViewPrompt
* @returns A promise that resolves to an object with the following properties:
* when: string
* visit: VisitStrategy
* visited: boolean
* path: string
*/
async function getViewPromptStateProperties(viewPrompt) {
let { when, path, visit = visits.VisitStrategy.once } = viewPrompt;
let visited = await visits.hasVisited(path);
if (state.state.dataEnabled && when) {
const { evaluatePredicate } = await Promise.resolve().then(function () { return require('./expressions-531d82f5.js'); }).then(function (n) { return n.expressions; });
const shouldGo = await evaluatePredicate(when);
if (shouldGo) {
visit = visits.VisitStrategy.once;
visited = false;
}
else {
visit = visits.VisitStrategy.optional;
}
}
return { when, visit, visited, path };
}
/**
* > Find the first unvisited item in the list that is not optional
* @param {IViewPrompt[]} doList - IViewPrompt[]
* @returns A Promise that resolves to an IViewPrompt or null
*/
async function findFirstUnvisited(doList) {
const found = doList
.filter(d => d.visit !== visits.VisitStrategy.optional)
.find(i => i.visited == false);
return found || null;
}
/**
* It takes an array of view prompts, and returns the first one that hasn't been visited yet
* @param childViewDos - Array<IViewPrompt>
* @returns A promise that resolves to the first unvisited view prompt.
*/
async function resolveNext(childViewDos) {
const converted = await Promise.all(childViewDos.map(e => getViewPromptStateProperties(e)));
const result = await findFirstUnvisited(converted);
return result;
}
const viewCss = ":host{display:none}:host(.active){display:block}:host(.active) ::slotted([slot='content']),:host(.active) div[slot='content']{display:none}:host(.exact){display:block}:host(.exact) ::slotted([slot='content']),:host(.exact) div[slot='content']{display:block}";
const View = class {
constructor(hostRef) {
index.registerInstance(this, hostRef);
this.match = null;
this.exactMatch = false;
this.srcElement = null;
this.contentElement = null;
/**
* The title for this view. This is prefixed
* before the app title configured in n-views
*
*/
this.pageTitle = '';
/**
* The page description for this view.
*
*/
this.pageDescription = '';
/**
* The keywords to add to the keywords meta-tag for this view.
*
*/
this.pageKeywords = '';
/**
* The robots instruction for search indexing
*
*/
this.pageRobots = 'all';
/**
* Header height or offset for scroll-top on this
* view.
*/
this.scrollTopOffset = 0;
/**
* The path for this route should only be matched
* when it is exact.
*/
this.exact = false;
/**
* Cross Origin Mode if the content is pulled from
* a remote location
*/
this.mode = 'cors';
/**
* Before rendering remote HTML, replace any data-tokens with their
* resolved values. This also commands this element to
* re-render it's HTML for data-changes. This can affect
* performance.
*
* IMPORTANT: ONLY WORKS ON REMOTE HTML
*/
this.resolveTokens = false;
/**
* Turn on debug statements for load, update and render events.
*/
this.debug = false;
/**
* Force render with data & route changes.
*/
this.noCache = false;
}
/**
* Return all child elements used for processing. This function is
* primarily meant for testing.
*
*/
async getChildren() {
return {
activators: this.route.actionActivators,
views: this.childViews,
dos: this.childPrompts,
};
}
get parent() {
var _a;
return ((_a = this.el.parentElement) === null || _a === void 0 ? void 0 : _a.closest('n-view')) || null;
}
get childPrompts() {
return Array.from(this.el.querySelectorAll('n-view-prompt') || []).filter(e => this.route.isChild(e));
}
get childViews() {
return Array.from(this.el.querySelectorAll('n-view') || []).filter(e => this.route.isChild(e));
}
async componentWillLoad() {
logging.debugIf(this.debug, `n-view: ${this.path} loading`);
this.contentKey = `rem-content-${strings.slugify(this.contentSrc || 'none')}`;
this.srcKey = `rem-source-${strings.slugify(this.src || 'none')}`;
if (!state$1.state.router) {
logging.warn(`n-view: ${this.path} cannot load outside of an n-views element`);
return;
}
this.route = state$1.state.router.createRoute(this.el, this.parent, (match) => {
this.match = match ? Object.assign({}, match) : null;
this.exactMatch = (match === null || match === void 0 ? void 0 : match.isExact) || false;
});
if (state.state.dataEnabled && this.resolveTokens) {
this.dataSubscription = new stateSubscriber.CommonStateSubscriber(this, 'dataEnabled', interfaces.DATA_EVENTS.DataChanged);
}
}
async componentWillRender() {
var _a;
logging.debugIf(this.debug, `n-view: ${this.path} will render`);
if (this.match) {
logging.debugIf(this.debug, `n-view: ${this.path} route is matched `);
if (this.src && this.srcElement == null) {
this.srcElement = await remote.resolveRemoteContentElement(window, this.src, this.mode, this.srcKey, this.resolveTokens);
remote.replaceHtmlInElement(this.el, `#${this.srcKey}`, this.srcElement);
}
logging.debugIf(this.debug, `n-view: ${this.path} found ${this.childViews.length} child views and` +
` ${this.childPrompts.length} child view-prompts`);
// exact-match
if (this.match.isExact) {
logging.debugIf(this.debug, `n-view: ${this.path} route exactly matched `);
const viewDos = this.childPrompts.map(el => {
const { path, when, visit } = el;
return {
path: this.route.normalizeChildUrl(path),
when,
visit,
};
});
const nextDo = await resolveNext(viewDos);
if (nextDo) {
this.route.replaceWithRoute(nextDo.path);
return;
}
else {
if (this.contentSrc && this.contentElement == null)
this.contentElement = await remote.resolveRemoteContentElement(window, this.contentSrc, this.mode, this.contentKey, this.resolveTokens, 'content');
visits.markVisit((_a = this.match) === null || _a === void 0 ? void 0 : _a.url);
}
}
}
}
render() {
logging.debugIf(this.debug, `n-view: ${this.path} render`);
remote.replaceHtmlInElement(this.el, `#${this.contentKey}`, this.contentElement);
return (index.h(index.Host, null, index.h("slot", null), index.h("slot", { name: "content" })));
}
async componentDidRender() {
var _a, _b, _c, _d;
if (!((_b = (_a = this.route) === null || _a === void 0 ? void 0 : _a.match) === null || _b === void 0 ? void 0 : _b.isExact)) {
(_c = this.contentElement) === null || _c === void 0 ? void 0 : _c.remove();
if (this.noCache)
this.contentElement = null;
}
await ((_d = this.route) === null || _d === void 0 ? void 0 : _d.loadCompleted());
}
disconnectedCallback() {
var _a, _b;
(_a = this.dataSubscription) === null || _a === void 0 ? void 0 : _a.destroy();
(_b = this.route) === null || _b === void 0 ? void 0 : _b.destroy();
}
get el() { return index.getElement(this); }
};
View.style = viewCss;
exports.n_view = View;