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
Implemented AmpContext and IframeMessagingClient #6310
Conversation
/** | ||
* @abstract | ||
*/ | ||
export class XDomainChildMessageHandler { |
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.
How about IframeMessagingClient
?
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.
works for me
try { | ||
// We should probably report exceptions within callback | ||
this.callbackFor_[payload.type](payload); | ||
} catch (err) { |
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 let it fail? since we've no idea if the failure is recoverable.
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 would letting the error propagate be a good thing? So if the callback fails for whatever reason, that the ad can see that it failed?
* Only valid for the trivial case when we will always be messaging our parent | ||
* Should be overwritten for subclasses | ||
*/ | ||
getAmpWindow(){ |
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.
getHostWindow()
, since in amp-inabox use case, it's beyond AMP
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.
fixed
*/ | ||
try { | ||
console.log("Attempting to make AmpContext"); | ||
const windowContextCreated = new Event('windowContextCreated'); |
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.
maybe prefix the event name with amp
to avoid conflict?
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.
sg
@@ -173,6 +173,28 @@ function compile(watch, shouldMinify, opt_preventRemoveAndMakeDir, | |||
includePolyfills: true, | |||
}); | |||
|
|||
compileJs('./3p/', 'ampcontext.js', |
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 we need 2 binaries ?
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.
Well the reason that it is split into 2 files, ampcontext and ampcontext-lib, is because firing the 'windowContextCreated' event from within the AmpContext constructor sends it before the instance is actually ready. Whether we actually need 2 binaries is a good question. Are the binaries only made for files that ad networks should get access to off our cdn? In that case I guess we don't need one for ampcontext.js
@keithwrightbos
* @returns {function} that when called stops triggering the callback | ||
* every time we receive a page visibility message. | ||
*/ | ||
AmpContext.prototype.observePageVisibility = function(callback) { |
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 not moving those methods into the class?
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
Enum for the different postmessage types for the window.context | ||
postmess api. | ||
*/ | ||
export const MessageType_ = { |
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.
do we plan to use it outside this file?
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.
yea I think I was, I can double check where. I know there was a reason I put the export on
* the class instance. | ||
* @private | ||
*/ | ||
setupMetadata_() { |
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.
pls move private method to the bottom of the class
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.startTime = context.startTime; | ||
this.referrer = context.referrer; | ||
} catch (err) { | ||
user().error('Could not parse metadata.'); |
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 will be a dev()
error
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.
fixed
|
||
/** @override */ | ||
getSentinel(){ | ||
this.setupMetadata_(); |
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 move this to constructor?
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, actually don't need to call it all in the constructor, setupmetadata takes care of it. just need to overwrite the parent class getSentinel. fixed it.
this.ancestors = []; | ||
for (let win = this.win_; win && win != win.parent; win = win.parent) { | ||
// Add window keeping the top-most one at the front. | ||
this.ancestors.unshift(win.parent); |
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: pushing then reversing the final array will be faster.
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
return this.ancestors[this.depth]; | ||
} else { | ||
dev().error('Incorrect sentinel format.'); | ||
throw new Error('Incorrect sentinel format.'); |
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 can be done as a dev().assert
:
const sentinelMatch = this.sentinel.match(/((\d+)-\d+)/);
dev().assert(sentinelMatch, 'Incorrect sentinel format.');
// use sentinelMatch
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
// Add window keeping the top-most one at the front. | ||
this.ancestors.unshift(win.parent); | ||
} | ||
return this.ancestors[this.depth]; |
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.
So depth
is top-down?
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.
yes
const sentinelMatch = this.sentinel.match(/((\d+)-\d+)/); | ||
if (sentinelMatch) { | ||
this.depth = Number(sentinelMatch[2]); | ||
this.ancestors = []; |
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.
Do we need ancestors
as a property?
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.
no, done
* that message | ||
* @private {object} | ||
*/ | ||
this.callbackFor_ = {}; |
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.
We have a map
helper in types.js
.
listen(this.win_, 'message', message => { | ||
// Does it look a message from AMP? | ||
if (message.source == this.ampWindow && message.data && | ||
message.data.indexOf('amp-') == 0) { |
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.
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.callbackFor_[payload.type]) { | ||
try { | ||
// We should probably report exceptions within callback | ||
this.callbackFor_[payload.type](payload); |
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: this will leak the callbackFor_
object as the this
context.
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 setting callbackFor_ as private enough? I'm not 100% sure what you are saying by this, sorry. Do you just mean that the way it currently is has callbackFor_ as public?
setupEventListener_() { | ||
listen(this.win_, 'message', message => { | ||
// Does it look a message from AMP? | ||
if (message.source == this.ampWindow && message.data && |
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 might be better flattened out:
if (message.source !== this.ampWindow) {
return;
}
if (!startsWith(String(message.data), 'amp-') {
return;
}
if (payload.sentinel !== this.sentinel) {
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.
done
constructor(win) { | ||
super(win); | ||
this.setupMetadata_(); | ||
this.ampWindow = this.getHostWindow(); |
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 this be a private property?
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.
yes that's fine
/** | ||
* Takes the current name on the window, and attaches it to | ||
* the name of the iframe. | ||
* @param {Iframe} iframe The iframe we are adding the context to. |
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.
HTMLIframeElement
?
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
(for dev: cherry pick on to frizz-ampcontext)
* functionality. | ||
*/ | ||
try { | ||
console/*OK*/.log('Attempting to make AmpContext'); |
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.
should use dev()
?
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
*/ | ||
import './polyfills'; | ||
import { | ||
dev, |
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, can you merge them to one line to save some space?
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
} | ||
|
||
/** @override */ | ||
getHostWindow() { |
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.
getHostWindow as a public method, can potentially be called multiple times, should return a cache when available.
we can move the computation logic into constructor.
or, if you want to do lazy initialization, which I don't see much value here, you can initialize this.ampWindow here. Then all the other code should not reference this.ampWindow directly, they should reference this method.
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. moved the logic into the constructor. getHostWindow just returns this.ampWindow now
this.ancestors.unshift(win.parent); | ||
} | ||
return this.ancestors[this.depth]; | ||
} else { |
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: can we reverse the if-else? i.e., fail early in the code and save some indentation.
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.
n/a, got rid of it
*/ | ||
observePageVisibility(callback) { | ||
const stopObserveFunc = this.registerCallback_(MessageType_.EMBED_STATE, | ||
callback); |
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.
we use 4 space indentation for line breaks.
in this case, you can break after '('
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
import {listen} from '../src/event-helper'; | ||
import {getRandom} from '../src/3p-frame'; | ||
import {user} from '../src/log'; | ||
/** |
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 a blank line
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 {function(object)} callback The callback function to call | ||
* when a message with type messageType is received. | ||
*/ | ||
registerCallback_(messageType, callback) { |
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.
maybe call it listenFor
?
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.
there is already a listenFor function in use, would rather be able to disambiguate
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.
sounds good.
@@ -173,6 +173,17 @@ function compile(watch, shouldMinify, opt_preventRemoveAndMakeDir, | |||
includePolyfills: true, | |||
}); | |||
|
|||
compileJs('./3p/', 'ampcontext-lib.js', | |||
'./dist.3p/' + (shouldMinify ? internalRuntimeVersion : 'current'), { | |||
minifiedName: 'ampcontext-lib.js', |
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.
how about ampcontext-v0.js
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.
that's fine
@@ -0,0 +1,32 @@ | |||
/** | |||
* Copyright 2015 The AMP HTML Authors. All Rights Reserved. |
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.
2016
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
@@ -0,0 +1,203 @@ | |||
/** | |||
* Copyright 2015 The AMP HTML Authors. All Rights Reserved. |
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.
2016
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
PTAL - I've addressed all the comments |
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 some cosmetic nitpicks.
this.callbackFor_[payload.type](payload); | ||
} catch (err) { | ||
user().error('IFRAME-MSG', | ||
`- Error in registered callback ${payload.type}`, err); |
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 probably want to config your IDE so that it indents 4 spaces on line break, instead of aligning.
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.
gah whoops, fixed
if (!message.data) { | ||
return; | ||
} | ||
if (!startsWith(String(message.data), 'amp-')) { |
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.
how about merging the 3 if
s into one block
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.
That's how I originally had it, I split it apart as per a comment from @jridgewell
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.
Fine, people have different taste :-)
* @param {function(object)} callback The callback function to call | ||
* when a message with type messageType is received. | ||
*/ | ||
registerCallback_(messageType, callback) { |
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.
sounds good.
Can you fix the Travis, so I can go ahead and merge? |
Just pushed changes ~1 min ago, fixes all of the lint/presubmit/etc stuff.
Or at least it does for me...
…On Wed, Nov 30, 2016 at 1:09 PM, Hongfei Ding ***@***.***> wrote:
Can you fix the Travis, so I can go ahead and merge?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#6310 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AEFDACBNgBAaLH0fGTtgAC3O_Ouft6p9ks5rDbvmgaJpZM4K5-Oe>
.
|
it passed all travis stuff, good to go
On Wed, Nov 30, 2016 at 1:13 PM, Brad Frizzell <bradfrizzell@google.com>
wrote:
… Just pushed changes ~1 min ago, fixes all of the lint/presubmit/etc stuff.
Or at least it does for me...
On Wed, Nov 30, 2016 at 1:09 PM, Hongfei Ding ***@***.***>
wrote:
> Can you fix the Travis, so I can go ahead and merge?
>
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub
> <#6310 (comment)>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AEFDACBNgBAaLH0fGTtgAC3O_Ouft6p9ks5rDbvmgaJpZM4K5-Oe>
> .
>
|
// Add window keeping the top-most one at the front. | ||
ancestors.push(win.parent); | ||
} | ||
ancestors.reverse(); |
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.
We can avoid the reverse by counting backwards:
this.ampWindow = ancestors[ancestors.length - 1 - this.depth];
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
/** Calculate the hostWindow / ampWindow_ */ | ||
const sentinelMatch = this.sentinel.match(/((\d+)-\d+)/); | ||
dev().assert(sentinelMatch, 'Incorrect sentinel format'); | ||
this.depth = Number(sentinelMatch[2]); |
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 this property 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.
nope, not needed as a property anymore. fixed
|
||
/** @override */ | ||
registerCallback_(messageType, callback) { | ||
user().assertEnumValue(MessageType_, messageType); |
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 allows the send-*
types, which weren't allowed before. Is that intentional?
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.
yes, I had previously made a mistake.
observePageVisibility(callback) { | ||
const stopObserveFunc = this.registerCallback_( | ||
MessageType_.EMBED_STATE, callback); | ||
this.ampWindow_.postMessage/*REVIEW*/({ |
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.
/*OK*/
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
observeIntersection(callback) { | ||
const stopObserveFunc = this.registerCallback_( | ||
MessageType_.INTERSECTION, callback); | ||
this.ampWindow_.postMessage/*REVIEW*/({ |
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.
/*OK*/
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 {int} width The new width for the ad we are requesting. | ||
*/ | ||
requestResize(height, width) { | ||
this.ampWindow_.postMessage/*REVIEW*/({ |
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.
/*OK*/
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.callbackFor_[payload.type]) { | ||
try { | ||
// We should probably report exceptions within callback | ||
this.callbackFor_[payload.type](payload); |
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: this leaks the callbackFor_
private property. We can assign the function to a variable, then call the variable to avoid.
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
} | ||
|
||
/** @override */ | ||
getHostWindow() { |
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.
We can avoid these awkward overrides by using a generator method in the base class:
class Base {
getHostWindow() {
if (!this.window_) {
this.window_ = this.generateWindow();
}
return this.window_;
}
generateWindow() {
return this.win.parent;
}
}
class Special extends Base {
generateWindow() {
// depth stuff
}
}
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 sounds better. @bradfrizzell what you say?
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.
implementing.
* Added ampcontext.js, ampcontext-lib and updated gulpfile. * Changed how ampcontext-lib creates window.context (for dev: cherry pick on to frizz-ampcontext) * Split out PostMessenger as a parent class * Changed name of class * Made changes as per Hongfei. Had to expose getRandom(). * super() must be called before we can use this * Fixed broken funtion documentation * Fixed bug in lib and changed error thrown * Made changes to fix presubmit failures * Made fixes as per reviewers * Fixed lint/style and presubmit errors.
* Added ampcontext.js, ampcontext-lib and updated gulpfile. * Changed how ampcontext-lib creates window.context (for dev: cherry pick on to frizz-ampcontext) * Split out PostMessenger as a parent class * Changed name of class * Made changes as per Hongfei. Had to expose getRandom(). * super() must be called before we can use this * Fixed broken funtion documentation * Fixed bug in lib and changed error thrown * Made changes to fix presubmit failures * Made fixes as per reviewers * Fixed lint/style and presubmit errors.
No description provided.