mnfst 0.5.132 → 0.5.134
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/lib/manifest.css +26 -17
- package/lib/manifest.data.js +10 -2
- package/lib/manifest.dropdown.css +12 -11
- package/lib/manifest.dropdowns.js +70 -40
- package/lib/manifest.form.css +17 -9
- package/lib/manifest.integrity.json +6 -6
- package/lib/manifest.localization.js +103 -55
- package/lib/manifest.markdown.js +12 -2
- package/lib/manifest.min.css +1 -1
- package/lib/manifest.sidebar.css +4 -4
- package/lib/manifest.svg.js +5 -1
- package/lib/manifest.toast.css +1 -1
- package/lib/manifest.tooltip.css +4 -4
- package/lib/manifest.tooltips.js +16 -4
- package/package.json +3 -2
|
@@ -11,6 +11,102 @@ const originalHtmlLang = (typeof document !== 'undefined' && document.documentEl
|
|
|
11
11
|
? (document.documentElement.lang || '')
|
|
12
12
|
: '';
|
|
13
13
|
|
|
14
|
+
// RTL language codes — module scope so both the init plugin (sets <html dir>)
|
|
15
|
+
// and the $locale magic (sets $locale.list direction) share one table.
|
|
16
|
+
const rtlLanguages = new Set([
|
|
17
|
+
// Arabic script
|
|
18
|
+
'ar', // Arabic
|
|
19
|
+
'az-Arab',// Azerbaijani (Arabic script)
|
|
20
|
+
'bal', // Balochi
|
|
21
|
+
'ckb', // Central Kurdish (Sorani)
|
|
22
|
+
'fa', // Persian (Farsi)
|
|
23
|
+
'glk', // Gilaki
|
|
24
|
+
'ks', // Kashmiri
|
|
25
|
+
'ku-Arab',// Kurdish (Arabic script)
|
|
26
|
+
'lrc', // Northern Luri
|
|
27
|
+
'mzn', // Mazanderani
|
|
28
|
+
'pnb', // Western Punjabi (Shahmukhi)
|
|
29
|
+
'ps', // Pashto
|
|
30
|
+
'sd', // Sindhi
|
|
31
|
+
'ur', // Urdu
|
|
32
|
+
|
|
33
|
+
// Hebrew script
|
|
34
|
+
'he', // Hebrew
|
|
35
|
+
'yi', // Yiddish
|
|
36
|
+
'jrb', // Judeo-Arabic
|
|
37
|
+
'jpr', // Judeo-Persian
|
|
38
|
+
'lad-Hebr',// Ladino (Hebrew script)
|
|
39
|
+
|
|
40
|
+
// Thaana script
|
|
41
|
+
'dv', // Dhivehi (Maldivian)
|
|
42
|
+
|
|
43
|
+
// N’Ko script
|
|
44
|
+
'nqo', // N’Ko (West Africa)
|
|
45
|
+
|
|
46
|
+
// Syriac script
|
|
47
|
+
'syr', // Syriac
|
|
48
|
+
'aii', // Assyrian Neo-Aramaic
|
|
49
|
+
'arc', // Aramaic
|
|
50
|
+
'sam', // Samaritan Aramaic
|
|
51
|
+
|
|
52
|
+
// Mandaic script
|
|
53
|
+
'mid', // Mandaic
|
|
54
|
+
|
|
55
|
+
// Other RTL minority/obscure scripts
|
|
56
|
+
'uga', // Ugaritic
|
|
57
|
+
'phn', // Phoenician
|
|
58
|
+
'xpr', // Parthian (ancient)
|
|
59
|
+
'peo', // Old Persian (cuneiform, but RTL)
|
|
60
|
+
'pal', // Middle Persian (Pahlavi)
|
|
61
|
+
'avst', // Avestan
|
|
62
|
+
'man', // Manding (N'Ko variants)
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
// Detect if a language is RTL
|
|
66
|
+
function isRTL(lang) {
|
|
67
|
+
return rtlLanguages.has(lang);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Native language name (endonym) for a BCP-47 code, e.g. 'fr' → "français".
|
|
71
|
+
// Derived from the browser's Intl.DisplayNames — no data files, no fetches.
|
|
72
|
+
// Falls back to the raw code for custom/unsupported codes.
|
|
73
|
+
const localeNameCache = new Map();
|
|
74
|
+
function localeName(code) {
|
|
75
|
+
if (localeNameCache.has(code)) return localeNameCache.get(code);
|
|
76
|
+
let name = code;
|
|
77
|
+
try {
|
|
78
|
+
if (typeof Intl !== 'undefined' && typeof Intl.DisplayNames === 'function') {
|
|
79
|
+
name = new Intl.DisplayNames([code], { type: 'language' }).of(code) || code;
|
|
80
|
+
}
|
|
81
|
+
} catch { /* unsupported code — keep raw code */ }
|
|
82
|
+
localeNameCache.set(code, name);
|
|
83
|
+
return name;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Rich list backing $locale.list: one object per available locale, with
|
|
87
|
+
// ordering views hung off the array as non-enumerable getters so x-for and
|
|
88
|
+
// spreads only ever see the locale items, never the view accessors.
|
|
89
|
+
// $locale.list → source (manifest.json) order
|
|
90
|
+
// $locale.list.alphabetical → by native name, locale-aware compare
|
|
91
|
+
// $locale.list.currentFirst → active locale first, rest in source order
|
|
92
|
+
function buildLocaleList(available, current) {
|
|
93
|
+
const list = available.map(code => ({
|
|
94
|
+
code,
|
|
95
|
+
name: localeName(code),
|
|
96
|
+
direction: isRTL(code) ? 'rtl' : 'ltr',
|
|
97
|
+
current: code === current
|
|
98
|
+
}));
|
|
99
|
+
Object.defineProperty(list, 'alphabetical', {
|
|
100
|
+
enumerable: false,
|
|
101
|
+
get() { return [...list].sort((a, b) => a.name.localeCompare(b.name)); }
|
|
102
|
+
});
|
|
103
|
+
Object.defineProperty(list, 'currentFirst', {
|
|
104
|
+
enumerable: false,
|
|
105
|
+
get() { return [...list].sort((a, b) => (b.current === true) - (a.current === true)); }
|
|
106
|
+
});
|
|
107
|
+
return list;
|
|
108
|
+
}
|
|
109
|
+
|
|
14
110
|
// Global setLocale wrapper - will be replaced with real implementation
|
|
15
111
|
let setLocaleImpl = null;
|
|
16
112
|
|
|
@@ -45,61 +141,6 @@ function initializeLocalizationPlugin() {
|
|
|
45
141
|
// Debug logging disabled for production
|
|
46
142
|
const debugLog = () => { };
|
|
47
143
|
|
|
48
|
-
// RTL language codes - using Set for O(1) lookups
|
|
49
|
-
const rtlLanguages = new Set([
|
|
50
|
-
// Arabic script
|
|
51
|
-
'ar', // Arabic
|
|
52
|
-
'az-Arab',// Azerbaijani (Arabic script)
|
|
53
|
-
'bal', // Balochi
|
|
54
|
-
'ckb', // Central Kurdish (Sorani)
|
|
55
|
-
'fa', // Persian (Farsi)
|
|
56
|
-
'glk', // Gilaki
|
|
57
|
-
'ks', // Kashmiri
|
|
58
|
-
'ku-Arab',// Kurdish (Arabic script)
|
|
59
|
-
'lrc', // Northern Luri
|
|
60
|
-
'mzn', // Mazanderani
|
|
61
|
-
'pnb', // Western Punjabi (Shahmukhi)
|
|
62
|
-
'ps', // Pashto
|
|
63
|
-
'sd', // Sindhi
|
|
64
|
-
'ur', // Urdu
|
|
65
|
-
|
|
66
|
-
// Hebrew script
|
|
67
|
-
'he', // Hebrew
|
|
68
|
-
'yi', // Yiddish
|
|
69
|
-
'jrb', // Judeo-Arabic
|
|
70
|
-
'jpr', // Judeo-Persian
|
|
71
|
-
'lad-Hebr',// Ladino (Hebrew script)
|
|
72
|
-
|
|
73
|
-
// Thaana script
|
|
74
|
-
'dv', // Dhivehi (Maldivian)
|
|
75
|
-
|
|
76
|
-
// N’Ko script
|
|
77
|
-
'nqo', // N’Ko (West Africa)
|
|
78
|
-
|
|
79
|
-
// Syriac script
|
|
80
|
-
'syr', // Syriac
|
|
81
|
-
'aii', // Assyrian Neo-Aramaic
|
|
82
|
-
'arc', // Aramaic
|
|
83
|
-
'sam', // Samaritan Aramaic
|
|
84
|
-
|
|
85
|
-
// Mandaic script
|
|
86
|
-
'mid', // Mandaic
|
|
87
|
-
|
|
88
|
-
// Other RTL minority/obscure scripts
|
|
89
|
-
'uga', // Ugaritic
|
|
90
|
-
'phn', // Phoenician
|
|
91
|
-
'xpr', // Parthian (ancient)
|
|
92
|
-
'peo', // Old Persian (cuneiform, but RTL)
|
|
93
|
-
'pal', // Middle Persian (Pahlavi)
|
|
94
|
-
'avst', // Avestan
|
|
95
|
-
'man', // Manding (N'Ko variants)
|
|
96
|
-
]);
|
|
97
|
-
|
|
98
|
-
// Detect if a language is RTL
|
|
99
|
-
function isRTL(lang) {
|
|
100
|
-
return rtlLanguages.has(lang);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
144
|
function isPrerenderedStaticBuild() {
|
|
104
145
|
return document.head?.querySelector('meta[name="manifest:prerendered"][content="1"]') !== null;
|
|
105
146
|
}
|
|
@@ -712,6 +753,13 @@ function registerLocaleMagic() {
|
|
|
712
753
|
if (prop === 'current') return currentStore?.current || document.documentElement.lang || 'en';
|
|
713
754
|
if (prop === 'available') return currentStore?.available || [document.documentElement.lang || 'en'];
|
|
714
755
|
if (prop === 'direction') return currentStore?.direction || 'ltr';
|
|
756
|
+
if (prop === 'list') {
|
|
757
|
+
const fallback = document.documentElement.lang || 'en';
|
|
758
|
+
return buildLocaleList(
|
|
759
|
+
currentStore?.available || [fallback],
|
|
760
|
+
currentStore?.current || fallback
|
|
761
|
+
);
|
|
762
|
+
}
|
|
715
763
|
if (prop === 'set') {
|
|
716
764
|
// Use the global setLocale function (wrapper or real implementation)
|
|
717
765
|
return async (locale, updateUrl = false) => {
|
package/lib/manifest.markdown.js
CHANGED
|
@@ -43,7 +43,13 @@ if (!window.ManifestDOMPurify) {
|
|
|
43
43
|
if (this._promise) return this._promise;
|
|
44
44
|
this._promise = new Promise((resolve, reject) => {
|
|
45
45
|
const script = document.createElement('script');
|
|
46
|
-
|
|
46
|
+
// Pinned + Subresource Integrity: a moving `@latest` (or a
|
|
47
|
+
// tampered CDN file) would otherwise run arbitrary JS in the
|
|
48
|
+
// user's page. The browser rejects the script if the bytes don't
|
|
49
|
+
// match the hash. Bump version AND integrity together.
|
|
50
|
+
script.src = 'https://cdn.jsdelivr.net/npm/dompurify@3.4.10/dist/purify.min.js';
|
|
51
|
+
script.integrity = 'sha384-eguRoJERj8ghOpzO//Rl7+ScQsQIR1cH+ajll7+fG+IpbNPlkZsQn9h8ccr+wPXx';
|
|
52
|
+
script.crossOrigin = 'anonymous';
|
|
47
53
|
script.onload = () => {
|
|
48
54
|
if (typeof window.DOMPurify !== 'undefined') {
|
|
49
55
|
resolve(window.DOMPurify);
|
|
@@ -96,7 +102,11 @@ async function loadMarkedJS() {
|
|
|
96
102
|
|
|
97
103
|
markedPromise = new Promise((resolve, reject) => {
|
|
98
104
|
const script = document.createElement('script');
|
|
99
|
-
|
|
105
|
+
// Pinned + Subresource Integrity (see DOMPurify loader above) — a
|
|
106
|
+
// floating version or tampered CDN file can't inject arbitrary JS.
|
|
107
|
+
script.src = 'https://cdn.jsdelivr.net/npm/marked@15.0.12/marked.min.js';
|
|
108
|
+
script.integrity = 'sha384-948ahk4ZmxYVYOc+rxN1H2gM1EJ2Duhp7uHtZ4WSLkV4Vtx5MUqnV+l7u9B+jFv+';
|
|
109
|
+
script.crossOrigin = 'anonymous';
|
|
100
110
|
script.onload = () => {
|
|
101
111
|
// Initialize marked.js
|
|
102
112
|
if (typeof marked !== 'undefined') {
|