- // ==UserScript==
- // @name Twitch Tab Completion (compatible with BTTV)
- // @namespace https://openuserjs.org/users/daybreakz
- // @version 1.0.9
- // @description Tab completion for emotes (and users) also add chat history. BetterTTV
- // @author Daybr3akz
- // @license MIT
- // @copyright 2017, daybreakz (https://openuserjs.org/users/daybreakz)
- // @match https://www.twitch.tv/*
- // @require http://code.jquery.com/jquery-3.2.1.slim.min.js
- // @grant none
- // ==/UserScript==
-
- // // ==OpenUserJS==
- // @author daybreakz
- // ==/OpenUserJS==
-
-
-
-
- /******/ (function(modules) { // webpackBootstrap
- /******/ // The module cache
- /******/ var installedModules = {};
- /******/
- /******/ // The require function
- /******/ function __webpack_require__(moduleId) {
- /******/
- /******/ // Check if module is in cache
- /******/ if(installedModules[moduleId]) {
- /******/ return installedModules[moduleId].exports;
- /******/ }
- /******/ // Create a new module (and put it into the cache)
- /******/ var module = installedModules[moduleId] = {
- /******/ i: moduleId,
- /******/ l: false,
- /******/ exports: {}
- /******/ };
- /******/
- /******/ // Execute the module function
- /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
- /******/
- /******/ // Flag the module as loaded
- /******/ module.l = true;
- /******/
- /******/ // Return the exports of the module
- /******/ return module.exports;
- /******/ }
- /******/
- /******/
- /******/ // expose the modules object (__webpack_modules__)
- /******/ __webpack_require__.m = modules;
- /******/
- /******/ // expose the module cache
- /******/ __webpack_require__.c = installedModules;
- /******/
- /******/ // define getter function for harmony exports
- /******/ __webpack_require__.d = function(exports, name, getter) {
- /******/ if(!__webpack_require__.o(exports, name)) {
- /******/ Object.defineProperty(exports, name, {
- /******/ configurable: false,
- /******/ enumerable: true,
- /******/ get: getter
- /******/ });
- /******/ }
- /******/ };
- /******/
- /******/ // getDefaultExport function for compatibility with non-harmony modules
- /******/ __webpack_require__.n = function(module) {
- /******/ var getter = module && module.__esModule ?
- /******/ function getDefault() { return module['default']; } :
- /******/ function getModuleExports() { return module; };
- /******/ __webpack_require__.d(getter, 'a', getter);
- /******/ return getter;
- /******/ };
- /******/
- /******/ // Object.prototype.hasOwnProperty.call
- /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
- /******/
- /******/ // __webpack_public_path__
- /******/ __webpack_require__.p = "";
- /******/
- /******/ // Load entry module and return exports
- /******/ return __webpack_require__(__webpack_require__.s = 3);
- /******/ })
- /************************************************************************/
- /******/ ([
- /* 0 */
- /***/ (function(module, exports, __webpack_require__) {
-
- "use strict";
-
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.getConnectRoot = getConnectRoot;
- exports.getChatController = getChatController;
- exports.getChatInputController = getChatInputController;
- exports.getCurrentChat = getCurrentChat;
- exports.setCurrentUser = setCurrentUser;
- exports.getCurrentUser = getCurrentUser;
- exports.getCurrentChannel = getCurrentChannel;
- exports.updateCurrentChannel = updateCurrentChannel;
- var REACT_ROOT = '#root div[data-reactroot]';
- var CHAT_CONTAINER = '.chat-room__container';
- var CHAT_INPUT = '.chat-input';
- // const $ = s => document.querySelectorAll(s);
- var $ = window.$;
-
- function getReactInstance(element) {
- for (var key in element) {
- if (key.startsWith('__reactInternalInstance$')) {
- return element[key];
- }
- }
- return null;
- }
-
- function getReactElement(element) {
- var instance = getReactInstance(element);
- if (!instance) return null;
- return instance._currentElement;
- }
-
- function getParentNode(reactElement) {
- try {
- return reactElement._owner._currentElement._owner;
- } catch (_) {
- return null;
- }
- }
-
- function searchReactChildren(node, predicate) {
- var maxDepth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 15;
- var depth = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
-
- try {
- if (predicate(node)) {
- return node;
- }
- } catch (_) {}
-
- if (!node || depth > maxDepth) {
- return null;
- }
-
- var children = node._renderedChildren,
- component = node._renderedComponent;
-
-
- if (children) {
- var _iteratorNormalCompletion = true;
- var _didIteratorError = false;
- var _iteratorError = undefined;
-
- try {
- for (var _iterator = Object.keys(children)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
- var key = _step.value;
-
- var childResult = searchReactChildren(children[key], predicate, maxDepth, depth + 1);
- if (childResult) {
- return childResult;
- }
- }
- } catch (err) {
- _didIteratorError = true;
- _iteratorError = err;
- } finally {
- try {
- if (!_iteratorNormalCompletion && _iterator.return) {
- _iterator.return();
- }
- } finally {
- if (_didIteratorError) {
- throw _iteratorError;
- }
- }
- }
- }
-
- if (component) {
- return searchReactChildren(component, predicate, maxDepth, depth + 1);
- }
-
- return null;
- }
-
- function getConnectRoot() {
- var root = void 0;
- try {
- root = getParentNode(getReactElement($(REACT_ROOT)[0]));
- } catch (_) {}
- return root;
- }
-
- function getChatController() {
- var container = $(CHAT_CONTAINER).parent()[0];
- if (!container) return null;
-
- var controller = searchReactChildren(getReactInstance(container), function (node) {
- return node._instance && node._instance.chatBuffer;
- });
-
- if (controller) {
- controller = controller._instance;
- }
-
- return controller;
- }
-
- function getChatInputController() {
- var container = $(CHAT_INPUT)[0];
- if (!container) return null;
-
- var controller = void 0;
- try {
- controller = getParentNode(getReactElement(container))._instance;
- } catch (_) {}
-
- return controller;
- }
-
- function getCurrentChat() {
- var container = $(CHAT_CONTAINER)[0];
- if (!container) return null;
- var controller = void 0;
- try {
- controller = getParentNode(getReactElement(container))._instance;
- } catch (_) {}
- return controller;
- }
-
- var currentUser = null;
- function setCurrentUser(accessToken, id, name, displayName) {
- // twitchAPI.setAccessToken(accessToken);
- currentUser = {
- id: id.toString(),
- name: name,
- displayName: displayName
- };
- }
-
- function getCurrentUser() {
- return currentUser;
- }
-
- var currentChannel = void 0;
- function getCurrentChannel() {
- return currentChannel;
- }
-
- function updateCurrentChannel() {
- var rv = void 0;
- var currentChat = getCurrentChat();
- if (currentChat && currentChat.props && currentChat.props.channelID) {
- var _currentChat$props = currentChat.props,
- channelID = _currentChat$props.channelID,
- channelLogin = _currentChat$props.channelLogin,
- channelDisplayName = _currentChat$props.channelDisplayName;
-
- rv = {
- id: channelID.toString(),
- name: channelLogin,
- displayName: channelDisplayName
- };
- }
- currentChannel = rv;
- return rv;
- }
-
- /***/ }),
- /* 1 */
- /***/ (function(module, exports, __webpack_require__) {
-
- "use strict";
-
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- window.customLog = localStorage.getItem('customLog') === 'true';
-
- var console = window.console;
- try {
- console = $('iframe')[0].contentWindow.console;
- } catch (e) {}
-
- function log(type) {
- if (!console || !window.customLog) return;
-
- for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
- args[_key - 1] = arguments[_key];
- }
-
- console[type].apply(console, ['SCRIPT:'].concat(args));
- }
-
- var debug = {
- log: log.bind(undefined, 'log'),
- error: log.bind(undefined, 'error'),
- warn: log.bind(undefined, 'warn'),
- info: log.bind(undefined, 'info')
- };
-
- exports.default = debug;
-
- /***/ }),
- /* 2 */
- /***/ (function(module, exports, __webpack_require__) {
-
- "use strict";
-
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
-
- var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
- var _debug = __webpack_require__(1);
-
- var _debug2 = _interopRequireDefault(_debug);
-
- var _twitch = __webpack_require__(0);
-
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
- function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
-
- function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
-
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
- var API_ENDPOINT = 'https://api.betterttv.net/2/';
- var fetchJson = function fetchJson(path) {
- return fetch('' + API_ENDPOINT + path).then(function (r) {
- return r.json();
- });
- };
-
- var channel = {};
-
- var EmotesProvider = function () {
- function EmotesProvider() {
- _classCallCheck(this, EmotesProvider);
-
- this.channelEmotes = new Set();
- this.globalEmotes = new Set();
- this.emojis = new Set();
- this.loadBTTVGlobalEmotes();
- // this.loadEmojis();
- }
-
- _createClass(EmotesProvider, [{
- key: 'updateChannel',
- value: function () {
- var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
- var currentChannel;
- return regeneratorRuntime.wrap(function _callee$(_context) {
- while (1) {
- switch (_context.prev = _context.next) {
- case 0:
- currentChannel = (0, _twitch.getCurrentChannel)();
-
- if (currentChannel) {
- _context.next = 3;
- break;
- }
-
- return _context.abrupt('return');
-
- case 3:
- if (!(currentChannel.id === channel.id)) {
- _context.next = 5;
- break;
- }
-
- return _context.abrupt('return');
-
- case 5:
- channel = currentChannel;
- _context.next = 8;
- return fetchJson('channels/' + channel.name);
-
- case 8:
- return _context.abrupt('return', _context.sent);
-
- case 9:
- case 'end':
- return _context.stop();
- }
- }
- }, _callee, this);
- }));
-
- function updateChannel() {
- return _ref.apply(this, arguments);
- }
-
- return updateChannel;
- }()
- }, {
- key: 'load',
- value: function () {
- var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
- var channelData;
- return regeneratorRuntime.wrap(function _callee2$(_context2) {
- while (1) {
- switch (_context2.prev = _context2.next) {
- case 0:
- _context2.next = 2;
- return this.updateChannel();
-
- case 2:
- channelData = _context2.sent;
-
- if (channelData && channelData.emotes) {
- this.loadBTTVChannelEmotes(channelData.emotes);
- }
-
- case 4:
- case 'end':
- return _context2.stop();
- }
- }
- }, _callee2, this);
- }));
-
- function load() {
- return _ref2.apply(this, arguments);
- }
-
- return load;
- }()
- }, {
- key: 'loadBTTVGlobalEmotes',
- value: function () {
- var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {
- var _this = this;
-
- var x, emotesJson;
- return regeneratorRuntime.wrap(function _callee3$(_context3) {
- while (1) {
- switch (_context3.prev = _context3.next) {
- case 0:
- _context3.next = 2;
- return fetchJson('emotes');
-
- case 2:
- x = _context3.sent;
- emotesJson = x.emotes;
-
- emotesJson.forEach(function (em) {
- if (!em || !em.code) return;
- _this.globalEmotes.add(em.code);
- });
- _debug2.default.log('Got globalEmotes');
-
- case 6:
- case 'end':
- return _context3.stop();
- }
- }
- }, _callee3, this);
- }));
-
- function loadBTTVGlobalEmotes() {
- return _ref3.apply(this, arguments);
- }
-
- return loadBTTVGlobalEmotes;
- }()
- }, {
- key: 'loadBTTVChannelEmotes',
- value: function loadBTTVChannelEmotes(emotesJson) {
- var _this2 = this;
-
- this.channelEmotes.clear();
- emotesJson.forEach(function (em) {
- if (!em || !em.code) return;
- _this2.channelEmotes.add(em.code);
- });
- _debug2.default.log('Got channel emotes');
- }
- }, {
- key: 'getEmotes',
- value: function getEmotes() {
- if (!window.BetterTTV) {
- return [];
- }
- var user = (0, _twitch.getCurrentUser)();user;
-
- var emotes = [].concat(_toConsumableArray(this.globalEmotes))
- // .concat([...this.emojis])
- .concat([].concat(_toConsumableArray(this.channelEmotes)));
- return emotes;
- }
- }]);
-
- return EmotesProvider;
- }();
-
- // let provider = new NopeProvider();
- // if (window.BetterTTV) {
-
-
- var provider = new EmotesProvider();
- exports.default = provider;
-
- /***/ }),
- /* 3 */
- /***/ (function(module, exports, __webpack_require__) {
-
- "use strict";
-
-
- var _routeKeysToPaths;
-
- var waitForChat = function () {
- var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
- var abort, currentIsWaiting;
- return regeneratorRuntime.wrap(function _callee$(_context) {
- while (1) {
- switch (_context.prev = _context.next) {
- case 0:
- abort = false;
-
- wait(15000).then(function () {
- return abort = true;
- });
- isWaiting = Symbol('waitingForChat');
- currentIsWaiting = isWaiting;
-
- case 4:
- if (abort) {
- _context.next = 14;
- break;
- }
-
- if (!checkChat()) {
- _context.next = 7;
- break;
- }
-
- return _context.abrupt('return', true);
-
- case 7:
- if (!(isWaiting !== currentIsWaiting)) {
- _context.next = 10;
- break;
- }
-
- _debug2.default.log('waitForChat was cancelled');
- return _context.abrupt('return', false);
-
- case 10:
- _context.next = 12;
- return wait(25);
-
- case 12:
- _context.next = 4;
- break;
-
- case 14:
- return _context.abrupt('return', false);
-
- case 15:
- case 'end':
- return _context.stop();
- }
- }
- }, _callee, this);
- }));
-
- return function waitForChat() {
- return _ref.apply(this, arguments);
- };
- }();
-
- var main = function () {
- var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
- var router;
- return regeneratorRuntime.wrap(function _callee2$(_context2) {
- while (1) {
- switch (_context2.prev = _context2.next) {
- case 0:
- _context2.next = 2;
- return getRouter();
-
- case 2:
- router = _context2.sent;
-
- router.history.listen(function (location) {
- return onRouteChange(location);
- });
- onRouteChange(router.history.location);
-
- case 5:
- case 'end':
- return _context2.stop();
- }
- }
- }, _callee2, this);
- }));
-
- return function main() {
- return _ref2.apply(this, arguments);
- };
- }();
-
- var _debug = __webpack_require__(1);
-
- var _debug2 = _interopRequireDefault(_debug);
-
- var _tab_completion = __webpack_require__(4);
-
- var _tab_completion2 = _interopRequireDefault(_tab_completion);
-
- var _emotes = __webpack_require__(2);
-
- var _emotes2 = _interopRequireDefault(_emotes);
-
- var _twitch = __webpack_require__(0);
-
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
- function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
-
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
-
- var currentPath = void 0;
-
- var routes = {
- DIRECTORY_FOLLOWING_LIVE: 'DIRECTORY_FOLLOWING_LIVE',
- DIRECTORY_FOLLOWING: 'DIRECTORY_FOLLOWING',
- DIRECTORY: 'DIRECTORY',
- CHAT: 'CHAT',
- CHANNEL: 'CHANNEL',
- VOD: 'VOD'
- };
-
- var routeKeysToPaths = (_routeKeysToPaths = {}, _defineProperty(_routeKeysToPaths, routes.DIRECTORY_FOLLOWING_LIVE, /^\/directory\/following\/live$/i), _defineProperty(_routeKeysToPaths, routes.DIRECTORY_FOLLOWING, /^\/directory\/following$/i), _defineProperty(_routeKeysToPaths, routes.DIRECTORY, /^\/directory/i), _defineProperty(_routeKeysToPaths, routes.CHAT, /^(\/popout)?\/[a-z0-9-_]+\/chat$/i), _defineProperty(_routeKeysToPaths, routes.VOD, /^\/videos\/[0-9]+$/i), _defineProperty(_routeKeysToPaths, routes.CHANNEL, /^\/[a-z0-9-_]+/i), _routeKeysToPaths);
-
- function getRouteFromPath(path) {
- var _iteratorNormalCompletion = true;
- var _didIteratorError = false;
- var _iteratorError = undefined;
-
- try {
- for (var _iterator = Object.keys(routeKeysToPaths)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
- var name = _step.value;
-
- var regex = routeKeysToPaths[name];
- if (!regex.test(path)) continue;
- return name;
- }
- } catch (err) {
- _didIteratorError = true;
- _iteratorError = err;
- } finally {
- try {
- if (!_iteratorNormalCompletion && _iterator.return) {
- _iterator.return();
- }
- } finally {
- if (_didIteratorError) {
- throw _iteratorError;
- }
- }
- }
-
- return null;
- }
-
- function getRouter() {
- return new Promise(function (resolve) {
- var loadInterval = setInterval(function () {
- var user = void 0,
- router = void 0;
- try {
- var connectRoot = (0, _twitch.getConnectRoot)();
- if (!connectRoot) return;
- var context = connectRoot._context;
- router = context.router;
- user = context.store.getState().session.user;
- } catch (_) {
- return;
- }
-
- if (!router || !user) return;
- clearInterval(loadInterval);
-
- (0, _twitch.setCurrentUser)(user.authToken, user.id, user.login, user.displayName);
- resolve(router);
- }, 25);
- });
- }
-
- function makeCheckChat() {
- var currentChatReference = null;
- return function () {
- if (!(0, _twitch.updateCurrentChannel)()) return false;
- var lastReference = currentChatReference;
- var currentChat = (0, _twitch.getCurrentChat)();
-
- if (currentChat && currentChat === lastReference) {
- return false;
- }
- if (lastReference && currentChat.props.channelID.toString() === lastReference.props.channelID.toString()) {
- return false;
- }
-
- currentChatReference = currentChat;
-
- return true;
- };
- }
- var checkChat = makeCheckChat();
-
- var wait = function wait(t) {
- return new Promise(function (r) {
- return setTimeout(r, t);
- });
- };
- var isWaiting = false;
-
-
- function triggerRouteChanged() {}
-
- function triggerChatLoaded() {
- _debug2.default.log('CHAT WAS LOADED');
- _tab_completion2.default.load(true);
- _emotes2.default.load();
- }
-
- function onRouteChange(location) {
- var lastPath = currentPath;
- var path = location.pathname;
- var route = getRouteFromPath(path);
- _debug2.default.log('New route: ' + location.pathname + ' as ' + route);
-
- // emit load
- triggerRouteChanged();
- currentPath = path;
- if (currentPath === lastPath) return;
- if (route === routes.CHAT || route === routes.CHANNEL) {
- waitForChat().then(function (loaded) {
- return loaded && triggerChatLoaded();
- });
- }
- }
-
- main();
-
- /***/ }),
- /* 4 */
- /***/ (function(module, exports, __webpack_require__) {
-
- "use strict";
-
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
-
- var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
- // const InputPatcherModule = require('./input-patcher-module');
-
-
- var _customInputModule = __webpack_require__(5);
-
- var _customInputModule2 = _interopRequireDefault(_customInputModule);
-
- var _chatHistoryModule = __webpack_require__(6);
-
- var _chatHistoryModule2 = _interopRequireDefault(_chatHistoryModule);
-
- var _twitch = __webpack_require__(0);
-
- var _debug = __webpack_require__(1);
-
- var _debug2 = _interopRequireDefault(_debug);
-
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
- // window.getChatController = getChatController;
-
- var CHAT_INPUT = '.chat-input';
- var $ = window.$;
-
- function patchSendMessage(callback) {
- var chatBuffer = (0, _twitch.getChatController)().chatBuffer;
- _debug2.default.log(chatBuffer);
-
- if (chatBuffer._consumeChatEventPatched === true) {
- return;
- }
- chatBuffer._consumeChatEventPatched = true;
- var twitchConsumeChatEvent = chatBuffer.consumeChatEvent;
-
- function myConsumeChatEvent(event) {
- if (event && event.type === 0) {
- try {
- callback(event);
- } catch (error) {
- _debug2.default.error(error);
- }
- }
- return twitchConsumeChatEvent.apply(this, arguments);
- }
- chatBuffer.consumeChatEvent = myConsumeChatEvent;
- }
-
- var ChatTabCompletionModule = function () {
- function ChatTabCompletionModule() {
- var _this = this;
-
- _classCallCheck(this, ChatTabCompletionModule);
-
- this.customInput = new _customInputModule2.default(this);
- this.chatHistory = new _chatHistoryModule2.default(this);
- this.currentInput = null;
-
- // watcher.on('load.chat', () => this.load());
- // settings.on('changed.tabAutocomplete', () => this.load(false));
-
- $('body').off('click.tabComplete focus.tabComplete keydown.tabComplete').on('click.tabComplete focus.tabComplete', CHAT_INPUT, function () {
- return _this.onFocus();
- }).on('keydown.tabComplete', CHAT_INPUT, function (e) {
- return _this.onKeydown(e);
- });
- }
-
- _createClass(ChatTabCompletionModule, [{
- key: 'load',
- value: function load() {
- var _this2 = this;
-
- var chatLoad = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
-
- this.customInput.load(chatLoad);
- this.chatHistory.load(chatLoad);
- // if (settings.get('tabAutocomplete')) {
- this.customInput.enable();
- this.currentInput = this.customInput;
- // } else {
- // this.customInput.disable();
- // this.currentInput = this.patchedInput;
- // }
- patchSendMessage(function (event) {
- _this2.currentInput.storeUser(event.user);
- });
- }
- }, {
- key: 'onKeydown',
- value: function onKeydown(e) {
- if (this.currentInput) {
- this.currentInput.onKeydown(e);
- }
- this.chatHistory.onKeydown(e);
- }
- }, {
- key: 'onFocus',
- value: function onFocus() {
- if (this.currentInput) {
- this.currentInput.onFocus();
- }
- this.chatHistory.onFocus();
- }
- }, {
- key: 'onSendMessage',
- value: function onSendMessage(message) {
- this.chatHistory.onSendMessage(message);
- }
- }]);
-
- return ChatTabCompletionModule;
- }();
-
- var mod = new ChatTabCompletionModule();
- exports.default = mod;
-
- /***/ }),
- /* 5 */
- /***/ (function(module, exports, __webpack_require__) {
-
- "use strict";
-
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
-
- var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
- var _emotes = __webpack_require__(2);
-
- var _emotes2 = _interopRequireDefault(_emotes);
-
- var _twitch = __webpack_require__(0);
-
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
- function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
-
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
- var $ = window.$;
-
-
- var ORIGINAL_TEXTAREA = '.chat-input textarea';
-
- function setReactTextareaValue(txt, msg) {
- txt.value = msg;
- var ev = new Event('input', { target: txt, bubbles: true });
- txt.dispatchEvent(ev);
- }
-
- function newTextArea() {
- var $oldText = $(ORIGINAL_TEXTAREA);
- var $text = $oldText.clone().insertBefore(ORIGINAL_TEXTAREA);
- $text.attr('id', 'bttv-chat-input');
- $oldText.attr('id', 'twitch-chat-input');
- $oldText.hide();
- $text.focus();
-
- $text[0].customSetValue = function (value) {
- $text.val(value);
- };
-
- $oldText[0].customSetValue = function (value) {
- setReactTextareaValue($oldText[0], value);
- };
-
- return { $text: $text, $oldText: $oldText };
- }
-
- var CustomInputModule = function () {
- function CustomInputModule(parentModule) {
- _classCallCheck(this, CustomInputModule);
-
- this.parentModule = parentModule;
- this.init();
- // watcher.on('input.onSendMessage', () => this.sendMessage());
- // watcher.on('chat.message', ($el, msg) => this.storeUser($el, msg));
- }
-
- _createClass(CustomInputModule, [{
- key: 'init',
- value: function init() {
- this.userList = new Set();
- this.tabTries = -1;
- this.suggestions = null;
- this.textSplit = ['', '', ''];
- }
- }, {
- key: 'storeUser',
- value: function storeUser(user) {
- this.userList.add(user.userDisplayName || user.userLogin);
- }
- }, {
- key: 'sendMessage',
- value: function sendMessage() {
- var message = this.$text.val();
- if (message.trim().length === 0) {
- return;
- }
- this.chatInputCtrl.props.onSendMessage(message);
- this.parentModule.onSendMessage(message);
- this.$text.val('');
- }
- }, {
- key: 'load',
- value: function load() {
- var createTextarea = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
-
- this.chatInputCtrl = (0, _twitch.getChatInputController)();
- if (createTextarea) {
- var _newTextArea = newTextArea(),
- $text = _newTextArea.$text,
- $oldText = _newTextArea.$oldText;
-
- this.$text = $text;
- this.$oldText = $oldText;
- this.userList = new Set();
- }
- }
- }, {
- key: 'enable',
- value: function enable() {
- this.$text.show();
- this.$oldText.hide();
- }
- }, {
- key: 'disable',
- value: function disable() {
- this.$text.hide();
- this.$oldText.show();
- }
- }, {
- key: 'getSuggestions',
- value: function getSuggestions(prefix) {
- var includeUsers = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
- var includeEmotes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
-
- var userList = [];
- var emoteList = [];
-
- if (includeEmotes) {
- var _emoteList;
-
- emoteList = _emotes2.default.getEmotes(); // .map(emote => emote.code);
- (_emoteList = emoteList).push.apply(_emoteList, _toConsumableArray(this.getTwitchEmotes()));
- emoteList = emoteList.filter(function (word) {
- return word.toLowerCase().indexOf(prefix.toLowerCase()) === 0;
- });
- emoteList = Array.from(new Set(emoteList).values());
- emoteList.sort();
- }
-
- if (includeUsers) {
- userList = this.getChatMembers().filter(function (word) {
- return word.toLowerCase().indexOf(prefix.toLowerCase()) === 0;
- });
- userList.sort();
- }
-
- return [].concat(_toConsumableArray(emoteList), _toConsumableArray(userList));
- }
- }, {
- key: 'onKeydown',
- value: function onKeydown(e, includeUsers) {
- var keyCode = e.key;
- if (e.ctrlKey) {
- return;
- }
- var $inputField = this.$text;
-
- if (keyCode === 'Enter' && !e.shiftKey) {
- e.preventDefault();
- this.sendMessage();
- } else if (keyCode === 'Tab') {
- e.preventDefault();
- this.onAutoComplete(includeUsers, e.shiftKey);
- } else if (keyCode === 'Escape' && this.tabTries >= 0) {
- $inputField.val(this.textSplit.join(''));
- } else if (keyCode !== 'Shift') {
- this.tabTries = -1;
- }
- }
- }, {
- key: 'onFocus',
- value: function onFocus() {
- this.tabTries = -1;
- }
- }, {
- key: 'onAutoComplete',
- value: function onAutoComplete(includeUsers, shiftKey) {
- var $inputField = this.$text;
-
- // First time pressing tab, split before and after the word
- if (this.tabTries === -1) {
- var caretPos = $inputField[0].selectionStart;
- var text = $inputField.val();
-
- var start = (/[\:\(\)\w]+$/.exec(text.substr(0, caretPos)) || { index: caretPos }).index;
- var end = caretPos + (/^\w+/.exec(text.substr(caretPos)) || [''])[0].length;
- this.textSplit = [text.substring(0, start), text.substring(start, end), text.substring(end + 1)];
-
- // If there are no words in front of the caret, exit
- if (this.textSplit[1] === '') return;
-
- // Get all matching completions
- var includeEmotes = this.textSplit[0].slice(-1) !== '@';
- this.suggestions = this.getSuggestions(this.textSplit[1], includeUsers, includeEmotes);
- }
-
- if (this.suggestions.length > 0) {
- this.tabTries += shiftKey ? -1 : 1; // shift key iterates backwards
- if (this.tabTries >= this.suggestions.length) this.tabTries = 0;
- if (this.tabTries < 0) this.tabTries = this.suggestions.length - 1;
- if (!this.suggestions[this.tabTries]) return;
-
- var cursorOffset = 0;
- if (this.textSplit[2].trim() === '') {
- this.textSplit[2] = ' ';
- cursorOffset = 1;
- }
-
- var cursorPos = this.textSplit[0].length + this.suggestions[this.tabTries].length + cursorOffset;
- $inputField.val(this.textSplit[0] + this.suggestions[this.tabTries] + this.textSplit[2]);
- $inputField[0].setSelectionRange(cursorPos, cursorPos);
- }
- }
- }, {
- key: 'getTwitchEmotes',
- value: function getTwitchEmotes() {
- var twEmotes = this.chatInputCtrl.props.emotes;
- if (!twEmotes) {
- return [];
- }
- return twEmotes.reduce(function (accum, v) {
- return accum.concat(v.emotes);
- }, []).map(function (emote) {
- return emote.displayName;
- });
- }
- }, {
- key: 'getChatMembers',
- value: function getChatMembers() {
- var broadcasterName = this.chatInputCtrl.props.channelDisplayName;
- this.userList.add(broadcasterName);
- return Array.from(this.userList.values());
- }
- }]);
-
- return CustomInputModule;
- }();
-
- exports.default = CustomInputModule;
-
- /***/ }),
- /* 6 */
- /***/ (function(module, exports, __webpack_require__) {
-
- "use strict";
-
-
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
-
- var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
-
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
- var $ = window.$;
-
- function isSuggestionsShowing() {
- return !!$('[data-a-target="autocomplete-balloon"]')[0];
- }
-
- var ChatHistoryModule = function () {
- function ChatHistoryModule(parentModule) {
- _classCallCheck(this, ChatHistoryModule);
-
- this.parentModule = parentModule;
- }
-
- _createClass(ChatHistoryModule, [{
- key: 'load',
- value: function load(resetHistory) {
- if (resetHistory) {
- this.messageHistory = [];
- }
- this.historyPos = -1;
- }
- }, {
- key: 'onKeydown',
- value: function onKeydown(e) {
- var keyCode = e.key;
- if (e.ctrlKey) {
- return;
- }
- var $inputField = $(e.target);
- var setInputValue = function setInputValue(value) {
- e.target.customSetValue(value);
- };
-
- if (keyCode === 'ArrowUp') {
- if (isSuggestionsShowing()) return;
- if ($inputField[0].selectionStart > 0) return;
- if (this.historyPos + 1 === this.messageHistory.length) return;
- var prevMsg = this.messageHistory[++this.historyPos];
- setInputValue(prevMsg);
- $inputField[0].setSelectionRange(0, 0);
- } else if (keyCode === 'ArrowDown') {
- if (isSuggestionsShowing()) return;
- if ($inputField[0].selectionStart < $inputField.val().length) return;
- if (this.historyPos > 0) {
- var _prevMsg = this.messageHistory[--this.historyPos];
- setInputValue(_prevMsg);
- $inputField[0].setSelectionRange(_prevMsg.length, _prevMsg.length);
- } else {
- var draft = $inputField.val().trim();
- if (this.historyPos < 0 && draft.length > 0) {
- this.messageHistory.unshift(draft);
- }
- this.historyPos = -1;
- $inputField.val('');
- setInputValue('');
- }
- } else if (this.historyPos >= 0) {
- this.messageHistory[this.historyPos] = $inputField.val();
- }
- }
- }, {
- key: 'onSendMessage',
- value: function onSendMessage(message) {
- if (message.trim().length === 0) return;
- this.messageHistory.unshift(message);
- this.historyPos = -1;
- // watcher.emit('input.onSendMessage', message);
- }
- }, {
- key: 'onFocus',
- value: function onFocus() {
- this.historyPos = -1;
- }
- }]);
-
- return ChatHistoryModule;
- }();
-
- exports.default = ChatHistoryModule;
-
- /***/ })
- /******/ ]);
- //# sourceMappingURL=main.bundle.js.map
-
-