diff --git a/.eslintrc b/.eslintrc index 54e46a46..9076968f 100644 --- a/.eslintrc +++ b/.eslintrc @@ -16,7 +16,8 @@ "Promise": false, "sinon": false, "xdescribe": false, - "xit": false + "xit": false, + "customElements": false }, "ecmaFeatures": { "arrowFunctions": true, diff --git a/elements/bulbs-carousel/bulbs-carousel-state.test.js b/elements/bulbs-carousel/bulbs-carousel-state.test.js index 0cb59afd..05ab5c58 100644 --- a/elements/bulbs-carousel/bulbs-carousel-state.test.js +++ b/elements/bulbs-carousel/bulbs-carousel-state.test.js @@ -39,7 +39,7 @@ describe(' BulbsCarouselState', () => { firstItem.style.transition = 'none'; // Kill animations for test document.body.appendChild(container); - // document.registerElement polyfill runs on next microtask in some browsers + // customElements.define polyfill runs on next microtask in some browsers // MUST wait until end of queue for elements to be constructed setImmediate(() => { subject = carousel.state; diff --git a/elements/bulbs-carousel/bulbs-carousel.js b/elements/bulbs-carousel/bulbs-carousel.js index d70795db..4c4b23f0 100644 --- a/elements/bulbs-carousel/bulbs-carousel.js +++ b/elements/bulbs-carousel/bulbs-carousel.js @@ -6,7 +6,7 @@ import BulbsCarouselState from './bulbs-carousel-state'; import './bulbs-carousel.scss'; export default class BulbsCarousel extends BulbsHTMLElement { - createdCallback () { + connectedCallback () { invariant( this.slider = this.querySelector('bulbs-carousel-slider'), ' MUST contain a element.' @@ -30,14 +30,13 @@ export default class BulbsCarousel extends BulbsHTMLElement { this.previousButtons = this.getElementsByTagName('bulbs-carousel-previous'); this.nextButtons = this.getElementsByTagName('bulbs-carousel-next'); - this.state = new BulbsCarouselState({ - carousel: this, - carouselItems: this.track.children, - currentIndex: 0, - }); - } - - attachedCallback () { + if (!this.state) { + this.state = new BulbsCarouselState({ + carousel: this, + carouselItems: this.track.children, + currentIndex: 0, + }); + } this.state.pageToCarouselItem(this.state.getActiveCarouselItem()); this.applyState(); } diff --git a/elements/bulbs-carousel/bulbs-carousel.test.js b/elements/bulbs-carousel/bulbs-carousel.test.js index b06d9dd3..74128c9a 100644 --- a/elements/bulbs-carousel/bulbs-carousel.test.js +++ b/elements/bulbs-carousel/bulbs-carousel.test.js @@ -52,7 +52,7 @@ describe('', () => { firstItem.style.transition = 'none'; // Kill animations for test document.body.appendChild(container); - // document.registerElement polyfill runs on next microtask in some browsers + // customElements.define polyfill runs on next microtask in some browsers // MUST wait until end of queue for elements to be constructed setImmediate(() => { track = carousel.track; @@ -69,7 +69,38 @@ describe('', () => { document.body.removeChild(container); }); - describe('createdCallback', () => { + describe('conn', () => { + }); + + describe('connectedCallback', () => { + context('there is an active carousel item', () => { + beforeEach(() => { + secondItem.setAttribute( + 'href', window.location.pathname + ); + }); + + it('pages to the active item in the carousel', () => { + subject.connectedCallback(); + expect(subject.state.pageToCarouselItem).to.have.been.calledWith( + secondItem + ); + }); + }); + + it('applies state', () => { + subject.connectedCallback(); + expect(subject.applyState).to.have.been.called; + }); + }); + + describe('onClick', () => { + beforeEach(() => { + sinon.spy(subject.state,'slideToPrevious'); + sinon.spy(subject.state,'slideToNext'); + sinon.spy(subject, 'stateChanged'); + }); + it('wraps slider content in a ', () => { expect(slider.childNodes).to.have.length(1); expect( @@ -91,7 +122,7 @@ describe('', () => { beforeEach(() => slider.remove()); it('throws an execption', () => { - expect(() => subject.createdCallback()).to.throw( + expect(() => subject.connectedCallback()).to.throw( /MUST contain a / ); }); @@ -99,40 +130,10 @@ describe('', () => { context('called twice', () => { it('does not create a second track', () => { - subject.createdCallback(); + subject.connectedCallback(); expect(subject.querySelector('bulbs-carousel-track bulbs-carousel-track')).to.be.null; }); }); - }); - - describe('attachedCallback', () => { - context('there is an active carousel item', () => { - beforeEach(() => { - secondItem.setAttribute( - 'href', window.location.pathname - ); - }); - - it('pages to the active item in the carousel', () => { - subject.attachedCallback(); - expect(subject.state.pageToCarouselItem).to.have.been.calledWith( - secondItem - ); - }); - }); - - it('applies state', () => { - subject.attachedCallback(); - expect(subject.applyState).to.have.been.called; - }); - }); - - describe('onClick', () => { - beforeEach(() => { - sinon.spy(subject.state,'slideToPrevious'); - sinon.spy(subject.state,'slideToNext'); - sinon.spy(subject, 'stateChanged'); - }); context('click on previous button', () => { beforeEach(() => previousButton.click()); diff --git a/elements/bulbs-carousel/buttons.js b/elements/bulbs-carousel/buttons.js index b825b01c..b2841766 100644 --- a/elements/bulbs-carousel/buttons.js +++ b/elements/bulbs-carousel/buttons.js @@ -1,13 +1,13 @@ import { BulbsHTMLElement, registerElement } from 'bulbs-elements/register'; export class NextButton extends BulbsHTMLElement { - createdCallback () { + connectedCallback () { this.innerHTML = ''; } } export class PreviousButton extends BulbsHTMLElement { - createdCallback () { + connectedCallback () { this.innerHTML = ''; } } diff --git a/elements/bulbs-carousel/buttons.test.js b/elements/bulbs-carousel/buttons.test.js index 30dcd8aa..679e21b5 100644 --- a/elements/bulbs-carousel/buttons.test.js +++ b/elements/bulbs-carousel/buttons.test.js @@ -5,11 +5,16 @@ let subject; describe('', () => { beforeEach((done) => { subject = document.createElement('bulbs-carousel-next'); - // document.registerElement polyfill runs on next microtask in some browsers + document.body.appendChild(subject); + // customElements.define polyfill runs on next microtask in some browsers // MUST wait until end of queue for elements to be constructed setImmediate(done); }); + afterEach(() => { + subject.remove(); + }); + it('renders a next icon', () => { expect(subject.firstChild.matches('i.fa.fa-angle-right')).to.be.true; }); @@ -18,11 +23,16 @@ describe('', () => { describe('', () => { beforeEach((done) => { subject = document.createElement('bulbs-carousel-previous'); - // document.registerElement polyfill runs on next microtask in some browsers + document.body.appendChild(subject); + // customElements.define polyfill runs on next microtask in some browsers // MUST wait until end of queue for elements to be constructed setImmediate(done); }); + afterEach(() => { + subject.remove(); + }); + it('renders a previous icon', () => { expect(subject.firstChild.matches('i.fa.fa-angle-left')).to.be.true; }); diff --git a/elements/bulbs-carousel/item.js b/elements/bulbs-carousel/item.js index 69f2768f..fd799622 100644 --- a/elements/bulbs-carousel/item.js +++ b/elements/bulbs-carousel/item.js @@ -2,7 +2,7 @@ import { BulbsHTMLElement, registerElement } from 'bulbs-elements/register'; import { moveChildren, copyAttribute } from 'bulbs-elements/util'; export default class CarouselItem extends BulbsHTMLElement { - createdCallback () { + connectedCallback () { if (this.getAttribute('href')) { let anchor = document.createElement('a'); diff --git a/elements/bulbs-carousel/item.test.js b/elements/bulbs-carousel/item.test.js index 3912b309..328bab46 100644 --- a/elements/bulbs-carousel/item.test.js +++ b/elements/bulbs-carousel/item.test.js @@ -18,7 +18,7 @@ describe('', () => { `; document.body.appendChild(container); - // document.registerElement polyfill runs on next microtask in some browsers + // customElements.define polyfill runs on next microtask in some browsers // MUST wait until end of queue for elements to be constructed setImmediate(() => { subject = container.querySelector('bulbs-carousel-item'); diff --git a/elements/bulbs-cinemagraph/bulbs-cinemagraph.js b/elements/bulbs-cinemagraph/bulbs-cinemagraph.js index 3c5e0992..8b72b831 100644 --- a/elements/bulbs-cinemagraph/bulbs-cinemagraph.js +++ b/elements/bulbs-cinemagraph/bulbs-cinemagraph.js @@ -8,38 +8,28 @@ function BulbsHTMLVideoElement () {} BulbsHTMLVideoElement.prototype = HTMLVideoElement.prototype; class BulbsCinemagraph extends BulbsHTMLVideoElement { - createdCallback () { + get duration () { + return parseFloat(this.getAttribute('cinemagraph-duration') || 0); + } + + connectedCallback () { if (!this.hasAttribute('cinemagraph-duration')) { console.warn('is="bulbs-cinemagraph" elements should have a [cinemagraph-duration] attribute set'); } - // makeVideoPlayableInline is dumb and goes just a little bit too far in the - // video, this results in a quick flash of a black frame in the loop. If we - // override the duration we can get the loop to loop properly. - // For now, this must be determined by hand. - Object.defineProperty(this, 'duration', { - get () { - return parseFloat(this.getAttribute('cinemagraph-duration')) || 0; - }, - }); - this.setAttribute('loop', true); this.setAttribute('webkit-playsinline', true); this.addEventListener('enterviewport', () => this.play()); this.addEventListener('exitviewport', () => this.pause()); - } - attachedCallback () { iphoneInlineVideo.default(this, /* hasAudio */ false); InViewMonitor.add(this); } - detachedCallback () { + disconnectedCallback () { InViewMonitor.remove(this); } } -BulbsCinemagraph.extends = 'video'; - -registerElement('bulbs-cinemagraph', BulbsCinemagraph); +registerElement('bulbs-cinemagraph', BulbsCinemagraph, { extends: 'video' }); diff --git a/elements/bulbs-cinemagraph/bulbs-cinemagraph.test.js b/elements/bulbs-cinemagraph/bulbs-cinemagraph.test.js index 8b7a75eb..031a0b03 100644 --- a/elements/bulbs-cinemagraph/bulbs-cinemagraph.test.js +++ b/elements/bulbs-cinemagraph/bulbs-cinemagraph.test.js @@ -5,13 +5,14 @@ import * as iphoneInlineVideo from 'iphone-inline-video'; describe('