@brightspace-ui/core 3.31.1 → 3.33.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/components/typography/styles.js +62 -0
- package/components/typography/typography.js +2 -60
- package/custom-elements.json +0 -252
- package/helpers/mathjax.js +1 -26
- package/mixins/localize/localize-mixin.js +19 -186
- package/mixins/localize/localize.js +255 -0
- package/package.json +1 -1
- package/tools/mathjax-test-context.js +1 -2
package/helpers/mathjax.js
CHANGED
@@ -45,7 +45,6 @@ class HtmlBlockMathRenderer {
|
|
45
45
|
|
46
46
|
const mathJaxConfig = {
|
47
47
|
deferTypeset: true,
|
48
|
-
enableMML3Support: context.enableMML3Support,
|
49
48
|
renderLatex: context.renderLatex,
|
50
49
|
outputScale: context.outputScale || 1,
|
51
50
|
window: window
|
@@ -62,24 +61,6 @@ class HtmlBlockMathRenderer {
|
|
62
61
|
elm.style.height = '0.5rem';
|
63
62
|
});
|
64
63
|
|
65
|
-
if (context.enableMML3Support) {
|
66
|
-
// There's a bug in the experimental MML3 plugin that causes mi and mo elements containing non-breaking
|
67
|
-
// spaces to break MathJax's math processing (e.g. <mo> </mo>, <mi>Some Identifier</mi>).
|
68
|
-
// Unfortunately, WIRIS tends to add a lot of these in chemistry equations, so they break math processing.
|
69
|
-
//
|
70
|
-
// In order to address this, we can just remove any non-breaking spaces entirely, replacing them with
|
71
|
-
// empty strings. MathJax will ignore any empty elements as a result, and while this may mean intended
|
72
|
-
// whitespace is occasionally removed, it's necessary for MathJax to render anything at all.
|
73
|
-
//
|
74
|
-
// NOTE: MathJax evidently has a fix for this in MathJax 4, so we should consider trying to remove this when
|
75
|
-
// the update comes out of beta and we decide to take it on.
|
76
|
-
//
|
77
|
-
// See https://github.com/mathjax/MathJax/issues/3030 for some related discussion.
|
78
|
-
elem.querySelectorAll('mo, mi').forEach(elm => {
|
79
|
-
elm.innerHTML = elm.innerHTML.replace(/ /g, '');
|
80
|
-
});
|
81
|
-
}
|
82
|
-
|
83
64
|
// If we're using deferred rendering, we need to create a document structure
|
84
65
|
// within the element so MathJax can appropriately process math.
|
85
66
|
if (!options.noDeferredRendering) elem.innerHTML = `<mjx-doc><mjx-head></mjx-head><mjx-body>${elem.innerHTML}</mjx-body></mjx-doc>`;
|
@@ -120,13 +101,7 @@ export function loadMathJax(mathJaxConfig) {
|
|
120
101
|
}
|
121
102
|
},
|
122
103
|
loader: {
|
123
|
-
load:
|
124
|
-
? [
|
125
|
-
'[mml]/mml3',
|
126
|
-
'ui/menu'
|
127
|
-
] : [
|
128
|
-
'ui/menu'
|
129
|
-
]
|
104
|
+
load: ['ui/menu']
|
130
105
|
},
|
131
106
|
startup: {
|
132
107
|
ready: () => {
|
@@ -1,70 +1,32 @@
|
|
1
|
-
import '
|
2
|
-
import { defaultLocale as fallbackLang, getDocumentLocaleSettings, supportedLangpacks } from '@brightspace-ui/intl/lib/common.js';
|
1
|
+
import { disallowedTagsRegex, getLocalizeClass, validateMarkup } from './localize.js';
|
3
2
|
import { dedupeMixin } from '@open-wc/dedupe-mixin';
|
4
|
-
import { getLocalizeOverrideResources } from '../../helpers/getLocalizeResources.js';
|
5
3
|
import { html } from 'lit';
|
6
4
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
7
|
-
import IntlMessageFormat from 'intl-messageformat';
|
8
5
|
|
9
|
-
export const _LocalizeMixinBase = dedupeMixin(superclass => class
|
6
|
+
export const _LocalizeMixinBase = dedupeMixin(superclass => class LocalizeMixinBaseClass extends getLocalizeClass(superclass) {
|
10
7
|
|
11
|
-
|
12
|
-
return {
|
13
|
-
__resources: { type: Object, attribute: false }
|
14
|
-
};
|
15
|
-
}
|
16
|
-
|
17
|
-
static documentLocaleSettings = getDocumentLocaleSettings();
|
8
|
+
#updatedProperties = new Map();
|
18
9
|
|
19
10
|
constructor() {
|
20
11
|
super();
|
21
|
-
|
22
|
-
let first = true;
|
23
|
-
this.__languageChangeCallback = () => {
|
24
|
-
if (!this._hasResources()) return;
|
25
|
-
const localizeResources = this.constructor._getAllLocalizeResources();
|
26
|
-
const resourcesLoadedPromise = Promise.all(localizeResources);
|
27
|
-
resourcesLoadedPromise
|
28
|
-
.then((results) => {
|
29
|
-
if (results.length === 0) {
|
30
|
-
return;
|
31
|
-
}
|
32
|
-
const resources = {};
|
33
|
-
for (const res of results) {
|
34
|
-
const language = res.language;
|
35
|
-
for (const [key, value] of Object.entries(res.resources)) {
|
36
|
-
resources[key] = { language, value };
|
37
|
-
}
|
38
|
-
}
|
39
|
-
this.__resources = resources;
|
40
|
-
this._onResourcesChange();
|
41
|
-
if (first) {
|
42
|
-
resolve();
|
43
|
-
first = false;
|
44
|
-
}
|
45
|
-
});
|
46
|
-
};
|
47
|
-
});
|
48
|
-
|
49
|
-
this.__updatedProperties = new Map();
|
12
|
+
super.constructor.setLocalizeMarkup(localizeMarkup);
|
50
13
|
}
|
51
14
|
|
52
15
|
connectedCallback() {
|
53
16
|
super.connectedCallback();
|
54
|
-
this.
|
55
|
-
this.__languageChangeCallback();
|
17
|
+
this.connect();
|
56
18
|
}
|
57
19
|
|
58
20
|
disconnectedCallback() {
|
59
21
|
super.disconnectedCallback();
|
60
|
-
this.
|
61
|
-
this.
|
22
|
+
this.disconnect();
|
23
|
+
this.#updatedProperties.clear();
|
62
24
|
}
|
63
25
|
|
64
26
|
async getUpdateComplete() {
|
65
27
|
await super.getUpdateComplete();
|
66
28
|
const hasResources = this._hasResources();
|
67
|
-
const resourcesLoaded = this.
|
29
|
+
const resourcesLoaded = this.localize.resources !== undefined && !this.pristine;
|
68
30
|
if (!hasResources || resourcesLoaded) {
|
69
31
|
return;
|
70
32
|
}
|
@@ -78,148 +40,35 @@ export const _LocalizeMixinBase = dedupeMixin(superclass => class LocalizeMixinC
|
|
78
40
|
return super.shouldUpdate(changedProperties);
|
79
41
|
}
|
80
42
|
|
81
|
-
const ready = this.
|
43
|
+
const ready = this.localize.resources !== undefined && !this.pristine;
|
44
|
+
|
82
45
|
if (!ready) {
|
83
46
|
changedProperties.forEach((oldValue, propName) => {
|
84
|
-
this.
|
47
|
+
this.#updatedProperties.set(propName, oldValue);
|
85
48
|
});
|
86
49
|
return false;
|
87
50
|
}
|
88
51
|
|
89
|
-
this.
|
52
|
+
this.#updatedProperties.forEach((oldValue, propName) => {
|
90
53
|
if (!changedProperties.has(propName)) {
|
91
54
|
changedProperties.set(propName, oldValue);
|
92
55
|
}
|
93
56
|
});
|
94
|
-
this.
|
57
|
+
this.#updatedProperties.clear();
|
95
58
|
|
96
59
|
return super.shouldUpdate(changedProperties);
|
97
|
-
|
98
|
-
}
|
99
|
-
|
100
|
-
localize(key) {
|
101
|
-
|
102
|
-
const { language, value } = this.__resources?.[key] ?? {};
|
103
|
-
if (!value) return '';
|
104
|
-
|
105
|
-
let params = {};
|
106
|
-
if (arguments.length > 1 && arguments[1]?.constructor === Object) {
|
107
|
-
// support for key-value replacements as a single arg
|
108
|
-
params = arguments[1];
|
109
|
-
} else {
|
110
|
-
// legacy support for localize-behavior replacements as many args
|
111
|
-
for (let i = 1; i < arguments.length; i += 2) {
|
112
|
-
params[arguments[i]] = arguments[i + 1];
|
113
|
-
}
|
114
|
-
}
|
115
|
-
|
116
|
-
const translatedMessage = new IntlMessageFormat(value, language);
|
117
|
-
let formattedMessage = value;
|
118
|
-
try {
|
119
|
-
if (Object.values(params).some(v => typeof v === 'function')) throw 'localize() does not support rich text.';
|
120
|
-
formattedMessage = translatedMessage.format(params);
|
121
|
-
} catch (e) {
|
122
|
-
console.error(e);
|
123
|
-
}
|
124
|
-
|
125
|
-
return formattedMessage;
|
126
60
|
}
|
127
61
|
|
128
|
-
|
129
|
-
|
130
|
-
const { language, value } = this.__resources?.[key] ?? {};
|
131
|
-
if (!value) return '';
|
132
|
-
|
133
|
-
const translatedMessage = new IntlMessageFormat(value, language);
|
134
|
-
let formattedMessage = value;
|
135
|
-
try {
|
136
|
-
const unvalidated = translatedMessage.format({
|
137
|
-
b: chunks => localizeMarkup`<b>${chunks}</b>`,
|
138
|
-
br: () => localizeMarkup`<br>`,
|
139
|
-
em: chunks => localizeMarkup`<em>${chunks}</em>`,
|
140
|
-
i: chunks => localizeMarkup`<i>${chunks}</i>`,
|
141
|
-
p: chunks => localizeMarkup`<p>${chunks}</p>`,
|
142
|
-
strong: chunks => localizeMarkup`<strong>${chunks}</strong>`,
|
143
|
-
...params
|
144
|
-
});
|
145
|
-
validateMarkup(unvalidated);
|
146
|
-
formattedMessage = unvalidated;
|
147
|
-
} catch (e) {
|
148
|
-
console.error(e);
|
149
|
-
}
|
150
|
-
|
151
|
-
return formattedMessage;
|
152
|
-
}
|
153
|
-
|
154
|
-
static _generatePossibleLanguages(config) {
|
155
|
-
|
156
|
-
if (config?.useBrowserLangs) return navigator.languages.map(e => e.toLowerCase()).concat('en');
|
157
|
-
|
158
|
-
const { language, fallbackLanguage } = this.documentLocaleSettings;
|
159
|
-
const langs = [ language, fallbackLanguage ]
|
160
|
-
.filter(e => e)
|
161
|
-
.map(e => [ e.toLowerCase(), e.split('-')[0] ])
|
162
|
-
.flat();
|
163
|
-
|
164
|
-
return Array.from(new Set([ ...langs, 'en-us', 'en' ]));
|
165
|
-
}
|
166
|
-
|
167
|
-
static _getAllLocalizeResources(config = this.localizeConfig) {
|
168
|
-
let resourcesLoadedPromises = [];
|
169
|
-
const superCtor = Object.getPrototypeOf(this);
|
170
|
-
// get imported terms for each config, head up the chain to get them all
|
171
|
-
if ('_getAllLocalizeResources' in superCtor) {
|
172
|
-
const superConfig = Object.prototype.hasOwnProperty.call(superCtor, 'localizeConfig') && superCtor.localizeConfig.importFunc ? superCtor.localizeConfig : config;
|
173
|
-
resourcesLoadedPromises = superCtor._getAllLocalizeResources(superConfig);
|
174
|
-
}
|
175
|
-
if (Object.prototype.hasOwnProperty.call(this, 'getLocalizeResources') || Object.prototype.hasOwnProperty.call(this, 'resources')) {
|
176
|
-
const possibleLanguages = this._generatePossibleLanguages(config);
|
177
|
-
const res = this.getLocalizeResources(possibleLanguages, config);
|
178
|
-
resourcesLoadedPromises.push(res);
|
179
|
-
}
|
180
|
-
return resourcesLoadedPromises;
|
181
|
-
}
|
182
|
-
|
183
|
-
_hasResources() {
|
184
|
-
return this.constructor['getLocalizeResources'] !== undefined;
|
185
|
-
}
|
186
|
-
|
187
|
-
_onResourcesChange() {
|
188
|
-
/** @ignore */
|
189
|
-
this.dispatchEvent(new CustomEvent('d2l-localize-resources-change'));
|
62
|
+
onLocalizeResourcesChange() {
|
63
|
+
this.requestUpdate('localize');
|
190
64
|
}
|
191
65
|
|
192
66
|
});
|
193
67
|
|
194
68
|
export const LocalizeMixin = superclass => class extends _LocalizeMixinBase(superclass) {
|
195
69
|
|
196
|
-
static
|
197
|
-
|
198
|
-
// in dev, don't request unsupported langpacks
|
199
|
-
if (!importFunc.toString().includes('switch') && !useBrowserLangs) {
|
200
|
-
langs = langs.filter(lang => supportedLangpacks.includes(lang));
|
201
|
-
}
|
202
|
-
|
203
|
-
for (const lang of [...langs, fallbackLang]) {
|
204
|
-
|
205
|
-
const resources = await Promise.resolve(importFunc(lang)).catch(() => {});
|
206
|
-
|
207
|
-
if (resources) {
|
208
|
-
|
209
|
-
if (osloCollection) {
|
210
|
-
return await getLocalizeOverrideResources(
|
211
|
-
lang,
|
212
|
-
resources,
|
213
|
-
() => osloCollection
|
214
|
-
);
|
215
|
-
}
|
216
|
-
|
217
|
-
return {
|
218
|
-
language: lang,
|
219
|
-
resources
|
220
|
-
};
|
221
|
-
}
|
222
|
-
}
|
70
|
+
static getLocalizeResources() {
|
71
|
+
return super._getLocalizeResources(...arguments);
|
223
72
|
}
|
224
73
|
|
225
74
|
static get localizeConfig() {
|
@@ -228,25 +77,9 @@ export const LocalizeMixin = superclass => class extends _LocalizeMixinBase(supe
|
|
228
77
|
|
229
78
|
};
|
230
79
|
|
231
|
-
export const allowedTags = Object.freeze(['d2l-link', 'd2l-tooltip-help', 'p', 'br', 'b', 'strong', 'i', 'em', 'button']);
|
232
|
-
|
233
|
-
const markupError = `localizeHTML() rich-text replacements must use localizeMarkup templates with only the following allowed elements: ${allowedTags}. For more information, see: https://github.com/BrightspaceUI/core/blob/main/mixins/localize/`;
|
234
|
-
const validTerminators = '([>\\s/]|$)';
|
235
|
-
const allowedAfterTriangleBracket = `/?(${allowedTags.join('|')})?${validTerminators}`;
|
236
|
-
const disallowedTagsRegex = new RegExp(`<(?!${allowedAfterTriangleBracket})`);
|
237
|
-
|
238
|
-
function validateMarkup(content, applyRegex) {
|
239
|
-
if (content) {
|
240
|
-
if (content.map) return content.forEach(item => validateMarkup(item));
|
241
|
-
if (content._localizeMarkup) return;
|
242
|
-
if (Object.hasOwn(content, '_$litType$')) throw markupError;
|
243
|
-
if (applyRegex && content.constructor === String && disallowedTagsRegex.test(content)) throw markupError;
|
244
|
-
}
|
245
|
-
}
|
246
|
-
|
247
80
|
export function localizeMarkup(strings, ...expressions) {
|
248
|
-
strings.forEach(str => validateMarkup(str,
|
249
|
-
expressions.forEach(exp => validateMarkup(exp,
|
81
|
+
strings.forEach(str => validateMarkup(str, disallowedTagsRegex));
|
82
|
+
expressions.forEach(exp => validateMarkup(exp, disallowedTagsRegex));
|
250
83
|
return { ...html(strings, ...expressions), _localizeMarkup: true };
|
251
84
|
}
|
252
85
|
|
@@ -0,0 +1,255 @@
|
|
1
|
+
import '@formatjs/intl-pluralrules/dist-es6/polyfill-locales.js';
|
2
|
+
import { defaultLocale as fallbackLang, getDocumentLocaleSettings, supportedLangpacks } from '@brightspace-ui/intl/lib/common.js';
|
3
|
+
import { getLocalizeOverrideResources } from '../../helpers/getLocalizeResources.js';
|
4
|
+
import IntlMessageFormat from 'intl-messageformat';
|
5
|
+
|
6
|
+
export const allowedTags = Object.freeze(['d2l-link', 'd2l-tooltip-help', 'p', 'br', 'b', 'strong', 'i', 'em', 'button']);
|
7
|
+
|
8
|
+
const getDisallowedTagsRegex = allowedTags => {
|
9
|
+
const validTerminators = '([>\\s/]|$)';
|
10
|
+
const allowedAfterTriangleBracket = `/?(${allowedTags.join('|')})?${validTerminators}`;
|
11
|
+
return new RegExp(`<(?!${allowedAfterTriangleBracket})`);
|
12
|
+
};
|
13
|
+
|
14
|
+
export const disallowedTagsRegex = getDisallowedTagsRegex(allowedTags);
|
15
|
+
const noAllowedTagsRegex = getDisallowedTagsRegex([]);
|
16
|
+
|
17
|
+
export const getLocalizeClass = (superclass = class {}) => class LocalizeClass extends superclass {
|
18
|
+
|
19
|
+
static documentLocaleSettings = getDocumentLocaleSettings();
|
20
|
+
static #localizeMarkup;
|
21
|
+
|
22
|
+
static setLocalizeMarkup(localizeMarkup) {
|
23
|
+
this.#localizeMarkup ??= localizeMarkup;
|
24
|
+
}
|
25
|
+
|
26
|
+
pristine = true;
|
27
|
+
#connected = false;
|
28
|
+
#localeChangeCallback;
|
29
|
+
#resourcesPromise;
|
30
|
+
#resolveResourcesLoaded;
|
31
|
+
|
32
|
+
async #localeChangeHandler() {
|
33
|
+
if (!this._hasResources()) return;
|
34
|
+
|
35
|
+
const resourcesPromise = this.constructor._getAllLocalizeResources(this.config);
|
36
|
+
this.#resourcesPromise = resourcesPromise;
|
37
|
+
const localizeResources = (await resourcesPromise).flat(Infinity);
|
38
|
+
// If the locale changed while resources were being fetched, abort
|
39
|
+
if (this.#resourcesPromise !== resourcesPromise) return;
|
40
|
+
|
41
|
+
const allResources = {};
|
42
|
+
const resolvedLocales = new Set();
|
43
|
+
for (const { language, resources } of localizeResources) {
|
44
|
+
for (const [key, value] of Object.entries(resources)) {
|
45
|
+
allResources[key] = { language, value };
|
46
|
+
resolvedLocales.add(language);
|
47
|
+
}
|
48
|
+
}
|
49
|
+
this.localize.resources = allResources;
|
50
|
+
this.localize.resolvedLocale = [...resolvedLocales][0];
|
51
|
+
if (resolvedLocales.size > 1) {
|
52
|
+
console.warn(`Resolved multiple locales in '${this.constructor.name || this.tagName || ''}': ${[...resolvedLocales].join(', ')}`);
|
53
|
+
}
|
54
|
+
|
55
|
+
if (this.pristine) {
|
56
|
+
this.pristine = false;
|
57
|
+
this.#resolveResourcesLoaded();
|
58
|
+
}
|
59
|
+
|
60
|
+
this.#onResourcesChange();
|
61
|
+
}
|
62
|
+
|
63
|
+
#onResourcesChange() {
|
64
|
+
if (this.#connected) {
|
65
|
+
this.dispatchEvent?.(new CustomEvent('d2l-localize-resources-change'));
|
66
|
+
this.config?.onResourcesChange?.();
|
67
|
+
this.onLocalizeResourcesChange?.();
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
connect() {
|
72
|
+
this.#localeChangeCallback = () => this.#localeChangeHandler();
|
73
|
+
LocalizeClass.documentLocaleSettings.addChangeListener(this.#localeChangeCallback);
|
74
|
+
this.#connected = true;
|
75
|
+
this.#localeChangeCallback();
|
76
|
+
}
|
77
|
+
|
78
|
+
disconnect() {
|
79
|
+
LocalizeClass.documentLocaleSettings.removeChangeListener(this.#localeChangeCallback);
|
80
|
+
this.#connected = false;
|
81
|
+
}
|
82
|
+
|
83
|
+
localize(key) {
|
84
|
+
|
85
|
+
const { language, value } = this.localize.resources?.[key] ?? {};
|
86
|
+
if (!value) return '';
|
87
|
+
|
88
|
+
let params = {};
|
89
|
+
if (arguments.length > 1 && arguments[1]?.constructor === Object) {
|
90
|
+
// support for key-value replacements as a single arg
|
91
|
+
params = arguments[1];
|
92
|
+
} else {
|
93
|
+
// legacy support for localize-behavior replacements as many args
|
94
|
+
for (let i = 1; i < arguments.length; i += 2) {
|
95
|
+
params[arguments[i]] = arguments[i + 1];
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
const translatedMessage = new IntlMessageFormat(value, language);
|
100
|
+
let formattedMessage = value;
|
101
|
+
try {
|
102
|
+
validateMarkup(formattedMessage, noAllowedTagsRegex);
|
103
|
+
formattedMessage = translatedMessage.format(params);
|
104
|
+
} catch (e) {
|
105
|
+
if (e.name === 'MarkupError') {
|
106
|
+
e = new Error('localize() does not support rich text. For more information, see: https://github.com/BrightspaceUI/core/blob/main/mixins/localize/'); // eslint-disable-line no-ex-assign
|
107
|
+
formattedMessage = '';
|
108
|
+
}
|
109
|
+
console.error(e);
|
110
|
+
}
|
111
|
+
|
112
|
+
return formattedMessage;
|
113
|
+
}
|
114
|
+
|
115
|
+
localizeHTML(key, params = {}) {
|
116
|
+
|
117
|
+
const { language, value } = this.localize.resources?.[key] ?? {};
|
118
|
+
if (!value) return '';
|
119
|
+
|
120
|
+
const translatedMessage = new IntlMessageFormat(value, language);
|
121
|
+
let formattedMessage = value;
|
122
|
+
try {
|
123
|
+
const unvalidated = translatedMessage.format({
|
124
|
+
b: chunks => LocalizeClass.#localizeMarkup`<b>${chunks}</b>`,
|
125
|
+
br: () => LocalizeClass.#localizeMarkup`<br>`,
|
126
|
+
em: chunks => LocalizeClass.#localizeMarkup`<em>${chunks}</em>`,
|
127
|
+
i: chunks => LocalizeClass.#localizeMarkup`<i>${chunks}</i>`,
|
128
|
+
p: chunks => LocalizeClass.#localizeMarkup`<p>${chunks}</p>`,
|
129
|
+
strong: chunks => LocalizeClass.#localizeMarkup`<strong>${chunks}</strong>`,
|
130
|
+
...params
|
131
|
+
});
|
132
|
+
validateMarkup(unvalidated);
|
133
|
+
formattedMessage = unvalidated;
|
134
|
+
} catch (e) {
|
135
|
+
if (e.name === 'MarkupError') formattedMessage = '';
|
136
|
+
console.error(e);
|
137
|
+
}
|
138
|
+
|
139
|
+
return formattedMessage;
|
140
|
+
}
|
141
|
+
|
142
|
+
__resourcesLoadedPromise = new Promise(r => this.#resolveResourcesLoaded = r);
|
143
|
+
|
144
|
+
static _generatePossibleLanguages(config) {
|
145
|
+
|
146
|
+
if (config?.useBrowserLangs) return navigator.languages.map(e => e.toLowerCase()).concat('en');
|
147
|
+
|
148
|
+
const { language, fallbackLanguage } = this.documentLocaleSettings;
|
149
|
+
const langs = [ language, fallbackLanguage ]
|
150
|
+
.filter(e => e)
|
151
|
+
.map(e => [ e.toLowerCase(), e.split('-')[0] ])
|
152
|
+
.flat();
|
153
|
+
|
154
|
+
return Array.from(new Set([ ...langs, 'en-us', 'en' ]));
|
155
|
+
}
|
156
|
+
|
157
|
+
static _getAllLocalizeResources(config = this.localizeConfig) {
|
158
|
+
const resourcesLoadedPromises = [];
|
159
|
+
const superCtor = Object.getPrototypeOf(this);
|
160
|
+
// get imported terms for each config, head up the chain to get them all
|
161
|
+
if ('_getAllLocalizeResources' in superCtor) {
|
162
|
+
const superConfig = Object.prototype.hasOwnProperty.call(superCtor, 'localizeConfig') && superCtor.localizeConfig.importFunc ? superCtor.localizeConfig : config;
|
163
|
+
resourcesLoadedPromises.push(superCtor._getAllLocalizeResources(superConfig));
|
164
|
+
}
|
165
|
+
if (Object.prototype.hasOwnProperty.call(this, 'getLocalizeResources') || Object.prototype.hasOwnProperty.call(this, 'resources')) {
|
166
|
+
const possibleLanguages = this._generatePossibleLanguages(config);
|
167
|
+
const resourcesPromise = this.getLocalizeResources(possibleLanguages, config);
|
168
|
+
resourcesLoadedPromises.push(resourcesPromise);
|
169
|
+
}
|
170
|
+
return Promise.all(resourcesLoadedPromises);
|
171
|
+
}
|
172
|
+
|
173
|
+
static async _getLocalizeResources(langs, { importFunc, osloCollection, useBrowserLangs }) {
|
174
|
+
|
175
|
+
// in dev, don't request unsupported langpacks
|
176
|
+
if (!importFunc.toString().includes('switch') && !useBrowserLangs) {
|
177
|
+
langs = langs.filter(lang => supportedLangpacks.includes(lang));
|
178
|
+
}
|
179
|
+
|
180
|
+
for (const lang of [...langs, fallbackLang]) {
|
181
|
+
|
182
|
+
const resources = await Promise.resolve(importFunc(lang)).catch(() => {});
|
183
|
+
|
184
|
+
if (resources) {
|
185
|
+
|
186
|
+
if (osloCollection) {
|
187
|
+
return await getLocalizeOverrideResources(
|
188
|
+
lang,
|
189
|
+
resources,
|
190
|
+
() => osloCollection
|
191
|
+
);
|
192
|
+
}
|
193
|
+
|
194
|
+
return {
|
195
|
+
language: lang,
|
196
|
+
resources
|
197
|
+
};
|
198
|
+
}
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
_hasResources() {
|
203
|
+
return this.constructor.localizeConfig ? Boolean(this.constructor.localizeConfig.importFunc) : this.constructor.getLocalizeResources !== undefined;
|
204
|
+
}
|
205
|
+
|
206
|
+
};
|
207
|
+
|
208
|
+
export const Localize = class extends getLocalizeClass() {
|
209
|
+
|
210
|
+
static getLocalizeResources() {
|
211
|
+
return super._getLocalizeResources(...arguments);
|
212
|
+
}
|
213
|
+
|
214
|
+
constructor(config) {
|
215
|
+
super();
|
216
|
+
super.constructor.setLocalizeMarkup(localizeMarkup);
|
217
|
+
this.config = config;
|
218
|
+
this.connect();
|
219
|
+
}
|
220
|
+
|
221
|
+
get ready() {
|
222
|
+
return this.__resourcesLoadedPromise;
|
223
|
+
}
|
224
|
+
|
225
|
+
connect() {
|
226
|
+
super.connect();
|
227
|
+
return this.ready;
|
228
|
+
}
|
229
|
+
|
230
|
+
};
|
231
|
+
|
232
|
+
class MarkupError extends Error {
|
233
|
+
name = this.constructor.name;
|
234
|
+
}
|
235
|
+
|
236
|
+
export function validateMarkup(content, disallowedTagsRegex) {
|
237
|
+
if (content) {
|
238
|
+
if (content.forEach) {
|
239
|
+
content.forEach(item => validateMarkup(item));
|
240
|
+
return;
|
241
|
+
}
|
242
|
+
if (content._localizeMarkup) return;
|
243
|
+
if (Object.hasOwn(content, '_$litType$')) throw new MarkupError('Rich-text replacements must use localizeMarkup templates. For more information, see: https://github.com/BrightspaceUI/core/blob/main/mixins/localize/');
|
244
|
+
|
245
|
+
if (content.constructor === String && disallowedTagsRegex?.test(content)) throw new MarkupError(`Rich-text replacements may use only the following allowed elements: ${allowedTags}. For more information, see: https://github.com/BrightspaceUI/core/blob/main/mixins/localize/`);
|
246
|
+
}
|
247
|
+
}
|
248
|
+
|
249
|
+
export function localizeMarkup(strings, ...expressions) {
|
250
|
+
strings.forEach(str => validateMarkup(str, disallowedTagsRegex));
|
251
|
+
expressions.forEach(exp => validateMarkup(exp, disallowedTagsRegex));
|
252
|
+
return strings.reduce((acc, i, idx) => {
|
253
|
+
return acc.push(i, expressions[idx] ?? '') && acc;
|
254
|
+
}, []).join('');
|
255
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@brightspace-ui/core",
|
3
|
-
"version": "3.
|
3
|
+
"version": "3.33.0",
|
4
4
|
"description": "A collection of accessible, free, open-source web components for building Brightspace applications",
|
5
5
|
"type": "module",
|
6
6
|
"repository": "https://github.com/BrightspaceUI/core.git",
|
@@ -4,6 +4,5 @@ console.warn('Using mathjax test context, this is intended for demo pages and te
|
|
4
4
|
|
5
5
|
addContext('d2l-mathjax', {
|
6
6
|
outputScale: 1.1,
|
7
|
-
renderLatex: !(window.location.search.indexOf('latex=false') !== -1)
|
8
|
-
enableMML3Support: true
|
7
|
+
renderLatex: !(window.location.search.indexOf('latex=false') !== -1)
|
9
8
|
});
|