| <!-- The <detail-list2-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: |
| data - Takes a search.NewSearchResponse describing search results to be |
| displayed. |
| |
| 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="digest-details2-sk.html"> |
| <link rel="import" href="zoom-dialog-sk.html"> |
| <link rel="import" href="help-dialog-sk.html"> |
| |
| <dom-module id="detail-list2-sk"> |
| <style type="text/css" media="screen"> |
| digest-details2-sk { |
| display: block; |
| box-shadow: 3px 3px 6px 1px rgba(133,133,133,1); |
| margin-top: 1em; |
| margin-bottom: 1em; |
| margin-left: 0; |
| margin-right: 0; |
| padding-left: 1em; |
| padding-top: 1em; |
| padding-bottom: 1em; |
| padding-right: 0; |
| } |
| |
| paper-button { |
| background: #1F78B4; |
| color: white; |
| } |
| |
| #indexStatus { |
| font-weight: bold; |
| font-size: 130%; |
| margin-left: 2em; |
| } |
| </style> |
| <template> |
| <div> |
| <paper-button on-tap=_focusFirst title="<" disabled$="[[_isFirst(_index)]]" raised>|<</paper-button> |
| <paper-button on-tap=_focusPrev title="k" disabled$="[[_isFirst(_index)]]" raised>Prev</paper-button> |
| <paper-button on-tap=_focusNext title="j" disabled$="[[_isLast(_index)]]" raised>Next</paper-button> |
| <paper-button on-tap=_focusLast title=">" disabled$="[[_isLast(_index)]]" raised>>|</paper-button> |
| <span id=indexStatus>Digest: [[_plusone(_index)]]/[[data.size]]</span> |
| </div> |
| |
| <digest-details2-sk |
| id="digestdetails" |
| mode="list" |
| triage |
| details="[[_item]]" |
| commits="[[data.commits]]" |
| issue="[[data.issue.id]]"> |
| </digest-details2-sk> |
| |
| <!-- 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><</th><td>First</td></tr> |
| <tr><th>></th><td>Last</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-list2-sk', |
| |
| properties: { |
| data: { |
| type: Object, |
| value: function() { |
| return { |
| digests: [], |
| commits: [], |
| issue: null, |
| offset: 0, |
| size: 0, |
| } |
| }, |
| reflectToAttribute: false, |
| observer: "_dataChange", |
| }, |
| _item: { |
| type: Object, |
| value: null, |
| reflectToAttribute: false, |
| }, |
| }, |
| |
| ready: function () { |
| this._zooming = false; |
| this._index = 0; |
| |
| 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(); |
| }, |
| |
| _dataChange: function() { |
| this._index = 0; |
| if (!this.data || !this.data.digests || this.data.digests.length === 0) { |
| return |
| } |
| this.set('_item', this.data.digests[0]); |
| }, |
| |
| _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 '<': |
| this._focusFirst(); |
| break; |
| case '>': |
| this._focusLast(); |
| 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 this.$.digestdetails; |
| }, |
| |
| // Move the focus to the next digest. |
| _focusNext: function () { |
| if (this.data.digests.length === 0) { |
| return |
| } |
| this._index = this._index+1; |
| if (this._index >= this.data.digests.length) { |
| this._index = this.data.digests.length-1 |
| } |
| this.set('_item', this.data.digests[this._index]); |
| }, |
| |
| // Move the focus to the previous digest. |
| _focusPrev: function () { |
| if (this.data.digests.length === 0) { |
| return |
| } |
| this._index = this._index-1; |
| if (this._index < 0) { |
| this._index = 0; |
| } |
| this.set('_item', this.data.digests[this._index]); |
| }, |
| |
| _focusFirst: function () { |
| if (this.data.digests.length === 0) { |
| return |
| } |
| this._index = 0; |
| this.set('_item', this.data.digests[this._index]); |
| }, |
| |
| _focusLast: function () { |
| if (this.data.digests.length === 0) { |
| return |
| } |
| this._index = this.data.digests.length-1; |
| this.set('_item', this.data.digests[this._index]); |
| }, |
| |
| _markFocus: function (status) { |
| var ele = this._findFocus(); |
| if (ele && ele.triggerTriage) { |
| ele.triggerTriage(status); |
| } |
| }, |
| |
| _plusone: function(index) { |
| return index+1; |
| }, |
| |
| _isFirst: function(index) { |
| return index === 0; |
| }, |
| |
| _isLast: function(index) { |
| if (this.data.digests) { |
| return index === this.data.digests.length-1; |
| } |
| return true; |
| }, |
| |
| }); |
| </script> |
| </dom-module> |