Skip to content

Commit

Permalink
Classical amp-inline-gallery-captions (0.1) (#32075)
Browse files Browse the repository at this point in the history
* git cherry-pick 8cfe718

* Fix missed parameter

* Lint fixes

* gulp presubmit

* Add experiments

* Pass slides in last

Co-authored-by: Sepand Parhami <sparhami@google.com>
  • Loading branch information
caroqliu and Sepand Parhami committed Feb 24, 2021
1 parent aeccddf commit 0adf076
Show file tree
Hide file tree
Showing 9 changed files with 454 additions and 9 deletions.
2 changes: 2 additions & 0 deletions build-system/compile/bundles.config.extensions.json
Expand Up @@ -220,7 +220,9 @@
"hasCss": true,
"cssBinaries": [
"amp-inline-gallery",
"amp-inline-gallery-captions",
"amp-inline-gallery-pagination",
"amp-inline-gallery-slide",
"amp-inline-gallery-thumbnails"
]
}
Expand Down
21 changes: 21 additions & 0 deletions extensions/amp-inline-gallery/0.1/amp-inline-gallery-captions.css
@@ -0,0 +1,21 @@
/**
* Copyright 2021 The AMP HTML Authors. 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.
*/

amp-inline-gallery-captions {
pointer-events: none;
padding-top: var(--caption-margin-top);
margin-top: calc(-1 * var(--i-amphtml-caption-height, 0));
}
91 changes: 91 additions & 0 deletions extensions/amp-inline-gallery/0.1/amp-inline-gallery-captions.js
@@ -0,0 +1,91 @@
/**
* Copyright 2019 The AMP HTML Authors. 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.
*/

import {closestAncestorElementBySelector} from '../../../src/dom';
import {exponentialFalloff} from './amp-inline-gallery-pagination';
import {isExperimentOn} from '../../../src/experiments';
import {isLayoutSizeDefined} from '../../../src/layout';
import {setImportantStyles} from '../../../src/style.js';
import {userAssert} from '../../../src/log';

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

/** @override */
isRelayoutNeeded() {
return true;
}

/** @override */
isLayoutSupported(layout) {
userAssert(
isExperimentOn(this.win, 'amp-inline-gallery-captions') ||
'expected "amp-inline-gallery-captions" experiment to be enabled'
);
return isLayoutSizeDefined(layout);
}

/** @override */
layoutCallback() {
const {height} = this./*OK*/ getLayoutBox();
const parentGallery = closestAncestorElementBySelector(
this.element,
'amp-inline-gallery'
);

setImportantStyles(parentGallery, {
'--i-amphtml-caption-height': `${height}px`,
});
}

/**
* @param {number} unusedTotal
* @param {number} index
* @param {number} offset
* @param {!Array<!Element>} slides
*/
updateProgress(unusedTotal, index, offset, slides) {
this.mutateElement(() => {
this.updateCaptionOpacities_(slides, index, offset);
});
}

