mirror of
https://github.com/Spengreb/sync.git
synced 2026-06-10 07:12: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
|
torbanned: false, // Block connections from Tor exit nodes
|
||||||
block_anonymous_users: false, //Only allow connections from registered users.
|
block_anonymous_users: false, //Only allow connections from registered users.
|
||||||
allow_ascii_control: false,// Allow ASCII control characters (\x00-\x1f)
|
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
|
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_delay: 0, // Minimum account/IP age to chat
|
||||||
new_user_chat_link_delay: 0, // Minimum account/IP age to post links
|
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;
|
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) {
|
if ("playlist_max_per_user" in data && user.account.effectiveRank >= 3) {
|
||||||
var max = parseInt(data.playlist_max_per_user);
|
var max = parseInt(data.playlist_max_per_user);
|
||||||
if (!isNaN(max) && max >= 0) {
|
if (!isNaN(max) && max >= 0) {
|
||||||
|
|
|
||||||
|
|
@ -192,6 +192,7 @@ mixin emotes
|
||||||
form.form-horizontal(action="javascript:void(0)", role="form")
|
form.form-horizontal(action="javascript:void(0)", role="form")
|
||||||
+textbox("cs-emotes-newname", "Emote name")
|
+textbox("cs-emotes-newname", "Emote name")
|
||||||
+textbox("cs-emotes-newimage", "Emote image")
|
+textbox("cs-emotes-newimage", "Emote image")
|
||||||
|
+textbox-auto("cs-emote_triggers", "Emote Search Trigger Symbols", ":!#/")
|
||||||
.form-group
|
.form-group
|
||||||
.col-sm-8.col-sm-offset-4
|
.col-sm-8.col-sm-offset-4
|
||||||
button#cs-emotes-newsubmit.btn.btn-primary Create Emote
|
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 */
|
/* emote autocomplete */
|
||||||
var EMOTE_SUGGEST_IDX = 0;
|
var EMOTE_SUGGEST_IDX = 0;
|
||||||
function emoteLastWord() {
|
var EMOTE_SUGGEST_CONTEXT = null;
|
||||||
var words = $("#chatline").val().split(" ");
|
|
||||||
return words[words.length - 1].toLowerCase();
|
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() {
|
function emoteAccept() {
|
||||||
var item = $("#emote-suggestions .active");
|
var item = $("#emote-suggestions .active");
|
||||||
if (!item.length) item = $("#emote-suggestions").children().first();
|
if (!item.length) item = $("#emote-suggestions").children().first();
|
||||||
if (!item.length) return;
|
if (!item.length || !EMOTE_SUGGEST_CONTEXT) return false;
|
||||||
var words = $("#chatline").val().split(" ");
|
var cl = document.getElementById("chatline");
|
||||||
words[words.length - 1] = item.data("name") + " ";
|
if (!cl) return false;
|
||||||
$("#chatline").val(words.join(" "));
|
|
||||||
|
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-suggestions").hide();
|
||||||
|
EMOTE_SUGGEST_CONTEXT = null;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
function emoteRefresh() {
|
function emoteRefresh() {
|
||||||
var partial = emoteLastWord();
|
var token = emoteTokenAtCaret();
|
||||||
var popup = $("#emote-suggestions");
|
var popup = $("#emote-suggestions");
|
||||||
if (partial.length < 2 || !CHANNEL.emotes || !CHANNEL.emotes.length) { popup.hide(); return; }
|
if (!token || !CHANNEL.emotes || !CHANNEL.emotes.length) {
|
||||||
var matches = CHANNEL.emotes.filter(function(e) {
|
EMOTE_SUGGEST_CONTEXT = null;
|
||||||
return e.name.toLowerCase().indexOf(partial) === 0;
|
popup.hide();
|
||||||
}).slice(0, 8);
|
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; }
|
if (!matches.length) { popup.hide(); return; }
|
||||||
popup.empty();
|
popup.empty();
|
||||||
matches.forEach(function(e) {
|
matches.forEach(function(e) {
|
||||||
|
|
@ -220,10 +278,16 @@ $("#chatline").on('keydown', function(ev) {
|
||||||
if (open) {
|
if (open) {
|
||||||
if (ev.keyCode == 27) { // Escape
|
if (ev.keyCode == 27) { // Escape
|
||||||
$("#emote-suggestions").hide();
|
$("#emote-suggestions").hide();
|
||||||
|
EMOTE_SUGGEST_CONTEXT = null;
|
||||||
ev.preventDefault(); return false;
|
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
|
} else if (ev.keyCode == 9 || (ev.keyCode == 39 && this.selectionStart === this.value.length)) { // Tab or right arrow at end
|
||||||
emoteAccept();
|
if (emoteAccept()) {
|
||||||
ev.preventDefault(); return false;
|
ev.preventDefault(); return false;
|
||||||
|
}
|
||||||
} else if (ev.keyCode == 38 || ev.keyCode == 40) { // Up/down navigate
|
} else if (ev.keyCode == 38 || ev.keyCode == 40) { // Up/down navigate
|
||||||
var items = $("#emote-suggestions").children();
|
var items = $("#emote-suggestions").children();
|
||||||
items.eq(EMOTE_SUGGEST_IDX).removeClass("active");
|
items.eq(EMOTE_SUGGEST_IDX).removeClass("active");
|
||||||
|
|
@ -237,6 +301,7 @@ $("#chatline").on('keydown', function(ev) {
|
||||||
// Enter/return
|
// Enter/return
|
||||||
if(ev.keyCode == 13) {
|
if(ev.keyCode == 13) {
|
||||||
$("#emote-suggestions").hide();
|
$("#emote-suggestions").hide();
|
||||||
|
EMOTE_SUGGEST_CONTEXT = null;
|
||||||
if (CHATTHROTTLE) {
|
if (CHATTHROTTLE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -995,6 +995,7 @@ function handleModPermissions() {
|
||||||
$("#cs-torbanned").prop("checked", CHANNEL.opts.torbanned);
|
$("#cs-torbanned").prop("checked", CHANNEL.opts.torbanned);
|
||||||
$("#cs-block_anonymous_users").prop("checked", CHANNEL.opts.block_anonymous_users);
|
$("#cs-block_anonymous_users").prop("checked", CHANNEL.opts.block_anonymous_users);
|
||||||
$("#cs-allow_ascii_control").prop("checked", CHANNEL.opts.allow_ascii_control);
|
$("#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_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-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));
|
$("#cs-new_user_chat_delay").val(formatTime(CHANNEL.opts.new_user_chat_delay || 0));
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue