@themarioga/grid-editor 9.0.0-beta.3 → 9.0.0-beta.4

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +24 -8
  3. package/dist/grideditor.bundle.min.js +2 -2
  4. package/dist/grideditor.css +187 -0
  5. package/dist/grideditor.d.ts +37 -0
  6. package/dist/grideditor.esm.js +6 -10
  7. package/dist/grideditor.js +6 -10
  8. package/dist/grideditor.min.css +1 -1
  9. package/dist/grideditor.min.css.map +1 -1
  10. package/dist/grideditor.min.js +1 -1
  11. package/dist/grideditor.min.js.map +3 -3
  12. package/dist/locales/grideditor.es.esm.js +20 -0
  13. package/dist/locales/grideditor.es.js +20 -0
  14. package/dist/locales/grideditor.es.min.js +2 -2
  15. package/dist/locales/grideditor.es.min.js.map +2 -2
  16. package/dist/plugins/grideditor.offcanvas.esm.js +551 -0
  17. package/dist/plugins/grideditor.offcanvas.js +556 -0
  18. package/dist/plugins/grideditor.offcanvas.min.js +1 -0
  19. package/dist/plugins/grideditor.offcanvas.min.js.map +7 -0
  20. package/dist/plugins/grideditor.popup.esm.js +90 -37
  21. package/dist/plugins/grideditor.popup.js +90 -37
  22. package/dist/plugins/grideditor.popup.min.js +1 -1
  23. package/dist/plugins/grideditor.popup.min.js.map +4 -4
  24. package/docs/events.md +4 -3
  25. package/docs/locale-keys.md +21 -1
  26. package/docs/plugins.md +11 -4
  27. package/example/containers.html +22 -4
  28. package/example/index.html +1 -1
  29. package/package.json +1 -1
  30. package/src/js/grideditor.js +7 -8
  31. package/src/js/locales/grideditor.es.js +20 -0
  32. package/src/js/plugins/grideditor.offcanvas.js +420 -0
  33. package/src/js/plugins/grideditor.popup.js +8 -70
  34. package/src/js/triggers/triggers.js +121 -0
  35. package/src/less/grideditor.less +60 -0
  36. package/types/grideditor.d.ts +37 -0
