diff --git a/amp.js b/amp.js index 76d16c21900c..b1bb5aeacd7e 100755 --- a/amp.js +++ b/amp.js @@ -36,7 +36,6 @@ createTask('check-renovate-config', 'checkRenovateConfig'); createTask('check-sourcemaps', 'checkSourcemaps'); createTask('check-types', 'checkTypes'); createTask('check-video-interface-list', 'checkVideoInterfaceList'); -createTask('cherry-pick', 'cherryPick'); createTask('clean'); createTask('codecov-upload', 'codecovUpload'); createTask('compile-jison', 'compileJison'); diff --git a/build-system/tasks/cherry-pick.js b/build-system/tasks/cherry-pick.js deleted file mode 100644 index 656ce2b86a85..000000000000 --- a/build-system/tasks/cherry-pick.js +++ /dev/null @@ -1,130 +0,0 @@ -'use strict'; - -const argv = require('minimist')(process.argv.slice(2)); -const {cyan, green, red, yellow} = require('kleur/colors'); -const {execOrThrow} = require('../common/exec'); -const {getOutput} = require('../common/process'); -const {log} = require('../common/logging'); - -/** - * Determines the name of the cherry-pick branch. - * - * @param {string} version - * @param {number} numCommits - * @return {string} - */ -function cherryPickBranchName(version, numCommits) { - const timestamp = version.slice(0, -3); - const suffixNumber = Number(version.slice(-3)) + numCommits; - const suffix = String(suffixNumber).padStart(3, '0'); - return `amp-release-${timestamp}${suffix}`; -} - -/** - * Updates tags from the remote and creates a branch at the release commit. - * - * @param {string} ref - * @param {string} branch - * @param {string} remote - */ -function prepareBranch(ref, branch, remote) { - log(green('INFO:'), 'Pulling latest from', cyan(remote)); - execOrThrow( - `git pull ${remote}`, - `Failed to pull latest from remote ${cyan(remote)}` - ); - - execOrThrow( - `git checkout -b ${branch} ${ref}`, - `Failed to checkout new branch at ref ${cyan(ref)}` - ); -} - -/** - * Cherry-picks a commit into a new branch. When the cherry-pick succeeds, - * returns `true`. In the event of a merge conflict, the cherry-pick is aborted - * and an error is thrown. - * - * @param {string} sha - */ -function performCherryPick(sha) { - try { - log(green('INFO:'), 'Cherry-picking commit', cyan(sha)); - execOrThrow( - `git cherry-pick -x ${sha}`, - `Failed to cherry-pick commit ${cyan(sha)}; aborting` - ); - } catch (e) { - log(green('INFO:'), 'Aborting cherry-pick of commit', cyan(sha)); - getOutput(`git cherry-pick --abort`); - throw e; - } -} - -/** - * @return {Promise} - */ -async function cherryPick() { - const {push, remote = 'origin'} = argv; - const commits = (argv.commits || '').split(',').filter(Boolean); - let onto = String(argv.onto || ''); - - if (!commits.length) { - throw new Error('Must provide commit list with --commits'); - } - if (!onto) { - throw new Error('Must provide 13-digit AMP version with --onto'); - } - if (onto.length === 15) { - log( - yellow('WARNING:'), - 'Expected a 13-digit AMP version but got a 15-digit RTV;', - 'ignoring channel prefix' - ); - // Be forgiving if someone provides a version instead of a full RTV. - onto = onto.substr(2); - } - if (onto.length !== 13) { - throw new Error('Expected 13-digit AMP version'); - } - - const branch = cherryPickBranchName(onto, commits.length); - try { - prepareBranch(onto, branch, remote); - commits.forEach(performCherryPick); - - if (push) { - log( - green('INFO:'), - 'Pushing branch', - cyan(branch), - 'to remote', - cyan(remote) - ); - execOrThrow( - `git push --set-upstream ${remote} ${branch}`, - `Failed to push branch ${cyan(branch)} to remote ${cyan(remote)}` - ); - } - - log( - green('SUCCESS:'), - `Cherry-picked ${commits.length} commits onto release ${onto}` - ); - } catch (e) { - log(red('ERROR:'), e.message); - log('Deleting branch', cyan(branch)); - getOutput(`git checkout main && git branch -d ${branch}`); - throw e; - } -} - -module.exports = {cherryPick}; - -cherryPick.description = 'Cherry-pick one or more commits onto a new branch'; -cherryPick.flags = { - 'commits': 'Comma-delimited list of commit SHAs to cherry-pick', - 'push': 'If set, push the created branch to the remote', - 'remote': 'Remote ref to refresh tags from (default: origin)', - 'onto': '13-digit AMP version to cherry-pick onto', -}; diff --git a/examples/amp-story/amp-story-shopping.html b/examples/amp-story/amp-story-shopping.html index b8ae1cdce669..39e5a0408b4c 100644 --- a/examples/amp-story/amp-story-shopping.html +++ b/examples/amp-story/amp-story-shopping.html @@ -114,7 +114,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." } ] } @@ -158,7 +158,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -173,7 +173,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -188,7 +188,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -204,7 +204,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." } ] } diff --git a/examples/amp-story/animations-presets.html b/examples/amp-story/animations-presets.html index 4e6142ba32d8..67564334ac0b 100644 --- a/examples/amp-story/animations-presets.html +++ b/examples/amp-story/animations-presets.html @@ -234,6 +234,23 @@

pan-up

pan-down

+ + + + +

pan-right

+

with pan-scaling-factor attr

+
+ + +
+
+
diff --git a/examples/amp-story/shopping/remote.json b/examples/amp-story/shopping/remote.json index c8b0e977ce4c..648f6c0bf5ef 100644 --- a/examples/amp-story/shopping/remote.json +++ b/examples/amp-story/shopping/remote.json @@ -18,7 +18,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto exped. Laborum ea molestias veritatis sint laudantium iusto exped." } ] } diff --git a/examples/amp-story/video/ecommerce.vtt b/examples/amp-story/video/ecommerce.vtt index 62a45a19b50d..bad4b6a1fe91 100644 --- a/examples/amp-story/video/ecommerce.vtt +++ b/examples/amp-story/video/ecommerce.vtt @@ -1,20 +1,20 @@ WEBVTT 00:00.000 --> 00:00.500 -(Lisa Wang) -I'm Lisa. +(Lisa Wang) +I'm Lisa. 00:00.500 --> 00:02.000 -I'm a product manager at Google. +I'm a product manager at Google. 00:02.000 --> 00:04.500 -And I lead our e-commerce initiatives. +And I lead our e-commerce initiatives. 00:04.500 --> 00:05.500 -And today I'm just going to walk +And today I'm just going to walk 00:05.500 --> 00:07.500 -through some of our best practices +through some of our best practices 00:07.500 --> 00:10.000 -for building e-commerce experiences in AMP. +for building e-commerce experiences in AMP. diff --git a/examples/amp-story/video/gmail.vtt b/examples/amp-story/video/gmail.vtt index a3d658f8dfee..8fab2f583db8 100644 --- a/examples/amp-story/video/gmail.vtt +++ b/examples/amp-story/video/gmail.vtt @@ -1,23 +1,23 @@ WEBVTT 00:00.000 --> 00:01.500 -(Aakash Sahney) -and I'm really excited to share more +(Aakash Sahney) +and I'm really excited to share more 00:01.500 --> 00:03.500 -about the announcement we made earlier today, +about the announcement we made earlier today, 00:03.500 --> 00:06.000 -which is like a whole new way to use AMP. +which is like a whole new way to use AMP. 00:06.000 --> 00:08.500 -We're going to talk about what's possible with AMP for email, +We're going to talk about what's possible with AMP for email, 00:08.500 --> 00:11.000 -show off some super slick demos from the three partners +show off some super slick demos from the three partners 00:11.000 --> 00:13.500 -that Paul just mentioned, and tell you a bit about how +that Paul just mentioned, and tell you a bit about how 00:13.500 --> 00:15.000 -you can get started. \ No newline at end of file +you can get started. \ No newline at end of file diff --git a/examples/amp-story/video/p1.vtt b/examples/amp-story/video/p1.vtt index 71ae951c12eb..a9acfc67004c 100644 --- a/examples/amp-story/video/p1.vtt +++ b/examples/amp-story/video/p1.vtt @@ -3,33 +3,33 @@ WEBVTT NOTE Malte Ubl on AMP stories 00:00.000 --> 00:02.500 -(Malte Ubl) -...and there's going to be surfacing of these stories +(Malte Ubl) +...and there's going to be surfacing of these stories 00:02.500 --> 00:04.000 -(Malte Ubl) -in Google Search. +(Malte Ubl) +in Google Search. NOTE Lisa Wang on AMP Toolbox Optimizer 00:04.500 --> 00:06.000 -(Lisa Wang) -So I'm also really excited to announce today +(Lisa Wang) +So I'm also really excited to announce today 00:06.000 --> 00:09.000 -(Lisa Wang) -that we're releasing the AMP Toolbox Optimizer, which +(Lisa Wang) +that we're releasing the AMP Toolbox Optimizer, which 00:09.000 --> 00:12.000 -(Lisa Wang) -is basically a toolkit that developers can use to optimize... +(Lisa Wang) +is basically a toolkit that developers can use to optimize... NOTE Aakash Sahney on AMP for email 00:06.000 --> 00:08.500 -(Aakash Sahney) -So with AMP for email, users can quickly take actions on things +(Aakash Sahney) +So with AMP for email, users can quickly take actions on things 00:08.500 --> 00:11.000 -(Aakash Sahney) -like RSVP'ing to an event. +(Aakash Sahney) +like RSVP'ing to an event. diff --git a/examples/amp-story/video/stamp.vtt b/examples/amp-story/video/stamp.vtt index 2befa4794337..f4302f823ffc 100644 --- a/examples/amp-story/video/stamp.vtt +++ b/examples/amp-story/video/stamp.vtt @@ -1,26 +1,26 @@ WEBVTT 00:00.000 --> 00:02.000 -(Jon Newmuis) -So today, we're excited to announce the developer +(Jon Newmuis) +So today, we're excited to announce the developer 00:02.000 --> 00:06.000 -preview of AMP stories, an open format for visual storytelling +preview of AMP stories, an open format for visual storytelling 00:06.000 --> 00:09.000 -on mobile. +on mobile. 00:09.000 --> 00:12.500 -To demonstrate, here's a story by CNN using the format. +To demonstrate, here's a story by CNN using the format. 00:12.500 --> 00:16.500 -As you can see, it's very visual with these full bleed images. +As you can see, it's very visual with these full bleed images. 00:16.500 --> 00:19.000 -And you can also include video assets as well. +And you can also include video assets as well. 00:19.000 --> 00:22.000 -The short-form bite-sized text is more easily +The short-form bite-sized text is more easily 00:22.000 --> 00:24.000 -consumable on mobile. \ No newline at end of file +consumable on mobile. \ No newline at end of file diff --git a/examples/visual-tests/amp-story/amp-story-shopping-landscape.html b/examples/visual-tests/amp-story/amp-story-shopping-landscape.html index 2756df0da95e..373b17992f9f 100644 --- a/examples/visual-tests/amp-story/amp-story-shopping-landscape.html +++ b/examples/visual-tests/amp-story/amp-story-shopping-landscape.html @@ -89,7 +89,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -164,7 +164,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -179,7 +179,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -194,7 +194,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -210,7 +210,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." } ] } diff --git a/examples/visual-tests/amp-story/amp-story-shopping-lang-de.html b/examples/visual-tests/amp-story/amp-story-shopping-lang-de.html index 9fa02b9ec607..5db508b1a9cf 100644 --- a/examples/visual-tests/amp-story/amp-story-shopping-lang-de.html +++ b/examples/visual-tests/amp-story/amp-story-shopping-lang-de.html @@ -119,7 +119,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." } ] } @@ -163,7 +163,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -178,7 +178,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -193,7 +193,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -209,7 +209,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." } ] } diff --git a/examples/visual-tests/amp-story/amp-story-shopping-rtl.html b/examples/visual-tests/amp-story/amp-story-shopping-rtl.html index 81bbd4277314..72f657c1dc3d 100644 --- a/examples/visual-tests/amp-story/amp-story-shopping-rtl.html +++ b/examples/visual-tests/amp-story/amp-story-shopping-rtl.html @@ -119,7 +119,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." } ] } @@ -163,7 +163,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -178,7 +178,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -193,7 +193,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -209,7 +209,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." } ] } diff --git a/examples/visual-tests/amp-story/amp-story-shopping.html b/examples/visual-tests/amp-story/amp-story-shopping.html index 9d1e33820bd6..ca5ba3ea1055 100644 --- a/examples/visual-tests/amp-story/amp-story-shopping.html +++ b/examples/visual-tests/amp-story/amp-story-shopping.html @@ -86,7 +86,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -161,7 +161,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -176,7 +176,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -191,7 +191,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." }, { "productUrl": "https://www.google.com", @@ -207,7 +207,7 @@ "reviewCount": 89, "reviewUrl": "https://www.google.com" }, - "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." + "productDetails": "Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci." } ] } diff --git a/extensions/amp-story-auto-ads/0.1/amp-story-auto-ads.js b/extensions/amp-story-auto-ads/0.1/amp-story-auto-ads.js index fea2d406e9f8..b4bf2ffae551 100644 --- a/extensions/amp-story-auto-ads/0.1/amp-story-auto-ads.js +++ b/extensions/amp-story-auto-ads/0.1/amp-story-auto-ads.js @@ -23,7 +23,7 @@ import {CSS as sharedCSS} from '../../../build/amp-story-auto-ads-shared-0.1.css import {getServicePromiseForDoc} from '../../../src/service-helpers'; import { StateProperty, - UIType, + UIType_Enum, } from '../../amp-story/1.0/amp-story-store-service'; import {EventType, dispatch} from '../../amp-story/1.0/events'; import {createShadowRootWithStyle} from '../../amp-story/1.0/utils'; @@ -324,7 +324,7 @@ export class AmpStoryAutoAds extends AMP.BaseElement { /** * Reacts to UI state updates and passes the information along as * attributes to the shadowed ad badge. - * @param {!UIType} uiState + * @param {!UIType_Enum} uiState * @private */ onUIStateUpdate_(uiState) { @@ -333,10 +333,10 @@ export class AmpStoryAutoAds extends AMP.BaseElement { this.adBadgeContainer_.removeAttribute(DESKTOP_FULLBLEED); this.adBadgeContainer_.removeAttribute(DESKTOP_ONE_PANEL); - if (uiState === UIType.DESKTOP_FULLBLEED) { + if (uiState === UIType_Enum.DESKTOP_FULLBLEED) { this.adBadgeContainer_.setAttribute(DESKTOP_FULLBLEED, ''); } - if (uiState === UIType.DESKTOP_ONE_PANEL) { + if (uiState === UIType_Enum.DESKTOP_ONE_PANEL) { this.adBadgeContainer_.setAttribute(DESKTOP_ONE_PANEL, ''); } }); diff --git a/extensions/amp-story-auto-ads/0.1/story-ad-page.js b/extensions/amp-story-auto-ads/0.1/story-ad-page.js index ee5b21b39e85..ba286bdaa9e8 100644 --- a/extensions/amp-story-auto-ads/0.1/story-ad-page.js +++ b/extensions/amp-story-auto-ads/0.1/story-ad-page.js @@ -38,7 +38,7 @@ import {getServicePromiseForDoc} from '../../../src/service-helpers'; import {assertConfig} from '../../amp-ad-exit/0.1/config'; import { StateProperty, - UIType, + UIType_Enum, } from '../../amp-story/1.0/amp-story-store-service'; /** @const {string} */ @@ -499,7 +499,7 @@ export class StoryAdPage { /** * Reacts to UI state updates and passes the information along as * attributes to the shadowed attribution icon. - * @param {!UIType} uiState + * @param {!UIType_Enum} uiState * @private */ onUIStateUpdate_(uiState) { @@ -509,7 +509,7 @@ export class StoryAdPage { this.adChoicesIcon_.classList.toggle( DESKTOP_FULLBLEED_CLASS, - uiState === UIType.DESKTOP_FULLBLEED + uiState === UIType_Enum.DESKTOP_FULLBLEED ); } diff --git a/extensions/amp-story-auto-ads/0.1/test/test-amp-story-auto-ads.js b/extensions/amp-story-auto-ads/0.1/test/test-amp-story-auto-ads.js index daede73ac3c5..3c1a98f114fc 100644 --- a/extensions/amp-story-auto-ads/0.1/test/test-amp-story-auto-ads.js +++ b/extensions/amp-story-auto-ads/0.1/test/test-amp-story-auto-ads.js @@ -19,7 +19,7 @@ import {NavigationDirection} from '../../../amp-story/1.0/amp-story-page'; import { Action, StateProperty, - UIType, + UIType_Enum, getStoreService, } from '../../../amp-story/1.0/amp-story-store-service'; import * as storyEvents from '../../../amp-story/1.0/events'; @@ -399,11 +399,11 @@ describes.realWin( const adBadgeContainer = doc.querySelector( '.i-amphtml-ad-overlay-container' ); - storeService.dispatch(Action.TOGGLE_UI, UIType.MOBILE); + storeService.dispatch(Action.TOGGLE_UI, UIType_Enum.MOBILE); expect(adBadgeContainer).not.to.have.attribute( Attributes.DESKTOP_ONE_PANEL ); - storeService.dispatch(Action.TOGGLE_UI, UIType.DESKTOP_ONE_PANEL); + storeService.dispatch(Action.TOGGLE_UI, UIType_Enum.DESKTOP_ONE_PANEL); expect(adBadgeContainer).to.have.attribute( Attributes.DESKTOP_ONE_PANEL ); diff --git a/extensions/amp-story-auto-ads/0.1/test/test-story-ad-page.js b/extensions/amp-story-auto-ads/0.1/test/test-story-ad-page.js index e11f4e458e1d..408292813c1e 100644 --- a/extensions/amp-story-auto-ads/0.1/test/test-story-ad-page.js +++ b/extensions/amp-story-auto-ads/0.1/test/test-story-ad-page.js @@ -7,7 +7,7 @@ import * as openWindowDialog from '../../../../src/open-window-dialog'; import * as service from '../../../../src/service-helpers'; import { Action, - UIType, + UIType_Enum, getStoreService, } from '../../../amp-story/1.0/amp-story-store-service'; import {StoryAdAnalytics} from '../story-ad-analytics'; @@ -389,7 +389,7 @@ describes.realWin('story-ad-page', {amp: true}, (env) => { }); it('propagates fullbleed state to attribution icon', async () => { - storeService.dispatch(Action.TOGGLE_UI, UIType.DESKTOP_FULLBLEED); + storeService.dispatch(Action.TOGGLE_UI, UIType_Enum.DESKTOP_FULLBLEED); const iframe = doc.createElement('iframe'); ampAdElement.appendChild(iframe); @@ -407,10 +407,10 @@ describes.realWin('story-ad-page', {amp: true}, (env) => { const attribution = doc.querySelector('.i-amphtml-story-ad-attribution'); expect(attribution).to.have.class('i-amphtml-story-ad-fullbleed'); - storeService.dispatch(Action.TOGGLE_UI, UIType.MOBILE); + storeService.dispatch(Action.TOGGLE_UI, UIType_Enum.MOBILE); expect(attribution).not.to.have.class('i-amphtml-story-ad-fullbleed'); - storeService.dispatch(Action.TOGGLE_UI, UIType.DESKTOP_FULLBLEED); + storeService.dispatch(Action.TOGGLE_UI, UIType_Enum.DESKTOP_FULLBLEED); expect(attribution).to.have.class('i-amphtml-story-ad-fullbleed'); }); diff --git a/extensions/amp-story-education/0.1/amp-story-education.js b/extensions/amp-story-education/0.1/amp-story-education.js index 3904eb79fbbd..4a5fda88e805 100644 --- a/extensions/amp-story-education/0.1/amp-story-education.js +++ b/extensions/amp-story-education/0.1/amp-story-education.js @@ -17,7 +17,7 @@ import { import { Action, StateProperty, - UIType, + UIType_Enum, } from '../../amp-story/1.0/amp-story-store-service'; import {createShadowRootWithStyle} from '../../amp-story/1.0/utils'; @@ -96,7 +96,7 @@ export class AmpStoryEducation extends AMP.BaseElement { this.viewer_ = Services.viewerForDoc(this.element); const isMobileUI = - this.storeService_.get(StateProperty.UI_STATE) === UIType.MOBILE; + this.storeService_.get(StateProperty.UI_STATE) === UIType_Enum.MOBILE; if (this.viewer_.isEmbedded() && isMobileUI) { const screen = this.viewer_.hasCapability('swipe') ? Screen.ONBOARDING_NAVIGATION_TAP_AND_SWIPE diff --git a/extensions/amp-story-page-attachment/0.1/amp-story-draggable-drawer.js b/extensions/amp-story-page-attachment/0.1/amp-story-draggable-drawer.js index 16c35276dd62..94a407b8ebba 100644 --- a/extensions/amp-story-page-attachment/0.1/amp-story-draggable-drawer.js +++ b/extensions/amp-story-page-attachment/0.1/amp-story-draggable-drawer.js @@ -18,7 +18,7 @@ import {CSS} from '../../../build/amp-story-draggable-drawer-header-0.1.css'; import { Action, StateProperty, - UIType, + UIType_Enum, } from '../../amp-story/1.0/amp-story-store-service'; import {createShadowRootWithStyle} from '../../amp-story/1.0/utils'; @@ -242,11 +242,11 @@ export class DraggableDrawer extends AMP.BaseElement { /** * Reacts to UI state updates. - * @param {!UIType} uiState + * @param {!UIType_Enum} uiState * @protected */ onUIStateUpdate_(uiState) { - const isMobile = uiState === UIType.MOBILE; + const isMobile = uiState === UIType_Enum.MOBILE; isMobile ? this.startListeningForTouchEvents_() : this.stopListeningForTouchEvents_(); diff --git a/extensions/amp-story-page-attachment/0.1/amp-story-page-attachment.js b/extensions/amp-story-page-attachment/0.1/amp-story-page-attachment.js index be9fb43e7671..7d53de1d46db 100644 --- a/extensions/amp-story-page-attachment/0.1/amp-story-page-attachment.js +++ b/extensions/amp-story-page-attachment/0.1/amp-story-page-attachment.js @@ -29,7 +29,7 @@ import {getSourceOrigin} from '../../../src/url'; import { Action, StateProperty, - UIType, + UIType_Enum, } from '../../amp-story/1.0/amp-story-store-service'; import {HistoryState, setHistoryState} from '../../amp-story/1.0/history'; import {StoryAnalyticsEvent} from '../../amp-story/1.0/story-analytics'; @@ -464,7 +464,7 @@ export class AmpStoryPageAttachment extends DraggableDrawer { }; const isMobileUI = - this.storeService.get(StateProperty.UI_STATE) === UIType.MOBILE; + this.storeService.get(StateProperty.UI_STATE) === UIType_Enum.MOBILE; if (!isMobileUI) { programaticallyClickOnTarget(); } else { diff --git a/extensions/amp-story-page-attachment/0.1/test/test-amp-story-page-attachment.js b/extensions/amp-story-page-attachment/0.1/test/test-amp-story-page-attachment.js index a40424e446a3..f7a785947575 100644 --- a/extensions/amp-story-page-attachment/0.1/test/test-amp-story-page-attachment.js +++ b/extensions/amp-story-page-attachment/0.1/test/test-amp-story-page-attachment.js @@ -9,7 +9,7 @@ import {LocalizationService} from '#service/localization'; import { Action, AmpStoryStoreService, - UIType, + UIType_Enum, } from 'extensions/amp-story/1.0/amp-story-store-service'; import {registerServiceBuilder} from 'src/service-helpers'; @@ -135,7 +135,7 @@ describes.realWin('amp-story-page-attachment', {amp: true}, (env) => { }); it('should click on anchor when outlink open method is called', async () => { - storeService.dispatch(Action.TOGGLE_UI, UIType.DESKTOP_ONE_PANEL); + storeService.dispatch(Action.TOGGLE_UI, UIType_Enum.DESKTOP_ONE_PANEL); const anchorEl = outlinkEl.querySelector('amp-story-page-outlink a'); const clickSpy = env.sandbox.spy(anchorEl, 'click'); diff --git a/extensions/amp-story-share-menu/0.1/amp-story-share-menu.js b/extensions/amp-story-share-menu/0.1/amp-story-share-menu.js index 52897e082b40..0d9eab8e1f41 100644 --- a/extensions/amp-story-share-menu/0.1/amp-story-share-menu.js +++ b/extensions/amp-story-share-menu/0.1/amp-story-share-menu.js @@ -24,7 +24,7 @@ import {getAmpdoc} from '../../../src/service-helpers'; import { Action, StateProperty, - UIType, + UIType_Enum, } from '../../amp-story/1.0/amp-story-store-service'; import { createShadowRootWithStyle, @@ -158,12 +158,12 @@ export class AmpStoryShareMenu extends AMP.BaseElement { /** * Reacts to UI state updates and triggers the right UI. - * @param {!UIType} uiState + * @param {!UIType_Enum} uiState * @private */ onUIStateUpdate_(uiState) { this.vsync_.mutate(() => { - uiState !== UIType.MOBILE + uiState !== UIType_Enum.MOBILE ? this.rootEl_.setAttribute('desktop', '') : this.rootEl_.removeAttribute('desktop'); }); diff --git a/extensions/amp-story-shopping/0.1/amp-story-shopping-attachment.js b/extensions/amp-story-shopping/0.1/amp-story-shopping-attachment.js index e6802fee2111..37de3572649e 100644 --- a/extensions/amp-story-shopping/0.1/amp-story-shopping-attachment.js +++ b/extensions/amp-story-shopping/0.1/amp-story-shopping-attachment.js @@ -36,6 +36,12 @@ const FONTS_TO_LOAD = [ }, ]; +/** + * @const {number} + * Max amount of characters for the product details text section. + */ +const MAX_PRODUCT_DETAILS_TEXT_LENGTH = 3000; + export class AmpStoryShoppingAttachment extends AMP.BaseElement { /** @param {!AmpElement} element */ constructor(element) { @@ -448,9 +454,19 @@ export class AmpStoryShoppingAttachment extends AMP.BaseElement { class="i-amphtml-amp-story-shopping-pdp-details-text" aria-hidden="true" > - {activeProductData.productDetails - // Replaces two newlines with 0 or more spaces between them with two newlines. - .replace(/\n\s*\n/g, '\n\n')} + { + // Add ellipses if product details text is greater than max. + (activeProductData.productDetails.length > + MAX_PRODUCT_DETAILS_TEXT_LENGTH + ? activeProductData.productDetails.slice( + 0, + MAX_PRODUCT_DETAILS_TEXT_LENGTH + ) + '...' + : activeProductData.productDetails + ) + // Replaces two newlines with 0 or more spaces between them with two newlines. + .replace(/\n\s*\n/g, '\n\n') + } )} diff --git a/extensions/amp-story-shopping/0.1/test/test-amp-story-shopping-config.js b/extensions/amp-story-shopping/0.1/test/test-amp-story-shopping-config.js index f7706bfe1732..63da5ac1ace5 100644 --- a/extensions/amp-story-shopping/0.1/test/test-amp-story-shopping-config.js +++ b/extensions/amp-story-shopping/0.1/test/test-amp-story-shopping-config.js @@ -57,7 +57,7 @@ describes.realWin( 'reviewUrl': 'https://www.google.com', }, 'productDetails': - 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci.', + 'Lorem ipsum dolor sit amet consectetur adipisicing elit. \n Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci.', }, { 'productUrl': 'https://www.google.com', @@ -73,7 +73,7 @@ describes.realWin( }, ], 'productDetails': - 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci.', + 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci.', }, ], }; @@ -142,7 +142,7 @@ describes.realWin( 'reviewUrl': 'https://www.google.com', }, 'productDetails': - 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci.', + 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto expedita atque provident doloremque, ad voluptatem culpa adipisci. \n\n Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere error deserunt dignissimos in laborum ea molestias veritatis sint laudantium iusto exped. Laborum ea molestias veritatis sint laudantium iusto exped.', }, }; env.sandbox.stub(Services, 'xhrFor').returns({ diff --git a/extensions/amp-story/1.0/amp-story-embedded-component.js b/extensions/amp-story/1.0/amp-story-embedded-component.js index 9c82d7dbcce0..a0ba10680810 100644 --- a/extensions/amp-story/1.0/amp-story-embedded-component.js +++ b/extensions/amp-story/1.0/amp-story-embedded-component.js @@ -12,7 +12,7 @@ import { EmbeddedComponentState, InteractiveComponentDef, StateProperty, - UIType, + UIType_Enum, getStoreService, } from './amp-story-store-service'; import {EventType, dispatch} from './events'; @@ -387,17 +387,16 @@ export class AmpStoryEmbeddedComponent { /** * Reacts to desktop state updates and hides navigation buttons since we * already have in the desktop UI. - * @param {!UIType} uiState + * @param {!UIType_Enum} uiState * @private */ onUIStateUpdate_(uiState) { this.mutator_.mutateElement( dev().assertElement(this.focusedStateOverlay_), () => { - const isDesktop = [ - UIType.DESKTOP_FULLBLEED, - UIType.DESKTOP_ONE_PANEL, - ].includes(uiState); + const isDesktop = + uiState === UIType_Enum.DESKTOP_FULLBLEED || + uiState === UIType_Enum.DESKTOP_ONE_PANEL; toggleAttribute(this.focusedStateOverlay_, 'desktop', isDesktop); } ); diff --git a/extensions/amp-story/1.0/amp-story-hint.js b/extensions/amp-story/1.0/amp-story-hint.js index 65f17f6751d7..62b4c9be30b9 100644 --- a/extensions/amp-story/1.0/amp-story-hint.js +++ b/extensions/amp-story/1.0/amp-story-hint.js @@ -7,7 +7,7 @@ import {localizeTemplate} from './amp-story-localization-service'; import { EmbeddedComponentState, StateProperty, - UIType, + UIType_Enum, getStoreService, } from './amp-story-store-service'; import {createShadowRootWithStyle} from './utils'; @@ -148,7 +148,7 @@ export class AmpStoryHint { * @private */ showHint_(hintClass) { - if (this.storeService_.get(StateProperty.UI_STATE) !== UIType.MOBILE) { + if (this.storeService_.get(StateProperty.UI_STATE) !== UIType_Enum.MOBILE) { return; } diff --git a/extensions/amp-story/1.0/amp-story-page.js b/extensions/amp-story/1.0/amp-story-page.js index 48a5ba39b194..bbbe298ae153 100644 --- a/extensions/amp-story/1.0/amp-story-page.js +++ b/extensions/amp-story/1.0/amp-story-page.js @@ -37,7 +37,7 @@ import {localizeTemplate} from './amp-story-localization-service'; import { Action, StateProperty, - UIType, + UIType_Enum, getStoreService, } from './amp-story-store-service'; import {AnimationManager, hasAnimations} from './animation'; @@ -553,12 +553,12 @@ export class AmpStoryPage extends AMP.BaseElement { /** * Reacts to UI state updates. - * @param {!UIType} uiState + * @param {!UIType_Enum} uiState * @private */ onUIStateUpdate_(uiState) { // On vertical rendering, render all the animations with their final state. - if (uiState === UIType.VERTICAL) { + if (uiState === UIType_Enum.VERTICAL) { this.maybeFinishAnimations_(); } } diff --git a/extensions/amp-story/1.0/amp-story-store-service.js b/extensions/amp-story/1.0/amp-story-store-service.js index ed38bab99ac6..91d00de2a01c 100644 --- a/extensions/amp-story/1.0/amp-story-store-service.js +++ b/extensions/amp-story/1.0/amp-story-store-service.js @@ -38,7 +38,7 @@ export const getStoreService = (win) => { * Different UI experiences to display the story. * @const @enum {number} */ -export const UIType = { +export const UIType_Enum = { MOBILE: 0, DESKTOP_FULLBLEED: 2, // Desktop UI if landscape mode is enabled. DESKTOP_ONE_PANEL: 4, // Desktop UI with one panel and space around story. @@ -137,7 +137,7 @@ export let ShoppingDataDef; * storyHasPlaybackUiState: boolean, * storyHasBackgroundAudioState: boolean, * systemUiIsVisibleState: boolean, - * uiState: !UIType, + * uiState: !UIType_Enum, * viewportWarningState: boolean, * actionsAllowlist: !Array<{tagOrTarget: string, method: string}>, * consentId: ?string, @@ -410,10 +410,10 @@ const actions = (state, action, data) => { }); case Action.TOGGLE_UI: if ( - state[StateProperty.UI_STATE] === UIType.VERTICAL && - data !== UIType.VERTICAL + state[StateProperty.UI_STATE] === UIType_Enum.VERTICAL && + data !== UIType_Enum.VERTICAL ) { - dev().error(TAG, 'Cannot switch away from UIType.VERTICAL'); + dev().error(TAG, 'Cannot switch away from UIType_Enum.VERTICAL'); return state; } return /** @type {!State} */ ({ @@ -596,7 +596,7 @@ export class AmpStoryStoreService { [StateProperty.STORY_HAS_BACKGROUND_AUDIO_STATE]: false, [StateProperty.STORY_HAS_PLAYBACK_UI_STATE]: false, [StateProperty.SYSTEM_UI_IS_VISIBLE_STATE]: true, - [StateProperty.UI_STATE]: UIType.MOBILE, + [StateProperty.UI_STATE]: UIType_Enum.MOBILE, // amp-story only allows actions on a case-by-case basis to preserve UX // behaviors. By default, no actions are allowed. [StateProperty.ACTIONS_ALLOWLIST]: [], diff --git a/extensions/amp-story/1.0/amp-story-system-layer.js b/extensions/amp-story/1.0/amp-story-system-layer.js index 786ad36fc8a7..85cdd1921aa6 100644 --- a/extensions/amp-story/1.0/amp-story-system-layer.js +++ b/extensions/amp-story/1.0/amp-story-system-layer.js @@ -13,7 +13,7 @@ import {localizeTemplate} from './amp-story-localization-service'; import { Action, StateProperty, - UIType, + UIType_Enum, getStoreService, } from './amp-story-store-service'; import {AmpStoryViewerMessagingHandler} from './amp-story-viewer-messaging-handler'; @@ -656,7 +656,7 @@ export class SystemLayer { /** * Reacts to UI state updates and triggers the expected UI. * Called inside a mutate context if not initializing. - * @param {!UIType} uiState + * @param {!UIType_Enum} uiState * @private */ onUIStateUpdate_(uiState) { @@ -667,11 +667,11 @@ export class SystemLayer { shadowRoot.removeAttribute('desktop'); switch (uiState) { - case UIType.DESKTOP_FULLBLEED: + case UIType_Enum.DESKTOP_FULLBLEED: shadowRoot.setAttribute('desktop', ''); shadowRoot.classList.add('i-amphtml-story-desktop-fullbleed'); break; - case UIType.DESKTOP_ONE_PANEL: + case UIType_Enum.DESKTOP_ONE_PANEL: shadowRoot.classList.add('i-amphtml-story-desktop-one-panel'); break; } diff --git a/extensions/amp-story/1.0/amp-story.js b/extensions/amp-story/1.0/amp-story.js index 800640e0510b..5dd1212e8d5c 100644 --- a/extensions/amp-story/1.0/amp-story.js +++ b/extensions/amp-story/1.0/amp-story.js @@ -97,7 +97,7 @@ import { InteractiveComponentDef, StateProperty, SubscriptionsState, - UIType, + UIType_Enum, getStoreService, } from './amp-story-store-service'; import {SystemLayer} from './amp-story-system-layer'; @@ -109,7 +109,7 @@ import {isPreviewMode} from './embed-mode'; import {EventType, dispatch} from './events'; import {HistoryState, getHistoryState, setHistoryState} from './history'; import {LiveStoryManager} from './live-story-manager'; -import {MediaPool, MediaType} from './media-pool'; +import {MediaPool, MediaType_Enum} from './media-pool'; import {AdvancementConfig, TapNavigationDirection} from './page-advancement'; import {PaginationButtons} from './pagination-buttons'; import { @@ -186,8 +186,8 @@ const STORY_LOADED_CLASS_NAME = 'i-amphtml-story-loaded'; /** @const {!Object} */ const MAX_MEDIA_ELEMENT_COUNTS = { - [MediaType.AUDIO]: 4, - [MediaType.VIDEO]: 8, + [MediaType_Enum.AUDIO]: 4, + [MediaType_Enum.VIDEO]: 8, }; /** @@ -310,7 +310,7 @@ export class AmpStory extends AMP.BaseElement { /** @private {?BackgroundBlur} */ this.backgroundBlur_ = null; - /** @private {?UIType} */ + /** @private {?UIType_Enum} */ this.uiState_ = null; /** @private {boolean} whether the styles were rewritten */ @@ -746,7 +746,7 @@ export class AmpStory extends AMP.BaseElement { this.win.document.addEventListener('contextmenu', (e) => { const uiState = this.storeService_.get(StateProperty.UI_STATE); - if (uiState === UIType.MOBILE) { + if (uiState === UIType_Enum.MOBILE) { if (!this.allowContextMenuOnMobile_(e.target)) { e.preventDefault(); } @@ -1687,14 +1687,14 @@ export class AmpStory extends AMP.BaseElement { /** * Reacts to UI state updates. - * @param {!UIType} uiState + * @param {!UIType_Enum} uiState * @private */ onUIStateUpdate_(uiState) { this.backgroundBlur_?.detach(); this.backgroundBlur_ = null; switch (uiState) { - case UIType.MOBILE: + case UIType_Enum.MOBILE: this.vsync_.mutate(() => { this.win.document.documentElement.setAttribute( 'i-amphtml-story-mobile', @@ -1705,7 +1705,7 @@ export class AmpStory extends AMP.BaseElement { this.element.classList.remove('i-amphtml-story-desktop-one-panel'); }); break; - case UIType.DESKTOP_ONE_PANEL: + case UIType_Enum.DESKTOP_ONE_PANEL: if (!this.backgroundBlur_) { this.backgroundBlur_ = new BackgroundBlur(this.win, this.element); this.backgroundBlur_.attach(); @@ -1723,7 +1723,7 @@ export class AmpStory extends AMP.BaseElement { this.element.classList.remove('i-amphtml-story-desktop-fullbleed'); }); break; - case UIType.DESKTOP_FULLBLEED: + case UIType_Enum.DESKTOP_FULLBLEED: this.vsync_.mutate(() => { this.win.document.documentElement.removeAttribute( 'i-amphtml-story-mobile' @@ -1735,7 +1735,7 @@ export class AmpStory extends AMP.BaseElement { break; // Because of the DOM mutations, switching from this mode to another is // not allowed, and prevented within the store service. - case UIType.VERTICAL: + case UIType_Enum.VERTICAL: const pageAttachments = scopedQuerySelectorAll( this.element, 'amp-story-page amp-story-page-attachment' @@ -1781,12 +1781,12 @@ export class AmpStory extends AMP.BaseElement { /** * Retrieves the UI type that should be used to view the story. - * @return {!UIType} + * @return {!UIType_Enum} * @private */ getUIType_() { if ( - this.uiState_ === UIType.MOBILE && + this.uiState_ === UIType_Enum.MOBILE && this.androidSoftKeyboardIsProbablyOpen_() ) { // The opening of the Android soft keyboard triggers a viewport resize @@ -1794,23 +1794,23 @@ export class AmpStory extends AMP.BaseElement { // desktop. Here, we assume that the soft keyboard is open if the latest // UI state is mobile while an input element has focus, and we then // ensure that the UI type does not unintentionally alter. - return UIType.MOBILE; + return UIType_Enum.MOBILE; } if (this.platform_.isBot()) { - return UIType.VERTICAL; + return UIType_Enum.VERTICAL; } if (!this.isDesktop_()) { - return UIType.MOBILE; + return UIType_Enum.MOBILE; } if (this.isLandscapeSupported_()) { - return UIType.DESKTOP_FULLBLEED; + return UIType_Enum.DESKTOP_FULLBLEED; } // Desktop one panel UI (default). - return UIType.DESKTOP_ONE_PANEL; + return UIType_Enum.DESKTOP_ONE_PANEL; } /** @@ -2188,13 +2188,13 @@ export class AmpStory extends AMP.BaseElement { } return { - [MediaType.AUDIO]: Math.min( + [MediaType_Enum.AUDIO]: Math.min( audioMediaElementsCount + MINIMUM_AD_MEDIA_ELEMENTS, - MAX_MEDIA_ELEMENT_COUNTS[MediaType.AUDIO] + MAX_MEDIA_ELEMENT_COUNTS[MediaType_Enum.AUDIO] ), - [MediaType.VIDEO]: Math.min( + [MediaType_Enum.VIDEO]: Math.min( videoMediaElementsCount + MINIMUM_AD_MEDIA_ELEMENTS, - MAX_MEDIA_ELEMENT_COUNTS[MediaType.VIDEO] + MAX_MEDIA_ELEMENT_COUNTS[MediaType_Enum.VIDEO] ), }; } diff --git a/extensions/amp-story/1.0/animation-presets.js b/extensions/amp-story/1.0/animation-presets.js index adb2522c4ddd..ac047ab8b7a9 100644 --- a/extensions/amp-story/1.0/animation-presets.js +++ b/extensions/amp-story/1.0/animation-presets.js @@ -23,6 +23,8 @@ const SCALE_START_ATTRIBUTE_NAME = 'scale-start'; /** @const {string} */ const SCALE_END_ATTRIBUTE_NAME = 'scale-end'; /** @const {string} */ +const PAN_SCALING_FACTOR_ATTRIBUTE_NAME = 'pan-scaling-factor'; +/** @const {string} */ const TRANSLATE_X_ATTRIBUTE_NAME = 'translate-x'; /** @const {string} */ const TRANSLATE_Y_ATTRIBUTE_NAME = 'translate-y'; @@ -33,6 +35,7 @@ const DEFAULT_CURVE = '0.4, 0.4, 0.0, 1'; export const PRESET_OPTION_ATTRIBUTES = [ SCALE_START_ATTRIBUTE_NAME, SCALE_END_ATTRIBUTE_NAME, + PAN_SCALING_FACTOR_ATTRIBUTE_NAME, TRANSLATE_X_ATTRIBUTE_NAME, TRANSLATE_Y_ATTRIBUTE_NAME, ]; @@ -285,7 +288,9 @@ export const presets = { easing: 'linear', keyframes(dimensions, options) { const translateX = options[TRANSLATE_X_ATTRIBUTE_NAME]; - const scalingFactor = calculateTargetScalingFactor(dimensions); + const scalingFactor = + options[PAN_SCALING_FACTOR_ATTRIBUTE_NAME] ?? + calculateTargetScalingFactor(dimensions); dimensions.targetWidth *= scalingFactor; dimensions.targetHeight *= scalingFactor; @@ -306,8 +311,9 @@ export const presets = { easing: 'linear', keyframes(dimensions, options) { const translateX = options[TRANSLATE_X_ATTRIBUTE_NAME]; - - const scalingFactor = calculateTargetScalingFactor(dimensions); + const scalingFactor = + options[PAN_SCALING_FACTOR_ATTRIBUTE_NAME] ?? + calculateTargetScalingFactor(dimensions); dimensions.targetWidth *= scalingFactor; dimensions.targetHeight *= scalingFactor; @@ -328,7 +334,9 @@ export const presets = { easing: 'linear', keyframes(dimensions, options) { const translateY = options[TRANSLATE_Y_ATTRIBUTE_NAME]; - const scalingFactor = calculateTargetScalingFactor(dimensions); + const scalingFactor = + options[PAN_SCALING_FACTOR_ATTRIBUTE_NAME] ?? + calculateTargetScalingFactor(dimensions); dimensions.targetWidth *= scalingFactor; dimensions.targetHeight *= scalingFactor; @@ -349,7 +357,9 @@ export const presets = { easing: 'linear', keyframes(dimensions, options) { const translateY = options[TRANSLATE_Y_ATTRIBUTE_NAME]; - const scalingFactor = calculateTargetScalingFactor(dimensions); + const scalingFactor = + options[PAN_SCALING_FACTOR_ATTRIBUTE_NAME] ?? + calculateTargetScalingFactor(dimensions); dimensions.targetWidth *= scalingFactor; dimensions.targetHeight *= scalingFactor; diff --git a/extensions/amp-story/1.0/media-pool.js b/extensions/amp-story/1.0/media-pool.js index 345e73cfd5d4..281093b1927f 100644 --- a/extensions/amp-story/1.0/media-pool.js +++ b/extensions/amp-story/1.0/media-pool.js @@ -26,9 +26,9 @@ import {ampMediaElementFor} from './utils'; import {userInteractedWith} from '../../../src/video-interface'; -/** @const @enum {string} */ -export const MediaType = { - UNSUPPORTED: 'unsupported', +/** @const @enum {string|number} */ +export const MediaType_Enum = { + UNSUPPORTED: 0, AUDIO: 'audio', VIDEO: 'video', }; @@ -120,7 +120,7 @@ let nextInstanceId = 0; export class MediaPool { /** * @param {!Window} win The window object. - * @param {!Object} maxCounts The maximum amount of each + * @param {!Object} maxCounts The maximum amount of each * media element that can be allocated by the pool. * @param {!ElementDistanceFnDef} distanceFn A function that, given an * element, returns the distance of that element from the current position @@ -143,14 +143,14 @@ export class MediaPool { /** * Holds all of the pool-bound media elements that have been allocated. - * @const {!Object>} + * @const {!Object>} * @visibleForTesting */ this.allocated = {}; /** * Holds all of the pool-bound media elements that have not been allocated. - * @const {!Object>} + * @const {!Object>} * @visibleForTesting */ this.unallocated = {}; @@ -198,7 +198,7 @@ export class MediaPool { /** @const {!Object} */ this.mediaFactory_ = { - [MediaType.AUDIO]: () => { + [MediaType_Enum.AUDIO]: () => { const audioEl = this.win_.document.createElement('audio'); audioEl.setAttribute('muted', ''); audioEl.muted = true; @@ -206,7 +206,7 @@ export class MediaPool { audioEl.classList.add('i-amphtml-pool-audio'); return audioEl; }, - [MediaType.VIDEO]: () => { + [MediaType_Enum.VIDEO]: () => { const videoEl = this.win_.document.createElement('video'); videoEl.setAttribute('muted', ''); videoEl.muted = true; @@ -225,20 +225,15 @@ export class MediaPool { * each of the types of media elements. We need to create these eagerly so * that all media elements exist by the time that blessAll() is invoked, * thereby "blessing" all media elements for playback without user gesture. - * @param {!Object} maxCounts The maximum amount of each + * @param {!Object} maxCounts The maximum amount of each * media element that can be allocated by the pool. * @private */ initializeMediaPool_(maxCounts) { let poolIdCounter = 0; - this.forEachMediaType_((key) => { - const type = MediaType[key]; - const count = maxCounts[type] || 0; - - if (count <= 0) { - return; - } + for (const type in maxCounts) { + const count = maxCounts[type]; const ctor = devAssert( this.mediaFactory_[type], @@ -268,7 +263,7 @@ export class MediaPool { mediaEl[MEDIA_ELEMENT_ORIGIN_PROPERTY_NAME] = MediaElementOrigin.POOL; this.unallocated[type].push(mediaEl); } - }); + } } /** @@ -333,25 +328,25 @@ export class MediaPool { * Gets the media type from a given element. * @param {!PoolBoundElementDef|!PlaceholderElementDef} mediaElement The * element whose media type should be retrieved. - * @return {!MediaType} + * @return {!MediaType_Enum} * @private */ getMediaType_(mediaElement) { const tagName = mediaElement.tagName.toLowerCase(); switch (tagName) { case 'audio': - return MediaType.AUDIO; + return MediaType_Enum.AUDIO; case 'video': - return MediaType.VIDEO; + return MediaType_Enum.VIDEO; default: - return MediaType.UNSUPPORTED; + return MediaType_Enum.UNSUPPORTED; } } /** * Reserves an element of the specified type by removing it from the set of * unallocated elements and returning it. - * @param {!MediaType} mediaType The type of media element to reserve. + * @param {!MediaType_Enum} mediaType The type of media element to reserve. * @return {?PoolBoundElementDef} The reserved element, if one exists. * @private */ @@ -362,7 +357,7 @@ export class MediaPool { /** * Retrieves the media element from the pool that matches the specified * element, if one exists. - * @param {!MediaType} mediaType The type of media element to get. + * @param {!MediaType_Enum} mediaType The type of media element to get. * @param {!DomElementDef} domMediaEl The element whose matching media * element should be retrieved. * @return {?PoolBoundElementDef} The media element in the pool that @@ -384,7 +379,7 @@ export class MediaPool { /** * Allocates the specified media element of the specified type. - * @param {!MediaType} mediaType The type of media element to allocate. + * @param {!MediaType_Enum} mediaType The type of media element to allocate. * @param {!PoolBoundElementDef} poolMediaEl The element to be allocated. * @private */ @@ -402,7 +397,7 @@ export class MediaPool { /** * Deallocates and returns the media element of the specified type furthest * from the current position in the document. - * @param {!MediaType} mediaType The type of media element to deallocate. + * @param {!MediaType_Enum} mediaType The type of media element to deallocate. * @param {!PlaceholderElementDef=} opt_elToAllocate If specified, the element * that is trying to be allocated, such that another element must be * evicted. @@ -460,7 +455,7 @@ export class MediaPool { /** * Evicts an element of the specified type, replaces it in the DOM with the * original media element, and returns it. - * @param {!MediaType} mediaType The type of media element to evict. + * @param {!MediaType_Enum} mediaType The type of media element to evict. * @param {!PlaceholderElementDef=} opt_elToAllocate If specified, the element * that is trying to be allocated, such that another element must be * evicted. @@ -481,7 +476,7 @@ export class MediaPool { } /** - * @param {!MediaType} mediaType The media type to check. + * @param {!MediaType_Enum} mediaType The media type to check. * @param {!DomElementDef} domMediaEl The element to check. * @return {boolean} true, if the specified element has already been allocated * as the specified type of media element. @@ -600,33 +595,6 @@ export class MediaPool { return swapOutOfDom; } - /** - * @param {function(string)} callbackFn - * @private - */ - forEachMediaType_(callbackFn) { - Object.keys(MediaType).forEach(callbackFn); - } - - /** - * Invokes a function for all media managed by the media pool. - * @param {function(!PoolBoundElementDef)} callbackFn The function to be - * invoked. - * @private - */ - forEachMediaElement_(callbackFn) { - [this.allocated, this.unallocated].forEach((mediaSet) => { - this.forEachMediaType_((key) => { - const type = MediaType[key]; - const els = /** @type {!Array} */ (mediaSet[type]); - if (!els) { - return; - } - els.forEach(callbackFn); - }); - }); - } - /** * Preloads the content of the specified media element in the DOM and returns * a media element that can be used in its stead for playback. @@ -891,7 +859,7 @@ export class MediaPool { return Promise.resolve(); } - if (mediaType == MediaType.VIDEO) { + if (mediaType == MediaType_Enum.VIDEO) { const ampVideoEl = domMediaEl.parentElement; if (ampVideoEl) { if (ampVideoEl.hasAttribute('noaudio')) { @@ -946,16 +914,18 @@ export class MediaPool { return Promise.resolve(); } - const blessPromises = []; - (this.ampElementsToBless_ || []).forEach(userInteractedWith); this.ampElementsToBless_ = null; // GC - this.forEachMediaElement_((mediaEl) => { - blessPromises.push(this.bless_(mediaEl)); - }); + const elements = [ + ...this.allocated[MediaType_Enum.AUDIO], + ...this.unallocated[MediaType_Enum.VIDEO], + ...this.allocated[MediaType_Enum.AUDIO], + ...this.unallocated[MediaType_Enum.VIDEO], + ]; + const blessPromises = elements.map((element) => this.bless_(element)); return Promise.all(blessPromises).then( () => { this.blessed_ = true; @@ -1071,7 +1041,7 @@ export class MediaPoolRoot { getElementDistance(unusedElement) {} /** - * @return {!Object} The maximum amount of each media + * @return {!Object} The maximum amount of each media * type to allow within this element. */ getMaxMediaElementCounts() {} diff --git a/extensions/amp-story/1.0/page-advancement.js b/extensions/amp-story/1.0/page-advancement.js index 9d402976ed4b..376ca1414284 100644 --- a/extensions/amp-story/1.0/page-advancement.js +++ b/extensions/amp-story/1.0/page-advancement.js @@ -13,7 +13,7 @@ import { EmbeddedComponentState, InteractiveComponentDef, StateProperty, - UIType, + UIType_Enum, getStoreService, } from './amp-story-store-service'; import {AdvancementMode} from './story-analytics'; @@ -704,7 +704,7 @@ export class ManualAdvancement extends AdvancementConfig { } /** - * Calculates the pageRect based on the UIType. + * Calculates the pageRect based on the UIType_Enum. * We can an use LayoutBox for mobile since the story page occupies entire screen. * Desktop UI needs the most recent value from the getBoundingClientRect function. * @return {DOMRect | LayoutBox} @@ -712,7 +712,7 @@ export class ManualAdvancement extends AdvancementConfig { */ getStoryPageRect_() { const uiState = this.storeService_.get(StateProperty.UI_STATE); - if (uiState !== UIType.DESKTOP_ONE_PANEL) { + if (uiState !== UIType_Enum.DESKTOP_ONE_PANEL) { return this.element_.getLayoutBox(); } else { return this.element_ diff --git a/extensions/amp-story/1.0/pagination-buttons.js b/extensions/amp-story/1.0/pagination-buttons.js index 0fd446c924b6..7134a9670d2c 100644 --- a/extensions/amp-story/1.0/pagination-buttons.js +++ b/extensions/amp-story/1.0/pagination-buttons.js @@ -18,28 +18,32 @@ import {AdvancementMode} from './story-analytics'; /** @struct @typedef {{className: string, triggers: string, label: LocalizedStringId_Enum}} */ let PaginationButtonStateDef; -/** @const {!Object} */ -const ButtonStates = { - PREVIOUS_PAGE: { - className: 'i-amphtml-story-back-prev', - triggers: EventType.PREVIOUS_PAGE, - label: LocalizedStringId_Enum.AMP_STORY_PREVIOUS_PAGE, - }, - NEXT_PAGE: { - className: 'i-amphtml-story-fwd-next', - triggers: EventType.NEXT_PAGE, - label: LocalizedStringId_Enum.AMP_STORY_NEXT_PAGE, - }, - NEXT_STORY: { - className: 'i-amphtml-story-fwd-next', - triggers: EventType.NEXT_PAGE, - label: LocalizedStringId_Enum.AMP_STORY_NEXT_STORY, - }, - REPLAY: { - className: 'i-amphtml-story-fwd-replay', - triggers: EventType.REPLAY, - label: LocalizedStringId_Enum.AMP_STORY_REPLAY, - }, +/** @const {PaginationButtonStateDef} */ +const BUTTON_STATE_PREVIOUS_PAGE = { + className: 'i-amphtml-story-back-prev', + triggers: EventType.PREVIOUS_PAGE, + label: LocalizedStringId_Enum.AMP_STORY_PREVIOUS_PAGE, +}; + +/** @const {PaginationButtonStateDef} */ +const BUTTON_STATE_NEXT_PAGE = { + className: 'i-amphtml-story-fwd-next', + triggers: EventType.NEXT_PAGE, + label: LocalizedStringId_Enum.AMP_STORY_NEXT_PAGE, +}; + +/** @const {PaginationButtonStateDef} */ +const BUTTON_STATE_NEXT_STORY = { + className: 'i-amphtml-story-fwd-next', + triggers: EventType.NEXT_PAGE, + label: LocalizedStringId_Enum.AMP_STORY_NEXT_STORY, +}; + +/** @const {PaginationButtonStateDef} */ +const BUTTON_STATE_REPLAY = { + className: 'i-amphtml-story-fwd-replay', + triggers: EventType.REPLAY, + label: LocalizedStringId_Enum.AMP_STORY_REPLAY, }; /** @@ -174,7 +178,7 @@ export class PaginationButtons { /** @private @const {!PaginationButton} */ this.forwardButton_ = new PaginationButton( doc, - ButtonStates.NEXT_PAGE, + BUTTON_STATE_NEXT_PAGE, this.storeService_, win ); @@ -182,7 +186,7 @@ export class PaginationButtons { /** @private @const {!PaginationButton} */ this.backButton_ = new PaginationButton( doc, - ButtonStates.PREVIOUS_PAGE, + BUTTON_STATE_PREVIOUS_PAGE, this.storeService_, win ); @@ -233,13 +237,13 @@ export class PaginationButtons { this.backButton_.setEnabled(pageIndex > 0); if (pageIndex < totalPages - 1) { - this.forwardButton_.updateState(ButtonStates.NEXT_PAGE); + this.forwardButton_.updateState(BUTTON_STATE_NEXT_PAGE); } else { const viewer = Services.viewerForDoc(this.ampStory_.element); if (viewer.hasCapability('swipe')) { - this.forwardButton_.updateState(ButtonStates.NEXT_STORY); + this.forwardButton_.updateState(BUTTON_STATE_NEXT_STORY); } else { - this.forwardButton_.updateState(ButtonStates.REPLAY); + this.forwardButton_.updateState(BUTTON_STATE_REPLAY); } } } diff --git a/extensions/amp-story/1.0/progress-bar.js b/extensions/amp-story/1.0/progress-bar.js index 77152d70c778..aff23d570e36 100644 --- a/extensions/amp-story/1.0/progress-bar.js +++ b/extensions/amp-story/1.0/progress-bar.js @@ -14,7 +14,7 @@ import {isExperimentOn} from 'src/experiments'; import { StateProperty, - UIType, + UIType_Enum, getStoreService, } from './amp-story-store-service'; import {EventType} from './events'; @@ -399,16 +399,16 @@ export class ProgressBar { /** * Reacts to UI state updates. - * @param {!UIType} uiState + * @param {!UIType_Enum} uiState * @private */ onUIStateUpdate_(uiState) { switch (uiState) { - case UIType.DESKTOP_FULLBLEED: + case UIType_Enum.DESKTOP_FULLBLEED: MAX_SEGMENTS = 70; ELLIPSE_WIDTH_PX = 3; break; - case UIType.MOBILE: + case UIType_Enum.MOBILE: MAX_SEGMENTS = 20; ELLIPSE_WIDTH_PX = 2; break; diff --git a/extensions/amp-story/1.0/test/test-amp-story-grid-layer.js b/extensions/amp-story/1.0/test/test-amp-story-grid-layer.js index bcfab398874b..494fac041242 100644 --- a/extensions/amp-story/1.0/test/test-amp-story-grid-layer.js +++ b/extensions/amp-story/1.0/test/test-amp-story-grid-layer.js @@ -8,7 +8,7 @@ import {registerServiceBuilder} from '../../../../src/service-helpers'; import {AmpStoryGridLayer} from '../amp-story-grid-layer'; import {AmpStoryPage} from '../amp-story-page'; import {Action, AmpStoryStoreService} from '../amp-story-store-service'; -import {MediaType} from '../media-pool'; +import {MediaType_Enum} from '../media-pool'; describes.realWin('amp-story-grid-layer', {amp: true}, (env) => { let win; @@ -28,8 +28,8 @@ describes.realWin('amp-story-grid-layer', {amp: true}, (env) => { const mediaPoolRoot = { getElement: () => win.document.createElement('div'), getMaxMediaElementCounts: () => ({ - [MediaType.VIDEO]: 8, - [MediaType.AUDIO]: 8, + [MediaType_Enum.VIDEO]: 8, + [MediaType_Enum.AUDIO]: 8, }), }; diff --git a/extensions/amp-story/1.0/test/test-amp-story-page.js b/extensions/amp-story/1.0/test/test-amp-story-page.js index f158ba847265..ec2c46c80d93 100644 --- a/extensions/amp-story/1.0/test/test-amp-story-page.js +++ b/extensions/amp-story/1.0/test/test-amp-story-page.js @@ -19,7 +19,7 @@ import {AmpAudio} from '../../../amp-audio/0.1/amp-audio'; import LocalizedStringsEn from '../_locales/en.json' assert {type: 'json'}; // lgtm[js/syntax-error] import {AmpStoryPage, PageState, Selectors} from '../amp-story-page'; import {Action, AmpStoryStoreService} from '../amp-story-store-service'; -import {MediaType} from '../media-pool'; +import {MediaType_Enum} from '../media-pool'; const extensions = ['amp-story:1.0', 'amp-audio']; @@ -43,8 +43,8 @@ describes.realWin('amp-story-page', {amp: {extensions}}, (env) => { const mediaPoolRoot = { getElement: () => win.document.createElement('div'), getMaxMediaElementCounts: () => ({ - [MediaType.VIDEO]: 8, - [MediaType.AUDIO]: 8, + [MediaType_Enum.VIDEO]: 8, + [MediaType_Enum.AUDIO]: 8, }), }; diff --git a/extensions/amp-story/1.0/test/test-amp-story.js b/extensions/amp-story/1.0/test/test-amp-story.js index fe67a100664b..8cb6433ed042 100644 --- a/extensions/amp-story/1.0/test/test-amp-story.js +++ b/extensions/amp-story/1.0/test/test-amp-story.js @@ -29,10 +29,10 @@ import { AmpStoryStoreService, StateProperty, SubscriptionsState, - UIType, + UIType_Enum, } from '../amp-story-store-service'; import {EventType, dispatch} from '../events'; -import {MediaType} from '../media-pool'; +import {MediaType_Enum} from '../media-pool'; import {AdvancementMode} from '../story-analytics'; import * as utils from '../utils'; @@ -350,7 +350,7 @@ describes.realWin( await story.layoutCallback(); expect(story.storeService_.get(StateProperty.UI_STATE)).to.equals( - UIType.DESKTOP_ONE_PANEL + UIType_Enum.DESKTOP_ONE_PANEL ); }); @@ -365,7 +365,7 @@ describes.realWin( await story.layoutCallback(); expect(story.storeService_.get(StateProperty.UI_STATE)).to.equals( - UIType.DESKTOP_FULLBLEED + UIType_Enum.DESKTOP_FULLBLEED ); }); @@ -979,8 +979,8 @@ describes.realWin( await story.layoutCallback(); const expected = { - [MediaType.AUDIO]: 2, - [MediaType.VIDEO]: 2, + [MediaType_Enum.AUDIO]: 2, + [MediaType_Enum.VIDEO]: 2, }; expect(story.getMaxMediaElementCounts()).to.deep.equal(expected); }); @@ -999,8 +999,8 @@ describes.realWin( story.element.appendChild(ampAudoEl); const expected = { - [MediaType.AUDIO]: 3, - [MediaType.VIDEO]: 3, + [MediaType_Enum.AUDIO]: 3, + [MediaType_Enum.VIDEO]: 3, }; expect(story.getMaxMediaElementCounts()).to.deep.equal(expected); }); @@ -1022,8 +1022,8 @@ describes.realWin( } const expected = { - [MediaType.AUDIO]: 4, - [MediaType.VIDEO]: 8, + [MediaType_Enum.AUDIO]: 4, + [MediaType_Enum.VIDEO]: 8, }; expect(story.getMaxMediaElementCounts()).to.deep.equal(expected); }); @@ -1256,7 +1256,7 @@ describes.realWin( const dispatchSwipeEvent = (deltaX, deltaY) => { // Triggers mobile UI so hint overlay can attach. - story.storeService_.dispatch(Action.TOGGLE_UI, UIType.MOBILE); + story.storeService_.dispatch(Action.TOGGLE_UI, UIType_Enum.MOBILE); story.element.dispatchEvent( new TouchEvent('touchstart', getTouchOptions(-10, -10)) diff --git a/extensions/amp-story/1.0/test/test-full-bleed-animations.js b/extensions/amp-story/1.0/test/test-full-bleed-animations.js index 027d86ef2870..0adf0e92f97e 100644 --- a/extensions/amp-story/1.0/test/test-full-bleed-animations.js +++ b/extensions/amp-story/1.0/test/test-full-bleed-animations.js @@ -224,12 +224,12 @@ describes.realWin( const dimensions = setDimensions(380, 580, 360, 580); expect(targetFitsWithinPage(dimensions)).to.be.true; - const factorThatWillMakeTargetFitPage = 380 / 360; + const factorThatWillMakeTargetFitPage = + dimensions.pageWidth / dimensions.targetWidth; const factor = factorThatWillMakeTargetFitPage * 1.25; expect(calculateTargetScalingFactor(dimensions)).to.equal(factor); - const calculatedKeyframes = presets['pan-up']; - calculatedKeyframes.keyframes = calculatedKeyframes.keyframes( + const calculatedKeyframes = presets['pan-up'].keyframes( dimensions, /* options */ {} ); @@ -248,7 +248,46 @@ describes.realWin( }, ]; - expect(calculatedKeyframes.keyframes).to.deep.equal(expectedKeyframes); + expect(calculatedKeyframes).to.deep.equal(expectedKeyframes); + }); + + ['pan-up', 'pan-down', 'pan-right', 'pan-left'].forEach((panAnimation) => { + it(`Should scale the target for ${panAnimation}.`, () => { + const dimensions = setDimensions(380, 580, 360, 580); + expect(targetFitsWithinPage(dimensions)).to.be.true; + + const factorThatWillMakeTargetFitPage = + dimensions.pageWidth / dimensions.targetWidth; + const factor = factorThatWillMakeTargetFitPage * 1.25; + expect(calculateTargetScalingFactor(dimensions)).to.equal(factor); + + const calculatedKeyframes = presets[panAnimation].keyframes( + dimensions, + /* options */ {} + ); + + const expectedScaleFactorStr = `scale(${factor})`; + calculatedKeyframes.forEach((keyframe) => { + expect(keyframe.transform).to.contain(expectedScaleFactorStr); + }); + }); + + it(`Should not scale the target if scaling factor is set for ${panAnimation}.`, () => { + const scalingFactor = 2; + + const dimensions = setDimensions(380, 580, 360, 580); + expect(targetFitsWithinPage(dimensions)).to.be.true; + + const calculatedKeyframes = presets[panAnimation].keyframes( + dimensions, + /* options */ {'pan-scaling-factor': scalingFactor} + ); + + const expectedScaleFactorStr = `scale(${scalingFactor})`; + calculatedKeyframes.forEach((keyframe) => { + expect(keyframe.transform).to.contain(expectedScaleFactorStr); + }); + }); }); } ); diff --git a/extensions/amp-story/1.0/test/test-media-pool.js b/extensions/amp-story/1.0/test/test-media-pool.js index b59376ddf431..823cccc3cdf7 100644 --- a/extensions/amp-story/1.0/test/test-media-pool.js +++ b/extensions/amp-story/1.0/test/test-media-pool.js @@ -2,7 +2,7 @@ import {findIndex} from '#core/types/array'; import {Services} from '#service'; -import {MediaPool, MediaType} from '../media-pool'; +import {MediaPool, MediaType_Enum} from '../media-pool'; const NOOP = () => {}; @@ -11,8 +11,8 @@ describes.realWin('media-pool', {}, (env) => { let mediaPool; let distanceFnStub; const COUNTS = { - [MediaType.AUDIO]: 2, - [MediaType.VIDEO]: 2, + [MediaType_Enum.AUDIO]: 2, + [MediaType_Enum.VIDEO]: 2, }; beforeEach(() => { diff --git a/extensions/amp-story/1.0/test/validator-amp-story-animations.html b/extensions/amp-story/1.0/test/validator-amp-story-animations.html index f7ce82c57092..82a83a060d84 100644 --- a/extensions/amp-story/1.0/test/validator-amp-story-animations.html +++ b/extensions/amp-story/1.0/test/validator-amp-story-animations.html @@ -37,6 +37,7 @@

