Skip to content

Commit

Permalink
amp-font extension + Font loader with promises! -
Browse files Browse the repository at this point in the history
  • Loading branch information
camelburrito committed Nov 11, 2015
1 parent bcaac9b commit ef040b6
Show file tree
Hide file tree
Showing 11 changed files with 1,000 additions and 1 deletion.
32 changes: 31 additions & 1 deletion examples/everything.amp.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,29 @@
display: block;
margin: 16px;
}
@font-face {
font-family: 'Comic AMP';
font-style: bold;
font-weight: 700;
src: url(fonts/ComicAMP.ttf) format('truetype');
}
.comic-amp-font-loaded .comic-amp {
font-family: 'Comic AMP', serif, sans-serif;
}

.comic-amp-font-loading .comic-amp {
color: #0ff;
}

.comic-amp-font-missing .comic-amp {
color: #f00;
}
</style>
<script async custom-element="amp-anim" src="https://cdn.ampproject.org/v0/amp-anim-0.1.js"></script>
<script async custom-element="amp-audio" src="https://cdn.ampproject.org/v0/amp-audio-0.1.js"></script>
<script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
<script async custom-element="amp-fit-text" src="https://cdn.ampproject.org/v0/amp-fit-text-0.1.js"></script>
<script async custom-element="amp-font" src="https://cdn.ampproject.org/v0/amp-font-0.1.js"></script>
<script async custom-element="amp-iframe" src="https://cdn.ampproject.org/v0/amp-iframe-0.1.js"></script>
<script async custom-element="amp-instagram" src="https://cdn.ampproject.org/v0/amp-instagram-0.1.js"></script>
<script async custom-element="amp-image-lightbox" src="https://cdn.ampproject.org/v0/amp-image-lightbox-0.1.js"></script>
Expand All @@ -79,13 +97,16 @@
<script async src="https://cdn.ampproject.org/v0.js"></script>
<script async src="./viewer-integr.js"></script>
</head>
<body>
<body class="comic-amp-font-loading">

<article>

<div class="logo"></div>

<h1 id="top">AMP #0</h1>
<p class="comic-amp">
Quisque ultricies id augue a convallis. Vivamus euismod est quis tellus laoreet lacinia. In quam tellus, mollis nec porta eget, volutpat sit amet nibh. Duis ac odio sem. Sed consequat, ante gravida fringilla suscipit, libero libero ullamcorper metus, nec porta est elit at est. Curabitur vel diam ligula. Nulla bibendum malesuada odio.
</p>
<p>
<amp-fit-text width="300" height="200" layout="responsive" class="box1">
Lorem ipsum dolor sit amet, has nisl nihil convenire et, vim at aeque inermis reprehendunt.
Expand Down Expand Up @@ -318,6 +339,15 @@ <h2>SVG</h2>
<div id="footer">The end. <a href="#top">Back to top.</a></div>

<amp-pixel src="https://pubads.g.doubleclick.net/activity;dc_iu=/12344/pixel;ord=$RANDOM?"></amp-pixel>
<amp-font
layout="nodisplay"
font-family="Comic Amp"
timeout="3000"
on-load-remove-class="comic-amp-font-loading"
on-error-remove-class="comic-amp-font-loading"
on-error-add-class="comic-amp-font-missing"
on-load-add-class="comic-amp-font-loaded">
</amp-font>
</article>
</body>
</html>
105 changes: 105 additions & 0 deletions examples/font.amp.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<!doctype html>
<html >
<head>
<meta charset="utf-8">
<title>Font example</title>
<link rel="canonical" href="amps.html" >
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<style amp-custom>
@font-face {
font-family: 'Comic AMP';
font-style: normal;
font-weight: 400;
src: url(fonts/ComicAMP.ttf) format('truetype');
}

@font-face {
font-family: 'Comic AMP Bold';
font-style: bold;
font-weight: 600;
src: url(fonts/ComicAMPBold.ttf) format('truetype');
}

.comic-amp-font-loaded {
font-family: 'Comic AMP', serif, sans-serif;
}

.comic-amp-bold-font-loaded .comic-amp-bold {
font-family: 'Comic AMP Bold', serif, sans-serif;
color: #000;
}

h1 {
font-size: 50px;
font-weight: bold;
}

p {
font-size: 20px;
font-weight: normal;
}

.comic-amp-font-loading {
color: #00f;
}

.comic-amp-bold-font-loading .comic-amp-bold {
color: #0ff;
}

.comic-amp-font-missing,
.comic-amp-bold-font-missing .comic-amp-bold {
color: #f00;
}
</style>
<script async custom-element="amp-font" src="https://cdn.ampproject.org/v0/amp-font-0.1.js"></script>
<style>body {opacity: 0}</style><noscript><style>body {opacity: 1}</style></noscript>
<script async src="https://cdn.ampproject.org/v0.js"></script>
</head>
<body class="comic-amp-font-loading comic-amp-bold-font-loading">

