-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integrate Google AdSense for Search and Adsense for Shopping (on the Custom Search Ads protocol) with AMP #6518
Conversation
@lannka Can you take a look at this? |
@jasti FYI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW I've reviewed this code, though I'm not a project owner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR!
I saw some methods with a hundred lines. Could you please extract out some functions for better readability?
* @param {Object} container HTML element of the CSA container | ||
* @param {number} height Height to resize, in pixels | ||
*/ | ||
function resizeCsa(container, height) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move private method to the bottom
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
* @param {*} backfillPageOptions AFS page options (if necessary) | ||
* @param {*} backfillAdblockOptions AFS ad unit options (if necessary) | ||
* @return {function(string,boolean)} The callback function | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add annotation @visibleForTesting
if it's public only for testing purpose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
* This is needed for an iOS bug found in versions 10.0.1 and below that | ||
* doesn't properly reflow the iframe upon orientation change. | ||
*/ | ||
window.addEventListener('orientationchange', function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it necessary to have this call outside your main function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@lannka Any other feedback? |
ping @lannka |
// Get parent width in case we want to override | ||
const width = global.document.body.clientWidth; | ||
|
||
validateData(data, [], ['afshPageOptions', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: please break line before 'afshPageOptions', and after 'ampSlotIndex'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
afshPageOptions['source'] = 'amp'; | ||
afshPageOptions['referer'] = window.context.referrer; | ||
} catch (e) {} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can leverage Object.assign
import {tryParseJson} from 'src/json.js';
const afshPageOptions = Object.assign(
{source: 'amp', referer: global.context.referrer},
tryParseJson(data['afshPageOptions']));
you might need to run gulp dep-check
to see if there's dependency errors. adding json.js
to the whitelist should fix that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tryParseJson isn't gauranteed to return an Object, so gulp check-types complains when I do this
actual parameter 1 of Object.assign does not match formal parameter
found : (*|undefined)
required: Object
tryParseJson(data['afsPageOptions']),
* This is needed for an iOS bug found in versions 10.0.1 and below that | ||
* doesn't properly reflow the iframe upon orientation change. | ||
*/ | ||
window.addEventListener('orientationchange', function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use arrow function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
// Save the height of the container before the event listener triggers | ||
const oldHeight = document.getElementById('csacontainer').style.height; | ||
|
||
setTimeout(function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
'ampSlotIndex']); | ||
|
||
// Add the ad container to the document | ||
const d = global.document.createElement('div'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you give it a better name, like containerDiv
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
* @param {Node} container HTML element of the CSA container | ||
* @param {number} containerH Height to resize the CSA container, in pixels | ||
*/ | ||
function createOverflow(overflowH, fullH, container, containerH) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: please swap the position of createOverFlow
and resizeCsa
. Easier for reader to follow the logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
global._googCsa('plas', afshPageOptions, afshAdblockOptions); | ||
} | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you want me to remove this? This is an ad call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i meant remove the blank line :-)
* @return {function(string,boolean)} The callback function | ||
* @visibleForTesting | ||
*/ | ||
export function generateCallback(backfillPageOptions, backfillAdblockOptions) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you will want to pass in the global object
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
||
/** | ||
* Create a callback function to resize the iframe and/or request backfill | ||
* @param {*} backfillPageOptions AFS page options (if necessary) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{?Object}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I annotate is as anything other than *, gulp check-types complains
found : (*|undefined)
required: Object
tryParseJson(data['afshPageOptions'])
* @param {string} containerName | ||
* @param {boolean} adsLoaded | ||
*/ | ||
const resizeIframe = function(containerName, adsLoaded) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of return a function, we typically do:
afshAdblockOptions['adLoadedCallback'] = resizeIframe.bind(null, afsPageOptions, afsAdblockOptions);
function resizeIframe(backfillPageOptions, backfillAdblockOptions, containerName, adsLoaded) {
...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Latest round of changes are done, but this code doesn't pass check-types because JSON.parse isn't guaranteed to return an Object.
change some variable names, mostly condense code
global.innerHeight doesn't work because I need the height of the AMP container at the time of requesting the ads before the iframe is resized. Different browsers have different behaviors (some bust the iframe, some don't). Changing to global.innerHeight broke the overflow implementation on iOS.
iOS9 appears to have a race condition and sometimes shows the overflow on top of the ads, even though ALL containers and iframe appear to have the right height set . Adding this to see if it fixes the issue. This doesn’t appear to be a problem for iOS10 or Android.
This reverts commit 2040f76.
I’m adding this because on ios9, the ad content is visible underneath the overflow element, even though the height of the container and iframe are being set correctly.
There is some weirdness I can't explain with iOS9 (9.3.5) that shows the overflow element on top of the adblock. When I inspect it, the heights for the AMP ad, AMP iframe, CSA div, and CSA iframe are all set correctly. I tried setting overflow-y: 'hidden' in the code and that didn't fix the problem either. If I scroll down and back up, the problem fixes itself. If I play around with the CSS properties (and don't actually change anything, just set it back to what it was before) it fixes itself. Not sure what's going on here but I'll investigate more on Monday. |
On iOS9, when a resize is requested sometimes the CSA iframe busts and then returns to it's full height even though we have set the height via CSS. I was able to stop this behavior by setting the iframe width to "100%", but you can still see a flicker of the ad expanding and contracting. For some reason this only happens some of the time on iOS9 and not at all on iOS10 or Android. Perhaps this is related to the iframe reflow issue that required me to add an event listener for orientation change. One possible way to stop the flicker is to make the overflow background a solid color and not transparent, but that locks partners into a particular styling which we probably don't want to do. Test page: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you had iOS9 particular bug that is hard to fix, I suggest you add a TODO and open an issue. We can get this PR in first.
}); | ||
|
||
// If resize was denied, show overflow element and resize container | ||
global.context.onResizeDenied(function(requestedHeight) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will there be a problem when resizeIframe()
get called multiple times? Seems we're going to register multiple listener here, which could create multiple overflow elements?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resize iframe is only called multiple times if the partner wants to make a new request for (AFS) ads if the first (AFSh) request didn't return anything. In this case, we won't have made an overflow or created any listeners because adsLoaded in resizeIframe will be false.
The resizeDenied and resizeSuccess functions check for existence of overflow before creating a new one and/or resizing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even though, I think logically it's better to move this logic out of the resize handler, to make sure we only register once.
const pageOptions = {source: 'amp', referer: global.context.referrer}; | ||
const adblockOptions = {container: containerId}; | ||
const afshPageOptions = Object.assign( | ||
Object(tryParseJson(data['afshPageOptions'])), pageOptions); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did you try swap the argument position? That will help you get rid of Object()
.
Object.assign(pageOptions, tryParseJson(data['afshPageOptions']));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, never mind. that will mutate pageOptions
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switching the order does not get rid of the check-types error. Furthermore, if a partner passes in "source" or "referrer" they would end up overriding what we set if we do it in this order.
global.addEventListener('orientationchange', () => { | ||
// Save the height of the container before the event listener triggers | ||
const oldHeight = containerDiv.style.height; | ||
setTimeout(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
global.setTimeout
*/ | ||
global.addEventListener('orientationchange', () => { | ||
// Save the height of the container before the event listener triggers | ||
const oldHeight = containerDiv.style.height; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you extract out the whole listener to a function?
|
||
// Only call for ads once the script has loaded | ||
loadScript(global, 'https://www.google.com/adsense/search/ads.js', () => { | ||
if (data['afsPageOptions'] != null && data['afshPageOptions'] == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you extract out the load callback to a function?
}); | ||
|
||
// If resize was denied, show overflow element and resize container | ||
global.context.onResizeDenied(function(requestedHeight) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even though, I think logically it's better to move this logic out of the resize handler, to make sure we only register once.
} | ||
|
||
// Event listener needed for iOS9 bug | ||
global.addEventListener('orientationchange', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
global.addEventListener('orientationchange', orientationChangeHandler.bind(null, global, containerDiv));
|
||
// Only call for ads once the script has loaded | ||
loadScript(global, 'https://www.google.com/adsense/search/ads.js', () => { | ||
requestCsaAds(global, data, afsPage, afsAd, afshPage, afshAd); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use bind here as well
let currentAmpHeight = null; | ||
|
||
// Enum to hold different ad types | ||
const ADTYPE = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/** @enum {string} */
// Enum to hold different ad types | ||
const ADTYPE = { | ||
UNSUPPORTED: 0, | ||
AFS: 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add some description about the enum value?
import * as sinon from 'sinon'; | ||
import * as _3p from '../../../3p/3p'; | ||
|
||
describe('amp-ad-csa-impl', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems this describe
wrapper can be omitted?
…resizeIframe other minor refactoring as well
I addressed your comments and tried to remove unnecessary code to make it more compact (and in some cases fit on one line). Let me know if I should reorder the helper functions or do anything else to clean it up. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some more nitpicks
|
||
/** | ||
* Enum for different AdSense Products | ||
* UNSUPPORTED: Value if we can't determine which product to request |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick, you can inline descriptions.
/** Value if we can't determine which product to request */
UNSUPPORTED: 0,
Object(tryParseJson(data['afsAdblockOptions'])), adblockOptions); | ||
|
||
// Special case for AFSh when "auto" is the requested width | ||
if (afshAd != null && afshAd['width'] == 'auto') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems afshAd
is guaranteed not null
* @param {?Object} afsP The parsed AFS page options object | ||
* @param {?Object} afsA The parsed AFS adblock options object | ||
* @param {?Object} afshP The parsed AFSh page options object | ||
* @param {?Object} afshA The parsed AFSh adblock options object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems none of the arguments can be null
*/ | ||
function requestCsaAds(global, data, afsP, afsA, afshP, afshA) { | ||
const type = getAdType(data); | ||
if (type == ADTYPE.AFS) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is switch
more appropriate here?
* AFSHBACKFILL: AdSense for Shopping, backfilled with AdSense for Search | ||
* @enum {number} | ||
*/ | ||
const ADTYPE = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AD_TYPE
UNSUPPORTED: 0, | ||
AFS: 1, | ||
AFSH: 2, | ||
AFSHBACKFILL: 3, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFSH_BACKFILL
* AFSHBACKFILL: AdSense for Shopping, backfilled with AdSense for Search | ||
* @enum {number} | ||
*/ | ||
const ADTYPE = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you just import this enum?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with one more comment. Please also resolve merge conflicts.
global._googCsa('plas', afshP, afshA); | ||
break; | ||
default: | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: return is not needed
* @param {boolean} ads If ads were returned or not | ||
* @visibleForTesting | ||
*/ | ||
export function resizeIframe(global, bkflPage, bkflAd, conName, ads) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shall we just split this function into 2?
function resizeIframe(global, containerName, hasAd) {}
function backfill(global, backfillPage, backfillAd) {}
it gives not just shorter argument list, but also avoided the recursive call of resizeIframe.
Then the above listener code becomes:
afshA['adLoadedCallback'] = (containerName, hasAd) => {
if (hasAd) {
resizeIframe(global, containerName, hasAd);
} else {
backfill(global, afsP, afsA)
}
}
# Conflicts: # ads/google/csa.js
# Conflicts: # 3p/integration.js # ads/_config.js # ads/google/adsense.md # examples/ads.amp.html # extensions/amp-ad/amp-ad.md
* @param {?Object} page Backfill AFS page options (if necessary) | ||
* @param {?Object} adblock Backfill AFS ad unit options (if necessary) | ||
*/ | ||
function backfillAds(global, page, adblock) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this little function is only used once, you can inline.
…Custom Search Ads protocol) with AMP (ampproject#6518) * Initial commit for CSA AMP ad integration * update ads example * assign throwaway variable so compiler doesn't complain * fix lint errors * define _googCsa in backfill function * Add link to CSA docs in AdSense docs * fix test error * fix type error * feedback from jeff * update css example * create overflow on resize denied if it doesn't exist * fix from jeff's comments * initial stab at unit tests * first stab at unit tests * add test for backfill * lint issues * create helper functions and move to bottom * hongfei's feedback * use Object.assign and tryparsejson * update tests * code review changes change some variable names, mostly condense code * change global.innerHeight back to initial height global.innerHeight doesn't work because I need the height of the AMP container at the time of requesting the ads before the iframe is resized. Different browsers have different behaviors (some bust the iframe, some don't). Changing to global.innerHeight broke the overflow implementation on iOS. * force dom reflow after appending overflow iOS9 appears to have a race condition and sometimes shows the overflow on top of the ads, even though ALL containers and iframe appear to have the right height set . Adding this to see if it fixes the issue. This doesn’t appear to be a problem for iOS10 or Android. * Revert "force dom reflow after appending overflow" This reverts commit 2040f76. * hide overflow of CSA iframe I’m adding this because on ios9, the ad content is visible underneath the overflow element, even though the height of the container and iframe are being set correctly. * Set iframe width to 100% to prevent ios9 from breaking the overflow implementation * move code into functions * Move resize handlers to own functions, register in CSA function, not resizeIframe other minor refactoring as well * nitpicks * add forgotten breaks to switch statement * Create two callback functions, one for backfill and one without. * Merge remote-tracking branch 'ampproject/master' into csa-integration # Conflicts: # ads/google/csa.js * Inline backfill ads function * Merge with adsense.md accidentally replaced HC link * travis errors * more travis errors
…Custom Search Ads protocol) with AMP (ampproject#6518) * Initial commit for CSA AMP ad integration * update ads example * assign throwaway variable so compiler doesn't complain * fix lint errors * define _googCsa in backfill function * Add link to CSA docs in AdSense docs * fix test error * fix type error * feedback from jeff * update css example * create overflow on resize denied if it doesn't exist * fix from jeff's comments * initial stab at unit tests * first stab at unit tests * add test for backfill * lint issues * create helper functions and move to bottom * hongfei's feedback * use Object.assign and tryparsejson * update tests * code review changes change some variable names, mostly condense code * change global.innerHeight back to initial height global.innerHeight doesn't work because I need the height of the AMP container at the time of requesting the ads before the iframe is resized. Different browsers have different behaviors (some bust the iframe, some don't). Changing to global.innerHeight broke the overflow implementation on iOS. * force dom reflow after appending overflow iOS9 appears to have a race condition and sometimes shows the overflow on top of the ads, even though ALL containers and iframe appear to have the right height set . Adding this to see if it fixes the issue. This doesn’t appear to be a problem for iOS10 or Android. * Revert "force dom reflow after appending overflow" This reverts commit 2040f76. * hide overflow of CSA iframe I’m adding this because on ios9, the ad content is visible underneath the overflow element, even though the height of the container and iframe are being set correctly. * Set iframe width to 100% to prevent ios9 from breaking the overflow implementation * move code into functions * Move resize handlers to own functions, register in CSA function, not resizeIframe other minor refactoring as well * nitpicks * add forgotten breaks to switch statement * Create two callback functions, one for backfill and one without. * Merge remote-tracking branch 'ampproject/master' into csa-integration # Conflicts: # ads/google/csa.js * Inline backfill ads function * Merge with adsense.md accidentally replaced HC link * travis errors * more travis errors
…Custom Search Ads protocol) with AMP (ampproject#6518) * Initial commit for CSA AMP ad integration * update ads example * assign throwaway variable so compiler doesn't complain * fix lint errors * define _googCsa in backfill function * Add link to CSA docs in AdSense docs * fix test error * fix type error * feedback from jeff * update css example * create overflow on resize denied if it doesn't exist * fix from jeff's comments * initial stab at unit tests * first stab at unit tests * add test for backfill * lint issues * create helper functions and move to bottom * hongfei's feedback * use Object.assign and tryparsejson * update tests * code review changes change some variable names, mostly condense code * change global.innerHeight back to initial height global.innerHeight doesn't work because I need the height of the AMP container at the time of requesting the ads before the iframe is resized. Different browsers have different behaviors (some bust the iframe, some don't). Changing to global.innerHeight broke the overflow implementation on iOS. * force dom reflow after appending overflow iOS9 appears to have a race condition and sometimes shows the overflow on top of the ads, even though ALL containers and iframe appear to have the right height set . Adding this to see if it fixes the issue. This doesn’t appear to be a problem for iOS10 or Android. * Revert "force dom reflow after appending overflow" This reverts commit 2040f76. * hide overflow of CSA iframe I’m adding this because on ios9, the ad content is visible underneath the overflow element, even though the height of the container and iframe are being set correctly. * Set iframe width to 100% to prevent ios9 from breaking the overflow implementation * move code into functions * Move resize handlers to own functions, register in CSA function, not resizeIframe other minor refactoring as well * nitpicks * add forgotten breaks to switch statement * Create two callback functions, one for backfill and one without. * Merge remote-tracking branch 'ampproject/master' into csa-integration # Conflicts: # ads/google/csa.js * Inline backfill ads function * Merge with adsense.md accidentally replaced HC link * travis errors * more travis errors
…Custom Search Ads protocol) with AMP (ampproject#6518) * Initial commit for CSA AMP ad integration * update ads example * assign throwaway variable so compiler doesn't complain * fix lint errors * define _googCsa in backfill function * Add link to CSA docs in AdSense docs * fix test error * fix type error * feedback from jeff * update css example * create overflow on resize denied if it doesn't exist * fix from jeff's comments * initial stab at unit tests * first stab at unit tests * add test for backfill * lint issues * create helper functions and move to bottom * hongfei's feedback * use Object.assign and tryparsejson * update tests * code review changes change some variable names, mostly condense code * change global.innerHeight back to initial height global.innerHeight doesn't work because I need the height of the AMP container at the time of requesting the ads before the iframe is resized. Different browsers have different behaviors (some bust the iframe, some don't). Changing to global.innerHeight broke the overflow implementation on iOS. * force dom reflow after appending overflow iOS9 appears to have a race condition and sometimes shows the overflow on top of the ads, even though ALL containers and iframe appear to have the right height set . Adding this to see if it fixes the issue. This doesn’t appear to be a problem for iOS10 or Android. * Revert "force dom reflow after appending overflow" This reverts commit 2040f76. * hide overflow of CSA iframe I’m adding this because on ios9, the ad content is visible underneath the overflow element, even though the height of the container and iframe are being set correctly. * Set iframe width to 100% to prevent ios9 from breaking the overflow implementation * move code into functions * Move resize handlers to own functions, register in CSA function, not resizeIframe other minor refactoring as well * nitpicks * add forgotten breaks to switch statement * Create two callback functions, one for backfill and one without. * Merge remote-tracking branch 'ampproject/master' into csa-integration # Conflicts: # ads/google/csa.js * Inline backfill ads function * Merge with adsense.md accidentally replaced HC link * travis errors * more travis errors
This change allows publishers to request Google AdSense for Search and AdSense for Shopping on the Custom Search Ads protocol. We introduce a new AMP ad type, called "csa".
#2659