Skip to content

Commit

Permalink
Move parameters to ampdoc from viewer
Browse files Browse the repository at this point in the history
  • Loading branch information
dvoytenko committed Aug 9, 2019
1 parent d2f9bae commit 9cf89ed
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 214 deletions.
2 changes: 1 addition & 1 deletion src/inabox/amp-inabox.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ startupChunk(self.document, function initial() {
installInaboxCidService(ampdoc);
installViewerServiceForDoc(ampdoc);
installInaboxViewportService(ampdoc);
installAmpdocServices(ampdoc, undefined, true);
installAmpdocServices(ampdoc, /* inabox */ true);
// We need the core services (viewer/resources) to start instrumenting
perf.coreServicesAvailable();
doNotTrackImpression();
Expand Down
11 changes: 7 additions & 4 deletions src/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,13 +418,14 @@ export class MultidocManager {
* Attaches the shadow root and calls the supplied DOM builder.
* @param {!Element} hostElement
* @param {string} url
* @param {!Object<string, string>|undefined} initParams
* @param {!Object<string, string>|undefined} params
* @param {function(!Object, !ShadowRoot,
* !./service/ampdoc-impl.AmpDocShadow):!Promise} builder
* @return {!Object}
* @private
*/
attachShadowDoc_(hostElement, url, initParams, builder) {
attachShadowDoc_(hostElement, url, params, builder) {
params = params || Object.create(null);
this.purgeShadowRoots_();

setStyle(hostElement, 'visibility', 'hidden');
Expand All @@ -440,7 +441,9 @@ export class MultidocManager {
amp.url = url;
const {origin} = parseUrlDeprecated(url);

const ampdoc = this.ampdocService_.installShadowDoc(url, shadowRoot);
const ampdoc = this.ampdocService_.installShadowDoc(url, shadowRoot, {
params,
});
/** @const {!./service/ampdoc-impl.AmpDocShadow} */
amp.ampdoc = ampdoc;
dev().fine(TAG, 'Attach to shadow root:', shadowRoot, ampdoc);
Expand All @@ -453,7 +456,7 @@ export class MultidocManager {
/* opt_isRuntimeCss */ true
);
// Instal doc services.
installAmpdocServices(ampdoc, initParams || Object.create(null));
installAmpdocServices(ampdoc);

const viewer = Services.viewerForDoc(ampdoc);

Expand Down
50 changes: 44 additions & 6 deletions src/service/ampdoc-impl.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,19 @@ import {getParentWindowFrameElement, registerServiceBuilder} from '../service';
import {getShadowRootNode} from '../shadow-embed';
import {isDocumentReady, whenDocumentReady} from '../document-ready';
import {isExperimentOn} from '../experiments';
import {map} from '../utils/object';
import {parseQueryString} from '../url';
import {rootNodeFor, waitForBodyOpenPromise} from '../dom';

/** @const {string} */
const AMPDOC_PROP = '__AMPDOC';

/** @const {string} */
const PARAMS_SENTINEL = '__AMP__';

/**
* @typedef {{
* params: (!Object<string, string>|undefined),
* signals: (?Signals|undefined),
* }}
*/
Expand All @@ -47,15 +53,31 @@ export class AmpDocService {
/**
* @param {!Window} win
* @param {boolean} isSingleDoc
* @param {!Object<string, string>=} opt_initParams
*/
constructor(win, isSingleDoc) {
constructor(win, isSingleDoc, opt_initParams) {
/** @const {!Window} */
this.win = win;

/** @private {?AmpDoc} */
this.singleDoc_ = null;
if (isSingleDoc) {
this.singleDoc_ = new AmpDocSingle(win);
// Params can be passed via iframe hash/name with hash taking precedence.
const params = map();
if (opt_initParams) {
Object.assign(params, opt_initParams);
} else {
if (win.name && win.name.indexOf(PARAMS_SENTINEL) == 0) {
Object.assign(
params,
parseQueryString(win.name.substring(PARAMS_SENTINEL.length))
);
}
if (win.location.hash) {
Object.assign(params, parseQueryString(win.location.hash));
}
}
this.singleDoc_ = new AmpDocSingle(win, {params});
win.document[AMPDOC_PROP] = this.singleDoc_;
}

Expand Down Expand Up @@ -199,15 +221,16 @@ export class AmpDocService {
* Creates and installs the ampdoc for the shadow root.
* @param {string} url
* @param {!ShadowRoot} shadowRoot
* @param {!AmpDocOptions=} opt_options
* @return {!AmpDocShadow}
* @restricted
*/
installShadowDoc(url, shadowRoot) {
installShadowDoc(url, shadowRoot, opt_options) {
devAssert(
!shadowRoot[AMPDOC_PROP],
'The shadow root already contains ampdoc'
);
const ampdoc = new AmpDocShadow(this.win, url, shadowRoot);
const ampdoc = new AmpDocShadow(this.win, url, shadowRoot, opt_options);
shadowRoot[AMPDOC_PROP] = ampdoc;
return ampdoc;
}
Expand Down Expand Up @@ -254,6 +277,9 @@ export class AmpDoc {
/** @private @const */
this.signals_ = (opt_options && opt_options.signals) || new Signals();

/** @private {!Object<string, string>} */
this.params_ = (opt_options && opt_options.params) || map();

/** @private @const {!Array<string>} */
this.declaredExtensions_ = [];
}
Expand Down Expand Up @@ -294,6 +320,17 @@ export class AmpDoc {
return this.signals_;
}

/**
* Returns the value of a ampdoc's startup parameter with the specified
* name or `null` if the parameter wasn't defined at startup time.
* @param {string} name
* @return {?string}
*/
getParam(name) {
const v = this.params_[name];
return v == null ? null : v;
}

/**
* Returns whether the specified extension has been declared on this ampdoc.
* @param {string} extensionId
Expand Down Expand Up @@ -703,10 +740,11 @@ export class AmpDocFie extends AmpDoc {
* initial configuration.
* @param {!Window} win
* @param {boolean} isSingleDoc
* @param {!Object<string, string>=} opt_initParams
*/
export function installDocService(win, isSingleDoc) {
export function installDocService(win, isSingleDoc, opt_initParams) {
registerServiceBuilder(win, 'ampdoc', function() {
return new AmpDocService(win, isSingleDoc);
return new AmpDocService(win, isSingleDoc, opt_initParams);
});
}

Expand Down
5 changes: 2 additions & 3 deletions src/service/core-services.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,10 @@ export function installRuntimeServices(global) {
/**
* Install ampdoc-level services.
* @param {!./ampdoc-impl.AmpDoc} ampdoc
* @param {!Object<string, string>=} opt_initParams
* @param {boolean=} opt_inabox
* @restricted
*/
export function installAmpdocServices(ampdoc, opt_initParams, opt_inabox) {
export function installAmpdocServices(ampdoc, opt_inabox) {
const isEmbedded = !!ampdoc.getParent();

// Order is important!
Expand All @@ -92,7 +91,7 @@ export function installAmpdocServices(ampdoc, opt_initParams, opt_inabox) {
: installCidService(ampdoc);
isEmbedded
? adoptServiceForEmbedDoc(ampdoc, 'viewer')
: installViewerServiceForDoc(ampdoc, opt_initParams);
: installViewerServiceForDoc(ampdoc);
isEmbedded
? adoptServiceForEmbedDoc(ampdoc, 'viewport')
: installViewportServiceForDoc(ampdoc);
Expand Down
78 changes: 21 additions & 57 deletions src/service/viewer-impl.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import {startsWith} from '../string';
import {urls} from '../config';

const TAG_ = 'Viewer';
const SENTINEL_ = '__AMP__';

/** @enum {string} */
export const Capability = {
Expand Down Expand Up @@ -73,9 +72,8 @@ let RequestResponderDef;
export class Viewer {
/**
* @param {!./ampdoc-impl.AmpDoc} ampdoc
* @param {!Object<string, string>=} opt_initParams
*/
constructor(ampdoc, opt_initParams) {
constructor(ampdoc) {
/** @const {!./ampdoc-impl.AmpDoc} */
this.ampdoc = ampdoc;

Expand Down Expand Up @@ -138,15 +136,12 @@ export class Viewer {
*/
this.messageQueue_ = [];

/** @const @private {!Object<string, string>} */
this.params_ = {};

/**
* Subset of this.params_ that only contains parameters in the URL hash,
* e.g. "#foo=bar".
* @const @private {!Object<string, string>}
*/
this.hashParams_ = {};
this.hashParams_ = map();

/** @private {?Promise} */
this.nextVisiblePromise_ = null;
Expand All @@ -172,35 +167,23 @@ export class Viewer {
/** @private {?function()} */
this.whenFirstVisibleResolve_ = deferred.resolve;

// Params can be passed either directly in multi-doc environment or via
// iframe hash/name with hash taking precedence.
if (opt_initParams) {
Object.assign(this.params_, opt_initParams);
} else {
if (this.win.name && this.win.name.indexOf(SENTINEL_) == 0) {
parseParams_(this.win.name.substring(SENTINEL_.length), this.params_);
}
if (this.win.location.hash) {
parseParams_(this.win.location.hash, this.hashParams_);
Object.assign(this.params_, this.hashParams_);
}
if (ampdoc.isSingleDoc()) {
Object.assign(this.hashParams_, parseQueryString(this.win.location.hash));
}

dev().fine(TAG_, 'Viewer params:', this.params_);

this.isRuntimeOn_ = !parseInt(this.params_['off'], 10);
this.isRuntimeOn_ = !parseInt(ampdoc.getParam('off'), 10);
dev().fine(TAG_, '- runtimeOn:', this.isRuntimeOn_);

this.overtakeHistory_ = !!(
parseInt(this.params_['history'], 10) || this.overtakeHistory_
parseInt(ampdoc.getParam('history'), 10) || this.overtakeHistory_
);
dev().fine(TAG_, '- history:', this.overtakeHistory_);

this.setVisibilityState_(this.params_['visibilityState']);
this.setVisibilityState_(ampdoc.getParam('visibilityState'));
dev().fine(TAG_, '- visibilityState:', this.getVisibilityState());

this.prerenderSize_ =
parseInt(this.params_['prerenderSize'], 10) || this.prerenderSize_;
parseInt(ampdoc.getParam('prerenderSize'), 10) || this.prerenderSize_;
dev().fine(TAG_, '- prerenderSize:', this.prerenderSize_);

/**
Expand Down Expand Up @@ -240,19 +223,19 @@ export class Viewer {
/** @private {string} */
this.unconfirmedReferrerUrl_ =
this.isEmbedded() &&
'referrer' in this.params_ &&
ampdoc.getParam('referrer') != null &&
this.isTrustedAncestorOrigins_() !== false
? this.params_['referrer']
? ampdoc.getParam('referrer')
: this.win.document.referrer;

/** @const @private {!Promise<string>} */
this.referrerUrl_ = new Promise(resolve => {
if (this.isEmbedded() && 'referrer' in this.params_) {
if (this.isEmbedded() && ampdoc.getParam('referrer') != null) {
// Viewer override, but only for whitelisted viewers. Only allowed for
// iframed documents.
this.isTrustedViewer().then(isTrusted => {
if (isTrusted) {
resolve(this.params_['referrer']);
resolve(ampdoc.getParam('referrer'));
} else {
resolve(this.win.document.referrer);
if (this.unconfirmedReferrerUrl_ != this.win.document.referrer) {
Expand All @@ -278,7 +261,7 @@ export class Viewer {
/** @const @private {!Promise<string>} */
this.viewerUrl_ = new Promise(resolve => {
/** @const {string} */
const viewerUrlOverride = this.params_['viewerUrl'];
const viewerUrlOverride = ampdoc.getParam('viewerUrl');
if (this.isEmbedded() && viewerUrlOverride) {
// Viewer override, but only for whitelisted viewers. Only allowed for
// iframed documents.
Expand All @@ -303,7 +286,7 @@ export class Viewer {

// Remove hash when we have an incoming click tracking string
// (see impression.js).
if (this.params_['click']) {
if (this.hashParams_['click']) {
const newUrl = removeFragment(this.win.location.href);
if (newUrl != this.win.location.href && this.win.history.replaceState) {
// Persist the hash that we removed has location.originalHash.
Expand Down Expand Up @@ -352,8 +335,8 @@ export class Viewer {
// for visibilityState.
// After https://github.com/ampproject/amphtml/issues/6070
// is fixed we should probably only keep the amp_js_v check here.
(this.params_['origin'] ||
this.params_['visibilityState'] ||
(this.ampdoc.getParam('origin') ||
this.ampdoc.getParam('visibilityState') ||
// Parent asked for viewer JS. We must be embedded.
this.win.location.search.indexOf('amp_js_v') != -1)) ||
this.isWebviewEmbedded() ||
Expand Down Expand Up @@ -401,7 +384,7 @@ export class Viewer {
* @export
*/
getParam(name) {
return this.params_[name];
return this.ampdoc.getParam(name);
}

/**
Expand All @@ -411,7 +394,7 @@ export class Viewer {
* @return {boolean}
*/
hasCapability(name) {
const capabilities = this.params_['cap'];
const capabilities = this.ampdoc.getParam('cap');
if (!capabilities) {
return false;
}
Expand All @@ -432,7 +415,7 @@ export class Viewer {
* @return {boolean}
*/
isWebviewEmbedded() {
return !this.isIframed_ && this.params_['webview'] == '1';
return !this.isIframed_ && this.ampdoc.getParam('webview') == '1';
}

/**
Expand Down Expand Up @@ -1103,22 +1086,6 @@ export class Viewer {
}
}

/**
* Parses the viewer parameters as a string.
*
* Visible for testing only.
*
* @param {string} str
* @param {!Object<string, string>} allParams
* @private
*/
function parseParams_(str, allParams) {
const params = parseQueryString(str);
for (const k in params) {
allParams[k] = params[k];
}
}

/**
* Creates an error for the case where a channel cannot be established.
* @param {*=} opt_reason
Expand All @@ -1145,15 +1112,12 @@ export function setViewerVisibilityState(viewer, state) {

/**
* @param {!./ampdoc-impl.AmpDoc} ampdoc
* @param {!Object<string, string>=} opt_initParams
*/
export function installViewerServiceForDoc(ampdoc, opt_initParams) {
export function installViewerServiceForDoc(ampdoc) {
registerServiceBuilderForDoc(
ampdoc,
'viewer',
function() {
return new Viewer(ampdoc, opt_initParams);
},
Viewer,
/* opt_instantiate */ true
);
}
Loading

0 comments on commit 9cf89ed

Please sign in to comment.