/* @license * Copyright 2019 Google LLC. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); class ImageAccessor { static fromArrayBuffer(buffer, width, height) { return new ImageAccessor(new ImageData(new Uint8ClampedArray(buffer), width, height)); } static fromImageElement(image) { canvas.width = image.naturalWidth; canvas.height = image.naturalHeight; context.drawImage(image, 0, 0); return new ImageAccessor(context.getImageData(0, 0, canvas.width, canvas.height)); } toArrayBuffer() { const { buffer } = this.source.data; return buffer.slice(0, buffer.byteLength); } cssColorAt(x, y) { if (x < 0 || y < 0 || x > (this.width - 1) || y > (this.height - 1)) { return 'black'; } const position = (y * this.width + x) * 4; const array = this.source.data; const color = `rgb(${array[position]}, ${array[position + 1]}, ${array[position + 2]})`; return color; } constructor(source) { this.source = source; } get width() { return this.source.width; } get height() { return this.source.height; } } /** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const t$1=globalThis,e$4=t$1.ShadowRoot&&(void 0===t$1.ShadyCSS||t$1.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,s$1=Symbol(),o$3=new WeakMap;let n$3 = class n{constructor(t,e,o){if(this._$cssResult$=true,o!==s$1)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e;}get styleSheet(){let t=this.o;const s=this.t;if(e$4&&void 0===t){const e=void 0!==s&&1===s.length;e&&(t=o$3.get(s)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&o$3.set(s,t));}return t}toString(){return this.cssText}};const r$4=t=>new n$3("string"==typeof t?t:t+"",void 0,s$1),S$1=(s,o)=>{if(e$4)s.adoptedStyleSheets=o.map((t=>t instanceof CSSStyleSheet?t:t.styleSheet));else for(const e of o){const o=document.createElement("style"),n=t$1.litNonce;void 0!==n&&o.setAttribute("nonce",n),o.textContent=e.cssText,s.appendChild(o);}},c$2=e$4?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const s of t.cssRules)e+=s.cssText;return r$4(e)})(t):t; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */const{is:i$2,defineProperty:e$3,getOwnPropertyDescriptor:r$3,getOwnPropertyNames:h$1,getOwnPropertySymbols:o$2,getPrototypeOf:n$2}=Object,a$1=globalThis,c$1=a$1.trustedTypes,l$1=c$1?c$1.emptyScript:"",p$2=a$1.reactiveElementPolyfillSupport,d$1=(t,s)=>t,u$1={toAttribute(t,s){switch(s){case Boolean:t=t?l$1:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t);}return t},fromAttribute(t,s){let i=t;switch(s){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t);}catch(t){i=null;}}return i}},f$1=(t,s)=>!i$2(t,s),y$1={attribute:true,type:String,converter:u$1,reflect:false,hasChanged:f$1};Symbol.metadata??=Symbol("metadata"),a$1.litPropertyMetadata??=new WeakMap;class b extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t);}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,s=y$1){if(s.state&&(s.attribute=false),this._$Ei(),this.elementProperties.set(t,s),!s.noAccessor){const i=Symbol(),r=this.getPropertyDescriptor(t,i,s);void 0!==r&&e$3(this.prototype,t,r);}}static getPropertyDescriptor(t,s,i){const{get:e,set:h}=r$3(this.prototype,t)??{get(){return this[s]},set(t){this[s]=t;}};return {get(){return e?.call(this)},set(s){const r=e?.call(this);h.call(this,s),this.requestUpdate(t,r,i);},configurable:true,enumerable:true}}static getPropertyOptions(t){return this.elementProperties.get(t)??y$1}static _$Ei(){if(this.hasOwnProperty(d$1("elementProperties")))return;const t=n$2(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties);}static finalize(){if(this.hasOwnProperty(d$1("finalized")))return;if(this.finalized=true,this._$Ei(),this.hasOwnProperty(d$1("properties"))){const t=this.properties,s=[...h$1(t),...o$2(t)];for(const i of s)this.createProperty(i,t[i]);}const t=this[Symbol.metadata];if(null!==t){const s=litPropertyMetadata.get(t);if(void 0!==s)for(const[t,i]of s)this.elementProperties.set(t,i);}this._$Eh=new Map;for(const[t,s]of this.elementProperties){const i=this._$Eu(t,s);void 0!==i&&this._$Eh.set(i,t);}this.elementStyles=this.finalizeStyles(this.styles);}static finalizeStyles(s){const i=[];if(Array.isArray(s)){const e=new Set(s.flat(1/0).reverse());for(const s of e)i.unshift(c$2(s));}else void 0!==s&&i.push(c$2(s));return i}static _$Eu(t,s){const i=s.attribute;return false===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=false,this.hasUpdated=false,this._$Em=null,this._$Ev();}_$Ev(){this._$ES=new Promise((t=>this.enableUpdating=t)),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach((t=>t(this)));}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.();}removeController(t){this._$EO?.delete(t);}_$E_(){const t=new Map,s=this.constructor.elementProperties;for(const i of s.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t);}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return S$1(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(true),this._$EO?.forEach((t=>t.hostConnected?.()));}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach((t=>t.hostDisconnected?.()));}attributeChangedCallback(t,s,i){this._$AK(t,i);}_$EC(t,s){const i=this.constructor.elementProperties.get(t),e=this.constructor._$Eu(t,i);if(void 0!==e&&true===i.reflect){const r=(void 0!==i.converter?.toAttribute?i.converter:u$1).toAttribute(s,i.type);this._$Em=t,null==r?this.removeAttribute(e):this.setAttribute(e,r),this._$Em=null;}}_$AK(t,s){const i=this.constructor,e=i._$Eh.get(t);if(void 0!==e&&this._$Em!==e){const t=i.getPropertyOptions(e),r="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:u$1;this._$Em=e,this[e]=r.fromAttribute(s,t.type),this._$Em=null;}}requestUpdate(t,s,i){if(void 0!==t){if(i??=this.constructor.getPropertyOptions(t),!(i.hasChanged??f$1)(this[t],s))return;this.P(t,s,i);} false===this.isUpdatePending&&(this._$ES=this._$ET());}P(t,s,i){this._$AL.has(t)||this._$AL.set(t,s),true===i.reflect&&this._$Em!==t&&(this._$Ej??=new Set).add(t);}async _$ET(){this.isUpdatePending=true;try{await this._$ES;}catch(t){Promise.reject(t);}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,s]of this._$Ep)this[t]=s;this._$Ep=void 0;}const t=this.constructor.elementProperties;if(t.size>0)for(const[s,i]of t) true!==i.wrapped||this._$AL.has(s)||void 0===this[s]||this.P(s,this[s],i);}let t=false;const s=this._$AL;try{t=this.shouldUpdate(s),t?(this.willUpdate(s),this._$EO?.forEach((t=>t.hostUpdate?.())),this.update(s)):this._$EU();}catch(s){throw t=false,this._$EU(),s}t&&this._$AE(s);}willUpdate(t){}_$AE(t){this._$EO?.forEach((t=>t.hostUpdated?.())),this.hasUpdated||(this.hasUpdated=true,this.firstUpdated(t)),this.updated(t);}_$EU(){this._$AL=new Map,this.isUpdatePending=false;}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return true}update(t){this._$Ej&&=this._$Ej.forEach((t=>this._$EC(t,this[t]))),this._$EU();}updated(t){}firstUpdated(t){}}b.elementStyles=[],b.shadowRootOptions={mode:"open"},b[d$1("elementProperties")]=new Map,b[d$1("finalized")]=new Map,p$2?.({ReactiveElement:b}),(a$1.reactiveElementVersions??=[]).push("2.0.4"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const t=globalThis,i$1=t.trustedTypes,s=i$1?i$1.createPolicy("lit-html",{createHTML:t=>t}):void 0,e$2="$lit$",h=`lit$${Math.random().toFixed(9).slice(2)}$`,o$1="?"+h,n$1=`<${o$1}>`,r$2=document,l=()=>r$2.createComment(""),c=t=>null===t||"object"!=typeof t&&"function"!=typeof t,a=Array.isArray,u=t=>a(t)||"function"==typeof t?.[Symbol.iterator],d="[ \t\n\f\r]",f=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,v=/-->/g,_=/>/g,m=RegExp(`>|${d}(?:([^\\s"'>=/]+)(${d}*=${d}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),p$1=/'/g,g=/"/g,$=/^(?:script|style|textarea|title)$/i,y=t=>(i,...s)=>({_$litType$:t,strings:i,values:s}),x=y(1),T=Symbol.for("lit-noChange"),E=Symbol.for("lit-nothing"),A=new WeakMap,C=r$2.createTreeWalker(r$2,129);function P(t,i){if(!a(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==s?s.createHTML(i):i}const V=(t,i)=>{const s=t.length-1,o=[];let r,l=2===i?"":3===i?"":"",c=f;for(let i=0;i"===u[0]?(c=r??f,d=-1):void 0===u[1]?d=-2:(d=c.lastIndex-u[2].length,a=u[1],c=void 0===u[3]?m:'"'===u[3]?g:p$1):c===g||c===p$1?c=m:c===v||c===_?c=f:(c=m,r=void 0);const x=c===m&&t[i+1].startsWith("/>")?" ":"";l+=c===f?s+n$1:d>=0?(o.push(a),s.slice(0,d)+e$2+s.slice(d)+h+x):s+h+(-2===d?i:x);}return [P(t,l+(t[s]||"")+(2===i?"":3===i?"":"")),o]};class N{constructor({strings:t,_$litType$:s},n){let r;this.parts=[];let c=0,a=0;const u=t.length-1,d=this.parts,[f,v]=V(t,s);if(this.el=N.createElement(f,n),C.currentNode=this.el.content,2===s||3===s){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes);}for(;null!==(r=C.nextNode())&&d.length0){r.textContent=i$1?i$1.emptyScript:"";for(let i=0;i2||""!==s[0]||""!==s[1]?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=E;}_$AI(t,i=this,s,e){const h=this.strings;let o=false;if(void 0===h)t=S(this,t,i,0),o=!c(t)||t!==this._$AH&&t!==T,o&&(this._$AH=t);else {const e=t;let n,r;for(t=h[0],n=0;n{const e=s?.renderBefore??i;let h=e._$litPart$;if(void 0===h){const t=s?.renderBefore??null;e._$litPart$=h=new R(i.insertBefore(l(),t),t,void 0,s??{});}return h._$AI(t),h}; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */let r$1 = class r extends b{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0;}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const s=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=B(s,this.renderRoot,this.renderOptions);}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(true);}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(false);}render(){return T}};r$1._$litElement$=true,r$1["finalized"]=true,globalThis.litElementHydrateSupport?.({LitElement:r$1});const i=globalThis.litElementPolyfillSupport;i?.({LitElement:r$1});(globalThis.litElementVersions??=[]).push("4.1.1"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */const o={attribute:true,type:String,converter:u$1,reflect:false,hasChanged:f$1},r=(t=o,e,r)=>{const{kind:n,metadata:i}=r;let s=globalThis.litPropertyMetadata.get(i);if(void 0===s&&globalThis.litPropertyMetadata.set(i,s=new Map),s.set(r.name,t),"accessor"===n){const{name:o}=r;return {set(r){const n=e.get.call(this);e.set.call(this,r),this.requestUpdate(o,n,t);},init(e){return void 0!==e&&this.P(o,void 0,t),e}}}if("setter"===n){const{name:o}=r;return function(r){const n=this[o];e.call(this,r),this.requestUpdate(o,n,t);}}throw Error("Unsupported decorator location: "+n)};function n(t){return (e,o)=>"object"==typeof o?r(t,e,o):((t,e,o)=>{const r=e.hasOwnProperty(o);return e.constructor.createProperty(o,r?{...t,wrapped:true}:t),r?Object.getOwnPropertyDescriptor(e,o):void 0})(t,e,o)} /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ const e$1=(e,t,c)=>(c.configurable=true,c.enumerable=true,c); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */function e(e,r){return (n,s,i)=>{const o=t=>t.renderRoot?.querySelector(e)??null;return e$1(n,s,{get(){return o(this)}})}} /* @license * Copyright 2019 Google LLC. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var __decorate$4 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; const PIXEL_SIZE = 10; class MagnifyingGlass extends r$1 { constructor() { super(...arguments); this.imageAccessor = null; this.pixel = null; this.direction = 'vertical'; this.position = { x: 0, y: 0 }; this.context = null; this.xRay = true; this.reticleSize = 1; } enhance() { if (this.pixel == null || this.imageAccessor == null) { return; } this.classList.remove('hidden'); if (this.context == null) { const canvas = this.shadowRoot.querySelector('canvas'); if (canvas == null) { return; } this.context = canvas.getContext('2d'); } const { context } = this; const rect = this.getBoundingClientRect(); const scale = rect.width / this.imageAccessor.width; for (let y = 0; y < 24; ++y) { for (let x = 0; x < 24; ++x) { context.fillStyle = this.imageAccessor.cssColorAt(this.pixel.x + x - 12, this.pixel.y + y - 12); context.fillRect(x * PIXEL_SIZE, y * PIXEL_SIZE, PIXEL_SIZE, PIXEL_SIZE); } } this.reticleSize = Math.round(26 * scale); this.position = { x: this.pixel.x * scale - 130, y: this.pixel.y * scale - 130 }; } toggleXRay() { this.xRay = !this.xRay; } hide() { this.classList.add('hidden'); } get glassPosition() { const { width, height } = this.imageAccessor != null ? this.imageAccessor : { width: 0, height: 0 }; const { x, y } = this.pixel != null ? this.pixel : { x: 0, y: 0 }; return this.direction === 'horizontal' ? x < (width / 2) ? 'right' : 'left' : y < (height / 2) ? 'bottom' : 'top'; } render() { this.enhance(); return x `
`; } } __decorate$4([ n({ type: Object }) ], MagnifyingGlass.prototype, "imageAccessor", void 0); __decorate$4([ n({ type: Object }) ], MagnifyingGlass.prototype, "pixel", void 0); __decorate$4([ n({ type: String }) ], MagnifyingGlass.prototype, "direction", void 0); __decorate$4([ n({ type: Object }) ], MagnifyingGlass.prototype, "position", void 0); __decorate$4([ n({ type: Boolean }) ], MagnifyingGlass.prototype, "xRay", void 0); __decorate$4([ n({ type: Number }) ], MagnifyingGlass.prototype, "reticleSize", void 0); customElements.define('magnifying-glass', MagnifyingGlass); /* @license * Copyright 2019 Google LLC. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var __decorate$3 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; class Images4Up extends r$1 { constructor() { super(...arguments); this.topLeftImageAccessor = null; this.topRightImageAccessor = null; this.bottomLeftImageAccessor = null; this.bottomRightImageAccessor = null; this.magnifiedPixel = null; this.dimensions = { width: 0, height: 0 }; this.containerRect = { x: 0, y: 0, width: 0, height: 0 }; } localCoordinateToImagePixel(localX, localY) { const constrainedX = Math.min(Math.max(localX - this.containerRect.x, -1), this.containerRect.width + 1); const constrainedY = Math.min(Math.max(localY - this.containerRect.y, -1), this.containerRect.height + 1); const scaledWidth = this.containerRect.width / 2; const scaledHeight = this.containerRect.height / 2; const scale = this.dimensions.width / scaledWidth; return { x: Math.floor((constrainedX % scaledWidth) * scale), y: Math.floor((constrainedY % scaledHeight) * scale) }; } selectPixel(pixel) { this.magnifiedPixel = pixel; this.dispatchEvent(new CustomEvent('select-pixel', { detail: pixel })); } onPointerEvent(event) { const pixel = this.localCoordinateToImagePixel(event.x, event.y); if (pixel.x > -1 && pixel.x < this.dimensions.width && pixel.y > -1 && pixel.y < this.dimensions.height) { this.selectPixel(pixel); } else { this.magnifiedPixel = null; } } connectedCallback() { super.connectedCallback && super.connectedCallback(); self.addEventListener('resize', (_event) => this.updateSize()); } updateSize() { const rect = this.getBoundingClientRect(); const { width: containerWidth, height: containerHeight } = rect; const fourUpWidth = 2 * this.dimensions.width; const fourUpHeight = 2 * this.dimensions.height; const containerAspectRatio = containerWidth / containerHeight; const fourUpAspectRatio = fourUpWidth / fourUpHeight; const scale = fourUpAspectRatio < containerAspectRatio ? containerHeight / fourUpHeight : containerWidth / fourUpWidth; const width = scale * fourUpWidth; const height = scale * fourUpHeight; const x = (containerWidth - width) / 2; const y = (containerHeight - height) / 2; this.containerRect = { x, y, width, height }; } async updated(changedProperties) { super.updated(changedProperties); if (changedProperties.has('dimensions') && this.dimensions != null) { this.updateSize(); this.selectPixel({ x: Math.floor(this.dimensions.width / 2), y: Math.floor(this.dimensions.height / 2) }); } } render() { const { x: x$1, y, width, height } = this.containerRect; return x `
`; } } __decorate$3([ n({ type: Object }) ], Images4Up.prototype, "topLeftImageAccessor", void 0); __decorate$3([ n({ type: Object }) ], Images4Up.prototype, "topRightImageAccessor", void 0); __decorate$3([ n({ type: Object }) ], Images4Up.prototype, "bottomLeftImageAccessor", void 0); __decorate$3([ n({ type: Object }) ], Images4Up.prototype, "bottomRightImageAccessor", void 0); __decorate$3([ n({ type: Object }) ], Images4Up.prototype, "magnifiedPixel", void 0); __decorate$3([ n({ type: Object }) ], Images4Up.prototype, "dimensions", void 0); __decorate$3([ n({ type: Object }) ], Images4Up.prototype, "containerRect", void 0); customElements.define('images-4-up', Images4Up); /** @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 */ const nativeShadow = !( window['ShadyDOM'] && window['ShadyDOM']['inUse'] ); /** @type {boolean} */ let nativeCssVariables_; /** * @param {(ShadyCSSOptions | ShadyCSSInterface)=} settings */ function calcCssVariables(settings) { if (settings && settings.shimcssproperties) { nativeCssVariables_ = false; } else { // chrome 49 has semi-working css vars, check if box-shadow works // safari 9.1 has a recalc bug: https://bugs.webkit.org/show_bug.cgi?id=155782 // However, shim css custom properties are only supported with ShadyDOM enabled, // so fall back on native if we do not detect ShadyDOM // Edge 15: custom properties used in ::before and ::after will also be used in the parent element // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12414257/ nativeCssVariables_ = nativeShadow || Boolean( !navigator.userAgent.match(/AppleWebKit\/601|Edge\/15/) && window.CSS && CSS.supports && CSS.supports('box-shadow', '0 0 0 var(--foo)') ); } } /** @type {string | undefined} */ let cssBuild; if (window.ShadyCSS && window.ShadyCSS.cssBuild !== undefined) { cssBuild = window.ShadyCSS.cssBuild; } /** @type {boolean} */ const disableRuntime = Boolean( window.ShadyCSS && window.ShadyCSS.disableRuntime ); if (window.ShadyCSS && window.ShadyCSS.nativeCss !== undefined) { nativeCssVariables_ = window.ShadyCSS.nativeCss; } else if (window.ShadyCSS) { calcCssVariables(window.ShadyCSS); // reset window variable to let ShadyCSS API take its place window.ShadyCSS = undefined; } else { calcCssVariables(window['WebComponents'] && window['WebComponents']['flags']); } // Hack for type error under new type inference which doesn't like that // nativeCssVariables is updated in a function and assigns the type // `function(): ?` instead of `boolean`. const nativeCssVariables = /** @type {boolean} */ (nativeCssVariables_); /** @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 */ /** @unrestricted */ class StyleNode { constructor() { /** @type {number} */ this['start'] = 0; /** @type {number} */ this['end'] = 0; /** @type {StyleNode} */ this['previous'] = null; /** @type {StyleNode} */ this['parent'] = null; /** @type {Array} */ this['rules'] = null; /** @type {string} */ this['parsedCssText'] = ''; /** @type {string} */ this['cssText'] = ''; /** @type {boolean} */ this['atRule'] = false; /** @type {number} */ this['type'] = 0; /** @type {string} */ this['keyframesName'] = ''; /** @type {string} */ this['selector'] = ''; /** @type {string} */ this['parsedSelector'] = ''; } } // given a string of css, return a simple rule tree /** * @param {string} text * @return {StyleNode} */ function parse(text) { text = clean(text); return parseCss(lex(text), text); } // remove stuff we don't care about that may hinder parsing /** * @param {string} cssText * @return {string} */ function clean(cssText) { return cssText.replace(RX.comments, '').replace(RX.port, ''); } // super simple {...} lexer that returns a node tree /** * @param {string} text * @return {!StyleNode} */ function lex(text) { let root = new StyleNode(); root['start'] = 0; root['end'] = text.length; let n = root; for (let i = 0, l = text.length; i < l; i++) { if (text[i] === OPEN_BRACE) { if (!n['rules']) { n['rules'] = []; } let p = n; let previous = p['rules'][p['rules'].length - 1] || null; n = new StyleNode(); n['start'] = i + 1; n['parent'] = p; n['previous'] = previous; p['rules'].push(n); } else if (text[i] === CLOSE_BRACE) { n['end'] = i + 1; n = n['parent'] || root; } } return root; } // add selectors/cssText to node tree /** * @param {StyleNode} node * @param {string} text * @return {!StyleNode} */ function parseCss(node, text) { let t = text.substring(node['start'], node['end'] - 1); node['parsedCssText'] = node['cssText'] = t.trim(); if (node['parent']) { let ss = node['previous'] ? node['previous']['end'] : node['parent']['start']; t = text.substring(ss, node['start'] - 1); t = _expandUnicodeEscapes(t); t = t.replace(RX.multipleSpaces, ' '); // TODO(sorvell): ad hoc; make selector include only after last ; // helps with mixin syntax t = t.substring(t.lastIndexOf(';') + 1); let s = (node['parsedSelector'] = node['selector'] = t.trim()); node['atRule'] = s.indexOf(AT_START) === 0; // note, support a subset of rule types... if (node['atRule']) { if (s.indexOf(MEDIA_START) === 0) { node['type'] = types.MEDIA_RULE; } else if (s.match(RX.keyframesRule)) { node['type'] = types.KEYFRAMES_RULE; node['keyframesName'] = node['selector'].split(RX.multipleSpaces).pop(); } } else { if (s.indexOf(VAR_START) === 0) { node['type'] = types.MIXIN_RULE; } else { node['type'] = types.STYLE_RULE; } } } let r$ = node['rules']; if (r$) { for (let i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) { parseCss(r, text); } } return node; } /** * conversion of sort unicode escapes with spaces like `\33 ` (and longer) into * expanded form that doesn't require trailing space `\000033` * @param {string} s * @return {string} */ function _expandUnicodeEscapes(s) { return s.replace(/\\([0-9a-f]{1,6})\s/gi, function () { let code = arguments[1], repeat = 6 - code.length; while (repeat--) { code = '0' + code; } return '\\' + code; }); } /** * stringify parsed css. * @param {StyleNode} node * @param {boolean=} preserveProperties * @param {string=} text * @return {string} */ function stringify(node, preserveProperties, text = '') { // calc rule cssText let cssText = ''; if (node['cssText'] || node['rules']) { let r$ = node['rules']; if (r$ && !_hasMixinRules(r$)) { for (let i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) { cssText = stringify(r, preserveProperties, cssText); } } else { cssText = preserveProperties ? node['cssText'] : removeCustomProps(node['cssText']); cssText = cssText.trim(); if (cssText) { cssText = ' ' + cssText + '\n'; } } } // emit rule if there is cssText if (cssText) { if (node['selector']) { text += node['selector'] + ' ' + OPEN_BRACE + '\n'; } text += cssText; if (node['selector']) { text += CLOSE_BRACE + '\n\n'; } } return text; } /** * @param {Array} rules * @return {boolean} */ function _hasMixinRules(rules) { let r = rules[0]; return ( Boolean(r) && Boolean(r['selector']) && r['selector'].indexOf(VAR_START) === 0 ); } /** * @param {string} cssText * @return {string} */ function removeCustomProps(cssText) { cssText = removeCustomPropAssignment(cssText); return removeCustomPropApply(cssText); } /** * @param {string} cssText * @return {string} */ function removeCustomPropAssignment(cssText) { return cssText.replace(RX.customProp, '').replace(RX.mixinProp, ''); } /** * @param {string} cssText * @return {string} */ function removeCustomPropApply(cssText) { return cssText.replace(RX.mixinApply, '').replace(RX.varApply, ''); } /** @enum {number} */ const types = { STYLE_RULE: 1, KEYFRAMES_RULE: 7, MEDIA_RULE: 4, MIXIN_RULE: 1000, }; const OPEN_BRACE = '{'; const CLOSE_BRACE = '}'; // helper regexp's const RX = { comments: /\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim, port: /@import[^;]*;/gim, customProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?(?:[;\n]|$)/gim, mixinProp: /(?:^[^;\-\s}]+)?--[^;{}]*?:[^{};]*?{[^}]*?}(?:[;\n]|$)?/gim, mixinApply: /@apply\s*\(?[^);]*\)?\s*(?:[;\n]|$)?/gim, varApply: /[^;:]*?:[^;]*?var\([^;]*\)(?:[;\n]|$)?/gim, keyframesRule: /^@[^\s]*keyframes/, multipleSpaces: /\s+/g, }; const VAR_START = '--'; const MEDIA_START = '@media'; const AT_START = '@'; /** @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 */ const VAR_ASSIGN = /(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};{])+)|\{([^}]*)\}(?:(?=[;\s}])|$))/gi; const MIXIN_MATCH = /(?:^|\W+)@apply\s*\(?([^);\n]*)\)?/gi; /** @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 */ /** @type {!Set} */ const styleTextSet = new Set(); const scopingAttribute = 'shady-unscoped'; /** * Add a specifically-marked style to the document directly, and only one copy of that style. * * @param {!HTMLStyleElement} style * @return {undefined} */ function processUnscopedStyle(style) { const text = style.textContent; if (!styleTextSet.has(text)) { styleTextSet.add(text); const newStyle = document.createElement('style'); newStyle.setAttribute('shady-unscoped', ''); newStyle.textContent = text; document.head.appendChild(newStyle); } } /** * Check if a style is supposed to be unscoped * @param {!HTMLStyleElement} style * @return {boolean} true if the style has the unscoping attribute */ function isUnscopedStyle(style) { return style.hasAttribute(scopingAttribute); } /** @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 */ /** * @param {string|StyleNode} rules * @param {function(StyleNode)=} callback * @return {string} */ function toCssText(rules, callback) { if (!rules) { return ''; } if (typeof rules === 'string') { rules = parse(rules); } return stringify(rules, nativeCssVariables); } /** * @param {HTMLStyleElement} style * @return {StyleNode} */ function rulesForStyle(style) { if (!style['__cssRules'] && style.textContent) { style['__cssRules'] = parse(style.textContent); } return style['__cssRules'] || null; } /** * @param {StyleNode} node * @param {Function=} styleRuleCallback * @param {Function=} keyframesRuleCallback * @param {boolean=} onlyActiveRules */ function forEachRule( node, styleRuleCallback, keyframesRuleCallback, onlyActiveRules ) { if (!node) { return; } let skipRules = false; let type = node['type']; if (type === types.STYLE_RULE) { styleRuleCallback(node); } else if (type === types.MIXIN_RULE) { skipRules = true; } let r$ = node['rules']; if (r$ && !skipRules) { for (let i = 0, l = r$.length, r; i < l && (r = r$[i]); i++) { forEachRule(r, styleRuleCallback); } } } /** * Walk from text[start] matching parens and * returns position of the outer end paren * @param {string} text * @param {number} start * @return {number} */ function findMatchingParen(text, start) { let level = 0; for (let i = start, l = text.length; i < l; i++) { if (text[i] === '(') { level++; } else if (text[i] === ')') { if (--level === 0) { return i; } } } return -1; } /** * @param {string} str * @param {function(string, string, string, string)} callback */ function processVariableAndFallback(str, callback) { // find 'var(' let start = str.indexOf('var('); if (start === -1) { // no var?, everything is prefix return callback(str, '', '', ''); } //${prefix}var(${inner})${suffix} let end = findMatchingParen(str, start + 3); let inner = str.substring(start + 4, end); let prefix = str.substring(0, start); // suffix may have other variables let suffix = processVariableAndFallback(str.substring(end + 1), callback); let comma = inner.indexOf(','); // value and fallback args should be trimmed to match in property lookup if (comma === -1) { // variable, no fallback return callback(prefix, inner.trim(), '', suffix); } // var(${value},${fallback}) let value = inner.substring(0, comma).trim(); let fallback = inner.substring(comma + 1).trim(); return callback(prefix, value, fallback, suffix); } /** * @type {function(*):*} */ (window['ShadyDOM'] && window['ShadyDOM']['wrap']) || ((node) => node); /** * @param {Element | {is: string, extends: string}} element * @return {{is: string, typeExtension: string}} */ function getIsExtends(element) { let localName = element['localName']; let is = '', typeExtension = ''; /* NOTE: technically, this can be wrong for certain svg elements with `-` in the name like `` */ if (localName) { if (localName.indexOf('-') > -1) { is = localName; } else { typeExtension = localName; is = (element.getAttribute && element.getAttribute('is')) || ''; } } else { is = /** @type {?} */ (element).is; typeExtension = /** @type {?} */ (element).extends; } return {is, typeExtension}; } /** * @param {Element|DocumentFragment} element * @return {string} */ function gatherStyleText(element) { /** @type {!Array} */ const styleTextParts = []; const styles = /** @type {!NodeList} */ (element.querySelectorAll( 'style' )); for (let i = 0; i < styles.length; i++) { const style = styles[i]; if (isUnscopedStyle(style)) { if (!nativeShadow) { processUnscopedStyle(style); style.parentNode.removeChild(style); } } else { styleTextParts.push(style.textContent); style.parentNode.removeChild(style); } } return styleTextParts.join('').trim(); } const CSS_BUILD_ATTR = 'css-build'; /** * Return the polymer-css-build "build type" applied to this element * * @param {!HTMLElement} element * @return {string} Can be "", "shady", or "shadow" */ function getCssBuild(element) { if (cssBuild !== undefined) { return /** @type {string} */ (cssBuild); } if (element.__cssBuild === undefined) { // try attribute first, as it is the common case const attrValue = element.getAttribute(CSS_BUILD_ATTR); if (attrValue) { element.__cssBuild = attrValue; } else { const buildComment = getBuildComment(element); if (buildComment !== '') { // remove build comment so it is not needlessly copied into every element instance removeBuildComment(element); } element.__cssBuild = buildComment; } } return element.__cssBuild || ''; } /** * Check if the given element, either a