<h1> Lorem Ipsum </h1>

<h2 class="comic-amp-bold">amp-font</h2>

<p>
"Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..."
"There is no one who loves pain itself, who seeks after it and wants to have it, simply because it is pain..."
</p>
<p class="comic-amp-bold">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur gravida ipsum vel hendrerit ultricies. Sed bibendum erat sit amet dui mattis imperdiet. Duis feugiat lobortis neque nec accumsan. Nam lacinia placerat enim in cursus. Sed id gravida arcu, sed condimentum mauris. Vestibulum convallis risus ut est ultrices mollis. Curabitur sit amet lorem et leo maximus consectetur non aliquet risus. Pellentesque tempus malesuada eros quis convallis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi dolor risus, convallis eget bibendum at, auctor vel enim. Phasellus posuere dictum fermentum.
</p>
<p>
Quisque ultricies id augue a convallis. Vivamus euismod est quis tellus laoreet lacinia. In quam tellus, mollis nec porta eget, volutpat sit amet nibh. Duis ac odio sem. Sed consequat, ante gravida fringilla suscipit, libero libero ullamcorper metus, nec porta est elit at est. Curabitur vel diam ligula. Nulla bibendum malesuada odio.
</p>
<p class="comic-amp-bold">
Pellentesque ultricies quam diam, sit amet sollicitudin ante imperdiet a. Pellentesque porta semper nisi, et lobortis est laoreet ac. Vivamus pulvinar egestas purus, vitae pharetra nisl mattis at. Duis gravida ac quam vel commodo. Pellentesque dignissim luctus magna, a fermentum ligula porttitor non. Duis sodales interdum urna, eu viverra elit dapibus vitae. Sed aliquet magna non erat suscipit, vel elementum nisl lacinia. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In eu tempor purus. Cras non libero vehicula, finibus arcu eget, eleifend nulla. Vestibulum non sollicitudin turpis. Fusce condimentum posuere risus nec congue. Curabitur aliquam lorem dolor.
</p>
<p>
Sed mollis, justo ac volutpat gravida, nisl eros imperdiet massa, sed aliquam nulla odio in urna. Pellentesque eros urna, rutrum vel luctus id, ultrices a libero. Morbi ante justo, gravida et velit at, convallis tristique metus. Nam elementum luctus facilisis. Vestibulum nec augue dignissim, gravida odio nec, volutpat libero. Cras vitae sagittis tellus, sed tincidunt ipsum. Maecenas et mauris id nunc porttitor tempus sit amet at libero.
</p>
<p class="comic-amp-bold">
Aenean ullamcorper risus quam, molestie sodales lacus volutpat at. Nunc vulputate est ut faucibus faucibus. Proin posuere viverra vestibulum. Vestibulum pretium nunc ut euismod sollicitudin. Etiam ornare posuere libero. Vestibulum urna massa, viverra sed ullamcorper ac, hendrerit sed dui. Vestibulum interdum lectus tellus, ut consequat quam pulvinar vitae. Mauris porttitor nulla porta urna convallis accumsan. Curabitur eget ante in libero fringilla elementum. Curabitur tempus arcu massa, gravida tristique erat convallis vitae. Sed lacinia elit justo, eget mollis dui vehicula sit amet. Nunc dignissim condimentum nunc, id pulvinar purus mattis ut. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque lacinia nibh ac enim laoreet imperdiet.
</p>

<amp-font
layout="nodisplay"
font-family="Comic AMP"
timeout="2000"
on-error-remove-class="comic-amp-font-loading"
on-error-add-class="comic-amp-font-missing"
on-load-remove-class="comic-amp-font-loading"
on-load-add-class="comic-amp-font-loaded">
</amp-font>
<amp-font
layout="nodisplay"
font-family="Comic AMP Bold"
timeout="3000"
font-weight="bold"
on-error-remove-class="comic-amp-bold-font-loading"
on-error-add-class="comic-amp-bold-font-missing"
on-load-remove-class="comic-amp-bold-font-loading"
on-load-add-class="comic-amp-bold-font-loaded">
</amp-font>
</body>
</html>
Binary file added examples/fonts/ComicAMP.ttf
Binary file not shown.
Binary file added examples/fonts/ComicAMPBold.ttf
Binary file not shown.
197 changes: 197 additions & 0 deletions extensions/amp-font/0.1/amp-font.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/**
* Copyright 2015 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.
*/


/**
* @fileoverview Triggers and monitors loading of custom fonts on AMP pages.
* Example:
* <code>
* <amp-font
* font-family="My Font"
* timeout="3s"
* font-weight="bold"
* on-error-add-class="myfont2-missing"
* on-error-remove-class="myfont3-loaded"
* on-load-add-class="myfont2-loaded"
* on-load-remove-class="myfont1-loaded"
* layout="nodisplay">
* </amp-font>
* </code>
*
* the amp-font element's layout type is nodisplay.
*/