/**
* Updates the opacities of the captions, based on their distance from the
* current slide.
* @param {!Array<!Element>} slides
* @param {number} index
* @param {number} offset
*/
updateCaptionOpacities_(slides, index, offset) {
slides.forEach((slide, i) => {
const indexDistance = Math.abs(index + offset - i);
// Want to fall off to zero at the mid way point, the next/prev slide
// will start fading in at the same time.
const falloffDistance = Math.min(2 * indexDistance, 1);
const opacity = exponentialFalloff(falloffDistance, 3);
setImportantStyles(slide, {
'--caption-opacity': opacity,
// Need to prevent pointer events on all other slide's captions so
// that the user can select the caption text, click on links, etc.
'pointer-events': opacity == 0 ? 'none' : 'all',
});
});
}
}
Expand Up @@ -254,8 +254,9 @@ export class AmpInlineGalleryPagination extends AMP.BaseElement {
* @param {number} total
* @param {number} index
* @param {number} offset
* @param {!Array<!Element>} unusedSlides
*/
updateProgress(total, index, offset) {
updateProgress(total, index, offset, unusedSlides) {
this.mutateElement(() => {
this.updateTotal_(total);
this.updateDots_(index, offset);
Expand Down
86 changes: 86 additions & 0 deletions extensions/amp-inline-gallery/0.1/amp-inline-gallery-slide.css
@@ -0,0 +1,86 @@
/**
* Copyright 2021 The AMP HTML Authors. 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.
*/

amp-inline-gallery-slide {
/*
* We do not want the slide to be positioned, so the captions can position
* relative to the gallery itself.
*/
position: static !important;
/*
* Do not transform the slide, but rather transform just the content.
*/
transform: none !important;
will-change: auto !important;
}

amp-inline-gallery-slide.i-amphtml-layout-size-defined {
/*
* Since the content is translated, it may be outside the area of the
* slide itself.
*/
overflow: visible !important;
}

.i-amphtml-inline-gallery-slide-container {
width: 100%;
height: 100%;
/* Override default from <figure> */
margin: 0;
}

.i-amphtml-inline-gallery-slide-content-slot {
display: flex;
align-items: center;
justify-content: center;
/* Subtract out height for the caption */
height: calc(100% - calc(var(--i-amphtml-caption-height, 0px)));
transform: var(--content-transform, translateZ(1px));
will-change: transform;
overflow: hidden;
}

.i-amphtml-inline-gallery-slide-caption {
position: absolute;
left: 6px;
right: 6px;
margin-top: var(--caption-margin-top);
height: var(--i-amphtml-caption-height, 0);
overflow: hidden;
opacity: var(--caption-opacity);
}

.i-amphtml-inline-gallery-slide-see-more {
float: right;
padding: 0;
padding-left: 6px;
border: 0;
color: #48f;
background-color: transparent;
outline: none;
font-family: inherit;
font-size: inherit;
line-height: 1.25em;
}

.i-amphtml-inline-gallery-slide-persistent-slot {
clear: both;
}

.i-amphtml-inline-gallery-slide-content-slot > * {
height: 100%;
width: 100%;
}
121 changes: 121 additions & 0 deletions extensions/amp-inline-gallery/0.1/amp-inline-gallery-slide.js
@@ -0,0 +1,121 @@
/**
* Copyright 2019 The AMP HTML Authors. 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.
*/

import {Layout} from '../../../src/layout';
import {Services} from '../../../src/services';
import {htmlFor} from '../../../src/static-template';
import {isExperimentOn} from '../../../src/experiments';
import {toArray} from '../../../src/types';
import {userAssert} from '../../../src/log';

export class AmpInlineGallerySlide extends AMP.BaseElement {
/**
* @return {!Element}
* @private
*/
createDom_() {
userAssert(
isExperimentOn(this.win, 'amp-inline-gallery-captions') ||
'expected "amp-inline-gallery-captions" experiment to be enabled'
);
const html = htmlFor(this.element);
const content = html`
<figure class="i-amphtml-inline-gallery-slide-container">
<div class="i-amphtml-inline-gallery-slide-content-slot"></div>
<figcaption class="i-amphtml-inline-gallery-slide-caption">
<amp-truncate-text layout="fill">
<span class="i-amphtml-inline-gallery-slide-caption-slot"></span>
<button
class="i-amphtml-inline-gallery-slide-see-more"
slot="collapsed"
>
See more
</button>
<div
class="i-amphtml-inline-gallery-slide-persistent-slot"
slot="persistent"
></div>
</amp-truncate-text>
</figcaption>
</figure>
`;
const expand = content.querySelector('[slot="collapsed"]');
expand.addEventListener('click', (e) => {
this.openLightbox();
e.stopPropagation();
});

return content;
}

/** @param {!AmpElement} element */
constructor(element) {
super(element);
}

/**
*
*/
openLightbox() {
Services.extensionsFor(this.win)
.installExtensionForDoc(this.getAmpDoc(), 'amp-lightbox-gallery')
.then(() => {
const el = document.querySelector('amp-lightbox-gallery');
return el.getImpl();
})
.then((impl) => {
impl.open(this.element, true);
});
}

/** @override */
isLayoutSupported() {
return Layout.FLEX_ITEM;
}

/** @override */
buildCallback() {
const dom = this.createDom_();
const captionSlot = dom.querySelector(
'.i-amphtml-inline-gallery-slide-caption-slot'
);
const contentSlot = dom.querySelector(
'.i-amphtml-inline-gallery-slide-content-slot'
);
const attributionSlot = dom.querySelector(
'.i-amphtml-inline-gallery-slide-persistent-slot'
);
const childNodesArray = toArray(this.element.childNodes);

childNodesArray
.filter((n) => {
return n.hasAttribute && n.getAttribute('slot') === 'caption';
})
.forEach((node) => captionSlot.appendChild(node));
childNodesArray
.filter((n) => {
return !n.hasAttribute || !n.hasAttribute('slot');
})
.forEach((node) => contentSlot.appendChild(node));
childNodesArray
.filter((n) => {
return n.hasAttribute && n.getAttribute('slot') === 'attribution';
})
.forEach((node) => attributionSlot.appendChild(node));

this.element.appendChild(dom);
}
}

0 comments on commit 0adf076

Please sign in to comment.