From e4647c7746dcced6896b62b4dbf38ee8fe70103b Mon Sep 17 00:00:00 2001 From: Sriram Krishnan Date: Wed, 30 Mar 2016 15:29:23 -0700 Subject: [PATCH] Move state classes to amp-sidebar and make them attributes - change layout type to no-display and add aria support. --- extensions/amp-sidebar/0.1/amp-sidebar.css | 18 ++--- extensions/amp-sidebar/0.1/amp-sidebar.js | 75 +++++++++++++------ .../amp-sidebar/0.1/test/test-amp-sidebar.js | 59 +++++++-------- extensions/amp-sidebar/amp-sidebar.md | 13 ++-- test/manual/amp-sidebar.amp.html | 2 +- 5 files changed, 92 insertions(+), 75 deletions(-) diff --git a/extensions/amp-sidebar/0.1/amp-sidebar.css b/extensions/amp-sidebar/0.1/amp-sidebar.css index b499e295d2b2..f2843f17ddf6 100644 --- a/extensions/amp-sidebar/0.1/amp-sidebar.css +++ b/extensions/amp-sidebar/0.1/amp-sidebar.css @@ -28,6 +28,10 @@ amp-sidebar { -webkit-overflow-scrolling: touch; } +amp-sidebar[side] { + display: block !important; +} + amp-sidebar[side="left"] { left: 0 !important; transform: translateX(-80vw) !important; @@ -38,19 +42,15 @@ amp-sidebar[side="right"] { transform: translateX(80vw) !important; } -.amp-sidebar-open amp-sidebar { +amp-sidebar[side][open] { transform: translateX(0vw) !important; } -.amp-sidebar-closed amp-sidebar, -.amp-sidebar-open amp-sidebar { +amp-sidebar[open], +.-amp-sidebar-closed { transition: transform 0.5s ease; } -.amp-sidebar-open { - overflow: hidden !important; -} - .-amp-sidebar-mask { position: fixed !important; top: 0 !important; @@ -64,7 +64,3 @@ amp-sidebar[side="right"] { z-index: 9998 !important; display: none; } - -.amp-sidebar-open .-amp-sidebar-mask { - display: block; -} diff --git a/extensions/amp-sidebar/0.1/amp-sidebar.js b/extensions/amp-sidebar/0.1/amp-sidebar.js index cca3be320cd2..0a52797886d1 100644 --- a/extensions/amp-sidebar/0.1/amp-sidebar.js +++ b/extensions/amp-sidebar/0.1/amp-sidebar.js @@ -39,7 +39,7 @@ export class AmpSidebar extends AMP.BaseElement { /** @override */ isLayoutSupported(layout) { - return layout == Layout.CONTAINER; + return layout == Layout.NOLAYOUT; } /** @override */ @@ -67,8 +67,8 @@ export class AmpSidebar extends AMP.BaseElement { /** @private @const {!Viewport} */ this.viewport_ = this.getViewport(); - /** @private @const {boolean} */ - this.hasMask_ = false; + /** @private @const {!Element} */ + this.maskElement_ = false; /** @private @const {boolean} */ this.isPaddingAdjusted_ = false; @@ -97,9 +97,10 @@ export class AmpSidebar extends AMP.BaseElement { this.fixIosElasticScrollLeak_(); } - if (this.documentElement_.classList.contains('amp-sidebar-open')) { - // Create the mask if the sidebar is rendered in open mode. + if (this.isOpen_()) { this.open_(); + } else { + this.element.setAttribute('aria-hidden', 'true'); } this.documentElement_.addEventListener('keydown', event => { @@ -141,6 +142,7 @@ export class AmpSidebar extends AMP.BaseElement { setStyles(div, { 'height': IOS_SAFARI_BOTTOMBAR_HEIGHT, 'width': '100%', + 'background-color': 'transparent', }); this.element.appendChild(div); } @@ -152,13 +154,22 @@ export class AmpSidebar extends AMP.BaseElement { * @private */ toggle_() { - if (this.documentElement_.classList.contains('amp-sidebar-open')) { + if (this.isOpen_()) { this.close_(); } else { this.open_(); } } + /** + * Returns true if the sidebar is opened. + * @returns {boolean} + * @private + */ + isOpen_() { + return this.element.hasAttribute('open'); + } + /** * Reveals the sidebar. * @private @@ -170,9 +181,10 @@ export class AmpSidebar extends AMP.BaseElement { } this.mutateElement(() => { this.viewport_.addToFixedLayer(this.element); - this.createMask_(); - this.documentElement_.classList.add('amp-sidebar-open'); - this.documentElement_.classList.remove('amp-sidebar-closed'); + this.openMask_(); + this.element.setAttribute('open', ''); + this.element.classList.remove('-amp-sidebar-closed'); + this.element.setAttribute('aria-hidden', 'false'); this.element./*REVIEW*/scrollTop = 1; }); } @@ -184,8 +196,10 @@ export class AmpSidebar extends AMP.BaseElement { close_() { this.viewport_.restoreOriginalTouchZoom(); this.mutateElement(() => { - this.documentElement_.classList.remove('amp-sidebar-open'); - this.documentElement_.classList.add('amp-sidebar-closed'); + this.closeMask_() + this.element.removeAttribute('open'); + this.element.classList.add('-amp-sidebar-closed'); + this.element.setAttribute('aria-hidden', 'true'); this.viewport_.removeFromFixedLayer(this.element); }); } @@ -217,20 +231,33 @@ export class AmpSidebar extends AMP.BaseElement { /** * @private */ - createMask_() { - if (this.hasMask_) { - return; + openMask_() { + if (!this.maskElement_) { + const mask = this.document_.createElement('div'); + mask.classList.add('-amp-sidebar-mask'); + mask.addEventListener('click', () => { + this.close_(); + }); + this.element.parentNode.appendChild(mask); + mask.addEventListener('touchmove', e => { + e.preventDefault(); + }); + this.maskElement_ = mask; } - const mask = this.document_.createElement('div'); - mask.classList.add('-amp-sidebar-mask'); - mask.addEventListener('click', () => { - this.toggle_(); - }); - this.element.parentNode.appendChild(mask); - mask.addEventListener('touchmove', e => { - e.preventDefault(); + setStyles(this.maskElement_, { + 'display': 'block', }); - this.hasMask_ = true; + } + + /** + * @private + */ + closeMask_() { + if (this.maskElement_) { + setStyles(this.maskElement_, { + 'display': 'none', + }); + } } /** @@ -238,7 +265,7 @@ export class AmpSidebar extends AMP.BaseElement { */ fixIosElasticScrollLeak_() { this.element.addEventListener('scroll', e => { - if (this.documentElement_.classList.contains('amp-sidebar-open')) { + if (this.isOpen_()) { if (this.element./*REVIEW*/scrollTop < 1) { this.element./*REVIEW*/scrollTop = 1; e.preventDefault(); diff --git a/extensions/amp-sidebar/0.1/test/test-amp-sidebar.js b/extensions/amp-sidebar/0.1/test/test-amp-sidebar.js index c1bce917d54a..ea7dc88961bd 100644 --- a/extensions/amp-sidebar/0.1/test/test-amp-sidebar.js +++ b/extensions/amp-sidebar/0.1/test/test-amp-sidebar.js @@ -94,8 +94,10 @@ describe('amp-sidebar', () => { callback(); }; impl.open_(); - expect(iframe.doc.documentElement.classList.contains('amp-sidebar-open')) - .to.be.true; + expect(sidebarElement.hasAttribute('open')).to.be.true; + expect(sidebarElement.getAttribute('aria-hidden')).to.equal('false'); + expect(sidebarElement.classList.contains('-amp-sidebar-closed')) + .to.be.false; }); }); @@ -108,9 +110,10 @@ describe('amp-sidebar', () => { callback(); }; impl.close_(); - expect( - iframe.doc.documentElement.classList.contains('amp-sidebar-closed')) - .to.be.true; + expect(sidebarElement.hasAttribute('open')).to.be.false; + expect(sidebarElement.getAttribute('aria-hidden')).to.equal('true'); + expect(sidebarElement.classList.contains('-amp-sidebar-closed')) + .to.be.true; }); }); @@ -122,23 +125,20 @@ describe('amp-sidebar', () => { impl.mutateElement = function(callback) { callback(); }; - expect(iframe.doc.documentElement.classList.contains('amp-sidebar-open')) + expect(sidebarElement.hasAttribute('open')).to.be.false; + expect(sidebarElement.getAttribute('aria-hidden')).to.equal('true'); + expect(sidebarElement.classList.contains('-amp-sidebar-closed')) .to.be.false; - expect( - iframe.doc.documentElement.classList.contains('amp-sidebar-closed')) - .to.be.false; impl.toggle_(); - expect(iframe.doc.documentElement.classList.contains('amp-sidebar-open')) - .to.be.true; - expect( - iframe.doc.documentElement.classList.contains('amp-sidebar-closed')) - .to.be.false; - impl.toggle_(); - expect(iframe.doc.documentElement.classList.contains('amp-sidebar-open')) + expect(sidebarElement.hasAttribute('open')).to.be.true; + expect(sidebarElement.getAttribute('aria-hidden')).to.equal('false'); + expect(sidebarElement.classList.contains('-amp-sidebar-closed')) .to.be.false; - expect( - iframe.doc.documentElement.classList.contains('amp-sidebar-closed')) - .to.be.true; + impl.toggle_(); + expect(sidebarElement.hasAttribute('open')).to.be.false; + expect(sidebarElement.getAttribute('aria-hidden')).to.equal('true'); + expect(sidebarElement.classList.contains('-amp-sidebar-closed')) + .to.be.true; }); }); @@ -150,14 +150,12 @@ describe('amp-sidebar', () => { impl.mutateElement = function(callback) { callback(); }; - expect(iframe.doc.documentElement.classList.contains('amp-sidebar-open')) - .to.be.false; + expect(sidebarElement.hasAttribute('open')).to.be.false; impl.open_(); - expect(iframe.doc.documentElement.classList.contains('amp-sidebar-open')) - .to.be.true; - expect( - iframe.doc.documentElement.classList.contains('amp-sidebar-closed')) - .to.be.false; + expect(sidebarElement.hasAttribute('open')).to.be.true; + expect(sidebarElement.getAttribute('aria-hidden')).to.equal('false'); + expect(sidebarElement.classList.contains('-amp-sidebar-closed')) + .to.be.false; const eventObj = document.createEventObject ? document.createEventObject() : document.createEvent('Events'); if (eventObj.initEvent) { @@ -169,11 +167,10 @@ describe('amp-sidebar', () => { const el = iframe.doc.documentElement; el.dispatchEvent ? el.dispatchEvent(eventObj) : el.fireEvent('onkeydown', eventObj); - expect(iframe.doc.documentElement.classList.contains('amp-sidebar-open')) - .to.be.false; - expect( - iframe.doc.documentElement.classList.contains('amp-sidebar-closed')) - .to.be.true; + expect(sidebarElement.hasAttribute('open')).to.be.false; + expect(sidebarElement.getAttribute('aria-hidden')).to.equal('true'); + expect(sidebarElement.classList.contains('-amp-sidebar-closed')) + .to.be.true; }); }); diff --git a/extensions/amp-sidebar/amp-sidebar.md b/extensions/amp-sidebar/amp-sidebar.md index 62dbec087d2b..5b8d6ed3337b 100644 --- a/extensions/amp-sidebar/amp-sidebar.md +++ b/extensions/amp-sidebar/amp-sidebar.md @@ -71,6 +71,7 @@ Alternatively pressing the escape key on the keyboard will also close the lightb Example ```html
+ ``` @@ -81,17 +82,13 @@ Example The `side` attribute may be set to `left` or `right` depending upon whether sidebar should open in the left or right side of the page. If a `side` is not set on the `amp-sidebar` then it will be inherited from the `body` tag's `dir` attribute (`ltr` => `left` , `rtl` => right') and if one does not exist then the `side` is defaulted to `left`. +**open** +The `open` attribute is present on the sidebar when it is open. + ## Styling The `amp-sidebar` component can be styled with standard CSS. - The `width` of the `amp-sidebar` may be set to adjust the width of the sidebar between the pre-set min(30vw) and max(80vw) values. - The height of the `amp-sidebar` may be set to adjust the height of the sidebar if required. If the height exceeds 100vw then the sidebar will have a vertical scrollbar. The preset height of the sidebar is 100vw and can be overridden in CSS to make it shorter. -- The current state of the sidebar is exposed via the `amp-sidebar-open` class name that is set on the `html` tag when the side bar is open on the page. -- The sidebar animation can be changed by overriding the following CSS selector: -```css -.amp-sidebar-closed amp-sidebar, -.amp-sidebar-open amp-sidebar { - transition: transform 0.5s ease; -} -``` +- The current state of the sidebar is exposed via the `open` attribute that is set on the `amp-sidebar` tag when the side bar is open on the page. diff --git a/test/manual/amp-sidebar.amp.html b/test/manual/amp-sidebar.amp.html index 07585d362954..f86be98351d3 100644 --- a/test/manual/amp-sidebar.amp.html +++ b/test/manual/amp-sidebar.amp.html @@ -184,7 +184,7 @@ - +
  • Nav item 1
  • Nav item 2