| <!-- The <detail-list-sk> custom element declaration. |
| |
| Manages a list of child elements like digest-detail-sk |
| that produce zoom-clicked, triage and commit-info events. |
| |
| Handles the events and also focus highlighting. |
| It also responds to keyboard shortcuts. Since keyboard events |
| are registered against the global 'document' object, it provides |
| the 'startUse' and 'endUse' functions to indicate when this element |
| is active. This is particularly important if it's part of dynamic |
| behavior like pop-up dialogs. |
| |
| Attributes: |
| None |
| |
| Events: |
| None |
| |
| Methods: |
| startUse - to be called before the element is atively being used. |
| It registers the necessary keyboard shortcuts. |
| |
| endUse - to be called once the element is not used any more. |
| |
| openHelpDialog - opens the help dialog for key bindings. |
| --> |
| |
| <link rel="import" href="zoom-dialog-sk.html"> |
| <link rel="import" href="help-dialog-sk.html"> |
| |
| <dom-module id="detail-list-sk"> |
| <template> |
| <content></content> |
| |
| <!-- zoom dialog --> |
| <zoom-dialog-sk id="detailsZoomDialog"></zoom-dialog-sk> |
| |
| <!-- help dialog --> |
| <help-dialog-sk id="helpDialog"> |
| <table> |
| <tr><th colspan=2>Keyboard Shortcuts</th></tr> |
| <tr><th>J</th><td>Next</td></tr> |
| <tr><th>K</th><td>Prev</td></tr> |
| <tr><th>W</th><td>Zoom</td></tr> |
| <tr><th>A</th><td>Postive</td></tr> |
| <tr><th>S</th><td>Negative</td></tr> |
| <tr><th>D</th><td>Untriaged</td></tr> |
| <tr><th>?</th><td>Help</td></tr> |
| </table> |
| </help-dialog-sk> |
| </template> |
| <script> |
| Polymer({ |
| is: 'detail-list-sk', |
| |
| ready: function () { |
| this._zooming = false; |
| |
| this.listen(this, 'zoom-clicked', "_handleZoomClicked"); |
| this.listen(this, 'iron-overlay-closed', '_handleZoomClosed'); |
| this.listen(this, 'triage', '_handleTriage'); |
| }, |
| |
| startUse: function() { |
| this.listen(document, 'keypress', '_handleKeyDown'); |
| }, |
| |
| endUse: function() { |
| this.unlisten(document, 'keypress', '_handleKeyDown'); |
| }, |
| |
| openHelpDialog: function() { |
| this.$.helpDialog.open(); |
| }, |
| |
| _handleKeyDown: function(e) { |
| if (this._zooming) { |
| return; |
| } |
| |
| var c = String.fromCharCode(e.keyCode).toUpperCase(); |
| switch (c) { |
| case 'J': |
| this._focusNext(); |
| break; |
| case 'K': |
| this._focusPrev(); |
| break; |
| case 'A': |
| this._markFocus('positive'); |
| break; |
| case 'S': |
| this._markFocus('negative'); |
| break; |
| case 'D': |
| this._markFocus('untriaged'); |
| break; |
| case 'W': |
| this._handleZoomClicked(); |
| break; |
| case '?': |
| this.openHelpDialog(); |
| break; |
| } |
| }, |
| |
| _handleZoomClosed: function (ev) { |
| this._zooming = false; |
| }, |
| |
| _handleZoomClicked: function (ev) { |
| var zoomDetail; |
| |
| // This was triggerd by a keyboard shortcut. |
| if (!ev) { |
| var ele = this._findFocus(); |
| if (ele == null) { |
| return |
| } |
| // Extract the zoom information from the element. |
| zoomDetail = ele.getZoomDetail(); |
| } else { |
| zoomDetail = ev.detail; |
| ev.stopPropagation(); |
| } |
| |
| this.$.detailsZoomDialog.open(zoomDetail); |
| this._zooming = true; |
| }, |
| |
| _handleTriage: function (ev) { |
| sk.post('/json/triage', JSON.stringify(ev.detail)).catch(sk.errorMessage); |
| }, |
| |
| // _findFocus returns the current details element with the keyboard focus. |
| _findFocus: function () { |
| return $$$('[data-focus]', this); |
| }, |
| |
| // _moveFocus does the actual work of changing the focus from lastEle |
| // to nextEle. |
| _moveFocus: function (lastEle, nextEle) { |
| // Don't wrap around past the bottom of the list. |
| if (lastEle != null && nextEle == null) { |
| return; |
| } |
| |
| if (lastEle != null) { |
| Polymer.dom(lastEle).removeAttribute('data-focus'); |
| } |
| |
| // If nothing is selected, then focus on the first details element. |
| if (nextEle == null) { |
| nextEle = Polymer.dom(this).firstElementChild; |
| } |
| |
| Polymer.dom(nextEle).setAttribute('data-focus', 'true'); |
| nextEle.scrollIntoView(true); |
| }, |
| |
| _focusSet: function (ele) { |
| var lastEle = this._findFocus(); |
| this._moveFocus(lastEle, ele); |
| }, |
| |
| // Move the focus to the next digest. |
| _focusNext: function () { |
| var nextEle = null; |
| var lastEle = this._findFocus(); |
| |
| if (lastEle != null) { |
| nextEle = lastEle.nextElementSibling; |
| if (nextEle.nodeName == 'TEMPLATE') { |
| nextEle = null; |
| } |
| } |
| this._moveFocus(lastEle, nextEle); |
| }, |
| |
| // Move the focus to the previous digest. |
| _focusPrev: function () { |
| var nextEle = null; |
| var lastEle = this._findFocus(); |
| |
| if (lastEle != null) { |
| nextEle = lastEle.previousElementSibling; |
| } |
| this._moveFocus(lastEle, nextEle); |
| }, |
| |
| _markFocus: function (status) { |
| var ele = this._findFocus(); |
| if (ele && ele.triggerTriage) { |
| ele.triggerTriage(status); |
| } |
| } |
| }); |
| </script> |
| </dom-module> |