Skip to content

Commit

Permalink
refactor amp/bento-lightbox-gallery
Browse files Browse the repository at this point in the history
fix lightbox gallery deps
  • Loading branch information
kvchari committed Dec 14, 2021
1 parent a2a63a2 commit b8645c9
Show file tree
Hide file tree
Showing 5 changed files with 294 additions and 215 deletions.
4 changes: 2 additions & 2 deletions build-system/test-configs/dep-check-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,8 @@ exports.rules = [
'extensions/amp-base-carousel/1.0/scroller.js->extensions/amp-lightbox-gallery/1.0/component.js',
'extensions/amp-lightbox-gallery/1.0/provider.js->extensions/amp-lightbox/1.0/component.js',
'extensions/amp-lightbox-gallery/1.0/provider.js->extensions/amp-base-carousel/1.0/component.js',
'extensions/amp-lightbox-gallery/1.0/base-element.js->extensions/amp-lightbox/1.0/component.jss.js',
'extensions/amp-lightbox-gallery/1.0/base-element.js->extensions/amp-base-carousel/1.0/component.jss.js',
'extensions/amp-lightbox-gallery/1.0/element.js->extensions/amp-lightbox/1.0/component.jss.js',
'extensions/amp-lightbox-gallery/1.0/element.js->extensions/amp-base-carousel/1.0/component.jss.js',

// <amp-date-display> versions share these date format helpers
'extensions/amp-date-display/**->extensions/amp-date-display/format.js',
Expand Down
65 changes: 54 additions & 11 deletions extensions/amp-lightbox-gallery/1.0/amp-lightbox-gallery.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,28 @@ import {
} from '#core/constants/action-constants';
import {createElementWithAttributes} from '#core/dom';
import {elementByTag} from '#core/dom/query';
import {dict} from '#core/types/object';

import {isExperimentOn} from '#experiments';

import {AmpPreactBaseElement} from '#preact/amp-base-element';

import {Services} from '#service';

import {triggerAnalyticsEvent} from '#utils/analytics';
import {userAssert} from '#utils/log';

import {BaseElement} from './base-element';
import {
Component,
afterLightboxGalleryClose,
beforeLightboxGalleryOpen,
checkNumInstancesOnMount,
checkNumInstancesOnUnmount,
getLightboxElements,
props,
shadowCss,
usesShadowDom,
} from './element';

import {CSS} from '../../../build/amp-lightbox-gallery-1.0.css';

Expand All @@ -22,7 +35,7 @@ const TAG = 'amp-lightbox-gallery';
/** @const {string} */
const DEFAULT_GALLERY_ID = 'amp-lightbox-gallery';

class AmpLightboxGallery extends BaseElement {
class AmpLightboxGallery extends AmpPreactBaseElement {
/** @override */
constructor(element) {
super(element);
Expand All @@ -48,7 +61,18 @@ class AmpLightboxGallery extends BaseElement {
(api, invocation) => this.openAction(api, invocation),
ActionTrust_Enum.HIGH
);
return super.init();
const lightboxElements = getLightboxElements(
this.element.ownerDocument,
(opt_index, opt_group) => this.api().open(opt_index, opt_group)
);
return dict({
'onBeforeOpen': () => this.beforeOpen(),
'onAfterOpen': () => this.afterOpen(),
'onAfterClose': () => this.afterClose(),
'onViewGrid': () => this.onViewGrid(),
'onToggleCaption': () => this.onToggleCaption(),
'render': () => lightboxElements,
});
}

/**
Expand All @@ -74,11 +98,15 @@ class AmpLightboxGallery extends BaseElement {
return super.isLayoutSupported(layout);
}

/** @protected */
beforeOpen() {
beforeLightboxGalleryOpen(this.element);
}

/** @override */
afterOpen() {
super.afterOpen();
const scroller = this.element.shadowRoot.querySelector('[part=scroller]');
this.setAsContainer?.(scroller);
this.setAsContainer(scroller);
triggerAnalyticsEvent(this.element, 'lightboxOpened');

this.history_
Expand All @@ -88,8 +116,8 @@ class AmpLightboxGallery extends BaseElement {

/** @override */
afterClose() {
super.afterClose();
this.removeAsContainer?.();
afterLightboxGalleryClose(this.element);
this.removeAsContainer();

if (this.historyId_ != null) {
this.history_.pop(this.historyId_);
Expand All @@ -99,23 +127,38 @@ class AmpLightboxGallery extends BaseElement {

/** @override */
onViewGrid() {
super.onViewGrid();
triggerAnalyticsEvent(this.element, 'thumbnailsViewToggled');
}

/** @override */
onToggleCaption() {
super.onToggleCaption();
triggerAnalyticsEvent(this.element, 'descriptionOverflowToggled');
}

/** @override */
mountCallback() {
checkNumInstancesOnMount(this.element);
}

/** @override */
unmountCallback() {
super.unmountCallback();
this.removeAsContainer?.();
checkNumInstancesOnUnmount();
this.removeAsContainer();
}
}

/** @override */
AmpLightboxGallery['Component'] = Component;

/** @override */
AmpLightboxGallery['props'] = props;

/** @override */
AmpLightboxGallery['usesShadowDom'] = usesShadowDom;

/** @override */
AmpLightboxGallery['shadowCss'] = shadowCss;

/**
* Tries to find an existing amp-lightbox-gallery, if there is none, it adds a
* default one.
Expand Down
217 changes: 19 additions & 198 deletions extensions/amp-lightbox-gallery/1.0/base-element.js
Original file line number Diff line number Diff line change
@@ -1,68 +1,23 @@
import {toggleAttribute} from '#core/dom';
import {
childElement,
closestAncestorElementBySelector,
elementByTag,
} from '#core/dom/query';
import {srcsetFromElement} from '#core/dom/srcset';
import {toggle} from '#core/dom/style';
import {toArray} from '#core/types/array';
import {dict} from '#core/types/object';

import * as Preact from '#preact';
import {PreactBaseElement} from '#preact/base-element';

import {
BentoLightboxGalleryProvider,
WithBentoLightboxGallery,
} from './component';
import {CSS as COMPONENT_CSS} from './component.jss';

import {CSS as CAROUSEL_CSS} from '../../amp-base-carousel/1.0/component.jss';
import {CSS as LIGHTBOX_CSS} from '../../amp-lightbox/1.0/component.jss';

/** @const {!Array<string>} */
const LIGHTBOX_ELIGIBLE_TAGS = ['AMP-IMG', 'IMG'];

/** @const {!Array<string>} */
const LIGHTBOX_ELIGIBLE_GROUP_SELECTORS = [
'AMP-BASE-CAROUSEL[lightbox]',
'AMP-STREAM-GALLERY[lightbox]',
'BENTO-BASE-CAROUSEL[lightbox]',
'BENTO-STREAM-GALLERY[lightbox]',
];

/** @const {string} */
const LIGHTBOX_ATTR = 'lightbox';

/** @const {string} */
const DEFAULT_GROUP = 'default';

/** @const {string} */
const DEFAULT_CAROUSEL_PREFIX = 'carousel';

/** @const {number} */
let count = 0;
Component,
afterLightboxGalleryClose,
beforeLightboxGalleryOpen,
checkNumInstancesOnMount,
checkNumInstancesOnUnmount,
getLightboxElements,
props,
shadowCss,
usesShadowDom,
} from './element';

export class BaseElement extends PreactBaseElement {
/** @param {!AmpElement} element */
constructor(element) {
super(element);

/** @private {boolean} */
this.open_ = false;
}

/** @override */
mountCallback() {
// There should only be one instance of `amp-lightbox-gallery` in a document.
if (count++) {
console /*OK */
.warn(
`${this.element.tagName} already exists in the document. Removing additional instance: ${this.element}`
);
this.element.parentNode?.removeChild(this.element);
}
checkNumInstancesOnMount(this.element);
}

/** @override */
Expand All @@ -73,169 +28,35 @@ export class BaseElement extends PreactBaseElement {
);
return dict({
'onBeforeOpen': () => this.beforeOpen(),
'onAfterOpen': () => this.afterOpen(),
'onAfterClose': () => this.afterClose(),
'onViewGrid': () => this.onViewGrid(),
'onToggleCaption': () => this.onToggleCaption(),
'render': () => lightboxElements,
});
}

/** @override */
unmountCallback() {
count--;
checkNumInstancesOnUnmount();
}

/** @protected */
beforeOpen() {
this.open_ = true;
toggleAttribute(this.element, 'open', true);
toggle(this.element, true);
beforeLightboxGalleryOpen(this.element);
}

/** @protected */
afterOpen() {}

/** @protected */
afterClose() {
this.open_ = false;
toggleAttribute(this.element, 'open', false);
toggle(this.element, false);
}

/** @protected */
onViewGrid() {}

/** @protected */
onToggleCaption() {}

/** @override */
mutationObserverCallback() {
const open = this.element.hasAttribute('open');
if (open === this.open_) {
return;
}
this.open_ = open;
open ? this.api().open() : this.api().close();
afterLightboxGalleryClose(this.element);
}
}

/**
* @param {!Document} document
* @param {function(number)} open
* @return {!Array<PreactDef.Renderable>}
*/
function getLightboxElements(document, open) {
const lightboxElements = [];

// Process all standalone elements into a lightbox.
toArray(document.querySelectorAll(LIGHTBOX_ELIGIBLE_TAGS)).forEach(
(element) => {
if (element.hasAttribute(LIGHTBOX_ATTR)) {
lightboxElements.push(
processLightboxElement(DEFAULT_GROUP, document, element, open)
);
}
}
);

// Process all lightboxed carousel elements into separate lightbox groups.
toArray(document.querySelectorAll(LIGHTBOX_ELIGIBLE_GROUP_SELECTORS)).forEach(
(element, index) => {
const group =
element.getAttribute(LIGHTBOX_ATTR) || DEFAULT_CAROUSEL_PREFIX + index;
toArray(element.children).forEach((child, index) =>
lightboxElements.push(
processLightboxElement(group, document, child, open, index)
)
);
}
);

return lightboxElements;
}

/**
* @param {string} defaultGroup
* @param {!Document} document
* @param {Element} element
* @param {function(number)} open
* @param {number} opt_index
* @return {PreactDef.Renderable}
*/
function processLightboxElement(
defaultGroup,
document,
element,
open,
opt_index
) {
const group = element.getAttribute(LIGHTBOX_ATTR) || defaultGroup;
const img = isLightboxEligible(element)
? element
: childElement(element, isLightboxEligible);
return (
<WithBentoLightboxGallery
group={group}
as="img"
caption={getDescriptionForElement(document, img)}
onMount={(index) => {
const onClick = () => open(opt_index ?? index, group);
element.addEventListener('click', onClick);
return () => {
element.removeEventListener('click', onClick);
};
}}
srcset={srcsetFromElement(img).stringify()}
/>
);
}

/**
* @param {Element} element
* @return {boolean}
*/
function isLightboxEligible(element) {
return LIGHTBOX_ELIGIBLE_TAGS.indexOf(element.tagName) !== -1;
}

/**
* @param {!Document} document
* @param {Element} element
* @return {string}
*/
function getDescriptionForElement(document, element) {
// If the element in question is the descendant of a figure element
// try using the figure caption as the lightbox description.
const figureParent = closestAncestorElementBySelector(element, 'figure');
if (figureParent) {
const figCaption = elementByTag(figureParent, 'figcaption');
if (figCaption) {
return figCaption./*OK*/ textContent;
}
}
const ariaDescribedBy = element.getAttribute('aria-describedby');
if (ariaDescribedBy) {
const descriptionElement = document.getElementById(ariaDescribedBy);
if (descriptionElement) {
return descriptionElement./*OK*/ textContent;
}
}
const ariaLabelledBy = element.getAttribute('aria-labelledby');
if (ariaLabelledBy) {
const descriptionElement = document.getElementById(ariaLabelledBy);
if (descriptionElement) {
return descriptionElement./*OK*/ innerText;
}
}
return element.getAttribute('alt') ?? element.getAttribute('aria-label');
}
/** @override */
BaseElement['Component'] = Component;

/** @override */
BaseElement['Component'] = BentoLightboxGalleryProvider;
BaseElement['props'] = props;

/** @override */
BaseElement['usesShadowDom'] = true;
BaseElement['usesShadowDom'] = usesShadowDom;

/** @override */
BaseElement['shadowCss'] = COMPONENT_CSS + LIGHTBOX_CSS + CAROUSEL_CSS;
BaseElement['shadowCss'] = shadowCss;
Loading

0 comments on commit b8645c9

Please sign in to comment.