@dosgato/templating 0.0.20 → 0.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
- import { PageWithAncestors, ComponentData } from './component';
2
- import { LinkDefinition } from './links';
1
+ import { PageWithAncestors, ComponentData } from './component.js';
2
+ import { LinkDefinition } from './links.js';
3
3
  export declare type APITemplateType = 'page' | 'component' | 'data';
4
4
  /**
5
5
  * This interface lays out the structure the API needs for each template in the system.
@@ -1,26 +1,21 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getKeywords = exports.extractLinksFromText = void 0;
4
- const stopwords_1 = require("./stopwords");
1
+ import { stopwords } from './stopwords.js';
5
2
  /**
6
3
  * This function is used by API template definitions to help them identify links inside large blocks
7
4
  * of text and return them for indexing.
8
5
  */
9
- function extractLinksFromText(text) {
6
+ export function extractLinksFromText(text) {
10
7
  const matches = text.matchAll(/{.*"type"\s?:\s+"\w+".*?}/gi);
11
8
  return Array.from(matches).map(m => JSON.parse(m[0]));
12
9
  }
13
- exports.extractLinksFromText = extractLinksFromText;
14
10
  /**
15
11
  * This function is used by API template definitions to help them identify all the searchable
16
12
  * words in a large block of text and return them for indexing.
17
13
  */
18
- function getKeywords(text, options) {
14
+ export function getKeywords(text, options) {
19
15
  return Array.from(new Set(text
20
16
  .toLocaleLowerCase()
21
17
  .normalize('NFD').replace(/\p{Diacritic}/gu, '')
22
18
  .split(/[^\w-]+/)
23
19
  .flatMap(word => word.includes('-') ? word.split('-').concat(word.replace('-', '')) : [word])
24
- .filter(word => word.length > 2 && (options?.stopwords === false || !stopwords_1.stopwords[word]) && isNaN(Number(word)))));
20
+ .filter(word => word.length > 2 && (options?.stopwords === false || !stopwords[word]) && isNaN(Number(word)))));
25
21
  }
26
- exports.getKeywords = getKeywords;
@@ -1,6 +1,6 @@
1
- import { EditBarOpts } from './editbar';
2
- import { LinkDefinition } from './links';
3
- import { ResourceProvider } from './provider';
1
+ import { EditBarOpts } from './editbar.js';
2
+ import { ResourceProvider } from './provider.js';
3
+ import { APIClient } from './render.js';
4
4
  /**
5
5
  * This is the primary templating class to build your templates. Subclass it and provide
6
6
  * at least a render function.
@@ -20,28 +20,48 @@ export declare abstract class Component<DataType extends ComponentData = any, Fe
20
20
  page?: Page;
21
21
  hadError: boolean;
22
22
  /**
23
- * This function will be provided by the rendering server and should be used inside your fetch,
24
- * method to convert a link, as input by a user, into a URL suitable for an href, or optionally
25
- * an absolute URL suitable for a backend http request or non-HTML document like an RSS feed.
23
+ * The rendering server will provide an instance of the APIClient interface so that
24
+ * you can run any API GraphQL query you like in your `fetch` function. There are also
25
+ * some useful methods there like processRich to help you convert links in rich text
26
+ * strings.
27
+ *
28
+ * Do NOT mutate data received from the API as it may be cached and given to other
29
+ * Component instances that run the same type of query.
26
30
  */
27
- resolveLink: (link: string | LinkDefinition, absolute?: boolean) => Promise<string>;
31
+ api: APIClient;
28
32
  /**
29
- * This function will be provided by the rendering server and should be used inside your fetch
30
- * method to prepare editor-provided HTML for rendering. It will do things like find and resolve
31
- * link definitions in the internal dosgato format and clean up tags that were accidentally left
32
- * open to protect overall page integrity.
33
+ * Retrieve the data for the root page of the page this component is on. Useful for
34
+ * implementing inheritance schemes.
35
+ *
36
+ * This function will be provided by the rendering service.
37
+ *
38
+ * Do NOT mutate the data returned by this function, as it may be cached and given to
39
+ * other Component instances.
33
40
  */
