@dosgato/templating 1.1.15 → 1.1.17

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.
@@ -18,7 +18,7 @@ export interface ValidationFeedback {
18
18
  * API to make sure it hasn't been used already.
19
19
  */
20
20
  export interface PageExtras<DataType = PageData> {
21
- /** A function for executing a graphql query to acquire more information than is already at hand. */
21
+ /** A function for executing a graphql query to acquire more information than is already at hand. Queries are executed by the system user, so be careful with it. */
22
22
  query: GraphQLQueryFn;
23
23
  /** The site id in which the page lives or is being created. Null if we are validating creation of a site. */
24
24
  siteId?: string;
@@ -331,10 +331,3 @@ export type AnyMigration = ComponentMigration | PageMigration | DataMigration;
331
331
  export type LinkGatheringFn<DataType> = (data: DataType) => (LinkDefinition | string | undefined)[];
332
332
  export type FulltextGatheringFn<DataType> = (data: DataType) => (string | undefined)[];
333
333
  export type GraphQLQueryFn = <T>(query: string, variables?: any) => Promise<T>;
334
- /**
335
- * This function is used by API template definitions to help them identify all the searchable
336
- * words in a large block of text and return them for indexing.
337
- */
338
- export declare function getKeywords(text?: string, options?: {
339
- stopwords?: boolean;
340
- }): string[];
@@ -1,21 +1,6 @@
1
- import { stopwordSet } from './stopwords.js';
2
1
  export var ValidationMessageType;
3
2
  (function (ValidationMessageType) {
4
3
  ValidationMessageType["ERROR"] = "error";
5
4
  ValidationMessageType["WARNING"] = "warning";
6
5
  ValidationMessageType["SUCCESS"] = "success";
7
6
  })(ValidationMessageType || (ValidationMessageType = {}));
8
- /**
9
- * This function is used by API template definitions to help them identify all the searchable
10
- * words in a large block of text and return them for indexing.
11
- */
12
- export function getKeywords(text, options) {
13
- if (!text)
14
- return [];
15
- return Array.from(new Set(text
16
- .normalize('NFD').replace(/\p{Diacritic}/gu, '')
17
- .toLocaleLowerCase()
18
- .split(/[^\w-]+/)
19
- .flatMap(word => word.includes('-') ? word.split('-').concat(word.replace('-', '')) : [word])
20
- .filter(word => word.length > 2 && (options?.stopwords === false || !stopwordSet.has(word)) && isNaN(Number(word)))));
21
- }
package/dist/component.js CHANGED
@@ -9,6 +9,10 @@ function defaultWrap(info) { return info.output; }
9
9
  * parent and child components linked.
10
10
  */
11
11
  export class Component extends ResourceProvider {
12
+ /**
13
+ * Provide this when you create a template to identify what you are defining.
14
+ */
15
+ static templateKey;
12
16
  /**
13
17
  * The first phase of rendering a component is the fetch phase. Each component may
14
18
  * provide a fetch method that looks up data it needs from external sources. This step
@@ -207,6 +211,17 @@ export class Component extends ResourceProvider {
207
211
  * CSS class
208
212
  */
209
213
  editClass() { return undefined; }
214
+ /**
215
+ * Override with `true` to indicate that this template never accepts data from editors
216
+ *
217
+ * Its edit bar will not have a pencil icon.
218
+ */
219
+ noData = false;
220
+ /**
221
+ * Override with `true` to indicate that this template renders its own edit bar
222
+ * so that the parent component will avoid rendering it
223
+ */
224
+ renderIncludesEditBar = false;
210
225
  /**
211
226
  * Components may override this function to give their new bars a custom
212
227
  * label
@@ -227,10 +242,10 @@ export class Component extends ResourceProvider {
227
242
  */
228
243
  editBar(opts = {}) {
229
244
  const options = { ...opts };
230
- options.label ?? (options.label = this.editLabel() ?? this.autoLabel);
245
+ options.label ??= this.editLabel() ?? this.autoLabel;
231
246
  options.extraClass = [options.extraClass, this.editClass()].filter(isNotBlank).join(' ');
232
- options.editMode ?? (options.editMode = this.editMode);
233
- options.inheritedFrom ?? (options.inheritedFrom = this.inheritedFrom);
247
+ options.editMode ??= this.editMode;
248
+ options.inheritedFrom ??= this.inheritedFrom;
234
249
  options.hideEdit = this.noData || options.hideEdit;
235
250
  return Component.editBar(this.path, options);
236
251
  }
@@ -241,29 +256,21 @@ export class Component extends ResourceProvider {
241
256
  */
242
257
  newBar(areaName, opts = {}) {
243
258
  const options = { ...opts };
244
- options.label ?? (options.label = this.newLabel(areaName) ?? (this.areas.size > 1 ? `Add ${areaName} Content` : `Add ${this.autoLabel} Content`));
259
+ options.label ??= this.newLabel(areaName) ?? (this.areas.size > 1 ? `Add ${areaName} Content` : `Add ${this.autoLabel} Content`);
245
260
  options.extraClass = [options.extraClass, this.newClass(areaName)].filter(isNotBlank).join(' ');
246
- options.editMode ?? (options.editMode = this.editMode);
261
+ options.editMode ??= this.editMode;
247
262
  return Component.newBar([this.path, 'areas', areaName].filter(isNotBlank).join('.'), options);
248
263
  }
264
+ /**
265
+ * These functions will be provided by the rendering server to assist in the
266
+ * rendering process.
267
+ */
268
+ static editBar;
269
+ static newBar;
249
270
  // the constructor is part of the recursive hydration mechanism: constructing
250
271
  // a Component will also construct/hydrate all its child components
251
272
  constructor(data, path, parent, editMode, extension) {
252
273
  super();
253
- /**
254
- * Override with `true` to indicate that this template never accepts data from editors
255
- *
256
- * Its edit bar will not have a pencil icon.
257
- */
258
- this.noData = false;
259
- /**
260
- * Override with `true` to indicate that this template renders its own edit bar
261
- * so that the parent component will avoid rendering it
262
- */
263
- this.renderIncludesEditBar = false;
264
- // Properties provided during the rendering process. You do not have to provide these when
265
- // building a template, but you can use them in the functions you do provide
266
- this.areas = new Map(); // a Map of area names and the array of hydrated components in each
267
274
  this.editMode = editMode;
268
275
  this.extension = extension;
269
276
  this.parent = parent;
@@ -278,6 +285,35 @@ export class Component extends ResourceProvider {
278
285
  throw new Error('Hydration failed, could not map component back to its page.');
279
286
  this.page = tmpParent;
280
287
  }
288
+ // Properties provided during the rendering process. You do not have to provide these when
289
+ // building a template, but you can use them in the functions you do provide
290
+ areas = new Map(); // a Map of area names and the array of hydrated components in each
291
+ data; // the component data
292
+ fetched; // where we store the output from your `fetched` method
293
+ renderCtx; // where we store the output from your `setContext` method
294
+ path; // the dot-separated path to this component within the page data
295
+ parent; // the hydrated parent component of this component
296
+ page; // the hydrated page component this component lives in
297
+ renderedAreas; // render server sets this just before `render` is called
298
+ hadError; // will be true if the fetch encountered an error, render will be skipped
299
+ autoLabel; // the rendering server will fetch template names and fill this
300
+ reqHeaders; // the HTTP headers of the request being processed, in case it would change the render
301
+ reqQuery; // the URL of the request being processed, so you can access the query or do routing work
302
+ // the index of this component in its area, after inheritance has occurred
303
+ // because we are waiting for inheritance, this will be undefined until the render phase
304
+ // it's also undefined for page templates but I'm intentionally making it non-optional
305
+ // because it would be non-sensical to try to use in a page template anyway
306
+ indexInArea;
307
+ /**
308
+ * the full array of components in the same area as this component, including self
309
+ *
310
+ * empty for page component
311
+ */
312
+ siblings;
313
+ /** the component before this one inside the area, null if this component is first */
314
+ prevSibling;
315
+ /** the component after this one inside the area, null if this component is last */
316
+ nextSibling;
281
317
  /**
282
318
  * For logging errors during rendering without crashing the render. If your fetch, setContext,
283
319
  * render, or renderVariation functions throw, the error will be logged but the page render will
@@ -293,6 +329,15 @@ export class Component extends ResourceProvider {
293
329
  }
294
330
  }
295
331
  export class Page extends Component {
332
+ /**
333
+ * The page id in case you need to pass it to the API, e.g. this.api.getRootPage(this.id)
334
+ * in a page template or this.api.getRootPage(this.page.id) in a component template.
335
+ */
336
+ id;
337
+ /**
338
+ * Other data we've already collected about the page being rendered, in case it's needed.
339
+ */
340
+ pageInfo;
296
341
  /**
297
342
  * A convenience to get the page title.
298
343
  *
@@ -301,6 +346,43 @@ export class Page extends Component {
301
346
  get title() {
302
347
  return this.pageInfo.data.title ?? titleCase(this.pageInfo.name);
303
348
  }
349
+ /**
350
+ * This will be filled by the rendering server. The template properties are described
351
+ * over in apitemplate.ts in the comment for APIPageTemplate.templateProperties.
352
+ *
353
+ * The properties will appear in the GraphQL API and the rendering server will automatically
354
+ * download them and provide them here so all you need to do as a template developer is
355
+ * reference the values in your fetch/setContext/render functions.
356
+ */
357
+ templateProperties;
358
+ /**
359
+ * This is a bunch of javascript and CSS and meta tags managed by the DosGato engine. It will
360
+ * be filled by the rendering server and your render function for your page template
361
+ * should place include it in the <head> element
362
+ */
363
+ headContent;
364
+ /**
365
+ * This method will be provided to page templates by the render server. You may call it
366
+ * at any time during fetch, context, or render, to set an HTTP header on the response
367
+ */
368
+ addHeader;
369
+ /**
370
+ * This method will be provided to page templates by the render server. You may call it to set
371
+ * the HTTP response status at any time during the fetch, context, or render.
372
+ */
373
+ setStatus;
374
+ /**
375
+ * URL for the currently rendering page
376
+ *
377
+ * The URL currently being rendered. For instance, if we are in edit mode it would begin
378
+ * with /.edit/ or in preview mode, /.preview/. Useful for referencing variations of the
379
+ * current page.
380
+ *
381
+ * Does not include hash or querystring.
382
+ *
383
+ * Also see `variationUrl` below.
384
+ */
385
+ url;
304
386
  /**
305
387
  * Get a URL for the current page with a different extension
306
388
  */
package/dist/index.d.ts CHANGED
@@ -3,5 +3,4 @@ export * from './component.js';
3
3
  export * from './links.js';
4
4
  export * from './provider.js';
5
5
  export * from './render.js';
6
- export * from './stopwords.js';
7
6
  export * from './uitemplate.js';
package/dist/index.js CHANGED
@@ -3,5 +3,4 @@ export * from './component.js';
3
3
  export * from './links.js';
4
4
  export * from './provider.js';
5
5
  export * from './render.js';
6
- export * from './stopwords.js';
7
6
  export * from './uitemplate.js';
package/dist/provider.js CHANGED
@@ -9,80 +9,80 @@
9
9
  * If you do this, don't forget to register the provider along with your templates!
10
10
  */
11
11
  export class ResourceProvider {
12
+ /**
13
+ * Each template should provide a map of CSS blocks where the map key is the unique name for
14
+ * the CSS and the value is the CSS itself. For instance, if a template needs CSS from a
15
+ * standard library like jquery-ui, it could include the full CSS for jquery-ui with 'jquery-ui'
16
+ * as the key. Other templates that depend on jquery-ui would also provide the CSS, but
17
+ * a page with both components would only include the CSS once, because they both called it
18
+ * 'jquery-ui'.
19
+ *
20
+ * A version string (e.g. '1.2.5') may be provided for each block. The block with the highest
21
+ * version number of any given name will be used. Other versions of that name will be ignored.
22
+ *
23
+ * For convenience you can either provide the `css` property with the CSS as a string, or the
24
+ * `path` property with the full server path (NOT URL) to a CSS file (node's __dirname function will
25
+ * help you determine it). You MUST provide one or the other.
26
+ *
27
+ * You may also set `async` to true if a css block is not needed for the initial render of
28
+ * the page. For instance, if your component has a modal that the user can trigger, you can
29
+ * defer the CSS for that modal since it will not be needed until the page has gone interactive
30
+ * and the user has clicked something.
31
+ */
32
+ static cssBlocks = new Map();
33
+ /**
34
+ * A template can provide SASS mixins and functions for use by other SASS-based CSS
35
+ * blocks.
36
+ *
37
+ * These includes can be utilized by other SASS with the SASS `@use` and `@include`
38
+ * commands, e.g.
39
+ * ```
40
+ * @use 'my-mixin-name' as mx;
41
+ * .someclass { @include mx.somemixin(); }
42
+ * ```
43
+ * In this case `my-mixin-name` is the key used for this Map.
44
+ */
45
+ static scssIncludes = new Map();
46
+ /**
47
+ * Same as cssBlocks() but for javascript.
48
+ *
49
+ * In this case `async` is much more useful, as most javascript is interactive and could run
50
+ * after the page renders. Any code that adds event observers or the like should be marked with
51
+ * async to improve the initial render time.
52
+ */
53
+ static jsBlocks = new Map();
54
+ /**
55
+ * If your template needs to serve any files, like fonts or images, you can provide
56
+ * a filesystem path in this static property and the files will be served by the rendering
57
+ * server. Use the provided `webpaths` map to obtain the proper resource URLs. They will be
58
+ * available as soon as your template has been registered to the rendering server's templateRegistry.
59
+ *
60
+ * The map name you pick should be globally unique and only collide with other templates as
61
+ * intended. For instance, the fontawesome font only needs to be provided once, even though
62
+ * several templates might depend on it. Setting the name as 'fontawesome5' on all three
63
+ * templates would ensure that the file would only be served once. Including the major version
64
+ * number is a good idea only if the major versions can coexist.
65
+ *
66
+ * Include a version number if applicable for the file you've included with your source. If
67
+ * multiple templates have a common file, the one that provides the highest version number will
68
+ * have its file served, while the others will be ignored.
69
+ *
70
+ * DO NOT change the mime type without changing the name. Other templates could end up with
71
+ * the wrong file extension.
72
+ */
73
+ static files = new Map();
74
+ /**
75
+ * Template code will need to generate HTML and CSS that points at the static files
76
+ * provided above. In order to do so, we need information from the template registry (since
77
+ * we have to deduplicate with other registered templates at startup time, and the structure
78
+ * of the webpath in general is the render server's concern).
79
+ *
80
+ * In order to avoid an ES6 dependency on the registry, we will have the registry write
81
+ * back to this map as templates are registered.
82
+ *
83
+ * Now when a template needs a web path to a resource to put into its HTML, it can do
84
+ * `<img src="${TemplateClass.webpath('keyname')}">`
85
+ */
86
+ static webpaths = new Map();
12
87
  static webpath(name) { return this.webpaths.get(name); }
13
88
  }
14
- /**
15
- * Each template should provide a map of CSS blocks where the map key is the unique name for
16
- * the CSS and the value is the CSS itself. For instance, if a template needs CSS from a
17
- * standard library like jquery-ui, it could include the full CSS for jquery-ui with 'jquery-ui'
18
- * as the key. Other templates that depend on jquery-ui would also provide the CSS, but
19
- * a page with both components would only include the CSS once, because they both called it
20
- * 'jquery-ui'.
21
- *
22
- * A version string (e.g. '1.2.5') may be provided for each block. The block with the highest
23
- * version number of any given name will be used. Other versions of that name will be ignored.
24
- *
25
- * For convenience you can either provide the `css` property with the CSS as a string, or the
26
- * `path` property with the full server path (NOT URL) to a CSS file (node's __dirname function will
27
- * help you determine it). You MUST provide one or the other.
28
- *
29
- * You may also set `async` to true if a css block is not needed for the initial render of
30
- * the page. For instance, if your component has a modal that the user can trigger, you can
31
- * defer the CSS for that modal since it will not be needed until the page has gone interactive
32
- * and the user has clicked something.
33
- */
34
- ResourceProvider.cssBlocks = new Map();
35
- /**
36
- * A template can provide SASS mixins and functions for use by other SASS-based CSS
37
- * blocks.
38
- *
39
- * These includes can be utilized by other SASS with the SASS `@use` and `@include`
40
- * commands, e.g.
41
- * ```
42
- * @use 'my-mixin-name' as mx;
43
- * .someclass { @include mx.somemixin(); }
44
- * ```
45
- * In this case `my-mixin-name` is the key used for this Map.
46
- */
47
- ResourceProvider.scssIncludes = new Map();
48
- /**
49
- * Same as cssBlocks() but for javascript.
50
- *
51
- * In this case `async` is much more useful, as most javascript is interactive and could run
52
- * after the page renders. Any code that adds event observers or the like should be marked with
53
- * async to improve the initial render time.
54
- */
55
- ResourceProvider.jsBlocks = new Map();
56
- /**
57
- * If your template needs to serve any files, like fonts or images, you can provide
58
- * a filesystem path in this static property and the files will be served by the rendering
59
- * server. Use the provided `webpaths` map to obtain the proper resource URLs. They will be
60
- * available as soon as your template has been registered to the rendering server's templateRegistry.
61
- *
62
- * The map name you pick should be globally unique and only collide with other templates as
63
- * intended. For instance, the fontawesome font only needs to be provided once, even though
64
- * several templates might depend on it. Setting the name as 'fontawesome5' on all three
65
- * templates would ensure that the file would only be served once. Including the major version
66
- * number is a good idea only if the major versions can coexist.
67
- *
68
- * Include a version number if applicable for the file you've included with your source. If
69
- * multiple templates have a common file, the one that provides the highest version number will
70
- * have its file served, while the others will be ignored.
71
- *
72
- * DO NOT change the mime type without changing the name. Other templates could end up with
73
- * the wrong file extension.
74
- */
75
- ResourceProvider.files = new Map();
76
- /**
77
- * Template code will need to generate HTML and CSS that points at the static files
78
- * provided above. In order to do so, we need information from the template registry (since
79
- * we have to deduplicate with other registered templates at startup time, and the structure
80
- * of the webpath in general is the render server's concern).
81
- *
82
- * In order to avoid an ES6 dependency on the registry, we will have the registry write
83
- * back to this map as templates are registered.
84
- *
85
- * Now when a template needs a web path to a resource to put into its HTML, it can do
86
- * `<img src="${TemplateClass.webpath('keyname')}">`
87
- */
88
- ResourceProvider.webpaths = new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dosgato/templating",
3
- "version": "1.1.15",
3
+ "version": "1.1.17",
4
4
  "description": "A library to support building templates for dosgato CMS.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,2 +0,0 @@
1
- export declare const stopwords: Record<string, boolean>;
2
- export declare const stopwordSet: Set<string>;
package/dist/stopwords.js DELETED
@@ -1,154 +0,0 @@
1
- export const stopwords = {
2
- myself: true,
3
- our: true,
4
- ours: true,
5
- ourselves: true,
6
- you: true,
7
- your: true,
8
- yours: true,
9
- yourself: true,
10
- yourselves: true,
11
- him: true,
12
- his: true,
13
- himself: true,
14
- she: true,
15
- her: true,
16
- hers: true,
17
- herself: true,
18
- its: true,
19
- itself: true,
20
- they: true,
21
- them: true,
22
- their: true,
23
- theirs: true,
24
- themselves: true,
25
- what: true,
26
- which: true,
27
- who: true,
28
- whom: true,
29
- this: true,
30
- that: true,
31
- these: true,
32
- those: true,
33
- are: true,
34
- was: true,
35
- were: true,
36
- been: true,
37
- being: true,
38
- have: true,
39
- has: true,
40
- had: true,
41
- having: true,
42
- does: true,
43
- did: true,
44
- doing: true,
45
- the: true,
46
- and: true,
47
- but: true,
48
- because: true,
49
- until: true,
50
- while: true,
51
- for: true,
52
- with: true,
53
- about: true,
54
- against: true,
55
- between: true,
56
- into: true,
57
- through: true,
58
- during: true,
59
- before: true,
60
- after: true,
61
- above: true,
62
- below: true,
63
- from: true,
64
- down: true,
65
- out: true,
66
- off: true,
67
- over: true,
68
- under: true,
69
- again: true,
70
- further: true,
71
- then: true,
72
- once: true,
73
- here: true,
74
- there: true,
75
- when: true,
76
- where: true,
77
- why: true,
78
- how: true,
79
- all: true,
80
- any: true,
81
- both: true,
82
- each: true,
83
- few: true,
84
- more: true,
85
- most: true,
86
- other: true,
87
- some: true,
88
- such: true,
89
- nor: true,
90
- not: true,
91
- only: true,
92
- own: true,
93
- same: true,
94
- than: true,
95
- too: true,
96
- very: true,
97
- can: true,
98
- will: true,
99
- just: true,
100
- don: true,
101
- should: true,
102
- now: true,
103
- // HTML
104
- div: true,
105
- span: true,
106
- img: true,
107
- abbr: true,
108
- area: true,
109
- main: true,
110
- aside: true,
111
- blockquote: true,
112
- button: true,
113
- caption: true,
114
- code: true,
115
- del: true,
116
- strong: true,
117
- font: true,
118
- embed: true,
119
- fieldset: true,
120
- form: true,
121
- figure: true,
122
- iframe: true,
123
- label: true,
124
- input: true,
125
- script: true,
126
- nav: true,
127
- select: true,
128
- option: true,
129
- picture: true,
130
- pre: true,
131
- small: true,
132
- style: true,
133
- svg: true,
134
- sub: true,
135
- table: true,
136
- tbody: true,
137
- href: true,
138
- src: true,
139
- srcset: true,
140
- class: true,
141
- textarea: true,
142
- title: true,
143
- onclick: true,
144
- www: true,
145
- com: true,
146
- // LinkDefinition
147
- siteId: true,
148
- path: true,
149
- type: true,
150
- assetId: true,
151
- linkId: true,
152
- url: true
153
- };
154
- export const stopwordSet = new Set(Object.keys(stopwords));