/**
* @summary aofl-picture
* @version 3.0.0
* @since 3.0.0
* @author Arian Khosravi <arian.khosravi@aofl.com>
*/
import {AoflElement} from '@aofl/element';
import style from './picture.css';
/**
* <aofl-picture> serves as a container for zero or more <aofl-source> and one <aofl-img> elements
* to provide versions of an image for different display sizes.
*
* @memberof module:@aofl/picture
* @extends {AoflElement}
*/
class AoflPicture extends AoflElement {
/**
* Creates an instance of AoflPicture.
*/
constructor() {
super();
this.img = null;
this.defaultSrc = null;
this.sources = [];
this.updateImageSrc = () => {
const matchedSource = AoflPicture.findMatchingSource(this.sources);
this.setMediaSrc(matchedSource);
};
}
/**
*
* @readonly
* @type {String}
*/
static get is() {
return 'aofl-picture';
}
/**
*
* @readonly
* @type {Object}
*/
static get properties() {
return {
'disable-sources': {type: Boolean}
};
}
/**
*
* @return {Object}
*/
render() {
return super.render((ctx, html) => html`<slot></slot>`, [style]);
}
/**
* setImg should be invoked by a slotted <aofl-img> and sets the aofl-img element as the main img element of aofl-picture.
*
* @param {HTMLElement} img
*/
setImg(img) {
/* istanbul ignore next */
if (this.img !== null) { return; }
this.img = img;
this.defaultSrc = {
src: this.img.src,
height: this.img.height,
width: this.img.width
};
this.updateImageSrc();
}
/**
* addSource should be invoked by a slotted <aofl-source> element and adds aofl-source elements as alternative
* sources for image besed on media attribute of aofl-source
*
* @param {String} source
*/
addSource(source) {
if (this['disable-sources']) return;
const mediaQuery = window.matchMedia(source.getAttribute('media'));
const sourceAttributes = {
src: source.getAttribute('srcset'),
height: source.getAttribute('height'),
width: source.getAttribute('width'),
mediaQuery
};
this.sources.push(sourceAttributes);
mediaQuery.addListener(this.updateImageSrc);
this.updateImageSrc();
}
/**
* Set's aofl-picture's image source to the matching aofl-source media query.
*
* @param {String} [source=this.defaultSrc]
*/
setMediaSrc(source = this.defaultSrc) {
if (!this.img) { return; }
const imgSrc = this.img.src;
if (imgSrc !== source.src) {
this.img.setAttribute('src', source.src);
/* istanbul ignore else */
if (source.width) {
this.img.setAttribute('width', source.width);
}
/* istanbul ignore else */
if (source.height) {
this.img.setAttribute('height', source.height);
}
}
}
/**
* Iterates through an array of sources and returns the first matching source.
*
* @param {Array} [sources=[]]
* @return {Object}
*/
static findMatchingSource(/* istanbul ignore next */sources = []) {
for (let i = 0; i < sources.length; i++) {
if (sources[i].mediaQuery.matches === true) {
return sources[i];
}
}
}
/**
*
*/
disconnectedCallback() {
for (let i = 0; i < this.sources.length; i++) {
this.sources[i].mediaQuery.removeListener(this.updateImageSrc);
}
super.disconnectedCallback();
}
}
if (window.customElements.get(AoflPicture.is) === void 0) {
window.customElements.define(AoflPicture.is, AoflPicture);
}
export default AoflPicture;