@lionrapid/core 0.2.0 → 0.3.0-beta.0
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/browser/auto-translator.d.ts.map +1 -1
- package/dist/browser/auto-translator.js +15 -4
- package/dist/browser/auto-translator.js.map +1 -1
- package/dist/browser/block-extractor.d.ts.map +1 -1
- package/dist/browser/block-extractor.js +6 -0
- package/dist/browser/block-extractor.js.map +1 -1
- package/dist/browser/editor/editor-api.d.ts +31 -1
- package/dist/browser/editor/editor-api.d.ts.map +1 -1
- package/dist/browser/editor/editor-api.js +43 -1
- package/dist/browser/editor/editor-api.js.map +1 -1
- package/dist/browser/editor/editor-init.js +25 -0
- package/dist/browser/editor/editor-init.js.map +1 -1
- package/dist/browser/editor/editor-styles.d.ts +1 -1
- package/dist/browser/editor/editor-styles.d.ts.map +1 -1
- package/dist/browser/editor/editor-styles.js +55 -0
- package/dist/browser/editor/editor-styles.js.map +1 -1
- package/dist/browser/editor/live-preview.d.ts.map +1 -1
- package/dist/browser/editor/live-preview.js +20 -3
- package/dist/browser/editor/live-preview.js.map +1 -1
- package/dist/browser/editor/sidebar.d.ts +20 -1
- package/dist/browser/editor/sidebar.d.ts.map +1 -1
- package/dist/browser/editor/sidebar.js +147 -9
- package/dist/browser/editor/sidebar.js.map +1 -1
- package/dist/browser/lionrapid.auto.dev.js +125 -311
- package/dist/browser/lionrapid.auto.dev.js.map +3 -3
- package/dist/browser/lionrapid.auto.js +125 -311
- package/dist/browser/lionrapid.auto.js.map +3 -3
- package/dist/browser/lionrapid.auto.min.js +3 -3
- package/dist/browser/lionrapid.auto.min.js.map +4 -4
- package/dist/browser/lionrapid.editor.js +274 -181
- package/dist/browser/lionrapid.editor.js.map +3 -3
- package/dist/browser/lionrapid.editor.min.js +58 -3
- package/dist/browser/lionrapid.editor.min.js.map +4 -4
- package/dist/browser/lionrapid.esm.js +108 -294
- package/dist/browser/lionrapid.esm.js.map +3 -3
- package/dist/browser/lionrapid.esm.min.js +2 -2
- package/dist/browser/lionrapid.esm.min.js.map +4 -4
- package/dist/browser/lionrapid.iife.dev.js +108 -294
- package/dist/browser/lionrapid.iife.dev.js.map +3 -3
- package/dist/browser/lionrapid.iife.js +108 -294
- package/dist/browser/lionrapid.iife.js.map +3 -3
- package/dist/browser/lionrapid.iife.min.js +2 -2
- package/dist/browser/lionrapid.iife.min.js.map +4 -4
- package/dist/browser/lionrapid.umd.js +108 -294
- package/dist/browser/lionrapid.umd.js.map +3 -3
- package/dist/browser/lionrapid.umd.min.js +2 -2
- package/dist/browser/lionrapid.umd.min.js.map +4 -4
- package/dist/browser/markup-parser.d.ts +9 -5
- package/dist/browser/markup-parser.d.ts.map +1 -1
- package/dist/browser/markup-parser.js +19 -23
- package/dist/browser/markup-parser.js.map +1 -1
- package/dist/content/canonical-tag.d.ts +34 -0
- package/dist/content/canonical-tag.d.ts.map +1 -0
- package/dist/content/canonical-tag.js +57 -0
- package/dist/content/canonical-tag.js.map +1 -0
- package/dist/content/index.d.ts +1 -4
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +3 -1
- package/dist/content/index.js.map +1 -1
- package/dist/content/parser/MarkupParser.d.ts +9 -49
- package/dist/content/parser/MarkupParser.d.ts.map +1 -1
- package/dist/content/parser/MarkupParser.js +37 -157
- package/dist/content/parser/MarkupParser.js.map +1 -1
- package/dist/content/serializer/HTMLSerializer.d.ts +10 -43
- package/dist/content/serializer/HTMLSerializer.d.ts.map +1 -1
- package/dist/content/serializer/HTMLSerializer.js +29 -69
- package/dist/content/serializer/HTMLSerializer.js.map +1 -1
- package/dist/content/types.d.ts +21 -12
- package/dist/content/types.d.ts.map +1 -1
- package/dist/content/validator/ContentValidator.d.ts +2 -2
- package/dist/content/validator/ContentValidator.js +2 -2
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/lionRapid.d.ts +1 -1
- package/dist/lionRapid.js +4 -4
- package/dist/lionRapid.js.map +1 -1
- package/dist/repositories/network-repository.d.ts +14 -0
- package/dist/repositories/network-repository.d.ts.map +1 -1
- package/dist/repositories/network-repository.js +26 -4
- package/dist/repositories/network-repository.js.map +1 -1
- package/package.json +1 -1
- package/dist/content/safe-href.d.ts +0 -22
- package/dist/content/safe-href.d.ts.map +0 -1
- package/dist/content/safe-href.js +0 -48
- package/dist/content/safe-href.js.map +0 -1
- package/dist/content/style-mapper/DefaultStyleMapper.d.ts +0 -59
- package/dist/content/style-mapper/DefaultStyleMapper.d.ts.map +0 -1
- package/dist/content/style-mapper/DefaultStyleMapper.js +0 -132
- package/dist/content/style-mapper/DefaultStyleMapper.js.map +0 -1
- package/dist/content/style-mapper/IStyleMapper.d.ts +0 -50
- package/dist/content/style-mapper/IStyleMapper.d.ts.map +0 -1
- package/dist/content/style-mapper/IStyleMapper.js +0 -6
- package/dist/content/style-mapper/IStyleMapper.js.map +0 -1
|
@@ -2138,153 +2138,51 @@ var LionRapid = (() => {
|
|
|
2138
2138
|
}
|
|
2139
2139
|
};
|
|
2140
2140
|
|
|
2141
|
-
// src/content/
|
|
2142
|
-
var
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
return
|
|
2141
|
+
// src/content/canonical-tag.ts
|
|
2142
|
+
var VOID_TAGS = /* @__PURE__ */ new Set([
|
|
2143
|
+
"area",
|
|
2144
|
+
"base",
|
|
2145
|
+
"br",
|
|
2146
|
+
"col",
|
|
2147
|
+
"embed",
|
|
2148
|
+
"hr",
|
|
2149
|
+
"img",
|
|
2150
|
+
"input",
|
|
2151
|
+
"link",
|
|
2152
|
+
"meta",
|
|
2153
|
+
"param",
|
|
2154
|
+
"source",
|
|
2155
|
+
"track",
|
|
2156
|
+
"wbr"
|
|
2157
|
+
]);
|
|
2158
|
+
function escapeAttrValue(value) {
|
|
2159
|
+
return value.replace(/"/g, """);
|
|
2160
2160
|
}
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
strike: "strikethrough",
|
|
2178
|
-
code: "code",
|
|
2179
|
-
mark: "highlight",
|
|
2180
|
-
sub: "subscript",
|
|
2181
|
-
sup: "superscript"
|
|
2182
|
-
});
|
|
2183
|
-
/**
|
|
2184
|
-
* Style → Element mapping (reverse)
|
|
2185
|
-
* Uses simple, familiar elements for developer convenience
|
|
2186
|
-
* Also accepts element names directly (strong, em, etc.)
|
|
2187
|
-
*/
|
|
2188
|
-
__publicField(this, "styleToElement", {
|
|
2189
|
-
// Semantic style names → simple elements
|
|
2190
|
-
bold: "b",
|
|
2191
|
-
italic: "i",
|
|
2192
|
-
underline: "u",
|
|
2193
|
-
strikethrough: "s",
|
|
2194
|
-
code: "code",
|
|
2195
|
-
highlight: "mark",
|
|
2196
|
-
subscript: "sub",
|
|
2197
|
-
superscript: "sup",
|
|
2198
|
-
// Element names (for servers that store styles as element names)
|
|
2199
|
-
strong: "b",
|
|
2200
|
-
b: "b",
|
|
2201
|
-
em: "i",
|
|
2202
|
-
i: "i",
|
|
2203
|
-
u: "u",
|
|
2204
|
-
s: "s",
|
|
2205
|
-
del: "s",
|
|
2206
|
-
strike: "s",
|
|
2207
|
-
mark: "mark",
|
|
2208
|
-
sub: "sub",
|
|
2209
|
-
sup: "sup"
|
|
2210
|
-
});
|
|
2211
|
-
}
|
|
2212
|
-
/**
|
|
2213
|
-
* Convert HTML element to style properties
|
|
2214
|
-
*
|
|
2215
|
-
* @param element - Tag name (e.g., "b", "a", "strong")
|
|
2216
|
-
* @param attrs - Element attributes (e.g., { href: "/url" })
|
|
2217
|
-
* @returns Array of style strings
|
|
2218
|
-
*/
|
|
2219
|
-
mapElementToStyles(element, attrs) {
|
|
2220
|
-
const styles = [];
|
|
2221
|
-
const tag = element.toLowerCase();
|
|
2222
|
-
const mappedStyle = this.elementToStyles[tag];
|
|
2223
|
-
if (mappedStyle) {
|
|
2224
|
-
styles.push(mappedStyle);
|
|
2225
|
-
}
|
|
2226
|
-
if (tag === "a" && attrs.href) {
|
|
2227
|
-
styles.push(`hyperlink:${attrs.href}`);
|
|
2228
|
-
}
|
|
2229
|
-
return styles;
|
|
2230
|
-
}
|
|
2231
|
-
/**
|
|
2232
|
-
* Convert style properties to HTML element
|
|
2233
|
-
*
|
|
2234
|
-
* Priority order:
|
|
2235
|
-
* 1. Hyperlink (becomes wrapper element with href)
|
|
2236
|
-
* 2. First recognized style property
|
|
2237
|
-
* 3. Fallback to span
|
|
2238
|
-
*
|
|
2239
|
-
* @param styles - Array of style strings
|
|
2240
|
-
* @returns Element info for serialization
|
|
2241
|
-
*/
|
|
2242
|
-
mapStylesToElement(styles) {
|
|
2243
|
-
for (const style of styles) {
|
|
2244
|
-
if (style.startsWith("hyperlink:")) {
|
|
2245
|
-
return {
|
|
2246
|
-
element: "a",
|
|
2247
|
-
attrs: { href: safeHref(style.slice("hyperlink:".length)) }
|
|
2248
|
-
};
|
|
2249
|
-
}
|
|
2250
|
-
}
|
|
2251
|
-
for (const style of styles) {
|
|
2252
|
-
const element = this.styleToElement[style];
|
|
2253
|
-
if (element) {
|
|
2254
|
-
return {
|
|
2255
|
-
element,
|
|
2256
|
-
attrs: {}
|
|
2257
|
-
};
|
|
2258
|
-
}
|
|
2259
|
-
}
|
|
2260
|
-
return { element: "span", attrs: {} };
|
|
2161
|
+
function serializeOpeningTag(tagName, attrs) {
|
|
2162
|
+
const tag = tagName.toLowerCase();
|
|
2163
|
+
let result = `<${tag}`;
|
|
2164
|
+
for (const [name, value] of Object.entries(attrs)) {
|
|
2165
|
+
result += ` ${name.toLowerCase()}="${escapeAttrValue(value)}"`;
|
|
2166
|
+
}
|
|
2167
|
+
result += ">";
|
|
2168
|
+
return result;
|
|
2169
|
+
}
|
|
2170
|
+
function extractTagName(rawOpenTag) {
|
|
2171
|
+
const end = rawOpenTag.search(/[\s>]/);
|
|
2172
|
+
return rawOpenTag.slice(1, end === -1 ? rawOpenTag.length : end).toLowerCase();
|
|
2173
|
+
}
|
|
2174
|
+
function readRawStyle(styles) {
|
|
2175
|
+
for (const s of styles) {
|
|
2176
|
+
if (s.startsWith("raw:")) return s.slice(4);
|
|
2261
2177
|
}
|
|
2262
|
-
|
|
2178
|
+
return null;
|
|
2179
|
+
}
|
|
2263
2180
|
|
|
2264
2181
|
// src/content/parser/MarkupParser.ts
|
|
2265
2182
|
var MarkupParser = class {
|
|
2266
|
-
constructor(options = {}) {
|
|
2267
|
-
__publicField(this, "styleMapper");
|
|
2268
|
-
this.styleMapper = options.styleMapper ?? new DefaultStyleMapper();
|
|
2269
|
-
}
|
|
2270
|
-
/**
|
|
2271
|
-
* Parse HTML string into ContentUnit
|
|
2272
|
-
*
|
|
2273
|
-
* Handles two input formats:
|
|
2274
|
-
* 1. HTML tags: `<b>text</b>` → converts to indexed `<1>text</1>` with styles
|
|
2275
|
-
* 2. Already indexed: `<1>text</1>` → passes through as-is (from server)
|
|
2276
|
-
*
|
|
2277
|
-
* @param input - HTML string with inline elements or already indexed
|
|
2278
|
-
* @returns ContentUnit with indexed tags and styles
|
|
2279
|
-
*/
|
|
2280
2183
|
parse(input) {
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
return {
|
|
2284
|
-
text: input,
|
|
2285
|
-
styles: {}
|
|
2286
|
-
// Empty - styles determined by children
|
|
2287
|
-
};
|
|
2184
|
+
if (/<\/?[0-9]+>/.test(input)) {
|
|
2185
|
+
return { text: input, styles: {} };
|
|
2288
2186
|
}
|
|
2289
2187
|
const styles = {};
|
|
2290
2188
|
let tagIndex = 0;
|
|
@@ -2292,88 +2190,45 @@ var LionRapid = (() => {
|
|
|
2292
2190
|
let result = "";
|
|
2293
2191
|
let pos = 0;
|
|
2294
2192
|
while (pos < input.length) {
|
|
2295
|
-
const
|
|
2296
|
-
if (!
|
|
2193
|
+
const tag = this.matchTag(input, pos);
|
|
2194
|
+
if (!tag) {
|
|
2297
2195
|
result += input.slice(pos);
|
|
2298
2196
|
break;
|
|
2299
2197
|
}
|
|
2300
|
-
result += input.slice(pos,
|
|
2301
|
-
if (
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
const stackIndex = tagStack.findIndex(
|
|
2309
|
-
(t) => t.index === matchingOpen
|
|
2310
|
-
);
|
|
2311
|
-
if (stackIndex !== -1) {
|
|
2312
|
-
tagStack.splice(stackIndex, 1);
|
|
2198
|
+
result += input.slice(pos, tag.startIndex);
|
|
2199
|
+
if (tag.isClosing) {
|
|
2200
|
+
let matchIdx = null;
|
|
2201
|
+
for (let i = tagStack.length - 1; i >= 0; i--) {
|
|
2202
|
+
if (tagStack[i].tag === tag.tag.toLowerCase()) {
|
|
2203
|
+
matchIdx = tagStack[i].index;
|
|
2204
|
+
tagStack.splice(i, 1);
|
|
2205
|
+
break;
|
|
2313
2206
|
}
|
|
2314
|
-
} else {
|
|
2315
|
-
result += input.slice(tagMatch.startIndex, tagMatch.endIndex);
|
|
2316
2207
|
}
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
const styleList = this.styleMapper.mapElementToStyles(
|
|
2320
|
-
tagMatch.tag,
|
|
2321
|
-
tagMatch.attrs
|
|
2322
|
-
);
|
|
2323
|
-
if (styleList.length > 0) {
|
|
2324
|
-
styles[String(tagIndex)] = styleList;
|
|
2325
|
-
result += `<${tagIndex}/>`;
|
|
2208
|
+
if (matchIdx !== null) {
|
|
2209
|
+
result += `</${matchIdx}>`;
|
|
2326
2210
|
}
|
|
2327
2211
|
} else {
|
|
2328
|
-
const
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
result += `<${tagIndex}>`;
|
|
2336
|
-
tagStack.push({ tag: tagMatch.tag.toLowerCase(), index: tagIndex });
|
|
2212
|
+
const tagName = tag.tag.toLowerCase();
|
|
2213
|
+
const isVoid = VOID_TAGS.has(tagName);
|
|
2214
|
+
const isSelfClosing = tag.isSelfClosing || isVoid;
|
|
2215
|
+
tagIndex++;
|
|
2216
|
+
styles[String(tagIndex)] = [`raw:${serializeOpeningTag(tagName, tag.attrs)}`];
|
|
2217
|
+
if (isSelfClosing) {
|
|
2218
|
+
result += `<${tagIndex}/>`;
|
|
2337
2219
|
} else {
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
tagMatch.endIndex,
|
|
2341
|
-
tagMatch.tag
|
|
2342
|
-
);
|
|
2343
|
-
if (closingIndex !== -1) {
|
|
2344
|
-
const innerContent = input.slice(tagMatch.endIndex, closingIndex);
|
|
2345
|
-
const innerUnit = this.parse(innerContent);
|
|
2346
|
-
const baseIndex = tagIndex;
|
|
2347
|
-
for (const [key, value] of Object.entries(innerUnit.styles)) {
|
|
2348
|
-
const adjustedKey = String(baseIndex + parseInt(key, 10));
|
|
2349
|
-
styles[adjustedKey] = value;
|
|
2350
|
-
}
|
|
2351
|
-
result += innerUnit.text.replace(/<(\/?)\d+>/g, (match, slash) => {
|
|
2352
|
-
const num = parseInt(match.replace(/[</>]/g, ""), 10);
|
|
2353
|
-
return `<${slash}${baseIndex + num}>`;
|
|
2354
|
-
});
|
|
2355
|
-
const closingMatch = this.matchTag(input, closingIndex);
|
|
2356
|
-
pos = closingMatch ? closingMatch.endIndex : closingIndex;
|
|
2357
|
-
const maxInnerIndex = Object.keys(innerUnit.styles).length > 0 ? Math.max(...Object.keys(innerUnit.styles).map(Number)) : 0;
|
|
2358
|
-
tagIndex = baseIndex + maxInnerIndex;
|
|
2359
|
-
continue;
|
|
2360
|
-
}
|
|
2220
|
+
result += `<${tagIndex}>`;
|
|
2221
|
+
tagStack.push({ tag: tagName, index: tagIndex });
|
|
2361
2222
|
}
|
|
2362
2223
|
}
|
|
2363
|
-
pos =
|
|
2224
|
+
pos = tag.endIndex;
|
|
2364
2225
|
}
|
|
2365
2226
|
while (tagStack.length > 0) {
|
|
2366
2227
|
const unclosed = tagStack.pop();
|
|
2367
2228
|
result += `</${unclosed.index}>`;
|
|
2368
2229
|
}
|
|
2369
|
-
return {
|
|
2370
|
-
text: result,
|
|
2371
|
-
styles
|
|
2372
|
-
};
|
|
2230
|
+
return { text: result, styles };
|
|
2373
2231
|
}
|
|
2374
|
-
/**
|
|
2375
|
-
* Match an HTML tag at the given position
|
|
2376
|
-
*/
|
|
2377
2232
|
matchTag(input, startPos) {
|
|
2378
2233
|
const tagStart = input.indexOf("<", startPos);
|
|
2379
2234
|
if (tagStart === -1) return null;
|
|
@@ -2396,9 +2251,6 @@ var LionRapid = (() => {
|
|
|
2396
2251
|
endIndex: tagStart + fullMatch.length
|
|
2397
2252
|
};
|
|
2398
2253
|
}
|
|
2399
|
-
/**
|
|
2400
|
-
* Parse HTML attributes string into key-value pairs
|
|
2401
|
-
*/
|
|
2402
2254
|
parseAttributes(attrsString) {
|
|
2403
2255
|
const attrs = {};
|
|
2404
2256
|
if (!attrsString.trim()) return attrs;
|
|
@@ -2406,60 +2258,14 @@ var LionRapid = (() => {
|
|
|
2406
2258
|
let match;
|
|
2407
2259
|
while ((match = attrPattern.exec(attrsString)) !== null) {
|
|
2408
2260
|
const [, name, doubleQuoted, singleQuoted, unquoted] = match;
|
|
2409
|
-
|
|
2410
|
-
attrs[name.toLowerCase()] = value;
|
|
2261
|
+
attrs[name.toLowerCase()] = doubleQuoted ?? singleQuoted ?? unquoted ?? "";
|
|
2411
2262
|
}
|
|
2412
2263
|
return attrs;
|
|
2413
2264
|
}
|
|
2414
|
-
/**
|
|
2415
|
-
* Find matching opening tag in the stack
|
|
2416
|
-
*/
|
|
2417
|
-
findMatchingOpenTag(stack, tagName) {
|
|
2418
|
-
for (let i = stack.length - 1; i >= 0; i--) {
|
|
2419
|
-
if (stack[i].tag === tagName) {
|
|
2420
|
-
return stack[i].index;
|
|
2421
|
-
}
|
|
2422
|
-
}
|
|
2423
|
-
return null;
|
|
2424
|
-
}
|
|
2425
|
-
/**
|
|
2426
|
-
* Find the closing tag index for a given opening tag
|
|
2427
|
-
*/
|
|
2428
|
-
findClosingTagIndex(input, startPos, tagName) {
|
|
2429
|
-
const lowerTag = tagName.toLowerCase();
|
|
2430
|
-
let depth = 1;
|
|
2431
|
-
let pos = startPos;
|
|
2432
|
-
while (pos < input.length && depth > 0) {
|
|
2433
|
-
const tagMatch = this.matchTag(input, pos);
|
|
2434
|
-
if (!tagMatch) break;
|
|
2435
|
-
if (tagMatch.tag.toLowerCase() === lowerTag) {
|
|
2436
|
-
if (tagMatch.isClosing) {
|
|
2437
|
-
depth--;
|
|
2438
|
-
if (depth === 0) {
|
|
2439
|
-
return tagMatch.startIndex;
|
|
2440
|
-
}
|
|
2441
|
-
} else if (!tagMatch.isSelfClosing) {
|
|
2442
|
-
depth++;
|
|
2443
|
-
}
|
|
2444
|
-
}
|
|
2445
|
-
pos = tagMatch.endIndex;
|
|
2446
|
-
}
|
|
2447
|
-
return -1;
|
|
2448
|
-
}
|
|
2449
2265
|
};
|
|
2450
2266
|
|
|
2451
2267
|
// src/content/serializer/HTMLSerializer.ts
|
|
2452
2268
|
var HTMLSerializer = class {
|
|
2453
|
-
constructor(options = {}) {
|
|
2454
|
-
__publicField(this, "styleMapper");
|
|
2455
|
-
this.styleMapper = options.styleMapper ?? new DefaultStyleMapper();
|
|
2456
|
-
}
|
|
2457
|
-
/**
|
|
2458
|
-
* Serialize ContentUnit to HTML string
|
|
2459
|
-
*
|
|
2460
|
-
* @param unit - ContentUnit with indexed tags and styles
|
|
2461
|
-
* @returns HTML string with semantic elements
|
|
2462
|
-
*/
|
|
2463
2269
|
serialize(unit) {
|
|
2464
2270
|
const { text, styles } = unit;
|
|
2465
2271
|
const tagPattern = /<(\/?)?(\d+)(\/)?>/g;
|
|
@@ -2468,40 +2274,25 @@ var LionRapid = (() => {
|
|
|
2468
2274
|
let match;
|
|
2469
2275
|
while ((match = tagPattern.exec(text)) !== null) {
|
|
2470
2276
|
result += text.slice(lastIndex, match.index);
|
|
2471
|
-
const [fullMatch, closingSlash, indexStr
|
|
2472
|
-
const
|
|
2473
|
-
const
|
|
2474
|
-
if (
|
|
2475
|
-
const
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2277
|
+
const [fullMatch, closingSlash, indexStr] = match;
|
|
2278
|
+
const styleList = styles[indexStr] ?? [];
|
|
2279
|
+
const rawOpen = readRawStyle(styleList);
|
|
2280
|
+
if (rawOpen) {
|
|
2281
|
+
const tagName = extractTagName(rawOpen);
|
|
2282
|
+
const isVoid = VOID_TAGS.has(tagName);
|
|
2283
|
+
if (closingSlash) {
|
|
2284
|
+
if (!isVoid) result += `</${tagName}>`;
|
|
2285
|
+
} else {
|
|
2286
|
+
result += rawOpen;
|
|
2287
|
+
}
|
|
2481
2288
|
} else {
|
|
2482
|
-
|
|
2483
|
-
const attrs = this.formatAttributes(mapping.attrs);
|
|
2484
|
-
result += `<${mapping.element}${attrs}>`;
|
|
2289
|
+
result += fullMatch;
|
|
2485
2290
|
}
|
|
2486
2291
|
lastIndex = match.index + fullMatch.length;
|
|
2487
2292
|
}
|
|
2488
2293
|
result += text.slice(lastIndex);
|
|
2489
2294
|
return result;
|
|
2490
2295
|
}
|
|
2491
|
-
/**
|
|
2492
|
-
* Format attributes object into HTML attribute string
|
|
2493
|
-
*/
|
|
2494
|
-
formatAttributes(attrs) {
|
|
2495
|
-
const entries = Object.entries(attrs);
|
|
2496
|
-
if (entries.length === 0) return "";
|
|
2497
|
-
return " " + entries.map(([key, value]) => `${key}="${this.escapeAttributeValue(value)}"`).join(" ");
|
|
2498
|
-
}
|
|
2499
|
-
/**
|
|
2500
|
-
* Escape special characters in attribute values
|
|
2501
|
-
*/
|
|
2502
|
-
escapeAttributeValue(value) {
|
|
2503
|
-
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
2504
|
-
}
|
|
2505
2296
|
};
|
|
2506
2297
|
|
|
2507
2298
|
// src/cache/CacheManager.ts
|
|
@@ -2735,7 +2526,7 @@ var LionRapid = (() => {
|
|
|
2735
2526
|
};
|
|
2736
2527
|
|
|
2737
2528
|
// src/lionRapid.ts
|
|
2738
|
-
var INDEXED_TAG_REGEX = /<\/?[0-9]
|
|
2529
|
+
var INDEXED_TAG_REGEX = /<\/?[0-9]+\/?>/;
|
|
2739
2530
|
var HTML_TAG_REGEX = /<[a-z][a-z0-9]*(?:\s+[^>]*)?\/?>/i;
|
|
2740
2531
|
var LionRapidCore = class {
|
|
2741
2532
|
constructor(eventEmitter, handlerChain, defaultLocale = "en", fallbackLocale = "en", defaultNamespace) {
|
|
@@ -2960,7 +2751,7 @@ var LionRapid = (() => {
|
|
|
2960
2751
|
*/
|
|
2961
2752
|
processIndexedValue(value, request) {
|
|
2962
2753
|
const processedText = this.processTranslationValue(value, request);
|
|
2963
|
-
return processedText.replace(/<\/?[0-9]
|
|
2754
|
+
return processedText.replace(/<\/?[0-9]+\/?>/g, "");
|
|
2964
2755
|
}
|
|
2965
2756
|
/**
|
|
2966
2757
|
* 📦 Get styles for a translation key from namespace cache (fallback)
|
|
@@ -3006,7 +2797,7 @@ var LionRapid = (() => {
|
|
|
3006
2797
|
try {
|
|
3007
2798
|
const unit = this.markupParser.parse(value);
|
|
3008
2799
|
const processedText = this.processTranslationValue(unit.text, request);
|
|
3009
|
-
return processedText.replace(/<\/?[0-9]
|
|
2800
|
+
return processedText.replace(/<\/?[0-9]+\/?>/g, "");
|
|
3010
2801
|
} catch (error) {
|
|
3011
2802
|
logger.warn(`ContentUnit processing failed for "${value}":`, error);
|
|
3012
2803
|
return this.processTranslationValue(value, request);
|
|
@@ -3075,7 +2866,7 @@ var LionRapid = (() => {
|
|
|
3075
2866
|
* @example
|
|
3076
2867
|
* ```typescript
|
|
3077
2868
|
* const unit = i18n.getContentUnit('terms', {}, 'Read our <b>Terms</b>.');
|
|
3078
|
-
* // → { text: "Read our <1>Terms</1>.", styles: {"1": ["
|
|
2869
|
+
* // → { text: "Read our <1>Terms</1>.", styles: {"1": ["raw:<b>"]} }
|
|
3079
2870
|
* ```
|
|
3080
2871
|
*/
|
|
3081
2872
|
getContentUnit(key, params, defaultValue) {
|
|
@@ -3684,7 +3475,7 @@ var LionRapid = (() => {
|
|
|
3684
3475
|
logger.debug("API base URL is not set");
|
|
3685
3476
|
throw new NetworkError("API base URL is not set");
|
|
3686
3477
|
}
|
|
3687
|
-
const url = this.buildUrl("getTranslation", { key });
|
|
3478
|
+
const url = this.withDraftsParam(this.buildUrl("getTranslation", { key }));
|
|
3688
3479
|
logger.debug(`API GET: ${url}`);
|
|
3689
3480
|
try {
|
|
3690
3481
|
const response = await this.makeRequest(url, "GET");
|
|
@@ -3720,7 +3511,7 @@ var LionRapid = (() => {
|
|
|
3720
3511
|
logger.debug("API base URL is not set");
|
|
3721
3512
|
throw new NetworkError("API base URL is not set");
|
|
3722
3513
|
}
|
|
3723
|
-
const url = this.buildUrl("getTranslation", { key });
|
|
3514
|
+
const url = this.withDraftsParam(this.buildUrl("getTranslation", { key }));
|
|
3724
3515
|
logger.debug(`API GET ContentUnit: ${url}`);
|
|
3725
3516
|
try {
|
|
3726
3517
|
const response = await this.makeRequest(url, "GET");
|
|
@@ -3761,7 +3552,7 @@ var LionRapid = (() => {
|
|
|
3761
3552
|
logger.debug("API base URL is not set");
|
|
3762
3553
|
throw new NetworkError("API base URL is not set");
|
|
3763
3554
|
}
|
|
3764
|
-
const url = this.buildUrl("getNamespace", { locale, namespace });
|
|
3555
|
+
const url = this.withDraftsParam(this.buildUrl("getNamespace", { locale, namespace }));
|
|
3765
3556
|
logger.debug(`API GET Namespace: ${url}`);
|
|
3766
3557
|
const namespaceKey = `${locale}:${namespace}`;
|
|
3767
3558
|
try {
|
|
@@ -3875,7 +3666,7 @@ var LionRapid = (() => {
|
|
|
3875
3666
|
logger.debug("API base URL is not set");
|
|
3876
3667
|
throw new NetworkError("API base URL is not set");
|
|
3877
3668
|
}
|
|
3878
|
-
const url = this.buildUrl("getNamespace", { locale, namespace });
|
|
3669
|
+
const url = this.withDraftsParam(this.buildUrl("getNamespace", { locale, namespace }));
|
|
3879
3670
|
logger.debug(`API GET Namespace ContentUnits: ${url}`);
|
|
3880
3671
|
const namespaceKey = `${locale}:${namespace}`;
|
|
3881
3672
|
try {
|
|
@@ -4087,6 +3878,26 @@ var LionRapid = (() => {
|
|
|
4087
3878
|
}
|
|
4088
3879
|
return `${baseUrl}${path}`;
|
|
4089
3880
|
}
|
|
3881
|
+
/**
|
|
3882
|
+
* Check whether the current page is running inside an active visual-editor
|
|
3883
|
+
* session. The editor JS sets `__lr_editor_active=1` as a session cookie
|
|
3884
|
+
* when its JWT is established; we read it here so client-side translation
|
|
3885
|
+
* fetches request draft content too, matching what the edge proxy does
|
|
3886
|
+
* server-side. Outside a browser (Node/SSR) this is always false.
|
|
3887
|
+
*/
|
|
3888
|
+
isEditorPreviewSession() {
|
|
3889
|
+
if (typeof document === "undefined") return false;
|
|
3890
|
+
return document.cookie.split("; ").some((c) => c === "__lr_editor_active=1");
|
|
3891
|
+
}
|
|
3892
|
+
/**
|
|
3893
|
+
* Append `include_drafts=true` to a built URL when an editor session is
|
|
3894
|
+
* active. Leaves the URL unchanged for normal visitors so the delivery
|
|
3895
|
+
* gate continues to apply in production.
|
|
3896
|
+
*/
|
|
3897
|
+
withDraftsParam(url) {
|
|
3898
|
+
if (!this.isEditorPreviewSession()) return url;
|
|
3899
|
+
return url + (url.includes("?") ? "&" : "?") + "include_drafts=true";
|
|
3900
|
+
}
|
|
4090
3901
|
/**
|
|
4091
3902
|
* Make HTTP request with timeout and headers
|
|
4092
3903
|
*/
|
|
@@ -4262,7 +4073,6 @@ var LionRapid = (() => {
|
|
|
4262
4073
|
};
|
|
4263
4074
|
|
|
4264
4075
|
// src/browser/markup-parser.ts
|
|
4265
|
-
var styleMapper = new DefaultStyleMapper();
|
|
4266
4076
|
function parseBlockElement(element) {
|
|
4267
4077
|
const styles = {};
|
|
4268
4078
|
let tagIndex = 0;
|
|
@@ -4280,22 +4090,17 @@ var LionRapid = (() => {
|
|
|
4280
4090
|
const attr = el.attributes[i];
|
|
4281
4091
|
attrs[attr.name.toLowerCase()] = attr.value;
|
|
4282
4092
|
}
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
let inner = "";
|
|
4289
|
-
for (let i = 0; i < node.childNodes.length; i++) {
|
|
4290
|
-
inner += walk(node.childNodes[i]);
|
|
4291
|
-
}
|
|
4292
|
-
return `<${idx}>${inner}</${idx}>`;
|
|
4093
|
+
tagIndex++;
|
|
4094
|
+
const idx = tagIndex;
|
|
4095
|
+
styles[String(idx)] = [`raw:${serializeOpeningTag(tag, attrs)}`];
|
|
4096
|
+
if (VOID_TAGS.has(tag)) {
|
|
4097
|
+
return `<${idx}/>`;
|
|
4293
4098
|
}
|
|
4294
|
-
let
|
|
4099
|
+
let inner = "";
|
|
4295
4100
|
for (let i = 0; i < node.childNodes.length; i++) {
|
|
4296
|
-
|
|
4101
|
+
inner += walk(node.childNodes[i]);
|
|
4297
4102
|
}
|
|
4298
|
-
return
|
|
4103
|
+
return `<${idx}>${inner}</${idx}>`;
|
|
4299
4104
|
}
|
|
4300
4105
|
let text = "";
|
|
4301
4106
|
for (let i = 0; i < element.childNodes.length; i++) {
|
|
@@ -4450,8 +4255,14 @@ var LionRapid = (() => {
|
|
|
4450
4255
|
// Server already translated
|
|
4451
4256
|
"data-lionrapid-client",
|
|
4452
4257
|
// Client already translated
|
|
4453
|
-
"data-no-translate"
|
|
4258
|
+
"data-no-translate",
|
|
4454
4259
|
// Explicitly marked to skip
|
|
4260
|
+
// Edge proxy already rendered this block with the correct translation
|
|
4261
|
+
// and styles. Skip in normal extraction so the client-side auto-translator
|
|
4262
|
+
// can't overwrite the styled DOM with a stale (or plain-text) cache entry.
|
|
4263
|
+
// The editor passes includeTranslated=true to bypass this and re-extract
|
|
4264
|
+
// edge-rendered blocks for inspection.
|
|
4265
|
+
"data-lr-block"
|
|
4455
4266
|
];
|
|
4456
4267
|
var BlockExtractor = class {
|
|
4457
4268
|
constructor(excludePatterns = {}, excludeSelectors = [], minTextLength = 2) {
|
|
@@ -4792,11 +4603,14 @@ var LionRapid = (() => {
|
|
|
4792
4603
|
if (!element.hasAttribute("data-lr-original")) {
|
|
4793
4604
|
element.setAttribute("data-lr-original", element.innerHTML);
|
|
4794
4605
|
}
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4606
|
+
const cacheHasStyles = cached.styles && Object.keys(cached.styles).length > 0;
|
|
4607
|
+
const sourceHasStyles = Object.keys(unit.styles).length > 0;
|
|
4608
|
+
const hasIndexedMarkers = /<\/?[0-9]+\/?>/.test(cached.value);
|
|
4609
|
+
if (sourceHasStyles && !hasIndexedMarkers) {
|
|
4798
4610
|
} else {
|
|
4799
|
-
|
|
4611
|
+
const styles = cacheHasStyles ? cached.styles : unit.styles;
|
|
4612
|
+
const translatedUnit = { text: cached.value, styles };
|
|
4613
|
+
element.innerHTML = htmlSerializer.serialize(translatedUnit);
|
|
4800
4614
|
}
|
|
4801
4615
|
element.setAttribute("data-lr-block", key);
|
|
4802
4616
|
element.setAttribute("data-lionrapid-client", "1");
|