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;
|
overflow: auto;
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
#chat .channel .chat {
|
||||||
right: 180px;
|
right: 180px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -788,18 +791,6 @@ kbd {
|
|||||||
transform: translateZ(0);
|
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 {
|
#chat .show-more {
|
||||||
display: none;
|
display: none;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
@ -1177,6 +1168,10 @@ kbd {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#chat .names-filtered {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
#chat .names .user {
|
#chat .names .user {
|
||||||
display: block;
|
display: block;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
@ -1216,6 +1211,10 @@ kbd {
|
|||||||
content: "Users";
|
content: "Users";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#chat .user-mode-search:before {
|
||||||
|
content: "Search Results";
|
||||||
|
}
|
||||||
|
|
||||||
#loading {
|
#loading {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
z-index: 1;
|
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 moment = require("moment");
|
||||||
const Mousetrap = require("mousetrap");
|
const Mousetrap = require("mousetrap");
|
||||||
const URI = require("urijs");
|
const URI = require("urijs");
|
||||||
|
const fuzzy = require("fuzzy");
|
||||||
|
|
||||||
// our libraries
|
// our libraries
|
||||||
const emojiMap = require("./libs/simplemap.json");
|
const emojiMap = require("./libs/simplemap.json");
|
||||||
@ -320,7 +321,10 @@ $(function() {
|
|||||||
|
|
||||||
function renderChannel(data) {
|
function renderChannel(data) {
|
||||||
renderChannelMessages(data);
|
renderChannelMessages(data);
|
||||||
renderChannelUsers(data);
|
|
||||||
|
if (data.type === "channel") {
|
||||||
|
renderChannelUsers(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderChannelMessages(data) {
|
function renderChannelMessages(data) {
|
||||||
@ -380,7 +384,19 @@ $(function() {
|
|||||||
return (oldSortOrder[a] || Number.MAX_VALUE) - (oldSortOrder[b] || Number.MAX_VALUE);
|
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) {
|
function renderNetworks(data) {
|
||||||
@ -1022,17 +1038,31 @@ $(function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
chat.on("input", ".search", function() {
|
chat.on("input", ".search", function() {
|
||||||
var value = $(this).val().toLowerCase();
|
const value = $(this).val();
|
||||||
var names = $(this).closest(".users").find(".names");
|
const parent = $(this).closest(".users");
|
||||||
names.find(".user").each(function() {
|
const names = parent.find(".names-original");
|
||||||
var btn = $(this);
|
const container = parent.find(".names-filtered");
|
||||||
var name = btn.text().toLowerCase().replace(/[+%@~]/, "");
|
|
||||||
if (name.indexOf(value) > -1) {
|
if (!value.length) {
|
||||||
btn.show();
|
container.hide();
|
||||||
} else {
|
names.show();
|
||||||
btn.hide();
|
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) {
|
chat.on("msg", ".messages", function(e, target, msg) {
|
||||||
|
@ -19,8 +19,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="messages"></div>
|
<div class="messages"></div>
|
||||||
</div>
|
</div>
|
||||||
|
{{#equal type "channel"}}
|
||||||
<aside class="sidebar">
|
<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>
|
</aside>
|
||||||
|
{{/equal}}
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
@ -30,4 +30,5 @@ module.exports = {
|
|||||||
toggle: require("./toggle.tpl"),
|
toggle: require("./toggle.tpl"),
|
||||||
unread_marker: require("./unread_marker.tpl"),
|
unread_marker: require("./unread_marker.tpl"),
|
||||||
user: require("./user.tpl"),
|
user: require("./user.tpl"),
|
||||||
|
user_filtered: require("./user_filtered.tpl"),
|
||||||
};
|
};
|
||||||
|
@ -1,18 +1,11 @@
|
|||||||
{{#if users.length}}
|
{{#diff "reset"}}{{/diff}}
|
||||||
<div class="count">
|
{{#each users}}
|
||||||
<input class="search" placeholder="{{users users.length}}" aria-label="Search among the user list">
|
{{#diff mode}}
|
||||||
</div>
|
{{#unless @first}}
|
||||||
{{/if}}
|
</div>
|
||||||
<div class="names">
|
{{/unless}}
|
||||||
{{#diff "reset"}}{{/diff}}
|
<div class="user-mode {{modes mode}}">
|
||||||
{{#each users}}
|
{{/diff}}
|
||||||
{{#diff mode}}
|
<span role="button" class="user {{colorClass name}}" data-name="{{name}}">{{mode}}{{name}}</span>
|
||||||
{{#unless @first}}
|
{{/each}}
|
||||||
</div>
|
|
||||||
{{/unless}}
|
|
||||||
<div class="user-mode {{modes mode}}">
|
|
||||||
{{/diff}}
|
|
||||||
<span role="button" class="user {{colorClass name}}" data-name="{{name}}">{{mode}}{{name}}</span>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</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",
|
"chai": "3.5.0",
|
||||||
"eslint": "3.19.0",
|
"eslint": "3.19.0",
|
||||||
"font-awesome": "4.7.0",
|
"font-awesome": "4.7.0",
|
||||||
|
"fuzzy": "0.1.3",
|
||||||
"handlebars": "4.0.6",
|
"handlebars": "4.0.6",
|
||||||
"handlebars-loader": "1.5.0",
|
"handlebars-loader": "1.5.0",
|
||||||
"jquery": "3.2.1",
|
"jquery": "3.2.1",
|
||||||
|
@ -19,6 +19,7 @@ let config = {
|
|||||||
"mousetrap",
|
"mousetrap",
|
||||||
"socket.io-client",
|
"socket.io-client",
|
||||||
"urijs",
|
"urijs",
|
||||||
|
"fuzzy",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
devtool: "source-map",
|
devtool: "source-map",
|
||||||
|
Loading…
Reference in New Issue
Block a user