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

Top500 ad insertions #46

Merged
merged 2 commits into from
Dec 11, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions app/content/webviewPreload.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,126 @@ ipc.on('zoom-reset', function () {
browserZoomLevel = 0
webFrame.setZoomLevel(browserZoomLevel)
})

/**
* Ensures a node replacement div is visible and has a proper zIndex
*/
function ensureNodeVisible (node) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

We probably want to differentiate between visible on the page and visible in the browser viewport. We don't need the former yet, but we will want it before we start displaying real ads. I put a task in the backlog in asana for it.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point.

if (document.defaultView.getComputedStyle(node).display === 'none') {
node.style.display = ''
}
if (document.defaultView.getComputedStyle(node).zIndex === '-1') {
node.style.zIndex = ''
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

What will this do to hidden ad divs that some less scrupulous pubs use? We would want to block those and not replace them

Copy link
Member Author

Choose a reason for hiding this comment

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

This is only used on the empty left over nodes after blocking is done. So those should already all be blocked.

}

/**
* Determines the ad size which should be shown
* It will first check the node's size and try to infer that way.
* If that is not possible it will rely on the iframeData
*
* @param node The node that is being replaced
* @param iframeData The known preprocessed iframeData for that node
*/
function getAdSize (node, iframeData) {
var acceptableAdSizes = [
[728, 90],
[300, 250],
[160, 600],
[320, 50]
]
for (var i = 0; i < acceptableAdSizes.length; i++) {
var adSize = acceptableAdSizes[i]
if (node.offsetWidth === adSize[0] && node.offsetHeight >= adSize[1] ||
node.offsetWidth >= adSize[0] && node.offsetHeight === adSize[1]) {
return adSize
}
}

if (iframeData) {
return [iframeData.width, iframeData.height]
}

return null
}

/**
* Processes a single node which is an ad
*
* @param node The node of the ad to process
* @param iframeData The iframe data of the node to process from the slimerJS bot
* @param placeholderUrl The vault URL with encoded user ID and session ID to use
*/
function processAdNode (node, iframeData, placeholderUrl) {
if (!node) {
return
}

var adSize = getAdSize(node, iframeData)
// Could not determine the ad size, so just skip this replacement
if (!adSize) {
return
}
var srcUrl = placeholderUrl + '&width=' + encodeURIComponent(adSize[0]) + '&height=' + encodeURIComponent(adSize[1])
if (node.tagName === 'IFRAME') {
node.src = srcUrl
} else {
while (node.firstChild) {
node.removeChild(node.firstChild)
}
var iframe = document.createElement('iframe')
iframe.style.padding = 0
iframe.style.border = 0
iframe.style.margin = 0
iframe.style.width = adSize[0] + 'px'
iframe.style.height = adSize[1] + 'px'
iframe.src = srcUrl
node.appendChild(iframe)
ensureNodeVisible(node)
if (node.parentNode) {
ensureNodeVisible(node.parentNode)
if (node.parentNode) {
ensureNodeVisible(node.parentNode.parentNode)
}
}
}
}

// Fires when the browser has ad replacement information to give
ipc.on('set-ad-div-candidates', function (e, adDivCandidates, placeholderUrl) {
// Keep a lookup for skipped common elements
var fallbackNodeDataForCommon = {}

// Process all of the specific ad information for this page
adDivCandidates.forEach(function (iframeData) {
var selector = '[id="' + iframeData.replaceId + '"]'
var node = document.querySelector(selector)
if (!node) {
return
}

// Skip over known common elements
if (iframeData.replaceId.startsWith('google_ads_iframe_') ||
iframeData.replaceId.endsWith('__container__')) {
fallbackNodeDataForCommon[node.id] = iframeData
return
}

// Find the node and process it
processAdNode(document.querySelector(selector), iframeData, placeholderUrl)
})

// Common selectors which could be on every page
var commonSelectors = [
'[id^="google_ads_iframe_"][id$="__container__"]'
]
commonSelectors.forEach(commonSelector => {
var nodes = document.querySelectorAll(commonSelector)
if (!nodes) {
return
}
Array.from(nodes).forEach(node => {
processAdNode(node, fallbackNodeDataForCommon[node.id], placeholderUrl)
})
})
})
41 changes: 27 additions & 14 deletions js/components/frame.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ const ReactDOM = require('react-dom')
const AppActions = require('../actions/appActions')
const ImmutableComponent = require('./immutableComponent')
const cx = require('../lib/classSet.js')
const uuid = require('node-uuid')

