mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
feat(ui): render the generated style parameter rows through Vue
This commit is contained in:
1 parent
926253e8a3
commit
bca7495cbf
9 files changed
+223
-202
No files matched your search
@@ -1437,11 +1437,11 @@ The application supplies actions and retains effect settings, restore claims and
|
||||
rendering. Native keyboard editing, model modes and current defaults are preserved.
|
||||
Destroying the UI removes these listeners before asynchronous teardown.
|
||||
|
||||
Ordinary sliders share the native range component in `ui/slider.js` and the
|
||||
`gev-quantitative-slider` surface in `ui/styles/slider.css`. Display, shader
|
||||
Ordinary sliders share the native `gev-quantitative-slider` surface in
|
||||
`ui/styles/slider.css`. Display, shader
|
||||
parameters, volume, replay speed, weather settings/history, imagery opacity and
|
||||
Street View's date filter use the same rail, thumb, value styling, keyboard focus and disabled state.
|
||||
Generated controls use `createSlider`; static templates and components apply the same class.
|
||||
Templates, components and generated controls apply the same class.
|
||||
Feature owners retain bounds, steps, formatted values, input/change timing and
|
||||
listener cleanup. The radio tuning dial, imagery comparison divider and event
|
||||
comparison/progression controls keep their specialized presentation and behavior.
|
||||
|
||||
@@ -96,8 +96,11 @@ They contain no application state.
|
||||
descriptor before acting), Display (in progress: `DisplayPanel` renders
|
||||
the HUD, Sonar, Scope, Celestial, detection, bloom and sharpen from the
|
||||
`gev-display` store, which VisualSettings publishes to, and the 3D
|
||||
aircraft group, which AircraftDisplay publishes beside it; the other
|
||||
groups follow one owner at a time), Context and Radio, the command dock,
|
||||
aircraft group, which AircraftDisplay publishes beside it; the style
|
||||
parameter rows render through Vue behind `createStyleParameters()`, as a
|
||||
render function so the portable `./ui/input` entry needs no component
|
||||
compiler; the other groups follow one owner at a time),
|
||||
Context and Radio, the command dock,
|
||||
the phone shell, then Cockpit. Layers that write into the right rail
|
||||
directly gain a slot instead.
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
"src/ui/visualInput.js",
|
||||
"src/ui/applicationShortcuts.js",
|
||||
"src/ui/styleParameters.js",
|
||||
"src/ui/slider.js",
|
||||
"src/ui/rail/rangeValue.js",
|
||||
"src/i18n/index.js",
|
||||
"src/i18n/locale.js",
|
||||
"src/i18n/locales/de.json",
|
||||
@@ -493,7 +493,7 @@
|
||||
"src/i18n/locales/zh-CN.json",
|
||||
"src/i18n/locales/zh-Hant.json"
|
||||
],
|
||||
"external": []
|
||||
"external": ["vue"]
|
||||
},
|
||||
"display-controls": {
|
||||
"exports": ["./ui/display"],
|
||||
@@ -550,7 +550,6 @@
|
||||
"src/ui/weatherPanel.js",
|
||||
"src/ui/railCards.js",
|
||||
"src/ui/railCardBlocks.js",
|
||||
"src/ui/slider.js",
|
||||
"src/ui/layerRowText.js",
|
||||
"src/ui/layerPanel/LayerRows.vue",
|
||||
"src/ui/layerPanel/RowText.vue",
|
||||
@@ -896,7 +895,6 @@
|
||||
"src/ui/shellElements.js",
|
||||
"src/ui/shellFeedback.js",
|
||||
"src/ui/styleParameters.js",
|
||||
"src/ui/slider.js",
|
||||
"src/ui/surfaceKeyboard.js",
|
||||
"src/ui/uiLifetime.js",
|
||||
"src/ui/visualEffects.js",
|
||||
@@ -2591,7 +2589,6 @@
|
||||
"src/ui/shellElements.js",
|
||||
"src/ui/shellFeedback.js",
|
||||
"src/ui/styleParameters.js",
|
||||
"src/ui/slider.js",
|
||||
"src/ui/surfaceKeyboard.js",
|
||||
"src/ui/uiLifetime.js",
|
||||
"src/ui/visualEffects.js",
|
||||
@@ -3669,7 +3666,7 @@
|
||||
"src/ui/applicationShortcuts.js",
|
||||
"src/ui/effects.js",
|
||||
"src/ui/styleParameters.js",
|
||||
"src/ui/slider.js",
|
||||
"src/ui/rail/rangeValue.js",
|
||||
"src/ui/uiLifetime.js",
|
||||
"src/ui/visualEffects.js",
|
||||
"src/ui/visualInput.js",
|
||||
|
||||
@@ -28,6 +28,7 @@ test('the first-run checkbox keeps its native visible label', () => {
|
||||
});
|
||||
|
||||
test('generated style sliders use the visible parameter label as their name', () => {
|
||||
assert.match(parameters, /label\.textContent\s*=\s*t\(metadata\.label\);/);
|
||||
assert.match(parameters, /ariaLabel:\s*t\(metadata\.label\)/);
|
||||
assert.match(parameters, /label:\s*t\(metadata\.label\),/);
|
||||
assert.match(parameters, /h\('span', \{ class: 'param-label' \}, row\.label\)/);
|
||||
assert.match(parameters, /'aria-label': row\.label,/);
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
import '../testSupport/registerDom.mjs';
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
@@ -18,6 +19,9 @@ import {
|
||||
} from '../data/detection.js';
|
||||
|
||||
const pause = async () => {};
|
||||
// The page fixture swaps the globals for stand-ins; generated rows render
|
||||
// into a real element, so keep the registered document.
|
||||
const realDocument = globalThis.document;
|
||||
class Element extends EventTarget {
|
||||
constructor() {
|
||||
super();
|
||||
@@ -67,8 +71,7 @@ function pageFixture(t) {
|
||||
const label = selector.match(/aria-label="([^"]+)"/)[1];
|
||||
return elements
|
||||
.get('param-sliders')
|
||||
.children.flatMap((row) => row.children)
|
||||
.find((el) => el.getAttribute('aria-label') === label);
|
||||
.querySelector(`input.param-slider[aria-label="${label}"]`);
|
||||
}
|
||||
return elements.get(selector.slice(1));
|
||||
};
|
||||
@@ -128,8 +131,7 @@ test('live visual cities follow local operating hours in summer and winter', ()
|
||||
|
||||
test('thermal controls wait for activation and use the real generated parameter rows', async (t) => {
|
||||
const { page, document, elements } = pageFixture(t);
|
||||
const container = new Element();
|
||||
container.ownerDocument = document;
|
||||
const container = realDocument.createElement('div');
|
||||
elements.set('param-sliders', container);
|
||||
const parameters = createStyleParameters({ container });
|
||||
t.after(() => parameters.destroy());
|
||||
@@ -159,9 +161,7 @@ test('thermal controls wait for activation and use the real generated parameter
|
||||
page.$eval = async (selector, fn, ...args) => {
|
||||
if (selector.startsWith('.style-btn')) return fn(new Element(), ...args);
|
||||
const label = selector.match(/aria-label="([^"]+)"/)[1];
|
||||
const slider = container.children
|
||||
.flatMap((row) => row.children)
|
||||
.find((el) => el.getAttribute('aria-label') === label);
|
||||
const slider = container.querySelector(`[aria-label="${label}"]`);
|
||||
assert.ok(slider);
|
||||
return fn(slider, ...args);
|
||||
};
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Build the shared native slider. Feature owners retain their input/change
|
||||
* listeners, formatting and teardown; this component installs no handlers.
|
||||
* Static sliders use the same gev-quantitative-slider class in their template.
|
||||
* @param {object} options
|
||||
* @param {Document} [options.documentRef] Document that owns the input.
|
||||
* @param {string} [options.className] Additional feature/layout hooks.
|
||||
* @param {number|string} [options.min]
|
||||
* @param {number|string} [options.max]
|
||||
* @param {number|string} [options.step]
|
||||
* @param {number|string} [options.value]
|
||||
* @param {string} [options.ariaLabel] Already translated accessible name.
|
||||
* @returns {HTMLInputElement}
|
||||
*/
|
||||
export function createSlider({
|
||||
documentRef = globalThis.document,
|
||||
className = '',
|
||||
min,
|
||||
max,
|
||||
step,
|
||||
value,
|
||||
ariaLabel,
|
||||
} = {}) {
|
||||
const input = documentRef.createElement('input');
|
||||
input.type = 'range';
|
||||
input.className = `gev-quantitative-slider${className ? ` ${className}` : ''}`;
|
||||
for (const [key, setting] of Object.entries({ min, max, step, value })) {
|
||||
if (setting !== undefined) input[key] = setting;
|
||||
}
|
||||
if (ariaLabel !== undefined) input.setAttribute('aria-label', ariaLabel);
|
||||
return input;
|
||||
}
|
||||
+78
-44
@@ -1,5 +1,6 @@
|
||||
import { h, render, withDirectives } from 'vue';
|
||||
import { formatNumber, t } from '../i18n/index.js';
|
||||
import { createSlider } from './slider.js';
|
||||
import { vRangeValue } from './rail/rangeValue.js';
|
||||
|
||||
/** A slider value in the UI language: 0.85 in English, 0,85 in Spanish. */
|
||||
const formatParam = (value, digits) =>
|
||||
@@ -10,65 +11,98 @@ const formatParam = (value, digits) =>
|
||||
});
|
||||
|
||||
/**
|
||||
* Own generated parameter rows and their input listeners.
|
||||
* The generated rows: a label, the shared native slider and its value in the
|
||||
* UI language. A render function, so the portable input package needs no
|
||||
* single-file-component compiler.
|
||||
*/
|
||||
const StyleParameterRows = {
|
||||
props: {
|
||||
rows: { type: Array, required: true },
|
||||
onInput: { type: Function, required: true },
|
||||
},
|
||||
render() {
|
||||
return this.rows.map((row) =>
|
||||
h('div', { key: row.name, class: 'param-slider-row' }, [
|
||||
h('span', { class: 'param-label' }, row.label),
|
||||
withDirectives(
|
||||
h('input', {
|
||||
type: 'range',
|
||||
class: 'gev-quantitative-slider param-slider',
|
||||
min: row.min,
|
||||
max: row.max,
|
||||
step: row.step,
|
||||
'aria-label': row.label,
|
||||
onInput: (event) => this.onInput(row.name, event.target.value),
|
||||
}),
|
||||
[[vRangeValue, row.value]],
|
||||
),
|
||||
h('span', { class: 'param-value' }, row.text),
|
||||
]),
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Own generated parameter rows and their input handling. Renders
|
||||
* StyleParameterRows into `container` and patches it synchronously.
|
||||
* The caller supplies uniform metadata/value access and rendering/persistence
|
||||
* callbacks. Replacing or destroying rows revokes all old input handlers.
|
||||
* @param {object} options
|
||||
* @param {HTMLElement} options.container Container owned by this component.
|
||||
* @param {Document} [options.documentRef] Document used to construct rows.
|
||||
* @returns {{render: Function, clear: Function, destroy: Function}}
|
||||
*/
|
||||
export function createStyleParameters({
|
||||
container,
|
||||
documentRef = container.ownerDocument,
|
||||
}) {
|
||||
let listeners = [];
|
||||
export function createStyleParameters({ container }) {
|
||||
let rows = [];
|
||||
let onInput = () => {};
|
||||
// Each render's handlers act only while that render is current.
|
||||
let generation = 0;
|
||||
let destroyed = false;
|
||||
const paint = () =>
|
||||
render(h(StyleParameterRows, { rows, onInput }), container);
|
||||
const clear = () => {
|
||||
if (destroyed) return;
|
||||
for (const [slider, listener] of listeners)
|
||||
slider.removeEventListener('input', listener);
|
||||
listeners = [];
|
||||
container.replaceChildren();
|
||||
generation++;
|
||||
rows = [];
|
||||
onInput = () => {};
|
||||
render(null, container);
|
||||
};
|
||||
return {
|
||||
/** Render uniform metadata with readValue, writeValue and onChange callbacks. */
|
||||
render({ uniforms, readValue, writeValue, onChange }) {
|
||||
if (destroyed) return;
|
||||
clear();
|
||||
for (const [name, metadata] of Object.entries(uniforms)) {
|
||||
const row = documentRef.createElement('div');
|
||||
row.className = 'param-slider-row';
|
||||
const label = documentRef.createElement('span');
|
||||
label.className = 'param-label';
|
||||
label.textContent = t(metadata.label);
|
||||
const slider = createSlider({
|
||||
documentRef,
|
||||
className: 'param-slider',
|
||||
ariaLabel: t(metadata.label),
|
||||
min: metadata.min,
|
||||
max: metadata.max,
|
||||
step: metadata.max <= 1 ? '0.01' : '0.1',
|
||||
value: readValue(name),
|
||||
});
|
||||
const digits = metadata.max <= 1 ? 2 : 1;
|
||||
const valueDisplay = documentRef.createElement('span');
|
||||
valueDisplay.className = 'param-value';
|
||||
valueDisplay.textContent = formatParam(
|
||||
parseFloat(slider.value),
|
||||
digits,
|
||||
const current = generation;
|
||||
rows = Object.entries(uniforms).map(([name, metadata]) => ({
|
||||
name,
|
||||
label: t(metadata.label),
|
||||
min: metadata.min,
|
||||
max: metadata.max,
|
||||
step: metadata.max <= 1 ? '0.01' : '0.1',
|
||||
digits: metadata.max <= 1 ? 2 : 1,
|
||||
value: readValue(name),
|
||||
text: '',
|
||||
}));
|
||||
onInput = (name, raw) => {
|
||||
if (destroyed || current !== generation) return;
|
||||
const value = parseFloat(raw);
|
||||
writeValue(name, value);
|
||||
rows = rows.map((row) =>
|
||||
row.name === name
|
||||
? { ...row, value, text: formatParam(value, row.digits) }
|
||||
: row,
|
||||
);
|
||||
const onInput = () => {
|
||||
const value = parseFloat(slider.value);
|
||||
writeValue(name, value);
|
||||
valueDisplay.textContent = formatParam(value, digits);
|
||||
onChange();
|
||||
};
|
||||
slider.addEventListener('input', onInput);
|
||||
listeners.push([slider, onInput]);
|
||||
row.append(label, slider, valueDisplay);
|
||||
container.appendChild(row);
|
||||
}
|
||||
paint();
|
||||
onChange();
|
||||
};
|
||||
paint();
|
||||
// The readout shows the value the slider holds once the browser has
|
||||
// clamped and snapped it to its step.
|
||||
const sliders = container.querySelectorAll('input.param-slider');
|
||||
rows = rows.map((row, index) => ({
|
||||
...row,
|
||||
text: formatParam(parseFloat(sliders[index].value), row.digits),
|
||||
}));
|
||||
paint();
|
||||
},
|
||||
clear,
|
||||
destroy() {
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
// src/ui/styleParameters.test.mjs — generated style-parameter rows render
|
||||
// through Vue behind createStyleParameters and hand input back to the owner.
|
||||
import '../testSupport/registerDom.mjs';
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createStyleParameters } from './styleParameters.js';
|
||||
|
||||
function parameters(t, values = { amount: 0.25, scale: 2 }) {
|
||||
document.body.replaceChildren();
|
||||
const container = document.body.appendChild(document.createElement('div'));
|
||||
const controller = createStyleParameters({ container });
|
||||
t.after(() => controller.destroy());
|
||||
const uniforms = {
|
||||
amount: { label: '<Amount>', min: 0, max: 1 },
|
||||
scale: { label: 'Scale', min: 0, max: 10 },
|
||||
};
|
||||
const order = [];
|
||||
const rowsOf = () => [...container.querySelectorAll('.param-slider-row')];
|
||||
const options = {
|
||||
uniforms,
|
||||
readValue: (name) => values[name],
|
||||
writeValue: (name, value) => {
|
||||
order.push(['write', name, value]);
|
||||
values[name] = value;
|
||||
},
|
||||
onChange: () => {
|
||||
order.push(['change', rowsOf()[0]?.children[2].textContent]);
|
||||
},
|
||||
};
|
||||
controller.render(options);
|
||||
return { container, controller, values, options, order, rowsOf };
|
||||
}
|
||||
|
||||
const input = (slider, value) => {
|
||||
slider.value = value;
|
||||
slider.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
};
|
||||
|
||||
test('parameter rows preserve labels, bounds, precision and initial values', (t) => {
|
||||
const f = parameters(t);
|
||||
const rows = f.rowsOf();
|
||||
assert.equal(rows.length, 2);
|
||||
assert.equal(rows[0].childNodes.length, 3, 'no text between the parts');
|
||||
const [label, slider, value] = rows[0].children;
|
||||
assert.equal(label.className, 'param-label');
|
||||
assert.equal(label.textContent, '<Amount>');
|
||||
assert.equal(slider.getAttribute('aria-label'), '<Amount>');
|
||||
assert.equal(slider.type, 'range');
|
||||
assert.equal(slider.className, 'gev-quantitative-slider param-slider');
|
||||
assert.equal(slider.getAttribute('min'), '0');
|
||||
assert.equal(slider.getAttribute('max'), '1');
|
||||
assert.equal(slider.getAttribute('step'), '0.01');
|
||||
assert.equal(slider.hasAttribute('value'), false, 'the value is live only');
|
||||
assert.equal(slider.value, '0.25');
|
||||
assert.equal(value.className, 'param-value');
|
||||
assert.equal(value.textContent, '0.25');
|
||||
assert.equal(rows[1].children[1].getAttribute('step'), '0.1');
|
||||
assert.equal(rows[1].children[2].textContent, '2.0');
|
||||
assert.deepEqual(
|
||||
f.order,
|
||||
[],
|
||||
'rendering must not write shader values or publish changes',
|
||||
);
|
||||
});
|
||||
|
||||
test('the readout shows the value the slider holds after clamping', (t) => {
|
||||
const f = parameters(t, { amount: 1.7, scale: -3 });
|
||||
const [amount, scale] = f.rowsOf();
|
||||
const held = (row, digits) => Number(row.children[1].value).toFixed(digits);
|
||||
assert.equal(amount.children[2].textContent, held(amount, 2));
|
||||
assert.equal(scale.children[2].textContent, held(scale, 1));
|
||||
assert.notEqual(amount.children[2].textContent, '1.70', 'not the raw value');
|
||||
});
|
||||
|
||||
test('input writes numeric values, updates the readout, then requests a change', (t) => {
|
||||
const f = parameters(t);
|
||||
input(f.rowsOf()[0].children[1], '0.75');
|
||||
assert.equal(f.values.amount, 0.75);
|
||||
assert.deepEqual(f.order, [
|
||||
['write', 'amount', 0.75],
|
||||
['change', '0.75'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('rebuilding the parameter panel revokes detached slider listeners', (t) => {
|
||||
const f = parameters(t);
|
||||
const oldSlider = f.rowsOf()[0].children[1];
|
||||
f.controller.render({
|
||||
...f.options,
|
||||
uniforms: { scale: f.options.uniforms.scale },
|
||||
});
|
||||
input(oldSlider, '0.8');
|
||||
assert.equal(f.values.amount, 0.25);
|
||||
assert.equal(f.rowsOf().length, 1);
|
||||
input(f.rowsOf()[0].children[1], '3.5');
|
||||
assert.equal(f.values.scale, 3.5);
|
||||
});
|
||||
|
||||
test('clearing removes rows and listeners but allows another style', (t) => {
|
||||
const f = parameters(t);
|
||||
const oldSlider = f.rowsOf()[0].children[1];
|
||||
f.controller.clear();
|
||||
input(oldSlider, '0.5');
|
||||
assert.equal(f.container.children.length, 0);
|
||||
assert.deepEqual(f.order, []);
|
||||
f.controller.render(f.options);
|
||||
assert.equal(f.rowsOf().length, 2);
|
||||
});
|
||||
|
||||
test('destroy is final and cannot clear a subsequent owner’s DOM', (t) => {
|
||||
const f = parameters(t);
|
||||
const oldSlider = f.rowsOf()[0].children[1];
|
||||
f.controller.destroy();
|
||||
const nextOwner = f.container.appendChild(document.createElement('p'));
|
||||
f.controller.render(f.options);
|
||||
f.controller.clear();
|
||||
f.controller.destroy();
|
||||
input(oldSlider, '0.5');
|
||||
assert.equal(f.container.children.length, 1);
|
||||
assert.equal(f.container.firstElementChild === nextOwner, true);
|
||||
assert.deepEqual(f.order, []);
|
||||
});
|
||||
+2
-106
@@ -1,9 +1,7 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
bindApplicationShortcuts,
|
||||
createStyleParameters,
|
||||
} from './visualInput.js';
|
||||
// Generated parameter rows render through Vue: styleParameters.test.mjs.
|
||||
import { bindApplicationShortcuts } from './visualInput.js';
|
||||
|
||||
class Element {
|
||||
constructor(tagName = 'DIV', ownerDocument) {
|
||||
@@ -141,105 +139,3 @@ test('destroy synchronously removes shortcuts and a replacement binds once', ()
|
||||
assert.deepEqual(f.calls, ['new']);
|
||||
replacement.destroy();
|
||||
});
|
||||
|
||||
function parameters() {
|
||||
const documentRef = {
|
||||
createElement: (tag) => new Element(tag.toUpperCase(), documentRef),
|
||||
};
|
||||
const container = new Element('DIV', documentRef);
|
||||
const controller = createStyleParameters({ container });
|
||||
const values = { amount: 0.25, scale: 2 };
|
||||
const uniforms = {
|
||||
amount: { label: '<Amount>', min: 0, max: 1 },
|
||||
scale: { label: 'Scale', min: 0, max: 10 },
|
||||
};
|
||||
const order = [];
|
||||
const options = {
|
||||
uniforms,
|
||||
readValue: (name) => values[name],
|
||||
writeValue: (name, value) => {
|
||||
order.push(['write', name, value]);
|
||||
values[name] = value;
|
||||
},
|
||||
onChange: () => {
|
||||
order.push(['change', container.children[0]?.children[2].textContent]);
|
||||
},
|
||||
};
|
||||
controller.render(options);
|
||||
return { container, controller, values, options, order };
|
||||
}
|
||||
|
||||
test('parameter rows preserve labels, bounds, precision and initial values', () => {
|
||||
const f = parameters();
|
||||
assert.equal(f.container.children.length, 2);
|
||||
const [label, slider, value] = f.container.children[0].children;
|
||||
assert.equal(label.textContent, '<Amount>');
|
||||
assert.equal(slider.attributes.get('aria-label'), '<Amount>');
|
||||
assert.equal(slider.type, 'range');
|
||||
assert.equal(slider.className, 'gev-quantitative-slider param-slider');
|
||||
assert.equal(slider.min, 0);
|
||||
assert.equal(slider.max, 1);
|
||||
assert.equal(slider.step, '0.01');
|
||||
assert.equal(value.textContent, '0.25');
|
||||
assert.equal(f.container.children[1].children[1].step, '0.1');
|
||||
assert.equal(f.container.children[1].children[2].textContent, '2.0');
|
||||
assert.deepEqual(
|
||||
f.order,
|
||||
[],
|
||||
'rendering must not write shader values or publish changes',
|
||||
);
|
||||
});
|
||||
|
||||
test('input writes numeric values, updates the readout, then requests a change', () => {
|
||||
const f = parameters();
|
||||
const slider = f.container.children[0].children[1];
|
||||
slider.value = '0.75';
|
||||
slider.emit('input');
|
||||
assert.equal(f.values.amount, 0.75);
|
||||
assert.deepEqual(f.order, [
|
||||
['write', 'amount', 0.75],
|
||||
['change', '0.75'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('rebuilding the parameter panel revokes detached slider listeners', () => {
|
||||
const f = parameters();
|
||||
const oldSlider = f.container.children[0].children[1];
|
||||
f.controller.render({
|
||||
...f.options,
|
||||
uniforms: { scale: f.options.uniforms.scale },
|
||||
});
|
||||
oldSlider.value = '0.8';
|
||||
oldSlider.emit('input');
|
||||
assert.equal(f.values.amount, 0.25);
|
||||
assert.equal(oldSlider.listeners.get('input').size, 0);
|
||||
assert.equal(f.container.children.length, 1);
|
||||
f.container.children[0].children[1].value = '3.5';
|
||||
f.container.children[0].children[1].emit('input');
|
||||
assert.equal(f.values.scale, 3.5);
|
||||
});
|
||||
|
||||
test('clearing removes rows and listeners but allows another style', () => {
|
||||
const f = parameters();
|
||||
const oldSlider = f.container.children[0].children[1];
|
||||
f.controller.clear();
|
||||
oldSlider.emit('input');
|
||||
assert.equal(f.container.children.length, 0);
|
||||
assert.deepEqual(f.order, []);
|
||||
f.controller.render(f.options);
|
||||
assert.equal(f.container.children.length, 2);
|
||||
});
|
||||
|
||||
test('destroy is final and cannot clear a subsequent owner’s DOM', () => {
|
||||
const f = parameters();
|
||||
const oldSlider = f.container.children[0].children[1];
|
||||
f.controller.destroy();
|
||||
const nextOwner = new Element();
|
||||
f.container.appendChild(nextOwner);
|
||||
f.controller.render(f.options);
|
||||
f.controller.clear();
|
||||
f.controller.destroy();
|
||||
oldSlider.emit('input');
|
||||
assert.deepEqual(f.container.children, [nextOwner]);
|
||||
assert.deepEqual(f.order, []);
|
||||
});
|
||||
Reference in new issue
Block a user