34
- processRich: (text: string) => Promise<string>;
41
+ getRootPageData: () => Promise<PageData>;
42
+ /**
43
+ * Retrieve the data for all ancestor pages of the page this component is on. Useful
44
+ * for implementing inheritance schemes.
45
+ *
46
+ * This function will be provided by the rendering service.
47
+ *
48
+ * Do NOT mutate the data returned by this function, as it may be cached and given to
49
+ * other Component instances.
50
+ */
51
+ getAncestorPageData: () => Promise<PageData[]>;
35
52
  /**
36
53
  * The first phase of rendering a component is the fetch phase. Each component may
37
54
  * provide a fetch method that looks up data it needs from external sources. This step
38
55
  * is FLAT - it will be executed concurrently for all the components on the page for
39
56
  * maximum speed.
40
57
  *
41
- * Note that this.page will be available, along with its ancestors property containing
42
- * all the data from ancestor pages, in case there is a need for inheritance. It is
43
- * recommended to copy any needed data into the return object, as future phases will not
44
- * want to resolve the inheritance again.
58
+ * Place any needed data into the return object, and it will be available to you as `this.fetched`
59
+ * during the rendering phase.
60
+ *
61
+ * Note that this.page will be available, and getRootPageData and getAncestorPageData are
62
+ * available in case there is a need for inheritance. If you need to inherit entire components,
63
+ * you may add them to your this.areas map, e.g.
64
+ * `this.areas.get('myarea').push(new Component(inheritedData, this.path + '/myarea/inherit1', this))`
45
65
  */
46
66
  fetch(editMode: boolean): Promise<FetchedType>;
47
67
  /**
@@ -156,6 +176,10 @@ export interface ComponentData {
156
176
  export interface PageData extends ComponentData {
157
177
  savedAtVersion: Date;
158
178
  }
179
+ export interface DataData {
180
+ templateKey: string;
181
+ savedAtVersion: Date;
182
+ }
159
183
  export interface ContextBase {
160
184
  /**
161
185
  * For accessibility, every component should consider whether it is creating headers
package/dist/component.js CHANGED
@@ -1,8 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Page = exports.Component = void 0;
4
- const editbar_1 = require("./editbar");
5
- const provider_1 = require("./provider");
1
+ import { editBar, newBar } from './editbar.js';
2
+ import { ResourceProvider } from './provider.js';
6
3
  /**
7
4
  * This is the primary templating class to build your templates. Subclass it and provide
8
5
  * at least a render function.
@@ -10,7 +7,7 @@ const provider_1 = require("./provider");
10
7
  * During rendering, it will be "hydrated" - placed into a full page structure with its
11
8
  * parent and child components linked.
12
9
  */
