mirror of
https://github.com/Spengreb/sync.git
synced 2026-06-09 23:02:05 +00:00
Merge branch 'emote-substring-search' into emote-substring-search-ux
This commit is contained in:
commit
73c90d8802
4 changed files with 115 additions and 14 deletions
|
|
@ -30,6 +30,7 @@ function OptionsModule(_channel) {
|
|||
torbanned: false, // Block connections from Tor exit nodes
|
||||
block_anonymous_users: false, //Only allow connections from registered users.
|
||||
allow_ascii_control: false,// Allow ASCII control characters (\x00-\x1f)
|
||||
emote_triggers: ":!#/", // Trigger symbols for emote autocomplete
|
||||
playlist_max_per_user: 0, // Maximum number of playlist items per user
|
||||
new_user_chat_delay: 0, // Minimum account/IP age to chat
|
||||
new_user_chat_link_delay: 0, // Minimum account/IP age to post links
|
||||
|
|
@ -353,6 +354,39 @@ OptionsModule.prototype.handleSetOptions = function (user, data) {
|
|||
sendUpdate = true;
|
||||
}
|
||||
|
||||
if ("emote_triggers" in data) {
|
||||
if (typeof data.emote_triggers !== "string") {
|
||||
user.socket.emit("validationError", {
|
||||
target: "#cs-emote_triggers",
|
||||
message: "Emote triggers must be a string of symbols"
|
||||
});
|
||||
} else {
|
||||
var rawTriggers = data.emote_triggers.trim();
|
||||
var normalized = "";
|
||||
for (var i = 0; i < rawTriggers.length; i++) {
|
||||
var ch = rawTriggers.charAt(i);
|
||||
if (/\s/.test(ch)) {
|
||||
continue;
|
||||
}
|
||||
if (normalized.indexOf(ch) === -1) {
|
||||
normalized += ch;
|
||||
}
|
||||
}
|
||||
|
||||
if (normalized.length === 0) {
|
||||
normalized = ":!#/";
|
||||
} else if (normalized.length > 16) {
|
||||
normalized = normalized.substring(0, 16);
|
||||
}
|
||||
|
||||
this.opts.emote_triggers = normalized;
|
||||
sendUpdate = true;
|
||||
user.socket.emit("validationPassed", {
|
||||
target: "#cs-emote_triggers"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ("playlist_max_per_user" in data && user.account.effectiveRank >= 3) {
|
||||
var max = parseInt(data.playlist_max_per_user);
|
||||
if (!isNaN(max) && max >= 0) {
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ mixin emotes
|
|||
form.form-horizontal(action="javascript:void(0)", role="form")
|
||||
+textbox("cs-emotes-newname", "Emote name")
|
||||
+textbox("cs-emotes-newimage", "Emote image")
|
||||
+textbox-auto("cs-emote_triggers", "Emote Search Trigger Symbols", ":!#/")
|
||||
.form-group
|
||||
.col-sm-8.col-sm-offset-4
|
||||
button#cs-emotes-newsubmit.btn.btn-primary Create Emote
|
||||
|
|
|
|||
93
www/js/ui.js
93
www/js/ui.js
|
|
@ -167,26 +167,84 @@ function chatTabComplete(chatline) {
|
|||
|
||||
/* emote autocomplete */
|
||||
var EMOTE_SUGGEST_IDX = 0;
|
||||
function emoteLastWord() {
|
||||
var words = $("#chatline").val().split(" ");
|
||||
return words[words.length - 1].toLowerCase();
|
||||
var EMOTE_SUGGEST_CONTEXT = null;
|
||||
|
||||
function getEmoteTriggerSymbols() {
|
||||
var raw = (CHANNEL && CHANNEL.opts && CHANNEL.opts.emote_triggers) || ":!#/";
|
||||
if (typeof raw !== "string" || raw.length === 0) {
|
||||
return ":!#/";
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
function escapeForRegex(s) {
|
||||
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
}
|
||||
|
||||
function emoteTokenAtCaret() {
|
||||
var cl = document.getElementById("chatline");
|
||||
if (!cl) return null;
|
||||
var caret = cl.selectionStart;
|
||||
if (typeof caret !== "number") return null;
|
||||
|
||||
var value = cl.value;
|
||||
var left = value.slice(0, caret);
|
||||
var tokenStart = left.lastIndexOf(" ") + 1;
|
||||
var token = left.slice(tokenStart);
|
||||
if (!token) return null;
|
||||
|
||||
var triggers = getEmoteTriggerSymbols();
|
||||
var triggerClass = escapeForRegex(triggers);
|
||||
var re = new RegExp("^([" + triggerClass + "])([^\\s]{2,})$");
|
||||
var m = token.match(re);
|
||||
if (!m) return null;
|
||||
|
||||
return {
|
||||
tokenStart: tokenStart,
|
||||
trigger: m[1],
|
||||
query: m[2].toLowerCase()
|
||||
};
|
||||
}
|
||||
|
||||
function emoteAccept() {
|
||||
var item = $("#emote-suggestions .active");
|
||||
if (!item.length) item = $("#emote-suggestions").children().first();
|
||||
if (!item.length) return;
|
||||
var words = $("#chatline").val().split(" ");
|
||||
words[words.length - 1] = item.data("name") + " ";
|
||||
$("#chatline").val(words.join(" "));
|
||||
if (!item.length || !EMOTE_SUGGEST_CONTEXT) return false;
|
||||
var cl = document.getElementById("chatline");
|
||||
if (!cl) return false;
|
||||
|
||||
var value = cl.value;
|
||||
var start = EMOTE_SUGGEST_CONTEXT.tokenStart;
|
||||
var end = cl.selectionStart;
|
||||
var replacement = item.data("name") + " ";
|
||||
cl.value = value.slice(0, start) + replacement + value.slice(end);
|
||||
var newPos = start + replacement.length;
|
||||
cl.setSelectionRange(newPos, newPos);
|
||||
$("#emote-suggestions").hide();
|
||||
EMOTE_SUGGEST_CONTEXT = null;
|
||||
return true;
|
||||
}
|
||||
function emoteRefresh() {
|
||||
var partial = emoteLastWord();
|
||||
var token = emoteTokenAtCaret();
|
||||
var popup = $("#emote-suggestions");
|
||||
if (partial.length < 2 || !CHANNEL.emotes || !CHANNEL.emotes.length) { popup.hide(); return; }
|
||||
var matches = CHANNEL.emotes.filter(function(e) {
|
||||
return e.name.toLowerCase().indexOf(partial) === 0;
|
||||
}).slice(0, 8);
|
||||
if (!token || !CHANNEL.emotes || !CHANNEL.emotes.length) {
|
||||
EMOTE_SUGGEST_CONTEXT = null;
|
||||
popup.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
var partial = token.query;
|
||||
EMOTE_SUGGEST_CONTEXT = token;
|
||||
|
||||
var matches = CHANNEL.emotes
|
||||
.filter(e => e.name.toLowerCase().includes(partial))
|
||||
.sort((a, b) => {
|
||||
const an = a.name.toLowerCase();
|
||||
const bn = b.name.toLowerCase();
|
||||
|
||||
return (bn.startsWith(partial) - an.startsWith(partial)) || an.localeCompare(bn);
|
||||
})
|
||||
.slice(0, 8);
|
||||
if (!matches.length) { popup.hide(); return; }
|
||||
popup.empty();
|
||||
matches.forEach(function(e) {
|
||||
|
|
@ -220,10 +278,16 @@ $("#chatline").on('keydown', function(ev) {
|
|||
if (open) {
|
||||
if (ev.keyCode == 27) { // Escape
|
||||
$("#emote-suggestions").hide();
|
||||
EMOTE_SUGGEST_CONTEXT = null;
|
||||
ev.preventDefault(); return false;
|
||||
} else if (ev.keyCode == 13) { // Enter accept
|
||||
if (emoteAccept()) {
|
||||
ev.preventDefault(); return false;
|
||||
}
|
||||
} else if (ev.keyCode == 9 || (ev.keyCode == 39 && this.selectionStart === this.value.length)) { // Tab or right arrow at end
|
||||
emoteAccept();
|
||||
ev.preventDefault(); return false;
|
||||
if (emoteAccept()) {
|
||||
ev.preventDefault(); return false;
|
||||
}
|
||||
} else if (ev.keyCode == 38 || ev.keyCode == 40) { // Up/down navigate
|
||||
var items = $("#emote-suggestions").children();
|
||||
items.eq(EMOTE_SUGGEST_IDX).removeClass("active");
|
||||
|
|
@ -237,6 +301,7 @@ $("#chatline").on('keydown', function(ev) {
|
|||
// Enter/return
|
||||
if(ev.keyCode == 13) {
|
||||
$("#emote-suggestions").hide();
|
||||
EMOTE_SUGGEST_CONTEXT = null;
|
||||
if (CHATTHROTTLE) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -995,6 +995,7 @@ function handleModPermissions() {
|
|||
$("#cs-torbanned").prop("checked", CHANNEL.opts.torbanned);
|
||||
$("#cs-block_anonymous_users").prop("checked", CHANNEL.opts.block_anonymous_users);
|
||||
$("#cs-allow_ascii_control").prop("checked", CHANNEL.opts.allow_ascii_control);
|
||||
$("#cs-emote_triggers").val(CHANNEL.opts.emote_triggers || ":!#/");
|
||||
$("#cs-playlist_max_per_user").val(CHANNEL.opts.playlist_max_per_user || 0);
|
||||
$("#cs-playlist_max_duration_per_user").val(formatTime(CHANNEL.opts.playlist_max_duration_per_user));
|
||||
$("#cs-new_user_chat_delay").val(formatTime(CHANNEL.opts.new_user_chat_delay || 0));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue