/* 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/. */
/** * The ShapesInContextEditor: * - communicates with the ShapesHighlighter actor from the server; * - listens to events for shape change and hover point coming from the shape-highlighter; * - writes shape value changes to the CSS declaration it was triggered from; * - synchronises highlighting coordinate points on mouse over between the shapes * highlighter and the shape value shown in the Rule view. * * It is instantiated once in HighlightersOverlay by calls to .getInContextEditor().
*/ class ShapesInContextEditor {
constructor(highlighter, inspector, state) {
EventEmitter.decorate(this);
this.inspector = inspector; this.highlighter = highlighter; // Refence to the NodeFront currently being highlighted. this.highlighterTargetNode = null; this.highligherEventHandlers = {}; this.highligherEventHandlers["shape-change"] = this.onShapeChange; this.highligherEventHandlers["shape-hover-on"] = this.onShapeHover; this.highligherEventHandlers["shape-hover-off"] = this.onShapeHover; // Mode for shapes highlighter: shape-outside or clip-path. Used to discern // when toggling the highlighter on the same node for different CSS properties. this.mode = null; // Reference to Rule view used to listen for changes this.ruleView = this.inspector.getPanel("ruleview").view; // Reference of |state| from HighlightersOverlay. this.state = state; // Reference to DOM node of the toggle icon for shapes highlighter. this.swatch = null;
// Commit triggers expensive DOM changes in TextPropertyEditor.update() // so we debounce it. this.commit = debounce(this.commit, 200, this); this.onHighlighterEvent = this.onHighlighterEvent.bind(this); this.onNodeFrontChanged = this.onNodeFrontChanged.bind(this); this.onShapeValueUpdated = this.onShapeValueUpdated.bind(this); this.onRuleViewChanged = this.onRuleViewChanged.bind(this);
/** * Get the reference to the TextProperty where shape changes should be written. * * We can't rely on the TextProperty to be consistent while changing the value of an * inline style because the fix for Bug 1467076 forces a full rebuild of TextProperties * for the inline style's mock-CSS Rule in the Rule view. * * On |toggle()|, we store the target TextProperty index, property name and parent rule. * Here, we use that index and property name to attempt to re-identify the correct * TextProperty in the rule. * * @return {TextProperty|null}
*/
get textProperty() { if (!this.rule || !this.rule.textProps) { returnnull;
}
/** * Called when the element style changes from the Rule view. * If the TextProperty we're acting on isn't enabled anymore or overridden, * turn off the shapes highlighter.
*/
async onRuleViewChanged() { if ( this.textProperty &&
(!this.textProperty.enabled || this.textProperty.overridden)
) {
await this.hide();
}
}
/** * Toggle the shapes highlighter for the given element. * * @param {NodeFront} node * The NodeFront of the element with a shape to highlight. * @param {Object} options * Object used for passing options to the shapes highlighter.
*/
async toggle(node, options, prop) { // Same target node, same mode -> hide and exit OR switch to toggle transform mode. if (node == this.highlighterTargetNode && this.mode === options.mode) { if (!options.transformMode) {
await this.hide(); return;
}
// Same target node, dfferent modes -> toggle between shape-outside, clip-path and offset-path. // Hide highlighter for previous property, but continue and show for other property. if (node == this.highlighterTargetNode && this.mode !== options.mode) {
await this.hide();
}
// Save the target TextProperty's parent rule, index and property name for later // re-identification of the TextProperty. @see |get textProperty()|. this.rule = prop.rule; this.textPropIndex = this.rule.textProps.indexOf(prop); this.textPropName = prop.name;
/** * Show the shapes highlighter for the given element. * * @param {NodeFront} node * The NodeFront of the element with a shape to highlight. * @param {Object} options * Object used for passing options to the shapes highlighter.
*/
async show(node, options) { const isShown = await this.highlighter.show(node, options); if (!isShown) { return;
}
/** * Identify the swatch (aka toggle icon) DOM node from the TextPropertyEditor of the * TextProperty we're working with. Whenever the TextPropertyEditor is updated (i.e. * when committing the shape value to the Rule view), it rebuilds its DOM and the old * swatch reference becomes invalid. Call this method to identify the current swatch.
*/
findSwatch() { if (!this.textProperty) { return;
}
/** * Handle events emitted by the highlighter. * Find any callback assigned to the event type and call it with the given data object. * * @param {Object} data * The data object sent in the event.
*/
onHighlighterEvent(data) { const handler = this.highligherEventHandlers[data.type]; if (!handler || typeof handler !== "function") { return;
}
handler.call(this, data); this.inspector.highlighters.emit("highlighter-event-handled");
}
/** * Clean up when node selection changes because Rule view and TextPropertyEditor * instances are not automatically destroyed when selection changes.
*/
async onNodeFrontChanged() { try {
await this.hide();
} catch (err) { // Silent error.
}
}
/** * Handler for "shape-change" event from the shapes highlighter. * * @param {Object} data * Data associated with the "shape-change" event. * Contains: * - {String} value: the new shape value. * - {String} type: the event type ("shape-change").
*/
onShapeChange(data) { this.preview(data.value); this.commit(data.value);
}
/** * Handler for "shape-hover-on" and "shape-hover-off" events from the shapes highlighter. * Called when the mouse moves over or off of a coordinate point inside the shapes * highlighter. Marks/unmarks the corresponding coordinate node in the shape value * from the Rule view. * * @param {Object} data * Data associated with the "shape-hover" event. * Contains: * - {String|null} point: coordinate to highlight or null if nothing to highlight * - {String} type: the event type ("shape-hover-on" or "shape-hover-on").
*/
onShapeHover(data) { const shapeValueEl = this.swatch && this.swatch.nextSibling; if (!shapeValueEl) { return;
}
const pointSelector = ".inspector-shape-point"; // First, unmark all highlighted coordinate nodes from Rule view for (const node of shapeValueEl.querySelectorAll(
`${pointSelector}.active`
)) {
node.classList.remove("active");
}
// Exit if there's no coordinate to highlight. if (typeof data.point !== "string") { return;
}
const point = data.point.includes(",")
? data.point.split(",")[0]
: data.point;
/** * Build selector for coordinate nodes in shape value that must be highlighted. * Coordinate values for inset() use class names instead of data attributes because * a single node may represent multiple coordinates in shorthand notation. * Example: inset(50px); The node wrapping 50px represents all four inset coordinates.
*/ const INSET_POINT_TYPES = ["top", "right", "bottom", "left"]; const selector = INSET_POINT_TYPES.includes(point)
? `${pointSelector}.${point}`
: `${pointSelector}[data-point='${point}']`;
for (const node of shapeValueEl.querySelectorAll(selector)) {
node.classList.add("active");
}
}
/** * Handler for "property-value-updated" event triggered by the Rule view. * Called after the shape value has been written to the element's style and the Rule * view updated. Emits an event on HighlightersOverlay that is expected by * tests in order to check if the shape value has been correctly applied.
*/
async onShapeValueUpdated() { if (this.textProperty) { // When TextPropertyEditor updates, it replaces the previous swatch DOM node. // Find and store the new one. this.findSwatch(); this.inspector.highlighters.emit("shapes-highlighter-changes-applied");
} else {
await this.hide();
}
}
/** * Preview a shape value on the element without committing the changes to the Rule view. * * @param {String} value * The shape value to set the current property to
*/
preview(value) { if (!this.textProperty) { return;
} // Update the element's style to see live results. this.textProperty.rule.previewPropertyValue(this.textProperty, value); // Update the text of CSS value in the Rule view. This makes it inert. // When commit() is called, the value is reparsed and its DOM structure rebuilt. this.swatch.nextSibling.textContent = value;
}
/** * Commit a shape value change which triggers an expensive operation that rebuilds * part of the DOM of the TextPropertyEditor. Called in a debounced manner; see * constructor. * * @param {String} value * The shape value for the current property
*/
commit(value) { if (!this.textProperty) { return;
}
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.