Merge pull request #856 from thelounge/astorije/fuzzy-match-user-list
Implement fuzzy-matching for the user list
This commit is contained in:
commit
586dde7761
@ -765,6 +765,9 @@ kbd {
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#chat .channel .chat {
|
||||
right: 180px;
|
||||
}
|
||||
|
||||
@ -788,18 +791,6 @@ kbd {
|
||||
transform: translateZ(0);
|
||||
}
|
||||
|
||||
#chat .lobby .chat,
|
||||
#chat .special .chat,
|
||||
#chat .query .chat {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#chat .lobby .sidebar,
|
||||
#chat .special .sidebar,
|
||||
#chat .query .sidebar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#chat .show-more {
|
||||
display: none;
|
||||
padding: 10px;
|
||||
@ -1177,6 +1168,10 @@ kbd {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#chat .names-filtered {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#chat .names .user {
|
||||
display: block;
|
||||
line-height: 1.6;
|
||||
@ -1216,6 +1211,10 @@ kbd {
|
||||
content: "Users";
|
||||
}
|
||||
|
||||
#chat .user-mode-search:before {
|
||||
content: "Search Results";
|
||||
}
|
||||
|
||||
#loading {
|
||||
font-size: 14px;
|
||||
z-index: 1;
|
||||
|
@ -1,5 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = function(count) {
|
||||
return count + " " + (count === 1 ? "user" : "users");
|
||||
};
|
@ -7,6 +7,7 @@ const $ = require("jquery");
|
||||
const moment = require("moment");
|
||||
const Mousetrap = require("mousetrap");
|
||||
const URI = require("urijs");
|
||||
const fuzzy = require("fuzzy");
|
||||
|
||||
// our libraries
|
||||
const emojiMap = require("./libs/simplemap.json");
|
||||
@ -320,8 +321,11 @@ $(function() {
|
||||
|
||||
function renderChannel(data) {
|
||||
renderChannelMessages(data);
|
||||
|
||||
if (data.type === "channel") {
|
||||
renderChannelUsers(data);
|
||||
}
|
||||
}
|
||||
|
||||
function renderChannelMessages(data) {
|
||||
var documentFragment = buildChannelMessages(data.id, data.messages);
|
||||
@ -380,7 +384,19 @@ $(function() {
|
||||
return (oldSortOrder[a] || Number.MAX_VALUE) - (oldSortOrder[b] || Number.MAX_VALUE);
|
||||
});
|
||||
|
||||
users.html(templates.user(data)).data("nicks", nicks);
|
||||
const search = users
|
||||
.find(".search")
|
||||
.attr("placeholder", nicks.length + " " + (nicks.length === 1 ? "user" : "users"));
|
||||
|
||||
users
|
||||
.find(".names-original")
|
||||
.html(templates.user(data))
|
||||
.data("nicks", nicks);
|
||||
|
||||
// Refresh user search
|
||||
if (search.val().length) {
|
||||
search.trigger("input");
|
||||
}
|
||||
}
|
||||
|
||||
function renderNetworks(data) {
|
||||
@ -1022,17 +1038,31 @@ $(function() {
|
||||
});
|
||||
|
||||
chat.on("input", ".search", function() {
|
||||
var value = $(this).val().toLowerCase();
|
||||
var names = $(this).closest(".users").find(".names");
|
||||
names.find(".user").each(function() {
|
||||
var btn = $(this);
|
||||
var name = btn.text().toLowerCase().replace(/[+%@~]/, "");
|
||||
if (name.indexOf(value) > -1) {
|
||||
btn.show();
|
||||
} else {
|
||||
btn.hide();
|
||||
const value = $(this).val();
|
||||
const parent = $(this).closest(".users");
|
||||
const names = parent.find(".names-original");
|
||||
const container = parent.find(".names-filtered");
|
||||
|
||||
if (!value.length) {
|
||||
container.hide();
|
||||
names.show();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
const fuzzyOptions = {
|
||||
pre: "<b>",
|
||||
post: "</b>",
|
||||
extract: el => $(el).text()
|
||||
};
|
||||
|
||||
const result = fuzzy.filter(
|
||||
value,
|
||||
names.find(".user").toArray(),
|
||||
fuzzyOptions
|
||||
);
|
||||
|
||||
names.hide();
|
||||
container.html(templates.user_filtered({matches: result})).show();
|
||||
});
|
||||
|
||||
chat.on("msg", ".messages", function(e, target, msg) {
|
||||
|
@ -19,8 +19,16 @@
|
||||
</div>
|
||||
<div class="messages"></div>
|
||||
</div>
|
||||
{{#equal type "channel"}}
|
||||
<aside class="sidebar">
|
||||
<div class="users"></div>
|
||||
<div class="users">
|
||||
<div class="count">
|
||||
<input type="search" class="search" aria-label="Search among the user list">
|
||||
</div>
|
||||
<div class="names names-filtered"></div>
|
||||
<div class="names names-original"></div>
|
||||
</div>
|
||||
</aside>
|
||||
{{/equal}}
|
||||
</div>
|
||||
{{/each}}
|
||||
|
@ -30,4 +30,5 @@ module.exports = {
|
||||
toggle: require("./toggle.tpl"),
|
||||
unread_marker: require("./unread_marker.tpl"),
|
||||
user: require("./user.tpl"),
|
||||
user_filtered: require("./user_filtered.tpl"),
|
||||
};
|
||||
|
@ -1,11 +1,5 @@
|
||||
{{#if users.length}}
|
||||
<div class="count">
|
||||
<input class="search" placeholder="{{users users.length}}" aria-label="Search among the user list">
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="names">
|
||||
{{#diff "reset"}}{{/diff}}
|
||||
{{#each users}}
|
||||
{{#diff "reset"}}{{/diff}}
|
||||
{{#each users}}
|
||||
{{#diff mode}}
|
||||
{{#unless @first}}
|
||||
</div>
|
||||
@ -13,6 +7,5 @@
|
||||
<div class="user-mode {{modes mode}}">
|
||||
{{/diff}}
|
||||
<span role="button" class="user {{colorClass name}}" data-name="{{name}}">{{mode}}{{name}}</span>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
5
client/views/user_filtered.tpl
Normal file
5
client/views/user_filtered.tpl
Normal file
@ -0,0 +1,5 @@
|
||||
<div class="user-mode user-mode-search">
|
||||
{{#each matches}}
|
||||
<span role="button" class="{{original.className}}">{{{string}}}</span>
|
||||
{{/each}}
|
||||
</div>
|
@ -65,6 +65,7 @@
|
||||
"chai": "3.5.0",
|
||||
"eslint": "3.19.0",
|
||||
"font-awesome": "4.7.0",
|
||||
"fuzzy": "0.1.3",
|
||||
"handlebars": "4.0.6",
|
||||
"handlebars-loader": "1.5.0",
|
||||
"jquery": "3.2.1",
|
||||
|
@ -19,6 +19,7 @@ let config = {
|
||||
"mousetrap",
|
||||
"socket.io-client",
|
||||
"urijs",
|
||||
"fuzzy",
|
||||
],
|
||||
},
|
||||
devtool: "source-map",
|
||||
|
Loading…
Reference in New Issue
Block a user