blob: e091dd4a73c8d558a4d8bcd0b557e9ca625a8b7b [file] [log] [blame]
<!-- 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>