ken-burns-effect

src="https://picsum.photos/1024/768?image=1077" animate-in="pan-left" animate-in-duration="30s" + pan-scaling-factor=".9" layout="fixed" width="1024" height="768"> diff --git a/extensions/amp-story/1.0/test/validator-amp-story-animations.out b/extensions/amp-story/1.0/test/validator-amp-story-animations.out index bdc02b9f8c25..1a2552c78fbd 100644 --- a/extensions/amp-story/1.0/test/validator-amp-story-animations.out +++ b/extensions/amp-story/1.0/test/validator-amp-story-animations.out @@ -38,6 +38,7 @@ PASS | src="https://picsum.photos/1024/768?image=1077" | animate-in="pan-left" | animate-in-duration="30s" +| pan-scaling-factor=".9" | layout="fixed" | width="1024" | height="768"> diff --git a/extensions/amp-story/amp-story.md b/extensions/amp-story/amp-story.md index 472637ae34d6..7d757f560139 100644 --- a/extensions/amp-story/amp-story.md +++ b/extensions/amp-story/amp-story.md @@ -729,6 +729,27 @@ _Example_: An image panning 50px down over 15 seconds. ``` +#### pan-scaling-factor [optional, only works with `pan-left`, `pan-right`, `pan-up`, & `pan-down` animations] + +The target scales automatically in a pan-left/pan-right/pan-up/pan-down animation to ensure it does not go out of the target boundary when panning. + +Use this attribute to override the default scaling factor calculation, and specify a static scaling factor. The value must be greater than 0, and decimals are allowed. + +_Example_: An image scales 1.3x when panning. + +```html + + +``` + ### Sequencing animations To chain animations in sequence, use the `animate-in-after` attribute. All elements in a given chain must be present in the same ``. Elements without the `animate-in-after` attribute do not belong to a sequence chain, and will start independently on page entrance. diff --git a/extensions/amp-story/validator-amp-story.protoascii b/extensions/amp-story/validator-amp-story.protoascii index 2de8d71ae0b4..92d6d499a559 100644 --- a/extensions/amp-story/validator-amp-story.protoascii +++ b/extensions/amp-story/validator-amp-story.protoascii @@ -267,6 +267,12 @@ tags: { name: "translate-y" value_regex_casei: "[0-9]+px" } + attrs: { + name: "pan-scaling-factor" + # Allow float number such as "12.3", ".1", or "5." + # Note that string with only decimal point such as "." is not allowed. + value_regex_casei: "^([0-9]*[.]?[0-9]+)|([0-9]+[.]?[0-9]*)$" + } attrs: { name: "justify-content" value: "center" @@ -362,6 +368,12 @@ tags: { name: "translate-y" value_regex_casei: "[0-9]+px" } + attrs: { + name: "pan-scaling-factor" + # Allow float number such as "12.3", ".1", or "5." + # Note that string with only decimal point such as "." is not allowed. + value_regex_casei: "^([0-9]*[.]?[0-9]+)|([0-9]+[.]?[0-9]*)$" + } reference_points: { tag_spec_name: "AMP-STORY-GRID-LAYER animate-in" } @@ -566,6 +578,12 @@ tags: { name: "translate-y" value_regex_casei: "[0-9]+px" } + attrs: { + name: "pan-scaling-factor" + # Allow float number such as "12.3", ".1", or "5." + # Note that string with only decimal point such as "." is not allowed. + value_regex_casei: "^([0-9]*[.]?[0-9]+)|([0-9]+[.]?[0-9]*)$" + } reference_points: { tag_spec_name: "AMP-STORY-CTA-LAYER animate-in" }