diff --git a/build-system/tasks/presubmit-checks.js b/build-system/tasks/presubmit-checks.js index 0232c1355f20..139f70c2b107 100644 --- a/build-system/tasks/presubmit-checks.js +++ b/build-system/tasks/presubmit-checks.js @@ -517,6 +517,7 @@ var forbiddenTermsSrcInclusive = { message: bannedTermsHelpString, whitelist: [ 'src/element-stub.js', + 'src/friendly-iframe-embed.js', 'src/runtime.js', 'src/service/extensions-impl.js', 'src/service/lightbox-manager-discovery.js', @@ -546,6 +547,7 @@ var forbiddenTermsSrcInclusive = { whitelist: [ 'src/base-element.js', 'src/event-helper.js', + 'src/friendly-iframe-embed.js', 'src/service/performance-impl.js', 'src/service/url-replacements-impl.js', 'extensions/amp-ad/0.1/amp-ad-api-handler.js', diff --git a/src/custom-element.js b/src/custom-element.js index 4244537ae823..11214b2ca843 100644 --- a/src/custom-element.js +++ b/src/custom-element.js @@ -145,10 +145,7 @@ export function stubElements(win) { // If amp-ad and amp-embed haven't been registered, manually register them // with ElementStub, in case the script to the element is not included. if (!knownElements['amp-ad'] && !knownElements['amp-embed']) { - win.ampExtendedElements['amp-ad'] = true; - registerElement(win, 'amp-ad', ElementStub); - win.ampExtendedElements['amp-embed'] = true; - registerElement(win, 'amp-embed', ElementStub); + stubLegacyElements(win); } } const list = win.document.querySelectorAll('[custom-element]'); @@ -166,6 +163,16 @@ export function stubElements(win) { } } +/** + * @param {!Window} win + */ +function stubLegacyElements(win) { + win.ampExtendedElements['amp-ad'] = true; + registerElement(win, 'amp-ad', ElementStub); + win.ampExtendedElements['amp-embed'] = true; + registerElement(win, 'amp-embed', ElementStub); +} + /** * Stub element if not yet known. * @param {!Window} win @@ -182,6 +189,22 @@ export function stubElementIfNotKnown(win, name) { registerElement(win, name, ElementStub); } +/** + * Copies the specified element to child window (friendly iframe). This way + * all implementations of the AMP elements are shared between all friendly + * frames. + * @param {!Window} childWin + * @param {string} name + */ +export function copyElementToChildWindow(childWin, name) { + if (!childWin.ampExtendedElements) { + childWin.ampExtendedElements = {}; + stubLegacyElements(childWin); + } + childWin.ampExtendedElements[name] = true; + registerElement(childWin, name, knownElements[name] || ElementStub); +} + /** * Applies layout to the element. Visible for testing only. diff --git a/src/dom.js b/src/dom.js index 0bbf77f35478..b976c2c62b03 100644 --- a/src/dom.js +++ b/src/dom.js @@ -18,6 +18,16 @@ import {dev} from './log'; import {cssEscape} from '../third_party/css-escape/css-escape'; import {toArray} from './types'; +const HTML_ESCAPE_CHARS = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`', +}; +const HTML_ESCAPE_REGEX = /(&|<|>|"|'|`)/g; + /** * Waits until the child element is constructed. Once the child is found, the @@ -544,3 +554,24 @@ export function escapeCssSelectorIdent(win, ident) { // Polyfill. return cssEscape(ident); } + + +/** + * Escapes `<`, `>` and other HTML charcaters with their escaped forms. + * @param {string} text + * @return {string} + */ +export function escapeHtml(text) { + if (!text) { + return text; + } + return text.replace(HTML_ESCAPE_REGEX, escapeHtmlChar); +} + +/** + * @param {string} c + * @return string + */ +function escapeHtmlChar(c) { + return HTML_ESCAPE_CHARS[c]; +} diff --git a/src/friendly-iframe-embed.js b/src/friendly-iframe-embed.js new file mode 100644 index 000000000000..acf713f928de --- /dev/null +++ b/src/friendly-iframe-embed.js @@ -0,0 +1,223 @@ +/** + * Copyright 2016 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 {escapeHtml} from './dom'; +import {extensionsFor} from './extensions'; +import {getTopWindow} from './service'; +import {loadPromise} from './event-helper'; +import {resourcesForDoc} from './resources'; + + +/** + * Parameters used to create the new "friendly iframe" embed. + * - html: The complete content of an AMP embed, which is itself an AMP + * document. Can include whatever is normally allowed in an AMP document, + * except for AMP `