Skip to content

Commit

Permalink
✨ AoG: Add amp-viewer-assistance extension. (ampproject#20725)
Browse files Browse the repository at this point in the history
* 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
hellokoji authored and bramanudom committed Mar 22, 2019
1 parent 54770c1 commit 9a1a4e8
Show file tree
Hide file tree
Showing 8 changed files with 562 additions and 0 deletions.
2 changes: 2 additions & 0 deletions build-system/tasks/compile.js
Expand Up @@ -241,6 +241,8 @@ function compile(entryModuleFilenames, outputDir, outputFilename, options) {
'extensions/amp-consent/**/*.js',
// Needed to access AmpGeo type for service locator
'extensions/amp-geo/**/*.js',
// Needed for AmpViewerAssistanceService
'extensions/amp-viewer-assistance/**/*.js',
// Needed for AmpViewerIntegrationVariableService
'extensions/amp-viewer-integration/**/*.js',
'src/*.js',
Expand Down
2 changes: 2 additions & 0 deletions build-system/tasks/presubmit-checks.js
Expand Up @@ -180,6 +180,7 @@ const forbiddenTerms = {
'src/service/action-impl.js',
'extensions/amp-access/0.1/amp-access.js',
'extensions/amp-form/0.1/amp-form.js',
'extensions/amp-viewer-assistance/0.1/amp-viewer-assistance.js',
],
},
'installActivityService': {
Expand Down Expand Up @@ -416,6 +417,7 @@ const forbiddenTerms = {
'src/inabox/inabox-viewer.js',
'src/service/cid-impl.js',
'src/impression.js',
'extensions/amp-viewer-assistance/0.1/amp-viewer-assistance.js',
],
},
'eval\\(': {
Expand Down
1 change: 1 addition & 0 deletions bundles.config.js
Expand Up @@ -395,6 +395,7 @@ exports.extensionBundles = [
],
},
{name: 'amp-google-vrview-image', version: '0.1', type: TYPES.MISC},
{name: 'amp-viewer-assistance', version: '0.1', type: TYPES.MISC},
{
name: 'amp-viewer-integration',
version: '0.1',
Expand Down
190 changes: 190 additions & 0 deletions extensions/amp-viewer-assistance/0.1/amp-viewer-assistance.js
@@ -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_();
});
});

0 comments on commit 9a1a4e8

Please sign in to comment.