| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * @fileoverview Leftover "cr." library functions to support some legacy |
| * JavaScript users. Do not use this file in new code. |
| */ |
| |
| import {assertNotReached} from 'chrome://resources/js/assert_ts.js'; |
| |
| /** |
| * Dispatches a simple event on an event target. |
| * @param {!EventTarget} target The event target to dispatch the event on. |
| * @param {string} type The type of the event. |
| * @param {boolean=} bubbles Whether the event bubbles or not. |
| * @param {boolean=} cancelable Whether the default action of the event |
| * can be prevented. Default is true. |
| * @return {boolean} If any of the listeners called {@code preventDefault} |
| * during the dispatch this will return false. |
| */ |
| export function dispatchSimpleEvent(target, type, bubbles, cancelable) { |
| const e = new Event( |
| type, |
| {bubbles: bubbles, cancelable: cancelable === undefined || cancelable}); |
| return target.dispatchEvent(e); |
| } |
| |
| /** |
| * Adds a {@code getInstance} static method that always return the same |
| * instance object. |
| * @param {!Function} ctor The constructor for the class to add the static |
| * method to. |
| */ |
| export function addSingletonGetter(ctor) { |
| ctor.getInstance = function() { |
| return ctor.instance_ || (ctor.instance_ = new ctor()); |
| }; |
| } |
| |
| /** |
| * Fires a property change event on the target. |
| * @param {!EventTarget} target The target to dispatch the event on. |
| * @param {string} propertyName The name of the property that changed. |
| * @param {*} newValue The new value for the property. |
| * @param {*} oldValue The old value for the property. |
| */ |
| export function dispatchPropertyChange( |
| target, propertyName, newValue, oldValue) { |
| const e = new Event(propertyName + 'Change'); |
| e.propertyName = propertyName; |
| e.newValue = newValue; |
| e.oldValue = oldValue; |
| target.dispatchEvent(e); |
| } |
| |
| /** |
| * Converts a camelCase javascript property name to a hyphenated-lower-case |
| * attribute name. |
| * @param {string} jsName The javascript camelCase property name. |
| * @return {string} The equivalent hyphenated-lower-case attribute name. |
| */ |
| function getAttributeName(jsName) { |
| return jsName.replace(/([A-Z])/g, '-$1').toLowerCase(); |
| } |
| |
| /** |
| * The kind of property to define in {@code getPropertyDescriptor}. |
| * @enum {string} |
| * @const |
| */ |
| export const PropertyKind = { |
| /** |
| * Plain old JS property where the backing data is stored as a "private" |
| * field on the object. |
| * Use for properties of any type. Type will not be checked. |
| */ |
| JS: 'js', |
| |
| /** |
| * The property backing data is stored as an attribute on an element. |
| * Use only for properties of type {string}. |
| */ |
| ATTR: 'attr', |
| |
| /** |
| * The property backing data is stored as an attribute on an element. If the |
| * element has the attribute then the value is true. |
| * Use only for properties of type {boolean}. |
| */ |
| BOOL_ATTR: 'boolAttr', |
| }; |
| |
| /** |
| * Helper function for getPropertyDescriptor that returns the getter to use for |
| * the property. |
| * @param {string} name The name of the property. |
| * @param {PropertyKind} kind The kind of the property. |
| * @return {function():*} The getter for the property. |
| */ |
| function getGetter(name, kind) { |
| let attributeName; |
| switch (kind) { |
| case PropertyKind.JS: |
| const privateName = name + '_'; |
| return function() { |
| return this[privateName]; |
| }; |
| case PropertyKind.ATTR: |
| attributeName = getAttributeName(name); |
| return function() { |
| return this.getAttribute(attributeName); |
| }; |
| case PropertyKind.BOOL_ATTR: |
| attributeName = getAttributeName(name); |
| return function() { |
| return this.hasAttribute(attributeName); |
| }; |
| } |
| |
| assertNotReached(); |
| } |
| |
| /** |
| * Helper function for getPropertyDescriptor that returns the setter of the |
| * right kind. |
| * @param {string} name The name of the property we are defining the setter |
| * for. |
| * @param {PropertyKind} kind The kind of property we are getting the |
| * setter for. |
| * @param {function(*, *):void=} setHook A function to run after the |
| * property is set, but before the propertyChange event is fired. |
| * @return {function(*):void} The function to use as a setter. |
| */ |
| function getSetter(name, kind, setHook) { |
| let attributeName; |
| switch (kind) { |
| case PropertyKind.JS: |
| const privateName = name + '_'; |
| return function(value) { |
| const oldValue = this[name]; |
| if (value !== oldValue) { |
| this[privateName] = value; |
| if (setHook) { |
| setHook.call(this, value, oldValue); |
| } |
| dispatchPropertyChange(this, name, value, oldValue); |
| } |
| }; |
| |
| case PropertyKind.ATTR: |
| attributeName = getAttributeName(name); |
| return function(value) { |
| const oldValue = this[name]; |
| if (value !== oldValue) { |
| if (value === undefined) { |
| this.removeAttribute(attributeName); |
| } else { |
| this.setAttribute(attributeName, value); |
| } |
| if (setHook) { |
| setHook.call(this, value, oldValue); |
| } |
| dispatchPropertyChange(this, name, value, oldValue); |
| } |
| }; |
| |
| case PropertyKind.BOOL_ATTR: |
| attributeName = getAttributeName(name); |
| return function(value) { |
| const oldValue = this[name]; |
| if (value !== oldValue) { |
| if (value) { |
| this.setAttribute(attributeName, name); |
| } else { |
| this.removeAttribute(attributeName); |
| } |
| if (setHook) { |
| setHook.call(this, value, oldValue); |
| } |
| dispatchPropertyChange(this, name, value, oldValue); |
| } |
| }; |
| } |
| |
| assertNotReached(); |
| } |
| |
| /** |
| * Returns a getter and setter to be used as property descriptor in |
| * Object.defineProperty(). When the setter changes the value a property change |
| * event with the type {@code name + 'Change'} is fired. |
| * @param {string} name The name of the property. |
| * @param {PropertyKind=} kind What kind of underlying storage to use. |
| * @param {function(?, ?):void=} setHook A function to run after the |
| * property is set, but before the propertyChange event is fired. |
| */ |
| export function getPropertyDescriptor(name, kind = PropertyKind.JS, setHook) { |
| return { |
| get: getGetter(name, kind), |
| set: getSetter(name, kind, setHook), |
| }; |
| } |