/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/** * Spectrum creates a color picker widget in any container you give it. * * Simple usage example: * * const {Spectrum} = require("devtools/client/shared/widgets/Spectrum"); * let s = new Spectrum(containerElement, [255, 126, 255, 1]); * s.on("changed", (rgba, color) => { * console.log("rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ", " + * rgba[3] + ")"); * }); * s.show(); * s.destroy(); * * Note that the color picker is hidden by default and you need to call show to * make it appear. This 2 stages initialization helps in cases you are creating * the color picker in a parent element that hasn't been appended anywhere yet * or that is hidden. Calling show() when the parent element is appended and * visible will allow spectrum to correctly initialize its various parts. * * Fires the following events: * - changed : When the user changes the current color
*/ class Spectrum {
constructor(parentEl, rgb) {
EventEmitter.decorate(this);
// Here we define the components for the "controls" section of the color picker. this.controls = this.element.querySelector(".spectrum-controls"); this.colorPreview = this.element.querySelector(".spectrum-color-preview");
/** * Map current rgb to the closest color available in the database by * calculating the delta-E between each available color and the current rgb * * @return {String} * Color name or closest color name
*/
get colorName() { const labColorEntries = Object.entries(labColors);
// Get the color name for the one that has the lowest delta-E const minDeltaE = Math.min(...deltaEs); const colorName = labColorEntries[deltaEs.indexOf(minDeltaE)][0]; return minDeltaE === 0
? colorName
: L10N.getFormatStr("colorPickerTooltip.colorNameTitle", colorName);
}
/** * Creates and initializes a slider element, attaches it to its parent container * based on the slider type and returns it * * @param {String} sliderType * The type of the slider (i.e. alpha or hue) * @param {Function} onSliderMove * The function to tie the slider to on input * @return {DOMNode} * Newly created slider
*/
createSlider(sliderType, onSliderMove) { const container = this.element.querySelector(`.spectrum-${sliderType}`);
/** * Updates the contrast label with appropriate content (i.e. large text indicator * if the contrast is calculated for large text, or a base label otherwise) * * @param {Boolean} isLargeText * True if contrast is calculated for large text.
*/
updateContrastLabel(isLargeText) { if (!isLargeText) { this.contrastLabel.textContent = L10N.getStr( "accessibility.contrast.ratio.label"
); return;
}
// Clear previously appended children before appending any new children while (this.contrastLabel.firstChild) { this.contrastLabel.firstChild.remove();
}
// Build an array of children nodes for the contrast label element const contents = contrastLabelStr
.split(new RegExp(largeTextStr), 2)
.map(content => this.document.createTextNode(content)); const largeTextIndicator = this.document.createElementNS(XHTML_NS, "span");
largeTextIndicator.className = "accessibility-color-contrast-large-text";
largeTextIndicator.textContent = largeTextStr;
largeTextIndicator.title = L10N.getStr( "accessibility.contrast.large.title"
);
contents.splice(1, 0, largeTextIndicator);
// Append children to contrast label for (const content of contents) { this.contrastLabel.appendChild(content);
}
}
/** * Updates a contrast value element with the given score, value and swatches. * * @param {DOMNode} el * Contrast value element to update. * @param {String} score * Contrast ratio score. * @param {Number} value * Contrast ratio value. * @param {Array} backgroundColor * RGBA color array for the background color to show in the swatch.
*/
updateContrastValueEl(el, score, value, backgroundColor) {
el.classList.toggle(score, true);
el.textContent = value.toFixed(2);
el.title = L10N.getFormatStr(
`accessibility.contrast.annotation.${score}`,
L10N.getFormatStr( "colorPickerTooltip.contrastAgainstBgTitle",
`rgba(${backgroundColor})`
)
);
el.parentElement.style.setProperty( "--accessibility-contrast-color", this.rgbCssString
);
el.parentElement.style.setProperty( "--accessibility-contrast-bg",
`rgba(${backgroundColor})`
);
}
updateColorPreview() { // Overlay the rgba color over a checkered image background. this.colorPreview.style.setProperty("--overlay-color", this.rgbCssString);
// We should be able to distinguish the color preview on high luminance rgba values. // Give the color preview a light grey border if the luminance of the current rgba // tuple is great. const colorLuminance = colorUtils.calculateLuminance(this.rgb); this.colorPreview.classList.toggle("high-luminance", colorLuminance > 0.85);
// Set title on color preview for better UX this.colorPreview.title = this.colorName;
}
updateHelperLocations() { const h = this.hsv[0]; const s = this.hsv[1]; const v = this.hsv[2];
// Placing the color dragger
let dragX = s * this.dragWidth;
let dragY = this.dragHeight - v * this.dragHeight; const helperDim = this.dragHelperHeight / 2;
/* Calculates the contrast ratio for the currently selected * color against a single or range of background colors and displays contrast ratio section * components depending on the contrast ratio calculated. * * Contrast ratio components include: * - contrastLargeTextIndicator: Hidden by default, shown when text has large font * size if there is no error in calculation. * - contrastValue(s): Set to calculated value(s), score(s) and text color on * background swatches. Set to error text * if there is an error in calculation.
*/
updateContrast() { // Remove additional classes on spectrum contrast, leaving behind only base classes this.spectrumContrast.classList.toggle("visible", false); this.spectrumContrast.classList.toggle("range", false); this.spectrumContrast.classList.toggle("error", false); // Assign only base class to all contrastValues, removing any score class this.contrastValue.className = this.contrastValueMin.className = this.contrastValueMax.className = "accessibility-contrast-value";
if (error) { this.updateContrastLabel(false); this.spectrumContrast.classList.toggle("error", true);
// If current background color is a range, show the error text in the contrast range // span. Otherwise, show it in the single contrast span. const contrastValEl = isRange
? this.contrastValueMin
: this.contrastValue;
contrastValEl.textContent = L10N.getStr("accessibility.contrast.error");
contrastValEl.title = L10N.getStr( "accessibility.contrast.annotation.transparent.error"
);
return;
}
this.updateContrastLabel(isLargeText); if (!isRange) { this.updateContrastValueEl( this.contrastValue,
score,
value,
backgroundColor
);
const i = Math.floor(h * 6); const f = h * 6 - i; const p = v * (1 - s); const q = v * (1 - f * s); const t = v * (1 - (1 - f) * s);
switch (i % 6) { case 0:
r = v;
g = t;
b = p; break; case 1:
r = q;
g = v;
b = p; break; case 2:
r = p;
g = v;
b = t; break; case 3:
r = p;
g = q;
b = v; break; case 4:
r = t;
g = p;
b = v; break; case 5:
r = v;
g = p;
b = q; break;
}
return [r * 255, g * 255, b * 255, a];
}
function rgbToHsv(r, g, b, a) {
r = r / 255;
g = g / 255;
b = b / 255;
const max = Math.max(r, g, b); const min = Math.min(r, g, b);
const v = max; const d = max - min; const s = max == 0 ? 0 : d / max;
let h; if (max == min) { // achromatic
h = 0;
} else { switch (max) { case r:
h = (g - b) / d + (g < b ? 6 : 0); break; case g:
h = (b - r) / d + 2; break; case b:
h = (r - g) / d + 4; break;
}
h /= 6;
} return [h, s, v, a];
}
function draggable(element, dragHelper, onmove) {
onmove = onmove || function () {};
const doc = element.ownerDocument;
let dragging = false;
let offset = {};
let maxHeight = 0;
let maxWidth = 0;
function prevent(e) {
e.stopPropagation();
e.preventDefault();
}
function move(e) { if (dragging) { if (e.buttons === 0) { // The button is no longer pressed but we did not get a mouseup event.
stop(); return;
} const pageX = e.pageX; const pageY = e.pageY;
/** * Calculates the contrast ratio for a DOM node's computed style against * a given background. * * @param {Object} computedStyle * The computed style for which we want to calculate the contrast ratio. * @param {Object} backgroundColor * Object with one or more of the following properties: value, min, max * @return {Object} * An object that may contain one or more of the following fields: error, * isLargeText, value, score for contrast.
*/ function getContrastRatio(computedStyle, backgroundColor) { const props = getTextProperties(computedStyle);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.