forked from ampproject/amphtml
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ AoG: Add amp-viewer-assistance extension. (ampproject#20725)
* Add amp-viewer-assistance extension (ampproject#15195). Change-Id: I78dac3ec9f85c3bbd1ceb4ce88a61b3f7d0dc539 * Address PR comments 1. Change-Id: I874c096e75e9428872b6609df4acb75a82ee5b09 * remove amp-viewer-integration styles Change-Id: I6692ccec7eaccfce9227115c1ebca24b3a5fe118 * Fix javascript closure typing. Change-Id: I3d282f2571cc48e388ddd222676a23ed0d61b67b * Add copyright and license comments to amp-viewer-assistance files. Change-Id: I5335d7d63843800a88319d760504fef7caab4d4f * Remove newline. Change-Id: If066222b53ed7912140c1e526e231aca43d9a38c * Address PR comments 2. Change-Id: I1c06c45a2159fcb5286db2a36e168907073a77fa * Update amp-viewer-assistance documentation. Change-Id: I9031cc6930c18de3ca691f41274f868670b72c7a * Remove redundant amp-viewer-assistnace validator files. Change-Id: I5c3194a511b64321500025e59375f618ed4660a4 * Remove amp-viewer-assistance-unstrusted experiement from experiments.js. Change-Id: Ib20566f920d3c92da648d49dc7dd30fc78eb313f * Address amp-viewer-assistance presubmit errors. Change-Id: If962d4a174593b2eed997acfbc01844c0a3b0f72 * Lint. Change-Id: Icaf921248e6f5f7f096c43cde4688d28f4943545 * Fix types. Change-Id: I65dfc764cb7a1a226b6aac444392f5936b21478d * Add expectAsyncConsoleError to catch error message in test. Change-Id: I78849d7d82c98d3353b2a9ad5a1ed99d5c04e2d4
- Loading branch information
1 parent
54770c1
commit 9a1a4e8
Showing
8 changed files
with
562 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
190 changes: 190 additions & 0 deletions
190
extensions/amp-viewer-assistance/0.1/amp-viewer-assistance.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
/** | ||
* Copyright 2019 The AMP HTML Authors. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS-IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import {ActionTrust} from '../../../src/action-constants'; | ||
import {Services} from '../../../src/services'; | ||
import {dev, user} from '../../../src/log'; | ||
import {dict} from '../../../src/utils/object'; | ||
import {isExperimentOn} from '../../../src/experiments'; | ||
import {tryParseJson} from '../../../src/json'; | ||
|
||
|
||
/** @const {string} */ | ||
const TAG = 'amp-viewer-assistance'; | ||
|
||
/** @const {string} */ | ||
const GSI_TOKEN_PROVIDER = 'actions-on-google-gsi'; | ||
|
||
export class AmpViewerAssistance { | ||
/** | ||
* @param {!../../../src/service/ampdoc-impl.AmpDoc} ampdoc | ||
*/ | ||
constructor(ampdoc) { | ||
const assistanceElement = ampdoc.getElementById('amp-viewer-assistance'); | ||
|
||
/** @private {boolean} */ | ||
this.enabled_ = !!assistanceElement; | ||
if (!this.enabled_) { | ||
return; | ||
} | ||
|
||
/** @const @private */ | ||
this.ampdoc_ = ampdoc; | ||
|
||
/** @const @private {!Element} */ | ||
this.assistanceElement_ = dev().assertElement(assistanceElement); | ||
|
||
/** @const @private {JsonObject|null|undefined} */ | ||
this.configJson_ = tryParseJson(this.assistanceElement_.textContent, e => { | ||
throw user().createError( | ||
'Failed to parse "amp-viewer-assistance" JSON: ' + e); | ||
}); | ||
|
||
/** @private @const {!../../../src/service/viewer-impl.Viewer} */ | ||
this.viewer_ = Services.viewerForDoc(ampdoc); | ||
|
||
/** @private @const {!../../../src/service/action-impl.ActionService} */ | ||
this.action_ = Services.actionServiceForDoc(this.assistanceElement_); | ||
|
||
/** @private @const {!../../../src/service/vsync-impl.Vsync} */ | ||
this.vsync_ = Services.vsyncFor(ampdoc.win); | ||
} | ||
|
||
/** | ||
* @param {!../../../src/service/action-impl.ActionInvocation} invocation | ||
* @return {?Promise} | ||
* @private | ||
*/ | ||
actionHandler_(invocation) { | ||
const {method, args} = invocation; | ||
if (method == 'updateActionState' && !!args) { | ||
this.viewer_./*OK*/sendMessageAwaitResponse(method, args).catch(error => { | ||
user().error(TAG, error.toString()); | ||
}); | ||
} else if (method == 'signIn') { | ||
this.requestSignIn_(); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/** | ||
* @private | ||
* @restricted | ||
* @return {!AmpViewerAssistance|Promise<!AmpViewerAssistance>} | ||
*/ | ||
start_() { | ||
if (!this.enabled_) { | ||
user().error(TAG, 'Could not find #amp-viewer-assistance element.'); | ||
return this; | ||
} | ||
return this.viewer_.isTrustedViewer().then(isTrustedViewer => { | ||
if (!isTrustedViewer && | ||
!isExperimentOn(this.ampdoc_.win, 'amp-viewer-assistance-untrusted')) { | ||
this.enabled_ = false; | ||
user().error(TAG, | ||
'amp-viewer-assistance is currently only supported on trusted' | ||
+ ' viewers.'); | ||
return this; | ||
} | ||
this.action_.installActionHandler( | ||
this.assistanceElement_, this.actionHandler_.bind(this), | ||
ActionTrust.HIGH); | ||
|
||
this.getIdTokenPromise(); | ||
|
||
this.viewer_./*OK*/sendMessage('viewerAssistanceConfig',dict({ | ||
'config': this.configJson_, | ||
})); | ||
return this; | ||
}); | ||
} | ||
|
||
/** | ||
* @return {!Promise<undefined>} | ||
*/ | ||
getIdTokenPromise() { | ||
return this.viewer_./*OK*/sendMessageAwaitResponse('getAccessTokenPassive', | ||
dict({ | ||
// For now there's only 1 provider option, so we just hard code it | ||
'providers': [GSI_TOKEN_PROVIDER], | ||
})) | ||
.then(token => { | ||
this.setIdTokenStatus_(Boolean(!!token)); | ||
return token; | ||
}).catch(() => { | ||
this.setIdTokenStatus_(/*available=*/false); | ||
}); | ||
} | ||
|
||
/** | ||
* @private | ||
*/ | ||
requestSignIn_() { | ||
this.viewer_./*OK*/sendMessageAwaitResponse('requestSignIn', dict({ | ||
'providers': [GSI_TOKEN_PROVIDER], | ||
})).then(token => { | ||
user().info(TAG, 'Token: ' + token); | ||
if (token) { | ||
this.setIdTokenStatus_(/*available=*/true); | ||
this.action_.trigger( | ||
this.assistanceElement_, 'signedIn', null, ActionTrust.HIGH); | ||
} else { | ||
this.setIdTokenStatus_(/*available=*/false); | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Toggles the CSS classes related to the status of the identity token. | ||
* @private | ||
* @param {boolean} available | ||
*/ | ||
setIdTokenStatus_(available) { | ||
this.toggleTopClass_( | ||
'amp-viewer-assistance-identity-available', available); | ||
} | ||
|
||
/** | ||
* Gets the root element of the AMP doc. | ||
* @return {!Element} | ||
* @private | ||
*/ | ||
getRootElement_() { | ||
const root = this.ampdoc_.getRootNode(); | ||
return dev().assertElement(root.documentElement || root.body || root); | ||
} | ||
|
||
/** | ||
* Toggles a class on the root element of the AMP doc. | ||
* @param {string} className | ||
* @param {boolean} on | ||
* @private | ||
*/ | ||
toggleTopClass_(className, on) { | ||
this.vsync_.mutate(() => { | ||
this.getRootElement_().classList.toggle(className, on); | ||
}); | ||
|
||
} | ||
} | ||
|
||
// Register the extension services. | ||
AMP.extension(TAG, '0.1', function(AMP) { | ||
AMP.registerServiceForDoc('amp-viewer-assistance', function(ampdoc) { | ||
return new AmpViewerAssistance(ampdoc).start_(); | ||
}); | ||
}); |
Oops, something went wrong.