13
- class Component extends provider_1.ResourceProvider {
10
+ export class Component extends ResourceProvider {
14
11
  // the constructor is part of the recursive hydration mechanism: constructing
15
12
  // a Component will also construct/hydrate all its child components
16
13
  constructor(data, path, parent) {
@@ -36,10 +33,13 @@ class Component extends provider_1.ResourceProvider {
36
33
  * is FLAT - it will be executed concurrently for all the components on the page for
37
34
  * maximum speed.
38
35
  *
39
- * Note that this.page will be available, along with its ancestors property containing
40
- * all the data from ancestor pages, in case there is a need for inheritance. It is
41
- * recommended to copy any needed data into the return object, as future phases will not
42
- * want to resolve the inheritance again.
36
+ * Place any needed data into the return object, and it will be available to you as `this.fetched`
37
+ * during the rendering phase.
38
+ *
39
+ * Note that this.page will be available, and getRootPageData and getAncestorPageData are
40
+ * available in case there is a need for inheritance. If you need to inherit entire components,
41
+ * you may add them to your this.areas map, e.g.
42
+ * `this.areas.get('myarea').push(new Component(inheritedData, this.path + '/myarea/inherit1', this))`
43
43
  */
44
44
  async fetch(editMode) {
45
45
  return undefined;
@@ -150,7 +150,7 @@ class Component extends provider_1.ResourceProvider {
150
150
  editBar(opts = {}) {
151
151
  opts.label ?? (opts.label = this.editLabel());
152
152
  opts.extraClass ?? (opts.extraClass = this.editClass());
153
- return (0, editbar_1.editBar)(this.path, opts);
153
+ return editBar(this.path, opts);
154
154
  }
155
155
  /**
156
156
  * Components may override this function to provide a custom new bar
@@ -160,11 +160,10 @@ class Component extends provider_1.ResourceProvider {
160
160
  newBar(areaName, opts = {}) {
161
161
  opts.label ?? (opts.label = this.newLabel(areaName));
162
162
  opts.extraClass ?? (opts.extraClass = this.newClass(areaName));
163
- return (0, editbar_1.newBar)(this.path + '.' + areaName, opts);
163
+ return newBar(this.path + '.' + areaName, opts);
164
164
  }
165
165
  }
166
- exports.Component = Component;
167
- class Page extends Component {
166
+ export class Page extends Component {
168
167
  constructor(page) {
169
168
  super(page.data, '/', undefined);
170
169
  this.pagePath = page.path;
@@ -174,4 +173,3 @@ class Page extends Component {
174
173
  console.warn(`Recoverable issue occured during render of ${this.pagePath}. Component at ${path} threw the following error:`, e);
175
174
  }
176
175
  }
177
- exports.Page = Page;
package/dist/editbar.js CHANGED
@@ -1,28 +1,23 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.newBar = exports.editBar = void 0;
4
- const txstate_utils_1 = require("txstate-utils");
5
- function editBar(path, opts) {
1
+ import { htmlEncode, randomid } from 'txstate-utils';
2
+ export function editBar(path, opts) {
6
3
  if (!opts.editMode)
7
4
  return '';
8
- const id = (0, txstate_utils_1.randomid)();
5
+ const id = randomid();
9
6
  return `
10
- <div class="dg-edit-bar ${opts.extraClass ?? ''}" data-path="${(0, txstate_utils_1.htmlEncode)(path)}" draggable="true" ondragstart="window.dgEditing.drag(event)" ondragover="window.dgEditing.over(event)" ondragend="window.dgEditing.drop(event)">
11
- <span id="${id}" class="dg-edit-bar-label">${(0, txstate_utils_1.htmlEncode)(opts.label)}</span>
7
+ <div class="dg-edit-bar ${opts.extraClass ?? ''}" data-path="${htmlEncode(path)}" draggable="true" ondragstart="window.dgEditing.drag(event)" ondragover="window.dgEditing.over(event)" ondragend="window.dgEditing.drop(event)">
8
+ <span id="${id}" class="dg-edit-bar-label">${htmlEncode(opts.label)}</span>
12
9
  <button onclick="window.dgEditing.edit(event)" aria-describedby="${id}">Edit</button>
13
10
  <button onclick="window.dgEditing.move(event)" aria-describedby="${id}">Move</button>
14
11
  <button onclick="window.dgEditing.del(event)" aria-describedby="${id}">Trash</button>
15
12
  </div>
16
13
  `.trim();
17
14
  }
18
- exports.editBar = editBar;
19
- function newBar(path, opts) {
15
+ export function newBar(path, opts) {
20
16
  if (!opts.editMode)
21
17
  return '';
22
18
  return `
23
- <div role="button" onclick="window.dgEditing.create(event)" class="dg-new-bar ${opts.extraClass ?? ''}" data-path="${(0, txstate_utils_1.htmlEncode)(path)}">
24
- ${(0, txstate_utils_1.htmlEncode)(opts.label)}
19
+ <div role="button" onclick="window.dgEditing.create(event)" class="dg-new-bar ${opts.extraClass ?? ''}" data-path="${htmlEncode(path)}">
20
+ ${htmlEncode(opts.label)}
25
21
  </div>
26
22
  `.trim();
27
23
  }
28
- exports.newBar = newBar;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- export * from './apitemplate';
2
- export * from './component';
3
- export * from './links';
4
- export * from './provider';
5
- export * from './uitemplate';
1
+ export * from './apitemplate.js';
2
+ export * from './component.js';
3
+ export * from './links.js';
4
+ export * from './provider.js';
5
+ export * from './render.js';
6
+ export * from './stopwords.js';
7
+ export * from './uitemplate.js';
package/dist/index.js CHANGED
@@ -1,21 +1,7 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./apitemplate"), exports);
18
- __exportStar(require("./component"), exports);
19
- __exportStar(require("./links"), exports);
20
- __exportStar(require("./provider"), exports);
21
- __exportStar(require("./uitemplate"), exports);
1
+ export * from './apitemplate.js';
2
+ export * from './component.js';
3
+ export * from './links.js';
4
+ export * from './provider.js';
5
+ export * from './render.js';
6
+ export * from './stopwords.js';
7
+ export * from './uitemplate.js';
package/dist/links.js CHANGED
@@ -1,2 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
package/dist/provider.js CHANGED
@@ -1,7 +1,4 @@
1
- "use strict";
2
1
  /* eslint-disable @typescript-eslint/no-extraneous-class */
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.ResourceProvider = void 0;
5
2
  /**
6
3
  * This class is a parent class for Component, but it can also be used as a standalone
7
4
  * if you are creating a set of templates with shared resources. This will be fairly
@@ -11,10 +8,9 @@ exports.ResourceProvider = void 0;
11
8
  *
12
9
  * If you do this, don't forget to register the provider along with your templates!
13
10
  */
14
- class ResourceProvider {
11
+ export class ResourceProvider {
15
12
  static webpath(name) { return this.webpaths.get(name); }
16
13
  }
17
- exports.ResourceProvider = ResourceProvider;
18
14
  /**
19
15
  * Each template should provide a map of CSS blocks where the map key is the unique name for
20
16
  * the CSS and the value is the CSS itself. For instance, if a template needs CSS from a
package/dist/render.d.ts CHANGED
@@ -1,5 +1,83 @@
1
- import { ContextBase } from './component';
1
+ import { ContextBase, DataData, PageData } from './component.js';
2
+ import { AssetLink, DataFolderLink, DataLink, LinkDefinition } from './links.js';
2
3
  export declare function printHeader(ctx: ContextBase, content: string): string;
3
4
  export declare function advanceHeader(ctx: ContextBase, content?: string): {
4
5
  headerLevel: number;
5
6
  };
7
+ export interface PictureResize {
8
+ /** the width of this particular resize */
9
+ width: number;
10
+ /** the URL to this particular resize, relative or absolute depends on options used */
11
+ src: string;
12
+ }
13
+ export interface PictureAttributes {
14
+ /** string appropriate for the src attribute of the default <img> tag */
15
+ src: string;
16
+ /** string appropriate for the srcset attribute of the default <img> tag, or use widths array to reconstruct */
17
+ srcset: string;
18
+ /** a list of available widths in case you want to filter some out and recreate the srcset */
19
+ widths: PictureResize[];
20
+ /** alternative text stored with the image in its asset repository, may be overridden by local alt text */
21
+ alt?: string;
22
+ /** the original intrinsic width of the image uploaded by the editor */
23
+ width: number;
24
+ /** the original intrinsic height of the image uploaded by the editor */
25
+ height: number;
26
+ /** a list of alternate formats like AVIF or WEBP and their resizes, useful for creating <source> tags */
27
+ alternates: {
28
+ /** the mime type of this alternate source, useful for the type attribute on a <source> tag */
29
+ mime: string;
30
+ /** the full srcset for the <source> tag, or use widths array to reconstruct */
31
+ srcset: string;
32
+ /** a list of available widths in case you want to filter some out and recreate the srcset */
33
+ widths: PictureResize[];
34
+ }[];
35
+ }
36
+ export interface APIClient {
37
+ /**
38
+ * Run any query against the API.
39
+ *
40
+ * Will be authenticated as appropriate - anonymous during published renders, as the editor
41
+ * during preview renders.
42
+ */
43
+ query: <T = any>(query: string, variables?: any) => Promise<T>;
44
+ /**
45
+ * This function will be provided by the rendering server and should be used inside your fetch,
46
+ * method to convert a link, as input by a user, into a URL suitable for an href, or optionally
47
+ * an absolute URL suitable for a backend http request or non-HTML document like an RSS feed.
48
+ */
49
+ resolveLink: (link: string | LinkDefinition, absolute?: boolean) => Promise<string>;
50
+ /**
51
+ * This function will be provided by the rendering server and should be used inside your fetch
52
+ * method to prepare editor-provided HTML for rendering. It will do things like find and resolve
53
+ * link definitions in the internal dosgato format and clean up tags that were accidentally left
54
+ * open to protect overall page integrity.
55
+ */
56
+ processRich: (text: string) => Promise<string>;
57
+ /**
58
+ * This function will retrieve information about an image to help you construct responsive HTML
59
+ * for a <picture> element including the <img> and all <source> tags.
60
+ *
61
+ * The alt text it returns will be the default alternative text from the asset repository. Alt
62
+ * text gathered from a template's dialog should generally take precedence (though the dialog may
63
+ * preload the alt text field with the asset repository default).
64
+ */
65
+ getImgAttributes: (link: string | AssetLink, absolute?: boolean) => Promise<PictureAttributes>;
66
+ /** Get the data for a specific page. Will be dataloaded. */
67
+ getPageData: ({ id, path }: {
68
+ id?: string;
69
+ path?: string;
70
+ }) => Promise<PageData>;
71
+ /**
72
+ * Get data items
73
+ *
74
+ * Returns an array in case link is a DataFolderLink. If link is a DataLink, will return an
75
+ * array with length <= 1.
76
+ */
77
+ getDataByLink: (link: string | DataLink | DataFolderLink) => Promise<DataData[]>;
78
+ /**
79
+ * Get data by full path including site. Use '/global' for global data. If path refers
80
+ * to a specific data item, will return an array with length <= 1.
81
+ */
82
+ getDataByPath: (templateKey: string, path: string) => Promise<DataData[]>;
83
+ }
package/dist/render.js CHANGED
@@ -1,9 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.advanceHeader = exports.printHeader = void 0;
4
- const txstate_utils_1 = require("txstate-utils");
5
- function printHeader(ctx, content) {
6
- if ((0, txstate_utils_1.isBlank)(content))
1
+ import { isBlank } from 'txstate-utils';
2
+ export function printHeader(ctx, content) {
3
+ if (isBlank(content))
7
4
  return '';
8
5
  const level = (ctx.headerLevel ?? 0) + 1;
9
6
  if (level < 1)
@@ -12,11 +9,9 @@ function printHeader(ctx, content) {
12
9
  return `<h6>${content}</h1>`;
13
10
  return `<h${level}>${content}</h${level}>`;
14
11
  }
15
- exports.printHeader = printHeader;
16
- function advanceHeader(ctx, content) {
12
+ export function advanceHeader(ctx, content) {
17
13
  const ret = { ...ctx };
18
- if (!(0, txstate_utils_1.isBlank)(content))
14
+ if (!isBlank(content))
19
15
  ret.headerLevel = (ret.headerLevel ?? 0) + 1;
20
16
  return ret;
21
17
  }
22
- exports.advanceHeader = advanceHeader;
package/dist/stopwords.js CHANGED
@@ -1,7 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.stopwords = void 0;
4
- exports.stopwords = {
1
+ export const stopwords = {
5
2
  myself: true,
6
3
  our: true,
7
4
  ours: true,
@@ -1,2 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@dosgato/templating",
3
- "version": "0.0.20",
3
+ "version": "0.0.23",
4
4
  "description": "A library to support building templates for dosgato CMS.",
5
+ "type": "module",
5
6
  "exports": {
6
- "require": "./dist/index.js",
7
- "import": "./dist-esm/index.js"
7
+ ".": "./dist/index.js",
8
+ "./package.json": "./package.json"
8
9
  },
9
10
  "types": "dist/index.d.ts",
10
11
  "scripts": {
@@ -36,6 +37,6 @@
36
37
  },
37
38
  "homepage": "https://github.com/txstate-etc/dosgato-templating#readme",
38
39
  "files": [
39
- "dist", "dist-esm"
40
+ "dist"
40
41
  ]
41
42
  }
package/dist-esm/index.js DELETED
@@ -1,7 +0,0 @@
1
- import all from '../dist/index.js'
2
-
3
- export const ResourceProvider = all.ResourceProvider
4
- export const Component = all.Component
5
- export const Page = all.Page
6
- export const extractLinksFromText = all.extractLinksFromText
7
- export const getKeywords = all.getKeywords
@@ -1,3 +0,0 @@
1
- {
2
- "type": "module"
3
- }