{"action":"created","comment":{"url":"https://api.github.com/repos/google/blockly/pulls/comments/61652825","id":61652825,"diff_hunk":"@@ -0,0 +1,305 @@\n+var blocklyApp = blocklyApp || {};\n+\n+blocklyApp.TreeService = ng.core\n+  .Class({\n+  \tconstructor: function(){\n+      console.log('making a new tree service');\n+      this.activeDesc_={};\n+      this.previousKey_;\n+      this.trees = document.getElementsByClassName('blocklyTree');\n+  \t},\n+    createId: function(obj){\n+      if (obj && obj.id){\n+        return obj.id;\n+      }\n+      return 'blockly-' + Blockly.genUid();\n+    },\n+    setActiveAttribute: function(tree){\n+      if (!document.getElementById(tree.getAttribute('aria-activedescendant'))){\n+        console.log('setting tree active descendant');\n+        tree.setAttribute('aria-activedescendant', tree.id+'-node0');\n+      }\n+    },\n+    setActiveDesc: function(node, id) {\n+      console.log('setting active descendant for tree ' + id);\n+      this.activeDesc_[id] = node;\n+    },\n+    getActiveDesc: function(id){\n+      return this.activeDesc_[id];\n+    },\n+    updateSelectedNode: function(node, tree, keepFocus){\n+      console.log('updating node: ' + node.id);\n+      var treeId = tree.id;\n+      var activeDesc = this.getActiveDesc(treeId);\n+      if (activeDesc) {\n+        activeDesc.classList.remove('blocklyActiveDescendant');\n+      } else {\n+        console.log('updateSelectedNode: there is no active descendant');\n+      }\n+      node.classList.add('blocklyActiveDescendant');\n+      tree.setAttribute('aria-activedescendant',node.id);\n+      this.setActiveDesc(node, treeId);\n+      node.setAttribute('aria-selected','true');\n+\n+      //make sure keyboard focus is on tree as a whole\n+      //in case before the user was editing a block and keyboard focus got shifted.\n+      if(keepFocus){\n+        tree.focus();\n+      }\n+    },\n+    workspaceButtonKeyHandler: function(e, treeId){\n+      console.log(e.keyCode);\n+      console.log('inside TreeService');\n+      switch(e.keyCode){\n+        case 9:\n+          //16,9: shift, tab\n+          if (e.shiftKey){\n+            console.log('shifttabbing');\n+            //if the previous key is shift, we're shift-tabbing mode\n+            this.goToPreviousTree(treeId,e);\n+          } else {\n+            //if previous key isn't shift, we're tabbing\n+            this.goToNextTree(treeId,e);\n+          }\n+          break;\n+      }\n+      this.previousKey_=e.keyCode;\n+    },\n+    goToNextTree: function(treeId,e){\n+      var next = false;\n+      for (var i=0; i<this.trees.length; i++){\n+        if (next){\n+          this.trees[i].focus();\n+          e.preventDefault();\n+          e.stopPropagation();\n+          return;\n+        }\n+        if (this.trees[i].id == treeId){\n+          next = true;\n+        }\n+      }\n+      e.preventDefault();\n+      e.stopPropagation();\n+    },\n+    goToPreviousTree: function(treeId, e){\n+      if (treeId == this.trees[0].id){\n+        return;\n+      }\n+      //otherwise, go to the previous tree class\n+      var next = false;\n+      for (var i=(this.trees.length - 1); i>=0; i--){\n+        if (next){\n+          this.trees[i].focus();\n+          e.preventDefault();\n+          e.stopPropagation();\n+          return;\n+        }\n+        if (this.trees[i].id == treeId){\n+          next = true;\n+        }\n+      }\n+      e.preventDefault();\n+      e.stopPropagation();\n+    },\n+    keyHandler: function(e, tree){\n+        var treeId = tree.id;\n+        var node = this.getActiveDesc(treeId);\n+        if (!node){\n+          console.log('KeyHandler: no active descendant');\n+        }\n+        console.log(e.keyCode);\n+        console.log('inside TreeService');\n+        switch(e.keyCode){\n+          case 9:\n+            //16,9: shift, tab\n+            if (e.shiftKey){\n+              console.log('shifttabbing');\n+              //if the previous key is shift, we're shift-tabbing mode\n+              this.goToPreviousTree(treeId,e);\n+            } else {\n+              //if previous key isn't shift, we're tabbing\n+              //we want to go to the run code button\n+              this.goToNextTree(treeId,e);\n+            }\n+            break;\n+          case 37:\n+            //left-facing arrow: go out a level, if possible. If not, do nothing\n+            e.preventDefault();\n+            e.stopPropagation();\n+            console.log('in left arrow section');\n+            var nextNode = node.parentNode;\n+            if (node.tagName == 'BUTTON' || node.tagName == 'INPUT'){\n+              nextNode = nextNode.parentNode;\n+            }\n+            while (nextNode && nextNode.className != 'treeview' && nextNode.tagName != 'LI') {\n+              nextNode = nextNode.parentNode;\n+            }\n+            if (nextNode.className == 'treeview' || nextNode == null){\n+              return;\n+            }\n+            this.updateSelectedNode(nextNode, tree);\n+            break;\n+          case 38:\n+            //up-facing arrow: go up a level, if possible. If not, do nothing\n+            e.preventDefault();\n+            e.stopPropagation();\n+            console.log('node passed in: ' + node.id);\n+            var prevSibling = this.getPreviousSibling(node);\n+            if (prevSibling && prevSibling.tagName != 'H1'){\n+              this.updateSelectedNode(prevSibling, tree);\n+            } else {\n+              console.log('no previous sibling');\n+            }\n+            break;\n+          case 39:\n+            e.preventDefault();\n+            e.stopPropagation();\n+            console.log('in right arrow section');\n+            var firstChild = this.getFirstChild(node);\n+            if (firstChild){\n+              this.updateSelectedNode(firstChild, tree);\n+            } else {\n+              console.log('no valid child');\n+            }\n+            break;\n+          case 40:\n+            //down-facing arrow: go down a level, if possible. If not, do nothing\n+            console.log('preventing propogation');\n+            e.preventDefault();\n+            e.stopPropagation();\n+            var nextSibling = this.getNextSibling(node);\n+            if (nextSibling){\n+              this.updateSelectedNode(nextSibling, tree);\n+            } else {\n+              console.log('no next sibling');\n+            }\n+            break;\n+          case 13:\n+            //if I've pressed enter, I want to interact with a child\n+            console.log('enter is pressed');\n+            var activeDesc = this.getActiveDesc(treeId);\n+            // if (activeDesc.tagName == 'BUTTON') {\n+            //   activeDesc.click();\n+            // }\n+            // if (activeDesc.tagName == 'INPUT'){\n+            //       activeDesc.focus();\n+            // }\n+            if (activeDesc){\n+              var children = activeDesc.children;\n+              var child = children[0];\n+              if (children.length == 1 && (child.tagName == 'INPUT' || child.tagName == 'BUTTON')){","path":"accessible/tree.service.js","position":190,"original_position":190,"commit_id":"0170fbef91cbcc4b84912dc614970256564e8e68","original_commit_id":"0170fbef91cbcc4b84912dc614970256564e8e68","user":{"login":"NeilFraser","id":250480,"avatar_url":"https://avatars.githubusercontent.com/u/250480?v=3","gravatar_id":"","url":"https://api.github.com/users/NeilFraser","html_url":"https://github.com/NeilFraser","followers_url":"https://api.github.com/users/NeilFraser/followers","following_url":"https://api.github.com/users/NeilFraser/following{/other_user}","gists_url":"https://api.github.com/users/NeilFraser/gists{/gist_id}","starred_url":"https://api.github.com/users/NeilFraser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/NeilFraser/subscriptions","organizations_url":"https://api.github.com/users/NeilFraser/orgs","repos_url":"https://api.github.com/users/NeilFraser/repos","events_url":"https://api.github.com/users/NeilFraser/events{/privacy}","received_events_url":"https://api.github.com/users/NeilFraser/received_events","type":"User","site_admin":false},"body":"Spaces.","created_at":"2016-04-29T22:24:43Z","updated_at":"2016-04-29T22:24:43Z","html_url":"https://github.com/google/blockly/pull/354#discussion_r61652825","pull_request_url":"https://api.github.com/repos/google/blockly/pulls/354","_links":{"self":{"href":"https://api.github.com/repos/google/blockly/pulls/comments/61652825"},"html":{"href":"https://github.com/google/blockly/pull/354#discussion_r61652825"},"pull_request":{"href":"https://api.github.com/repos/google/blockly/pulls/354"}}},"pull_request":{"url":"https://api.github.com/repos/google/blockly/pulls/354","id":68438554,"html_url":"https://github.com/google/blockly/pull/354","diff_url":"https://github.com/google/blockly/pull/354.diff","patch_url":"https://github.com/google/blockly/pull/354.patch","issue_url":"https://api.github.com/repos/google/blockly/issues/354","number":354,"state":"open","locked":false,"title":"AccessibleBlockly","user":{"login":"madCode","id":2229305,"avatar_url":"https://avatars.githubusercontent.com/u/2229305?v=3","gravatar_id":"","url":"https://api.github.com/users/madCode","html_url":"https://github.com/madCode","followers_url":"https://api.github.com/users/madCode/followers","following_url":"https://api.github.com/users/madCode/following{/other_user}","gists_url":"https://api.github.com/users/madCode/gists{/gist_id}","starred_url":"https://api.github.com/users/madCode/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/madCode/subscriptions","organizations_url":"https://api.github.com/users/madCode/orgs","repos_url":"https://api.github.com/users/madCode/repos","events_url":"https://api.github.com/users/madCode/events{/privacy}","received_events_url":"https://api.github.com/users/madCode/received_events","type":"User","site_admin":false},"body":"AccessibleBlockly is an alternative web UI for developers that is supports keyboard navigation. If the user is blind, AccessibleBlockly is best experienced in conjunction with NVDA or Jaws on Firefox on Windows.","created_at":"2016-04-29T21:45:54Z","updated_at":"2016-04-29T22:24:43Z","closed_at":null,"merged_at":null,"merge_commit_sha":"32d43a40667c980ce8c1258027a3a6a72f04008b","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/google/blockly/pulls/354/commits","review_comments_url":"https://api.github.com/repos/google/blockly/pulls/354/comments","review_comment_url":"https://api.github.com/repos/google/blockly/pulls/comments{/number}","comments_url":"https://api.github.com/repos/google/blockly/issues/354/comments","statuses_url":"https://api.github.com/repos/google/blockly/statuses/0170fbef91cbcc4b84912dc614970256564e8e68","head":{"label":"madCode:rebase-blind","ref":"rebase-blind","sha":"0170fbef91cbcc4b84912dc614970256564e8e68","user":{"login":"madCode","id":2229305,"avatar_url":"https://avatars.githubusercontent.com/u/2229305?v=3","gravatar_id":"","url":"https://api.github.com/users/madCode","html_url":"https://github.com/madCode","followers_url":"https://api.github.com/users/madCode/followers","following_url":"https://api.github.com/users/madCode/following{/other_user}","gists_url":"https://api.github.com/users/madCode/gists{/gist_id}","starred_url":"https://api.github.com/users/madCode/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/madCode/subscriptions","organizations_url":"https://api.github.com/users/madCode/orgs","repos_url":"https://api.github.com/users/madCode/repos","events_url":"https://api.github.com/users/madCode/events{/privacy}","received_events_url":"https://api.github.com/users/madCode/received_events","type":"User","site_admin":false},"repo":{"id":53075895,"name":"blockly","full_name":"madCode/blockly","owner":{"login":"madCode","id":2229305,"avatar_url":"https://avatars.githubusercontent.com/u/2229305?v=3","gravatar_id":"","url":"https://api.github.com/users/madCode","html_url":"https://github.com/madCode","followers_url":"https://api.github.com/users/madCode/followers","following_url":"https://api.github.com/users/madCode/following{/other_user}","gists_url":"https://api.github.com/users/madCode/gists{/gist_id}","starred_url":"https://api.github.com/users/madCode/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/madCode/subscriptions","organizations_url":"https://api.github.com/users/madCode/orgs","repos_url":"https://api.github.com/users/madCode/repos","events_url":"https://api.github.com/users/madCode/events{/privacy}","received_events_url":"https://api.github.com/users/madCode/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/madCode/blockly","description":"The web-based visual programming editor.","fork":true,"url":"https://api.github.com/repos/madCode/blockly","forks_url":"https://api.github.com/repos/madCode/blockly/forks","keys_url":"https://api.github.com/repos/madCode/blockly/keys{/key_id}","collaborators_url":"https://api.github.com/repos/madCode/blockly/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/madCode/blockly/teams","hooks_url":"https://api.github.com/repos/madCode/blockly/hooks","issue_events_url":"https://api.github.com/repos/madCode/blockly/issues/events{/number}","events_url":"https://api.github.com/repos/madCode/blockly/events","assignees_url":"https://api.github.com/repos/madCode/blockly/assignees{/user}","branches_url":"https://api.github.com/repos/madCode/blockly/branches{/branch}","tags_url":"https://api.github.com/repos/madCode/blockly/tags","blobs_url":"https://api.github.com/repos/madCode/blockly/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/madCode/blockly/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/madCode/blockly/git/refs{/sha}","trees_url":"https://api.github.com/repos/madCode/blockly/git/trees{/sha}","statuses_url":"https://api.github.com/repos/madCode/blockly/statuses/{sha}","languages_url":"https://api.github.com/repos/madCode/blockly/languages","stargazers_url":"https://api.github.com/repos/madCode/blockly/stargazers","contributors_url":"https://api.github.com/repos/madCode/blockly/contributors","subscribers_url":"https://api.github.com/repos/madCode/blockly/subscribers","subscription_url":"https://api.github.com/repos/madCode/blockly/subscription","commits_url":"https://api.github.com/repos/madCode/blockly/commits{/sha}","git_commits_url":"https://api.github.com/repos/madCode/blockly/git/commits{/sha}","comments_url":"https://api.github.com/repos/madCode/blockly/comments{/number}","issue_comment_url":"https://api.github.com/repos/madCode/blockly/issues/comments{/number}","contents_url":"https://api.github.com/repos/madCode/blockly/contents/{+path}","compare_url":"https://api.github.com/repos/madCode/blockly/compare/{base}...{head}","merges_url":"https://api.github.com/repos/madCode/blockly/merges","archive_url":"https://api.github.com/repos/madCode/blockly/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/madCode/blockly/downloads","issues_url":"https://api.github.com/repos/madCode/blockly/issues{/number}","pulls_url":"https://api.github.com/repos/madCode/blockly/pulls{/number}","milestones_url":"https://api.github.com/repos/madCode/blockly/milestones{/number}","notifications_url":"https://api.github.com/repos/madCode/blockly/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/madCode/blockly/labels{/name}","releases_url":"https://api.github.com/repos/madCode/blockly/releases{/id}","deployments_url":"https://api.github.com/repos/madCode/blockly/deployments","created_at":"2016-03-03T19:09:31Z","updated_at":"2016-03-19T05:32:02Z","pushed_at":"2016-04-29T21:41:24Z","git_url":"git://github.com/madCode/blockly.git","ssh_url":"git@github.com:madCode/blockly.git","clone_url":"https://github.com/madCode/blockly.git","svn_url":"https://github.com/madCode/blockly","homepage":"https://developers.google.com/blockly/","size":73445,"stargazers_count":1,"watchers_count":1,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":0,"forks":1,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"google:develop","ref":"develop","sha":"6c0bf9f9662615cded68f1ae587042f20934694a","user":{"login":"google","id":1342004,"avatar_url":"https://avatars.githubusercontent.com/u/1342004?v=3","gravatar_id":"","url":"https://api.github.com/users/google","html_url":"https://github.com/google","followers_url":"https://api.github.com/users/google/followers","following_url":"https://api.github.com/users/google/following{/other_user}","gists_url":"https://api.github.com/users/google/gists{/gist_id}","starred_url":"https://api.github.com/users/google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/google/subscriptions","organizations_url":"https://api.github.com/users/google/orgs","repos_url":"https://api.github.com/users/google/repos","events_url":"https://api.github.com/users/google/events{/privacy}","received_events_url":"https://api.github.com/users/google/received_events","type":"Organization","site_admin":false},"repo":{"id":13872231,"name":"blockly","full_name":"google/blockly","owner":{"login":"google","id":1342004,"avatar_url":"https://avatars.githubusercontent.com/u/1342004?v=3","gravatar_id":"","url":"https://api.github.com/users/google","html_url":"https://github.com/google","followers_url":"https://api.github.com/users/google/followers","following_url":"https://api.github.com/users/google/following{/other_user}","gists_url":"https://api.github.com/users/google/gists{/gist_id}","starred_url":"https://api.github.com/users/google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/google/subscriptions","organizations_url":"https://api.github.com/users/google/orgs","repos_url":"https://api.github.com/users/google/repos","events_url":"https://api.github.com/users/google/events{/privacy}","received_events_url":"https://api.github.com/users/google/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/google/blockly","description":"The web-based visual programming editor.","fork":false,"url":"https://api.github.com/repos/google/blockly","forks_url":"https://api.github.com/repos/google/blockly/forks","keys_url":"https://api.github.com/repos/google/blockly/keys{/key_id}","collaborators_url":"https://api.github.com/repos/google/blockly/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/google/blockly/teams","hooks_url":"https://api.github.com/repos/google/blockly/hooks","issue_events_url":"https://api.github.com/repos/google/blockly/issues/events{/number}","events_url":"https://api.github.com/repos/google/blockly/events","assignees_url":"https://api.github.com/repos/google/blockly/assignees{/user}","branches_url":"https://api.github.com/repos/google/blockly/branches{/branch}","tags_url":"https://api.github.com/repos/google/blockly/tags","blobs_url":"https://api.github.com/repos/google/blockly/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/google/blockly/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/google/blockly/git/refs{/sha}","trees_url":"https://api.github.com/repos/google/blockly/git/trees{/sha}","statuses_url":"https://api.github.com/repos/google/blockly/statuses/{sha}","languages_url":"https://api.github.com/repos/google/blockly/languages","stargazers_url":"https://api.github.com/repos/google/blockly/stargazers","contributors_url":"https://api.github.com/repos/google/blockly/contributors","subscribers_url":"https://api.github.com/repos/google/blockly/subscribers","subscription_url":"https://api.github.com/repos/google/blockly/subscription","commits_url":"https://api.github.com/repos/google/blockly/commits{/sha}","git_commits_url":"https://api.github.com/repos/google/blockly/git/commits{/sha}","comments_url":"https://api.github.com/repos/google/blockly/comments{/number}","issue_comment_url":"https://api.github.com/repos/google/blockly/issues/comments{/number}","contents_url":"https://api.github.com/repos/google/blockly/contents/{+path}","compare_url":"https://api.github.com/repos/google/blockly/compare/{base}...{head}","merges_url":"https://api.github.com/repos/google/blockly/merges","archive_url":"https://api.github.com/repos/google/blockly/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/google/blockly/downloads","issues_url":"https://api.github.com/repos/google/blockly/issues{/number}","pulls_url":"https://api.github.com/repos/google/blockly/pulls{/number}","milestones_url":"https://api.github.com/repos/google/blockly/milestones{/number}","notifications_url":"https://api.github.com/repos/google/blockly/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/google/blockly/labels{/name}","releases_url":"https://api.github.com/repos/google/blockly/releases{/id}","deployments_url":"https://api.github.com/repos/google/blockly/deployments","created_at":"2013-10-25T21:13:33Z","updated_at":"2016-04-29T21:53:10Z","pushed_at":"2016-04-29T21:45:54Z","git_url":"git://github.com/google/blockly.git","ssh_url":"git@github.com:google/blockly.git","clone_url":"https://github.com/google/blockly.git","svn_url":"https://github.com/google/blockly","homepage":"https://developers.google.com/blockly/","size":97726,"stargazers_count":2238,"watchers_count":2238,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":728,"mirror_url":null,"open_issues_count":87,"forks":728,"open_issues":87,"watchers":2238,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/google/blockly/pulls/354"},"html":{"href":"https://github.com/google/blockly/pull/354"},"issue":{"href":"https://api.github.com/repos/google/blockly/issues/354"},"comments":{"href":"https://api.github.com/repos/google/blockly/issues/354/comments"},"review_comments":{"href":"https://api.github.com/repos/google/blockly/pulls/354/comments"},"review_comment":{"href":"https://api.github.com/repos/google/blockly/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/google/blockly/pulls/354/commits"},"statuses":{"href":"https://api.github.com/repos/google/blockly/statuses/0170fbef91cbcc4b84912dc614970256564e8e68"}}}}