-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
amp-accordion #1849
amp-accordion #1849
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/** | ||
* Copyright 2016 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. | ||
*/ | ||
|
||
/* Non-overridable properties */ | ||
amp-accordion { | ||
display: block !important; | ||
} | ||
|
||
/* Make sections non-floatable */ | ||
amp-accordion > section { | ||
float: none !important; | ||
} | ||
|
||
/* Hide all children and make them non-floatable */ | ||
amp-accordion > section > *:nth-child(n) { | ||
display: none !important; | ||
float: none !important; | ||
} | ||
|
||
/* Display the first 2 elements (heading and content) */ | ||
amp-accordion > section > .-amp-accordion-header, | ||
amp-accordion > section > .-amp-accordion-content { | ||
display: block !important; | ||
overflow: hidden !important; /* clearfix */ | ||
position: relative !important; | ||
} | ||
|
||
amp-accordion, | ||
amp-accordion > section, | ||
.-amp-accordion-header, | ||
.-amp-accordion-content { | ||
margin: 0; | ||
} | ||
|
||
|
||
|
||
/* heading element*/ | ||
.-amp-accordion-header { | ||
cursor: pointer; | ||
background-color: #efefef; | ||
padding-right: 20px; | ||
border: solid 1px #dfdfdf; | ||
} | ||
|
||
/* Collapse content by default. */ | ||
amp-accordion > section > .-amp-accordion-content { | ||
display: none !important; | ||
} | ||
|
||
/* Expand content when needed. */ | ||
amp-accordion > section[expanded] > .-amp-accordion-content { | ||
display: block !important; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/** | ||
* Copyright 2016 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 {assert} from '../../../src/asserts'; | ||
import {isExperimentOn} from '../../../src/experiments'; | ||
import {log} from '../../../src/log'; | ||
|
||
/** @const */ | ||
const EXPERIMENT = 'amp-accordion'; | ||
|
||
/** @const */ | ||
const TAG = 'AmpAccordion'; | ||
|
||
class AmpAccordion extends AMP.BaseElement { | ||
|
||
/** @override */ | ||
isLayoutSupported(layout) { | ||
return layout == Layout.CONTAINER; | ||
} | ||
|
||
/** @override */ | ||
buildCallback() { | ||
/** @const @private {!NodeList} */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's add experiment as requested by @ericlindley-g There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
this.sections_ = this.getRealChildren(); | ||
|
||
/** @const @private {boolean} */ | ||
this.isExperimentOn_ = isExperimentOn(this.getWin(), EXPERIMENT); | ||
if (!this.isExperimentOn_) { | ||
log.warn(TAG, `Experiment ${EXPERIMENT} disabled`); | ||
return; | ||
} | ||
this.sections_.forEach(section => { | ||
assert( | ||
section.tagName.toLowerCase() == 'section', | ||
'Sections should be enclosed in a <section> tag, ' + | ||
'See https://github.com/ampproject/amphtml/blob/master/extensions/' + | ||
'amp-accordion/amp-accordion.md. Found in: %s', this.element); | ||
const sectionComponents_ = section.children; | ||
assert( | ||
sectionComponents_.length == 2, | ||
'Each section must have exactly two children. ' + | ||
'See https://github.com/ampproject/amphtml/blob/master/extensions/' + | ||
'amp-accordion/amp-accordion.md. Found in: %s', this.element); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replied :) |
||
const header = sectionComponents_[0]; | ||
const content = sectionComponents_[1]; | ||
header.classList.add('-amp-accordion-header'); | ||
content.classList.add('-amp-accordion-content'); | ||
header.addEventListener('click', event => { | ||
event.preventDefault(); | ||
this.mutateElement(() => { | ||
if (section.hasAttribute('expanded')) { | ||
section.removeAttribute('expanded'); | ||
} else { | ||
section.setAttribute('expanded', ''); | ||
} | ||
}, content); | ||
}); | ||
}); | ||
} | ||
} | ||
|
||
AMP.registerElement('amp-accordion', AmpAccordion, $CSS$); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/** | ||
* Copyright 2016 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 {Timer} from '../../../../src/timer'; | ||
import {adopt} from '../../../../src/runtime'; | ||
import {createIframePromise} from '../../../../testing/iframe'; | ||
import {toggleExperiment} from '../../../../src/experiments'; | ||
require('../../../../build/all/v0/amp-accordion-0.1.max'); | ||
|
||
adopt(window); | ||
|
||
describe('amp-accordion', () => { | ||
const timer = new Timer(window); | ||
function getAmpAccordion() { | ||
return createIframePromise().then(iframe => { | ||
toggleExperiment(iframe.win, 'amp-accordion', true); | ||
const ampAccordion = iframe.doc.createElement('amp-accordion'); | ||
for (let i = 0; i < 3; i++) { | ||
const section = iframe.doc.createElement('section'); | ||
section.innerHTML = "<h2>Section " + i + "</h2><div>Loreum ipsum</div>"; | ||
ampAccordion.appendChild(section); | ||
if (i == 1) { | ||
section.setAttribute('expanded', ''); | ||
} | ||
} | ||
return iframe.addElement(ampAccordion).then(() => { | ||
return Promise.resolve({ | ||
iframe: iframe, | ||
ampAccordion: ampAccordion | ||
}); | ||
}); | ||
}); | ||
} | ||
|
||
it('should expand when header of a collapsed section is clicked', () => { | ||
return getAmpAccordion().then(obj => { | ||
const iframe = obj.iframe; | ||
let clickEvent; | ||
if (iframe.doc.createEvent) { | ||
clickEvent = iframe.doc.createEvent('MouseEvent'); | ||
clickEvent.initMouseEvent('click', true, true, iframe.win, 1); | ||
} else { | ||
clickEvent = iframe.doc.createEventObject(); | ||
clickEvent.type = 'click'; | ||
} | ||
const headerElements = | ||
iframe.doc.querySelectorAll('section > *:first-child'); | ||
expect(headerElements[0].parentNode.hasAttribute('expanded')).to.be.false; | ||
headerElements[0].dispatchEvent(clickEvent); | ||
return timer.promise(50).then(() => { | ||
expect(headerElements[0].parentNode.hasAttribute('expanded')) | ||
.to.be.true; | ||
}); | ||
}); | ||
}); | ||
it('should collapse when header of an expanded section is clicked', () => { | ||
return getAmpAccordion().then(obj => { | ||
const iframe = obj.iframe; | ||
let clickEvent; | ||
if (iframe.doc.createEvent) { | ||
clickEvent = iframe.doc.createEvent('MouseEvent'); | ||
clickEvent.initMouseEvent('click', true, true, iframe.win, 1); | ||
} else { | ||
clickEvent = iframe.doc.createEventObject(); | ||
clickEvent.type = 'click'; | ||
} | ||
const headerElements = | ||
iframe.doc.querySelectorAll('section > *:first-child'); | ||
expect(headerElements[1].parentNode.hasAttribute('expanded')).to.be.true; | ||
headerElements[1].dispatchEvent(clickEvent); | ||
return timer.promise(50).then(() => { | ||
expect(headerElements[1].parentNode.hasAttribute('expanded')) | ||
.to.be.false; | ||
}); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
<!--- | ||
Copyright 2016 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. | ||
--> | ||
|
||
### <a name="amp-accordion"></a> `amp-accordion` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Heads up that we're adding a new documentation structure on these pages. It might be nice to start using that here. Check out https://github.com/ampproject/amphtml/pull/1841/files#diff-b06bcda88a7e36daa21769e39db62da6R17 for an example -- lines 17 to 36 with the header and the are the key part. |
||
|
||
An accordion provides a way for viewers to have a glance at the outline of the content and jump to a section or their choice at their will. This would be extremely helpful for handheld mobile devices where even a couple of sentences in a section would lead to the viewer needing to scroll. | ||
|
||
#### Behavior | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add something about where the expand/collapse behavior is triggered? I assume it's the first child of a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
|
||
Each of the `amp-accordion` component’s immediate children is considered a section in the accordion. Each of these nodes must be a `<section>` tag. | ||
|
||
- An `amp-accordion` can contain one or more `<section>`s as its direct children. | ||
- Each `<section>` must contain only two direct children. | ||
- The first child (of the section) will be considered as the heading of the section. Clicking/tapping on this section will trigger the expand/collapse behaviour. | ||
- The second child (of the section) will be the content or the section | ||
- There is no restriction on the type of tags that could be used for the `<section>`’s children. | ||
- Any additional children of the `<section>` would be ignored not be displayed. (This should just be a safety backup and should be enforced in the validator) | ||
- Clicking/tapping on the heading of a section expands/ or collapses the section. | ||
|
||
```html | ||
<amp-accordion> | ||
<section expanded> | ||
<h2>Section 1</h2> | ||
<p>Bunch of awesome content</p> | ||
</section> | ||
<section> | ||
<h2>Section 2</h2> | ||
<div>Bunch of awesome content</div> | ||
</section> | ||
<section> | ||
<h2>Section 3</h2> | ||
<amp-img src="/awesome.png" width="300" height="300"></amp-img> | ||
</section> | ||
</amp-accordion> | ||
``` | ||
|
||
#### Attributes | ||
|
||
**expanded** | ||
|
||
The `expanded` attribute can be set on any `<section>` that needs to be expanded on page load. | ||
|
||
#### Styling | ||
|
||
- You may use the `amp-accordion` element selector to style it freely. | ||
- `amp-accordion` elements are always `display: block`. | ||
- `<section>` and the heading and content element are not float-able. | ||
- `<section>`s will have an `expanded` attribute when they are expanded. | ||
- The content element is clear-fixed with `overflow: hidden` and hence cannot have scrollbars. | ||
- margins of the `amp-accordion`, `<section>` and the heading and content elements are set to 0 and can be overridden in custom styles. | ||
- Both the header and content elements are `position: relative`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<!doctype html> | ||
<html ⚡> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>AMP #0</title> | ||
<link rel="canonical" href="amps.html" > | ||
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1"> | ||
<link href='https://fonts.googleapis.com/css?family=Questrial' rel='stylesheet' type='text/css'> | ||
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript> | ||
<script async src="../../dist/amp.js"></script> | ||
<script async custom-element="amp-youtube" src="../../dist/v0/amp-accordion-0.1.max.js"></script> | ||
</head> | ||
<body> | ||
<h1>AMP #0</h1> | ||
<amp-accordion> | ||
<section> | ||
<h2>Section 1</h2> | ||
<div> | ||
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus | ||
</div> | ||
</section> | ||
<section> | ||
<h2>Section 2</h2> | ||
<div> | ||
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan porttitor, facilisis luctus, metus | ||
</div> | ||
</section> | ||
<section> | ||
<h2>Section 3</h2> | ||
<div> | ||
<amp-img id="img1" srcset="https://lh4.googleusercontent.com/kDqWeHQ0Zt-UFeHAlc2ydE9AwK7W-kbMXBqyuNvPNy0mNSGAP7FOVB3_1iAOdbQSsbZByErbehvvSKtnTb1L5GoYreijfKwgYwpP1eLCHyl9Am7BSpwRuBABOAO12PtyPBTirdAadnxOmfq9dH_rsLSTaYGmNz1D5QIwXeWd8UeDNUQ3f-cMgvkq4ePqmKoe9t5ySqqLMZs-v3wTi2pd4jV_CurzcMB76k_b4lyD5w77NUowkSaQfscYVQpkDjo6OgG2nBiKJ2TITWVDu2rvt6NuEoOD9xaHgXuv81OnOjXCokxZd5K6TZiAH-Qm1jTKGMANklXiXt6hbwrN3QPA1mq2FardxGNLj1_oqOpXaqfUuj8LvejFRY6zJMGq0r6S_TEtPvbyulIg4PkKPIaVzi5nVdGrAWWoesWh-ORqmxZ4FIhdbd_Igsdh5AcMETBcZz3l5-IX0hmnyUeT5IOPSGw-p3Esgp_abwWB9-kElEiiHPD4QuQ_swsRu0NSFwfRi_QefnJQJ5UATng6iVP3K0g7uumHcwLtFId0vCeHp4A=w1024-h768-no" width=512 height=344></amp-img> | ||
</div> | ||
</section> | ||
</amp-accordion> | ||
</body> | ||
</html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this FOUC?
It probably does. We may need to add this to the list of extensions that block doc render.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more than just FOUC, right? This will cause a major re-layout when element is rebuilt. In particular, the overall height will change. Do we have solutions for this?