import {FontLoader} from './fontloader';
import {timer} from '../../../src/timer';
import * as style from '../../../src/style';

/** @private @const {number} */
const DEFAULT_TIMEOUT_ = 3000;

/** @private @const {string} */
const DEFAULT_WEIGHT_ = '400';

/** @private @const {string} */
const DEFAULT_VARIANT_ = 'normal';

/** @private @const {string} */
const DEFAULT_STYLE_ = 'normal';

/** @private @const {string} */
const DEFAULT_SIZE_ = 'medium';

/** @private @const {number}*/
/**
* https://output.jsbin.com/badore - is js bin experiment to test timeouts on
* various mobile devices. Loade the page and try refreshing it to serve the
* font from cache.
*
* Font load times (from the browser cache) documented as follows:
* Wifi
* iPhone6(iOs 9.1) - safari - 2ms ~ 14ms
* Windows phone(8.1 Update 2) - IE - 20ms ~ 46ms
* Nexus5 (Android 6.0.0) - Chrome(44.0.2403.133) - 24ms ~ 52ms
* Samsung Galaxy S4 (Android 4.4.2) - Default Browser - 7ms - 24ms
*
* LTE
* iPhone6(iOs 9.1) - safari - 6ms ~ 14ms
* Nexus5 (Android 6.0.0) - Chrome(46.0.2) - 46ms ~ 100ms
*/
const CACHED_FONT_LOAD_TIME_ = 100;


export class AmpFont extends AMP.BaseElement {


/** @override */
prerenderAllowed() {
return true;
}


/** @override */
buildCallback() {
/** @private @const {string} */
this.fontFamily_ = AMP.assert(this.element.getAttribute('font-family'),
'The font-family attribute is required for <amp-font> %s',
this.element);
/** @private @const {string} */
this.fontWeight_ =
this.element.getAttribute('font-weight') || DEFAULT_WEIGHT_;
/** @private @const {string} */
this.fontStyle_ =
this.element.getAttribute('font-style') || DEFAULT_STYLE_;
/** @private @const {string} */
this.fontVariant_ =
this.element.getAttribute('font-variant') || DEFAULT_VARIANT_;
/** @private @const {!Document} */
this.document_ = this.getWin().document;
/** @private @const {!Element} */
this.documentElement_ = this.document_.documentElement;
/** @private @const {!FontLoader} */
this.fontLoader_ = new FontLoader(this.getWin());
this.startLoad_();
}


/**
* Starts to download the font.
* @private
*/
startLoad_() {
/** @type FontConfig */
const fontConfig = {
style: this.fontStyle_,
variant: this.fontVariant_,
weight: this.fontWeight_,
size: DEFAULT_SIZE_,
family: this.fontFamily_
};
this.fontLoader_.load(fontConfig, this.getTimeout_()).then(() => {
this.onFontLoadSuccess_();
}).catch(error => {
this.onFontLoadError_();
throw error;
});
}


/**
* @private
*/
onFontLoadSuccess_() {
const addClassName = this.element.getAttribute('on-load-add-class');
const removeClassName =
this.element.getAttribute('on-load-remove-class');
this.onFontLoadFinish_(addClassName, removeClassName);
}


/**
* @private
*/
onFontLoadError_() {
const addClassName = this.element.getAttribute('on-error-add-class');
const removeClassName =
this.element.getAttribute('on-error-remove-class');
this.onFontLoadFinish_(addClassName, removeClassName);
}


/**
* @param {?string} addClassName css class to be added to the
* document-element.
* @param {?string} removeClassName css class to be removed from the
* document-element.
* @private
*/
onFontLoadFinish_(addClassName, removeClassName) {
if (addClassName) {
this.documentElement_.classList.add(addClassName);
}
if (removeClassName) {
this.documentElement_.classList.remove(removeClassName);
this.document_.body.classList.remove(removeClassName);
};
this.dispose_();
}


/**
* @private
*/
dispose_() {
this.fontLoader_ = null;
}


/**
* Computes and returns the time (in ms) to wait for font download.
* @returns {number} time (in ms) to wait for font download.
* @private
*/
getTimeout_() {
let timeoutInMs = parseInt(this.element.getAttribute('timeout'), 10);
timeoutInMs = isNaN(timeoutInMs) || timeoutInMs < 0 ?
DEFAULT_TIMEOUT_ : timeoutInMs;
timeoutInMs = Math.max(
(timeoutInMs - timer.timeSinceStart()), CACHED_FONT_LOAD_TIME_);
return timeoutInMs;
}
}


AMP.registerElement('amp-font', AmpFont);
Loading

0 comments on commit ef040b6

Please sign in to comment.