UNPKG

ember-legacy-class-transform

Version:
168 lines 5.77 kB
import { sanitizeAttributeValue, requiresSanitization } from './sanitized-values'; import { normalizeProperty } from './props'; import { SVG_NAMESPACE } from './helper'; import { normalizeTextValue } from '../compiled/opcodes/content'; export function defaultManagers(element, attr, _isTrusting, _namespace) { let tagName = element.tagName; let isSVG = element.namespaceURI === SVG_NAMESPACE; if (isSVG) { return defaultAttributeManagers(tagName, attr); } let { type, normalized } = normalizeProperty(element, attr); if (type === 'attr') { return defaultAttributeManagers(tagName, normalized); } else { return defaultPropertyManagers(tagName, normalized); } } export function defaultPropertyManagers(tagName, attr) { if (requiresSanitization(tagName, attr)) { return new SafePropertyManager(attr); } if (isUserInputValue(tagName, attr)) { return INPUT_VALUE_PROPERTY_MANAGER; } if (isOptionSelected(tagName, attr)) { return OPTION_SELECTED_MANAGER; } return new PropertyManager(attr); } export function defaultAttributeManagers(tagName, attr) { if (requiresSanitization(tagName, attr)) { return new SafeAttributeManager(attr); } return new AttributeManager(attr); } export function readDOMAttr(element, attr) { let isSVG = element.namespaceURI === SVG_NAMESPACE; let { type, normalized } = normalizeProperty(element, attr); if (isSVG) { return element.getAttribute(normalized); } if (type === 'attr') { return element.getAttribute(normalized); } { return element[normalized]; } } ; export class AttributeManager { constructor(attr) { this.attr = attr; } setAttribute(env, element, value, namespace) { let dom = env.getAppendOperations(); let normalizedValue = normalizeAttributeValue(value); if (!isAttrRemovalValue(normalizedValue)) { dom.setAttribute(element, this.attr, normalizedValue, namespace); } } updateAttribute(env, element, value, namespace) { if (value === null || value === undefined || value === false) { if (namespace) { env.getDOM().removeAttributeNS(element, namespace, this.attr); } else { env.getDOM().removeAttribute(element, this.attr); } } else { this.setAttribute(env, element, value); } } } ; export class PropertyManager extends AttributeManager { setAttribute(_env, element, value, _namespace) { if (!isAttrRemovalValue(value)) { element[this.attr] = value; } } removeAttribute(env, element, namespace) { // TODO this sucks but to preserve properties first and to meet current // semantics we must do this. let { attr } = this; if (namespace) { env.getDOM().removeAttributeNS(element, namespace, attr); } else { env.getDOM().removeAttribute(element, attr); } } updateAttribute(env, element, value, namespace) { // ensure the property is always updated element[this.attr] = value; if (isAttrRemovalValue(value)) { this.removeAttribute(env, element, namespace); } } } ; function normalizeAttributeValue(value) { if (value === false || value === undefined || value === null) { return null; } if (value === true) { return ''; } // onclick function etc in SSR if (typeof value === 'function') { return null; } return String(value); } function isAttrRemovalValue(value) { return value === null || value === undefined; } class SafePropertyManager extends PropertyManager { setAttribute(env, element, value) { super.setAttribute(env, element, sanitizeAttributeValue(env, element, this.attr, value)); } updateAttribute(env, element, value) { super.updateAttribute(env, element, sanitizeAttributeValue(env, element, this.attr, value)); } } function isUserInputValue(tagName, attribute) { return (tagName === 'INPUT' || tagName === 'TEXTAREA') && attribute === 'value'; } class InputValuePropertyManager extends AttributeManager { setAttribute(_env, element, value) { let input = element; input.value = normalizeTextValue(value); } updateAttribute(_env, element, value) { let input = element; let currentValue = input.value; let normalizedValue = normalizeTextValue(value); if (currentValue !== normalizedValue) { input.value = normalizedValue; } } } export const INPUT_VALUE_PROPERTY_MANAGER = new InputValuePropertyManager('value'); function isOptionSelected(tagName, attribute) { return tagName === 'OPTION' && attribute === 'selected'; } class OptionSelectedManager extends PropertyManager { setAttribute(_env, element, value) { if (value !== null && value !== undefined && value !== false) { let option = element; option.selected = true; } } updateAttribute(_env, element, value) { let option = element; if (value) { option.selected = true; } else { option.selected = false; } } } export const OPTION_SELECTED_MANAGER = new OptionSelectedManager('selected'); class SafeAttributeManager extends AttributeManager { setAttribute(env, element, value) { super.setAttribute(env, element, sanitizeAttributeValue(env, element, this.attr, value)); } updateAttribute(env, element, value, _namespace) { super.updateAttribute(env, element, sanitizeAttributeValue(env, element, this.attr, value)); } }