Early implementation of amp-access-laterpay#5920
Early implementation of amp-access-laterpay#5920dvoytenko merged 33 commits intoampproject:masterfrom laterpay:master
Conversation
|
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed, please reply here (e.g.
|
|
@trodrigues Thanks a lot! I set "WIP" label for now. I'll review the initial code and send my comments along.
I (or you :)) will expose the needed functionality via
This depends on whether the configuration changes are in the documents or in your JS module. If it's your JS module - then it should be all handled by caches automatically - they update JS versions and force new version downloads very regularly. You will be looking at most 1wk deployment latency. |
| */ | ||
|
|
||
| import {accessServiceFor} from '../../../src/access-service'; | ||
| import {xhrFor} from '../../../src/xhr'; |
| "vendor": "laterpay", | ||
| "laterpay": {}, | ||
| "laterpay": { | ||
| "access": true |
There was a problem hiding this comment.
Could you explain this please? Seems like this is not needed.
There was a problem hiding this comment.
Yes, this is not needed. I'll remove it.
| this.accessService_ = accessService; | ||
| // TODO: implement | ||
| this.win_ = this.accessService_.win; | ||
| this.laterpayConfig_ = this.accessService_.adapter_.getConfig(); |
There was a problem hiding this comment.
We'll need to expose this as a public method on AccessService, e.g. getConfig(). This is because all private vars are obfuscated.
| this.win_ = this.accessService_.win; | ||
| this.laterpayConfig_ = this.accessService_.adapter_.getConfig(); | ||
| this.purchaseConfig_ = null; | ||
| this.purchaseOptionListeners_ = []; |
There was a problem hiding this comment.
Could you please add jsdoc for private vars?
| } | ||
|
|
||
| getInitialPurchaseConfig_() { | ||
| const urlPromise = this.accessService_.buildUrl_(CONFIG_URL, |
There was a problem hiding this comment.
Let's keep for now. I'll find a way to pass context with config and buildUrl for you in a separate PR.
There was a problem hiding this comment.
Has there been any progress on this one?
There was a problem hiding this comment.
Feel free to expose buildUrl as a public method on the AccessService. But please keep the private buildUrl_ intact to avoid refactoring for now.
| 'amp-access-laterpay-list')[0]; | ||
| const listContainer = document.createElement('ul'); | ||
| // TODO set these up somewhere else and make them configurable | ||
| this.purchaseConfig_.premiumcontent.title = 'Buy this article'; |
There was a problem hiding this comment.
A bigger question I have is how you'd make this translated?
There was a problem hiding this comment.
The possibility I had thought about was to have it be supplied via the in page configuration parameters, which means the merchant could just server render it for whatever language they wanted. This is similar to what we do with our existing client side integration and meta tags: https://connectormwi.laterpay.net/docs/inpage_configuration/translations.html
There was a problem hiding this comment.
Ok. This sounds good. But what's the default? English?
There was a problem hiding this comment.
I mean in your current API...
There was a problem hiding this comment.
Yeah, the default is English.
| listContainer.appendChild(this.createPurchaseOption_(timepass)); | ||
| }); | ||
| const purchaseButton = document.createElement('button'); | ||
| purchaseButton.innerHTML = 'Confirm your selection'; |
There was a problem hiding this comment.
oops, I keep forgetting about textContent
| this.purchaseConfig_.timepasses.forEach(timepass => { | ||
| listContainer.appendChild(this.createPurchaseOption_(timepass)); | ||
| }); | ||
| const purchaseButton = document.createElement('button'); |
There was a problem hiding this comment.
Ditto on this.win_.document.createElement
| purchaseButton.innerHTML = 'Confirm your selection'; | ||
| purchaseButton.disabled = true; | ||
| this.purchaseButton_ = purchaseButton; | ||
| listenOnce(purchaseButton, 'click', this.handlePurchase_.bind(this)); |
There was a problem hiding this comment.
Is this really listenOnce? Is it possible for a user to cancel and select another option and try "purchase" again?
There was a problem hiding this comment.
They should get redirected to our domain for the purchase flow when performing this action, so they would only be able to do that by coming back to the page.
There was a problem hiding this comment.
But that's not what would happen with the "login dialog" when it runs in numerous different scenarios. E.g. it can be launched as a popup dialog. In this case, the page is still there. We will call for the re-authorization if anything changes and it's certainly possible to re-render this dialog if that's what you want. But this is why I was asking..
There was a problem hiding this comment.
Ah yes, that makes sense.
I also just had a better look at the code of the login method in AccessService.
So after the loginPromise is resolved, should I keep the dialog around and only remove it on reauthorization if the authorization is successful, or should I remove it immediately and then re-render? I'm thinking the first approach is probably the better one.
There was a problem hiding this comment.
Either option is up to you. But generally, I'd recommend to rerender the dialog from scratch since you'll get the best and freshest data again.
| }); | ||
| } | ||
|
|
||
| renderPurchaseOverlay_() { |
|
Btw, just dropping a note to mention that I've been sidetracked by a few other things but I expect to resume work on this next week. |
|
@dvoytenko In case you don't find them immediately, I added a couple of replies in comments that became outdated after my last push. |
|
@trodrigues Thanks! Replied. Let me know when it's ready for a review again. And apologies for the delay. Indeed GitHub makes it hard to know when the overall scope is ready for response and people tend to reply bit-by-bit before sending an overall response. If not too hard, could you please send a note "PTAL again" once ready? |
|
@dvoytenko still need to add tests for amp-access-laterpay and update the amp access service tests, but I've implemented those changes to the login methods, and did most of the remaining work on our implementation. I still have a couple of known bugs to fix and one more feature to add (already purchased link) and also need to do some cleanup on the mock service I want to publish separately to test this with. In any case, I'd appreciate a review of these new changes, specially on the changes made to the other modules outside of amp-access-laterpay. |
| "laterpay": {}, | ||
| "authorizationFallbackResponse": {"error": true} | ||
| "authorizationFallbackResponse": {"error": true}, | ||
| "noPingback": true, |
There was a problem hiding this comment.
Why noPingback = true? I don't think you want this. The access system will delegate this call to the pingback method in your service and you can process it as you like, but it's better not advise it in the sample docs.
There was a problem hiding this comment.
Oh, right, I can override that call. I'll do that then.
|
|
||
| <section amp-access="NOT error AND NOT access" amp-access-hide class="login-section"> | ||
| <a on="tap:amp-access.login">Login to read more!</a> | ||
| <amp-access-laterpay-list></amp-access-laterpay-list> |
There was a problem hiding this comment.
So, I looked through this in more detail, and I have two points/questions:
- Would the name
amp-access-laterpay-dialogbe better for this? - Do you have a default action that you can take if a publisher didn't specify this tag? E.g. is it possible to append the dialog to the bottom of the page? Or something like this?
- The way custom elements are supported in AMP, this maybe better to switch to use an element with id, e.g.
<div id="amp-access-laterpay-dialog">. WDYT? If you prefer a tag name - I'll update our validator to allow it and will ensure that AMP runtime does not try to "manage" this tag, it's all possible, but I wanted to discuss.
There was a problem hiding this comment.
- Given that people can potentially customize the look and feel of it, some might prefer displaying it as a dialog while others might prefer displaying it as just a section below an article. But in any case, I don't have any strong preference for one name or the other.
- Right now, no, and we'd like to give the users some measure of control over where this shows up, rather than just having a dialog pop up over all of their content. What we do in our existing client side integration is to have them specify a selector for an element over which our dialog will be placed. So we also don't have a "default" action there, it's always something that requires that little bit of configuration. AFAIK so far this hasn't been a major issue specially because the publishers we've worked with so far seem to like to have that measure of control.
- Either would be fine, also don't have a special preference on this. Just assumed this would be the best way for doing this in AMP.
There was a problem hiding this comment.
Ok. Let's start with id="amp-access-laterpay-dialog" format. And we'll adjust as needed.
| this.vendorConfig_ = configJson[this.vendorName_]; | ||
|
|
||
| /** @const @private {boolean} */ | ||
| this.isPingbackEnabled_ = !configJson['noPingback']; |
There was a problem hiding this comment.
Asked a question about it above. If you don't need pingback at this time (though I think you probably do need it) you can just do a no-op in your service.
There was a problem hiding this comment.
I ended up changing that on the service, but I thought it should still make sense to return the configuration value here.
There was a problem hiding this comment.
True. It does. Let's keep.
| /** | ||
| * Runs the login flow using one of the predefined urls in the amp-access config | ||
| * | ||
| * @param {string} type Type of login defined in the config |
| loginWithType_(type) { | ||
| // Login URL should always be available at this time. | ||
| const loginUrl = user().assert(this.loginUrlMap_[type], | ||
| 'Login URL is not ready: %s', type); |
There was a problem hiding this comment.
Could you change the order? The loginConfig_ assert should go before loginUrlMap_: the record absent in the loginConfig_ is a misconfiguration and it will always mean that loginUrlMap_ is also missing. The reverse is not true, however.
There was a problem hiding this comment.
Ah right, I somehow reordered this when moving it from the other method, not sure why.
| * @param {string} url | ||
| * @return {!Promise} | ||
| */ | ||
| loginWithUrl(url) { |
There was a problem hiding this comment.
We can't use url as an analytics label. Two options we have:
- No label at all (eventLabel == empty string). This will result in analytics events that look like this:
access-login-success. - A label by the name of you source, e.g. "laterpay". The analytics event would look like
access-login-laterpay-success. You can pass "laterpay" as an argument to this method.
Overall, I'd say, if you only supply "laterpay" as an event type, there's no a lot of point in having it at all and we can just go with ''. However, of you'll have a couple of different login types, it might be a good idea to provide them. E.g. "laterpay-login1", "laterpay-login2" - this sort of thing.
There was a problem hiding this comment.
Ah, we do have different purchase types, pay per use or single item sale (time passes), which we essentially use as the different login urls, so that would probably be the correct thing to pass along here.
| // Login URL should always be available at this time. | ||
| const loginUrl = user().assert(this.loginUrlMap_[type], | ||
| 'Login URL is not ready: %s', type); | ||
| dev().fine(TAG, 'Start login: ', eventLabel); |
There was a problem hiding this comment.
Let's do fine(TAG, 'Start login: ', loginUrl, eventLabel)
| if (response.status < 200 || response.status >= 300) { | ||
| /** @const {!Error} */ | ||
| const err = user().createError(`HTTP error ${response.status}`); | ||
| err.response = response; |
There was a problem hiding this comment.
Do you use it anywhere? It's an interesting idea, but if there's some specific need - it might be better to just parse it out and fill it in here specifically rather leave it up to the client to dig in the XHR response?
There was a problem hiding this comment.
I am, here.
That makes me ask: did you see the diff of the amp-access-laterpay.js file? I saw someone complain about this on twitter the other day, but apparently when diffs are too big (I guess) it just does this:

I was looking at the Files Changed tab and thinking "where did all of that code go? I wrote more code than this" and that's when I noticed this collapsed diff.
There was a problem hiding this comment.
Maybe that's what it was. I see it now. Thanks!
|
@trodrigues This looks great! I made a few comments, but nothing major. The changes to the login API look exactly how I imagined them. It looks like you didn't get yet to exposing public |
|
Ah right, I didn't change the |
|
@trodrigues I made couple of responses, but I think we are all good, provided we address One more thing though - this might be a good time to add some content into |
|
I've fixed the issues you mentioned, as well as the broken tests for amp-access and amp-access-vendor. Biggest outstanding issues:
I'm going to be away on leave until the end of year so this will wait until then. In the meanwhile, I also wanted to ask a question about something we noticed while using a demo for this. After logging in, when you get back to the page the scroll position is always maintained. Depending on where the dialog is placed (and if the publisher makes some content available previously or not) this can be a bit confusing or weird. Would it be ok if we included a |
|
@trodrigues Action items sound good.
Is this in popup case or redirect case? Generally, I'd say it's fine if it's behind the configuration flag. You'd need to use |
|
@trodrigues (Happy New Year!) I saw the commit. Should I re-review? |
|
Hi there! thanks :) Yes, you can have another look now. I was just finishing up a couple of other things. So now there's tests and documentation I've also added the feature we discussed about the scroll to top, and an optional header/footer where publishers can potentially set a title and a footer where they can add some further information (like the example you had once pointed out from SPIEGEL where they add some extra explanation about our service). Other than all this, I'm still waiting for our server endpoint to be finished up and deployed, so I'd leave this marked as experimental until that's ready. |
|
Oh, forgot something! I noticed other extended components have a validation section in the readme with a link to some validation rules. Do we also need to add this? Can you give me a bit more info on how to go about that if so? Also, I'll see about adding also something to ampbyexample.com |
| @@ -0,0 +1,55 @@ | |||
| .amp-access-laterpay { | |||
| padding: 16px; | |||
| width: 420px; | |||
There was a problem hiding this comment.
What would happen in, e.g., iPhone6 with 375px width? E.g. do we need max-width: 100% here or something like that?
| this.laterpayConfig_ = this.accessService_.getAdapterConfig(); | ||
|
|
||
| /** @const @private {!PurchaseConfigDef} */ | ||
| this.purchaseConfig_ = null; |
There was a problem hiding this comment.
Doesn't match type since it's defined as non-nullable (!). Also, I think it's not a @const.
There was a problem hiding this comment.
Oh right. weirdly enough I didn't get any warnings/errors when building it. Should that have happened?
There was a problem hiding this comment.
I turned off type compilation on your extension to avoid distracting you too much. So I only comment on the structural things. When we are ready, I'll turn it on and do few minor fixes in one PR.
| this.purchaseConfig_ = null; | ||
|
|
||
| /** @const @private {?Function} */ | ||
| this.purchaseButtonListener_ = null; |
There was a problem hiding this comment.
Ditto, is this really a @const? And few below...
| this.purchaseConfigBaseUrl_ = configUrl + CONFIG_BASE_PATH; | ||
| const articleId = this.laterpayConfig_.articleId; | ||
| if (articleId) { | ||
| this.purchaseConfigBaseUrl_ += '&article_id=' + articleId; |
There was a problem hiding this comment.
Please use encodeURIComponent(articleId)
There was a problem hiding this comment.
Ah thanks, I think I fixed it somewhere else but forgot it here.
| getArticleTitle_() { | ||
| const title = this.doc_.querySelector( | ||
| this.laterpayConfig_.articleTitleSelector); | ||
| dev().assert( |
There was a problem hiding this comment.
This should be user().assert() since the publisher has to see this error. Also, is this config property strictly required? Any reasonable default such as document.title?
There was a problem hiding this comment.
Right, I actually was unsure of that and forgot to ask.
I believe it is strictly required because we show it in the payment dialog (so the user knows what they're paying for) but I'll look into what we do in our existing frontend integration.
There was a problem hiding this comment.
Strict requirement: agree. But if we can try to default, e.g. to this.doc_.title - I see it as a good thing - let's duplicative configuration when they are exactly the same. But if in your experience they are almost never the same - let's keep the way it is.
There was a problem hiding this comment.
Ok, so I was thinking, use this as a default yes, but log a warning message when in dev mode.
|
|
||
| /** | ||
| * @return {!Promise} | ||
| * @returns {boolean} |
There was a problem hiding this comment.
@return {boolean}. Though, the interface defines it as Promise?
| @@ -0,0 +1,241 @@ | |||
| <!--- | |||
| Copyright 2015 The AMP HTML Authors. All Rights Reserved. | |||
| this.vendorConfig_ = configJson[this.vendorName_]; | ||
|
|
||
| /** @const @private {boolean} */ | ||
| this.isPingbackEnabled_ = !configJson['noPingback']; |
| */ | ||
| login(type) { | ||
| login_(loginUrl, eventLabel) { | ||
| const now = Date.now(); |
There was a problem hiding this comment.
Please add @private in the jsdoc.
| }, err => { | ||
| const status = err && err.response && err.response.status; | ||
| if (status === 402) { | ||
| this.purchaseConfig_ = err.responseJson; |
There was a problem hiding this comment.
I'm not sure I'm seeing responseJson actually set anywhere. Could you please confirm?
There was a problem hiding this comment.
This is set by the xhr service, in the callback used in the fetchJson method: https://github.com/ampproject/amphtml/blob/master/src/service/xhr-impl.js#L436
Is that what you meant?
There was a problem hiding this comment.
I see. Sorry, I thought it was you change. LG.
|
Thanks, @trodrigues! I left few more comments, but nothing major. I'll ask someone to add the validator config for you, so don't worry about that. |
|
|
||
| /** | ||
| * @param {!string} href | ||
| * @returns {!Node} |
|
|
||
| /** | ||
| * @private | ||
| * @returns {!Promise} |
There was a problem hiding this comment.
It's @return (no "s" at the end).
There was a problem hiding this comment.
Bad habits from using some jsdoc flavours that allow both 😁
|
|
||
| /** | ||
| * @return {!Promise} | ||
| * @returns {!Promise} |
| this.vendorConfig_ = configJson[this.vendorName_]; | ||
|
|
||
| /** @const @private {boolean} */ | ||
| this.isPingbackEnabled_ = !configJson['noPingback']; |
There was a problem hiding this comment.
True. It does. Let's keep.
| getArticleTitle_() { | ||
| const title = this.doc_.querySelector( | ||
| this.laterpayConfig_.articleTitleSelector); | ||
| dev().assert( |
There was a problem hiding this comment.
Strict requirement: agree. But if we can try to default, e.g. to this.doc_.title - I see it as a good thing - let's duplicative configuration when they are exactly the same. But if in your experience they are almost never the same - let's keep the way it is.
| this.purchaseConfigBaseUrl_ = configUrl + CONFIG_BASE_PATH; | ||
| const articleId = this.laterpayConfig_.articleId; | ||
| if (articleId) { | ||
| this.purchaseConfigBaseUrl_ += '&article_id=' + encodeURIComponent(articleId); |
There was a problem hiding this comment.
Linter complains that this line is too long.
|
@trodrigues Great! Just a few small comments and I'll be able to merge. At the same time, I'm almost done with validator changes, so it should be all ready on AMP's side. |
| /** @private {?Function} */ | ||
| this.alreadyPurchasedListener_ = null; | ||
|
|
||
| /** @const @private {!Array<Event>} */ |
There was a problem hiding this comment.
{!Array<function(!Event)>}?
| this.currentLocale_ = this.laterpayConfig_.locale || 'en'; | ||
|
|
||
| /** @private {Object} */ | ||
| this.i18n_ = Object.assign(DEFAULT_MESSAGES, |
There was a problem hiding this comment.
This will mutate DEFAULT_MESSAGES. You can use Object.assign({}, DEFAULT_MESSAGES, ...) to avoid.
There was a problem hiding this comment.
Ah yes, thanks. Shouldn't be the biggest of issues because DEFAULT_MESSAGES wouldn't ever really get reused but it makes sense.
| /** @const @private {!Xhr} */ | ||
| this.xhr_ = xhrFor(this.win_); | ||
|
|
||
| installStyles(this.win_.document, CSS, () => {}, false, TAG); |
There was a problem hiding this comment.
Should this be done in the constructor? Can we ever have multiple instances?
There was a problem hiding this comment.
There shouldn't be multiple instances of this extension, no, so I'd rather add a check for that.
Given that the instance of this class is already created at the end of this file when the vendor is registered, I'm wondering it it's already the case?
| } else { | ||
| throw err; | ||
| } | ||
| return {access: err.responseJson.access}; |
There was a problem hiding this comment.
err.responseJson is not garaunteed since buildUrl or timeoutPromise could cause the error.
There was a problem hiding this comment.
Ah right. That value should always be false in this case anyway, so there's really no need to get it from the response anyway.
| AUTHORIZATION_TIMEOUT, | ||
| this.xhr_.fetchJson(url, { | ||
| credentials: 'include', | ||
| requireAmpResponseSourceOrigin: true, |
| getContainer_() { | ||
| const id = TAG + '-dialog'; | ||
| const dialogContainer = this.doc_.getElementById(id); | ||
| user().assert( |
There was a problem hiding this comment.
Nit: We can return user().assertElement(), which will allow us to return a {!Element}.
There was a problem hiding this comment.
Oh, yes, that's right. I saw that pattern somewhere in existing code but forgot about it. Thanks!
| this.purchaseButtonListener_(); | ||
| } | ||
| if (this.alreadyPurchasedListener_) { | ||
| this.alreadyPurchasedListener_(); |
There was a problem hiding this comment.
We should null this out afterwards.
| unlistener(); | ||
| } | ||
| if (this.purchaseButtonListener_) { | ||
| this.purchaseButtonListener_(); |
There was a problem hiding this comment.
We should null this out afterwards.
|
@trodrigues @jridgewell I'm all good to merge on my side. Let me know if anything still outstanding. I see that Travis is red with this error: Sounds like there's some typing issue. PTAL. I can merge as soon as Travis is green. |
- add private tag - ensure assert comes first
Also rename i18n keys for clarity.
|
Hah, this was a weird one. The typechecker output is: But the values actually used inside of the method are numbers. I did change some stuff in this method but on first thought, nothing that would affect this value. Then looking at my changes, I remembered I fixed a typo on the type hints for the existing code: Changing the actual expected type in the |
|
@trodrigues Yes, clearly |
- add license to css file - rename property to avoid scrollTop check
|
Had already done so but that exposed a couple of other issues which I also just pushed a fix for. |
|
Merged! Thanks a lot! |
|
Thank you too :) When our server endpoints are ready and we try everything together I'll open a PR to remove the experimental flag. Anything else I should consider when doing that? |
|
@trodrigues Whenever ready, yes, send me the launch PR where experiment is removed and indicate if you want an immediate launch or wait for normal deployment cycle. Our normal cycle takes the changes 1 week to canary and the following week to PROD, but I can launch experiments immediately if desired. |
* Early implementation of amp-access-laterpay * Remove unused amp-access-laterpay config params * Code cleanup issues from PR * Expose response in error object for assertSuccess * Further work on amp-access-laterpay - Remove unnecessary pingback skeleton - Add jsdoc annotations for existing code - Laterpay config retrieval based on draft spec - Improve rendering of the purchase overlay - Price formatting and localization * Expose adapter config on AccessService * Fix pingback detection in amp-access-vendor * Allow amp-access login flow with url only Create new methods loginWithType_ (similar to old login method) and loginWithUrl as entry points to old login method (now private). * Fix exposure of amp access vendor config * Add "already purchased" link * Add CSS for amp-access-laterpay * PR feedback fixes: - add private tag - ensure assert comes first * Add event label to loginWithUrl calls * Also check if we're on localdev mode * Fix amp-access login tests * Fix amp-access-vendor tests * Use id instead of custom element for amp-access-laterpay * Override pingback in amp-access-laterpay * Expose buildUrl in amp-access * Add tests for amp-access-laterpay * Simplify example page * Apply labels properly based on purchase type Also rename i18n keys for clarity. * Add readme for amp-access-laterpay * Typos, cleanup, linting * Add option for scrolling to top after auth * Add header/footer to amp-access-laterpay * Fix some default styling issues * Address PR feedback and update LaterPay description * Address more PR feedback fixes * Add validator info to amp-access-laterpay readme * Add types for missing config options * Add sandbox flag to LaterPay config options * Fix some linting and rules issues - add license to css file - rename property to avoid scrollTop check
* Early implementation of amp-access-laterpay * Remove unused amp-access-laterpay config params * Code cleanup issues from PR * Expose response in error object for assertSuccess * Further work on amp-access-laterpay - Remove unnecessary pingback skeleton - Add jsdoc annotations for existing code - Laterpay config retrieval based on draft spec - Improve rendering of the purchase overlay - Price formatting and localization * Expose adapter config on AccessService * Fix pingback detection in amp-access-vendor * Allow amp-access login flow with url only Create new methods loginWithType_ (similar to old login method) and loginWithUrl as entry points to old login method (now private). * Fix exposure of amp access vendor config * Add "already purchased" link * Add CSS for amp-access-laterpay * PR feedback fixes: - add private tag - ensure assert comes first * Add event label to loginWithUrl calls * Also check if we're on localdev mode * Fix amp-access login tests * Fix amp-access-vendor tests * Use id instead of custom element for amp-access-laterpay * Override pingback in amp-access-laterpay * Expose buildUrl in amp-access * Add tests for amp-access-laterpay * Simplify example page * Apply labels properly based on purchase type Also rename i18n keys for clarity. * Add readme for amp-access-laterpay * Typos, cleanup, linting * Add option for scrolling to top after auth * Add header/footer to amp-access-laterpay * Fix some default styling issues * Address PR feedback and update LaterPay description * Address more PR feedback fixes * Add validator info to amp-access-laterpay readme * Add types for missing config options * Add sandbox flag to LaterPay config options * Fix some linting and rules issues - add license to css file - rename property to avoid scrollTop check
This is the first attempt at an implementation for amp-access-laterpay.
(For anyone looking at this out of context, this comes as a follow up to some communication with @dvoytenko out of this repository and is based on some preparation work he did recently to allow for this implementation effort to occur)
This first implementation is mostly trying to get the basic workflow down, so no proper tests/docs/type hints yet (and could probably do with a WIP label 😄 )
Also, while I had quite a bit of a look at other modules, and some of the spec docs to get a better idea of the overall codebase patterns and existing methods and utilities I'm sure this still needs a bit of work in conforming to those. I'm adding some details below.
TODO
Layout creation
The current attempt at an implementation merely injects some DOM elements into an
amp-access-laterpay-listelement. Looking at the guidance here we could possibly ask the publisher to predefine a width/height for this to avoid reflows.In such a case I feel like having an overlay rather than an in page list would be more appropriate, but we don't have a strong need here for one particular case or the other (in page or overlay), we can go with what works best for performance/ux reasons.
I'd also like to better understand if I need to use any specific pattern when rendering the list into the DOM. I've noticed the use of the vsync module in multiple places but don't entirely understand if I should be making use of it in this case or not.
Opening the login window
At the moment the code which opens the login window is unfinished. The current
loginmethod in theaccessServicetakes as an argument atypewhich refers to the login type defined in the login configuration. Given that in this case we're getting the login urls from the service, I'd like to just pass that URL directly to the login method, given that I also don't wish to reimplement everything else the login method is doing, given that that is useful for our use case as well, and for handing back control toamp-access.My proposal would be to make some changes to the
loginmethod to take an URL instead and have the URL lookup happen before that method gets called (or as another code path inside of the method, but the previous solution sounds cleaner to me).What happens in cached pages?
At the moment, the configuration for our (LaterPay) service is defined in the module. While this shouldn't change in the future, in the case that it does it would probably mean that we'd have to publish a new version of this extension with a new configuration. In such a case we'd probably also advise our customers to make that update and follow the guidelines at https://developers.google.com/amp/cache/overview but given that we don't control the publisher page we can't ever be entirely sure if/when changes are properly made.
I was wondering if we should concern ourselves in any way with this potential situation for the case of this implementation and have any sort of fallback mechanism in case a user gets an out of date page trying to talk to a non existing authorization access point.