diff --git a/3p/ampcontext-integration.js b/3p/ampcontext-integration.js index fd4385e97140..5a517fd29b26 100644 --- a/3p/ampcontext-integration.js +++ b/3p/ampcontext-integration.js @@ -69,7 +69,8 @@ export class IntegrationAmpContext extends AbstractAmpContext { // available. return (this.embedType_ === 'facebook' || this.embedType_ === 'twitter' - || this.embedType_ == 'github'); + || this.embedType_ === 'github' + || this.embedType_ === 'mathml'); } /** @return {!Window} */ diff --git a/3p/integration.js b/3p/integration.js index 166ea162e9c5..9b6cc8472fdb 100644 --- a/3p/integration.js +++ b/3p/integration.js @@ -63,6 +63,7 @@ import {MessageType} from '../src/3p-frame-messaging'; // 3P - please keep in alphabetic order import {facebook} from './facebook'; import {github} from './github'; +import {mathml} from './mathml'; import {reddit} from './reddit'; import {twitter} from './twitter'; @@ -327,6 +328,7 @@ register('loka', loka); register('mads', mads); register('mantis-display', mantisDisplay); register('mantis-recommend', mantisRecommend); +register('mathml', mathml); register('mediaimpact', mediaimpact); register('medianet', medianet); register('mediavine', mediavine); diff --git a/3p/mathml.js b/3p/mathml.js new file mode 100644 index 000000000000..4b53b7d7abb7 --- /dev/null +++ b/3p/mathml.js @@ -0,0 +1,70 @@ +/** + * Copyright 2018 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 {writeScript} from './3p'; +import {user} from '../src/log'; + +/** + * Get the correct script for the mathml formula. + * + * Use writeScript: Failed to execute 'write' on 'Document': It isn't possible + * to write into a document from an asynchronously-loaded external script unless + * it is explicitly opened. + * + * @param {!Window} global + * @param {string} scriptSource The source of the script, different for post and comment embeds. + */ +function getMathmlJs(global, scriptSource, cb) { + writeScript(global, scriptSource, function() { + cb(global.MathJax); + }); +} + +/** + * @param {!Window} global + * @param {!Object} data + */ +export function mathml(global, data) { + user().assert( + data.formula, + 'The formula attribute is required for %s', + data.element); + + getMathmlJs( + global, + 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML', + mathjax => { + // Dimensions are given by the parent frame. + delete data.width; + delete data.height; + const div = document.createElement('div'); + div.setAttribute('id','mathmlformula'); + div.textContent = data.formula; + global.document.body.appendChild(div); + mathjax.Hub.Queue(function() { + const rendered = document.getElementById('MathJax-Element-1-Frame'); + // Remove built in mathjax margins. + const display = document.getElementsByClassName('MJXc-display'); + if (display[0]) { + display[0].setAttribute('style','margin-top:0;margin-bottom:0'); + context.requestResize( + rendered./*OK*/offsetWidth, + rendered./*OK*/offsetHeight + ); + } + }); + } + ); +} diff --git a/ads/ads.extern.js b/ads/ads.extern.js index df81451be5f8..1092dbbe4a57 100644 --- a/ads/ads.extern.js +++ b/ads/ads.extern.js @@ -49,6 +49,13 @@ data.src; //twitter.js data.tweetid +//mathml.js +data.formula +var mathjax +mathjax.Hub +mathjax.Hub.Queue +window.MathJax + // Under ads/google folder // adsense.js diff --git a/examples/amp-mathml.amp.html b/examples/amp-mathml.amp.html new file mode 100644 index 000000000000..26a0b6e9787a --- /dev/null +++ b/examples/amp-mathml.amp.html @@ -0,0 +1,31 @@ + + + + + amp-mathml example + + + + + + + +

The Quadratic Formula

+ + +

Cauchy's Integral Formula

+ + +

Double angle formula for Cosines

+ + +

Inline formula.

+ This is an example of a formula placed inline in the middle of a block of text. This shows how the formula will fit inside a block of text and can be styled with CSS. + + diff --git a/extensions/amp-mathml/0.1/amp-mathml.css b/extensions/amp-mathml/0.1/amp-mathml.css new file mode 100644 index 000000000000..3af74c01e39c --- /dev/null +++ b/extensions/amp-mathml/0.1/amp-mathml.css @@ -0,0 +1,27 @@ +/** + * Copyright 2018 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. + */ + +amp-mathml[inline] { + display: inline-block; +} + +amp-mathml { + height: 1px; +} + +amp-mathml[inline] { + width: 1px; +} diff --git a/extensions/amp-mathml/0.1/amp-mathml.js b/extensions/amp-mathml/0.1/amp-mathml.js new file mode 100644 index 000000000000..1867e173945c --- /dev/null +++ b/extensions/amp-mathml/0.1/amp-mathml.js @@ -0,0 +1,71 @@ +/** + * Copyright 2018 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 {Layout} from '../../../src/layout'; +import {getIframe} from '../../../src/3p-frame'; +import {removeElement} from '../../../src/dom'; +import {listenFor} from '../../../src/iframe-helper'; +import {CSS} from '../../../build/amp-mathml-0.1.css'; + +export class AmpMathml extends AMP.BaseElement { + + /** @param {!AmpElement} element */ + constructor(element) { + super(element); + + /** @private {?HTMLIFrameElement} */ + this.iframe_ = null; + } + + preconnectCallback() { + this.preconnect.url('https://cdnjs.cloudflare.com'); + } + + layoutCallback() { + const iframe = getIframe(this.win, this.element, 'mathml'); + this.applyFillContent(iframe); + // Triggered by context.updateDimensions() inside the iframe. + listenFor(iframe, 'embed-size', data => { + if (!this.element.hasAttribute('inline')) { + // Don't change the width if not inlined. + data['width'] = undefined; + } + this.element.getResources()./*OK*/changeSize( + this.element, data['height'], data['width']); + }, /* opt_is3P */true); + this.element.appendChild(iframe); + this.iframe_ = iframe; + return this.loadPromise(iframe); + } + + unlayoutCallback() { + if (this.iframe_) { + removeElement(this.iframe_); + this.iframe_ = null; + } + return true; + } + + /** @override */ + isLayoutSupported(layout) { + return layout == Layout.CONTAINER; + } + +} + + +AMP.extension('amp-mathml', '0.1', AMP => { + AMP.registerElement('amp-mathml', AmpMathml, CSS); +}); diff --git a/extensions/amp-mathml/OWNERS.yaml b/extensions/amp-mathml/OWNERS.yaml new file mode 100644 index 000000000000..c412bf2a6d87 --- /dev/null +++ b/extensions/amp-mathml/OWNERS.yaml @@ -0,0 +1 @@ +- adamsilverstein diff --git a/extensions/amp-mathml/amp-mathml.md b/extensions/amp-mathml/amp-mathml.md new file mode 100644 index 000000000000..0e157dcc18e4 --- /dev/null +++ b/extensions/amp-mathml/amp-mathml.md @@ -0,0 +1,72 @@ + + +# `amp-mathml` + + + + + + + + + + + + + + + + + + +
DescriptionDisplays a MathML formula.
Required Script<script async custom-element="amp-form" src="https://cdn.ampproject.org/v0/amp-mathml-0.1.js"></script>
Supported Layoutscontainer
ExamplesAnnotated code example for amp-mathml
+ +## Behavior + +This extension creates an iframe and renders a MathML formula. + +#### Example: The Quadratic Formula + +```html + + +``` + +#### Example: Cauchy's Integral Formula + +```html + + +``` +#### Example: Double angle formula for Cosines + +```html + + +``` +#### Example: Inline formula. + +This is an example of a formula placed inline in the middle of a block of text. `` This shows how the formula will fit inside a block of text and can be styled with CSS. + +## Attributes + +##### data-formula (required) + +The formula to render. + +## Validation +See [amp-mathml rules](https://github.com/ampproject/amphtml/blob/master/extensions/amp-mathml/validator-amp-mathml.protoascii) in the AMP validator specification. diff --git a/extensions/amp-mathml/validator-amp-mathml.protoascii b/extensions/amp-mathml/validator-amp-mathml.protoascii new file mode 100644 index 000000000000..bc0bd4e68c20 --- /dev/null +++ b/extensions/amp-mathml/validator-amp-mathml.protoascii @@ -0,0 +1,43 @@ +# +# Copyright 2018 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. +# + +tags: { # amp-mathml + html_format: AMP + tag_name: "SCRIPT" + extension_spec: { + name: "amp-html" + allowed_versions: "0.1" + allowed_versions: "latest" + } + attr_lists: "common-extension-attrs" +} + +tags: { # + html_format: AMP + tag_name: "AMP-MATHML" + requires_extension: "amp-mathml" + attrs: { + name: "formula" + mandatory: true + } + attrs: { + name: "inline" + } + attr_lists: "extended-amp-global" + amp_layout: { + supported_layouts: CONTAINER + } +} diff --git a/gulpfile.js b/gulpfile.js index b7d005279bea..b4f01e7c9d33 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -112,6 +112,7 @@ declareExtension('amp-lightbox', '0.1', true); declareExtension('amp-lightbox-viewer', '0.1', true); declareExtension('amp-list', '0.1', false); declareExtension('amp-live-list', '0.1', true); +declareExtension('amp-mathml', '0.1', true); declareExtension('amp-mustache', '0.1', false); declareExtension('amp-nexxtv-player', '0.1', false); declareExtension('amp-o2-player', '0.1', false);