Skip to content
This repository has been archived by the owner on Feb 13, 2019. It is now read-only.

bulbs-video lazy loading #171

Merged
merged 13 commits into from
Oct 6, 2016
2 changes: 1 addition & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"presets": ["react", "es2015"],
"presets": ["react", "es2015", "stage-2"],
Copy link
Contributor Author

@kand kand Oct 5, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allows us to use object spread provided in current es-next Stage 3; babel, for some reason, is currently providing this in stage-2.

let a = {'one': 1};
let b = {'two': 2};
let c = {...a, ...b};
console.log(c);
// outputs: {'one': 1, 'two': 2}

"plugins": [
"transform-object-assign",
"transform-proto-to-assign",
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ Use this if developing elements within `bulbs-elements` locally
$ ./scripts/webpack-dev-server
```

You can access the examples site now by visiting [localhost:8080]().
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A helpful note.


## Common Components

Some components can be used in more than one element.
Expand Down
30 changes: 30 additions & 0 deletions elements/bulbs-video/bulbs-video-examples.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,36 @@ let examples = {
`;
},
},
'Lazy Load': {
render () {
return `
<div
style="text-align: center;">
Open the console<br>
And inspect the videos<br>
To see lazy load<br>
</div>
<marquee
scrollamount="10"
style="
height: 1000px;
font-size: 50px;
text-align: center;
">
SPACE FOR LAZY LOADING EMULATION. SCROLL TO SEE THE VIDEO.
</marquee>
<div>The following video is not lazy loaded:</div>
<bulbs-video
src="http://localhost:8080/fixtures/bulbs-video/clickhole.json"
disable-lazy-loading>
</bulbs-video>
<div>The following video is lazy loaded:</div>
<bulbs-video
src="http://localhost:8080/fixtures/bulbs-video/clickhole.json">
</bulbs-video>
`;
},
},
},
};

Expand Down
36 changes: 21 additions & 15 deletions elements/bulbs-video/bulbs-video.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { PropTypes } from 'react';
import { registerReactElement } from 'bulbs-elements/register';
import BulbsElement from 'bulbs-elements/bulbs-element';
import { loadOnDemand } from 'bulbs-elements/util'

