Merge pull request #922 from glowing-bear/buffer-jump
Implement Alt+J buffer jump like in WeeChat
This commit is contained in:
commit
539f892e8e
5 changed files with 143 additions and 11 deletions
|
@ -73,10 +73,29 @@ td.message {
|
||||||
border-bottom: 2px solid #555;
|
border-bottom: 2px solid #555;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-group-addon, .input-group-btn {
|
.input-group-btn {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input-group-addon {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#jump-addon {
|
||||||
|
width: 0px;
|
||||||
|
max-width: 0px;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all ease-in-out 0.5s;
|
||||||
|
}
|
||||||
|
.showjumpkeys #jump-addon {
|
||||||
|
width: auto;
|
||||||
|
max-width: 70px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.footer button {
|
.footer button {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
@ -466,6 +485,33 @@ div.colourbox {
|
||||||
align: right;
|
align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#sidebar .showjumpkeys .buffer .buffer-jump-key {
|
||||||
|
transition: all ease-in-out 0.2s;
|
||||||
|
-webkit-transition: all ease-in-out 0.2s;
|
||||||
|
transition-delay: 0s;
|
||||||
|
-webkit-transition-delay: 0s;
|
||||||
|
opacity: 0.7;
|
||||||
|
margin-left: -1.2em;
|
||||||
|
margin-right: 0.1em;
|
||||||
|
}
|
||||||
|
#sidebar .buffer .buffer-jump-key {
|
||||||
|
margin-left: -1.2em;
|
||||||
|
margin-right: -0.2em;
|
||||||
|
font-size: smaller;
|
||||||
|
transition: all ease-in-out 0.2s;
|
||||||
|
-webkit-transition: all ease-in-out 0.2s;
|
||||||
|
opacity: 0;
|
||||||
|
text-shadow: -1px 0px 4px rgba(255, 255, 255, 0.4),
|
||||||
|
0px -1px 4px rgba(255, 255, 255, 0.4),
|
||||||
|
1px 0px 4px rgba(255, 255, 255, 0.4),
|
||||||
|
0px 1px 4px rgba(255, 255, 255, 0.4);
|
||||||
|
vertical-align: baseline;
|
||||||
|
display: inline-block;
|
||||||
|
width: 1em;
|
||||||
|
align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.gb-modal {
|
.gb-modal {
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
10
index.html
10
index.html
|
@ -262,10 +262,13 @@ npm run build-electron-{windows, darwin, linux}</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="sidebar" data-state="visible" ng-swipe-left="hideSidebar()" ng-swipe-disable-mouse class="vertical-line">
|
<div id="sidebar" data-state="visible" ng-swipe-left="hideSidebar()" ng-swipe-disable-mouse class="vertical-line">
|
||||||
<ul class="nav nav-pills nav-stacked" ng-class="{'indented': (predicate === 'serverSortKey'), 'showquickkeys': showQuickKeys}">
|
<ul class="nav nav-pills nav-stacked" ng-class="{'indented': (predicate === 'serverSortKey'), 'showquickkeys': showQuickKeys, 'showjumpkeys': showJumpKeys}">
|
||||||
<li class="bufferfilter">
|
<li class="bufferfilter">
|
||||||
<form role="form">
|
<form role="form">
|
||||||
<input class="form-control favorite-font" type="text" id="bufferFilter" ng-model="search" ng-keydown="handleSearchBoxKey($event)" placeholder="Search" autocomplete="off">
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon" id="jump-addon">Jump</span>
|
||||||
|
<input class="form-control favorite-font" type="text" id="bufferFilter" ng-model="search" ng-keydown="handleSearchBoxKey($event)" placeholder="{{ search_placeholder || 'Search' }}" autocomplete="off" aria-describedby="jump-addon">
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
<li class="buffer" ng-class="{'active': buffer.active,
|
<li class="buffer" ng-class="{'active': buffer.active,
|
||||||
|
@ -278,10 +281,11 @@ npm run build-electron-{windows, darwin, linux}</pre>
|
||||||
'channel_plus': buffer.prefix === '+',
|
'channel_plus': buffer.prefix === '+',
|
||||||
'channel_ampersand': buffer.prefix === '&',
|
'channel_ampersand': buffer.prefix === '&',
|
||||||
'private': buffer.type === 'private'}"
|
'private': buffer.type === 'private'}"
|
||||||
ng-repeat="(key, buffer) in (filteredBuffers = (getBuffers() | toArray:'withidx' | filter:{fullName:search} | filter:hasUnread | orderBy:predicate | getBufferQuickKeys:this))">
|
ng-repeat="(key, buffer) in (filteredBuffers = (getBuffers() | toArray:'withidx' | filter:bufferlistfilter | filter:hasUnread | orderBy:predicate | getBufferQuickKeys:this))">
|
||||||
<a ng-click="setActiveBuffer(buffer.id)" title="{{ buffer.fullName }}" href="#">
|
<a ng-click="setActiveBuffer(buffer.id)" title="{{ buffer.fullName }}" href="#">
|
||||||
<span class="badge pull-right" ng-class="{'danger': buffer.notification}" ng-bind="buffer.notification || buffer.unread"></span>
|
<span class="badge pull-right" ng-class="{'danger': buffer.notification}" ng-bind="buffer.notification || buffer.unread"></span>
|
||||||
<span class="buffer-quick-key">{{ buffer.$quickKey }}</span>
|
<span class="buffer-quick-key">{{ buffer.$quickKey }}</span>
|
||||||
|
<span class="buffer-jump-key">{{ ("0" + buffer.$jumpKey).slice(-2) }}</span>
|
||||||
<span class="buffername">{{ buffer.trimmedName || buffer.fullName }}</span>
|
<span class="buffername">{{ buffer.trimmedName || buffer.fullName }}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -162,6 +162,11 @@ weechat.filter('getBufferQuickKeys', function () {
|
||||||
return left[0] - right[0] || left[1] - right[1];
|
return left[0] - right[0] || left[1] - right[1];
|
||||||
}).forEach(function(info, keyIdx) {
|
}).forEach(function(info, keyIdx) {
|
||||||
obj[ info[2] ].$quickKey = keyIdx < 10 ? (keyIdx + 1) % 10 : '';
|
obj[ info[2] ].$quickKey = keyIdx < 10 ? (keyIdx + 1) % 10 : '';
|
||||||
|
// Don't update jump key upon filtering
|
||||||
|
if (obj[ info[2] ].$jumpKey === undefined) {
|
||||||
|
// Only assign jump keys up to 99
|
||||||
|
obj[ info[2] ].$jumpKey = (keyIdx < 99) ? keyIdx + 1 : '';
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
|
|
|
@ -216,6 +216,7 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout',
|
||||||
|
|
||||||
// Clear search term on buffer change
|
// Clear search term on buffer change
|
||||||
$scope.search = '';
|
$scope.search = '';
|
||||||
|
$scope.search_placeholder = 'Search';
|
||||||
|
|
||||||
if (!utils.isMobileUi()) {
|
if (!utils.isMobileUi()) {
|
||||||
// This needs to happen asynchronously to prevent the enter key handler
|
// This needs to happen asynchronously to prevent the enter key handler
|
||||||
|
@ -374,9 +375,20 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Watch model and update channel sorting when it changes
|
// Watch model and update channel sorting when it changes
|
||||||
settings.addCallback('orderbyserver', function(orderbyserver) {
|
var set_filter_predicate = function(orderbyserver) {
|
||||||
$rootScope.predicate = orderbyserver ? 'serverSortKey' : 'number';
|
if ($rootScope.showJumpKeys) {
|
||||||
});
|
$rootScope.predicate = '$jumpKey';
|
||||||
|
} else if (orderbyserver) {
|
||||||
|
$rootScope.predicate = 'serverSortKey';
|
||||||
|
} else {
|
||||||
|
$rootScope.predicate = 'number';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
settings.addCallback('orderbyserver', set_filter_predicate);
|
||||||
|
// convenience wrapper for jump keys
|
||||||
|
$rootScope.refresh_filter_predicate = function() {
|
||||||
|
set_filter_predicate(settings.orderbyserver);
|
||||||
|
};
|
||||||
|
|
||||||
settings.addCallback('useFavico', function(useFavico) {
|
settings.addCallback('useFavico', function(useFavico) {
|
||||||
// this check is necessary as this is called on page load, too
|
// this check is necessary as this is called on page load, too
|
||||||
|
@ -684,6 +696,25 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout',
|
||||||
return !buffer.hidden;
|
return !buffer.hidden;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// filter bufferlist for search or jump key
|
||||||
|
$rootScope.bufferlistfilter = function(buffer) {
|
||||||
|
if ($rootScope.showJumpKeys) {
|
||||||
|
// filter by jump key
|
||||||
|
if ($rootScope.jumpDecimal === undefined) {
|
||||||
|
// no digit input yet, show all buffers
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
var min_jumpKey = 10 * $rootScope.jumpDecimal,
|
||||||
|
max_jumpKey = 10 * ($rootScope.jumpDecimal + 1);
|
||||||
|
return (min_jumpKey <= buffer.$jumpKey) &&
|
||||||
|
(buffer.$jumpKey < max_jumpKey);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// filter by buffer name
|
||||||
|
return buffer.fullName.indexOf($scope.search) !== -1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Watch model and update show setting when it changes
|
// Watch model and update show setting when it changes
|
||||||
settings.addCallback('nonicklist', function() {
|
settings.addCallback('nonicklist', function() {
|
||||||
$scope.showNicklist = $scope.updateShowNicklist();
|
$scope.showNicklist = $scope.updateShowNicklist();
|
||||||
|
|
|
@ -277,17 +277,53 @@ weechat.directive('inputBar', function() {
|
||||||
var tmpIterCandidate = $scope.iterCandidate;
|
var tmpIterCandidate = $scope.iterCandidate;
|
||||||
$scope.iterCandidate = null;
|
$scope.iterCandidate = null;
|
||||||
|
|
||||||
|
var bufferNumber;
|
||||||
|
var sortedBuffers;
|
||||||
|
var filteredBufferNum;
|
||||||
|
var activeBufferId;
|
||||||
|
|
||||||
|
// if Alt+J was pressed last...
|
||||||
|
if ($rootScope.showJumpKeys) {
|
||||||
|
var cleanup = function() { // cleanup helper
|
||||||
|
$rootScope.showJumpKeys = false;
|
||||||
|
$rootScope.jumpDecimal = undefined;
|
||||||
|
$scope.$parent.search = '';
|
||||||
|
$scope.$parent.search_placeholder = 'Search';
|
||||||
|
$rootScope.refresh_filter_predicate();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ... we expect two digits now
|
||||||
|
if (!$event.altKey && (code > 47 && code < 58)) {
|
||||||
|
// first digit
|
||||||
|
if ($rootScope.jumpDecimal === undefined) {
|
||||||
|
$rootScope.jumpDecimal = code - 48;
|
||||||
|
$event.preventDefault();
|
||||||
|
$scope.$parent.search = $rootScope.jumpDecimal;
|
||||||
|
$rootScope.refresh_filter_predicate();
|
||||||
|
// second digit, jump to correct buffer
|
||||||
|
} else {
|
||||||
|
bufferNumber = ($rootScope.jumpDecimal * 10) + (code - 48);
|
||||||
|
$scope.$parent.setActiveBuffer(bufferNumber, '$jumpKey');
|
||||||
|
|
||||||
|
$event.preventDefault();
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not a decimal digit, abort
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Left Alt+[0-9] -> jump to buffer
|
// Left Alt+[0-9] -> jump to buffer
|
||||||
if ($event.altKey && !$event.ctrlKey && (code > 47 && code < 58) && settings.enableQuickKeys) {
|
if ($event.altKey && !$event.ctrlKey && (code > 47 && code < 58) && settings.enableQuickKeys) {
|
||||||
if (code === 48) {
|
if (code === 48) {
|
||||||
code = 58;
|
code = 58;
|
||||||
}
|
}
|
||||||
var bufferNumber = code - 48 - 1 ;
|
bufferNumber = code - 48 - 1 ;
|
||||||
|
|
||||||
var activeBufferId;
|
|
||||||
// quick select filtered entries
|
// quick select filtered entries
|
||||||
if (($scope.$parent.search.length || $scope.$parent.onlyUnread) && $scope.$parent.filteredBuffers.length) {
|
if (($scope.$parent.search.length || $scope.$parent.onlyUnread) && $scope.$parent.filteredBuffers.length) {
|
||||||
var filteredBufferNum = $scope.$parent.filteredBuffers[bufferNumber];
|
filteredBufferNum = $scope.$parent.filteredBuffers[bufferNumber];
|
||||||
if (filteredBufferNum !== undefined) {
|
if (filteredBufferNum !== undefined) {
|
||||||
activeBufferId = [filteredBufferNum.number, filteredBufferNum.id];
|
activeBufferId = [filteredBufferNum.number, filteredBufferNum.id];
|
||||||
}
|
}
|
||||||
|
@ -295,7 +331,7 @@ weechat.directive('inputBar', function() {
|
||||||
// Map the buffers to only their numbers and IDs so we don't have to
|
// Map the buffers to only their numbers and IDs so we don't have to
|
||||||
// copy the entire (possibly very large) buffer object, and then sort
|
// copy the entire (possibly very large) buffer object, and then sort
|
||||||
// the buffers according to their WeeChat number
|
// the buffers according to their WeeChat number
|
||||||
var sortedBuffers = _.map(models.getBuffers(), function(buffer) {
|
sortedBuffers = _.map(models.getBuffers(), function(buffer) {
|
||||||
return [buffer.number, buffer.id];
|
return [buffer.number, buffer.id];
|
||||||
}).sort(function(left, right) {
|
}).sort(function(left, right) {
|
||||||
// By default, Array.prototype.sort() sorts alphabetically.
|
// By default, Array.prototype.sort() sorts alphabetically.
|
||||||
|
@ -402,6 +438,16 @@ weechat.directive('inputBar', function() {
|
||||||
connection.sendHotlistClearAll();
|
connection.sendHotlistClearAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Alt+J -> Jump to buffer
|
||||||
|
if ($event.altKey && (code === 106 || code === 74)) {
|
||||||
|
$event.preventDefault();
|
||||||
|
// reset search state and show jump keys
|
||||||
|
$scope.$parent.search = '';
|
||||||
|
$scope.$parent.search_placeholder = 'Number';
|
||||||
|
$rootScope.showJumpKeys = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
var caretPos;
|
var caretPos;
|
||||||
|
|
||||||
// Arrow up -> go up in history
|
// Arrow up -> go up in history
|
||||||
|
|
Loading…
Reference in a new issue