Permalink
Browse files

Integrate new tab completion methods

There is now an option to choose which tab completion method to use.
Also, emotes can be tab completed.
1 parent e1ad7c6 commit 27e168ba8b3999715da96e3c0c6a5c717b8ea510 @calzoneman committed Jan 11, 2017
Showing with 109 additions and 9 deletions.
  1. +1 −1 package.json
  2. +1 −0 templates/channel.pug
  3. +6 −0 templates/useroptions.pug
  4. +36 −2 test/www/tabcomplete.js
  5. +2 −1 www/js/data.js
  6. +3 −3 www/js/tabcomplete.js
  7. +58 −2 www/js/ui.js
  8. +2 −0 www/js/util.js
View
@@ -2,7 +2,7 @@
"author": "Calvin Montgomery",
"name": "CyTube",
"description": "Online media synchronizer and chat",
- "version": "3.27.1",
+ "version": "3.28.0",
"repository": {
"url": "http://github.com/calzoneman/sync"
},
@@ -240,6 +240,7 @@ html(lang="en")
script(id="socketio-js", src=sioSource)
script(src="/js/data.js")
script(src="/js/util.js")
+ script(src="/js/tabcomplete.js")
script(src="/js/player.js")
script(src="/js/paginator.js")
script(src="/js/ui.js")
@@ -114,6 +114,12 @@ mixin us-chat
+rcheckbox("us-sendbtn", "Add a send button to chat")
+rcheckbox("us-no-emotes", "Disable chat emotes")
+rcheckbox("us-strip-image", "Remove images from chat")
+ .form-group
+ label.control-label.col-sm-4(for="#us-chat-tab-method") Tab completion method
+ .col-sm-8
+ select#us-chat-tab-method.form-control
+ option(value="Cycle options") Cycle options
+ option(value="Longest unique match") Longest unique match
mixin us-mod
#us-mod.tab-pane
@@ -4,7 +4,7 @@ require('../../www/js/tabcomplete');
describe('CyTube.tabCompletionMethods', () => {
- describe('"Longest unique prefix"', () => {
+ describe('"Longest unique match"', () => {
const testcases = [
{
input: 'and his name is j',
@@ -27,6 +27,16 @@ describe('CyTube.tabCompletionMethods', () => {
description: 'completes a unique match'
},
{
+ input: 'johnc',
+ position: 5,
+ options: ['johncena', 'johnstamos', 'johto'],
+ output: {
+ text: 'johncena ',
+ newPosition: 9
+ },
+ description: 'completes a unique match at the beginning of the string'
+ },
+ {
input: 'and his name is johnc',
position: 21,
options: ['asdf'],
@@ -70,7 +80,7 @@ describe('CyTube.tabCompletionMethods', () => {
testcases.forEach(test => {
it(test.description, () => {
assert.deepEqual(
- CyTube.tabCompleteMethods['Longest unique prefix'](
+ CyTube.tabCompleteMethods['Longest unique match'](
test.input,
test.position,
test.options,
@@ -109,6 +119,30 @@ describe('CyTube.tabCompletionMethods', () => {
description: 'cycles through options correctly'
},
{
+ input: 'c',
+ position: 1,
+ options: ['COBOL', 'Carlos', 'carl', 'john', 'joseph', ''],
+ outputs: [
+ {
+ text: 'carl ',
+ newPosition: 5
+ },
+ {
+ text: 'Carlos ',
+ newPosition: 7
+ },
+ {
+ text: 'COBOL ',
+ newPosition: 6
+ },
+ {
+ text: 'carl ',
+ newPosition: 5
+ }
+ ],
+ description: 'cycles through options correctly at the beginning of the string'
+ },
+ {
input: 'hey ',
position: 5,
options: ['COBOL', 'Carlos', 'carl', 'john'],
View
@@ -123,7 +123,8 @@ var USEROPTS = {
show_shadowchat : getOrDefault("show_shadowchat", false),
emotelist_sort : getOrDefault("emotelist_sort", true),
no_emotes : getOrDefault("no_emotes", false),
- strip_image : getOrDefault("strip_image", false)
+ strip_image : getOrDefault("strip_image", false),
+ chat_tab_method : getOrDefault("chat_tab_method", "Cycle options")
};
/* Backwards compatibility check */
@@ -2,20 +2,20 @@ CyTube.tabCompleteMethods = {};
// Bash-style completion
// Only completes as far as it is possible to maintain uniqueness of the completion.
-CyTube.tabCompleteMethods['Longest unique prefix'] = function (input, position, options, context) {
+CyTube.tabCompleteMethods['Longest unique match'] = function (input, position, options, context) {
var lower = input.toLowerCase();
// First, backtrack to the nearest whitespace to find the
// incomplete string that should be completed.
var start;
var incomplete = '';
for (start = position - 1; start >= 0; start--) {
if (/\s/.test(lower[start])) {
- start++;
break;
}
incomplete = lower[start] + incomplete;
}
+ start++;
// Nothing to complete
if (!incomplete.length) {
@@ -101,12 +101,12 @@ CyTube.tabCompleteMethods['Cycle options'] = function (input, position, options,
var incomplete = '';
for (start = position - 1; start >= 0; start--) {
if (/\s/.test(lower[start])) {
- start++;
break;
}
incomplete = lower[start] + incomplete;
}
+ start++;
// Nothing to complete
if (!incomplete.length) {
View
@@ -111,7 +111,11 @@ $("#guestname").keydown(function (ev) {
}
});
-function chatTabComplete() {
+
+/**
+ * TODO: Remove this post-deployment
+ */
+function oldChatTabComplete() {
var words = $("#chatline").val().split(" ");
var current = words[words.length - 1].toLowerCase();
if (!current.match(/^[\w-]{1,20}$/)) {
@@ -186,6 +190,54 @@ function chatTabComplete() {
$("#chatline").val(words.join(" "));
}
+CyTube.chatTabCompleteData = {
+ context: {}
+};
+
+function chatTabComplete() {
+ if (!CyTube.tabCompleteMethods) {
+ oldChatTabComplete();
+ return;
+ }
+ var chatline = document.getElementById("chatline");
+ var currentText = chatline.value;
+ var currentPosition = chatline.selectionEnd;
+ if (typeof currentPosition !== 'number' || !chatline.setSelectionRange) {
+ // Bail, we're on IE8 or something similarly dysfunctional
+ return;
+ }
+ var firstWord = !/\s/.test(currentText.trim());
+ var options = [];
+ var userlistElems = document.getElementById("userlist").children;
+ for (var i = 0; i < userlistElems.length; i++) {
+ var username = userlistElems[i].children[1].textContent;
+ if (firstWord) {
+ username += ':';
+ }
+ options.push(username);
+ }
+
+ CHANNEL.emotes.forEach(function (emote) {
+ options.push(emote.name);
+ });
+
+ var method = USEROPTS.chat_tab_method;
+ if (!CyTube.tabCompleteMethods[method]) {
+ console.error("Unknown chat tab completion method '" + method + "', using default");
+ method = "Cycle options";
+ }
+
+ var result = CyTube.tabCompleteMethods[method](
+ currentText,
+ currentPosition,
+ options,
+ CyTube.chatTabCompleteData.context
+ );
+
+ chatline.value = result.text;
+ chatline.setSelectionRange(result.newPosition, result.newPosition);
+}
+
$("#chatline").keydown(function(ev) {
// Enter/return
if(ev.keyCode == 13) {
@@ -218,7 +270,11 @@ $("#chatline").keydown(function(ev) {
return;
}
else if(ev.keyCode == 9) { // Tab completion
- chatTabComplete();
+ try {
+ chatTabComplete();
+ } catch (error) {
+ console.error(error);
+ }
ev.preventDefault();
return false;
}
View
@@ -643,6 +643,7 @@ function showUserOptions() {
$("#us-sendbtn").prop("checked", USEROPTS.chatbtn);
$("#us-no-emotes").prop("checked", USEROPTS.no_emotes);
$("#us-strip-image").prop("checked", USEROPTS.strip_image);
+ $("#us-chat-tab-method").val(USEROPTS.chat_tab_method);
$("#us-modflair").prop("checked", USEROPTS.modhat);
$("#us-shadowchat").prop("checked", USEROPTS.show_shadowchat);
@@ -677,6 +678,7 @@ function saveUserOptions() {
USEROPTS.chatbtn = $("#us-sendbtn").prop("checked");
USEROPTS.no_emotes = $("#us-no-emotes").prop("checked");
USEROPTS.strip_image = $("#us-strip-image").prop("checked");
+ USEROPTS.chat_tab_method = $("#us-chat-tab-method").val();
if (CLIENT.rank >= 2) {
USEROPTS.modhat = $("#us-modflair").prop("checked");

0 comments on commit 27e168b

Please sign in to comment.