@rr0/cms 0.3.14 → 0.3.16
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.
- package/dist/OpenGraphCommand.d.ts +3 -2
- package/dist/OpenGraphCommand.js +3 -2
- package/dist/OpenGraphCommand.test.js +1 -1
- package/dist/RR0Build.d.ts +10 -5
- package/dist/RR0Build.js +35 -46
- package/dist/RR0Build.test.js +19 -2
- package/dist/anchor/AnchorReplaceCommandTest.js +1 -2
- package/dist/book/BookService.test.js +2 -2
- package/dist/people/author/AuthorReplaceCommand.d.ts +3 -3
- package/dist/people/author/AuthorReplaceCommand.js +3 -3
- package/dist/people/author/AuthorReplaceCommandTest.js +4 -4
- package/dist/science/crypto/ufo/enquete/dossier/CaseDirectoryStep.test.js +2 -2
- package/dist/science/crypto/ufo/enquete/dossier/CaseService.js +1 -1
- package/dist/time/EventRenderer.d.ts +2 -1
- package/dist/time/EventRenderer.js +2 -2
- package/dist/time/TimeLinkDefaultHandler.d.ts +3 -1
- package/dist/time/TimeLinkDefaultHandler.js +6 -5
- package/dist/time/TimeOptions.d.ts +4 -0
- package/dist/time/TimeOptions.js +1 -0
- package/dist/time/TimeService.d.ts +3 -24
- package/dist/time/TimeService.js +2 -33
- package/dist/time/TimeTagReplaceCommand.test.js +3 -3
- package/dist/time/TimeTestUtil.d.ts +6 -4
- package/dist/time/TimeTestUtil.js +10 -8
- package/dist/time/TimeUrlBuilder.d.ts +7 -3
- package/dist/time/TimeUrlBuilder.js +14 -0
- package/dist/time/TimeUrlBuilder.test.js +2 -1
- package/dist/time/datasource/ChronologyReplacer.js +1 -1
- package/dist/time/datasource/ChronologyReplacerFactory.d.ts +3 -3
- package/dist/time/datasource/ChronologyReplacerFactory.js +3 -3
- package/dist/time/datasource/DatasourceTestCase.js +1 -1
- package/dist/time/datasource/rr0/RR0HttpDatasource.js +1 -1
- package/dist/time/html/TimeElementFactory.js +3 -3
- package/dist/time/html/TimeRenderer.d.ts +4 -3
- package/dist/time/html/TimeRenderer.js +12 -9
- package/dist/time/html/TimeReplacer.test.js +15 -14
- package/dist/time/html/TimeReplacerFactory.d.ts +3 -1
- package/dist/time/html/TimeReplacerFactory.js +3 -2
- package/dist/time/index.d.ts +1 -0
- package/dist/time/index.js +1 -0
- package/package.json +3 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ReplaceCommand } from "ssg-api/dist/src/step/content/replace/ReplaceCommand.js";
|
|
2
2
|
import { HtmlRR0Context } from "./RR0Context.js";
|
|
3
3
|
import { Canvas, CanvasRenderingContext2D } from "canvas";
|
|
4
|
-
import { TimeService } from "./time/index.js";
|
|
4
|
+
import { TimeService, TimeTextBuilder } from "./time/index.js";
|
|
5
5
|
/**
|
|
6
6
|
* Create a preview image for each page sharing.
|
|
7
7
|
*/
|
|
@@ -10,10 +10,11 @@ export declare class OpenGraphCommand implements ReplaceCommand<HtmlRR0Context>
|
|
|
10
10
|
protected timeFiles: string[];
|
|
11
11
|
protected baseUrl: string;
|
|
12
12
|
protected timeService: TimeService;
|
|
13
|
+
readonly timeTextBuilder: TimeTextBuilder;
|
|
13
14
|
protected width: number;
|
|
14
15
|
protected height: number;
|
|
15
16
|
protected num: number;
|
|
16
|
-
constructor(outDir: string, timeFiles: string[], baseUrl: string, timeService: TimeService, width?: number, height?: number);
|
|
17
|
+
constructor(outDir: string, timeFiles: string[], baseUrl: string, timeService: TimeService, timeTextBuilder: TimeTextBuilder, width?: number, height?: number);
|
|
17
18
|
execute(context: HtmlRR0Context): Promise<void>;
|
|
18
19
|
getInfoStr(context: HtmlRR0Context): string;
|
|
19
20
|
contentStepEnd(): Promise<void>;
|
package/dist/OpenGraphCommand.js
CHANGED
|
@@ -6,11 +6,12 @@ import assert from "assert";
|
|
|
6
6
|
* Create a preview image for each page sharing.
|
|
7
7
|
*/
|
|
8
8
|
export class OpenGraphCommand {
|
|
9
|
-
constructor(outDir, timeFiles, baseUrl, timeService, width = 1200, height = 600) {
|
|
9
|
+
constructor(outDir, timeFiles, baseUrl, timeService, timeTextBuilder, width = 1200, height = 600) {
|
|
10
10
|
this.outDir = outDir;
|
|
11
11
|
this.timeFiles = timeFiles;
|
|
12
12
|
this.baseUrl = baseUrl;
|
|
13
13
|
this.timeService = timeService;
|
|
14
|
+
this.timeTextBuilder = timeTextBuilder;
|
|
14
15
|
this.width = width;
|
|
15
16
|
this.height = height;
|
|
16
17
|
this.num = 0;
|
|
@@ -55,7 +56,7 @@ export class OpenGraphCommand {
|
|
|
55
56
|
context.time.setDayOfMonth(timeContext.getDayOfMonth());
|
|
56
57
|
context.time.setHour(undefined);
|
|
57
58
|
context.time.setMinutes(undefined);
|
|
58
|
-
timeStr = this.
|
|
59
|
+
timeStr = this.timeTextBuilder.build(context);
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
const copyrightStr = context.file.meta.copyright || "RR0.org";
|
|
@@ -6,7 +6,7 @@ describe("OpenGraphCommand", () => {
|
|
|
6
6
|
test("time page", () => {
|
|
7
7
|
const timeFile = rr0TestUtil.time.filePath("0/0/6/5/index.html");
|
|
8
8
|
const context = rr0TestUtil.newHtmlContext(timeFile, "");
|
|
9
|
-
const command = new OpenGraphCommand(outDir, [context.file.name], "https://rr0.org", rr0TestUtil.time.getService());
|
|
9
|
+
const command = new OpenGraphCommand(outDir, [context.file.name], "https://rr0.org", rr0TestUtil.time.getService(), rr0TestUtil.time.timeTextBuilder);
|
|
10
10
|
expect(command.getInfoStr(context)).toBe("Chronologie, RR0.org");
|
|
11
11
|
});
|
|
12
12
|
});
|
package/dist/RR0Build.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { RR0CaseMapping,
|
|
1
|
+
import { RR0CaseMapping, TimeRenderer, TimeService, TimeTextBuilder, TimeUrlBuilder } from "./time";
|
|
2
2
|
import { CaseFactory } from "./science/index.js";
|
|
3
3
|
import { CityService, DepartmentService, OrganizationService } from "./org/index.js";
|
|
4
|
-
import { RR0ContextImpl } from "./RR0Context.js";
|
|
4
|
+
import { HtmlRR0Context, RR0ContextImpl } from "./RR0Context.js";
|
|
5
5
|
import { FileWriteConfig } from "ssg-api";
|
|
6
6
|
import { PeopleDirectoryStepOptions } from "./people";
|
|
7
7
|
import { AllDataService, PeopleFactory } from "@rr0/data";
|
|
8
8
|
import { GooglePlaceService } from "@rr0/place";
|
|
9
9
|
import { CountryService } from "./org/country/CountryService";
|
|
10
10
|
import { BuildContext } from "./BuildContext";
|
|
11
|
+
import { ReplaceCommand } from "ssg-api/dist/src/step/content/replace";
|
|
12
|
+
import { TimeOptions } from "./time/TimeOptions";
|
|
11
13
|
export interface RR0BuildOptions {
|
|
12
14
|
contentRoots: string[];
|
|
13
15
|
copies: string[];
|
|
@@ -15,7 +17,7 @@ export interface RR0BuildOptions {
|
|
|
15
17
|
locale: string;
|
|
16
18
|
googleMapsApiKey: string;
|
|
17
19
|
mail: string;
|
|
18
|
-
timeOptions:
|
|
20
|
+
timeOptions: TimeOptions;
|
|
19
21
|
siteBaseUrl: string;
|
|
20
22
|
timeFormat: Intl.DateTimeFormatOptions;
|
|
21
23
|
directoryPages: string[];
|
|
@@ -25,6 +27,7 @@ export interface RR0BuildOptions {
|
|
|
25
27
|
directoryExcluded: string[];
|
|
26
28
|
directoryOptions: PeopleDirectoryStepOptions;
|
|
27
29
|
mappings: RR0CaseMapping<any>[];
|
|
30
|
+
contentReplacers: ReplaceCommand<HtmlRR0Context>[];
|
|
28
31
|
}
|
|
29
32
|
export interface RR0BuildArgs {
|
|
30
33
|
/**
|
|
@@ -59,14 +62,16 @@ export declare class RR0Build implements BuildContext {
|
|
|
59
62
|
readonly context: RR0ContextImpl;
|
|
60
63
|
readonly placeService: GooglePlaceService;
|
|
61
64
|
readonly orgService: OrganizationService<any>;
|
|
62
|
-
readonly timeService: TimeService;
|
|
63
65
|
readonly caseFactory: CaseFactory;
|
|
64
66
|
readonly dataService: AllDataService;
|
|
65
67
|
readonly peopleFactory: PeopleFactory;
|
|
66
|
-
readonly timeTextBuilder: TimeTextBuilder;
|
|
67
68
|
readonly cityService: CityService;
|
|
68
69
|
readonly departmentService: DepartmentService;
|
|
69
70
|
readonly countryService: CountryService;
|
|
71
|
+
readonly timeTextBuilder: TimeTextBuilder;
|
|
72
|
+
readonly timeService: TimeService;
|
|
73
|
+
readonly timeRenderer: TimeRenderer;
|
|
74
|
+
readonly timeUrlBuilder: TimeUrlBuilder;
|
|
70
75
|
constructor(options: RR0BuildOptions);
|
|
71
76
|
run(args: RR0BuildArgs): Promise<void>;
|
|
72
77
|
}
|
package/dist/RR0Build.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import fs from "fs";
|
|
3
|
-
import { CaseSummaryRenderer, ChronologyReplacerFactory, CsvMapper, EventReplacer, EventReplacerFactory, HttpSource,
|
|
3
|
+
import { CaseSummaryRenderer, ChronologyReplacerFactory, CsvMapper, EventReplacer, EventReplacerFactory, HttpSource, SsiTitleReplaceCommand, TimeElementFactory, TimeLinkDefaultHandler, TimeRenderer, TimeReplacer, TimeReplacerFactory, TimeService, TimeTextBuilder, TimeUrlBuilder } from "./time";
|
|
4
4
|
import { CaseDirectoryStep, CaseFactory, CaseService } from "./science/index.js";
|
|
5
5
|
import { PlaceReplacerFactory } from "./place/index.js";
|
|
6
6
|
import { cities, CityService, CmsOrganizationFactory, countries, departments, DepartmentService, OrganizationService, regions, RegionService } from "./org/index.js";
|
|
7
7
|
import { RR0ContextImpl } from "./RR0Context.js";
|
|
8
8
|
import { HtmlTable } from "./util/index.js";
|
|
9
|
-
import {
|
|
10
|
-
import { LanguageReplaceCommand } from "./lang/index.js";
|
|
9
|
+
import { ClassDomReplaceCommand, CopyStep, DomReplaceCommand, HtAccessToNetlifyConfigReplaceCommand, HtmlFileContents, Ssg, SsiIncludeReplaceCommand } from "ssg-api";
|
|
11
10
|
import { AuthorReplaceCommand, PeopleDirectoryStepFactory, PeopleReplacerFactory, WitnessReplacerFactory } from "./people";
|
|
12
11
|
import { PersistentSourceRegistry, SourceFileCounter, SourceIndexStep, SourceRenderer, SourceReplacer, SourceReplacerFactory } from "./source";
|
|
13
12
|
import { NoteFileCounter, NoteRenderer, NoteReplacer, NoteReplacerFactory } from "./note/index.js";
|
|
@@ -16,16 +15,13 @@ import { MetaLinkReplaceCommand } from "./MetaLinkReplaceCommand.js";
|
|
|
16
15
|
import { OutlineReplaceCommand } from "./outline/index.js";
|
|
17
16
|
import { ImageCommand } from "./ImageCommand.js";
|
|
18
17
|
import { SearchIndexStep, SearchVisitor } from "./search/index.js";
|
|
19
|
-
import { BaseReplaceCommand } from "./BaseReplaceCommand.js";
|
|
20
18
|
import { OpenGraphCommand } from "./OpenGraphCommand.js";
|
|
21
|
-
import { DescriptionReplaceCommand } from "./DescriptionReplaceCommand.js";
|
|
22
19
|
import { BookContentVisitor, BookDirectoryStep } from "./book/index.js";
|
|
23
20
|
import { IndexedReplacerFactory } from "./index/IndexedReplacerFactory.js";
|
|
24
21
|
import { APIFactory, CodeReplacerFactory } from "./tech/index.js";
|
|
25
22
|
import { RR0ContentStep } from "./RR0ContentStep.js";
|
|
26
23
|
import { UnitReplaceCommand } from "./value/index.js";
|
|
27
24
|
import { DefaultContentVisitor } from "./DefaultContentVisitor.js";
|
|
28
|
-
import { rr0DefaultCopyright } from "./RR0DefaultCopyright.js";
|
|
29
25
|
import { TimeContext } from "@rr0/time";
|
|
30
26
|
import { writeFile } from "@javarome/fileutil";
|
|
31
27
|
import { AllDataService, EventDataFactory, PeopleFactory, PeopleService, RR0EventFactory, TypedDataFactory } from "@rr0/data";
|
|
@@ -68,8 +64,7 @@ export class RR0Build {
|
|
|
68
64
|
this.cityService = cityService;
|
|
69
65
|
const timeTextBuilder = this.timeTextBuilder = new TimeTextBuilder(options.timeFormat);
|
|
70
66
|
const timeOptions = options.timeOptions;
|
|
71
|
-
const
|
|
72
|
-
const timeUrlBuilder = new TimeUrlBuilder({ rootDir: timeRoot });
|
|
67
|
+
const timeUrlBuilder = this.timeUrlBuilder = new TimeUrlBuilder(timeOptions);
|
|
73
68
|
const sightingFactory = new EventDataFactory(eventFactory, "sighting", ["index"]);
|
|
74
69
|
const caseFactory = this.caseFactory = new CaseFactory(eventFactory);
|
|
75
70
|
const peopleFactory = this.peopleFactory = new PeopleFactory(eventFactory);
|
|
@@ -81,14 +76,15 @@ export class RR0Build {
|
|
|
81
76
|
dataService.getFromDir("", ["people", "case"]).then(data => {
|
|
82
77
|
console.debug(data);
|
|
83
78
|
});
|
|
84
|
-
this.
|
|
79
|
+
this.timeRenderer = new TimeRenderer(timeUrlBuilder, timeTextBuilder);
|
|
80
|
+
this.timeService = new TimeService(dataService, timeOptions);
|
|
85
81
|
}
|
|
86
82
|
async run(args) {
|
|
87
83
|
const context = this.context;
|
|
88
84
|
const timeFiles = this.options.timeOptions.files;
|
|
89
85
|
context.setVar("timeFilesCount", timeFiles.length);
|
|
90
|
-
const
|
|
91
|
-
const timeElementFactory = new TimeElementFactory(
|
|
86
|
+
const timeRenderer = this.timeRenderer;
|
|
87
|
+
const timeElementFactory = new TimeElementFactory(timeRenderer);
|
|
92
88
|
const timeReplacer = new TimeReplacer(timeElementFactory);
|
|
93
89
|
const caseFiles = await this.caseFactory.getFiles();
|
|
94
90
|
let dataService = this.dataService;
|
|
@@ -112,9 +108,10 @@ export class RR0Build {
|
|
|
112
108
|
const peopleSteps = await peopleDirectoryFactory.create(directoryOptions);
|
|
113
109
|
// Publish case.json files so that vraiufo.com will find them
|
|
114
110
|
const copies = this.options.copies;
|
|
115
|
-
|
|
111
|
+
const ufoCasesRootDirs = ufoCasesStep.config.rootDirs;
|
|
112
|
+
copies.push(...ufoCasesRootDirs.map(dir => path.join(dir, "case.json")));
|
|
116
113
|
const outDir = this.options.outDir;
|
|
117
|
-
await writeFile(path.join(outDir, "casesDirs.json"), JSON.stringify(
|
|
114
|
+
await writeFile(path.join(outDir, "casesDirs.json"), JSON.stringify(ufoCasesRootDirs), "utf-8");
|
|
118
115
|
const dirsContainingPeopleJson = peopleSteps.reduce((rootDirs, peopleStep) => {
|
|
119
116
|
rootDirs.push(...peopleStep.config.rootDirs);
|
|
120
117
|
return rootDirs;
|
|
@@ -128,52 +125,26 @@ export class RR0Build {
|
|
|
128
125
|
const baseUrl = this.options.siteBaseUrl;
|
|
129
126
|
const timeFormat = this.options.timeFormat;
|
|
130
127
|
const sourceRegistryFileName = this.options.sourceRegistryFileName;
|
|
128
|
+
const timeService = this.timeService;
|
|
131
129
|
const sourceFactory = new PersistentSourceRegistry(dataService, http, baseUrl, sourceRegistryFileName, timeFormat, timeService);
|
|
132
130
|
const noteCounter = new NoteFileCounter();
|
|
133
131
|
const noteRenderer = new NoteRenderer(noteCounter);
|
|
134
132
|
const caseRenderer = new CaseSummaryRenderer(noteRenderer, sourceFactory, sourceRenderer, timeElementFactory);
|
|
135
|
-
const mappings = this.options.mappings || [
|
|
133
|
+
const mappings = this.options.mappings || [];
|
|
136
134
|
mappings.forEach(mapping => mapping.init(this));
|
|
137
|
-
const
|
|
135
|
+
const timeUrlBuilder = this.timeUrlBuilder;
|
|
136
|
+
const databaseAggregationCommand = new DomReplaceCommand(".contents ul", new ChronologyReplacerFactory(timeUrlBuilder, mappings, caseRenderer));
|
|
138
137
|
const timeDefaultHandler = (context) => {
|
|
139
138
|
let title;
|
|
140
139
|
title = timeService.titleFromFile(context, context.file.name, timeTextBuilder);
|
|
141
140
|
return title;
|
|
142
141
|
};
|
|
143
|
-
const pageReplaceCommands = [
|
|
144
|
-
new BaseReplaceCommand("/"),
|
|
145
|
-
new LanguageReplaceCommand(),
|
|
146
|
-
new SsiEchoVarReplaceCommand("copyright", [rr0DefaultCopyright]),
|
|
147
|
-
new StringEchoVarReplaceCommand(),
|
|
148
|
-
new AngularExpressionReplaceCommand(),
|
|
149
|
-
new SsiIfReplaceCommand(),
|
|
150
|
-
new SsiSetVarReplaceCommand("title", (_match, ...args) => `<title>${args[0]}</title>`),
|
|
151
|
-
new SsiSetVarReplaceCommand("url", (_match, ...args) => `<meta name="url" content="${args[0]}"/>`),
|
|
152
|
-
new SsiLastModifiedReplaceCommand(timeFormat),
|
|
153
|
-
new SsiTitleReplaceCommand([timeDefaultHandler]),
|
|
154
|
-
new DescriptionReplaceCommand("UFO data for french-reading people", "abstract"),
|
|
155
|
-
new AuthorReplaceCommand(timeService)
|
|
156
|
-
];
|
|
157
142
|
const sourceCounter = new SourceFileCounter();
|
|
158
143
|
const sourceReplacer = new SourceReplacer(sourceRenderer, sourceFactory, sourceCounter);
|
|
159
144
|
const sourceReplacerFactory = new SourceReplacerFactory(sourceReplacer);
|
|
160
145
|
const noteReplacer = new NoteReplacer(noteRenderer);
|
|
161
146
|
const noteReplacerFactory = new NoteReplacerFactory(noteReplacer);
|
|
162
147
|
const eventReplacer = new EventReplacer(caseRenderer, dataService);
|
|
163
|
-
const contentsReplaceCommand = [
|
|
164
|
-
new ClassDomReplaceCommand(new EventReplacerFactory(eventReplacer), "event"),
|
|
165
|
-
new ClassDomReplaceCommand(sourceReplacerFactory, "source"),
|
|
166
|
-
new DomReplaceCommand("time", new TimeReplacerFactory(timeReplacer)),
|
|
167
|
-
new DomReplaceCommand("code", new CodeReplacerFactory()),
|
|
168
|
-
new ClassDomReplaceCommand(new PeopleReplacerFactory(peopleService, peopleRenderer), "people"),
|
|
169
|
-
new ClassDomReplaceCommand(new PlaceReplacerFactory(), "place"),
|
|
170
|
-
new ClassDomReplaceCommand(new WitnessReplacerFactory(), "temoin", "temoin1", "temoin2", "temoin3"),
|
|
171
|
-
new ClassDomReplaceCommand(noteReplacerFactory, "note"),
|
|
172
|
-
new ClassDomReplaceCommand(new IndexedReplacerFactory(), "indexed"),
|
|
173
|
-
new UnitReplaceCommand(),
|
|
174
|
-
new MetaLinkReplaceCommand(new TimeLinkDefaultHandler(timeService, timeTextBuilder)),
|
|
175
|
-
databaseAggregationCommand
|
|
176
|
-
];
|
|
177
148
|
const ssg = new Ssg(config);
|
|
178
149
|
const getOutputPath = (context) => path.join(outDir, context.file.name);
|
|
179
150
|
const force = args.force === "true";
|
|
@@ -204,8 +175,7 @@ export class RR0Build {
|
|
|
204
175
|
replacements: [new class extends SsiIncludeReplaceCommand {
|
|
205
176
|
filePath(context, fileNameArg) {
|
|
206
177
|
const dirName = path.dirname(context.file.name);
|
|
207
|
-
return fileNameArg.startsWith("/") ?
|
|
208
|
-
path.join(process.cwd(), fileNameArg) : path.join(dirName, fileNameArg);
|
|
178
|
+
return fileNameArg.startsWith("/") ? path.join(process.cwd(), fileNameArg) : path.join(dirName, fileNameArg);
|
|
209
179
|
}
|
|
210
180
|
}([csvTransformer])],
|
|
211
181
|
getOutputPath
|
|
@@ -222,13 +192,32 @@ export class RR0Build {
|
|
|
222
192
|
if (args.books) {
|
|
223
193
|
contentVisitors.push(new BookContentVisitor(bookMeta, bookLinks));
|
|
224
194
|
}
|
|
195
|
+
const pageReplaceCommands = [
|
|
196
|
+
...this.options.contentReplacers,
|
|
197
|
+
new SsiTitleReplaceCommand([timeDefaultHandler]),
|
|
198
|
+
new AuthorReplaceCommand(timeRenderer)
|
|
199
|
+
];
|
|
200
|
+
const contentsReplaceCommand = [
|
|
201
|
+
new ClassDomReplaceCommand(new EventReplacerFactory(eventReplacer), "event"),
|
|
202
|
+
new ClassDomReplaceCommand(sourceReplacerFactory, "source"),
|
|
203
|
+
new DomReplaceCommand("time", new TimeReplacerFactory(timeReplacer, timeUrlBuilder)),
|
|
204
|
+
new DomReplaceCommand("code", new CodeReplacerFactory()),
|
|
205
|
+
new ClassDomReplaceCommand(new PeopleReplacerFactory(peopleService, peopleRenderer), "people"),
|
|
206
|
+
new ClassDomReplaceCommand(new PlaceReplacerFactory(), "place"),
|
|
207
|
+
new ClassDomReplaceCommand(new WitnessReplacerFactory(), "temoin", "temoin1", "temoin2", "temoin3"),
|
|
208
|
+
new ClassDomReplaceCommand(noteReplacerFactory, "note"),
|
|
209
|
+
new ClassDomReplaceCommand(new IndexedReplacerFactory(), "indexed"),
|
|
210
|
+
new UnitReplaceCommand(),
|
|
211
|
+
new MetaLinkReplaceCommand(new TimeLinkDefaultHandler(timeService, timeUrlBuilder, timeTextBuilder)),
|
|
212
|
+
databaseAggregationCommand
|
|
213
|
+
];
|
|
225
214
|
const contentReplacements = [
|
|
226
215
|
...pageReplaceCommands,
|
|
227
216
|
...contentsReplaceCommand,
|
|
228
217
|
new OutlineReplaceCommand(),
|
|
229
218
|
new AnchorReplaceCommand(baseUrl, [new CaseAnchorHandler(caseService, timeTextBuilder), new DataAnchorHandler(dataService)]),
|
|
230
219
|
new ImageCommand(outDir, 275, 500),
|
|
231
|
-
new OpenGraphCommand(outDir, timeFiles, baseUrl, timeService)
|
|
220
|
+
new OpenGraphCommand(outDir, timeFiles, baseUrl, timeService, timeTextBuilder)
|
|
232
221
|
];
|
|
233
222
|
ssg.add(new RR0ContentStep({
|
|
234
223
|
contentConfigs: [{ roots: contentRoots, replacements: contentReplacements, getOutputPath }],
|
package/dist/RR0Build.test.js
CHANGED
|
@@ -5,6 +5,11 @@ import { BaseOvniFranceRR0Mapping, FuforaRR0Mapping, NuforcRR0Mapping, RR0Mappin
|
|
|
5
5
|
import { testFilePath } from "./test";
|
|
6
6
|
import * as process from "node:process";
|
|
7
7
|
import { GeipanRR0Mapping } from "./org/eu/fr/cnes/geipan/geipan/GeipanRR0Mapping";
|
|
8
|
+
import { BaseReplaceCommand } from "./BaseReplaceCommand";
|
|
9
|
+
import { LanguageReplaceCommand } from "./lang";
|
|
10
|
+
import { AngularExpressionReplaceCommand, SsiEchoVarReplaceCommand, SsiIfReplaceCommand, SsiLastModifiedReplaceCommand, SsiSetVarReplaceCommand, StringEchoVarReplaceCommand } from "ssg-api";
|
|
11
|
+
import { rr0DefaultCopyright } from "./RR0DefaultCopyright";
|
|
12
|
+
import { DescriptionReplaceCommand } from "./DescriptionReplaceCommand";
|
|
8
13
|
describe("Build", () => {
|
|
9
14
|
console.time("ssg");
|
|
10
15
|
const args = {
|
|
@@ -92,7 +97,7 @@ describe("Build", () => {
|
|
|
92
97
|
const sourceRegistryFileName = testFilePath("source/index.json");
|
|
93
98
|
const siteBaseUrl = "https://rr0.org/";
|
|
94
99
|
const mail = "rr0@rr0.org";
|
|
95
|
-
const timeOptions = {
|
|
100
|
+
const timeOptions = { rootDir: testFilePath("time"), files: timeFiles };
|
|
96
101
|
// const actions: ChronologyReplacerActions = {read: ["backup", "fetch"], write: ["backup", "pages"]}
|
|
97
102
|
// const actions: ChronologyReplacerActions = {read: [], write: ["backup"]}
|
|
98
103
|
const actions = { read: ["fetch"], write: ["backup"] };
|
|
@@ -116,7 +121,19 @@ describe("Build", () => {
|
|
|
116
121
|
sourceRegistryFileName,
|
|
117
122
|
directoryExcluded: ["people/Astronomers_fichiers", "people/witness", "people/author"].map(testFilePath),
|
|
118
123
|
directoryOptions,
|
|
119
|
-
mappings
|
|
124
|
+
mappings,
|
|
125
|
+
contentReplacers: [
|
|
126
|
+
new BaseReplaceCommand("/"),
|
|
127
|
+
new LanguageReplaceCommand(),
|
|
128
|
+
new SsiEchoVarReplaceCommand("copyright", [rr0DefaultCopyright]),
|
|
129
|
+
new StringEchoVarReplaceCommand(),
|
|
130
|
+
new AngularExpressionReplaceCommand(),
|
|
131
|
+
new SsiIfReplaceCommand(),
|
|
132
|
+
new SsiSetVarReplaceCommand("title", (_match, ...args) => `<title>${args[0]}</title>`),
|
|
133
|
+
new SsiSetVarReplaceCommand("url", (_match, ...args) => `<meta name="url" content="${args[0]}"/>`),
|
|
134
|
+
new SsiLastModifiedReplaceCommand(timeFormat),
|
|
135
|
+
new DescriptionReplaceCommand("UFO data for french-reading people", "abstract")
|
|
136
|
+
]
|
|
120
137
|
});
|
|
121
138
|
await build.run(args);
|
|
122
139
|
});
|
|
@@ -8,9 +8,8 @@ import path from "path";
|
|
|
8
8
|
describe("AnchorReplaceCommand", () => {
|
|
9
9
|
test("replace anchor tag", async () => {
|
|
10
10
|
const dataService = rr0TestUtil.dataService;
|
|
11
|
-
const timeService = rr0TestUtil.time.getService();
|
|
12
11
|
const timeTextBuilder = new TimeTextBuilder(rr0TestUtil.intlOptions);
|
|
13
|
-
const timeRenderer = new TimeRenderer(
|
|
12
|
+
const timeRenderer = new TimeRenderer(rr0TestUtil.time.urlBuilder, timeTextBuilder);
|
|
14
13
|
const timeElementFactory = new TimeElementFactory(timeRenderer);
|
|
15
14
|
const roswellUrl = "/src/science/crypto/ufo/enquete/dossier/Roswell";
|
|
16
15
|
const caseFiles = [path.join(roswellUrl, "index.html")];
|
|
@@ -20,10 +20,10 @@ const config = {
|
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
const timeOptions = {
|
|
23
|
-
|
|
23
|
+
rootDir: testFilePath("time"),
|
|
24
24
|
files: []
|
|
25
25
|
};
|
|
26
|
-
const timeUrlBuilder = new TimeUrlBuilder(
|
|
26
|
+
const timeUrlBuilder = new TimeUrlBuilder(timeOptions);
|
|
27
27
|
let files = [];
|
|
28
28
|
const peopleService = new PeopleService(dataService, peopleFactory, { files, rootDir: testFilePath("people") });
|
|
29
29
|
const books = new BookService(logger, dry, peopleService, timeUrlBuilder, config);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { RegexReplacer, SsiEchoVarReplaceCommand } from "ssg-api";
|
|
2
2
|
import { HtmlRR0Context } from "../../RR0Context.js";
|
|
3
|
-
import {
|
|
3
|
+
import { TimeRenderer } from "../../time";
|
|
4
4
|
/**
|
|
5
5
|
* Replaces "<!--#echo var="author" -->" and "<!--#echo var="copyright" -->"
|
|
6
6
|
* by the page's <meta name="author">s' content.
|
|
7
7
|
*/
|
|
8
8
|
export declare class AuthorReplaceCommand extends SsiEchoVarReplaceCommand {
|
|
9
|
-
protected
|
|
10
|
-
constructor(
|
|
9
|
+
protected timeRenderer: TimeRenderer;
|
|
10
|
+
constructor(timeRenderer: TimeRenderer);
|
|
11
11
|
protected createReplacer(context: HtmlRR0Context): Promise<RegexReplacer>;
|
|
12
12
|
}
|
|
@@ -4,9 +4,9 @@ import { SsiEchoVarReplaceCommand } from "ssg-api";
|
|
|
4
4
|
* by the page's <meta name="author">s' content.
|
|
5
5
|
*/
|
|
6
6
|
export class AuthorReplaceCommand extends SsiEchoVarReplaceCommand {
|
|
7
|
-
constructor(
|
|
7
|
+
constructor(timeRenderer) {
|
|
8
8
|
super("author");
|
|
9
|
-
this.
|
|
9
|
+
this.timeRenderer = timeRenderer;
|
|
10
10
|
}
|
|
11
11
|
async createReplacer(context) {
|
|
12
12
|
return {
|
|
@@ -19,7 +19,7 @@ export class AuthorReplaceCommand extends SsiEchoVarReplaceCommand {
|
|
|
19
19
|
authorsHtml += authorsHtml ? ": " + copyright : copyright;
|
|
20
20
|
}
|
|
21
21
|
if (authorsHtml && context.time.getYear()) {
|
|
22
|
-
const { result, replacement } = this.
|
|
22
|
+
const { result, replacement } = this.timeRenderer.renderContent(context, undefined, { url: true, contentOnly: false });
|
|
23
23
|
result.append(replacement);
|
|
24
24
|
authorsHtml += ", " + result.outerHTML;
|
|
25
25
|
}
|
|
@@ -8,7 +8,7 @@ describe("AuthorReplaceCommand", async () => {
|
|
|
8
8
|
const timeService = await rr0TestUtil.time.getService();
|
|
9
9
|
test("no author", async () => {
|
|
10
10
|
const timeFile = rr0TestUtil.time.filePath("1/9/5/4/index.html");
|
|
11
|
-
const command = new AuthorReplaceCommand(
|
|
11
|
+
const command = new AuthorReplaceCommand(rr0TestUtil.time.timeRenderer);
|
|
12
12
|
const context = rr0TestUtil.newHtmlContext(timeFile, `This is published by <!--#echo var="author" -->!`);
|
|
13
13
|
await command.execute(context);
|
|
14
14
|
expect(context.file.meta.author).toEqual([]);
|
|
@@ -16,7 +16,7 @@ describe("AuthorReplaceCommand", async () => {
|
|
|
16
16
|
});
|
|
17
17
|
test("author only", async () => {
|
|
18
18
|
const timeFile = rr0TestUtil.time.filePath("1/9/5/4/10/index.html");
|
|
19
|
-
const command = new AuthorReplaceCommand(
|
|
19
|
+
const command = new AuthorReplaceCommand(rr0TestUtil.time.timeRenderer);
|
|
20
20
|
const context = rr0TestUtil.newHtmlContext(timeFile, `This is published by <!--#echo var="author" -->!`);
|
|
21
21
|
context.file.meta.author.push("Beau, Jérôme");
|
|
22
22
|
const time = relativeTimeTextBuilder.build(undefined, context);
|
|
@@ -26,7 +26,7 @@ describe("AuthorReplaceCommand", async () => {
|
|
|
26
26
|
});
|
|
27
27
|
test("copyright only", async () => {
|
|
28
28
|
const timeFile = rr0TestUtil.time.filePath("1/9/5/4/10/index.html");
|
|
29
|
-
const command = new AuthorReplaceCommand(
|
|
29
|
+
const command = new AuthorReplaceCommand(rr0TestUtil.time.timeRenderer);
|
|
30
30
|
const context = rr0TestUtil.newHtmlContext(timeFile, `This is published by <!--#echo var="author" -->!`);
|
|
31
31
|
context.file.meta.copyright = "Some publication";
|
|
32
32
|
const time = relativeTimeTextBuilder.build(undefined, context);
|
|
@@ -37,7 +37,7 @@ describe("AuthorReplaceCommand", async () => {
|
|
|
37
37
|
});
|
|
38
38
|
test("author with copyright", async () => {
|
|
39
39
|
const timeFile = rr0TestUtil.time.filePath("1/9/5/4/10/index.html");
|
|
40
|
-
const command = new AuthorReplaceCommand(
|
|
40
|
+
const command = new AuthorReplaceCommand(rr0TestUtil.time.timeRenderer);
|
|
41
41
|
const context = rr0TestUtil.newHtmlContext(timeFile, `This is published by <!--#echo var="author" -->!`);
|
|
42
42
|
context.file.meta.author.push("Beau, Jérôme");
|
|
43
43
|
context.file.meta.copyright = "Some publication";
|
|
@@ -22,8 +22,8 @@ describe("DirectoryStep", () => {
|
|
|
22
22
|
const eventFactory = new RR0EventFactory();
|
|
23
23
|
const dataService = new AllDataService([new TypedDataFactory(eventFactory, "case")]);
|
|
24
24
|
const caseFiles = await rr0TestUtil.caseFactory.getFiles();
|
|
25
|
-
const
|
|
26
|
-
const timeElementFactory = new TimeElementFactory(
|
|
25
|
+
const timeRenderer = rr0TestUtil.time.timeRenderer;
|
|
26
|
+
const timeElementFactory = new TimeElementFactory(timeRenderer);
|
|
27
27
|
const caseService = new CaseService(dataService, rr0TestUtil.caseFactory, timeElementFactory, caseFiles);
|
|
28
28
|
const ufoCasesExclusions = [];
|
|
29
29
|
const step = new CaseDirectoryStep(caseService, caseService.files, ufoCasesExclusions, casesDirectoryPath, outputFunc, rr0TestUtil.config);
|
|
@@ -21,7 +21,7 @@ export class CaseService extends AbstractDataService {
|
|
|
21
21
|
if (time) {
|
|
22
22
|
caseContext.time = new TimeContext((_a = time.year) === null || _a === void 0 ? void 0 : _a.value, (_b = time.month) === null || _b === void 0 ? void 0 : _b.value, (_c = time.day) === null || _c === void 0 ? void 0 : _c.value, (_d = time.hour) === null || _d === void 0 ? void 0 : _d.value, (_e = time.minute) === null || _e === void 0 ? void 0 : _e.value, (_f = time.timeshift) === null || _f === void 0 ? void 0 : _f.toString());
|
|
23
23
|
const options = { year: "numeric" };
|
|
24
|
-
const { result, replacement } = this.timeElementFactory.renderer.renderContent(caseContext, undefined, { url: true }, options);
|
|
24
|
+
const { result, replacement } = this.timeElementFactory.renderer.renderContent(caseContext, undefined, { url: true, contentOnly: false }, options);
|
|
25
25
|
result.append(replacement);
|
|
26
26
|
details.push(result.outerHTML);
|
|
27
27
|
}
|
|
@@ -6,6 +6,7 @@ import { RR0Data, RR0Event } from "@rr0/data";
|
|
|
6
6
|
import { Source } from "@rr0/data/dist/source";
|
|
7
7
|
import { PlaceRenderer } from "../place/PlaceRenderer";
|
|
8
8
|
import { Place } from "@rr0/place";
|
|
9
|
+
import { TimeRenderOptions } from "./html";
|
|
9
10
|
/**
|
|
10
11
|
* Render a case summary as HTML.
|
|
11
12
|
*/
|
|
@@ -18,7 +19,7 @@ export declare class EventRenderer<E extends RR0Event> {
|
|
|
18
19
|
constructor(noteRenderer: NoteRenderer, sourceFactory: SourceFactory, sourceRenderer: SourceRenderer, timeElementFactory: TimeElementFactory);
|
|
19
20
|
placeElement(context: HtmlRR0Context, place: Place): HTMLSpanElement;
|
|
20
21
|
renderEnd(context: HtmlRR0Context, event: RR0Data, container: HTMLElement): Promise<void>;
|
|
21
|
-
render(context: HtmlRR0Context, event: E, container: HTMLElement): Promise<void>;
|
|
22
|
+
render(context: HtmlRR0Context, event: E, container: HTMLElement, options?: TimeRenderOptions): Promise<void>;
|
|
22
23
|
renderNotes(context: HtmlRR0Context, notes: string[], container: HTMLElement): Promise<void>;
|
|
23
24
|
renderSources(context: HtmlRR0Context, sources: Source[], container: HTMLElement): Promise<void>;
|
|
24
25
|
}
|
|
@@ -29,12 +29,12 @@ export class EventRenderer {
|
|
|
29
29
|
}
|
|
30
30
|
container.append(".");
|
|
31
31
|
}
|
|
32
|
-
async render(context, event, container) {
|
|
32
|
+
async render(context, event, container, options = { url: true, contentOnly: false }) {
|
|
33
33
|
const eventContext = context.clone();
|
|
34
34
|
const eventTime = eventContext.time.date = event.time;
|
|
35
35
|
assert.ok(eventTime, `Event of type "${event.type}" has no time`);
|
|
36
36
|
container.dataset.time = eventTime.toString();
|
|
37
|
-
const timeEl = this.timeElementFactory.create(eventContext, context);
|
|
37
|
+
const timeEl = this.timeElementFactory.create(eventContext, context, options);
|
|
38
38
|
container.append(timeEl);
|
|
39
39
|
const place = event.place;
|
|
40
40
|
if (place) {
|
|
@@ -3,10 +3,12 @@ import { HtmlRR0Context } from "../RR0Context.js";
|
|
|
3
3
|
import { Link } from "ssg-api";
|
|
4
4
|
import { TimeTextBuilder } from "./text/TimeTextBuilder.js";
|
|
5
5
|
import { TimeService } from "./TimeService";
|
|
6
|
+
import { TimeUrlBuilder } from "./TimeUrlBuilder";
|
|
6
7
|
export declare class TimeLinkDefaultHandler implements LinkHandler<HtmlRR0Context> {
|
|
7
8
|
protected service: TimeService;
|
|
9
|
+
protected urlBuilder: TimeUrlBuilder;
|
|
8
10
|
protected timeTextBuilder: TimeTextBuilder;
|
|
9
|
-
constructor(service: TimeService, timeTextBuilder: TimeTextBuilder);
|
|
11
|
+
constructor(service: TimeService, urlBuilder: TimeUrlBuilder, timeTextBuilder: TimeTextBuilder);
|
|
10
12
|
contents(context: HtmlRR0Context): Link | undefined;
|
|
11
13
|
next(context: HtmlRR0Context): Link | undefined;
|
|
12
14
|
prev(context: HtmlRR0Context): Link | undefined;
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { LinkType } from "ssg-api";
|
|
2
2
|
export class TimeLinkDefaultHandler {
|
|
3
|
-
constructor(service, timeTextBuilder) {
|
|
3
|
+
constructor(service, urlBuilder, timeTextBuilder) {
|
|
4
4
|
this.service = service;
|
|
5
|
+
this.urlBuilder = urlBuilder;
|
|
5
6
|
this.timeTextBuilder = timeTextBuilder;
|
|
6
7
|
}
|
|
7
8
|
contents(context) {
|
|
8
9
|
const prevLink = this.prev(context);
|
|
9
10
|
if (prevLink) {
|
|
10
|
-
const
|
|
11
|
-
let contentUrl =
|
|
12
|
-
if (contentUrl !=
|
|
13
|
-
const text = service.titleFromFile(context, contentUrl, this.timeTextBuilder);
|
|
11
|
+
const urlBuilder = this.urlBuilder;
|
|
12
|
+
let contentUrl = urlBuilder.matchExistingTimeFile(prevLink.url.substring(1));
|
|
13
|
+
if (contentUrl != urlBuilder.options.rootDir) {
|
|
14
|
+
const text = this.service.titleFromFile(context, contentUrl, this.timeTextBuilder);
|
|
14
15
|
if (text) {
|
|
15
16
|
return { type: LinkType.prev, text, url: "/" + contentUrl };
|
|
16
17
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,34 +1,13 @@
|
|
|
1
|
-
import { TimeRenderer } from "./html/TimeRenderer.js";
|
|
2
1
|
import { TimeTextBuilder } from "./text/TimeTextBuilder.js";
|
|
3
|
-
import { TimeUrlBuilder } from "./TimeUrlBuilder";
|
|
4
2
|
import { AbstractDataService, AllDataService, RR0Event, RR0EventJson } from "@rr0/data";
|
|
5
3
|
import { HtmlRR0Context } from "../RR0Context";
|
|
6
4
|
import { TimeContext } from "@rr0/time";
|
|
7
|
-
|
|
8
|
-
readonly root: string;
|
|
9
|
-
readonly files: string[];
|
|
10
|
-
};
|
|
5
|
+
import { TimeOptions } from "./TimeOptions";
|
|
11
6
|
export declare class TimeService extends AbstractDataService<RR0Event, RR0EventJson> {
|
|
12
|
-
|
|
13
|
-
readonly urlBuilder: TimeUrlBuilder;
|
|
7
|
+
protected options: TimeOptions;
|
|
14
8
|
readonly timePathRegex: RegExp;
|
|
15
9
|
static readonly defaultRegex: RegExp;
|
|
16
|
-
|
|
17
|
-
readonly root: string;
|
|
18
|
-
constructor(dataService: AllDataService, textBuilder: TimeTextBuilder, urlBuilder: TimeUrlBuilder, options: TimeServiceOptions, timePathRegex?: RegExp);
|
|
19
|
-
isTimeFile(filePath: string): boolean;
|
|
20
|
-
/**
|
|
21
|
-
* @return the found time URL or undefined if not found.
|
|
22
|
-
*/
|
|
23
|
-
matchExistingTimeFile(url: string): string | undefined;
|
|
24
|
-
/**
|
|
25
|
-
* Instantiate a Date object matching an ISO date ("1972-08-12 16:34" for instance).
|
|
26
|
-
*
|
|
27
|
-
* Approximated dates like "~1972" will be converted to exact dates ("1972").
|
|
28
|
-
*
|
|
29
|
-
* @param isoDate
|
|
30
|
-
*/
|
|
31
|
-
dateFromIso(isoDate: string): Date;
|
|
10
|
+
constructor(dataService: AllDataService, options: TimeOptions, timePathRegex?: RegExp);
|
|
32
11
|
parseFileName(fileName: string): RegExpExecArray | null;
|
|
33
12
|
titleFromFile(context: HtmlRR0Context, fileName: string, timeTextBuilder: TimeTextBuilder): string | undefined;
|
|
34
13
|
contextFromFileName(context: HtmlRR0Context, fileName?: string): TimeContext | undefined;
|
package/dist/time/TimeService.js
CHANGED
|
@@ -1,42 +1,11 @@
|
|
|
1
|
-
import { TimeRenderer } from "./html/TimeRenderer.js";
|
|
2
1
|
import { AbstractDataService } from "@rr0/data";
|
|
3
2
|
import { RR0ContextImpl } from "../RR0Context";
|
|
4
3
|
import { StringUtil } from "../util";
|
|
5
4
|
export class TimeService extends AbstractDataService {
|
|
6
|
-
constructor(dataService,
|
|
5
|
+
constructor(dataService, options, timePathRegex = TimeService.defaultRegex) {
|
|
7
6
|
super(dataService, null, options.files);
|
|
8
|
-
this.
|
|
9
|
-
this.urlBuilder = urlBuilder;
|
|
7
|
+
this.options = options;
|
|
10
8
|
this.timePathRegex = timePathRegex;
|
|
11
|
-
this.root = options.root;
|
|
12
|
-
this.renderer = new TimeRenderer(this, this.textBuilder);
|
|
13
|
-
}
|
|
14
|
-
isTimeFile(filePath) {
|
|
15
|
-
return this.files.includes(filePath);
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* @return the found time URL or undefined if not found.
|
|
19
|
-
*/
|
|
20
|
-
matchExistingTimeFile(url) {
|
|
21
|
-
while (url && url !== this.root && this.files.indexOf(`${url}/index.html`) < 0) {
|
|
22
|
-
const slash = url.lastIndexOf("/");
|
|
23
|
-
url = url.substring(0, slash);
|
|
24
|
-
}
|
|
25
|
-
return url === this.root ? undefined : url;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Instantiate a Date object matching an ISO date ("1972-08-12 16:34" for instance).
|
|
29
|
-
*
|
|
30
|
-
* Approximated dates like "~1972" will be converted to exact dates ("1972").
|
|
31
|
-
*
|
|
32
|
-
* @param isoDate
|
|
33
|
-
*/
|
|
34
|
-
dateFromIso(isoDate) {
|
|
35
|
-
isoDate = isoDate.replace("~", "");
|
|
36
|
-
if (isoDate.charAt(0) === "-") {
|
|
37
|
-
isoDate = "-" + "0".repeat(7 - isoDate.length) + isoDate.substring(1);
|
|
38
|
-
}
|
|
39
|
-
return new Date(isoDate);
|
|
40
9
|
}
|
|
41
10
|
parseFileName(fileName) {
|
|
42
11
|
return this.timePathRegex.exec(fileName);
|
|
@@ -5,11 +5,11 @@ import { DomReplaceCommand } from "ssg-api";
|
|
|
5
5
|
import { TimeReplacer } from "./html/TimeReplacer.js";
|
|
6
6
|
import path from "path";
|
|
7
7
|
describe("HtmlTagReplaceCommand", async () => {
|
|
8
|
-
const timeRoot = rr0TestUtil.time.timeOptions.
|
|
9
|
-
await rr0TestUtil.time.getService({
|
|
8
|
+
const timeRoot = rr0TestUtil.time.timeOptions.rootDir;
|
|
9
|
+
const timeService = await rr0TestUtil.time.getService({ rootDir: path.join(rr0TestUtil.rootDir, timeRoot), files: ["time/2/0/0/4/index.html"] });
|
|
10
10
|
test("replace time tag", async () => {
|
|
11
11
|
const replacer = new TimeReplacer(rr0TestUtil.time.timeElementFactory);
|
|
12
|
-
const command = new DomReplaceCommand("time", new TimeReplacerFactory(replacer));
|
|
12
|
+
const command = new DomReplaceCommand("time", new TimeReplacerFactory(replacer, rr0TestUtil.time.urlBuilder));
|
|
13
13
|
const context = rr0TestUtil.time.newHtmlContext("1/9/9/0/08/index.html", `<time>2004</time> <a href="/science/crypto/ufo/enquete/dossier/Roswell">Roswell</a>`);
|
|
14
14
|
await command.execute(context);
|
|
15
15
|
expect(context.file.contents).toBe(`<html><head><meta name="generator" content="ssg-api"></head><body><span class="time-resolved">en <a href="${path.join("/", timeRoot, "2/0/0/4/")}"><time datetime="2004">2004</time></a></span> <a href="/science/crypto/ufo/enquete/dossier/Roswell">Roswell</a></body></html>`);
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import { TimeElementFactory,
|
|
1
|
+
import { TimeElementFactory, TimeRenderer, TimeService, TimeTextBuilder, TimeUrlBuilder } from "../time/index.js";
|
|
2
2
|
import { RR0TestUtil } from "../test";
|
|
3
3
|
import { HtmlRR0Context } from "../RR0Context";
|
|
4
|
+
import { TimeOptions } from "./TimeOptions";
|
|
4
5
|
export declare class TimeTestUtil {
|
|
5
6
|
readonly timeTextBuilder: TimeTextBuilder;
|
|
6
7
|
timeElementFactory: TimeElementFactory;
|
|
7
|
-
timeOptions:
|
|
8
|
+
timeOptions: TimeOptions;
|
|
8
9
|
urlBuilder: TimeUrlBuilder;
|
|
9
10
|
protected timeService: TimeService;
|
|
10
|
-
fullRoot: string;
|
|
11
|
+
readonly fullRoot: string;
|
|
12
|
+
readonly timeRenderer: TimeRenderer;
|
|
11
13
|
constructor(rr0TestUtil: RR0TestUtil);
|
|
12
14
|
newHtmlContext(inputFileName: string, contents?: string, locale?: string): HtmlRR0Context;
|
|
13
15
|
filePath(inputFileName: string): string;
|
|
14
16
|
url(inputFileName: string): string;
|
|
15
|
-
getService(options?:
|
|
17
|
+
getService(options?: TimeOptions): TimeService;
|
|
16
18
|
}
|
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
import path from "path";
|
|
2
|
-
import { TimeElementFactory, TimeService, TimeTextBuilder, TimeUrlBuilder } from "../time/index.js";
|
|
2
|
+
import { TimeElementFactory, TimeRenderer, TimeService, TimeTextBuilder, TimeUrlBuilder } from "../time/index.js";
|
|
3
3
|
import { rr0TestUtil } from "../test";
|
|
4
4
|
export class TimeTestUtil {
|
|
5
5
|
constructor(rr0TestUtil) {
|
|
6
|
-
this.timeOptions = {
|
|
7
|
-
this.urlBuilder = new TimeUrlBuilder(
|
|
6
|
+
this.timeOptions = { rootDir: "time", files: [] };
|
|
7
|
+
this.urlBuilder = new TimeUrlBuilder(this.timeOptions);
|
|
8
8
|
this.timeTextBuilder = new TimeTextBuilder(rr0TestUtil.intlOptions);
|
|
9
|
-
this.fullRoot = path.join(rr0TestUtil.rootDir, this.timeOptions.
|
|
9
|
+
this.fullRoot = path.join(rr0TestUtil.rootDir, this.timeOptions.rootDir);
|
|
10
|
+
this.timeRenderer = new TimeRenderer(this.urlBuilder, this.timeTextBuilder);
|
|
10
11
|
}
|
|
11
12
|
newHtmlContext(inputFileName, contents, locale = "fr") {
|
|
12
13
|
return rr0TestUtil.newHtmlContext(this.filePath(inputFileName), contents, locale);
|
|
13
14
|
}
|
|
14
15
|
filePath(inputFileName) {
|
|
15
|
-
return path.join(this.timeOptions.
|
|
16
|
+
return path.join(this.timeOptions.rootDir, inputFileName);
|
|
16
17
|
}
|
|
17
18
|
url(inputFileName) {
|
|
18
19
|
return path.join("/", this.filePath(inputFileName));
|
|
19
20
|
}
|
|
20
21
|
getService(options = this.timeOptions) {
|
|
21
22
|
if (!this.timeService
|
|
22
|
-
|| this.
|
|
23
|
+
|| this.timeOptions.rootDir !== options.rootDir
|
|
23
24
|
|| JSON.stringify(this.timeService.files) !== JSON.stringify(options.files)) {
|
|
24
|
-
this.
|
|
25
|
-
this.
|
|
25
|
+
this.timeOptions = options;
|
|
26
|
+
this.timeService = new TimeService(rr0TestUtil.dataService, options);
|
|
27
|
+
this.timeElementFactory = new TimeElementFactory(this.timeRenderer);
|
|
26
28
|
}
|
|
27
29
|
return this.timeService;
|
|
28
30
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { Level2Date as EdtfDate, TimeContext } from "@rr0/time";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
2
|
+
import { TimeOptions } from "./TimeOptions";
|
|
3
|
+
export type TimeUrlBuilderOptions = TimeOptions;
|
|
5
4
|
export declare class TimeUrlBuilder {
|
|
6
5
|
readonly options: TimeUrlBuilderOptions;
|
|
7
6
|
constructor(options: TimeUrlBuilderOptions);
|
|
8
7
|
fromContext(time: TimeContext): string;
|
|
9
8
|
fromEdtf(time: EdtfDate): string;
|
|
10
9
|
fromYYMMDD(year: number, month: number, day: number): string;
|
|
10
|
+
isTimeFile(filePath: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* @return the found time URL or undefined if not found.
|
|
13
|
+
*/
|
|
14
|
+
matchExistingTimeFile(url: string): string | undefined;
|
|
11
15
|
}
|
|
@@ -23,4 +23,18 @@ export class TimeUrlBuilder {
|
|
|
23
23
|
}
|
|
24
24
|
return url;
|
|
25
25
|
}
|
|
26
|
+
isTimeFile(filePath) {
|
|
27
|
+
return this.options.files.includes(filePath);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* @return the found time URL or undefined if not found.
|
|
31
|
+
*/
|
|
32
|
+
matchExistingTimeFile(url) {
|
|
33
|
+
const rootDir = this.options.rootDir;
|
|
34
|
+
while (url && url !== rootDir && !this.isTimeFile(`${url}/index.html`)) {
|
|
35
|
+
const slash = url.lastIndexOf("/");
|
|
36
|
+
url = url.substring(0, slash);
|
|
37
|
+
}
|
|
38
|
+
return url === rootDir ? undefined : url;
|
|
39
|
+
}
|
|
26
40
|
}
|
|
@@ -7,7 +7,8 @@ import path from "path";
|
|
|
7
7
|
describe("TimeUrlBuilder", () => {
|
|
8
8
|
const config = rr0TestUtil.config;
|
|
9
9
|
const rootDir = rr0TestUtil.time.fullRoot;
|
|
10
|
-
const
|
|
10
|
+
const timeOptions = { rootDir, files: [] };
|
|
11
|
+
const timeUrlBuilder = new TimeUrlBuilder(timeOptions);
|
|
11
12
|
test("builds year", () => {
|
|
12
13
|
{
|
|
13
14
|
const context = new RR0ContextImpl("fr", new TimeContext(), config);
|
|
@@ -44,7 +44,7 @@ export class ChronologyReplacer {
|
|
|
44
44
|
for (const c of allCases) {
|
|
45
45
|
const outDoc = context.file.document;
|
|
46
46
|
const eventEl = outDoc.createElement("li");
|
|
47
|
-
await this.renderer.render(context, c, eventEl);
|
|
47
|
+
await this.renderer.render(context, c, eventEl, { url: true, contentOnly: true });
|
|
48
48
|
element.append(eventEl);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
@@ -2,12 +2,12 @@ import { DomReplacer, ReplacerFactory } from "ssg-api";
|
|
|
2
2
|
import { ChronologyReplacer } from "./ChronologyReplacer.js";
|
|
3
3
|
import { HtmlRR0Context } from "../../RR0Context.js";
|
|
4
4
|
import { CaseSummaryRenderer } from "../CaseSummaryRenderer.js";
|
|
5
|
-
import { TimeService } from "../TimeService.js";
|
|
6
5
|
import { RR0CaseMapping } from "./rr0/RR0CaseMapping.js";
|
|
6
|
+
import { TimeUrlBuilder } from "../TimeUrlBuilder";
|
|
7
7
|
export declare class ChronologyReplacerFactory implements ReplacerFactory<DomReplacer> {
|
|
8
|
-
protected
|
|
8
|
+
protected timeUrlBuilder: TimeUrlBuilder;
|
|
9
9
|
protected readonly replacer: ChronologyReplacer;
|
|
10
|
-
constructor(
|
|
10
|
+
constructor(timeUrlBuilder: TimeUrlBuilder, datasources: RR0CaseMapping<any>[], caseRenderer: CaseSummaryRenderer);
|
|
11
11
|
/**
|
|
12
12
|
* Creates a contextual replacer for time tags.
|
|
13
13
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ChronologyReplacer } from "./ChronologyReplacer.js";
|
|
2
2
|
export class ChronologyReplacerFactory {
|
|
3
|
-
constructor(
|
|
4
|
-
this.
|
|
3
|
+
constructor(timeUrlBuilder, datasources, caseRenderer) {
|
|
4
|
+
this.timeUrlBuilder = timeUrlBuilder;
|
|
5
5
|
this.replacer = new ChronologyReplacer(datasources, caseRenderer);
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
@@ -12,7 +12,7 @@ export class ChronologyReplacerFactory {
|
|
|
12
12
|
async create(context) {
|
|
13
13
|
return {
|
|
14
14
|
replace: async (ul) => {
|
|
15
|
-
const isTimeFile = this.
|
|
15
|
+
const isTimeFile = this.timeUrlBuilder.isTimeFile(context.file.name);
|
|
16
16
|
if (isTimeFile) {
|
|
17
17
|
ul = await this.replacer.replacement(context, ul);
|
|
18
18
|
}
|
|
@@ -45,7 +45,7 @@ export class DatasourceTestCase {
|
|
|
45
45
|
const http = new HttpSource();
|
|
46
46
|
const timeService = await rr0TestUtil.time.getService();
|
|
47
47
|
const sourceFactory = new SourceFactory(dataService, http, baseUrl, this.intlOptions, timeService);
|
|
48
|
-
const timeElementFactory = new TimeElementFactory(new TimeRenderer(
|
|
48
|
+
const timeElementFactory = new TimeElementFactory(new TimeRenderer(rr0TestUtil.time.urlBuilder, this.timeTextBuilder));
|
|
49
49
|
const eventRenderer = new CaseSummaryRenderer(new NoteRenderer(new NoteFileCounter()), sourceFactory, new SourceRenderer(this.timeTextBuilder), timeElementFactory);
|
|
50
50
|
const items = [];
|
|
51
51
|
for (const c of cases) {
|
|
@@ -6,7 +6,7 @@ export class TimeElementFactory {
|
|
|
6
6
|
constructor(renderer) {
|
|
7
7
|
this.renderer = renderer;
|
|
8
8
|
}
|
|
9
|
-
create(context, previousContext, options = { url: true }) {
|
|
9
|
+
create(context, previousContext, options = { url: true, contentOnly: false }) {
|
|
10
10
|
let replacement;
|
|
11
11
|
const time = context.time;
|
|
12
12
|
const interval = time.interval;
|
|
@@ -52,7 +52,7 @@ export class TimeElementFactory {
|
|
|
52
52
|
result.append(startingReplacement, replacement);
|
|
53
53
|
return result;
|
|
54
54
|
}
|
|
55
|
-
valueReplacement(context, previousContext, options = { url: true }) {
|
|
55
|
+
valueReplacement(context, previousContext, options = { url: true, contentOnly: false }) {
|
|
56
56
|
let replacement;
|
|
57
57
|
if (context.time.duration) {
|
|
58
58
|
replacement = this.durationReplacement(context);
|
|
@@ -100,7 +100,7 @@ export class TimeElementFactory {
|
|
|
100
100
|
}
|
|
101
101
|
return replacement;
|
|
102
102
|
}
|
|
103
|
-
dateTimeReplacement(context, previousContext, options = { url: true }) {
|
|
103
|
+
dateTimeReplacement(context, previousContext, options = { url: true, contentOnly: false }) {
|
|
104
104
|
let replacement = undefined;
|
|
105
105
|
if (context.time.isDefined()) {
|
|
106
106
|
replacement = this.renderer.render(context, previousContext, options);
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { HtmlRR0Context, RR0Context } from "../../RR0Context.js";
|
|
2
2
|
import { TimeTextBuilder } from "../text/TimeTextBuilder.js";
|
|
3
3
|
import { RelativeTimeTextBuilder } from "../text/RelativeTimeTextBuilder.js";
|
|
4
|
-
import {
|
|
4
|
+
import { TimeUrlBuilder } from "../TimeUrlBuilder";
|
|
5
5
|
export interface TimeRenderOptions {
|
|
6
6
|
url: boolean;
|
|
7
|
+
contentOnly: boolean;
|
|
7
8
|
}
|
|
8
9
|
export declare class TimeRenderer {
|
|
9
|
-
readonly
|
|
10
|
+
readonly urlBuilder: TimeUrlBuilder;
|
|
10
11
|
protected textBuilder: TimeTextBuilder;
|
|
11
12
|
protected readonly relativeTextBuilder: RelativeTimeTextBuilder;
|
|
12
|
-
constructor(
|
|
13
|
+
constructor(urlBuilder: TimeUrlBuilder, textBuilder: TimeTextBuilder);
|
|
13
14
|
render(context: HtmlRR0Context, previousContext?: RR0Context, options?: TimeRenderOptions): HTMLElement;
|
|
14
15
|
renderContent(context: HtmlRR0Context, previousContext: RR0Context, options: TimeRenderOptions, renderOptions?: Intl.DateTimeFormatOptions): {
|
|
15
16
|
result: HTMLElement;
|
|
@@ -2,22 +2,25 @@ import { RelativeTimeTextBuilder } from "../text/RelativeTimeTextBuilder.js";
|
|
|
2
2
|
import { UrlUtil } from "../../util/url/UrlUtil.js";
|
|
3
3
|
import { TimeReplacer } from "./TimeReplacer.js";
|
|
4
4
|
export class TimeRenderer {
|
|
5
|
-
constructor(
|
|
6
|
-
this.
|
|
5
|
+
constructor(urlBuilder, textBuilder) {
|
|
6
|
+
this.urlBuilder = urlBuilder;
|
|
7
7
|
this.textBuilder = textBuilder;
|
|
8
8
|
this.relativeTextBuilder = new RelativeTimeTextBuilder(textBuilder);
|
|
9
9
|
}
|
|
10
|
-
render(context, previousContext, options = { url: true }) {
|
|
10
|
+
render(context, previousContext, options = { url: true, contentOnly: false }) {
|
|
11
11
|
const { result, replacement } = this.renderContent(context, previousContext, options);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
if (!options.contentOnly) {
|
|
13
|
+
const timeMessages = context.messages.context.time;
|
|
14
|
+
const time = context.time;
|
|
15
|
+
const message = time.getDayOfMonth() ? timeMessages.on : timeMessages.in;
|
|
16
|
+
result.append(message(time.approximate));
|
|
17
|
+
}
|
|
18
|
+
result.append(replacement);
|
|
16
19
|
return result;
|
|
17
20
|
}
|
|
18
21
|
renderContent(context, previousContext, options, renderOptions = this.textBuilder.options) {
|
|
19
22
|
const time = context.time;
|
|
20
|
-
const absoluteTimeUrl = this.
|
|
23
|
+
const absoluteTimeUrl = this.urlBuilder.fromContext(time);
|
|
21
24
|
const title = this.textBuilder.build(context, renderOptions);
|
|
22
25
|
const text = (previousContext ? this.relativeTextBuilder.build(previousContext, context) : undefined) || title;
|
|
23
26
|
const file = context.file;
|
|
@@ -30,7 +33,7 @@ export class TimeRenderer {
|
|
|
30
33
|
}
|
|
31
34
|
timeEl.textContent = text;
|
|
32
35
|
const dirName = currentFileName.substring(0, currentFileName.indexOf("/index"));
|
|
33
|
-
const existingUrl = options.url && this.
|
|
36
|
+
const existingUrl = options.url && this.urlBuilder.matchExistingTimeFile(absoluteTimeUrl);
|
|
34
37
|
if (existingUrl && existingUrl !== dirName) {
|
|
35
38
|
const a = replacement = doc.createElement("a");
|
|
36
39
|
a.href = UrlUtil.absolute(existingUrl);
|
|
@@ -6,9 +6,9 @@ import { TimeElementFactory } from "./TimeElementFactory.js";
|
|
|
6
6
|
import { TimeTextBuilder } from "../text/TimeTextBuilder.js";
|
|
7
7
|
import path from "path";
|
|
8
8
|
describe("TimeReplacer", async () => {
|
|
9
|
-
const timeRoot = rr0TestUtil.time.timeOptions.
|
|
10
|
-
const
|
|
11
|
-
|
|
9
|
+
const timeRoot = rr0TestUtil.time.timeOptions.rootDir;
|
|
10
|
+
const timeOptions = {
|
|
11
|
+
rootDir: timeRoot,
|
|
12
12
|
files: [
|
|
13
13
|
path.join(timeRoot, "1/9/4/7/07/02/index.html"),
|
|
14
14
|
path.join(timeRoot, "2/0/0/3/index.html"),
|
|
@@ -21,13 +21,14 @@ describe("TimeReplacer", async () => {
|
|
|
21
21
|
path.join(timeRoot, "2/0/0/6/07/14/index.html"),
|
|
22
22
|
path.join(timeRoot, "2/0/0/7/06/15/index.html")
|
|
23
23
|
]
|
|
24
|
-
}
|
|
24
|
+
};
|
|
25
|
+
const timeService = await rr0TestUtil.time.getService(timeOptions);
|
|
25
26
|
const textBuilder = new TimeTextBuilder(rr0TestUtil.intlOptions);
|
|
26
|
-
const timeRenderer = new TimeRenderer(
|
|
27
|
+
const timeRenderer = new TimeRenderer(rr0TestUtil.time.urlBuilder, textBuilder);
|
|
27
28
|
const timeElementFactory = new TimeElementFactory(timeRenderer);
|
|
28
29
|
const replacer = new TimeReplacer(timeElementFactory);
|
|
29
30
|
function timeUrl(pathStr) {
|
|
30
|
-
return path.join("/",
|
|
31
|
+
return path.join("/", timeOptions.rootDir, pathStr, "index.html");
|
|
31
32
|
}
|
|
32
33
|
test("parses year", async () => {
|
|
33
34
|
{
|
|
@@ -35,7 +36,7 @@ describe("TimeReplacer", async () => {
|
|
|
35
36
|
const timeEl = context.file.document.createElement("time");
|
|
36
37
|
timeEl.textContent = "2003";
|
|
37
38
|
const replacement = await replacer.replacement(context, timeEl);
|
|
38
|
-
expect(replacement.outerHTML).toBe(`<span class="time-resolved">en <a href="${path.join("/",
|
|
39
|
+
expect(replacement.outerHTML).toBe(`<span class="time-resolved">en <a href="${path.join("/", timeOptions.rootDir, "2/0/0/3/")}"><time datetime="2003">2003</time></a></span>`);
|
|
39
40
|
expect(context.time.getYear()).toBe(2003);
|
|
40
41
|
expect(context.time.getMonth()).toBe(undefined);
|
|
41
42
|
expect(context.time.getDayOfMonth()).toBe(undefined);
|
|
@@ -48,7 +49,7 @@ describe("TimeReplacer", async () => {
|
|
|
48
49
|
const timeEl = context.file.document.createElement("time");
|
|
49
50
|
timeEl.innerHTML = "2003\n ";
|
|
50
51
|
const replacement = await replacer.replacement(context, timeEl);
|
|
51
|
-
expect(replacement.outerHTML).toBe(`<span class="time-resolved">en <a href="${path.join("/",
|
|
52
|
+
expect(replacement.outerHTML).toBe(`<span class="time-resolved">en <a href="${path.join("/", timeOptions.rootDir, "2/0/0/3/")}"><time datetime="2003">2003</time></a></span>`);
|
|
52
53
|
expect(context.time.getYear()).toBe(2003);
|
|
53
54
|
expect(context.time.getMonth()).toBe(undefined);
|
|
54
55
|
expect(context.time.getDayOfMonth()).toBe(undefined);
|
|
@@ -64,7 +65,7 @@ describe("TimeReplacer", async () => {
|
|
|
64
65
|
original.textContent = interval;
|
|
65
66
|
const replaced = await replacer.replacement(context, original);
|
|
66
67
|
expect(replaced.outerHTML)
|
|
67
|
-
.toBe(`<span class="time-interval"><span class="time-resolved">en <a href="${path.join("/",
|
|
68
|
+
.toBe(`<span class="time-interval"><span class="time-resolved">en <a href="${path.join("/", timeOptions.rootDir, "2/0/0/3/")}"><time datetime="2003">2003</time></a></span> à <span class="time-resolved">en <a href="${path.join("/", timeOptions.rootDir, "2/0/0/4/")}"><time datetime="2004">2004</time></a></span></span>`);
|
|
68
69
|
expect(context.time.getYear()).toBe(2004);
|
|
69
70
|
expect(context.time.getMonth()).toBe(undefined);
|
|
70
71
|
expect(context.time.getDayOfMonth()).toBe(undefined);
|
|
@@ -93,7 +94,7 @@ describe("TimeReplacer", async () => {
|
|
|
93
94
|
original.textContent = "2003-12-24T10:22CDT";
|
|
94
95
|
const replacement = await replacer.replacement(context, original);
|
|
95
96
|
expect(replacement.outerHTML)
|
|
96
|
-
.toBe(`<span class="time-resolved">le <a href="${path.join("/",
|
|
97
|
+
.toBe(`<span class="time-resolved">le <a href="${path.join("/", timeOptions.rootDir, "2/0/0/3/12/24/")}"><time datetime="2003-12-24T10:22-05">mercredi 24 décembre 2003 à 10:22</time></a></span>`); // TODO: Text should have timezone info
|
|
97
98
|
expect(context.time.getYear()).toBe(2003);
|
|
98
99
|
expect(context.time.getMonth()).toBe(12);
|
|
99
100
|
expect(context.time.getDayOfMonth()).toBe(24);
|
|
@@ -120,7 +121,7 @@ describe("TimeReplacer", async () => {
|
|
|
120
121
|
const original = context.file.document.createElement("time");
|
|
121
122
|
original.textContent = "2004-09";
|
|
122
123
|
const replacement = await replacer.replacement(context, original);
|
|
123
|
-
expect(replacement.outerHTML).toBe(`<span class="time-resolved">en <a href="${path.join("/",
|
|
124
|
+
expect(replacement.outerHTML).toBe(`<span class="time-resolved">en <a href="${path.join("/", timeOptions.rootDir, "2/0/0/4/09/")}"><time datetime="2004-09">septembre 2004</time></a></span>`);
|
|
124
125
|
expect(context.time.getYear()).toBe(2004);
|
|
125
126
|
expect(context.time.getMonth()).toBe(9);
|
|
126
127
|
expect(context.time.getDayOfMonth()).toBe(undefined);
|
|
@@ -133,7 +134,7 @@ describe("TimeReplacer", async () => {
|
|
|
133
134
|
const timeEl = context.file.document.createElement("time");
|
|
134
135
|
timeEl.textContent = "2005-08-23";
|
|
135
136
|
const replacement = await replacer.replacement(context, timeEl);
|
|
136
|
-
expect(replacement.outerHTML).toBe(`<span class="time-resolved">le <a href="${path.join("/",
|
|
137
|
+
expect(replacement.outerHTML).toBe(`<span class="time-resolved">le <a href="${path.join("/", timeOptions.rootDir, "2/0/0/5/08/23/")}"><time datetime="2005-08-23">mardi 23 août 2005</time></a></span>`);
|
|
137
138
|
expect(context.time.getYear()).toBe(2005);
|
|
138
139
|
expect(context.time.getMonth()).toBe(8);
|
|
139
140
|
expect(context.time.getDayOfMonth()).toBe(23);
|
|
@@ -201,7 +202,7 @@ describe("TimeReplacer", async () => {
|
|
|
201
202
|
const timeEl = context.file.document.createElement("time");
|
|
202
203
|
timeEl.textContent = "2006-07-14 17:56";
|
|
203
204
|
const replacement = await replacer.replacement(context, timeEl);
|
|
204
|
-
expect(replacement.outerHTML).toBe(`<span class="time-resolved">le <a href="${path.join("/",
|
|
205
|
+
expect(replacement.outerHTML).toBe(`<span class="time-resolved">le <a href="${path.join("/", timeOptions.rootDir, "2/0/0/6/07/14/")}"><time datetime="2006-07-14T17:56">vendredi 14 juillet 2006 à 17:56</time></a></span>`);
|
|
205
206
|
expect(context.time.getYear()).toBe(2006);
|
|
206
207
|
expect(context.time.getMonth()).toBe(7);
|
|
207
208
|
expect(context.time.getDayOfMonth()).toBe(14);
|
|
@@ -211,7 +212,7 @@ describe("TimeReplacer", async () => {
|
|
|
211
212
|
const timeEl1 = context.file.document.createElement("time");
|
|
212
213
|
timeEl1.textContent = "2007-06-15 18:47";
|
|
213
214
|
const replacement1 = await replacer.replacement(context, timeEl1);
|
|
214
|
-
expect(replacement1.outerHTML).toBe(`<span class="time-resolved">le <a href="${path.join("/",
|
|
215
|
+
expect(replacement1.outerHTML).toBe(`<span class="time-resolved">le <a href="${path.join("/", timeOptions.rootDir, "2/0/0/7/06/15/")}"><time datetime="2007-06-15T18:47">vendredi 15 juin 2007 à 18:47</time></a></span>`);
|
|
215
216
|
expect(context.time.getYear()).toBe(2007);
|
|
216
217
|
expect(context.time.getMonth()).toBe(6);
|
|
217
218
|
expect(context.time.getDayOfMonth()).toBe(15);
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { TimeReplacer } from "./TimeReplacer.js";
|
|
2
2
|
import { HtmlRR0Context } from "../../RR0Context.js";
|
|
3
3
|
import { DomReplacer, ReplacerFactory } from "ssg-api";
|
|
4
|
+
import { TimeUrlBuilder } from "../TimeUrlBuilder";
|
|
4
5
|
export declare class TimeReplacerFactory implements ReplacerFactory<DomReplacer> {
|
|
5
6
|
protected readonly replacer: TimeReplacer;
|
|
6
|
-
|
|
7
|
+
protected readonly timeUrlBuilder: TimeUrlBuilder;
|
|
8
|
+
constructor(replacer: TimeReplacer, timeUrlBuilder: TimeUrlBuilder);
|
|
7
9
|
/**
|
|
8
10
|
* Creates a contextual replacer for time tags.
|
|
9
11
|
*
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export class TimeReplacerFactory {
|
|
2
|
-
constructor(replacer) {
|
|
2
|
+
constructor(replacer, timeUrlBuilder) {
|
|
3
3
|
this.replacer = replacer;
|
|
4
|
+
this.timeUrlBuilder = timeUrlBuilder;
|
|
4
5
|
}
|
|
5
6
|
/**
|
|
6
7
|
* Creates a contextual replacer for time tags.
|
|
@@ -10,7 +11,7 @@ export class TimeReplacerFactory {
|
|
|
10
11
|
async create(context) {
|
|
11
12
|
return {
|
|
12
13
|
replace: (original) => {
|
|
13
|
-
return this.replacer.replacement(this.
|
|
14
|
+
return this.replacer.replacement(this.timeUrlBuilder.isTimeFile(context.file.name) ? context.clone() : context, original);
|
|
14
15
|
}
|
|
15
16
|
};
|
|
16
17
|
}
|
package/dist/time/index.d.ts
CHANGED
package/dist/time/index.js
CHANGED
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@rr0/cms",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"author": "Jérôme Beau <rr0@rr0.org> (https://rr0.org)",
|
|
5
|
-
"version": "0.3.
|
|
5
|
+
"version": "0.3.16",
|
|
6
6
|
"description": "RR0 Content Management System (CMS)",
|
|
7
7
|
"exports": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@javarome/fileutil": "^0.3.6",
|
|
32
32
|
"@rr0/common": "^1.1.3",
|
|
33
|
-
"@rr0/data": "^0.3.
|
|
33
|
+
"@rr0/data": "^0.3.13",
|
|
34
34
|
"@rr0/lang": "^0.1.12",
|
|
35
35
|
"@rr0/place": "^0.5.2",
|
|
36
|
-
"@rr0/time": "^0.
|
|
36
|
+
"@rr0/time": "^0.11.0",
|
|
37
37
|
"canvas": "^2.11.2",
|
|
38
38
|
"csv-parser": "^3.0.0",
|
|
39
39
|
"glob": "^11.0.0",
|