UNPKG

@polymer/polymer

Version:

The Polymer library makes it easy to create your own web components. Give your element some markup and properties, and then use it on a site. Polymer provides features like dynamic templates and data binding to reduce the amount of boilerplate you need to

189 lines (164 loc) 5.77 kB
<!-- @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 --> <link rel="import" href="property-accessors.html"> <script> (function() { 'use strict'; 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'; const DIR_CHECK = /:dir\((?:ltr|rtl)\)/; const SHIM_SHADOW = Boolean(window['ShadyDOM'] && window['ShadyDOM']['inUse']); /** * @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 Polymer.PropertyAccessors * @memberof Polymer */ Polymer.DirMixin = Polymer.dedupingMixin((base) => { if (!SHIM_SHADOW) { if (!observer) { getRTL(); observer = new MutationObserver(updateDirection); observer.observe(document.documentElement, {attributes: true, attributeFilter: ['dir']}); } } /** * @constructor * @extends {base} * @implements {Polymer_PropertyAccessors} * @private */ const elementBase = Polymer.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); if (!SHIM_SHADOW && DIR_CHECK.test(cssText)) { cssText = this._replaceDirInCssText(cssText); this.__activateDir = true; } 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); 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; }); })(); </script>