diff options
Diffstat (limited to 'chromium/third_party/catapult/third_party/polymer3/bower_components/polymer/lib/mixins/dir-mixin.js')
-rw-r--r-- | chromium/third_party/catapult/third_party/polymer3/bower_components/polymer/lib/mixins/dir-mixin.js | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/chromium/third_party/catapult/third_party/polymer3/bower_components/polymer/lib/mixins/dir-mixin.js b/chromium/third_party/catapult/third_party/polymer3/bower_components/polymer/lib/mixins/dir-mixin.js new file mode 100644 index 00000000000..0e6d31e34fe --- /dev/null +++ b/chromium/third_party/catapult/third_party/polymer3/bower_components/polymer/lib/mixins/dir-mixin.js @@ -0,0 +1,179 @@ +/** +@license +Copyright (c) 2017 The Polymer Project Authors. All rights reserved. +This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt +The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt +The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt +Code distributed by Google as part of the polymer project is also +subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt +*/ +import { PropertyAccessors } from './property-accessors.js'; + +import { dedupingMixin } from '../utils/mixin.js'; + +const HOST_DIR = /:host\(:dir\((ltr|rtl)\)\)/g; +const HOST_DIR_REPLACMENT = ':host([dir="$1"])'; + +const EL_DIR = /([\s\w-#\.\[\]\*]*):dir\((ltr|rtl)\)/g; +const EL_DIR_REPLACMENT = ':host([dir="$2"]) $1'; + +/** + * @type {!Array<!Polymer_DirMixin>} + */ +const DIR_INSTANCES = []; + +/** @type {MutationObserver} */ +let observer = null; + +let DOCUMENT_DIR = ''; + +function getRTL() { + DOCUMENT_DIR = document.documentElement.getAttribute('dir'); +} + +/** + * @param {!Polymer_DirMixin} instance Instance to set RTL status on + */ +function setRTL(instance) { + if (!instance.__autoDirOptOut) { + const el = /** @type {!HTMLElement} */(instance); + el.setAttribute('dir', DOCUMENT_DIR); + } +} + +function updateDirection() { + getRTL(); + DOCUMENT_DIR = document.documentElement.getAttribute('dir'); + for (let i = 0; i < DIR_INSTANCES.length; i++) { + setRTL(DIR_INSTANCES[i]); + } +} + +function takeRecords() { + if (observer && observer.takeRecords().length) { + updateDirection(); + } +} + +/** + * Element class mixin that allows elements to use the `:dir` CSS Selector to + * have text direction specific styling. + * + * With this mixin, any stylesheet provided in the template will transform + * `:dir` into `:host([dir])` and sync direction with the page via the + * element's `dir` attribute. + * + * Elements can opt out of the global page text direction by setting the `dir` + * attribute directly in `ready()` or in HTML. + * + * Caveats: + * - Applications must set `<html dir="ltr">` or `<html dir="rtl">` to sync + * direction + * - Automatic left-to-right or right-to-left styling is sync'd with the + * `<html>` element only. + * - Changing `dir` at runtime is supported. + * - Opting out of the global direction styling is permanent + * + * @mixinFunction + * @polymer + * @appliesMixin PropertyAccessors + */ +export const DirMixin = dedupingMixin((base) => { + + if (!observer) { + getRTL(); + observer = new MutationObserver(updateDirection); + observer.observe(document.documentElement, {attributes: true, attributeFilter: ['dir']}); + } + + /** + * @constructor + * @extends {base} + * @implements {Polymer_PropertyAccessors} + */ + const elementBase = PropertyAccessors(base); + + /** + * @polymer + * @mixinClass + * @implements {Polymer_DirMixin} + */ + class Dir extends elementBase { + + /** + * @override + * @suppress {missingProperties} Interfaces in closure do not inherit statics, but classes do + */ + static _processStyleText(cssText, baseURI) { + cssText = super._processStyleText(cssText, baseURI); + cssText = this._replaceDirInCssText(cssText); + return cssText; + } + + /** + * Replace `:dir` in the given CSS text + * + * @param {string} text CSS text to replace DIR + * @return {string} Modified CSS + */ + static _replaceDirInCssText(text) { + let replacedText = text; + replacedText = replacedText.replace(HOST_DIR, HOST_DIR_REPLACMENT); + replacedText = replacedText.replace(EL_DIR, EL_DIR_REPLACMENT); + if (text !== replacedText) { + this.__activateDir = true; + } + return replacedText; + } + + constructor() { + super(); + /** @type {boolean} */ + this.__autoDirOptOut = false; + } + + /** + * @suppress {invalidCasts} Closure doesn't understand that `this` is an HTMLElement + * @return {void} + */ + ready() { + super.ready(); + this.__autoDirOptOut = /** @type {!HTMLElement} */(this).hasAttribute('dir'); + } + + /** + * @suppress {missingProperties} If it exists on elementBase, it can be super'd + * @return {void} + */ + connectedCallback() { + if (elementBase.prototype.connectedCallback) { + super.connectedCallback(); + } + if (this.constructor.__activateDir) { + takeRecords(); + DIR_INSTANCES.push(this); + setRTL(this); + } + } + + /** + * @suppress {missingProperties} If it exists on elementBase, it can be super'd + * @return {void} + */ + disconnectedCallback() { + if (elementBase.prototype.disconnectedCallback) { + super.disconnectedCallback(); + } + if (this.constructor.__activateDir) { + const idx = DIR_INSTANCES.indexOf(this); + if (idx > -1) { + DIR_INSTANCES.splice(idx, 1); + } + } + } + } + + Dir.__activateDir = false; + + return Dir; +}); |