@@ -0,0 +1,551 @@
1
+ // src/js/plugins/grideditor.offcanvas.js
2
+ import { GridEditor } from "../grideditor.esm.js";
3
+
4
+ // src/js/dom.js
5
+ function all(root, selector) {
6
+ return root ? Array.prototype.slice.call(root.querySelectorAll(selector)) : [];
7
+ }
8
+ function children(node, selector) {
9
+ if (!node) {
10
+ return [];
11
+ }
12
+ return Array.prototype.filter.call(node.children, function(each) {
13
+ return !selector || each.matches(selector);
14
+ });
15
+ }
16
+ function child(node, selector) {
17
+ return children(node, selector)[0] || null;
18
+ }
19
+ function closest(node, selector, stopAt) {
20
+ var found = node && node.nodeType === 1 ? node.closest(selector) : null;
21
+ if (found && stopAt && found !== stopAt && !stopAt.contains(found)) {
22
+ return null;
23
+ }
24
+ return found;
25
+ }
26
+ function parse(html) {
27
+ var template = document.createElement("template");
28
+ template.innerHTML = html;
29
+ return Array.prototype.slice.call(template.content.childNodes);
30
+ }
31
+ function create(html) {
32
+ var nodes = parse(html.trim());
33
+ for (var i = 0; i < nodes.length; i++) {
34
+ if (nodes[i].nodeType === 1) {
35
+ return nodes[i];
36
+ }
37
+ }
38
+ return null;
39
+ }
40
+ function element(tag, attributes, text) {
41
+ var node = document.createElement(tag);
42
+ Object.keys(attributes || {}).forEach(function(name) {
43
+ var value = attributes[name];
44
+ if (value !== null && value !== void 0 && value !== false) {
45
+ node.setAttribute(name, value);
46
+ }
47
+ });
48
+ if (text !== void 0 && text !== null) {
49
+ node.textContent = text;
50
+ }
51
+ return node;
52
+ }
53
+ function addClass(node, names) {
54
+ split(names).forEach(function(name) {
55
+ node.classList.add(name);
56
+ });
57
+ return node;
58
+ }
59
+ function removeClass(node, names) {
60
+ split(names).forEach(function(name) {
61
+ node.classList.remove(name);
62
+ });
63
+ return node;
64
+ }
65
+ function toggleClass(node, names, state) {
66
+ split(names).forEach(function(name) {
67
+ if (state === void 0) {
68
+ node.classList.toggle(name);
69
+ } else {
70
+ node.classList.toggle(name, !!state);
71
+ }
72
+ });
73
+ return node;
74
+ }
75
+ function hasClass(node, name) {
76
+ return !!node && node.nodeType === 1 && node.classList.contains(name);
77
+ }
78
+ function split(names) {
79
+ return String(names || "").split(/\s+/).filter(Boolean);
80
+ }
81
+ function dropEmptyClass(node) {
82
+ if (!node.getAttribute("class")) {
83
+ node.removeAttribute("class");
84
+ }
85
+ return node;
86
+ }
87
+ function delegate(root, types, selector, handler, options) {
88
+ var listener = function(event) {
89
+ var match = closest(event.target, selector, root);
90
+ if (match && root.contains(match)) {
91
+ return handler.call(match, event);
92
+ }
93
+ return void 0;
94
+ };
95
+ split(types).forEach(function(type) {
96
+ root.addEventListener(type, listener, options);
97
+ });
98
+ return listener;
99
+ }
100
+
101
+ // src/js/triggers/triggers.js
102
+ function triggersFor(ge, kind, idAttribute, targetAttribute, toggle) {
103
+ var triggerClass = "ge-" + kind + "-trigger";
104
+ var orphanClass = "ge-" + kind + "-orphan";
105
+ var listening = null;
106
+ function idOf(container) {
107
+ return container.getAttribute(idAttribute);
108
+ }
109
+ function exists(id, root) {
110
+ return all(root || ge.canvas, "[" + idAttribute + "]").some(function(container) {
111
+ return idOf(container) === id;
112
+ });
113
+ }
114
+ function wire() {
115
+ all(ge.canvas, "[" + targetAttribute + "]").forEach(function(trigger) {
116
+ addClass(trigger, triggerClass);
117
+ var wanted = trigger.getAttribute(targetAttribute);
118
+ trigger.removeAttribute("data-bs-toggle");
119
+ trigger.removeAttribute("data-bs-target");
120
+ if (exists(wanted)) {
121
+ removeClass(trigger, orphanClass);
122
+ return;
123
+ }
124
+ var column = trigger.closest(".column");
125
+ var nearby = column ? all(column, "[" + idAttribute + "]") : [];
126
+ if (nearby.length === 1) {
127
+ trigger.setAttribute(targetAttribute, idOf(nearby[0]));
128
+ removeClass(trigger, orphanClass);
129
+ return;
130
+ }
131
+ addClass(trigger, orphanClass);
132
+ ge.operate(function() {
133
+ ge.emit(kind + "-orphan", ge.payloadFor(kind, trigger, {
134
+ parent: trigger.parentElement,
135
+ source: "api",
136
+ missing: wanted
137
+ }));
138
+ });
139
+ });
140
+ }
141
+ function write(root) {
142
+ root = root || ge.canvas;
143
+ all(root, "[" + targetAttribute + "]").forEach(function(trigger) {
144
+ var wanted = trigger.getAttribute(targetAttribute);
145
+ removeClass(trigger, orphanClass);
146
+ dropEmptyClass(trigger);
147
+ if (!exists(wanted, root)) {
148
+ return;
149
+ }
150
+ trigger.setAttribute("data-bs-toggle", toggle);
151
+ trigger.setAttribute("data-bs-target", "#" + wanted);
152
+ });
153
+ }
154
+ return {
155
+ write,
156
+ // Triggers are markup the host owns, anywhere in the canvas, so they
157
+ // are looked at whenever the canvas is initialized rather than only
158
+ // when a container is touched
159
+ onInit: function() {
160
+ wire();
161
+ if (listening) {
162
+ listening.abort();
163
+ }
164
+ listening = new AbortController();
165
+ delegate(ge.canvas, "click", "." + triggerClass + ", [" + targetAttribute + "]", function(e) {
166
+ if (hasClass(ge.canvas, "ge-editing")) {
167
+ e.preventDefault();
168
+ }
169
+ }, { signal: listening.signal });
170
+ },
171
+ onDeinit: function() {
172
+ if (listening) {
173
+ listening.abort();
174
+ }
175
+ listening = null;
176
+ write();
177
+ }
178
+ };
179
+ }
180
+
181
+ // src/js/plugins/grideditor.offcanvas.js
182
+ Object.assign(GridEditor.locales.en, {
183
+ "container.add_offcanvas": "Offcanvas",
184
+ "container.offcanvas_title": "Title",
185
+ "container.offcanvas_trigger": "Open",
186
+ "tool.toggle_offcanvas": "Fold this offcanvas away while editing",
187
+ "container.offcanvas_section": "Offcanvas",
188
+ "container.offcanvas_placement": "Placement",
189
+ "container.offcanvas_start": "Start",
190
+ "container.offcanvas_end": "End",
191
+ "container.offcanvas_top": "Top",
192
+ "container.offcanvas_bottom": "Bottom",
193
+ "container.offcanvas_backdrop": "Backdrop",
194
+ "container.offcanvas_backdrop_yes": "Yes",
195
+ "container.offcanvas_backdrop_no": "No",
196
+ "container.offcanvas_backdrop_static": "Static",
197
+ "container.offcanvas_scroll": "Allow body scroll",
198
+ "container.offcanvas_keyboard": "Close with Esc",
199
+ "container.offcanvas_responsive": "Responsive",
200
+ "container.offcanvas_responsive_never": "Always offcanvas",
201
+ "container.offcanvas_responsive_from": "Inline from {breakpoint}",
202
+ "container.offcanvas_dark": "Dark theme"
203
+ });
204
+ var DEFAULTS = {
205
+ placement: "start",
206
+ backdrop: true,
207
+ scroll: false,
208
+ keyboard: true,
209
+ responsive: null,
210
+ dark: false
211
+ };
212
+ var KEYS = ["placement", "backdrop", "scroll", "keyboard", "responsive", "dark"];
213
+ var PLACEMENTS = ["start", "end", "top", "bottom"];
214
+ var BACKDROPS = [true, false, "static"];
215
+ var LABELS = {
216
+ placement: { labelKey: "container.offcanvas_placement" },
217
+ backdrop: { labelKey: "container.offcanvas_backdrop" },
218
+ responsive: { labelKey: "container.offcanvas_responsive" },
219
+ scroll: { labelKey: "container.offcanvas_scroll" },
220
+ keyboard: { labelKey: "container.offcanvas_keyboard" },
221
+ dark: { labelKey: "container.offcanvas_dark" }
222
+ };
223
+ var PLACEMENT_CHOICES = [
224
+ { value: "start", labelKey: "container.offcanvas_start" },
225
+ { value: "end", labelKey: "container.offcanvas_end" },
226
+ { value: "top", labelKey: "container.offcanvas_top" },
227
+ { value: "bottom", labelKey: "container.offcanvas_bottom" }
228
+ ];
229
+ var BACKDROP_CHOICES = [
230
+ { value: "true", labelKey: "container.offcanvas_backdrop_yes" },
231
+ { value: "false", labelKey: "container.offcanvas_backdrop_no" },
232
+ { value: "static", labelKey: "container.offcanvas_backdrop_static" }
233
+ ];
234
+ var fieldCounter = 0;
235
+ GridEditor.containers.offcanvas = function(ge) {
236
+ var RESPONSIVE = ge.breakpoints.filter(function(key) {
237
+ return key !== "xs";
238
+ });
239
+ var sections = [];
240
+ var triggers = triggersFor(ge, "offcanvas", "data-ge-offcanvas-id", "data-ge-offcanvas-target", "offcanvas");
241
+ var CHECKS = {
242
+ placement: function(value) {
243
+ return PLACEMENTS.indexOf(value) !== -1;
244
+ },
245
+ backdrop: function(value) {
246
+ return BACKDROPS.indexOf(value) !== -1;
247
+ },
248
+ responsive: function(value) {
249
+ return value === null || RESPONSIVE.indexOf(value) !== -1;
250
+ }
251
+ };
252
+ function isValid(key, value) {
253
+ return CHECKS[key] ? CHECKS[key](value) : typeof value === "boolean";
254
+ }
255
+ function takes(key) {
256
+ if (key === "placement") {
257
+ return JSON.stringify(PLACEMENTS);
258
+ }
259
+ if (key === "backdrop") {
260
+ return JSON.stringify(BACKDROPS);
261
+ }
262
+ if (key === "responsive") {
263
+ return JSON.stringify([null].concat(RESPONSIVE));
264
+ }
265
+ return "[true,false]";
266
+ }
267
+ function chosen(options, key) {
268
+ var setting = ge.settings.offcanvas || {};
269
+ var value = options[key] !== void 0 ? options[key] : setting[key];
270
+ if (value === void 0) {
271
+ return DEFAULTS[key];
272
+ }
273
+ if (isValid(key, value)) {
274
+ return value;
275
+ }
276
+ ge.warn("offcanvas: " + JSON.stringify(value) + " is not a " + key + ", which takes " + takes(key) + ": " + JSON.stringify(DEFAULTS[key]) + " is used");
277
+ return DEFAULTS[key];
278
+ }
279
+ function isPanelClass(name) {
280
+ return name === "offcanvas" || /^offcanvas-/.test(name) && RESPONSIVE.indexOf(name.slice(10)) !== -1;
281
+ }
282
+ function isPanel(node) {
283
+ return Array.prototype.some.call(node.classList, isPanelClass);
284
+ }
285
+ function panelOf(container) {
286
+ var id = container.getAttribute("data-ge-offcanvas-id");
287
+ var own = children(container);
288
+ return own.filter(function(node) {
289
+ return id && node.id === id;
290
+ })[0] || own.filter(isPanel)[0] || null;
291
+ }
292
+ function triggerOf(container) {
293
+ return child(container, "[data-ge-offcanvas-target]");
294
+ }
295
+ function dropTriggerMarks(root) {
296
+ all(root, ".ge-offcanvas-trigger").forEach(function(trigger) {
297
+ removeClass(trigger, "ge-offcanvas-trigger");
298
+ dropEmptyClass(trigger);
299
+ });
300
+ }
301
+ function hideClass(responsive) {
302
+ return "d-" + responsive + "-none";
303
+ }
304
+ function read(container) {
305
+ var panel = panelOf(container);
306
+ var backdrop = panel.getAttribute("data-bs-backdrop");
307
+ var responsive = null;
308
+ Array.prototype.forEach.call(panel.classList, function(name) {
309
+ if (name !== "offcanvas" && isPanelClass(name)) {
310
+ responsive = name.slice(10);
311
+ }
312
+ });
313
+ return {
314
+ placement: PLACEMENTS.filter(function(place) {
315
+ return hasClass(panel, "offcanvas-" + place);
316
+ })[0] || "start",
317
+ backdrop: backdrop === "false" ? false : backdrop === "static" ? "static" : true,
318
+ scroll: panel.getAttribute("data-bs-scroll") === "true",
319
+ keyboard: panel.getAttribute("data-bs-keyboard") !== "false",
320
+ responsive,
321
+ dark: panel.getAttribute("data-bs-theme") === "dark"
322
+ };
323
+ }
324
+ function setAttribute(panel, name, value) {
325
+ if (value === null) {
326
+ panel.removeAttribute(name);
327
+ } else {
328
+ panel.setAttribute(name, value);
329
+ }
330
+ }
331
+ function write(container, key, value) {
332
+ var panel = panelOf(container);
333
+ if (key === "placement") {
334
+ PLACEMENTS.forEach(function(place) {
335
+ removeClass(panel, "offcanvas-" + place);
336
+ });
337
+ addClass(panel, "offcanvas-" + value);
338
+ }
339
+ if (key === "backdrop") {
340
+ setAttribute(panel, "data-bs-backdrop", value === true ? null : String(value));
341
+ }
342
+ if (key === "scroll") {
343
+ setAttribute(panel, "data-bs-scroll", value ? "true" : null);
344
+ }
345
+ if (key === "keyboard") {
346
+ setAttribute(panel, "data-bs-keyboard", value ? null : "false");
347
+ }
348
+ if (key === "responsive") {
349
+ var before = read(container).responsive;
350
+ var trigger = triggerOf(container);
351
+ var rest = Array.prototype.filter.call(panel.classList, function(name) {
352
+ return !isPanelClass(name);
353
+ });
354
+ panel.className = [value === null ? "offcanvas" : "offcanvas-" + value].concat(rest).join(" ");
355
+ if (trigger) {
356
+ if (before !== null) {
357
+ removeClass(trigger, hideClass(before));
358
+ }
359
+ if (value !== null) {
360
+ addClass(trigger, hideClass(value));
361
+ }
362
+ dropEmptyClass(trigger);
363
+ }
364
+ }
365
+ if (key === "dark") {
366
+ if (value) {
367
+ panel.setAttribute("data-bs-theme", "dark");
368
+ } else if (panel.getAttribute("data-bs-theme") === "dark") {
369
+ panel.removeAttribute("data-bs-theme");
370
+ }
371
+ }
372
+ }
373
+ function nextId() {
374
+ return "ge-offcanvas-option-" + ++fieldCounter;
375
+ }
376
+ function field(labelKey, control, id) {
377
+ var box = element("div", { "class": "ge-offcanvas-option mb-2" });
378
+ box.appendChild(element("label", { "class": "form-label", "for": id }, ge.t(labelKey)));
379
+ box.appendChild(control);
380
+ return box;
381
+ }
382
+ function checkbox(labelKey, onChange) {
383
+ var id = nextId();
384
+ var box = element("div", { "class": "form-check" });
385
+ var input = box.appendChild(element("input", { "class": "form-check-input", type: "checkbox", id }));
386
+ box.appendChild(element("label", { "class": "form-check-label", "for": id }, ge.t(labelKey)));
387
+ input.addEventListener("change", function() {
388
+ onChange(input.checked);
389
+ });
390
+ return { box, input };
391
+ }
392
+ function select(choices, onChange) {
393
+ var id = nextId();
394
+ var control = element("select", { "class": "form-select form-select-sm", id });
395
+ choices.forEach(function(choice) {
396
+ control.appendChild(element("option", { value: choice.value }, choice.label));
397
+ });
398
+ control.addEventListener("change", function() {
399
+ onChange(control.value);
400
+ });
401
+ return { id, control };
402
+ }
403
+ function createSection(container) {
404
+ var body = element("div", { "class": "ge-offcanvas-options" });
405
+ function change(key, value) {
406
+ write(container, key, value);
407
+ render();
408
+ }
409
+ var translated = function(choice) {
410
+ return { value: choice.value, label: ge.t(choice.labelKey) };
411
+ };
412
+ var selects = {
413
+ placement: select(PLACEMENT_CHOICES.map(translated), function(value) {
414
+ change("placement", value);
415
+ }),
416
+ backdrop: select(BACKDROP_CHOICES.map(translated), function(value) {
417
+ change("backdrop", value === "static" ? "static" : value === "true");
418
+ }),
419
+ responsive: select([{ value: "", label: ge.t("container.offcanvas_responsive_never") }].concat(
420
+ RESPONSIVE.map(function(key) {
421
+ return { value: key, label: ge.t("container.offcanvas_responsive_from", { breakpoint: key }) };
422
+ })
423
+ ), function(value) {
424
+ change("responsive", value === "" ? null : value);
425
+ })
426
+ };
427
+ Object.keys(selects).forEach(function(key) {
428
+ var box = field(LABELS[key].labelKey, selects[key].control, selects[key].id);
429
+ box.setAttribute("data-ge-offcanvas-option", key);
430
+ body.appendChild(box);
431
+ });
432
+ var inputs = {};
433
+ ["scroll", "keyboard", "dark"].forEach(function(key) {
434
+ var each = checkbox(LABELS[key].labelKey, function(on) {
435
+ change(key, on);
436
+ });
437
+ inputs[key] = each.input;
438
+ each.box.setAttribute("data-ge-offcanvas-option", key);
439
+ body.appendChild(each.box);
440
+ });
441
+ function render() {
442
+ var values = read(container);
443
+ selects.placement.control.value = values.placement;
444
+ selects.backdrop.control.value = String(values.backdrop);
445
+ selects.responsive.control.value = values.responsive === null ? "" : values.responsive;
446
+ Object.keys(inputs).forEach(function(key) {
447
+ inputs[key].checked = values[key];
448
+ });
449
+ }
450
+ render();
451
+ sections.push({ node: container, element: body, render });
452
+ return body;
453
+ }
454
+ return {
455
+ labelKey: "container.add_offcanvas",
456
+ paneKind: "offcanvas",
457
+ // The ids a copy of an offcanvas has to rename together
458
+ references: ["data-ge-offcanvas-id", "data-ge-offcanvas-target"],
459
+ onInit: triggers.onInit,
460
+ onDeinit: function() {
461
+ sections = [];
462
+ triggers.onDeinit();
463
+ dropTriggerMarks(ge.canvas);
464
+ },
465
+ // What onDeinit and unmark do, on a copy of the canvas
466
+ cleanMarkup: function(root) {
467
+ var definition = this;
468
+ triggers.write(root);
469
+ dropTriggerMarks(root);
470
+ all(root, '[data-ge-container="offcanvas"]').forEach(function(container) {
471
+ definition.unmark(container);
472
+ });
473
+ },
474
+ create: function(options) {
475
+ options = options || {};
476
+ var id = ge.containerId("offcanvas");
477
+ var container = element("div", { "data-ge-container": "offcanvas", "data-ge-offcanvas-id": id });
478
+ if (options.trigger !== false) {
479
+ container.appendChild(element("button", {
480
+ type: "button",
481
+ "class": "btn btn-primary ge-offcanvas-trigger",
482
+ "data-ge-offcanvas-target": id
483
+ }, options.trigger_label || ge.t("container.offcanvas_trigger")));
484
+ }
485
+ var panel = container.appendChild(element("div", {
486
+ "class": "offcanvas",
487
+ tabindex: "-1",
488
+ id,
489
+ "aria-labelledby": id + "-label"
490
+ }));
491
+ var header = panel.appendChild(element("div", { "class": "offcanvas-header" }));
492
+ header.appendChild(element("h5", { "class": "offcanvas-title", id: id + "-label" })).appendChild(element(
493
+ "span",
494
+ { "class": "ge-pane-label" },
495
+ options.title || ge.t("container.offcanvas_title")
496
+ ));
497
+ header.appendChild(create('<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>'));
498
+ panel.appendChild(element("div", { "class": "offcanvas-body" })).appendChild(ge.defaultRegion());
499
+ KEYS.forEach(function(key) {
500
+ write(container, key, chosen(options, key));
501
+ });
502
+ return container;
503
+ },
504
+ mark: function(container) {
505
+ var header = child(panelOf(container), ".offcanvas-header");
506
+ all(header, "[data-bs-dismiss]").forEach(function(dismiss) {
507
+ ge.suspendToggles(dismiss);
508
+ });
509
+ all(header, ".offcanvas-title").forEach(function(title) {
510
+ ge.makeLabelEditable(ge.labelIn(title));
511
+ });
512
+ },
513
+ unmark: function(container) {
514
+ var header = child(panelOf(container), ".offcanvas-header");
515
+ if (header) {
516
+ ge.resumeToggles(header);
517
+ ge.unwrapLabels(header);
518
+ }
519
+ removeClass(container, "ge-offcanvas-collapsed");
520
+ },
521
+ /** A page of unfolded panels stays workable if they can be folded away. */
522
+ tools: function(drawer, container) {
523
+ ge.createTool(
524
+ drawer,
525
+ ge.t("tool.toggle_offcanvas"),
526
+ "ge-toggle-offcanvas",
527
+ "bi bi-chevron-bar-contract",
528
+ function() {
529
+ toggleClass(container, "ge-offcanvas-collapsed");
530
+ }
531
+ );
532
+ },
533
+ panelSection: function(node, kind) {
534
+ if (kind === "offcanvas" && panelOf(node)) {
535
+ return { labelKey: "container.offcanvas_section", body: createSection(node) };
536
+ }
537
+ return null;
538
+ },
539
+ // After a view change or a change of classes: the sections follow
540
+ onRefresh: function(scope) {
541
+ sections = sections.filter(function(entry) {
542
+ return entry.element.isConnected;
543
+ });
544
+ sections.forEach(function(entry) {
545
+ if (entry.node === scope || scope.contains(entry.node)) {
546
+ entry.render();
547
+ }
548
+ });
549
+ }
550
+ };
551
+ };