react-dfp
Version:
A React implementation of the google [DFP](https://developers.google.com/doubleclick-gpt/reference "GPT Reference") API. This package is inspired in the awesome library [jquery.dfp](https://github.com/coop182/jquery.dfp.js), and aims to provide its same e
222 lines (197 loc) • 6.07 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
import DFPManager from './manager';
import { Context } from './dfpslotsprovider';
let dynamicAdCount = 0;
export class AdSlot extends React.Component {
static propTypes = {
dfpNetworkId: PropTypes.string,
adUnit: PropTypes.string,
sizes: PropTypes.arrayOf(
PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.number),
PropTypes.string,
]),
),
renderOutOfThePage: PropTypes.bool,
sizeMapping: PropTypes.arrayOf(PropTypes.object),
fetchNow: PropTypes.bool,
adSenseAttributes: PropTypes.object,
targetingArguments: PropTypes.object,
onSlotRender: PropTypes.func,
onSlotRegister: PropTypes.func,
onSlotIsViewable: PropTypes.func,
onSlotVisibilityChanged: PropTypes.func,
shouldRefresh: PropTypes.func,
slotId: PropTypes.string,
className: PropTypes.string,
};
static defaultProps = {
fetchNow: false,
};
constructor(props) {
super(props);
this.doRegisterSlot = this.doRegisterSlot.bind(this);
this.generateSlotId = this.generateSlotId.bind(this);
this.getSlotId = this.getSlotId.bind(this);
this.mapContextToAdSlotProps = this.mapContextToAdSlotProps.bind(this);
this.slotShouldRefresh = this.slotShouldRefresh.bind(this);
this.slotRenderEnded = this.slotRenderEnded.bind(this);
this.slotRegisterCallback = this.slotRegisterCallback.bind(this);
this.slotIsViewable = this.slotIsViewable.bind(this);
this.slotVisibilityChanged = this.slotVisibilityChanged.bind(this);
this.getClasses = this.getClasses.bind(this);
this.state = {
slotId: this.props.slotId || null,
className: this.props.className || '',
};
this.adElementRef = React.createRef ? React.createRef() : (element) => {
this.adElementRef = element;
};
}
componentDidMount() {
// register this ad-unit in the <DFPSlotProvider>, when available.
if (this.context !== undefined && this.context.newSlotCallback) {
this.context.newSlotCallback();
}
this.registerSlot();
}
componentWillUnmount() {
this.unregisterSlot();
}
getSlotId() {
return this.props.slotId || this.state.slotId;
}
getClasses() {
const baseClass = 'adunitContainer';
const extraClasses = this.state.className.split(' ');
extraClasses.push(baseClass);
return extraClasses;
}
generateSlotId() {
return `adSlot-${dynamicAdCount++}`;
}
mapContextToAdSlotProps() {
const context = this.context;
const mappedProps = {};
if (context.dfpNetworkId !== undefined) {
mappedProps.dfpNetworkId = context.dfpNetworkId;
}
if (context.dfpAdUnit !== undefined) {
mappedProps.adUnit = context.dfpAdUnit;
}
if (context.dfpSizeMapping !== undefined) {
mappedProps.sizeMapping = context.dfpSizeMapping;
}
if (context.dfpTargetingArguments !== undefined) {
mappedProps.targetingArguments = context.dfpTargetingArguments;
}
return mappedProps;
}
doRegisterSlot() {
DFPManager.registerSlot({
...this.mapContextToAdSlotProps(),
...this.props,
...this.state,
slotShouldRefresh: this.slotShouldRefresh,
});
if (this.props.fetchNow === true) {
DFPManager.load(this.getSlotId());
}
DFPManager.attachSlotRenderEnded(this.slotRenderEnded);
DFPManager.attachSlotIsViewable(this.slotIsViewable);
DFPManager.attachSlotVisibilityChanged(this.slotVisibilityChanged);
this.slotRegisterCallback();
}
registerSlot() {
if (this.state.slotId === null) {
this.setState({
slotId: this.generateSlotId(),
}, this.doRegisterSlot);
} else {
this.doRegisterSlot();
}
}
unregisterSlot() {
DFPManager.unregisterSlot({
...this.mapContextToAdSlotProps(),
...this.props,
...this.state,
});
DFPManager.detachSlotRenderEnded(this.slotRenderEnded);
DFPManager.detachSlotIsViewable(this.slotIsViewable);
DFPManager.detachSlotVisibilityChanged(this.slotVisibilityChanged);
}
slotRenderEnded(eventData) {
if (eventData.slotId === this.getSlotId()) {
if (this.props.onSlotRender !== undefined) {
// now that slot has rendered we have access to the ref
const params = {
...eventData,
adElementRef: this.adElementRef,
};
this.props.onSlotRender(params);
}
}
}
slotRegisterCallback() {
if (typeof this.props.onSlotRegister === 'function') {
this.props.onSlotRegister({
slotId: this.getSlotId(),
sizes: this.props.sizes,
slotCount: dynamicAdCount,
adElementRef: this.adElementRef,
});
}
}
slotIsViewable(eventData) {
if (eventData.slotId === this.getSlotId()) {
if (this.props.onSlotIsViewable !== undefined) {
this.props.onSlotIsViewable(eventData);
}
}
}
slotVisibilityChanged(eventData) {
if (eventData.slotId === this.getSlotId()) {
if (this.props.onSlotVisibilityChanged !== undefined) {
this.props.onSlotVisibilityChanged(eventData);
}
}
}
slotShouldRefresh() {
let r = true;
if (this.props.shouldRefresh !== undefined) {
r = this.props.shouldRefresh({
...this.mapContextToAdSlotProps(),
...this.props,
slotId: this.getSlotId(),
});
}
return r;
}
render() {
const { slotId } = this.state;
const props = { className: 'adBox' };
if (slotId !== null) {
props.id = slotId;
}
return (
<div className={this.getClasses().join(' ').trim()}>
<div ref={this.adElementRef} {...props} />
</div>
);
}
}
if (Context === null) {
// React < 16.3
AdSlot.contextTypes = {
dfpNetworkId: PropTypes.string,
dfpAdUnit: PropTypes.string,
dfpSizeMapping: PropTypes.arrayOf(PropTypes.object),
dfpTargetingArguments: PropTypes.object,
newSlotCallback: PropTypes.func,
};
} else {
AdSlot.contextType = Context;
}
export default AdSlot;