{"action":"created","comment":{"url":"https://api.github.com/repos/ampproject/amphtml/pulls/comments/194118314","pull_request_review_id":127237482,"id":194118314,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE5NDExODMxNA==","diff_hunk":"@@ -96,62 +112,135 @@ export class HighlightHandler {\n    * @param {!HighlightInfoDef} highlightInfo The highlighting info in JSON.\n    */\n   constructor(ampdoc, highlightInfo) {\n-    /** @const {!../../../src/service/ampdoc-impl.AmpDoc} */\n+    /** @private @const {!../../../src/service/ampdoc-impl.AmpDoc} */\n     this.ampdoc_ = ampdoc;\n+    /** @private @const {!../../../src/service/viewer-impl.Viewer} */\n+    this.viewer_ = Services.viewerForDoc(ampdoc);\n \n     /** @private {?Array<!Element>} */\n     this.highlightedNodes_ = null;\n \n     this.initHighlight_(highlightInfo);\n   }\n \n+  /**\n+   * @param {string} state\n+   * @param {JsonObject=} opt_params\n+   * @private\n+   */\n+  sendHighlightState_(state, opt_params) {\n+    const params = dict({'state': state});\n+    for (const key in opt_params) {\n+      params[key] = opt_params[key];\n+    }\n+    this.viewer_.sendMessage(HIGHLIGHT_STATE, params);\n+  }\n+\n   /**\n    * @param {!HighlightInfoDef} highlightInfo\n-    * @private\n-    */\n-  initHighlight_(highlightInfo) {\n-    const ampdoc = this.ampdoc_;\n-    const {win} = ampdoc;\n-    const sens = findSentences(win, ampdoc.getBody(), highlightInfo.sentences);\n+   * @private\n+   */\n+  findHighlightedNodes_(highlightInfo) {\n+    const {win} = this.ampdoc_;\n+    const sens = findSentences(\n+        win, this.ampdoc_.getBody(), highlightInfo.sentences);\n     if (!sens) {\n       return;\n     }\n-    const spans = markTextRangeList(win, sens);\n-    if (spans.length <= 0) {\n+    const nodes = markTextRangeList(win, sens);\n+    if (!nodes || nodes.length == 0) {\n+      return;\n+    }\n+    this.highlightedNodes_ = nodes;\n+  }\n+\n+  /**\n+   * @param {!HighlightInfoDef} highlightInfo\n+   * @private\n+   */\n+  initHighlight_(highlightInfo) {\n+    this.findHighlightedNodes_(highlightInfo);\n+    if (!this.highlightedNodes_) {\n+      this.sendHighlightState_('not_found');\n       return;\n     }\n-    for (let i = 0; i < spans.length; i++) {\n-      const n = spans[i];\n+    const scrollTop = this.calcTopToCenterHighlightedNodes_();\n+    this.sendHighlightState_('found', dict({'scroll': scrollTop}));\n+\n+    for (let i = 0; i < this.highlightedNodes_.length; i++) {\n+      const n = this.highlightedNodes_[i];\n       n['style']['backgroundColor'] = '#ff0';\n       n['style']['color'] = '#333';\n     }\n-    this.highlightedNodes_ = spans;\n-    const viewer = Services.viewerForDoc(ampdoc);\n-    const visibility = viewer.getVisibilityState();\n+\n+    const visibility = this.viewer_.getVisibilityState();\n     if (visibility == 'visible') {\n-      Services.viewportForDoc(ampdoc).animateScrollIntoView(spans[0], 500);\n+      this.centerHighlightedNodes_();\n     } else {\n+      if (scrollTop > SCROLL_ANIMATION_HEIGHT_LIMIT) {\n+        Services.viewportForDoc(this.ampdoc_).setScrollTop(\n+            scrollTop - SCROLL_ANIMATION_HEIGHT_LIMIT);\n+      }\n       let called = false;\n-      viewer.onVisibilityChanged(() => {\n+      this.viewer_.onVisibilityChanged(() => {\n         // TODO(yunabe): Unregister the handler.\n-        if (called || viewer.getVisibilityState() != 'visible') {\n+        if (called || this.viewer_.getVisibilityState() != 'visible') {\n           return;\n         }\n-        Services.viewportForDoc(ampdoc).animateScrollIntoView(spans[0], 500);\n-        viewer.sendMessage('highlightShown', null);\n+        this.centerHighlightedNodes_();\n         called = true;\n       });\n     }\n+    listenOnce(this.ampdoc_.getBody(), 'click',\n+        this.dismissHighlight_.bind(this));\n+  }\n+\n+  /**\n+   * @return {number}\n+   * @private\n+   */\n+  calcTopToCenterHighlightedNodes_() {\n+    const nodes = this.highlightedNodes_;\n+    if (!nodes) {\n+      return 0;\n+    }\n+    const viewport = Services.viewportForDoc(this.ampdoc_);\n+    let minTop = Number.MAX_VALUE;\n+    let maxBottom = 0;\n+    for (let i = 0; i < nodes.length; i++) {\n+      const rect = viewport.getLayoutRect(nodes[i]);","path":"extensions/amp-viewer-integration/0.1/highlight-handler.js","position":156,"original_position":156,"commit_id":"b9f7b6b7de42cfe65604a5021e2ad257b0005e55","original_commit_id":"b9f7b6b7de42cfe65604a5021e2ad257b0005e55","user":{"login":"alanorozco","id":254946,"node_id":"MDQ6VXNlcjI1NDk0Ng==","avatar_url":"https://avatars2.githubusercontent.com/u/254946?v=4","gravatar_id":"","url":"https://api.github.com/users/alanorozco","html_url":"https://github.com/alanorozco","followers_url":"https://api.github.com/users/alanorozco/followers","following_url":"https://api.github.com/users/alanorozco/following{/other_user}","gists_url":"https://api.github.com/users/alanorozco/gists{/gist_id}","starred_url":"https://api.github.com/users/alanorozco/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alanorozco/subscriptions","organizations_url":"https://api.github.com/users/alanorozco/orgs","repos_url":"https://api.github.com/users/alanorozco/repos","events_url":"https://api.github.com/users/alanorozco/events{/privacy}","received_events_url":"https://api.github.com/users/alanorozco/received_events","type":"User","site_admin":false},"body":"nit: Use destructuring: \r\n\r\n```js\r\nconst {top, bottom} = viewport.getLayoutRect(nodes[i]);\r\n```","created_at":"2018-06-08T16:51:04Z","updated_at":"2018-06-08T16:51:30Z","html_url":"https://github.com/ampproject/amphtml/pull/15791#discussion_r194118314","pull_request_url":"https://api.github.com/repos/ampproject/amphtml/pulls/15791","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/comments/194118314"},"html":{"href":"https://github.com/ampproject/amphtml/pull/15791#discussion_r194118314"},"pull_request":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/15791"}}},"pull_request":{"url":"https://api.github.com/repos/ampproject/amphtml/pulls/15791","id":192350548,"node_id":"MDExOlB1bGxSZXF1ZXN0MTkyMzUwNTQ4","html_url":"https://github.com/ampproject/amphtml/pull/15791","diff_url":"https://github.com/ampproject/amphtml/pull/15791.diff","patch_url":"https://github.com/ampproject/amphtml/pull/15791.patch","issue_url":"https://api.github.com/repos/ampproject/amphtml/issues/15791","number":15791,"state":"open","locked":false,"title":"Scroll AMP doc to center highlighted elements in the viewport","user":{"login":"yunabe","id":255937,"node_id":"MDQ6VXNlcjI1NTkzNw==","avatar_url":"https://avatars0.githubusercontent.com/u/255937?v=4","gravatar_id":"","url":"https://api.github.com/users/yunabe","html_url":"https://github.com/yunabe","followers_url":"https://api.github.com/users/yunabe/followers","following_url":"https://api.github.com/users/yunabe/following{/other_user}","gists_url":"https://api.github.com/users/yunabe/gists{/gist_id}","starred_url":"https://api.github.com/users/yunabe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yunabe/subscriptions","organizations_url":"https://api.github.com/users/yunabe/orgs","repos_url":"https://api.github.com/users/yunabe/repos","events_url":"https://api.github.com/users/yunabe/events{/privacy}","received_events_url":"https://api.github.com/users/yunabe/received_events","type":"User","site_admin":false},"body":"This pull request should be merged after https://github.com/ampproject/amphtml/pull/15337. There is only one new commit in this PR (https://github.com/ampproject/amphtml/pull/15791/commits/26747096f085e317b24106339e2d7f8605983702)","created_at":"2018-06-04T09:37:45Z","updated_at":"2018-06-08T16:51:30Z","closed_at":null,"merged_at":null,"merge_commit_sha":"06f6e827699e8b0dcee724ca963e5efeb4fedbf0","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":596633554,"node_id":"MDU6TGFiZWw1OTY2MzM1NTQ=","url":"https://api.github.com/repos/ampproject/amphtml/labels/cla:%20yes","name":"cla: yes","color":"ededed","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/ampproject/amphtml/pulls/15791/commits","review_comments_url":"https://api.github.com/repos/ampproject/amphtml/pulls/15791/comments","review_comment_url":"https://api.github.com/repos/ampproject/amphtml/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ampproject/amphtml/issues/15791/comments","statuses_url":"https://api.github.com/repos/ampproject/amphtml/statuses/b9f7b6b7de42cfe65604a5021e2ad257b0005e55","head":{"label":"yunabe:scrolldev","ref":"scrolldev","sha":"b9f7b6b7de42cfe65604a5021e2ad257b0005e55","user":{"login":"yunabe","id":255937,"node_id":"MDQ6VXNlcjI1NTkzNw==","avatar_url":"https://avatars0.githubusercontent.com/u/255937?v=4","gravatar_id":"","url":"https://api.github.com/users/yunabe","html_url":"https://github.com/yunabe","followers_url":"https://api.github.com/users/yunabe/followers","following_url":"https://api.github.com/users/yunabe/following{/other_user}","gists_url":"https://api.github.com/users/yunabe/gists{/gist_id}","starred_url":"https://api.github.com/users/yunabe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yunabe/subscriptions","organizations_url":"https://api.github.com/users/yunabe/orgs","repos_url":"https://api.github.com/users/yunabe/repos","events_url":"https://api.github.com/users/yunabe/events{/privacy}","received_events_url":"https://api.github.com/users/yunabe/received_events","type":"User","site_admin":false},"repo":{"id":133592499,"node_id":"MDEwOlJlcG9zaXRvcnkxMzM1OTI0OTk=","name":"amphtml","full_name":"yunabe/amphtml","owner":{"login":"yunabe","id":255937,"node_id":"MDQ6VXNlcjI1NTkzNw==","avatar_url":"https://avatars0.githubusercontent.com/u/255937?v=4","gravatar_id":"","url":"https://api.github.com/users/yunabe","html_url":"https://github.com/yunabe","followers_url":"https://api.github.com/users/yunabe/followers","following_url":"https://api.github.com/users/yunabe/following{/other_user}","gists_url":"https://api.github.com/users/yunabe/gists{/gist_id}","starred_url":"https://api.github.com/users/yunabe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yunabe/subscriptions","organizations_url":"https://api.github.com/users/yunabe/orgs","repos_url":"https://api.github.com/users/yunabe/repos","events_url":"https://api.github.com/users/yunabe/events{/privacy}","received_events_url":"https://api.github.com/users/yunabe/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/yunabe/amphtml","description":"AMP HTML source code, samples, and documentation.  See below for more info.","fork":true,"url":"https://api.github.com/repos/yunabe/amphtml","forks_url":"https://api.github.com/repos/yunabe/amphtml/forks","keys_url":"https://api.github.com/repos/yunabe/amphtml/keys{/key_id}","collaborators_url":"https://api.github.com/repos/yunabe/amphtml/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/yunabe/amphtml/teams","hooks_url":"https://api.github.com/repos/yunabe/amphtml/hooks","issue_events_url":"https://api.github.com/repos/yunabe/amphtml/issues/events{/number}","events_url":"https://api.github.com/repos/yunabe/amphtml/events","assignees_url":"https://api.github.com/repos/yunabe/amphtml/assignees{/user}","branches_url":"https://api.github.com/repos/yunabe/amphtml/branches{/branch}","tags_url":"https://api.github.com/repos/yunabe/amphtml/tags","blobs_url":"https://api.github.com/repos/yunabe/amphtml/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/yunabe/amphtml/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/yunabe/amphtml/git/refs{/sha}","trees_url":"https://api.github.com/repos/yunabe/amphtml/git/trees{/sha}","statuses_url":"https://api.github.com/repos/yunabe/amphtml/statuses/{sha}","languages_url":"https://api.github.com/repos/yunabe/amphtml/languages","stargazers_url":"https://api.github.com/repos/yunabe/amphtml/stargazers","contributors_url":"https://api.github.com/repos/yunabe/amphtml/contributors","subscribers_url":"https://api.github.com/repos/yunabe/amphtml/subscribers","subscription_url":"https://api.github.com/repos/yunabe/amphtml/subscription","commits_url":"https://api.github.com/repos/yunabe/amphtml/commits{/sha}","git_commits_url":"https://api.github.com/repos/yunabe/amphtml/git/commits{/sha}","comments_url":"https://api.github.com/repos/yunabe/amphtml/comments{/number}","issue_comment_url":"https://api.github.com/repos/yunabe/amphtml/issues/comments{/number}","contents_url":"https://api.github.com/repos/yunabe/amphtml/contents/{+path}","compare_url":"https://api.github.com/repos/yunabe/amphtml/compare/{base}...{head}","merges_url":"https://api.github.com/repos/yunabe/amphtml/merges","archive_url":"https://api.github.com/repos/yunabe/amphtml/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/yunabe/amphtml/downloads","issues_url":"https://api.github.com/repos/yunabe/amphtml/issues{/number}","pulls_url":"https://api.github.com/repos/yunabe/amphtml/pulls{/number}","milestones_url":"https://api.github.com/repos/yunabe/amphtml/milestones{/number}","notifications_url":"https://api.github.com/repos/yunabe/amphtml/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/yunabe/amphtml/labels{/name}","releases_url":"https://api.github.com/repos/yunabe/amphtml/releases{/id}","deployments_url":"https://api.github.com/repos/yunabe/amphtml/deployments","created_at":"2018-05-16T01:21:03Z","updated_at":"2018-06-08T15:42:49Z","pushed_at":"2018-06-08T15:42:42Z","git_url":"git://github.com/yunabe/amphtml.git","ssh_url":"git@github.com:yunabe/amphtml.git","clone_url":"https://github.com/yunabe/amphtml.git","svn_url":"https://github.com/yunabe/amphtml","homepage":"https://www.ampproject.org","size":459436,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_projects":true,"has_downloads":false,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"ampproject:master","ref":"master","sha":"8bf052af906d2da134f2849fd5152febdc2a454d","user":{"login":"ampproject","id":14114390,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE0MTE0Mzkw","avatar_url":"https://avatars3.githubusercontent.com/u/14114390?v=4","gravatar_id":"","url":"https://api.github.com/users/ampproject","html_url":"https://github.com/ampproject","followers_url":"https://api.github.com/users/ampproject/followers","following_url":"https://api.github.com/users/ampproject/following{/other_user}","gists_url":"https://api.github.com/users/ampproject/gists{/gist_id}","starred_url":"https://api.github.com/users/ampproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ampproject/subscriptions","organizations_url":"https://api.github.com/users/ampproject/orgs","repos_url":"https://api.github.com/users/ampproject/repos","events_url":"https://api.github.com/users/ampproject/events{/privacy}","received_events_url":"https://api.github.com/users/ampproject/received_events","type":"Organization","site_admin":false},"repo":{"id":41766002,"node_id":"MDEwOlJlcG9zaXRvcnk0MTc2NjAwMg==","name":"amphtml","full_name":"ampproject/amphtml","owner":{"login":"ampproject","id":14114390,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE0MTE0Mzkw","avatar_url":"https://avatars3.githubusercontent.com/u/14114390?v=4","gravatar_id":"","url":"https://api.github.com/users/ampproject","html_url":"https://github.com/ampproject","followers_url":"https://api.github.com/users/ampproject/followers","following_url":"https://api.github.com/users/ampproject/following{/other_user}","gists_url":"https://api.github.com/users/ampproject/gists{/gist_id}","starred_url":"https://api.github.com/users/ampproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ampproject/subscriptions","organizations_url":"https://api.github.com/users/ampproject/orgs","repos_url":"https://api.github.com/users/ampproject/repos","events_url":"https://api.github.com/users/ampproject/events{/privacy}","received_events_url":"https://api.github.com/users/ampproject/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/ampproject/amphtml","description":"AMP HTML source code, samples, and documentation.  See below for more info.","fork":false,"url":"https://api.github.com/repos/ampproject/amphtml","forks_url":"https://api.github.com/repos/ampproject/amphtml/forks","keys_url":"https://api.github.com/repos/ampproject/amphtml/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ampproject/amphtml/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ampproject/amphtml/teams","hooks_url":"https://api.github.com/repos/ampproject/amphtml/hooks","issue_events_url":"https://api.github.com/repos/ampproject/amphtml/issues/events{/number}","events_url":"https://api.github.com/repos/ampproject/amphtml/events","assignees_url":"https://api.github.com/repos/ampproject/amphtml/assignees{/user}","branches_url":"https://api.github.com/repos/ampproject/amphtml/branches{/branch}","tags_url":"https://api.github.com/repos/ampproject/amphtml/tags","blobs_url":"https://api.github.com/repos/ampproject/amphtml/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ampproject/amphtml/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ampproject/amphtml/git/refs{/sha}","trees_url":"https://api.github.com/repos/ampproject/amphtml/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ampproject/amphtml/statuses/{sha}","languages_url":"https://api.github.com/repos/ampproject/amphtml/languages","stargazers_url":"https://api.github.com/repos/ampproject/amphtml/stargazers","contributors_url":"https://api.github.com/repos/ampproject/amphtml/contributors","subscribers_url":"https://api.github.com/repos/ampproject/amphtml/subscribers","subscription_url":"https://api.github.com/repos/ampproject/amphtml/subscription","commits_url":"https://api.github.com/repos/ampproject/amphtml/commits{/sha}","git_commits_url":"https://api.github.com/repos/ampproject/amphtml/git/commits{/sha}","comments_url":"https://api.github.com/repos/ampproject/amphtml/comments{/number}","issue_comment_url":"https://api.github.com/repos/ampproject/amphtml/issues/comments{/number}","contents_url":"https://api.github.com/repos/ampproject/amphtml/contents/{+path}","compare_url":"https://api.github.com/repos/ampproject/amphtml/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ampproject/amphtml/merges","archive_url":"https://api.github.com/repos/ampproject/amphtml/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ampproject/amphtml/downloads","issues_url":"https://api.github.com/repos/ampproject/amphtml/issues{/number}","pulls_url":"https://api.github.com/repos/ampproject/amphtml/pulls{/number}","milestones_url":"https://api.github.com/repos/ampproject/amphtml/milestones{/number}","notifications_url":"https://api.github.com/repos/ampproject/amphtml/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ampproject/amphtml/labels{/name}","releases_url":"https://api.github.com/repos/ampproject/amphtml/releases{/id}","deployments_url":"https://api.github.com/repos/ampproject/amphtml/deployments","created_at":"2015-09-01T22:10:53Z","updated_at":"2018-06-08T16:30:01Z","pushed_at":"2018-06-08T16:46:21Z","git_url":"git://github.com/ampproject/amphtml.git","ssh_url":"git@github.com:ampproject/amphtml.git","clone_url":"https://github.com/ampproject/amphtml.git","svn_url":"https://github.com/ampproject/amphtml","homepage":"https://www.ampproject.org","size":459613,"stargazers_count":11657,"watchers_count":11657,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":false,"has_wiki":false,"has_pages":false,"forks_count":2431,"mirror_url":null,"archived":false,"open_issues_count":1268,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":2431,"open_issues":1268,"watchers":11657,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/15791"},"html":{"href":"https://github.com/ampproject/amphtml/pull/15791"},"issue":{"href":"https://api.github.com/repos/ampproject/amphtml/issues/15791"},"comments":{"href":"https://api.github.com/repos/ampproject/amphtml/issues/15791/comments"},"review_comments":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/15791/comments"},"review_comment":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/15791/commits"},"statuses":{"href":"https://api.github.com/repos/ampproject/amphtml/statuses/b9f7b6b7de42cfe65604a5021e2ad257b0005e55"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"alanorozco"}}