The following samples show you some of the ways that you can use the Notification API:
8 | ",
10 | "license": "Apache-2.0",
11 | "dependencies": {
12 | "express": "^4.14.0"
13 | },
14 | "engines": {
15 | "node": ">=6.5.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/mouseevent-get-modifier-state/demo.js:
--------------------------------------------------------------------------------
1 | // A subset of keys from https://w3c.github.io/uievents/#keys-modifiers
2 | var modifierKeys = ['Alt', 'Control', 'Meta', 'Shift', 'AltGraph'];
3 |
4 | document.querySelector('#output').addEventListener('mousemove', function(evt) {
5 | modifierKeys.forEach(function(modifierKey) {
6 | var pressed = evt.getModifierState(modifierKey);
7 | document.getElementById(modifierKey).style.fontWeight =
8 | pressed ? 'bold' : 'normal';
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/notifications/README.md:
--------------------------------------------------------------------------------
1 | Notification API Samples
2 | ===
3 |
4 | Samples for various Notification options
5 |
6 | vibrate
7 | ====
8 | [Live demo](https://googlechrome.github.io/samples/notifications/vibrate.html)
9 |
10 | Learn more at https://www.chromestatus.com/feature/5727996321202176
11 |
12 | requireInteraction
13 | ====
14 | [Live demo](https://googlechrome.github.io/samples/notifications/requireInteraction.html)
15 |
16 | Learn more at https://www.chromestatus.com/feature/5641440986136576
17 |
--------------------------------------------------------------------------------
/event-istrusted/demo.js:
--------------------------------------------------------------------------------
1 | var greenButton = document.querySelector('#greenButton');
2 | var redButton = document.querySelector('#redButton');
3 |
4 | greenButton.addEventListener('click', function(event) {
5 | if (event.isTrusted) {
6 | ChromeSamples.log('User clicked the green button. It is a trusted event.');
7 | } else {
8 | ChromeSamples.log('User did NOT click the green button.');
9 | }
10 | });
11 |
12 | redButton.addEventListener('click', function() {
13 | greenButton.click();
14 | });
15 |
--------------------------------------------------------------------------------
/fetch-api/fetch-post.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Fetch API POST
3 | chrome_version: 42
4 | feature_id: 6730533392351232
5 | ---
6 |
7 | Background
8 | This sample shows how the Fetch API can make POST requests.
9 |
10 |
14 |
15 |
16 | {% include output_helper.html %}
17 |
18 | {% include js_snippet.html filename='fetch-post-demo.js' %}
19 |
--------------------------------------------------------------------------------
/media/playback-rate-exception.js:
--------------------------------------------------------------------------------
1 | const audio = document.querySelector('audio');
2 |
3 | function onButtonClick(event) {
4 | const text = event.target.textContent;
5 | const playbackRate = Number(/playbackRate = (-?\d+([/.]\d+)?)/.exec(text)[1]);
6 |
7 | try {
8 | audio.playbackRate = playbackRate;
9 | } catch(error) {
10 | log('> Error: ' + error.message);
11 | }
12 | }
13 |
14 | audio.addEventListener('ratechange', function(event) {
15 | log('> Playback rate changed to ' + event.target.playbackRate);
16 | });
17 |
18 |
--------------------------------------------------------------------------------
/proxies-es6/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Proxies (ES2015)
3 | chrome_version: 49
4 | feature_id: 4811188005240832
5 | ---
6 |
7 | Background
8 | ES2015 Proxies enable creation of objects with the full range of behaviors available to host objects. They can be used for interception, object virtualization and logging/profiling.
9 |
10 | {% include output_helper.html %}
11 |
12 | {% include js_snippet.html filename='demo.js' %}
13 |
--------------------------------------------------------------------------------
/web-bluetooth/availability-async-await.js:
--------------------------------------------------------------------------------
1 | (async () => {
2 | try {
3 | const isBluetoothAvailable = await navigator.bluetooth.getAvailability();
4 | log(`> Bluetooth is ${isBluetoothAvailable ? 'available' : 'unavailable'}`);
5 | } catch(error) {
6 | log('Argh! ' + error);
7 | }
8 | })();
9 |
10 | if ('onavailabilitychanged' in navigator.bluetooth) {
11 | navigator.bluetooth.addEventListener('availabilitychanged', function(event) {
12 | log(`> Bluetooth is ${event.value ? 'available' : 'unavailable'}`);
13 | });
14 | }
--------------------------------------------------------------------------------
/media/color-gamut-media-query.js:
--------------------------------------------------------------------------------
1 | if (window.matchMedia("(color-gamut: srgb)").matches) {
2 | log(`Screen supports approximately the sRGB gamut or more.`);
3 | }
4 |
5 | if (window.matchMedia("(color-gamut: p3)").matches) {
6 | log(`Screen supports approximately the gamut specified
7 | by the DCI P3 Color Space or more.`);
8 | }
9 |
10 | if (window.matchMedia("(color-gamut: rec2020)").matches) {
11 | log(`Screen supports approximately the gamut specified
12 | by the ITU-R Recommendation BT.2020 Color Space or more.`);
13 | }
14 |
--------------------------------------------------------------------------------
/app-install-banner/cancelable-banner/readme.md:
--------------------------------------------------------------------------------
1 | Cancelable App Install Banner Sample
2 | ===
3 |
4 | See https://googlechrome.github.io/samples/app-install-banner/cancelable-banner/index.html for a live demo.
5 |
6 |
7 | #### Directions:
8 |
9 | * Install Chrome, or another browser that supports Service Workers and manifest
10 | * Visit the site over several minutes.
11 | * Or, more usefully, enable chrome://flags/#bypass-app-banner-engagement-checks
12 |
13 | On the second vist, you will see a message on the page that says the event was cancelled.
14 |
--------------------------------------------------------------------------------
/service-worker/windowclient-navigate/service-worker.js:
--------------------------------------------------------------------------------
1 | self.addEventListener('activate', event => {
2 | event.waitUntil(self.clients.claim().then(() => {
3 | // See https://developer.mozilla.org/en-US/docs/Web/API/Clients/matchAll
4 | return self.clients.matchAll({type: 'window'});
5 | }).then(clients => {
6 | return clients.map(client => {
7 | // Check to make sure WindowClient.navigate() is supported.
8 | if ('navigate' in client) {
9 | return client.navigate('activated.html');
10 | }
11 | });
12 | }));
13 | });
14 |
--------------------------------------------------------------------------------
/dialog/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: dialog Element
3 | chrome_version: 37
4 | feature_id: 5770237022568448
5 | ---
6 |
7 | {% capture html %}
8 |
9 | This button will open a native dialog element:
10 |
11 |
12 |
13 |
18 | {% endcapture %}
19 | {% include html_snippet.html html=html %}
20 |
21 | {% include js_snippet.html filename='demo.js' %}
22 |
--------------------------------------------------------------------------------
/fetch-api/fetch-success-error-handlers.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Fetch API Response Handlers
3 | chrome_version: 42
4 | feature_id: 6730533392351232
5 | ---
6 |
7 | Background
8 |
9 | This sample shows how the Promise returned by the Fetch API can be handled to
10 | deal with both successful and error responses.
11 |
12 |
13 | {% include output_helper.html %}
14 |
15 | {% include js_snippet.html filename='fetch-success-error-handlers-demo.js' %}
16 |
--------------------------------------------------------------------------------
/image-capture/update-camera-zoom.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Image Capture / Update Camera Zoom
3 | chrome_version: 87
4 | feature_id: 5570717087170560
5 | local_css_files: ['update-camera-zoom.css']
6 | check_min_version: true
7 | index: index.html
8 | ---
9 |
10 | Background
11 | The ImageCapture Web API allows web developers to change the zoom setting of
12 | the camera.
13 |
14 |
15 |
16 |
17 | {% include output_helper.html %}
18 |
19 | {% include js_snippet.html filename='update-camera-zoom.js' %}
20 |
--------------------------------------------------------------------------------
/web-share/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Scrapbook PWA
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app-install-banner/useraction-banner/readme.md:
--------------------------------------------------------------------------------
1 | App Install Banner User Response Sample
2 | ===
3 |
4 | See https://googlechrome.github.io/samples/app-install-banner/useraction-banner/index.html for a live demo.
5 |
6 |
7 | #### Directions:
8 |
9 | * Install Chrome, or another browser that supports Service Workers and manifest
10 | * Visit the site over several minutes.
11 | * Or, more usefully, enable chrome://flags/#bypass-app-banner-engagement-checks
12 |
13 | On the second vist, you will see a message on the page that says the user either installed the app or dismissed the banner.
14 |
--------------------------------------------------------------------------------
/cut-and-copy/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Cut and Copy
3 | chrome_version: 43
4 | feature_id: 5223997243392000
5 | ---
6 |
7 | Simple Cut Example
8 |
9 |
10 |
11 | Simple Copy Example
12 | Email me at matt@example.co.uk
13 |
14 |
15 | {% include output_helper.html %}
16 |
17 | {% include js_snippet.html filename='demo.js' %}
18 |
--------------------------------------------------------------------------------
/image-capture/grab-frame-take-photo.css:
--------------------------------------------------------------------------------
1 | #results {
2 | display: flex;
3 | align-items: center;
4 | justify-content: center;
5 | }
6 |
7 | #results > div {
8 | width: 33%;
9 | text-align: center;
10 | line-height: 24px;
11 | }
12 |
13 | @media (max-width: 814px) {
14 |
15 | #results {
16 | flex-flow: column;
17 | }
18 |
19 | #results > div {
20 | width: 100%;
21 | margin-bottom: 24px;
22 | }
23 |
24 | }
25 |
26 | video, canvas {
27 | object-fit: contain;
28 | border: 2px solid rgba(255, 255, 255, 1);
29 | background: #263238;
30 | height: 198px;
31 | width: 100%;
32 | }
33 |
--------------------------------------------------------------------------------
/extended-object-literals-es6/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Extended Object Literals (ES6)
3 | chrome_version: 42
4 | feature_id: 4873630588600320
5 | ---
6 |
7 | Background
8 |
9 | Extended Object Literals simplify object creation and composition by reducing the required amount
10 | of typing with some syntactic sugar.
11 |
12 |
13 | With this, object literals are now syntactically similar to ES6’s new class syntax and have less
14 | duplication in common use-cases like constructor function.
15 |
16 |
17 | {% include output_helper.html %}
18 |
19 | {% include js_snippet.html filename='demo.js' %}
20 |
--------------------------------------------------------------------------------
/object-assign-es6/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: ES6 Object.assign()
3 | chrome_version: 45
4 | feature_id: REPLACE_ME
5 | ---
6 |
7 | Background
8 | Object.assign() copies the values (of all enumerable own properties) from one or more source objects to a target object. It has a signature of Object.assign(target, ...sources). The target object is the first parameter and is also used as the return value. Object.assign() is useful for merging objects or cloning them shallowly.
9 |
10 | {% include output_helper.html %}
11 |
12 | {% include js_snippet.html filename='demo.js' %}
13 |
--------------------------------------------------------------------------------
/intrinsic-size/unsized.html:
--------------------------------------------------------------------------------
1 |
2 |

3 |
4 |
5 |
6 |
7 |
10 |
17 |
--------------------------------------------------------------------------------
/arrows-es6/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: ES6 Arrow functions
3 | chrome_version: 45
4 | feature_id: 5047308127305728
5 | ---
6 |
7 | Background
8 |
9 | ES6 fat arrow functions have a shorter syntax compared to
10 | function expressions and lexically bind the this value. Arrow functions are always anonymous and effectively turn
11 | function (arguments) { expression } into arguments => expression. If using an expression after an arrow, the return is implicit, so no return is required.
12 |
13 | {% include output_helper.html %}
14 |
15 | {% include js_snippet.html filename='demo.js' %}
16 |
--------------------------------------------------------------------------------
/intrinsic-size/sized.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
7 |
8 |
11 |
18 |
--------------------------------------------------------------------------------
/media/color-gamut-media-query.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: color-gamut Media Query
3 | chrome_version: 58
4 | feature_id: 5354410980933632
5 | check_min_version: true
6 | ---
7 |
8 | Background
9 | As wide color gamut screens are more and more popular, sites can now access
10 | the approximate range of colors supported by Chrome and output devices using
11 | the color-gamut Media Query.
12 |
13 |
14 | {% include output_helper.html initial_output_content=initial_output_content %}
15 |
16 |
19 |
20 | {% include js_snippet.html filename='color-gamut-media-query.js' %}
21 |
22 |
--------------------------------------------------------------------------------
/array-includes-es7/demo.js:
--------------------------------------------------------------------------------
1 | var basketOfApples = ['🍎', '🍏', '🍎', '🍏', '🌰', '🍎', '🍏'];
2 | if (basketOfApples.includes('🌰')) {
3 | ChromeSamples.log('Your basket of apples contains a chestnut.');
4 | }
5 | // The old way still "works"...
6 | if (basketOfApples.indexOf('🌰') !== -1) {
7 | ChromeSamples.log('Your basket of apples contains a chestnut.');
8 | }
9 |
10 | var buildingInFire = [' ', ' ', '🔥', '🔥', '🔥', ' '];
11 | if (buildingInFire.includes('🔥', 3)) {
12 | ChromeSamples.log('A fire is burning after the 3rd floor.');
13 | }
14 | if (buildingInFire.includes('🔥', -2)) {
15 | ChromeSamples.log('A fire is burning in the last 2 floors.');
16 | }
17 |
--------------------------------------------------------------------------------
/web-bluetooth/availability.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Web Bluetooth / Availability
3 | chrome_version: 78
4 | check_min_version: true
5 | feature_id: 6229592081694720
6 | icon_url: icon.png
7 | index: index.html
8 | ---
9 |
10 | {% include_relative _includes/intro.html %}
11 |
12 | This sample illustrates the use of the Web Bluetooth API to determine whether
13 | Bluetooth is available. You may want to check out the Availability (Async Await) sample.
15 |
16 | {% include output_helper.html %}
17 |
18 | {% include_relative _includes/utils.html %}
19 |
20 | {% include js_snippet.html filename='availability.js' %}
21 |
--------------------------------------------------------------------------------
/media/opus-in-mp4-for-mse.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Opus in ISO-BMFF with MSE
3 | chrome_version: 70
4 | feature_id: 5100845653819392
5 | check_min_version: true
6 | ---
7 |
8 | Background
9 |
10 | Opus is an audio codec already supported in regular Chrome HTML5 playback.
11 | Support for Opus in ISO-BMFF in Chrome HTML5 Media Source Extensions (MSE) is
12 | now added in Chrome 70.
13 |
14 |
15 |
16 |
17 | {% include output_helper.html initial_output_content=initial_output_content %}
18 |
19 |
22 |
23 | {% include js_snippet.html filename='opus-in-mp4-for-mse.js' %}
24 |
--------------------------------------------------------------------------------
/media/flac-in-mp4-for-mse.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: FLAC in ISO-BMFF with MSE
3 | chrome_version: 62
4 | feature_id: 5713014258925568
5 | check_min_version: true
6 | ---
7 |
8 | Background
9 |
10 | FLAC is a lossless audio coding format, already supported in regular Chrome
11 | HTML5 playback. Support for FLAC in ISO-BMFF to Chrome HTML5 Media Source
12 | Extensions (MSE) is added in Chrome 62.
13 |
14 |
15 |
16 |
17 | {% include output_helper.html initial_output_content=initial_output_content %}
18 |
19 |
22 |
23 | {% include js_snippet.html filename='flac-in-mp4-for-mse.js' %}
24 |
25 |
--------------------------------------------------------------------------------
/web-bluetooth/availability-async-await.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Web Bluetooth / Availability (Async Await)
3 | chrome_version: 78
4 | check_min_version: true
5 | feature_id: 6229592081694720
6 | icon_url: icon.png
7 | index: index.html
8 | ---
9 |
10 | {% include_relative _includes/intro.html %}
11 |
12 | This sample illustrates the use of the Web Bluetooth API to determine whether
13 | Bluetooth is available. You may want to check out the Availability (Promises) sample.
15 |
16 | {% include output_helper.html %}
17 |
18 | {% include_relative _includes/utils.html %}
19 |
20 | {% include js_snippet.html filename='availability-async-await.js' %}
21 |
--------------------------------------------------------------------------------
/media-session/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | title: Media Session Samples
3 | feature_name: Media Session
4 | chrome_version: 57
5 | feature_id: 5639924124483584
6 | ---
7 |
8 | The following samples show you some of the ways that you can use the Media
9 | Session API.
10 |
11 | Samples
12 |
13 | Audio - control playback of an audio playlist.
14 | Video - control playback of a video playlist.
15 | Video Conferencing - handle video conferencing actions in a Picture-in-Picture window.
16 | Slides - handle presenting slides actions in a Picture-in-Picture window.
17 |
--------------------------------------------------------------------------------
/paymentrequest/payment-handler/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Payment Handler API
3 | chrome_version: 68
4 | feature_id: 5160285237149696
5 | ---
6 |
7 | Background
8 |
9 | PaymentRequest lets
10 | you accept payment from different payment methods.
11 |
12 |
13 |
14 | This sample accepts the URL-based payment method.
15 |
16 |
17 | {% capture initial_output_content %}
18 |
19 |
20 | {% endcapture %}
21 | {% include output_helper.html initial_output_content=initial_output_content %}
22 |
23 | {% include js_snippet.html filename='demo.js' %}
24 |
--------------------------------------------------------------------------------
/_includes/js_snippet.html:
--------------------------------------------------------------------------------
1 | {% if include.filename or include.js %}
2 | {% unless include.displayonly %}
3 | {% if include.filename %}
4 |
5 | {% else %}
6 |
7 | {% endif %}
8 | {% endunless %}
9 |
10 | {% if include.title == null %}
11 | JavaScript Snippet
12 | {% elsif include.title != "" %}
13 | {{include.title}}
14 | {% endif %}
15 |
16 | {% if include.filename %}
17 | {% highlight js %}{% include_relative {{include.filename}} %}{% endhighlight %}
18 | {% else %}
19 | {% highlight js %}{{include.js}}{% endhighlight %}
20 | {% endif %}
21 | {% endif %}
22 |
--------------------------------------------------------------------------------
/intrinsic-size/width_only.html:
--------------------------------------------------------------------------------
1 |
2 |

3 |
4 |
5 |
6 |
7 |
10 |
17 |
--------------------------------------------------------------------------------
/fetch-api/fetch-reddit.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Fetch API Reddit
3 | chrome_version: 42
4 | feature_id: 6730533392351232
5 | ---
6 |
7 |
12 |
13 | Background
14 |
15 | This is an example of fetching some data (Reddit subreddits) which is then used to
16 | populate a menu allowing a user to make another fetch (for the subreddit content).
17 |
18 |
19 | {% capture initial_output_content %}
20 |
21 |
22 | {% endcapture %}
23 | {% include output_helper.html initial_output_content=initial_output_content %}
24 |
25 | {% include js_snippet.html filename='fetch-reddit-demo.js' %}
26 |
--------------------------------------------------------------------------------
/play-return-promise/demo.js:
--------------------------------------------------------------------------------
1 | function startPlayback() {
2 | return document.querySelector('#music').play();
3 | }
4 |
5 | ChromeSamples.log('Attempting to play automatically...');
6 |
7 | startPlayback().then(function() {
8 | ChromeSamples.log('The play() Promise fulfilled! Rock on!');
9 | }).catch(function(error) {
10 | ChromeSamples.log('The play() Promise rejected!');
11 | ChromeSamples.log('Use the Play button instead.');
12 | ChromeSamples.log(error);
13 |
14 | var playButton = document.querySelector('#play');
15 | // The user interaction requirement is met if
16 | // playback is triggered via a click event.
17 | playButton.addEventListener('click', startPlayback);
18 | playButton.hidden = false;
19 | });
20 |
--------------------------------------------------------------------------------
/destructuring-es6/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Destructuring (ES2015)
3 | chrome_version: 49
4 | feature_id: 4588790303686656
5 | ---
6 |
7 | Background
8 | Destructuring assignment allows extracting data from arrays or objects using a syntax that mirrors array and object literals.
9 |
10 | The object and array literal expressions provide an easy way to create ad hoc packages of data. Once you've created these packages of data, you can use them any way you want to. You can even return them from functions.
11 |
12 | {% include output_helper.html %}
13 |
14 | {% include js_snippet.html filename='demo.js' %}
15 |
--------------------------------------------------------------------------------
/image-capture/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | title: Image Capture Samples
3 | feature_name: MediaStream Image Capture
4 | chrome_version: 59
5 | feature_id: 4843864737185792
6 | ---
7 |
8 | The following samples show you some of the ways that you can use the Image
9 | Capture API.
10 |
11 | Samples
12 |
13 | Grab Frame - Take Photo - capture images in the form of a Blob or as an ImageBitmap.
14 | Update Camera Zoom - change the zoom setting of the camera.
15 | Photo Resolution - set the image width of the photo.
16 | Background Blur - control camera background blur.
17 |
--------------------------------------------------------------------------------
/paymentrequest/google-pay/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: PaymentRequest Google Pay
3 | chrome_version: 53
4 | feature_id: 5639348045217792
5 | ---
6 |
7 | Background
8 |
9 | PaymentRequest lets
10 | you accept payment from different payment methods.
11 |
12 |
13 |
14 | This sample accepts Google Pay payments and does not request shipping
15 | information.
16 |
17 |
18 | {% capture initial_output_content %}
19 |
20 |
21 | {% endcapture %}
22 | {% include output_helper.html initial_output_content=initial_output_content %}
23 |
24 | {% include js_snippet.html filename='demo.js' %}
25 |
--------------------------------------------------------------------------------
/collections-iterators-es6/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Collections and Iterators (ES6)
3 | chrome_version: 38
4 | feature_id: 4696563918045184
5 | ---
6 |
7 | Background
8 |
9 |
10 | There are several new types of collections and ways of iterating over collections in the
11 | draft ECMAScript 6 specification.
12 |
13 |
14 |
15 | This sample demonstrates creating and working with two types of collections, Set
16 | and Map. It also demonstrates using the for...of syntax to iterate over
17 | each type of collection.
18 |
19 |
20 | {% include output_helper.html %}
21 |
22 | {% include js_snippet.html filename='demo.js' %}
23 |
--------------------------------------------------------------------------------
/vibration/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Vibration API
3 | chrome_version: 32
4 | feature_id: 5698768766763008
5 | ---
6 |
7 | You can control the vibration capability of your device using the Vibration API. Chrome only supports this feature on Android devices.
8 |
9 | {% include js_snippet.html filename='demo1.js' %}
10 |
11 |
12 | {% include js_snippet.html filename='demo2.js' %}
13 |
14 |
15 | {% include js_snippet.html filename='demo3.js' %}
16 |
17 |
18 | {% include js_snippet.html filename='demo4.js' %}
19 |
20 |
--------------------------------------------------------------------------------
/decorators-es7/read-write/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "es7-decorator",
3 | "version": "0.0.1",
4 | "private": true,
5 | "engines": {
6 | "node": ">=0.10.0"
7 | },
8 | "devDependencies": {
9 | "gulp": "^3.8.11",
10 | "browserify": "^9.0.8",
11 | "watchify": "^3.1.1",
12 | "gulp-watchify": "^0.5.0",
13 | "vinyl-source-stream": "^1.1.0",
14 | "vinyl-buffer": "^1.0.0",
15 | "gulp-util": "^3.0.4",
16 | "lodash.assign": "^3.1.0",
17 | "babelify": "^6.0.2",
18 | "gulp-watch": "^4.2.4",
19 | "gulp-minify-css": "^1.1.0",
20 | "gulp-uglify": "^1.2.0",
21 | "gulp-rename": "^1.2.2",
22 | "gulp-sass": "^1.3.3",
23 | "gulp-streamify": "0.0.5",
24 | "del": "^1.1.1",
25 | "run-sequence": "^1.1.0"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/paymentrequest/free-shipping/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: PaymentRequest Free Shipping
3 | chrome_version: 53
4 | feature_id: 5639348045217792
5 | ---
6 |
7 | Background
8 |
9 | PaymentRequest lets
10 | you accept payment from different payment methods.
11 |
12 |
13 |
14 | This sample accepts BobBucks and provides
15 | free shipping worldwide.
16 |
17 |
18 | {% capture initial_output_content %}
19 |
20 |
21 | {% endcapture %}
22 | {% include output_helper.html initial_output_content=initial_output_content %}
23 |
24 | {% include js_snippet.html filename='demo.js' %}
25 |
--------------------------------------------------------------------------------
/push-messaging-and-notifications/demo.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function Debug() {
4 |
5 | }
6 |
7 | Debug.prototype.log = function() {
8 | var paragraphElement = document.createElement('p');
9 | paragraphElement.textContent = Array.prototype.join.call(arguments, '');
10 | document.querySelector('.js-log').appendChild(paragraphElement);
11 | };
12 |
13 | window.addEventListener('load', function() {
14 | var logDiv = document.createElement('div');
15 | logDiv.classList.add('js-log');
16 |
17 | var heading = document.createElement('h2');
18 | heading.textContent = 'Log';
19 | logDiv.appendChild(heading);
20 |
21 | document.body.appendChild(logDiv);
22 |
23 | window.Demo = window.Demo || {};
24 | window.Demo.debug = window.Demo.debug || new Debug();
25 | });
26 |
--------------------------------------------------------------------------------
/input-device-capabilities/demo.js:
--------------------------------------------------------------------------------
1 | function uiEventHandler(event) {
2 | if (event.type === 'mousedown' && event.sourceCapabilities.firesTouchEvents) {
3 | // If this is a "fake" mousedown event synthesized when tapping on a touchscreen, ignore it.
4 | return;
5 | }
6 |
7 | var status = 'The device that triggered this ' + event.type + ' event ' +
8 | (event.sourceCapabilities.firesTouchEvents ? 'does' : 'does not') +
9 | ' fire touch events.';
10 | ChromeSamples.setStatus(status);
11 |
12 | // At this point, you might do something like set a "pressed" style on the button, etc.
13 | }
14 |
15 | var button = document.querySelector('#press-me');
16 | button.addEventListener('mousedown', uiEventHandler);
17 | button.addEventListener('touchstart', uiEventHandler);
18 |
--------------------------------------------------------------------------------
/service-worker/foreign-fetch/foreign-fetch-sw.js:
--------------------------------------------------------------------------------
1 | // This is deployed to https://foreign-fetch-demo.appspot.com/foreign-fetch-sw.js
2 |
3 | self.addEventListener('install', event => {
4 | event.registerForeignFetch({
5 | scopes: ['/random'], // or self.registration.scope to handle everything
6 | origins: ['*'] // or ['https://example.com'] to limit the remote origins
7 | });
8 | });
9 |
10 | self.addEventListener('foreignfetch', event => {
11 | event.respondWith(
12 | fetch(event.request) // Try to make a network request
13 | .catch(() => new Response('34')) // Offline? Your random number is 34!
14 | .then(response => {
15 | return {
16 | response,
17 | origin: event.origin // Make this a CORS response
18 | };
19 | })
20 | );
21 | });
22 |
--------------------------------------------------------------------------------
/default-parameters-es6/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Default parameters (ES2015)
3 | chrome_version: 49
4 | feature_id: 5275456790069248
5 | ---
6 |
7 | Background
8 |
9 | Default parameters allow formal function parameters to be initialized with default values if no value (or undefined) is supplied.
10 |
11 | In ES5, one would test parameter values in the body of the function and assign a value if they were undefined. In ES2015, a check in the function body is no longer required and one can simply defined default values for parameters in the function head.
12 |
13 | {% include output_helper.html %}
14 |
15 | {% include js_snippet.html filename='demo.js' %}
16 |
--------------------------------------------------------------------------------
/paymentrequest/can-make-payment/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: PaymentRequest Can Make Payment
3 | chrome_version: 56
4 | feature_id: 5639348045217792
5 | ---
6 |
7 | Background
8 |
9 | PaymentRequest lets
10 | you accept payment from different payment methods.
11 |
12 |
13 |
14 | This sample accepts both Android Pay and
15 | BobBucks and checks whether the browser
16 | can make payment.
17 |
18 |
19 | {% capture initial_output_content %}
20 |
21 |
22 | {% endcapture %}
23 | {% include output_helper.html initial_output_content=initial_output_content %}
24 |
25 | {% include js_snippet.html filename='demo.js' %}
26 |
--------------------------------------------------------------------------------
/paymentrequest/contact-info/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: PaymentRequest Contact Info
3 | chrome_version: 53
4 | feature_id: 5639348045217792
5 | ---
6 |
7 | Background
8 |
9 | PaymentRequest lets
10 | you accept payment from different payment methods.
11 |
12 |
13 |
14 | This sample accepts BobBucks and requests
15 | payer's contact information: name, phone number, and email address.
16 |
17 |
18 | {% capture initial_output_content %}
19 |
20 |
21 | {% endcapture %}
22 | {% include output_helper.html initial_output_content=initial_output_content %}
23 |
24 | {% include js_snippet.html filename='demo.js' %}
25 |
--------------------------------------------------------------------------------
/paymentrequest/shipping-options/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: PaymentRequest Shipping Options
3 | chrome_version: 53
4 | feature_id: 5639348045217792
5 | ---
6 |
7 | Background
8 |
9 | PaymentRequest lets
10 | you accept payment from different payment methods.
11 |
12 |
13 |
14 | This sample accepts BobBucks and provides
15 | a couple of shipping options regardless of shipping address.
16 |
17 |
18 | {% capture initial_output_content %}
19 |
20 |
21 | {% endcapture %}
22 | {% include output_helper.html initial_output_content=initial_output_content %}
23 |
24 | {% include js_snippet.html filename='demo.js' %}
25 |
--------------------------------------------------------------------------------
/beacon/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Beacon
3 | chrome_version: 39
4 | feature_id: 5517433905348608
5 | ---
6 |
7 | Background
8 |
9 | Beacon lets you asynchronously transfer small HTTP data from
10 | the User Agent to a web server. It can be used e.g. to send analytics
11 | or diagnostics code without delaying the page's unload or affecting
12 | the performance of the next navigation.
13 |
14 |
15 |
16 | The sample below sends a beacon to a sample server at
17 | https://putsreq.herokuapp.com/4GE2nVUuDoDGsNyKES2G on unload.
18 | Close this page and visit the
19 | PutsReq inspect page
20 | to see if the beacon data was received.
21 |
22 |
23 | {% include js_snippet.html filename='demo.js' %}
24 |
--------------------------------------------------------------------------------
/new-target-es6/demo.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | class Parent {
3 | constructor() {
4 | // new.target is a constructor reference, and new.target.name is human-friendly name.
5 | /* jshint ignore:start */
6 | ChromeSamples.log('Hello from Parent! ' +
7 | 'I was constructed via new ' + new.target.name + '()');
8 | /* jshint ignore:end */
9 | }
10 | }
11 |
12 | class FirstChild extends Parent {}
13 |
14 | class SecondChild extends Parent {}
15 |
16 | function notAConstructor() {
17 | /* jshint ignore:start */
18 | ChromeSamples.log('Hello from notAConstructor()! My new.target is ' +
19 | new.target);
20 | /* jshint ignore:end */
21 | }
22 |
23 | // Call all the constructors and the function when the page loads.
24 | new Parent();
25 | new FirstChild();
26 | new SecondChild();
27 | notAConstructor();
28 |
--------------------------------------------------------------------------------
/object-assign-es6/demo.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Merge an object
4 | let first = {name: 'Tony'};
5 | let last = {lastName: 'Stark'};
6 | let person = Object.assign(first, last);
7 | ChromeSamples.log(person);
8 | // {name: 'Tony', lastName: 'Stark'}
9 | ChromeSamples.log(first);
10 | // first = {name: 'Tony', lastName: 'Stark'} as the target also changed
11 |
12 | // Merge multiple sources
13 | let a = Object.assign({foo: 0}, {bar: 1}, {baz: 2});
14 | ChromeSamples.log(a);
15 | // {foo: 0, bar: 1, baz: 2}
16 |
17 | // Merge and overwrite equal keys
18 | let b = Object.assign({foo: 0}, {foo: 1}, {foo: 2});
19 | ChromeSamples.log(b);
20 | // {foo: 2}
21 |
22 | // Clone an object
23 | let obj = {person: 'Thor Odinson'};
24 | let clone = Object.assign({}, obj);
25 | ChromeSamples.log(clone);
26 | // {person: 'Thor Odinson'}
27 |
--------------------------------------------------------------------------------
/decorators-es7/read-write/src/scripts/app-core.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2015 Google Inc. All rights reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | import SampleController from './controllers/SampleController';
19 | let s = new SampleController();
20 |
--------------------------------------------------------------------------------
/paymentrequest/dynamic-shipping/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: PaymentRequest Dynamic Shipping
3 | chrome_version: 53
4 | feature_id: 5639348045217792
5 | ---
6 |
7 | Background
8 |
9 | PaymentRequest lets
10 | you accept payment from different payment methods.
11 |
12 |
13 |
14 | This sample accepts BobBucks and varies the
15 | availability and price of shipping options depending on the shipping address.
16 |
17 |
18 | {% capture initial_output_content %}
19 |
20 |
21 | {% endcapture %}
22 | {% include output_helper.html initial_output_content=initial_output_content %}
23 |
24 | {% include js_snippet.html filename='demo.js' %}
25 |
--------------------------------------------------------------------------------
/variable-fonts-experiments/samples/SimpleSliderDemo/style.css:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2018 Google Inc. All Rights Reserved.
3 | Licensed under the Apache License, Version 2.0
4 | (the "License"); you may not use this file
5 | except in compliance with the License.
6 | You may obtain a copy of the License at
7 | http://www.apache.org/licenses/LICENSE-2.0
8 | Unless required by applicable law or agreed to
9 | in writing, software distributed under the License
10 | is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
12 | either express or implied.
13 | See the License for the specific language governing
14 | permissions and limitations under the License.
15 | Licensed under the Apache License,
16 | Version 2.0 (the "License");
17 | */
18 | :root {
19 |
20 | }
--------------------------------------------------------------------------------
/battery-status/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Battery Status API
3 | chrome_version: 38
4 | feature_id: 4537134732017664
5 | ---
6 |
7 | Background
8 |
9 | The Battery Status API lets you monitor what
10 | is happening to the power of the device that your page is running on.
11 |
12 |
13 | {% capture initial_output_content %}
14 |
15 | Charging:
16 | Time to charge:
17 | Time to discharge:
18 | Battery Level:
19 | {% endcapture %}
20 | {% include output_helper.html initial_output_content=initial_output_content %}
21 |
22 | {% include js_snippet.html filename='demo.js' %}
23 |
--------------------------------------------------------------------------------
/presentation-api/receiver/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Demo Receiver
6 |
23 |
24 |
25 |
26 | Hello World!
27 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/extended-object-literals-es6/demo.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var a = 'somestring';
4 | var b = 5;
5 | var c = {key: 'value'};
6 |
7 | // The following two declarations are equivalent:
8 | var es5 = {a: a, b: b, c: c};
9 | var es6 = {a, b, c}; // Property name is inferred from variable name
10 | ChromeSamples.log('es5:', es5);
11 | ChromeSamples.log('es6:', es6);
12 |
13 | function person(name, age) {
14 | return {name, age}; // Again, property name is inferred
15 | }
16 |
17 | var me = person('Alex', 26);
18 | ChromeSamples.log('me:', me);
19 |
20 | var tools = {
21 | add1(i) { // You don’t have to type `function` over and over
22 | return i + 1;
23 | },
24 | * countdown(i) { // also works with generators
25 | while (i > 0) {
26 | yield i--;
27 | }
28 | }
29 | };
30 | ChromeSamples.log('If you add1() to 5 you get', tools.add1(5));
31 |
--------------------------------------------------------------------------------
/web-bluetooth/battery-level-async-await.js:
--------------------------------------------------------------------------------
1 | async function onButtonClick() {
2 | try {
3 | log('Requesting Bluetooth Device...');
4 | const device = await navigator.bluetooth.requestDevice({
5 | filters: [{services: ['battery_service']}]});
6 |
7 | log('Connecting to GATT Server...');
8 | const server = await device.gatt.connect();
9 |
10 | log('Getting Battery Service...');
11 | const service = await server.getPrimaryService('battery_service');
12 |
13 | log('Getting Battery Level Characteristic...');
14 | const characteristic = await service.getCharacteristic('battery_level');
15 |
16 | log('Reading Battery Level...');
17 | const value = await characteristic.readValue();
18 |
19 | log('> Battery Level is ' + value.getUint8(0) + '%');
20 | } catch(error) {
21 | log('Argh! ' + error);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/block-modal-dialogs-sandboxed-iframe/iframe.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
24 |
25 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/event-listeners-mandatory-arguments/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: addEventListener/removeEventListener non-optional arguments
3 | chrome_version: 49
4 | feature_id: 5640816202612736
5 | ---
6 |
7 | Background
8 | Previously, Chrome treated the first two arguments (type and
9 | listener) of addEventListener
10 | and removeEventListener
12 | optional, while they are non-optional in the spec and other browsers. This has
13 | changed: Now calling these methods with zero or one argument throws an
14 | Exception.
15 |
16 | {% include output_helper.html %}
17 |
18 | {% include js_snippet.html filename='demo.js' %}
19 |
20 |
--------------------------------------------------------------------------------
/service-worker/custom-offline-page/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: "Service Worker Sample: Custom Offline Page"
3 | chrome_version: 40
4 | feature_id: 6561526227927040
5 | ---
6 |
7 | Background
8 |
9 | This sample demonstrates basic service worker registration. During the installation step, a
10 | custom "Sorry, you're offline." page is cached. The service worker handles all fetch requests
11 | for HTML pages (ignoring other requests), and if fetching an HTML page fails due to a network
12 | error, it will instead return the cached "offline" page.
13 |
14 |
15 |
16 | Try disconnecting from your network, and then reload this page.
17 |
18 |
19 | {% include js_snippet.html filename='index.js' title="This Page's JavaScript" %}
20 | {% include js_snippet.html filename='service-worker.js' displayonly=true title="Service Worker's JavaScript" %}
21 |
--------------------------------------------------------------------------------
/decorators-es7/read-write/src/styles/app-core.scss:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Copyright 2015 Google Inc. All rights reserved.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | main {
19 | background: #999;
20 | border-radius: 3px;
21 | position: absolute;
22 | top: 200px;
23 | width: 200px;
24 | height: 300px;
25 | }
26 |
--------------------------------------------------------------------------------
/fetch-api/fetch-success-error-handlers-demo.js:
--------------------------------------------------------------------------------
1 | function makeRequest(url) {
2 | fetch(url).then(function(response) {
3 | // Shorthand to check for an HTTP 2xx response status.
4 | // See https://fetch.spec.whatwg.org/#dom-response-ok
5 | if (response.ok) {
6 | return response;
7 | }
8 | // Raise an exception to reject the promise and trigger the outer .catch() handler.
9 | // By default, an error response status (4xx, 5xx) does NOT cause the promise to reject!
10 | throw Error(response.statusText);
11 | }).then(function(response) {
12 | return response.json();
13 | }).then(function(json) {
14 | ChromeSamples.log('Request succeeded with JSON response:', json);
15 | }).catch(function(error) {
16 | ChromeSamples.log('Request failed:', error.message);
17 | });
18 | }
19 |
20 | makeRequest('notfound.json');
21 | makeRequest('users.json');
22 |
23 |
--------------------------------------------------------------------------------
/web-bluetooth/service-worker.js:
--------------------------------------------------------------------------------
1 | function addToCache(request, networkResponse) {
2 | return caches.open('web-bluetooth')
3 | .then(cache => cache.put(request, networkResponse));
4 | }
5 |
6 | function getCacheResponse(request) {
7 | return caches.open('web-bluetooth').then(cache => {
8 | return cache.match(request);
9 | });
10 | }
11 |
12 | function getNetworkOrCacheResponse(request) {
13 | return fetch(request).then(networkResponse => {
14 | addToCache(request, networkResponse.clone());
15 | return networkResponse;
16 | }).catch(_ => {
17 | return getCacheResponse(request)
18 | .then(cacheResponse => cacheResponse || Response.error());
19 | });
20 | }
21 |
22 | self.addEventListener('fetch', event => {
23 | if (event.request.url.startsWith(self.location.origin)) {
24 | event.respondWith(getNetworkOrCacheResponse(event.request));
25 | }
26 | });
27 |
--------------------------------------------------------------------------------
/rest-parameters-es6/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Rest parameters (ES2015)
3 | chrome_version: 47
4 | feature_id: 5937087912083456
5 | ---
6 |
7 | Background
8 |
9 | Rest parameters allow your functions to have variable number of arguments without using the arguments object. The rest parameter is an instance of Array so all the array methods just work.
10 |
11 |
12 | Note that there can only be a single rest parameter for a given function. This means that listAnimals(...cats, ...dogs) will not work, whilst listAnimals(...cats) will work just fine.
13 |
14 | {% include output_helper.html %}
15 |
16 | {% include js_snippet.html filename='demo.js' %}
17 |
--------------------------------------------------------------------------------
/picture-in-picture/skip-ad.js:
--------------------------------------------------------------------------------
1 | try {
2 | navigator.mediaSession.setActionHandler('skipad', null);
3 | showSkipAdButton();
4 | } catch(error) {
5 | log('Argh! The "Skip Ad" media session action is not supported.');
6 | }
7 |
8 | function showSkipAdButton() {
9 | log('The Picture-in-Picture window will show a "Skip Ad" button.');
10 | navigator.mediaSession.setActionHandler('skipad', onSkipAdButtonClick);
11 | }
12 |
13 | // Hide "Skip Ad" button when user clicks it and play another video.
14 | function onSkipAdButtonClick() {
15 | log('> User clicked "Skip Ad" button.');
16 | navigator.mediaSession.setActionHandler('skipad', null);
17 |
18 | video.src = "https://storage.googleapis.com/media-session/caminandes/short.mp4";
19 | video.play();
20 | }
21 |
22 | enterPictureInPictureButton.addEventListener('click', async () => {
23 | await video.play();
24 | await video.requestPictureInPicture();
25 | });
--------------------------------------------------------------------------------
/service-worker/windowclient-navigate/activated.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: "Service Worker: WindowClient.navigate()"
3 | chrome_version: 49
4 | feature_id: 5314750808326144
5 | ---
6 |
7 | Background
8 |
9 | If you're seeing this page, you've most likely been navigated here from
10 | index.html following the service worker activation.
11 |
12 |
13 |
14 | The service worker called client.navigate('activated.html') on
15 | each window that it controlled, which caused all of them to navigate to this
16 | page.
17 |
18 |
19 |
20 | When you revisit index.html, you'll remain on that
21 | page, since the activate event is only fired once for each
22 | service worker version.
23 |
24 |
25 | {% include js_snippet.html filename='service-worker.js' displayonly=true title="Service Worker's JavaScript" %}
26 |
--------------------------------------------------------------------------------
/formdata-methods/demo.js:
--------------------------------------------------------------------------------
1 | var form = document.getElementById('form');
2 | form.addEventListener('submit', function(ev) {
3 | ev.preventDefault();
4 |
5 | var formData = new FormData(form);
6 | var dateOfBirth = new Date(formData.get('dob'));
7 | var status = '';
8 |
9 | // Remove 'dob' from FormData if the user is <18.
10 | var date = new Date();
11 | date.setDate(date.getDate() - 365 * 18);
12 | if (Number(dateOfBirth) > Number(date)) {
13 | status = 'User is less than 18 years old!';
14 | formData.delete('dob');
15 | formData.set('underage', 'true');
16 | } else {
17 | status = 'User okay, name=`' + formData.get('name') + '`';
18 | }
19 | status += ', keys=' + Array.from(formData.keys());
20 |
21 | // This could be sent to a server with-
22 | // window.fetch(url, {body: formData, method: 'POST'})
23 |
24 | ChromeSamples.setContent(document.createTextNode(status));
25 | });
26 |
--------------------------------------------------------------------------------
/media/error-message.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: MediaError.message
3 | chrome_version: 59
4 | feature_id: 4996058069336064
5 | check_min_version: true
6 | ---
7 |
8 | Background
9 | The MediaError.message string provides, if available, any additional error
10 | message detail to help web developers debugging media player errors. Note that
11 | this sample demonstrates only a tiny fraction of such messages.
12 |
13 | Set video with:
14 |
15 |
16 |
17 |
18 | Or
19 |
20 |
21 | {% include output_helper.html initial_output_content=initial_output_content %}
22 |
23 | {% include js_snippet.html filename='error-message.js' %}
24 |
--------------------------------------------------------------------------------
/variable-fonts-experiments/samples/SliderDemoCustomProp/style.css:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2018 Google Inc. All Rights Reserved.
3 | Licensed under the Apache License, Version 2.0
4 | (the "License"); you may not use this file
5 | except in compliance with the License.
6 | You may obtain a copy of the License at
7 | http://www.apache.org/licenses/LICENSE-2.0
8 | Unless required by applicable law or agreed to
9 | in writing, software distributed under the License
10 | is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
12 | either express or implied.
13 | See the License for the specific language governing
14 | permissions and limitations under the License.
15 | Licensed under the Apache License,
16 | Version 2.0 (the "License");
17 | */
18 | :root {
19 | --number: 3;
20 | }
21 |
22 |
23 | #sergio {
24 | width: calc(var(--number) * 100px);
25 | background: red;
26 | height: 100px;
27 | }
--------------------------------------------------------------------------------
/web-bluetooth/battery-level.js:
--------------------------------------------------------------------------------
1 | function onButtonClick() {
2 | log('Requesting Bluetooth Device...');
3 | navigator.bluetooth.requestDevice(
4 | {filters: [{services: ['battery_service']}]})
5 | .then(device => {
6 | log('Connecting to GATT Server...');
7 | return device.gatt.connect();
8 | })
9 | .then(server => {
10 | log('Getting Battery Service...');
11 | return server.getPrimaryService('battery_service');
12 | })
13 | .then(service => {
14 | log('Getting Battery Level Characteristic...');
15 | return service.getCharacteristic('battery_level');
16 | })
17 | .then(characteristic => {
18 | log('Reading Battery Level...');
19 | return characteristic.readValue();
20 | })
21 | .then(value => {
22 | let batteryLevel = value.getUint8(0);
23 | log('> Battery Level is ' + batteryLevel + '%');
24 | })
25 | .catch(error => {
26 | log('Argh! ' + error);
27 | });
28 | }
29 |
--------------------------------------------------------------------------------
/fetch-api/fetch-post-demo.js:
--------------------------------------------------------------------------------
1 | function createGist(opts) {
2 | ChromeSamples.log('Posting request to GitHub API...');
3 | fetch('https://api.github.com/gists', {
4 | method: 'post',
5 | body: JSON.stringify(opts)
6 | }).then(function(response) {
7 | return response.json();
8 | }).then(function(data) {
9 | ChromeSamples.log('Created Gist:', data.html_url);
10 | });
11 | }
12 |
13 | function submitGist() {
14 | var content = document.querySelector('textarea').value;
15 | if (content) {
16 | createGist({
17 | description: 'Fetch API Post example',
18 | public: true,
19 | files: {
20 | 'test.js': {
21 | content: content
22 | }
23 | }
24 | });
25 | } else {
26 | ChromeSamples.log('Please enter in content to POST to a new Gist.');
27 | }
28 | }
29 |
30 | var submitBtn = document.querySelector('button');
31 | submitBtn.addEventListener('click', submitGist);
32 |
--------------------------------------------------------------------------------
/image-capture/photo-resolution.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Image Capture / Photo Resolution
3 | chrome_version: 61
4 | feature_id: 5104908176982016
5 | local_css_files: ['photo-resolution.css']
6 | check_min_version: true
7 | index: index.html
8 | ---
9 |
10 | Background
11 | The ImageCapture Web API allows web developers to manipulate "Non-Live"
12 | camera capabilities and settings such as the photo resolution, red eye
13 | reduction, and flash mode.
14 | This sample demonstrates the use of setting the image width of the
15 | photo.
16 |
17 |
18 |
19 |
20 |
21 |
22 | {% include output_helper.html %}
23 |
24 | {% include js_snippet.html filename='photo-resolution.js' %}
25 |
26 |
29 |
--------------------------------------------------------------------------------
/css-motion-path/demo.js:
--------------------------------------------------------------------------------
1 | var firstScissorHalf = document.querySelector('#firstScissorHalf');
2 | var secondScissorHalf = document.querySelector('#secondScissorHalf');
3 |
4 | var positionKeyframes = [{motionOffset: '0%'}, {motionOffset: '100%'}];
5 | var positionTiming = {duration: 12000, iterations: Infinity};
6 | firstScissorHalf.animate(positionKeyframes, positionTiming);
7 | secondScissorHalf.animate(positionKeyframes, positionTiming);
8 |
9 | var firstRotationKeyframes = [
10 | {motionRotation: 'auto 0deg'},
11 | {motionRotation: 'auto -45deg'},
12 | {motionRotation: 'auto 0deg'}
13 | ];
14 | var secondRotationKeyframes = [
15 | {motionRotation: 'auto 0deg'},
16 | {motionRotation: 'auto 45deg'},
17 | {motionRotation: 'auto 0deg'}
18 | ];
19 | var rotationTiming = {duration: 1000, iterations: Infinity};
20 | firstScissorHalf.animate(firstRotationKeyframes, rotationTiming);
21 | secondScissorHalf.animate(secondRotationKeyframes, rotationTiming);
22 |
--------------------------------------------------------------------------------
/media-capabilities/decoding-info.js:
--------------------------------------------------------------------------------
1 | const mediaConfig = {
2 | type: 'media-source', // or 'file'
3 | audio: {
4 | contentType: 'audio/webm; codecs=opus',
5 | channels: '2', // audio channels used by the track
6 | bitrate: 132266, // number of bits used to encode a second of audio
7 | samplerate: 48000 // number of samples of audio carried per second
8 | },
9 | video: {
10 | contentType: 'video/webm; codecs="vp09.00.10.08"',
11 | width: 1920,
12 | height: 1080,
13 | bitrate: 2646242, // number of bits used to encode a second of video
14 | framerate: '25' // number of frames used in one second
15 | }
16 | };
17 |
18 | navigator.mediaCapabilities.decodingInfo(mediaConfig).then(result => {
19 | log('This configuration is' +
20 | (result.supported ? '' : ' NOT') + ' supported,' +
21 | (result.smooth ? '' : ' NOT') + ' smooth and' +
22 | (result.powerEfficient ? '' : ' NOT') + ' power efficient.');
23 | });
24 |
--------------------------------------------------------------------------------
/variable-fonts-experiments/readme.md:
--------------------------------------------------------------------------------
1 | # Project Title
2 |
3 | You can read the full article at
4 | [Web Fundamentals](https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts/).
5 |
6 |
7 | This is a collection of experiments inspired by [axis-praxis.org](https://www.axis-praxis.org/specimens/__DEFAULT__) and [typetools.typenetwork.com/](https://typetools.typenetwork.com/typespec/). The goal is to demonstrate the flexibility of Variable Fonts and the potential they hold for designers and developers.
8 |
9 |
10 | ## Getting Started
11 |
12 | These are standalone HTML files and can be run in a browser.
13 |
14 | Working Demo be seen at [https://variable-font-experiments.glitch.me/](variable-font-experiments.glitch.me/)
15 |
16 | ## Authors
17 |
18 | * **Mustafa Kurtuldu** - *Initial work*
19 |
20 | ## Acknowledgments
21 |
22 | Thanks to
23 |
24 | * (https://www.axis-praxis.org/)
25 | * (https://typetools.typenetwork.com/typespec/)
--------------------------------------------------------------------------------
/app-install-banner/basic-banner/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "App Install Banner Sample",
3 | "short_name": "App Install Banner Sample",
4 | "icons": [
5 | {
6 | "src": "launcher-icon-0-75x.png",
7 | "sizes": "36x36",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "launcher-icon-1x.png",
12 | "sizes": "48x48",
13 | "type": "image/png"
14 | },
15 | {
16 | "src": "launcher-icon-1-5x.png",
17 | "sizes": "72x72",
18 | "type": "image/png"
19 | },
20 | {
21 | "src": "launcher-icon-2x.png",
22 | "sizes": "96x96",
23 | "type": "image/png"
24 | },
25 | {
26 | "src": "launcher-icon-3x.png",
27 | "sizes": "144x144",
28 | "type": "image/png"
29 | },
30 | {
31 | "src": "launcher-icon-4x.png",
32 | "sizes": "192x192",
33 | "type": "image/png"
34 | }
35 | ],
36 | "start_url": "./index.html",
37 | "display": "standalone"
38 | }
39 |
--------------------------------------------------------------------------------
/app-install-banner/cancelable-banner/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "App Install Banner Sample",
3 | "short_name": "App Install Banner Sample",
4 | "icons": [
5 | {
6 | "src": "launcher-icon-0-75x.png",
7 | "sizes": "36x36",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "launcher-icon-1x.png",
12 | "sizes": "48x48",
13 | "type": "image/png"
14 | },
15 | {
16 | "src": "launcher-icon-1-5x.png",
17 | "sizes": "72x72",
18 | "type": "image/png"
19 | },
20 | {
21 | "src": "launcher-icon-2x.png",
22 | "sizes": "96x96",
23 | "type": "image/png"
24 | },
25 | {
26 | "src": "launcher-icon-3x.png",
27 | "sizes": "144x144",
28 | "type": "image/png"
29 | },
30 | {
31 | "src": "launcher-icon-4x.png",
32 | "sizes": "192x192",
33 | "type": "image/png"
34 | }
35 | ],
36 | "start_url": "./index.html",
37 | "display": "standalone"
38 | }
39 |
--------------------------------------------------------------------------------
/app-install-banner/useraction-banner/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "App Install Banner Sample",
3 | "short_name": "App Install Banner Sample",
4 | "icons": [
5 | {
6 | "src": "launcher-icon-0-75x.png",
7 | "sizes": "36x36",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "launcher-icon-1x.png",
12 | "sizes": "48x48",
13 | "type": "image/png"
14 | },
15 | {
16 | "src": "launcher-icon-1-5x.png",
17 | "sizes": "72x72",
18 | "type": "image/png"
19 | },
20 | {
21 | "src": "launcher-icon-2x.png",
22 | "sizes": "96x96",
23 | "type": "image/png"
24 | },
25 | {
26 | "src": "launcher-icon-3x.png",
27 | "sizes": "144x144",
28 | "type": "image/png"
29 | },
30 | {
31 | "src": "launcher-icon-4x.png",
32 | "sizes": "192x192",
33 | "type": "image/png"
34 | }
35 | ],
36 | "start_url": "./index.html",
37 | "display": "standalone"
38 | }
39 |
--------------------------------------------------------------------------------
/encoding-api/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Encoding API
3 | chrome_version: 38
4 | feature_id: 5714368087982080
5 | ---
6 |
7 | Background
8 |
9 | The JavaScript Encoding API allows developers to encode and decode strings using a wide range of
10 | character encodings.
11 |
12 |
13 |
14 | The example on this page illustrates decoding data from a file into JavaScript strings.
15 | The code obtains raw binary ArrayBuffer by making an XMLHttpRequest
16 | for a local file. The code then calls TextDecoder.decode() to translate the data
17 | into a string, given the appropriate character encoding.
18 |
19 |
20 |
21 | In a real world scenario, source data might be read from files that predate Unicode
22 | or from a legacy database system that only supported a specific character encoding.
23 |
24 |
25 | {% include output_helper.html %}
26 |
27 | {% include js_snippet.html filename='demo.js' %}
28 |
--------------------------------------------------------------------------------
/media/sourcebuffer-changetype.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Codec and container switching in MSE
3 | chrome_version: 70
4 | feature_id: 5719220952236032
5 | check_min_version: true
6 | ---
7 |
8 | Background
9 |
10 | Chrome adds support for improved cross-codec or cross-bytestream transitions in
11 | Media Source Extensions (MSE) playback using a new changeType()
12 | method on SourceBuffer. It basically allows the type of media bytes
13 | subsequently appended to the SourceBuffer to be changed.
14 |
15 |
16 | This sample demonstrates the use of this new method by appending different
17 | types of media bytes to a single SourceBuffer of a MediaSource attached to an
18 | audio element.
19 |
20 |
21 |
22 |
23 | {% include output_helper.html initial_output_content=initial_output_content %}
24 |
25 |
28 |
29 | {% include js_snippet.html filename='sourcebuffer-changetype.js' %}
30 |
--------------------------------------------------------------------------------
/web-share/src/js/constants.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2019 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | **/
16 |
17 | export const cacheName = 'media';
18 | export const channelName = 'messages';
19 | export const fadeConfig = {duration: 200};
20 | export const iconSrcs = {
21 | audio: 'images/audio.png',
22 | image: 'images/image.png',
23 | video: 'images/video.png',
24 | };
25 | export const urlPrefix = '/_media/';
26 |
--------------------------------------------------------------------------------
/app-install-banner/deferred-banner/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "App Install Deferred Banner Sample",
3 | "short_name": "App Install Deferred Banner Sample",
4 | "icons": [
5 | {
6 | "src": "launcher-icon-0-75x.png",
7 | "sizes": "36x36",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "launcher-icon-1x.png",
12 | "sizes": "48x48",
13 | "type": "image/png"
14 | },
15 | {
16 | "src": "launcher-icon-1-5x.png",
17 | "sizes": "72x72",
18 | "type": "image/png"
19 | },
20 | {
21 | "src": "launcher-icon-2x.png",
22 | "sizes": "96x96",
23 | "type": "image/png"
24 | },
25 | {
26 | "src": "launcher-icon-3x.png",
27 | "sizes": "144x144",
28 | "type": "image/png"
29 | },
30 | {
31 | "src": "launcher-icon-4x.png",
32 | "sizes": "192x192",
33 | "type": "image/png"
34 | }
35 | ],
36 | "start_url": "./index.html",
37 | "display": "standalone"
38 | }
39 |
--------------------------------------------------------------------------------
/play-return-promise/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: HTMLMediaElement.play() Returns a Promise
3 | chrome_version: 50
4 | feature_id: 5920584248590336
5 | ---
6 |
7 | Background
8 |
9 | Many mobile browsers prevent JavaScript from initiating playback of media elements
10 | unless it's in response to user interaction.
11 |
12 |
13 | It's historically been difficult to detect failed playbacks due to mobile browser
14 | restrictions, but the new
15 | Promise-based
16 | interface to the play() method provides a friendly way of detecting whether
17 | playback succeeded or failed.
18 |
19 |
20 | {% capture html %}
21 |
22 |
23 | {% endcapture %}
24 |
25 | {% include output_helper.html %}
26 |
27 | {% include html_snippet.html html=html %}
28 | {% include js_snippet.html filename='demo.js' %}
29 |
--------------------------------------------------------------------------------
/web-bluetooth/reset-energy-async-await.js:
--------------------------------------------------------------------------------
1 | async function onButtonClick() {
2 | try {
3 | log('Requesting Bluetooth Device...');
4 | const device = await navigator.bluetooth.requestDevice({
5 | filters: [{services: ['heart_rate']}]});
6 |
7 | log('Connecting to GATT Server...');
8 | const server = await device.gatt.connect();
9 |
10 | log('Getting Heart Rate Service...');
11 | const service = await server.getPrimaryService('heart_rate');
12 |
13 | log('Getting Heart Rate Control Point Characteristic...');
14 | const characteristic = await service.getCharacteristic('heart_rate_control_point');
15 |
16 | log('Writing Heart Rate Control Point Characteristic...');
17 | // Writing 1 is the signal to reset energy expended.
18 | let resetEnergyExpended = Uint8Array.of(1);
19 | await characteristic.writeValue(resetEnergyExpended);
20 |
21 | log('> Energy expended has been reset.');
22 | } catch(error) {
23 | log('Argh! ' + error);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/image-capture/update-camera-zoom.js:
--------------------------------------------------------------------------------
1 | navigator.mediaDevices.getUserMedia({video: { zoom: true }})
2 | .then(mediaStream => {
3 | document.querySelector('video').srcObject = mediaStream;
4 |
5 | const [track] = mediaStream.getVideoTracks();
6 | const capabilities = track.getCapabilities();
7 | const settings = track.getSettings();
8 |
9 | const input = document.querySelector('input[type="range"]');
10 |
11 | // Check whether zoom is supported or not.
12 | if (!('zoom' in settings)) {
13 | return Promise.reject('Zoom is not supported by ' + track.label);
14 | }
15 |
16 | // Map zoom to a slider element.
17 | input.min = capabilities.zoom.min;
18 | input.max = capabilities.zoom.max;
19 | input.step = capabilities.zoom.step;
20 | input.value = settings.zoom;
21 | input.oninput = function(event) {
22 | track.applyConstraints({advanced: [ {zoom: event.target.value} ]});
23 | }
24 | input.hidden = false;
25 | })
26 | .catch(error => ChromeSamples.log('Argh!', error.name || error));
27 |
--------------------------------------------------------------------------------
/web-application-manifest/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Web Application Manifest Sample",
3 | "icons": [
4 | {
5 | "src": "launcher-icon-0-75x.png",
6 | "sizes": "36x36",
7 | "type": "image/png"
8 | },
9 | {
10 | "src": "launcher-icon-1x.png",
11 | "sizes": "48x48",
12 | "type": "image/png"
13 | },
14 | {
15 | "src": "launcher-icon-1-5x.png",
16 | "sizes": "72x72",
17 | "type": "image/png"
18 | },
19 | {
20 | "src": "launcher-icon-2x.png",
21 | "sizes": "96x96",
22 | "type": "image/png"
23 | },
24 | {
25 | "src": "launcher-icon-3x.png",
26 | "sizes": "144x144",
27 | "type": "image/png"
28 | },
29 | {
30 | "src": "launcher-icon-4x.png",
31 | "sizes": "192x192",
32 | "type": "image/png"
33 | }
34 | ],
35 | "theme_color": "#9E9E9E",
36 | "background_color": "#9E9E9E",
37 | "start_url": "index.html",
38 | "display": "standalone",
39 | "orientation": "landscape"
40 | }
41 |
--------------------------------------------------------------------------------
/web-bluetooth/watch-advertisements.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Web Bluetooth / Watch Advertisements
3 | chrome_version: 87
4 | check_min_version: true
5 | feature_id: 5180688812736512
6 | icon_url: icon.png
7 | index: index.html
8 | ---
9 |
10 | {% include_relative _includes/intro.html %}
11 |
12 | This sample illustrates the use of the Web Bluetooth API to read out
13 | advertisement data from nearby Bluetooth devices. You may want to check out the Watch Advertisements (Async Await) sample.
15 |
16 |
17 |
18 | {% include output_helper.html %}
19 |
20 | {% include js_snippet.html filename='watch-advertisements.js' %}
21 |
22 | {% include_relative _includes/utils.html %}
23 |
24 |
31 |
--------------------------------------------------------------------------------
/webassembly/webp.c:
--------------------------------------------------------------------------------
1 | #include "emscripten.h"
2 | #include "src/webp/encode.h"
3 | #include
4 |
5 | EMSCRIPTEN_KEEPALIVE
6 | int version() {
7 | return WebPGetEncoderVersion();
8 | }
9 |
10 | EMSCRIPTEN_KEEPALIVE
11 | uint8_t* create_buffer(int width, int height) {
12 | return malloc(width * height * 4 * sizeof(uint8_t));
13 | }
14 |
15 | EMSCRIPTEN_KEEPALIVE
16 | void destroy_buffer(uint8_t* p) {
17 | free(p);
18 | }
19 |
20 | int result[2];
21 | EMSCRIPTEN_KEEPALIVE
22 | void encode(uint8_t* img_in, int width, int height, float quality) {
23 | uint8_t* img_out;
24 | size_t size;
25 | size = WebPEncodeRGBA(img_in, width, height, width * 4, quality, &img_out);
26 | result[0] = (int)img_out;
27 | result[1] = size;
28 | }
29 |
30 | EMSCRIPTEN_KEEPALIVE
31 | void free_result(uint8_t* result) {
32 | WebPFree(result);
33 | }
34 |
35 | EMSCRIPTEN_KEEPALIVE
36 | int get_result_pointer() {
37 | return result[0];
38 | }
39 |
40 | EMSCRIPTEN_KEEPALIVE
41 | int get_result_size() {
42 | return result[1];
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/fetch-api/fetch-referrer-policy.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Fetch Referrer Policy
3 | chrome_version: 52
4 | feature_id: 5692236742262784
5 | ---
6 |
7 | Background
8 |
9 | This sample shows how requests made via the Fetch API can use a specific
10 | referrer policy,
11 | which affects the value of the Referer HTTP header that's sent
12 | to remote servers.
13 |
14 |
15 | {% capture initial_output_content %}
16 |
17 | Multiple fetch() requests are made for a local resource, each with a
18 | different referrerPolicy set. You can see the requests and the
19 | Referer header associated with each in
20 | Chrome DevTools.
21 |
22 | {% endcapture %}
23 | {% include output_helper.html initial_output_content=initial_output_content %}
24 |
25 | {% include js_snippet.html filename='fetch-referrer-policy.js' %}
26 |
--------------------------------------------------------------------------------
/web-bluetooth/reset-energy.js:
--------------------------------------------------------------------------------
1 | function onButtonClick() {
2 | log('Requesting Bluetooth Device...');
3 | navigator.bluetooth.requestDevice({filters: [{services: ['heart_rate']}]})
4 | .then(device => {
5 | log('Connecting to GATT Server...');
6 | return device.gatt.connect();
7 | })
8 | .then(server => {
9 | log('Getting Heart Rate Service...');
10 | return server.getPrimaryService('heart_rate');
11 | })
12 | .then(service => {
13 | log('Getting Heart Rate Control Point Characteristic...');
14 | return service.getCharacteristic('heart_rate_control_point');
15 | })
16 | .then(characteristic => {
17 | log('Writing Heart Rate Control Point Characteristic...');
18 |
19 | // Writing 1 is the signal to reset energy expended.
20 | let resetEnergyExpended = Uint8Array.of(1);
21 | return characteristic.writeValue(resetEnergyExpended);
22 | })
23 | .then(_ => {
24 | log('> Energy expended has been reset.');
25 | })
26 | .catch(error => {
27 | log('Argh! ' + error);
28 | });
29 | }
30 |
--------------------------------------------------------------------------------
/web-bluetooth/watch-advertisements-async-await.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Web Bluetooth / Watch Advertisements (Async Await)
3 | chrome_version: 87
4 | check_min_version: true
5 | feature_id: 5180688812736512
6 | icon_url: icon.png
7 | index: index.html
8 | ---
9 |
10 | {% include_relative _includes/intro.html %}
11 |
12 | This sample illustrates the use of the Web Bluetooth API to read out
13 | advertisement data from nearby Bluetooth devices. You may want to check out the Watch Advertisements sample.
15 |
16 |
17 |
18 | {% include output_helper.html %}
19 |
20 | {% include js_snippet.html filename='watch-advertisements-async-await.js' %}
21 |
22 | {% include_relative _includes/utils.html %}
23 |
24 |
31 |
--------------------------------------------------------------------------------
/media/flac-in-mp4-for-mse.js:
--------------------------------------------------------------------------------
1 | const audio = document.querySelector('audio');
2 |
3 | if (MediaSource.isTypeSupported('audio/mp4; codecs="flac"')) {
4 | const mediaSource = new MediaSource();
5 | audio.src = URL.createObjectURL(mediaSource);
6 |
7 | mediaSource.addEventListener('sourceopen', function() {
8 | URL.revokeObjectURL(audio.src);
9 |
10 | const sourceBuffer = mediaSource.addSourceBuffer('audio/mp4; codecs="flac"');
11 |
12 | log('Fetching audio file...');
13 | fetch('https://storage.googleapis.com/media-session/flac.mp4')
14 | .then(response => response.arrayBuffer())
15 | .then(data => {
16 | sourceBuffer.appendBuffer(data);
17 | sourceBuffer.addEventListener('updateend', function() {
18 | if (!sourceBuffer.updating && mediaSource.readyState === 'open') {
19 | mediaSource.endOfStream();
20 | log('Audio is ready to play!');
21 | }
22 | });
23 | });
24 | });
25 | } else {
26 | log('FLAC in ISO-BMFF with MSE is not supported on this platform.');
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/media/opus-in-mp4-for-mse.js:
--------------------------------------------------------------------------------
1 | const audio = document.querySelector('audio');
2 |
3 | if (MediaSource.isTypeSupported('audio/mp4; codecs="opus"')) {
4 | const mediaSource = new MediaSource();
5 | audio.src = URL.createObjectURL(mediaSource);
6 |
7 | mediaSource.addEventListener('sourceopen', function() {
8 | URL.revokeObjectURL(audio.src);
9 |
10 | const sourceBuffer = mediaSource.addSourceBuffer('audio/mp4; codecs="opus"');
11 |
12 | log('Fetching audio file...');
13 | fetch('https://storage.googleapis.com/media-session/bear-opus.mp4')
14 | .then(response => response.arrayBuffer())
15 | .then(data => {
16 | sourceBuffer.appendBuffer(data);
17 | sourceBuffer.addEventListener('updateend', function() {
18 | if (!sourceBuffer.updating && mediaSource.readyState === 'open') {
19 | mediaSource.endOfStream();
20 | log('Audio is ready to play!');
21 | }
22 | });
23 | });
24 | });
25 | } else {
26 | log('Opus in ISO-BMFF with MSE is not supported on this platform.');
27 | }
28 |
--------------------------------------------------------------------------------
/paymentrequest/stickersheet/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: PaymentRequest Stickersheet
3 | chrome_version: 53
4 | feature_id: 5639348045217792
5 | ---
6 |
7 | Background
8 |
9 | This contains all of the steps you need to take when designing a flow in Sketch App.
10 |
11 |
12 | The file is made up of multiple symbols that can be overridden. To learn more about the UX of the Payments Request API, checkout the article on Web Fundamentals.
13 |
14 |
15 | You can download it here
16 |
17 |
18 |
19 | Licenses
20 | Attribution 4.0 International (CC BY 4.0)
21 |
22 | Authors
23 |
24 | Stickersheet Designer: Mustafa Kurtuldu
25 | Original UI & UX Design: Bruno Bergher
26 |
27 |
--------------------------------------------------------------------------------
/async-clipboard/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Asynchronous Clipboard API
3 | chrome_version: 66
4 | feature_id: 5861289330999296
5 | local_css_files: ['demo.css']
6 | ---
7 |
8 | Background
9 | This is a demonstration of the text portions of the Asynchronous Clipboard API, shipping in Chrome 66.
10 | Note: the permissions API requires that you enable the Experimental Web Platform Features flag in Chrome: chrome://flags/#enable-experimental-web-platform-features
11 |
12 | {% capture initial_output_content %}
13 |
14 |
15 |
16 | Permissions:
17 |
18 |
19 | {% endcapture %}
20 | {% include output_helper.html initial_output_content=initial_output_content %}
21 |
22 | {% include js_snippet.html filename='demo.js' %}
23 |
--------------------------------------------------------------------------------
/auto-picture-in-picture/index.js:
--------------------------------------------------------------------------------
1 | if (window.matchMedia("(display-mode: browser)").matches)
2 | log('Warning! Install this sample app first.');
3 | else {
4 | // If Progressive Web App is installed and running in a window,
5 | // request user camera and show its stream in the video.
6 | navigator.mediaDevices.getUserMedia({ video: true })
7 | .then(stream => {
8 | video.srcObject = stream;
9 | return video.play();
10 |
11 | // User can now show/hide window and video will enter and exit
12 | // automatically Picture-in-Picture when the document's visibility
13 | // changes.
14 | });
15 | }
16 |
17 | video.addEventListener('enterpictureinpicture', function(event) {
18 | log('> Video entered Picture-in-Picture');
19 | });
20 |
21 | video.addEventListener('leavepictureinpicture', function(event) {
22 | log('> Video left Picture-in-Picture');
23 | });
24 |
25 | /* Feature support */
26 |
27 | if (!('autoPictureInPicture' in HTMLVideoElement.prototype)) {
28 | log('Warning! Auto Picture-in-Picture is not available.');
29 | }
30 |
--------------------------------------------------------------------------------
/media/error-message.js:
--------------------------------------------------------------------------------
1 | let video = document.createElement('video');
2 |
3 | video.addEventListener('error', function(event) {
4 | ChromeSamples.log('Error Message: ' + video.error.message);
5 | });
6 |
7 |
8 |
9 | emptySrcButton.addEventListener('click', function() {
10 | video.src= '';
11 | });
12 |
13 | nonExistentFileButton.addEventListener('click', function() {
14 | video.src = 'nonExistentFile.webm';
15 | });
16 |
17 | invalidFileButton.addEventListener('click', function() {
18 | video.src = 'no_streams.webm';
19 | });
20 |
21 | crossOriginInvalidFileButton.addEventListener('click', function() {
22 | video.src = 'https://storage.googleapis.com/media-error/no_streams.webm';
23 | // Error message will be cleared out because file is cross-origin.
24 | });
25 |
26 | chooseFileButton.addEventListener('change', function() {
27 | const file = chooseFileButton.files[0];
28 | video.src = URL.createObjectURL(file);
29 | });
30 |
31 | video.addEventListener('canplay', function() {
32 | ChromeSamples.log('"canplay" event received');
33 | });
34 |
35 |
--------------------------------------------------------------------------------
/network-information/demo.js:
--------------------------------------------------------------------------------
1 | navigator.connection.addEventListener('change', logNetworkInfo);
2 |
3 | function logNetworkInfo() {
4 | // Network type that browser uses
5 | log(' type: ' + navigator.connection.type);
6 |
7 | // Effective bandwidth estimate
8 | log(' downlink: ' + navigator.connection.downlink + ' Mb/s');
9 |
10 | // Effective round-trip time estimate
11 | log(' rtt: ' + navigator.connection.rtt + ' ms');
12 |
13 | // Upper bound on the downlink speed of the first network hop
14 | log(' downlinkMax: ' + navigator.connection.downlinkMax + ' Mb/s');
15 |
16 | // Effective connection type determined using a combination of recently
17 | // observed rtt and downlink values: ' +
18 | log('effectiveType: ' + navigator.connection.effectiveType);
19 |
20 | // True if the user has requested a reduced data usage mode from the user
21 | // agent.
22 | log(' saveData: ' + navigator.connection.saveData);
23 |
24 | // Add whitespace for readability
25 | log('');
26 | }
27 |
28 | logNetworkInfo();
29 |
--------------------------------------------------------------------------------
/web-share/src/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "background_color": "#ECEFF1",
3 | "description": "An offline-first PWA that acts as a share source and target.",
4 | "display": "standalone",
5 | "icons": [{
6 | "src": "images/splash.jpg",
7 | "sizes": "512x512",
8 | "type": "image/jpg"
9 | }, {
10 | "purpose": "maskable",
11 | "src": "images/splash.jpg",
12 | "sizes": "512x512",
13 | "type": "image/jpg"
14 | }, {
15 | "src": "images/icon.png",
16 | "sizes": "192x192",
17 | "type": "image/png"
18 | }],
19 | "name": "Scrapbook PWA",
20 | "scope": "/",
21 | "share_target": {
22 | "action": "/_share-target",
23 | "enctype": "multipart/form-data",
24 | "method": "POST",
25 | "params": {
26 | "files": [{
27 | "name": "media",
28 | "accept": [
29 | "audio/*",
30 | "image/*",
31 | "video/*"
32 | ]
33 | }]
34 | }
35 | },
36 | "short_name": "Scrapbook PWA",
37 | "start_url": "/?utm_source=installed",
38 | "theme_color": "#37474F"
39 | }
40 |
--------------------------------------------------------------------------------
/auto-picture-in-picture/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Auto Picture-in-Picture Sample",
3 | "icons": [
4 | {
5 | "src": "launcher-icon-0-75x.png",
6 | "sizes": "36x36",
7 | "type": "image/png"
8 | },
9 | {
10 | "src": "launcher-icon-1x.png",
11 | "sizes": "48x48",
12 | "type": "image/png"
13 | },
14 | {
15 | "src": "launcher-icon-1-5x.png",
16 | "sizes": "72x72",
17 | "type": "image/png"
18 | },
19 | {
20 | "src": "launcher-icon-2x.png",
21 | "sizes": "96x96",
22 | "type": "image/png"
23 | },
24 | {
25 | "src": "launcher-icon-3x.png",
26 | "sizes": "144x144",
27 | "type": "image/png"
28 | },
29 | {
30 | "src": "launcher-icon-4x.png",
31 | "sizes": "192x192",
32 | "type": "image/png"
33 | }
34 | ],
35 | "theme_color": "#9E9E9E",
36 | "background_color": "#9E9E9E",
37 | "start_url": "index.html",
38 | "scope": "/auto-picture-in-picture/",
39 | "display": "standalone",
40 | "orientation": "landscape"
41 | }
42 |
--------------------------------------------------------------------------------
/web-nfc/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Web NFC
3 | chrome_version: 89
4 | feature_id: 6261030015467520
5 | check_min_version: true
6 | ---
7 |
8 | Background
9 |
10 | Web NFC aims to provide sites the ability to read and write to NFC tags when
11 | they are brought in close proximity to the user’s device (usually 5-10 cm, 2-4
12 | inches). The current scope is limited to NDEF, a lightweight binary message
13 | format. Low-level I/O operations (e.g. ISO-DEP, NFC-A/B, NFC-F) and Host-based
14 | Card Emulation (HCE) are not supported within the current scope.
15 |
16 |
17 |
18 |
19 |
20 |
21 | {% include output_helper.html initial_output_content=initial_output_content %}
22 |
23 |
29 |
30 | {% include js_snippet.html filename='index.js' %}
31 |
--------------------------------------------------------------------------------
/push-messaging-and-notifications/README.md:
--------------------------------------------------------------------------------
1 | Push Messaging and Notification Sample
2 | ===
3 |
4 | Learn more at https://www.chromestatus.com/feature/5416033485586432 and https://www.chromestatus.com/feature/5480344312610816
5 |
6 | To use this sample please do the following:
7 |
8 | 1. Create a project on the [Firebase Developer Console](https://console.firebase.google.com).
9 | 1. Go to Settings (the cog near the top left corner), click the 'Cloud Messaging Tab'.
10 | 1. Create a copy of [config.sample.js](config.sample.js) called config.js.
11 | 1. Create a copy of [manifest.sample.json](manifest.sample.json) called manifest.json.
12 | 1. Replace `` in your new `config.js` file with your own API key from your new project on Firebase Developer Console.
13 | 4. Replace `` in your new `manifest.json` with your own sender ID from the Firebase Developer Console project.
14 |
15 | # Related Samples
16 | Push messaging and notifications are built on [service workers](https://github.com/GoogleChrome/samples/tree/gh-pages/service-worker).
17 |
--------------------------------------------------------------------------------
/classes-es6/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Classes (ES6)
3 | chrome_version: 42
4 | feature_id: 4633745457938432
5 | ---
6 |
7 | Background
8 |
9 | ES6 Classes formalize the common JavaScript pattern of simulating class-like inheritance hierarchies
10 | using functions and prototypes. They are effectively simple sugaring over prototype-based OO, offering
11 | a convenient declarative form for class patterns which encourage interoperability.
12 |
13 |
14 | Classes (as shipped in Chrome) support prototype-based inheritance, constructors, super calls, instance
15 | and static methods. The samples included in this demo are:
16 |
17 |
18 |
19 | - Creating a new class (declaration-form)
20 | - Creating a new class (expression-form)
21 | - Extending an existing class
22 | - Subclassing methods of a parent class
23 | - Defining static methods
24 | - Subclassing built-ins
25 |
26 |
27 |
28 | {% include output_helper.html %}
29 |
30 | {% include js_snippet.html filename='demo.js' %}
31 |
--------------------------------------------------------------------------------
/image-capture/background-blur.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: Image Capture / Control Camera Background Blur
3 | chrome_version: 106
4 | feature_id: 5077577782263808
5 | local_css_files: ['background-blur.css']
6 | check_min_version: true
7 | index: index.html
8 | origin_trial: AnfKCMTULZHC0KSWjw9Pv9s7yQQin85gn6RM2b/t9OXz7FMNXQR1yDcxykZZ2yTMEtidMwyOMo29e8cqiC875QMAAABqeyJvcmlnaW4iOiJodHRwczovL2dvb2dsZWNocm9tZS5naXRodWIuaW86NDQzIiwiZmVhdHVyZSI6Ik1lZGlhQ2FwdHVyZUJhY2tncm91bmRCbHVyIiwiZXhwaXJ5IjoxNjk4OTY5NTk5fQ==
9 | ---
10 |
11 | Background
12 | The ImageCapture Web API allows web developers to control the background blur
13 | of the camera.
14 | Note: Background Blur is still under development. You must be using Chrome
15 | with the chrome://flags/#enable-experimental-web-platform-features
16 | flag enabled.
17 |
18 |
19 |
20 |
21 | {% include output_helper.html %}
22 |
23 | {% include js_snippet.html filename='background-blur.js' %}
24 |
25 |
28 |
--------------------------------------------------------------------------------
/hdcp-detection/index.js:
--------------------------------------------------------------------------------
1 | function onButtonClick() {
2 | const minHdcpVersion = document.querySelector('#minHdcpVersion').value;
3 | const config = [{
4 | videoCapabilities: [{
5 | contentType: 'video/webm; codecs="vp09.00.10.08"',
6 | robustness: 'SW_SECURE_DECODE' // Widevine L3
7 | }]
8 | }];
9 |
10 | log('Requesting Widevine system access...');
11 | navigator.requestMediaKeySystemAccess('com.widevine.alpha', config)
12 | .then(mediaKeySystemAccess => mediaKeySystemAccess.createMediaKeys())
13 | .then(mediaKeys => {
14 | log('Getting HDCP status...');
15 | if (!('getStatusForPolicy' in mediaKeys)) {
16 | return Promise.reject('HDCP Policy Check API is not available.');
17 | }
18 |
19 | /* This is where the real magic happens... */
20 | return mediaKeys.getStatusForPolicy({ minHdcpVersion });
21 | })
22 | .then(status => {
23 | if (status !== 'usable') {
24 | return Promise.reject(status);
25 | }
26 |
27 | log('> HDCP is available for ' + minHdcpVersion);
28 | })
29 | .catch(error => {
30 | log('Argh! ' + error);
31 | });
32 | }
33 |
--------------------------------------------------------------------------------
/new-target-es6/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | feature_name: new.target
3 | chrome_version: 46
4 | feature_id: 5210159227863040
5 | ---
6 |
7 | Background
8 |
9 | The new.target
10 | value is part of the ES2015 (formerly known as ES6) specification, and can take one of two values:
11 |
12 |
13 | -
14 | Inside of a constructor,
new.target is set to a reference to the constructor that
15 | was used when calling new.
16 |
17 | -
18 | Inside of a normal function,
new.target is set to undefined.
19 |
20 |
21 |
22 | new.target is useful for distinguishing at runtime whether code is being executed as
23 | a constructor or as a function. It is also handy as a way to determine the specific subclass
24 | that was used with new from within a superclass constructor.
25 |
26 |
27 | {% include output_helper.html %}
28 |
29 | {% include js_snippet.html filename='demo.js' %}
30 |
--------------------------------------------------------------------------------
/picture-in-picture/css-pseudo-class.js:
--------------------------------------------------------------------------------
1 | togglePipButton.addEventListener('click', async function(event) {
2 | togglePipButton.disabled = true;
3 | try {
4 |
5 | if (video !== document.pictureInPictureElement)
6 | await video.requestPictureInPicture();
7 | else
8 | await document.exitPictureInPicture();
9 |
10 | } catch(error) {
11 | log(`> Argh! ${error}`);
12 | } finally {
13 | togglePipButton.disabled = false;
14 | }
15 | });
16 |
17 | /* Feature support */
18 |
19 | if ('pictureInPictureEnabled' in document) {
20 | // Set button ability depending on whether Picture-in-Picture can be used.
21 | setPipButton();
22 | video.addEventListener('loadedmetadata', setPipButton);
23 | video.addEventListener('emptied', setPipButton);
24 | } else {
25 | // Hide button if Picture-in-Picture is not supported.
26 | togglePipButton.hidden = true;
27 | }
28 |
29 | function setPipButton() {
30 | togglePipButton.disabled = (video.readyState === 0) ||
31 | !document.pictureInPictureEnabled ||
32 | video.disablePictureInPicture;
33 | }
34 |
--------------------------------------------------------------------------------
/web-share/src/svelte/components/Navbar.svelte:
--------------------------------------------------------------------------------
1 |
16 |
21 |
22 |
31 |
32 |
33 | {#each buttons as button}
34 |
35 | {/each}
36 |
37 |
--------------------------------------------------------------------------------
/variable-fonts-experiments/samples/SimpleSliderDemo/script.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2018 Google Inc. All Rights Reserved.
3 | Licensed under the Apache License, Version 2.0
4 | (the "License"); you may not use this file
5 | except in compliance with the License.
6 | You may obtain a copy of the License at
7 | http://www.apache.org/licenses/LICENSE-2.0
8 | Unless required by applicable law or agreed to
9 | in writing, software distributed under the License
10 | is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
12 | either express or implied.
13 | See the License for the specific language governing
14 | permissions and limitations under the License.
15 | Licensed under the Apache License,
16 | Version 2.0 (the "License");
17 | */
18 | 'use strict';
19 |
20 | window.addEventListener('load', function() {
21 |
22 | // init
23 | var textbox = document.querySelector('#textbox');
24 | var slider = document.querySelector('#slider');
25 |
26 | slider.addEventListener('input', function() {
27 |
28 | textbox.value = slider.value;
29 | console.log(textbox.value);
30 |
31 | });
32 |
33 | });
--------------------------------------------------------------------------------
/event-listeners-mandatory-arguments/demo.js:
--------------------------------------------------------------------------------
1 | ChromeSamples.log('Call document.body.addEventListener with no arguments.');
2 | try {
3 | document.body.addEventListener();
4 | } catch (error) {
5 | ChromeSamples.log('> ' + error.message + '\n');
6 | }
7 |
8 | ChromeSamples.log('Call document.body.addEventListener with one argument.');
9 | try {
10 | document.body.addEventListener('click');
11 | } catch (error) {
12 | ChromeSamples.log('> ' + error.message + '\n');
13 | }
14 |
15 | ChromeSamples.log('Call document.body.removeEventListener with no arguments.');
16 | try {
17 | document.body.removeEventListener();
18 | } catch (error) {
19 | ChromeSamples.log('> ' + error.message + '\n');
20 | }
21 |
22 | ChromeSamples.log('Call document.body.removeEventListener with one argument.');
23 | try {
24 | document.body.removeEventListener('click');
25 | } catch (error) {
26 | ChromeSamples.log('> ' + error.message + '\n');
27 | }
28 |
29 | // Example of valid usage:
30 | var handler = function() {
31 | // Do something.
32 | };
33 | document.body.addEventListener('click', handler);
34 | document.body.removeEventListener('click', handler);
35 |
--------------------------------------------------------------------------------
/variable-fonts-experiments/samples/SimpleSliderDemo/slider-test.html:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 | Simple Slider JS demo
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app-install-banner/related-applications/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "App Install Banner Sample",
3 | "short_name": "App Install Banner Sample",
4 | "icons": [
5 | {
6 | "src": "launcher-icon-0-75x.png",
7 | "sizes": "36x36",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "launcher-icon-1x.png",
12 | "sizes": "48x48",
13 | "type": "image/png"
14 | },
15 | {
16 | "src": "launcher-icon-1-5x.png",
17 | "sizes": "72x72",
18 | "type": "image/png"
19 | },
20 | {
21 | "src": "launcher-icon-2x.png",
22 | "sizes": "96x96",
23 | "type": "image/png"
24 | },
25 | {
26 | "src": "launcher-icon-3x.png",
27 | "sizes": "144x144",
28 | "type": "image/png"
29 | },
30 | {
31 | "src": "launcher-icon-4x.png",
32 | "sizes": "192x192",
33 | "type": "image/png"
34 | }
35 | ],
36 | "prefer_related_applications": true,
37 | "related_applications": [
38 | {
39 | "platform": "play",
40 | "id": "com.google.samples.apps.iosched"
41 | }
42 | ],
43 | "start_url": "./index.html",
44 | "display": "standalone"
45 | }
46 |
--------------------------------------------------------------------------------
/intersectionobserver/demo.js:
--------------------------------------------------------------------------------
1 | /* global IntersectionObserver */
2 | var scroller = document.querySelector('#scroller');
3 | var sentinel = document.querySelector('#sentinel');
4 | var counter = 1;
5 |
6 | function loadItems(n) {
7 | for (var i = 0; i < n; i++) {
8 | var newItem = document.createElement('div');
9 | newItem.classList.add('item');
10 | newItem.textContent = 'Item ' + counter++;
11 | scroller.appendChild(newItem);
12 | }
13 | }
14 |
15 | var intersectionObserver = new IntersectionObserver(entries => {
16 | // If the browser is busy while scrolling happens, multiple entries can
17 | // accumulate between invocations of this callback. As long as any one
18 | // of the notifications reports the sentinel within the scrolling viewport,
19 | // we add more content.
20 | if (entries.some(entry => entry.intersectionRatio > 0)) {
21 | loadItems(10);
22 | // appendChild will move the existing element, so there is no need to
23 | // remove it first.
24 | scroller.appendChild(sentinel);
25 | loadItems(5);
26 | ChromeSamples.setStatus('Loaded up to item ' + counter);
27 | }
28 | });
29 | intersectionObserver.observe(sentinel);
30 |
--------------------------------------------------------------------------------
/web-share/src/svelte/components/Snackbar.svelte:
--------------------------------------------------------------------------------
1 |
16 |
19 |
20 |
38 |
39 |
40 | {message}
41 |
42 |
--------------------------------------------------------------------------------
/webaudio-method-chaining/demo.js:
--------------------------------------------------------------------------------
1 | // Handle cross-browser differences.
2 | var context;
3 | if (typeof AudioContext === 'function') {
4 | context = new AudioContext();
5 | } else if (typeof webkitAudioContext === 'function') {
6 | context = new webkitAudioContext();
7 | } else {
8 | ChromeSamples.setStatus('The Web Audio API is not supported in your browser');
9 | }
10 |
11 | if (context) {
12 | // Use the