@brightspace-ui/core 1.207.4 → 1.208.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.
@@ -10,6 +10,10 @@
10
10
  import { provideInstance } from '../../../mixins/provider-mixin.js';
11
11
 
12
12
  class DemoReplacementRenderer {
13
+ get canRenderInline() {
14
+ return true;
15
+ }
16
+
13
17
  async render(elem) {
14
18
  const elemsToReplace = elem.querySelectorAll('[data-replace-me-id]');
15
19
  if (elemsToReplace.length === 0) return elem;
@@ -188,6 +192,119 @@
188
192
  </template>
189
193
  </d2l-demo-snippet>
190
194
 
195
+ <h2>HTML Block (math, no deferred rendering)</h2>
196
+
197
+ <d2l-demo-snippet>
198
+ <template>
199
+ <d2l-html-block no-deferred-rendering>
200
+ <div>
201
+ <math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
202
+ <mi>x</mi>
203
+ <mo>=</mo>
204
+ <mrow>
205
+ <mfrac>
206
+ <mrow>
207
+ <mo>&#x2212;</mo>
208
+ <mi>b</mi>
209
+ <mo>&#xB1;</mo>
210
+ <msqrt>
211
+ <msup>
212
+ <mi>b</mi>
213
+ <mn>2</mn>
214
+ </msup>
215
+ <mo>&#x2212;</mo>
216
+ <mn>4</mn>
217
+ <mi>a</mi>
218
+ <mi>c</mi>
219
+ </msqrt>
220
+ </mrow>
221
+ <mrow>
222
+ <mn>2</mn>
223
+ <mi>a</mi>
224
+ </mrow>
225
+ </mfrac>
226
+ </mrow>
227
+ <mtext>.</mtext>
228
+ </math>
229
+ <math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
230
+ <msup>
231
+ <mrow>
232
+ <mo>(</mo>
233
+ <mrow>
234
+ <munderover>
235
+ <mo>∑<!-- ∑ --></mo>
236
+ <mrow class="MJX-TeXAtom-ORD">
237
+ <mi>k</mi>
238
+ <mo>=</mo>
239
+ <mn>1</mn>
240
+ </mrow>
241
+ <mi>n</mi>
242
+ </munderover>
243
+ <msub>
244
+ <mi>a</mi>
245
+ <mi>k</mi>
246
+ </msub>
247
+ <msub>
248
+ <mi>b</mi>
249
+ <mi>k</mi>
250
+ </msub>
251
+ </mrow>
252
+ <mo>)</mo>
253
+ </mrow>
254
+ <mrow class="MJX-TeXAtom-ORD">
255
+ <mspace width="negativethinmathspace"></mspace>
256
+ <mspace width="negativethinmathspace"></mspace>
257
+ <mn>2</mn>
258
+ </mrow>
259
+ </msup>
260
+ <mo>≤<!-- ≤ --></mo>
261
+ <mrow>
262
+ <mo>(</mo>
263
+ <mrow>
264
+ <munderover>
265
+ <mo>∑<!-- ∑ --></mo>
266
+ <mrow class="MJX-TeXAtom-ORD">
267
+ <mi>k</mi>
268
+ <mo>=</mo>
269
+ <mn>1</mn>
270
+ </mrow>
271
+ <mi>n</mi>
272
+ </munderover>
273
+ <msubsup>
274
+ <mi>a</mi>
275
+ <mi>k</mi>
276
+ <mn>2</mn>
277
+ </msubsup>
278
+ </mrow>
279
+ <mo>)</mo>
280
+ </mrow>
281
+ <mrow>
282
+ <mo>(</mo>
283
+ <mrow>
284
+ <munderover>
285
+ <mo>∑<!-- ∑ --></mo>
286
+ <mrow class="MJX-TeXAtom-ORD">
287
+ <mi>k</mi>
288
+ <mo>=</mo>
289
+ <mn>1</mn>
290
+ </mrow>
291
+ <mi>n</mi>
292
+ </munderover>
293
+ <msubsup>
294
+ <mi>b</mi>
295
+ <mi>k</mi>
296
+ <mn>2</mn>
297
+ </msubsup>
298
+ </mrow>
299
+ <mo>)</mo>
300
+ </mrow>
301
+ </math>
302
+ <p>The wizard (<span data-replace-me-id="0">Elmer Fudd</span>) quickly jinxed the gnomes before they vaporized.</p>
303
+ </div>
304
+ </d2l-html-block>
305
+ </template>
306
+ </d2l-demo-snippet>
307
+
191
308
  <h2>HTML Block (inline math)</h2>
192
309
 
193
310
  <d2l-demo-snippet>
@@ -118,6 +118,17 @@ const getRenderers = () => {
118
118
  */
119
119
  class HtmlBlock extends LitElement {
120
120
 
121
+ static get properties() {
122
+ return {
123
+ /**
124
+ * Whether to disable deferred rendering of the user-authored HTML. Do *not* set this
125
+ * unless your HTML relies on script executions that may break upon stamping.
126
+ * @type {Boolean}
127
+ */
128
+ noDeferredRendering: { type: Boolean, attribute: 'no-deferred-rendering' }
129
+ };
130
+ }
131
+
121
132
  static get styles() {
122
133
  return [ htmlBlockContentStyles, css`
123
134
  :host {
@@ -131,7 +142,10 @@ class HtmlBlock extends LitElement {
131
142
  :host([hidden]) {
132
143
  display: none;
133
144
  }
134
- ::slotted(*) {
145
+ :host([no-deferred-rendering]) div.d2l-html-block-rendered {
146
+ display: none;
147
+ }
148
+ :host(:not([no-deferred-rendering])) ::slotted(*) {
135
149
  display: none;
136
150
  }
137
151
  `];
@@ -139,6 +153,7 @@ class HtmlBlock extends LitElement {
139
153
 
140
154
  constructor() {
141
155
  super();
156
+ this.noDeferredRendering = false;
142
157
 
143
158
  const rendererContextAttributes = getRenderers().reduce((attrs, currentRenderer) => {
144
159
  if (currentRenderer.contextAttributes) currentRenderer.contextAttributes.forEach(attr => attrs.push(attr));
@@ -153,9 +168,9 @@ class HtmlBlock extends LitElement {
153
168
  super.connectedCallback();
154
169
  if (this._contextObserverController) this._contextObserverController.hostConnected();
155
170
 
156
- if (!this._templateObserver) return;
171
+ if (!this._templateObserver || this.noDeferredRendering) return;
157
172
 
158
- const template = this.querySelector('template');
173
+ const template = this._findSlottedElement('TEMPLATE');
159
174
  if (template) this._templateObserver.observe(template.content, { attributes: true, childList: true, subtree: true });
160
175
  }
161
176
 
@@ -172,24 +187,14 @@ class HtmlBlock extends LitElement {
172
187
 
173
188
  this.shadowRoot.innerHTML += '<div class="d2l-html-block-rendered"></div><slot></slot>';
174
189
 
175
- this.shadowRoot.querySelector('slot').addEventListener('slotchange', async e => {
176
-
177
- const template = e.target.assignedNodes({ flatten: true })
178
- .find(node => (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'TEMPLATE'));
179
-
180
- this._stamp(template);
181
-
182
- });
190
+ this.shadowRoot.querySelector('slot').addEventListener('slotchange', async e => await this._render(e.target));
183
191
  this._renderContainer = this.shadowRoot.querySelector('.d2l-html-block-rendered');
184
192
  this._context = this._contextObserverController ? { ...this._contextObserverController.values } : {};
185
193
  }
186
194
 
187
195
  updated() {
188
196
  super.updated();
189
- if (this._contextObserverController && this._contextObjectHasChanged()) {
190
- const template = this.querySelector('template');
191
- this._stamp(template);
192
- }
197
+ if (this._contextObserverController && this._contextObjectHasChanged()) this._render();
193
198
  }
194
199
 
195
200
  _contextObjectHasChanged() {
@@ -201,7 +206,40 @@ class HtmlBlock extends LitElement {
201
206
  return false;
202
207
  }
203
208
 
204
- _stamp(template) {
209
+ _findSlottedElement(tagName, slot) {
210
+ if (!slot) slot = this.shadowRoot.querySelector('slot');
211
+ return slot.assignedNodes({ flatten: true })
212
+ .find(node => (node.nodeType === Node.ELEMENT_NODE && node.tagName === tagName.toUpperCase()));
213
+ }
214
+
215
+ async _processRenderers(elem) {
216
+ for (const renderer of getRenderers()) {
217
+ if (this.noDeferredRendering && !renderer.canRenderInline) continue;
218
+
219
+ if (this._contextObserverController && renderer.contextAttributes) {
220
+ const contextValues = new Map();
221
+ renderer.contextAttributes.forEach(attr => contextValues.set(attr, this._contextObserverController.values.get(attr)));
222
+ elem = await renderer.render(elem, contextValues);
223
+ } else {
224
+ elem = await renderer.render(elem);
225
+ }
226
+ }
227
+
228
+ return elem;
229
+ }
230
+
231
+ async _render(slot) {
232
+ if (this.noDeferredRendering) await this._renderInline(slot);
233
+ else this._stamp(slot);
234
+ }
235
+
236
+ async _renderInline(slot) {
237
+ const noDeferredRenderingContainer = this._findSlottedElement('DIV', slot);
238
+ if (!noDeferredRenderingContainer) return;
239
+ await this._processRenderers(noDeferredRenderingContainer);
240
+ }
241
+
242
+ _stamp(slot) {
205
243
  const stampHTML = async template => {
206
244
  const fragment = template ? document.importNode(template.content, true) : null;
207
245
  if (fragment) {
@@ -209,15 +247,7 @@ class HtmlBlock extends LitElement {
209
247
  let temp = document.createElement('div');
210
248
  temp.appendChild(fragment);
211
249
 
212
- for (const renderer of getRenderers()) {
213
- if (this._contextObserverController && renderer.contextAttributes) {
214
- const contextValues = new Map();
215
- renderer.contextAttributes.forEach(attr => contextValues.set(attr, this._contextObserverController.values.get(attr)));
216
- temp = await renderer.render(temp, contextValues);
217
- } else {
218
- temp = await renderer.render(temp);
219
- }
220
- }
250
+ temp = await this._processRenderers(temp);
221
251
  this._renderContainer.innerHTML = temp.innerHTML;
222
252
 
223
253
  } else {
@@ -225,6 +255,8 @@ class HtmlBlock extends LitElement {
225
255
  }
226
256
  };
227
257
 
258
+ const template = this._findSlottedElement('TEMPLATE', slot);
259
+
228
260
  if (this._templateObserver) this._templateObserver.disconnect();
229
261
  if (template) {
230
262
  this._templateObserver = new MutationObserver(() => stampHTML(template));
@@ -3377,6 +3377,23 @@
3377
3377
  "name": "d2l-html-block",
3378
3378
  "path": "./components/html-block/html-block.js",
3379
3379
  "description": "A component for displaying user-authored HTML.",
3380
+ "attributes": [
3381
+ {
3382
+ "name": "no-deferred-rendering",
3383
+ "description": "Whether to disable deferred rendering of the user-authored HTML. Do *not* set this\nunless your HTML relies on script executions that may break upon stamping.",
3384
+ "type": "Boolean",
3385
+ "default": "false"
3386
+ }
3387
+ ],
3388
+ "properties": [
3389
+ {
3390
+ "name": "noDeferredRendering",
3391
+ "attribute": "no-deferred-rendering",
3392
+ "description": "Whether to disable deferred rendering of the user-authored HTML. Do *not* set this\nunless your HTML relies on script executions that may break upon stamping.",
3393
+ "type": "Boolean",
3394
+ "default": "false"
3395
+ }
3396
+ ],
3380
3397
  "slots": [
3381
3398
  {
3382
3399
  "name": "",
@@ -4,6 +4,12 @@ let mathJaxLoaded;
4
4
 
5
5
  export class HtmlBlockMathRenderer {
6
6
 
7
+ get canRenderInline() {
8
+ // The custom MathJax ShadowAdaptor creates a new document and renders
9
+ // its contents to the DOM.
10
+ return false;
11
+ }
12
+
7
13
  get contextAttributes() {
8
14
  return [mathjaxContextAttribute];
9
15
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brightspace-ui/core",
3
- "version": "1.207.4",
3
+ "version": "1.208.0",
4
4
  "description": "A collection of accessible, free, open-source web components for building Brightspace applications",
5
5
  "repository": "https://github.com/BrightspaceUI/core.git",
6
6
  "publishConfig": {