fix(#7143): add eslint-plugin-no-sanitize and fix errors (#7144)

This commit is contained in:
Jesse Mazzella
2023-10-16 09:26:12 -07:00
committed by GitHub
parent 76889cf60d
commit 9849e0398e
11 changed files with 114 additions and 64 deletions

View File

@ -15,7 +15,8 @@ module.exports = {
'plugin:compat/recommended', 'plugin:compat/recommended',
'plugin:vue/vue3-recommended', 'plugin:vue/vue3-recommended',
'plugin:you-dont-need-lodash-underscore/compatible', 'plugin:you-dont-need-lodash-underscore/compatible',
'plugin:prettier/recommended' 'plugin:prettier/recommended',
'plugin:no-unsanitized/DOM'
], ],
parser: 'vue-eslint-parser', parser: 'vue-eslint-parser',
parserOptions: { parserOptions: {

View File

@ -27,6 +27,7 @@
"eslint": "8.48.0", "eslint": "8.48.0",
"eslint-config-prettier": "9.0.0", "eslint-config-prettier": "9.0.0",
"eslint-plugin-compat": "4.2.0", "eslint-plugin-compat": "4.2.0",
"eslint-plugin-no-unsanitized": "4.0.2",
"eslint-plugin-playwright": "0.12.0", "eslint-plugin-playwright": "0.12.0",
"eslint-plugin-prettier": "4.2.1", "eslint-plugin-prettier": "4.2.1",
"eslint-plugin-simple-import-sort": "10.0.0", "eslint-plugin-simple-import-sort": "10.0.0",

View File

@ -161,8 +161,11 @@ export default {
let originalClassName = this.dragGhost.classList[0]; let originalClassName = this.dragGhost.classList[0];
this.dragGhost.className = ''; this.dragGhost.className = '';
this.dragGhost.classList.add(originalClassName, iconClass); this.dragGhost.classList.add(originalClassName, iconClass);
this.dragGhost.textContent = '';
const span = document.createElement('span');
span.textContent = this.domainObject.name;
this.dragGhost.appendChild(span);
this.dragGhost.innerHTML = `<span>${this.domainObject.name}</span>`;
event.dataTransfer.setDragImage(this.dragGhost, 0, 0); event.dataTransfer.setDragImage(this.dragGhost, 0, 0);
} }

View File

@ -20,12 +20,10 @@
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<!-- eslint-disable vue/no-v-html -->
<template> <template>
<div class="gl-plot-chart-area"> <div class="gl-plot-chart-area">
<span v-html="canvasTemplate"></span> <canvas :style="canvasStyle"></canvas>
<span v-html="canvasTemplate"></span> <canvas :style="canvasStyle"></canvas>
<div ref="limitArea" class="js-limit-area"> <div ref="limitArea" class="js-limit-area">
<limit-label <limit-label
v-for="(limitLabel, index) in visibleLimitLabels" v-for="(limitLabel, index) in visibleLimitLabels"
@ -147,12 +145,20 @@ export default {
emits: ['chart-loaded', 'plot-reinitialize-canvas'], emits: ['chart-loaded', 'plot-reinitialize-canvas'],
data() { data() {
return { return {
canvasTemplate:
'<canvas style="position: absolute; background: none; width: 100%; height: 100%;"></canvas>',
visibleLimitLabels: [], visibleLimitLabels: [],
visibleLimitLines: [] visibleLimitLines: []
}; };
}, },
computed: {
canvasStyle() {
return {
position: 'absolute',
background: 'none',
width: '100%',
height: '100%'
};
}
},
watch: { watch: {
highlights: { highlights: {
handler() { handler() {
@ -488,7 +494,10 @@ export default {
// Have to throw away the old canvas elements and replace with new // Have to throw away the old canvas elements and replace with new
// canvas elements in order to get new drawing contexts. // canvas elements in order to get new drawing contexts.
const div = document.createElement('div'); const div = document.createElement('div');
div.innerHTML = this.canvasTemplate + this.canvasTemplate; div.innerHTML = `
<canvas style="position: absolute; background: none; width: 100%; height: 100%;"></canvas>
<canvas style="position: absolute; background: none; width: 100%; height: 100%;"></canvas>
`;
const mainCanvas = div.querySelectorAll('canvas')[1]; const mainCanvas = div.querySelectorAll('canvas')[1];
const overlayCanvas = div.querySelectorAll('canvas')[0]; const overlayCanvas = div.querySelectorAll('canvas')[0];
this.canvas.parentNode.replaceChild(mainCanvas, this.canvas); this.canvas.parentNode.replaceChild(mainCanvas, this.canvas);

View File

@ -214,7 +214,7 @@ define([
const options = this.generateSelectOptions(); const options = this.generateSelectOptions();
newInput = document.createElement('select'); newInput = document.createElement('select');
newInput.innerHTML = options; newInput.appendChild(options);
emitChange = true; emitChange = true;
} else { } else {
@ -244,12 +244,16 @@ define([
Condition.prototype.generateSelectOptions = function () { Condition.prototype.generateSelectOptions = function () {
let telemetryMetadata = this.conditionManager.getTelemetryMetadata(this.config.object); let telemetryMetadata = this.conditionManager.getTelemetryMetadata(this.config.object);
let options = ''; let fragment = document.createDocumentFragment();
telemetryMetadata[this.config.key].enumerations.forEach((enumeration) => { telemetryMetadata[this.config.key].enumerations.forEach((enumeration) => {
options += '<option value="' + enumeration.value + '">' + enumeration.string + '</option>'; const option = document.createElement('option');
option.value = enumeration.value;
option.textContent = enumeration.string;
fragment.appendChild(option);
}); });
return options; return fragment;
}; };
return Condition; return Condition;

View File

@ -167,7 +167,8 @@ define([
const ruleHeader = self.domElement const ruleHeader = self.domElement
.querySelectorAll('.widget-rule-header')[0] .querySelectorAll('.widget-rule-header')[0]
.cloneNode(true); .cloneNode(true);
indicator.innerHTML = ruleHeader; indicator.textContent = '';
indicator.appendChild(ruleHeader);
}); });
self.widgetDnD.setDragImage( self.widgetDnD.setDragImage(
self.domElement.querySelectorAll('.widget-rule-header')[0].cloneNode(true) self.domElement.querySelectorAll('.widget-rule-header')[0].cloneNode(true)
@ -239,8 +240,8 @@ define([
this.listenTo(this.toggleConfigButton, 'click', toggleConfig); this.listenTo(this.toggleConfigButton, 'click', toggleConfig);
this.listenTo(this.trigger, 'change', onTriggerInput); this.listenTo(this.trigger, 'change', onTriggerInput);
this.title.innerHTML = self.config.name; this.title.innerText = self.config.name;
this.description.innerHTML = self.config.description; this.description.innerText = self.config.description;
this.trigger.value = self.config.trigger; this.trigger.value = self.config.trigger;
this.listenTo(this.grippy, 'mousedown', onDragStart); this.listenTo(this.grippy, 'mousedown', onDragStart);
@ -456,7 +457,7 @@ define([
const lastOfType = self.conditionArea.querySelector('li:last-of-type'); const lastOfType = self.conditionArea.querySelector('li:last-of-type');
lastOfType.parentNode.insertBefore($condition, lastOfType); lastOfType.parentNode.insertBefore($condition, lastOfType);
if (loopCnt > 0) { if (loopCnt > 0) {
$condition.querySelector('.t-condition-context').innerHTML = triggerContextStr + ' when'; $condition.querySelector('.t-condition-context').innerText = triggerContextStr + ' when';
} }
loopCnt++; loopCnt++;
@ -528,7 +529,7 @@ define([
} }
description = description === '' ? this.config.description : description; description = description === '' ? this.config.description : description;
this.description.innerHTML = self.config.description; this.description.innerText = self.config.description;
this.config.description = description; this.config.description = description;
}; };

View File

@ -247,9 +247,10 @@ define([
SummaryWidget.prototype.updateWidget = function () { SummaryWidget.prototype.updateWidget = function () {
const WIDGET_ICON_CLASS = 'c-sw__icon js-sw__icon'; const WIDGET_ICON_CLASS = 'c-sw__icon js-sw__icon';
const activeRule = this.rulesById[this.activeId]; const activeRule = this.rulesById[this.activeId];
this.applyStyle(this.domElement.querySelector('#widget'), activeRule.getProperty('style')); this.applyStyle(this.domElement.querySelector('#widget'), activeRule.getProperty('style'));
this.domElement.querySelector('#widget').title = activeRule.getProperty('message'); this.domElement.querySelector('#widget').title = activeRule.getProperty('message');
this.domElement.querySelector('#widgetLabel').innerHTML = activeRule.getProperty('label'); this.domElement.querySelector('#widgetLabel').textContent = activeRule.getProperty('label');
this.domElement.querySelector('#widgetIcon').classList = this.domElement.querySelector('#widgetIcon').classList =
WIDGET_ICON_CLASS + ' ' + activeRule.getProperty('icon'); WIDGET_ICON_CLASS + ' ' + activeRule.getProperty('icon');
}; };

View File

@ -44,11 +44,12 @@ define([
self.setNullOption(this.nullOption); self.setNullOption(this.nullOption);
self.items.forEach(function (item) { self.items.forEach(function (item) {
const itemElement = `<div class = "c-palette__item ${item}" data-item = "${item}"></div>`; const itemElement = document.createElement('div');
const temp = document.createElement('div'); itemElement.className = 'c-palette__item ' + item;
temp.innerHTML = itemElement; itemElement.setAttribute('data-item', item);
self.itemElements[item] = temp.firstChild;
self.domElement.querySelector('.c-palette__items').appendChild(temp.firstChild); self.itemElements[item] = itemElement;
self.domElement.querySelector('.c-palette__items').appendChild(itemElement);
}); });
self.domElement.querySelector('.c-menu').style.display = 'none'; self.domElement.querySelector('.c-menu').style.display = 'none';

View File

@ -1,35 +1,60 @@
define(['./summary-widget.html', '@braintree/sanitize-url'], function ( import * as urlSanitizeLib from '@braintree/sanitize-url';
summaryWidgetTemplate,
urlSanitizeLib
) {
const WIDGET_ICON_CLASS = 'c-sw__icon js-sw__icon';
function SummaryWidgetView(domainObject, openmct) { const WIDGET_ICON_CLASS = 'c-sw__icon js-sw__icon';
class SummaryWidgetView {
#createSummaryWidgetTemplate() {
const anchor = document.createElement('a');
anchor.classList.add(
't-summary-widget',
'c-summary-widget',
'js-sw',
'u-links',
'u-fills-container'
);
const widgetIcon = document.createElement('div');
widgetIcon.id = 'widgetIcon';
widgetIcon.classList.add('c-sw__icon', 'js-sw__icon');
anchor.appendChild(widgetIcon);
const widgetLabel = document.createElement('div');
widgetLabel.id = 'widgetLabel';
widgetLabel.classList.add('c-sw__label', 'js-sw__label');
widgetLabel.textContent = 'Loading...';
anchor.appendChild(widgetLabel);
return anchor;
}
constructor(domainObject, openmct) {
this.openmct = openmct; this.openmct = openmct;
this.domainObject = domainObject; this.domainObject = domainObject;
this.hasUpdated = false; this.hasUpdated = false;
this.render = this.render.bind(this); this.render = this.render.bind(this);
} }
SummaryWidgetView.prototype.updateState = function (datum) { updateState(datum) {
this.hasUpdated = true; this.hasUpdated = true;
this.widget.style.color = datum.textColor; this.widget.style.color = datum.textColor;
this.widget.style.backgroundColor = datum.backgroundColor; this.widget.style.backgroundColor = datum.backgroundColor;
this.widget.style.borderColor = datum.borderColor; this.widget.style.borderColor = datum.borderColor;
this.widget.title = datum.message; this.widget.title = datum.message;
this.label.title = datum.message; this.label.title = datum.message;
this.label.innerHTML = datum.ruleLabel; this.label.textContent = datum.ruleLabel;
this.icon.className = WIDGET_ICON_CLASS + ' ' + datum.icon; this.icon.className = WIDGET_ICON_CLASS + ' ' + datum.icon;
}; }
SummaryWidgetView.prototype.render = function () { render() {
if (this.unsubscribe) { if (this.unsubscribe) {
this.unsubscribe(); this.unsubscribe();
} }
this.hasUpdated = false; this.hasUpdated = false;
this.container.innerHTML = summaryWidgetTemplate; const anchor = this.#createSummaryWidgetTemplate();
this.container.appendChild(anchor);
this.widget = this.container.querySelector('a'); this.widget = this.container.querySelector('a');
this.icon = this.container.querySelector('#widgetIcon'); this.icon = this.container.querySelector('#widgetIcon');
this.label = this.container.querySelector('.js-sw__label'); this.label = this.container.querySelector('.js-sw__label');
@ -49,13 +74,13 @@ define(['./summary-widget.html', '@braintree/sanitize-url'], function (
const renderTracker = {}; const renderTracker = {};
this.renderTracker = renderTracker; this.renderTracker = renderTracker;
this.openmct.telemetry this.openmct.telemetry
.request(this.domainObject, { .request(this.domainObject, {
strategy: 'latest', strategy: 'latest',
size: 1 size: 1
}) })
.then( .then((results) => {
function (results) {
if ( if (
this.destroyed || this.destroyed ||
this.hasUpdated || this.hasUpdated ||
@ -66,16 +91,15 @@ define(['./summary-widget.html', '@braintree/sanitize-url'], function (
} }
this.updateState(results[results.length - 1]); this.updateState(results[results.length - 1]);
}.bind(this) });
);
this.unsubscribe = this.openmct.telemetry.subscribe( this.unsubscribe = this.openmct.telemetry.subscribe(
this.domainObject, this.domainObject,
this.updateState.bind(this) this.updateState.bind(this)
); );
}; }
SummaryWidgetView.prototype.show = function (container) { show(container) {
this.container = container; this.container = container;
this.render(); this.render();
this.removeMutationListener = this.openmct.objects.observe( this.removeMutationListener = this.openmct.objects.observe(
@ -84,14 +108,14 @@ define(['./summary-widget.html', '@braintree/sanitize-url'], function (
this.onMutation.bind(this) this.onMutation.bind(this)
); );
this.openmct.time.on('timeSystem', this.render); this.openmct.time.on('timeSystem', this.render);
}; }
SummaryWidgetView.prototype.onMutation = function (domainObject) { onMutation(domainObject) {
this.domainObject = domainObject; this.domainObject = domainObject;
this.render(); this.render();
}; }
SummaryWidgetView.prototype.destroy = function (container) { destroy() {
this.unsubscribe(); this.unsubscribe();
this.removeMutationListener(); this.removeMutationListener();
this.openmct.time.off('timeSystem', this.render); this.openmct.time.off('timeSystem', this.render);
@ -100,7 +124,7 @@ define(['./summary-widget.html', '@braintree/sanitize-url'], function (
delete this.label; delete this.label;
delete this.openmct; delete this.openmct;
delete this.domainObject; delete this.domainObject;
}; }
}
return SummaryWidgetView; export default SummaryWidgetView;
});

View File

@ -1,4 +0,0 @@
<a class="t-summary-widget c-summary-widget js-sw u-links u-fills-container">
<div id="widgetIcon" class="c-sw__icon js-sw__icon"></div>
<div id="widgetLabel" class="c-sw__label js-sw__label">Loading...</div>
</a>

View File

@ -1,8 +1,17 @@
export function convertTemplateToHTML(templateString) { export function convertTemplateToHTML(templateString) {
const template = document.createElement('template'); const parser = new DOMParser();
template.innerHTML = templateString; const doc = parser.parseFromString(templateString, 'text/html');
return template.content.cloneNode(true).children; // Create a document fragment to hold the parsed content
const fragment = document.createDocumentFragment();
// Append nodes from the parsed content to the fragment
while (doc.body.firstChild) {
fragment.appendChild(doc.body.firstChild);
}
// Convert children of the fragment to an array and return
return Array.from(fragment.children);
} }
export function toggleClass(element, className) { export function toggleClass(element, className) {