import VideoField from './fields/video';
import VideoRequest from './fields/video-request';
Expand Down Expand Up @@ -57,22 +58,26 @@ export default class BulbsVideo extends BulbsElement {
}
*/
render () {
let allProps = {
...this.props,
...this.state,
actions: this.store.actions,
autoplayNext: typeof this.props.twitterHandle === 'string',
disableLazyLoading: typeof this.props.disableLazyLoading === 'string',
disableMetaLink: typeof this.props.disableMetaLink === 'string',
embedded: typeof this.props.embedded === 'string',
enablePosterMeta: typeof this.props.enablePosterMeta === 'string',
muted: typeof this.props.muted === 'string',
noEndcard: typeof this.props.noEndcard === 'string',
};

if (!allProps.disableLazyLoading) {

return loadOnDemand(BulbsVideoRoot)(allProps);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the main change. If the bulbs-video instance has not been provided a disable-lazy-loading property, the video element will be subject to lazy loading.

}

return (
<BulbsVideoRoot
{...this.state}
twitterHandle={this.props.twitterHandle}
targetCampaignId={this.props.targetCampaignId}
targetCampaignNumber={this.props.targetCampaignNumber}
targetHostChannel={this.props.targetHostChannel}
targetSpecialCoverage={this.props.targetSpecialCoverage}
autoplayNext={typeof this.props.twitterHandle === 'string'}
embedded={typeof this.props.embedded === 'string'}
enablePosterMeta={typeof this.props.enablePosterMeta === 'string'}
disableMetaLink={typeof this.props.disableMetaLink === 'string'}
muted={typeof this.props.muted === 'string'}
noEndcard={typeof this.props.noEndcard === 'string'}
actions={this.store.actions}
/>
<BulbsVideoRoot {...allProps} />
);
}
}
Expand All @@ -87,6 +92,7 @@ Object.assign(BulbsVideo, {
propTypes: {
autoplay: PropTypes.string,
autoplayNext: PropTypes.string,
disableLazyLoading: PropTypes.string,
disableMetaLink: PropTypes.string,
embedded: PropTypes.string,
enablePosterMeta: PropTypes.string,
Expand Down
50 changes: 49 additions & 1 deletion elements/bulbs-video/bulbs-video.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@ describe('<bulbs-video>', () => {
let subject;
let props = {
src,
disableLazyLoading: true,
};

beforeEach(() => {
BulbsVideo.prototype.setState = sinon.spy();
fetchMock.mock(src, {});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this into each context that needs it since we want to delay this instantiation in lazy load tests.

subject = new BulbsVideo(props);
});

describe('#initialDispatch', () => {

beforeEach(() => {
subject = new BulbsVideo(props);
});

it('fetches video data', () => {
let spy = sinon.spy(subject.store.actions, 'fetchVideo');
subject.initialDispatch();
Expand All @@ -36,6 +41,10 @@ describe('<bulbs-video>', () => {
let resetSpy;
let newSrc;

beforeEach(() => {
subject = new BulbsVideo(props);
});

context('src did not change', () => {
beforeEach(() => {
fetchSpy = sinon.spy(subject.store.actions, 'fetchVideo');
Expand Down Expand Up @@ -72,4 +81,43 @@ describe('<bulbs-video>', () => {
});
});
});

describe('lazy loading', () => {
let container;

beforeEach((done) => {
props.disableLazyLoading = false;

container = document.createElement('div');

container.innerHTML = `<div style="height: 1000px;"></div>`;
document.body.appendChild(container);
setImmediate(() => done());
});

afterEach(() => {
container.innerHTML = '';
});

it('should not load video until it is within viewing threshold', (done) => {
let videoElement = document.createElement('bulbs-video');
videoElement.setAttribute('src', src);
container.appendChild(videoElement);

container.firstElementChild.style.height = '0px';
try {
window.dispatchEvent(new Event('scroll'));
}
catch (error) {
const event = document.createEvent('Event');
event.initEvent('scroll', false, true);
window.dispatchEvent(event);
}

requestAnimationFrame(() => {
expect($(container).find('.bulbs-video-root').length).to.equal(1);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@collin is this the best way we can test this? Doesn't seem to be the best way to do this, but it works.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm not sure of a better way either.

done();
});
});
});
});
2 changes: 0 additions & 2 deletions elements/bulbs-video/components/cover.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import VideoMetaRoot from '../elements/meta/components/root';

export default function Cover (props) {
let { video, actions, enablePosterMeta, disableMetaLink } = props;
let imageId = parseInt(video.poster_url.match(/\d+/)[0], 10);
let metaElement;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per @collin, this property is no longer used and was throwing errors during tests.


if (enablePosterMeta) {
Expand All @@ -22,7 +21,6 @@ export default function Cover (props) {
>
<img
className='bulbs-video-poster'
imageId={imageId}
src={video.poster_url}
/>
<div className='bulbs-video-poster-overlay'>
Expand Down
1 change: 0 additions & 1 deletion elements/bulbs-video/components/cover.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ describe('<bulbs-video> <Cover>', function () {
expect(subject).to.contain(
<img
className='bulbs-video-poster'
imageId={imageId}
src={posterUrl}
/>
);
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"babel-preset-react-hmre": "^1.0.1",
"babel-preset-stage-2": "^6.17.0",
"bower": "^1.7.9",
"camelcase": "^2.0.1",
"chai": "^3.4.1",
Expand Down Expand Up @@ -133,4 +134,4 @@
"scroll-to-element": "^2.0.0",
"yo": "^1.6.0"
}
}
}