import adInfo from '../data/adInfo.js'
import Config from '../constants/config.js'

class Frame extends ImmutableComponent {
constructor () {
Expand All @@ -17,6 +21,10 @@ class Frame extends ImmutableComponent {
return ReactDOM.findDOMNode(this.refs.webview)
}

componentDidMount () {
this.addEventListeners()
}

componentDidUpdate () {
const activeShortcut = this.props.frame.get('activeShortcut')
switch (activeShortcut) {
Expand Down Expand Up @@ -48,62 +56,67 @@ class Frame extends ImmutableComponent {
}
}

componentDidMount () {
addEventListeners () {
this.webview.addEventListener('new-window', (e) => {
console.log('new window: ' + e.url)
AppActions.newFrame({
location: e.url
})
})
this.webview.addEventListener('close', () => {
console.log('close window')
})
this.webview.addEventListener('enter-html-full-screen', () => {
console.log('enter html full screen')
})
this.webview.addEventListener('leave-html-full-screen', () => {
console.log('leave html full screen')
})
this.webview.addEventListener('page-favicon-updated', () => {
console.log('favicon updated')
})
this.webview.addEventListener('page-title-set', ({title}) => {
console.log('title set', title)
AppActions.setFrameTitle(this.props.frame, title)
})
this.webview.addEventListener('dom-ready', () => {
console.log('dom is ready')
this.webview.addEventListener('dom-ready', (event) => {
this.insertAds(event.target.src)
})
this.webview.addEventListener('load-commit', (event) => {
if (event.isMainFrame) {
let key = this.props.frame.get('key')
console.log('load committed', event.url, key)
AppActions.setLocation(event.url, key)
}
})
this.webview.addEventListener('did-start-loading', () => {
console.log('spinner start loading')
AppActions.onWebviewLoadStart(
this.props.frame)
})
this.webview.addEventListener('did-stop-loading', () => {
console.log('did stop loading')
AppActions.onWebviewLoadEnd(
this.props.frame,
this.webview.getURL())
})
this.webview.addEventListener('did-fail-load', () => {
console.log('did fail load')
})
this.webview.addEventListener('did-finish-load', () => {
console.log('did finish load')
AppActions.updateBackForwardState(
this.props.frame,
this.webview.canGoBack(),
this.webview.canGoForward())
})
}

insertAds (currentLocation) {
let host = new window.URL(currentLocation).hostname.replace('www.', '')
let adDivCandidates = adInfo[host]
if (adDivCandidates) {
// TODO: Use a real user ID and sessionID
const userId = uuid.v4()
const sessionId = uuid.v4()

const placeholderUrl = Config.vault.replacementUrl(userId) + '?' + [
`sessionId=${sessionId}`,
`tagName=IFRAME`
].join('&')
this.webview.send('set-ad-div-candidates', adDivCandidates, placeholderUrl)
}
}

goBack () {
this.webview.goBack()
}
Expand Down
6 changes: 5 additions & 1 deletion js/constants/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

var vaultHost = process.env.VAULT_HOST || 'http://localhost:3000'
// VAULT_HOST can be set to:
// https://vault.brave.com for production
// https://vault-staging.brave.com for a dev build
// http://localhost:3000 for production
var vaultHost = process.env.VAULT_HOST || 'https://vault-staging.brave.com'

export default {
zoom: {
Expand Down
Loading