- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus vel quam
- eu turpis eleifend pretium. Aenean sagittis, leo ac congue mattis, est
- nisl accumsan eros, sit amet suscipit massa lectus non nibh. In justo
- libero, ultricies sed tristique vel, tincidunt non nulla. Pellentesque vel
- pharetra risus. Donec tempus tortor at est vulputate ultrices. Quisque
- sagittis pretium facilisis. Aliquam dignissim dapibus nibh sed bibendum.
- Phasellus et nulla pulvinar, placerat sapien ac, vehicula mauris. Mauris
- efficitur quis orci sed convallis. Maecenas ut nibh placerat, gravida
- risus eu, tincidunt diam. Vivamus vitae mauris interdum, iaculis nisi
- eget, vulputate lectus. Maecenas condimentum risus eu sapien molestie
- sollicitudin. Fusce lobortis purus at fringilla imperdiet. Duis non orci
- ultricies, vulputate urna sit amet, euismod velit. Vivamus tempor, nisi
- vitae suscipit dignissim, risus lacus imperdiet risus, et mattis leo massa
- nec erat. Nulla cursus a leo a dapibus. Nullam dapibus est ut condimentum
- iaculis. Sed mollis lorem at sagittis dignissim. Donec euismod urna nec
- ligula rhoncus dapibus ullamcorper at erat. Curabitur nec quam vitae nisi
- efficitur tincidunt. Aliquam molestie turpis eget risus molestie, non
- cursus metus cursus. Nullam diam nisl, tincidunt viverra luctus id, mattis
- sed dui. Integer egestas, nunc eu hendrerit tristique, est magna cursus
- ex, nec gravida elit magna sit amet neque. Pellentesque luctus leo sed
- purus blandit malesuada et eu magna. Praesent molestie dolor diam, at
- finibus purus efficitur ullamcorper. Mauris sit amet neque sapien. Nunc
- tincidunt velit id nisl eleifend, a imperdiet ligula sagittis.
-
-
-
diff --git a/extensions/amp-list/0.1/amp-list.js b/extensions/amp-list/0.1/amp-list.js
index 86c885bf3bac..5da563c3ef53 100644
--- a/extensions/amp-list/0.1/amp-list.js
+++ b/extensions/amp-list/0.1/amp-list.js
@@ -24,7 +24,12 @@ import {
markElementForDiffing,
} from '../../../src/purifier/sanitation';
import {Deferred} from '../../../src/utils/promise';
-import {Layout, getLayoutClass, parseLayout} from '../../../src/layout';
+import {
+ Layout,
+ getLayoutClass,
+ isLayoutSizeDefined,
+ parseLayout,
+} from '../../../src/layout';
import {LoadMoreService} from './service/load-more-service';
import {Pass} from '../../../src/pass';
import {Services} from '../../../src/services';
@@ -56,7 +61,7 @@ import {
} from '../../../src/utils/xhr-utils';
import {isArray, toArray} from '../../../src/types';
import {isExperimentOn} from '../../../src/experiments';
-import {px, setImportantStyles, setStyles, toggle} from '../../../src/style';
+import {px, setStyles, toggle} from '../../../src/style';
import {setDOM} from '../../../third_party/set-dom/set-dom';
import {startsWith} from '../../../src/string';
@@ -125,9 +130,6 @@ export class AmpList extends AMP.BaseElement {
*/
this.layoutCompleted_ = false;
- /** @private {boolean} */
- this.isLayoutContainer_ = false;
-
/**
* The `src` attribute's initial value.
* @private {?string}
@@ -175,18 +177,7 @@ export class AmpList extends AMP.BaseElement {
/** @override */
isLayoutSupported(layout) {
- if (layout === Layout.CONTAINER) {
- userAssert(
- this.getPlaceholder(),
- '%s with layout=container relies on a placeholder to determine an initial height. ' +
- 'For more info on adding a placeholder see: ' +
- 'https://go.amp.dev/c/amp-list/#placeholder-and-fallback. %s',
- TAG,
- this.element
- );
- this.isLayoutContainer_ = true;
- }
- return true;
+ return isLayoutSizeDefined(layout);
}
/** @override */
@@ -307,13 +298,12 @@ export class AmpList extends AMP.BaseElement {
/**
* @private
- * @return {Promise}
*/
maybeResizeListToFitItems_() {
if (this.loadMoreEnabled_) {
this.attemptToFitLoadMore_(dev().assertElement(this.container_));
} else {
- return this.attemptToFit_(dev().assertElement(this.container_));
+ this.attemptToFit_(dev().assertElement(this.container_));
}
}
@@ -444,7 +434,6 @@ export class AmpList extends AMP.BaseElement {
const isLayoutContainer = mutations['is-layout-container'];
if (isLayoutContainer) {
- this.isLayoutContainer_ = true;
this.changeToLayoutContainer_();
}
@@ -474,9 +463,7 @@ export class AmpList extends AMP.BaseElement {
// In the load-more case, we allow the container to be height auto
// in order to reasonably make space for the load-more button and
// load-more related UI elements underneath.
- // In the layout=container case, we allow the container to take
- // the height of its children instead, whereas fill-content forces height:0
- if (!this.loadMoreEnabled_ && !this.isLayoutContainer_) {
+ if (!this.loadMoreEnabled_) {
this.applyFillContent(container, true);
}
return container;
@@ -550,9 +537,10 @@ export class AmpList extends AMP.BaseElement {
(isFetch && this.element.hasAttribute('reset-on-refresh')) ||
this.element.getAttribute('reset-on-refresh') === 'always'
) {
- const reset = () => {
- this.togglePlaceholder(true);
- this.toggleLoading(true, /* opt_force */ true);
+ // Placeholder and loading don't need a mutate context.
+ this.togglePlaceholder(true);
+ this.toggleLoading(true, /* opt_force */ true);
+ this.mutateElement(() => {
this.toggleFallback_(false);
// Clean up bindings in children before removing them from DOM.
if (this.bind_) {
@@ -563,13 +551,6 @@ export class AmpList extends AMP.BaseElement {
});
}
removeChildren(dev().assertElement(this.container_));
- };
- if (!this.loadMoreEnabled_ && this.isLayoutContainer_) {
- this.lockHeightAndMutate_(reset);
- return;
- }
- this.measureElement(() => {
- reset();
if (this.loadMoreEnabled_) {
this.getLoadMoreService_().hideAllLoadMoreElements();
}
@@ -1002,8 +983,10 @@ export class AmpList extends AMP.BaseElement {
render_(elements, opt_append = false) {
dev().info(TAG, 'render:', this.element, elements);
const container = dev().assertElement(this.container_);
- const renderAndResize = () => {
+
+ return this.mutateElement(() => {
this.hideFallbackAndPlaceholder_();
+
if (this.element.hasAttribute('diffable') && container.hasChildNodes()) {
this.diff_(container, elements);
} else {
@@ -1028,17 +1011,8 @@ export class AmpList extends AMP.BaseElement {
const r = this.element.getResources().getResourceForElement(this.element);
r.resetPendingChangeSize();
- return this.maybeResizeListToFitItems_();
- };
-
- if (!this.loadMoreEnabled_ && this.isLayoutContainer_) {
- return this.lockHeightAndMutate_(() =>
- renderAndResize().then((resized) =>
- resized ? this.unlockHeightInsideMutate_() : null
- )
- );
- }
- return this.mutateElement(renderAndResize);
+ this.maybeResizeListToFitItems_();
+ });
}
/**
@@ -1135,44 +1109,6 @@ export class AmpList extends AMP.BaseElement {
}
}
- /**
- * Measure and lock height before performing given mutate fn.
- * Applicable for layout=container without infinite scrolling.
- * @private
- * @param {!Function} mutate
- * @return {!Promise}
- */
- lockHeightAndMutate_(mutate) {
- devAssert(
- !this.loadMoreEnabled_,
- 'amp-list[layout=container] does not support infinite scrolling with [load-more].'
- );
- let currentHeight;
- return this.measureMutateElement(
- () => {
- currentHeight = this.element./*OK*/ offsetHeight;
- },
- () => {
- setImportantStyles(this.element, {
- 'height': `${currentHeight}px`,
- 'overflow': 'hidden',
- });
- return mutate();
- }
- );
- }
-
- /**
- * Applicable for layout=container.
- * @private
- */
- unlockHeightInsideMutate_() {
- setImportantStyles(this.element, {
- 'height': '',
- 'overflow': '',
- });
- }
-
/**
* Attempts to change the height of the amp-list to fit a target child.
*
@@ -1181,19 +1117,17 @@ export class AmpList extends AMP.BaseElement {
*
* @param {!Element} target
* @private
- * @return {!Promise}
*/
attemptToFit_(target) {
- return this.measureElement(() => {
+ if (this.element.getAttribute('layout') == Layout.CONTAINER) {
+ return;
+ }
+ this.measureElement(() => {
const targetHeight = target./*OK*/ scrollHeight;
const height = this.element./*OK*/ offsetHeight;
if (targetHeight > height) {
- return this.attemptChangeHeight(targetHeight).then(
- () => true,
- () => false
- );
+ this.attemptChangeHeight(targetHeight).catch(() => {});
}
- return true;
});
}
@@ -1203,9 +1137,6 @@ export class AmpList extends AMP.BaseElement {
* @private
*/
attemptToFitLoadMore_(target) {
- if (this.isLayoutContainer_) {
- return;
- }
const element = !!this.loadMoreSrc_
? this.getLoadMoreService_().getLoadMoreButton()
: this.getLoadMoreService_().getLoadMoreEndElement();
@@ -1218,29 +1149,31 @@ export class AmpList extends AMP.BaseElement {
* @private
*/
attemptToFitLoadMoreElement_(element, target) {
+ if (this.element.getAttribute('layout') == Layout.CONTAINER) {
+ return;
+ }
this.measureElement(() => {
const targetHeight = target./*OK*/ scrollHeight;
const height = this.element./*OK*/ offsetHeight;
const loadMoreHeight = element ? element./*OK*/ offsetHeight : 0;
- if (targetHeight + loadMoreHeight <= height) {
- return;
- }
- this.attemptChangeHeight(targetHeight + loadMoreHeight)
- .then(() => {
- this.resizeFailed_ = false;
- // If there were not enough items to fill the list, consider
- // automatically loading more if load-more="auto" is enabled
- if (this.element.getAttribute('load-more') === 'auto') {
- this.maybeLoadMoreItems_();
- }
- setStyles(dev().assertElement(this.container_), {
- 'max-height': '',
+ if (targetHeight + loadMoreHeight > height) {
+ this.attemptChangeHeight(targetHeight + loadMoreHeight)
+ .then(() => {
+ this.resizeFailed_ = false;
+ // If there were not enough items to fill the list, consider
+ // automatically loading more if load-more="auto" is enabled
+ if (this.element.getAttribute('load-more') === 'auto') {
+ this.maybeLoadMoreItems_();
+ }
+ setStyles(dev().assertElement(this.container_), {
+ 'max-height': '',
+ });
+ })
+ .catch(() => {
+ this.resizeFailed_ = true;
+ this.adjustContainerForLoadMoreButton_();
});
- })
- .catch(() => {
- this.resizeFailed_ = true;
- this.adjustContainerForLoadMoreButton_();
- });
+ }
});
}
@@ -1299,7 +1232,6 @@ export class AmpList extends AMP.BaseElement {
if (overflowElement) {
toggle(overflowElement, false);
}
- this.isLayoutContainer_ = true;
this.element.setAttribute('layout', 'container');
this.element.setAttribute('i-amphtml-layout', 'container');
this.element.classList.add('i-amphtml-layout-container');
diff --git a/extensions/amp-list/0.1/test/test-amp-list-load-more.js b/extensions/amp-list/0.1/test/test-amp-list-load-more.js
index c597e9f336d4..8b1d34a68040 100644
--- a/extensions/amp-list/0.1/test/test-amp-list-load-more.js
+++ b/extensions/amp-list/0.1/test/test-amp-list-load-more.js
@@ -42,7 +42,6 @@ describes.realWin(
let ampdoc;
let element, list;
let templates;
- let lockHeightSpy;
beforeEach(() => {
win = env.win;
@@ -56,18 +55,13 @@ describes.realWin(
};
env.sandbox.stub(Services, 'templatesFor').returns(templates);
env.sandbox.stub(AmpDocService.prototype, 'getAmpDoc').returns(ampdoc);
-
- element = doc.createElement('amp-list');
- list = new AmpList(element);
- lockHeightSpy = env.sandbox.spy(list, 'lockHeightAndMutate_');
- });
-
- afterEach(() => {
- expect(lockHeightSpy.notCalled).to.be.true;
});
describe('manual', () => {
beforeEach(() => {
+ element = doc.createElement('amp-list');
+ list = new AmpList(element);
+
env.sandbox.stub(list, 'getAmpDoc').returns(ampdoc);
env.sandbox.stub(list, 'getFallback').returns(null);
@@ -153,6 +147,9 @@ describes.realWin(
describe('loading states', () => {
beforeEach(() => {
+ element = doc.createElement('amp-list');
+ list = new AmpList(element);
+
env.sandbox.stub(list, 'getAmpDoc').returns(ampdoc);
env.sandbox.stub(list, 'getFallback').returns(null);
@@ -221,6 +218,7 @@ describes.realWin(
expect(renderSpy).to.be.calledTwice;
expect(renderSpy).to.be.calledWith([div3, div4], true);
+ list.container_;
expect(list.container_.children).to.have.lengthOf(4);
});
@@ -233,6 +231,7 @@ describes.realWin(
env.sandbox
.stub(list, 'maybeRenderLoadMoreTemplates_')
.returns(Promise.resolve([]));
+
const div1 = doc.createElement('div');
div1.textContent = '1';
const div2 = doc.createElement('div');
diff --git a/extensions/amp-list/0.1/test/test-amp-list.js b/extensions/amp-list/0.1/test/test-amp-list.js
index ef79428202e9..5c62a37b6ffa 100644
--- a/extensions/amp-list/0.1/test/test-amp-list.js
+++ b/extensions/amp-list/0.1/test/test-amp-list.js
@@ -179,18 +179,11 @@ describes.repeated(
}
function expectRender() {
- // Call mutate OR measureMutate, then measure during render.
+ // Call mutate/measure during render.
listMock
.expects('mutateElement')
.callsFake((m) => m())
- .atLeast(0);
- listMock
- .expects('measureMutateElement')
- .callsFake((m, n) => {
- m();
- n();
- })
- .atLeast(0);
+ .atLeast(1);
listMock
.expects('measureElement')
.callsFake((m) => m())
@@ -246,48 +239,6 @@ describes.repeated(
return list.layoutCallback();
});
- it('should unlock height for layout=container with successful attemptChangeHeight', async () => {
- const itemElement = doc.createElement('div');
- const placeholder = doc.createElement('div');
- placeholder.style.height = '1337px';
- element.appendChild(placeholder);
- element.getPlaceholder = () => placeholder;
- list.isLayoutSupported('container');
- expectFetchAndRender(DEFAULT_FETCHED_DATA, [itemElement]);
-
- listMock
- .expects('attemptChangeHeight')
- .withExactArgs(1337)
- .returns(Promise.resolve(true));
- listMock
- .expects('maybeResizeListToFitItems_')
- .returns(Promise.resolve(true));
- listMock.expects('unlockHeightInsideMutate_').once();
-
- return list.layoutCallback();
- });
-
- it('should not unlock height for layout=container for unsuccessful attemptChangeHeight', () => {
- const itemElement = doc.createElement('div');
- const placeholder = doc.createElement('div');
- placeholder.style.height = '1337px';
- element.appendChild(placeholder);
- element.getPlaceholder = () => placeholder;
- list.isLayoutSupported('container');
- expectFetchAndRender(DEFAULT_FETCHED_DATA, [itemElement]);
-
- listMock
- .expects('attemptChangeHeight')
- .withExactArgs(1337)
- .returns(Promise.reject(false));
- listMock
- .expects('maybeResizeListToFitItems_')
- .returns(Promise.resolve(false));
- listMock.expects('unlockHeightInsideMutate_').never();
-
- return list.layoutCallback();
- });
-
it('should attemptChangeHeight rendered contents', () => {
const itemElement = doc.createElement('div');
itemElement.style.height = '1337px';
@@ -453,8 +404,8 @@ describes.repeated(
expect(list.container_.contains(foo)).to.be.true;
const opts = {refresh: true, resetOnRefresh: true, expr: 'items'};
-
expectFetchAndRender(DEFAULT_FETCHED_DATA, [foo], opts);
+
return list.executeAction({
method: 'refresh',
satisfiesTrust: () => true,
diff --git a/extensions/amp-list/0.1/test/validator-amp-list.html b/extensions/amp-list/0.1/test/validator-amp-list.html
index 903988b289bc..8176e3a00440 100644
--- a/extensions/amp-list/0.1/test/validator-amp-list.html
+++ b/extensions/amp-list/0.1/test/validator-amp-list.html
@@ -135,14 +135,6 @@
src="https://data.com/articles.json?ref=CANONICAL_URL"
[is-layout-container]="containerState">
-
-
-
-
-
-
-
-
+
+
+
+
|
-|
-|
-|
-|
-|
-|
-|
-|
|
|
| > ^~~~~~~~~
-amp-list/0.1/test/validator-amp-list.html:152:2 The attribute 'binding' in tag 'amp-list' is set to the invalid value 'this-is-an-error'. (see https://amp.dev/documentation/components/amp-list)
+amp-list/0.1/test/validator-amp-list.html:144:2 The attribute 'binding' in tag 'amp-list' is set to the invalid value 'this-is-an-error'. (see https://amp.dev/documentation/components/amp-list)
| src="https://data.com/articles.json?ref=CANONICAL_URL"
| binding="this-is-an-error">
|
@@ -164,27 +156,34 @@ amp-list/0.1/test/validator-amp-list.html:152:2 The attribute 'binding' in tag '
|
| > ^~~~~~~~~
-amp-list/0.1/test/validator-amp-list.html:158:2 The attribute 'wdith' may not appear in tag 'amp-list'. (see https://amp.dev/documentation/components/amp-list)
+amp-list/0.1/test/validator-amp-list.html:150:2 The attribute 'wdith' may not appear in tag 'amp-list'. (see https://amp.dev/documentation/components/amp-list)
| wdith=10 height=10>
|
|
|
|
>> ^~~~~~~~~
-amp-list/0.1/test/validator-amp-list.html:163:2 The tag 'amp-list' is missing a mandatory attribute - pick at least one of ['src','[src]','data-amp-bind-src']. (see https://amp.dev/documentation/components/amp-list)
+amp-list/0.1/test/validator-amp-list.html:155:2 The tag 'amp-list' is missing a mandatory attribute - pick at least one of ['src','[src]','data-amp-bind-src']. (see https://amp.dev/documentation/components/amp-list)
+|
+|
+|
+|
+>> ^~~~~~~~~
+amp-list/0.1/test/validator-amp-list.html:160:2 Incomplete layout attributes specified for tag 'amp-list'. For example, provide attributes 'width' and 'height'. (see https://amp.dev/documentation/components/amp-list)
|
|
|
| > ^~~~~~~~~
-amp-list/0.1/test/validator-amp-list.html:167:2 The attribute 'load-more' in tag 'amp-list' is set to the invalid value ''. (see https://amp.dev/documentation/components/amp-list)
+amp-list/0.1/test/validator-amp-list.html:164:2 The attribute 'load-more' in tag 'amp-list' is set to the invalid value ''. (see https://amp.dev/documentation/components/amp-list)
| src="https://data.com/articles.json?ref=CANONICAL_URL"
| load-more>
|
|
| > ^~~~~~~~~
-amp-list/0.1/test/validator-amp-list.html:172:2 The attribute 'load-more' in tag 'amp-list' is set to the invalid value 'gibberish'. (see https://amp.dev/documentation/components/amp-list)
+amp-list/0.1/test/validator-amp-list.html:169:2 The attribute 'load-more' in tag 'amp-list' is set to the invalid value 'gibberish'. (see https://amp.dev/documentation/components/amp-list)
| src="https://data.com/articles.json?ref=CANONICAL_URL"
| load-more="gibberish"
| load-more-bookmark="next">
@@ -192,26 +191,26 @@ amp-list/0.1/test/validator-amp-list.html:172:2 The attribute 'load-more' in tag
|
|
>> ^~~~~~~~~
-amp-list/0.1/test/validator-amp-list.html:178:2 The attribute 'load-more-button' may not appear in tag 'div'.
+amp-list/0.1/test/validator-amp-list.html:175:2 The attribute 'load-more-button' may not appear in tag 'div'.
|
>> ^~~~~~~~~
-amp-list/0.1/test/validator-amp-list.html:179:2 The attribute 'load-more-loading' may not appear in tag 'div'.
+amp-list/0.1/test/validator-amp-list.html:176:2 The attribute 'load-more-loading' may not appear in tag 'div'.
|
>> ^~~~~~~~~
-amp-list/0.1/test/validator-amp-list.html:180:2 The attribute 'load-more-failed' may not appear in tag 'div'.
+amp-list/0.1/test/validator-amp-list.html:177:2 The attribute 'load-more-failed' may not appear in tag 'div'.
|
>> ^~~~~~~~~
-amp-list/0.1/test/validator-amp-list.html:181:2 The attribute 'load-more-end' may not appear in tag 'div'.
+amp-list/0.1/test/validator-amp-list.html:178:2 The attribute 'load-more-end' may not appear in tag 'div'.
|
>> ^~~~~~~~~
-amp-list/0.1/test/validator-amp-list.html:182:2 The parent tag of tag 'amp-list-load-more' is 'body', but it can only be 'amp-list'. (see https://amp.dev/documentation/components/amp-list)
+amp-list/0.1/test/validator-amp-list.html:179:2 The parent tag of tag 'amp-list-load-more' is 'body', but it can only be 'amp-list'. (see https://amp.dev/documentation/components/amp-list)
|
|
>> ^~~~~~~~~
-amp-list/0.1/test/validator-amp-list.html:187:4 The parent tag of tag 'amp-list-load-more button[load-more-clickable]' is 'amp-list', but it can only be 'amp-list-load-more'. (see https://amp.dev/documentation/components/amp-list)
+amp-list/0.1/test/validator-amp-list.html:184:4 The parent tag of tag 'amp-list-load-more button[load-more-clickable]' is 'amp-list', but it can only be 'amp-list-load-more'. (see https://amp.dev/documentation/components/amp-list)
|
|
| > ^~~~~~~~~
-amp-list/0.1/test/validator-amp-list.html:196:2 Attribute 'template' in tag 'amp-list' contains a value that does not match any other tags on the page. (see https://amp.dev/documentation/components/amp-list)
+amp-list/0.1/test/validator-amp-list.html:193:2 Attribute 'template' in tag 'amp-list' contains a value that does not match any other tags on the page. (see https://amp.dev/documentation/components/amp-list)
| src="https://data.com/articles.json?ref=CANONICAL_URL"
| template="missing">
|
@@ -234,9 +233,9 @@ amp-list/0.1/test/validator-amp-list.html:196:2 Attribute 'template' in tag 'amp
|
|
>> ^~~~~~~~~
-amp-list/0.1/test/validator-amp-list.html:206:2 The mandatory attribute 'type' is missing in tag 'template'. (see https://amp.dev/documentation/components/amp-mustache)
+amp-list/0.1/test/validator-amp-list.html:203:2 The mandatory attribute 'type' is missing in tag 'template'. (see https://amp.dev/documentation/components/amp-mustache)
>> ^~~~~~~~~
-amp-list/0.1/test/validator-amp-list.html:206:2 The tag 'template' requires including the 'amp-mustache' extension JavaScript. (see https://amp.dev/documentation/components/amp-mustache)
+amp-list/0.1/test/validator-amp-list.html:203:2 The tag 'template' requires including the 'amp-mustache' extension JavaScript. (see https://amp.dev/documentation/components/amp-mustache)
|
| ` element exposes a `refresh` action that other elements can refe
### Dynamic resizing
-`` can be used with `layout="CONTAINER"` with two caveats: (1) A list with changing contents must have a determinable initial height from a fixed-height placeholder, and (2) once content changes inside the list, resize will occur _only_ if it does not cause content jumping. This is enforced by locking the height of the list prior to rendering contents and conditionally unlocking it accordingly.
-
[filter formats="websites, stories"]
-In several cases, we need the `` to resize on user interaction. For example, when the `` contains an amp-accordion that a user may tap on, when the contents of the `` change size due to bound CSS classes, or when the number of items inside an `` changes due to a bound `[src]` attribute. The `changeToLayoutContainer` action handles this by changing the amp list to `layout="CONTAINER"` when triggering this action. If there is no placeholder, or content is known to change only on user interaction, it may be more suitable to use a different layout than "container" initially and then change accordingly. See the following example:
+In several cases, we may need the `` to resize on user interaction. For example, when the `` contains an amp-accordion that a user may tap on, when the contents of the `` change size due to bound CSS classes, or when the number of items inside an `` changes due to a bound `[src]` attribute. The `changeToLayoutContainer` action handles this by changing the amp list to `layout="CONTAINER"` when triggering this action. See the following example:
[/filter]
[filter formats="email"]
diff --git a/extensions/amp-list/validator-amp-list.protoascii b/extensions/amp-list/validator-amp-list.protoascii
index 9f490851ae72..1d6f6c85dcf6 100644
--- a/extensions/amp-list/validator-amp-list.protoascii
+++ b/extensions/amp-list/validator-amp-list.protoascii
@@ -117,7 +117,6 @@ tags: { # with mandatory src and/or [src] attr
}
attr_lists: "extended-amp-global"
amp_layout: {
- supported_layouts: CONTAINER
supported_layouts: FILL
supported_layouts: FIXED
supported_layouts: FIXED_HEIGHT
@@ -242,7 +241,6 @@ tags: { #
}
attr_lists: "extended-amp-global"
amp_layout: {
- supported_layouts: CONTAINER
supported_layouts: FILL
supported_layouts: FIXED
supported_layouts: FIXED_HEIGHT
@@ -308,7 +306,6 @@ tags: { #
}
attr_lists: "extended-amp-global"
amp_layout: {
- supported_layouts: CONTAINER
supported_layouts: FILL
supported_layouts: FIXED
supported_layouts: FIXED_HEIGHT
diff --git a/validator/testdata/amp4email_feature_tests/amp_list.html b/validator/testdata/amp4email_feature_tests/amp_list.html
index 7153af4231d8..783137586612 100644
--- a/validator/testdata/amp4email_feature_tests/amp_list.html
+++ b/validator/testdata/amp4email_feature_tests/amp_list.html
@@ -40,15 +40,6 @@
-
-
-
-
-
-
-
-
-
-|
-|
-|
-|
-|
-|
-|
-|
|
| > ^~~~~~~~~
-amp4email_feature_tests/amp_list.html:130:0 Missing URL for attribute 'src' in tag 'AMP-LIST (AMP4EMAIL)'. (see https://amp.dev/documentation/components/amp-list)
+amp4email_feature_tests/amp_list.html:121:0 Missing URL for attribute 'src' in tag 'AMP-LIST (AMP4EMAIL)'. (see https://amp.dev/documentation/components/amp-list)
| src="">
|
|
@@ -156,7 +147,7 @@ amp4email_feature_tests/amp_list.html:130:0 Missing URL for attribute 'src' in t
|
|
>> ^~~~~~~~~
-amp4email_feature_tests/amp_list.html:138:0 The attribute 'src' may not appear in tag 'amp-state (AMP4EMAIL)'. (see https://amp.dev/documentation/components/amp-bind)
+amp4email_feature_tests/amp_list.html:129:0 The attribute 'src' may not appear in tag 'amp-state (AMP4EMAIL)'. (see https://amp.dev/documentation/components/amp-bind)
|
|
|
@@ -168,7 +159,7 @@ amp4email_feature_tests/amp_list.html:138:0 The attribute 'src' may not appear i
| -->
| > ^~~~~~~~~
-amp4email_feature_tests/amp_list.html:148:0 Invalid URL protocol 'http:' for attribute 'src' in tag 'AMP-LIST (AMP4EMAIL)'. (see https://amp.dev/documentation/components/amp-list)
+amp4email_feature_tests/amp_list.html:139:0 Invalid URL protocol 'http:' for attribute 'src' in tag 'AMP-LIST (AMP4EMAIL)'. (see https://amp.dev/documentation/components/amp-list)
| src="http://somelink.com">
|
|
@@ -178,7 +169,7 @@ amp4email_feature_tests/amp_list.html:148:0 Invalid URL protocol 'http:' for att
|
| > ^~~~~~~~~
-amp4email_feature_tests/amp_list.html:156:0 The attribute 'src' may not appear in tag 'amp-state (AMP4EMAIL)'. (see https://amp.dev/documentation/components/amp-bind)
+amp4email_feature_tests/amp_list.html:147:0 The attribute 'src' may not appear in tag 'amp-state (AMP4EMAIL)'. (see https://amp.dev/documentation/components/amp-bind)
| src="http://somelink.com">
|
|
@@ -192,7 +183,7 @@ amp4email_feature_tests/amp_list.html:156:0 The attribute 'src' may not appear i
| -->
| > ^~~~~~~~~
-amp4email_feature_tests/amp_list.html:168:0 The attribute '[src]' may not appear in tag 'AMP-LIST (AMP4EMAIL)'. (see https://amp.dev/documentation/components/amp-list)
+amp4email_feature_tests/amp_list.html:159:0 The attribute '[src]' may not appear in tag 'AMP-LIST (AMP4EMAIL)'. (see https://amp.dev/documentation/components/amp-list)
| [src]="evil">
|
|
@@ -202,7 +193,7 @@ amp4email_feature_tests/amp_list.html:168:0 The attribute '[src]' may not appear
|
|
>> ^~~~~~~~~
-amp4email_feature_tests/amp_list.html:176:0 The attribute '[src]' may not appear in tag 'amp-state (AMP4EMAIL)'. (see https://amp.dev/documentation/components/amp-bind)
+amp4email_feature_tests/amp_list.html:167:0 The attribute '[src]' may not appear in tag 'amp-state (AMP4EMAIL)'. (see https://amp.dev/documentation/components/amp-bind)
|
|
|
@@ -211,7 +202,7 @@ amp4email_feature_tests/amp_list.html:176:0 The attribute '[src]' may not appear
| -->
| > ^~~~~~~~~
-amp4email_feature_tests/amp_list.html:183:0 The relative URL 'foo{{bar' for attribute 'src' in tag 'AMP-LIST (AMP4EMAIL)' is disallowed. (see https://amp.dev/documentation/components/amp-list)
+amp4email_feature_tests/amp_list.html:174:0 The relative URL 'foo{{bar' for attribute 'src' in tag 'AMP-LIST (AMP4EMAIL)' is disallowed. (see https://amp.dev/documentation/components/amp-list)
| src="foo{{bar">
|
|
@@ -221,7 +212,7 @@ amp4email_feature_tests/amp_list.html:183:0 The relative URL 'foo{{bar' for attr
|
| > ^~~~~~~~~
-amp4email_feature_tests/amp_list.html:191:0 The relative URL 'foo}}bar' for attribute 'src' in tag 'AMP-LIST (AMP4EMAIL)' is disallowed. (see https://amp.dev/documentation/components/amp-list)
+amp4email_feature_tests/amp_list.html:182:0 The relative URL 'foo}}bar' for attribute 'src' in tag 'AMP-LIST (AMP4EMAIL)' is disallowed. (see https://amp.dev/documentation/components/amp-list)
| src="foo}}bar">
|
|
@@ -237,7 +228,7 @@ amp4email_feature_tests/amp_list.html:191:0 The relative URL 'foo}}bar' for attr
|
| disallowed
>> ^~~~~~~~~
-amp4email_feature_tests/amp_list.html:205:4 The attribute 'href' in tag 'A (AMP4EMAIL)' is set to the invalid value '{{bar}}{{foo}}'.
+amp4email_feature_tests/amp_list.html:196:4 The attribute 'href' in tag 'A (AMP4EMAIL)' is set to the invalid value '{{bar}}{{foo}}'.
|
|
|