/* * Copyright (C) 2016-2020 phantombot.github.io/PhantomBot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ $(function() { const helpers = {}; // Delay in ms for animations. helpers.DELAY_MS = 325; // Debug states enums. helpers.DEBUG_STATES = { NONE: 0, DEBUG: 1, INFO: 2, FORCE: 3 }; // Debug status. 0 = off | 1 = on. helpers.DEBUG_STATE = (localStorage.getItem('phantombot_debug_state') !== null ? parseInt(localStorage.getItem('phantombot_debug_state')) : helpers.DEBUG_STATES.NONE); // Debug types. helpers.LOG_TYPE = helpers.DEBUG_STATES; // Panel version. SEE: https://semver.org/ // Example: MAJOR.MINOR.PATCH helpers.PANEL_VERSION = "1.3.0"; /* * @function adds commas to thousands. * * @param {String} number * @return {String} */ helpers.parseNumber = function(number) { return (number + '').replace(/\B(?=(\d{3})+(?!\d))/g, ','); }; /* * @function Fixes the number * * @param {String} number * @return {JSON} */ helpers.fixNumber = function(number, force) { const newNumber = parseInt(number.toString().replace(/,/g, '')); const thousandReplace = 9999; const millionReplace = 999999; if (!isNaN(newNumber)) { if (newNumber > thousandReplace && newNumber < millionReplace) { return ((newNumber / 1000).toFixed(1) + 'K'); } else if (newNumber > millionReplace) { return ((newNumber / 1000000).toFixed(1) + 'M'); } } return number; }; /* * @function checks if the object has a valid string or number. * * @param {Object} obj * @return {Boolean} */ helpers.isValidNumberOrString = function(obj) { let value = (typeof obj === 'object' ? obj.val() : obj); if (isNaN(value)) { if (typeof value === 'string' && value.length > 0) { return true; } } else { if (typeof value === 'number' && value > 0) { return true; } } return false; }; /* * @function Checks if the value is null and returns the default if it is. * * @param {String} value * @param {String} def * @return {String} */ helpers.getDefaultIfNullOrUndefined = function(value, def) { if (value === null || value === undefined) { return def; } else { return value; } }; /* * @function gets the proper event message. * * @param {Object} event * @return {String} */ helpers.getEventMessage = function(event) { switch (event.type.toLowerCase()) { case 'subscriber': return (event.username + ' just subscribed!'); case 'prime subscriber': return (event.username + ' just subscribed with Twitch Prime!'); case 'resubscriber': return (event.username + ' just resubscribed for ' + event.months + ' months in a row!'); case 'follower': return (event.username + ' just followed!'); case 'bits': return (event.username + ' just cheered ' + event.amount + ' bits!'); case 'host': return (event.username + ' just hosted with ' + event.viewers + ' viewers!'); case 'auto-host': return (event.username + ' just auto-hosted with ' + event.viewers + ' viewers!'); case 'tip': // To be added soon. break; case 'raid': return (event.username + ' raided for ' + event.viewers + ' viewers!'); case 'gifted subscription': return (event.username + ' gifted a subscription to ' + event.recipient + '!'); } }; /* * @function that gets the right color for an event. * * @param {String} event * @return {String} */ // Use these colours for this function: https://mdbootstrap.com/css/colors/ helpers.getEventColor = function(event) { switch (event.toLowerCase()) { case 'subscriber': return 'background-color: #16a7d9;'; case 'prime subscriber': return 'background-color: #1693bc;'; case 'resubscriber': return 'background-color: #ed961c;'; case 'follower': return 'background-color: #c62828;'; case 'bits': return 'background-color: #6441a5;'; case 'host': return 'background-color: #ed4c1c;'; case 'auto-host': return 'background-color: #ffff00; color: #000000;'; case 'tip': // To be added soon. return 'background-color: #6441a5;'; case 'raid': return 'background-color: #4caf50;'; case 'gifted subscription': return 'background-color: #01579b;'; } }; /* * @function handles the string input checks. * * @param {Object} obj * @return {Boolean} */ helpers.handleInputString = function(obj) { if (obj.length === 0) { helpers.logError('Failed to handle string due to the object being null.', helpers.LOG_TYPE.FORCE); return; } // Make sure the input has a value in it. if (obj.val().length < 1) { if (!obj.parent().hasClass('has-error')) { // Add the error class to the parent. obj.parent().addClass('has-error'); // Append text saying the form cannot be empty. obj.after($('

', { 'class': 'help-block', 'text': 'You cannot leave this field empty.' })); let btn = obj.closest('form').find('button'); if (btn.data('candisable') !== undefined) { // Disable the button obj.closest('form').find('button').prop('disabled', true).addClass('disabled'); } toastr.error('Missing data in input field.'); return false; } } else { if (obj.parent().find('p').length > 0) { if (obj.parent().hasClass('has-error')) { // Remove error class. obj.parent().removeClass('has-error'); // Remove the help text. obj.parent().find('p').remove(); // Enabled the button again. obj.closest('form').find('button').prop('disabled', false).removeClass('disabled'); return true; } } } return !obj.parent().hasClass('has-error'); }; /* * @function handles the number input checks. * * @param {Object} obj * @return {Boolean} */ helpers.handleInputNumber = function(obj, min, max) { if (obj.length === 0) { helpers.logError('Failed to handle number due to the object being null.', helpers.LOG_TYPE.FORCE); return; } min = (min === undefined ? 0 : min); let newMax = (max === undefined ? Number.MAX_SAFE_INTEGER : max); // Make sure the input has a value in it. if (isNaN(parseInt(obj.val())) || isNaN(obj.val()) || parseInt(obj.val()) < min || parseInt(obj.val()) > newMax) { if (!obj.parent().hasClass('has-error')) { // Add the error class to the parent. obj.parent().addClass('has-error'); // Append text saying the form cannot be empty. obj.after($('

', { 'class': 'help-block', 'text': 'Please enter a number that is greater or equal to ' + min + (max !== undefined ? ' and less or equal than ' + newMax + '' : '') + '.' })); let btn = obj.closest('form').find('button'); if (btn.data('candisable') !== undefined) { // Disable the button obj.closest('form').find('button').prop('disabled', true).addClass('disabled'); } toastr.error('Missing data in input field.'); return false; } } else { if (obj.parent().find('p').length > 0) { if (obj.parent().hasClass('has-error')) { // Remove error class. obj.parent().removeClass('has-error'); // Remove the help text. obj.parent().find('p').remove(); // Enabled the button again. obj.closest('form').find('button').removeClass('disabled'); return true; } } } return !obj.parent().hasClass('has-error'); }; /* * @function handles the date input checks. * * @param {Object} obj * @return {Boolean} */ helpers.handleInputDate = function(obj) { if (obj.length === 0) { helpers.logError('Failed to handle date due to the object being null.', helpers.LOG_TYPE.FORCE); return; } let matched = obj.val().match(/^((\d{2}|\d{4})(\\|\/|\.|-)(\d{2})(\\|\/|\.|-)(\d{4}|\d{2}))$/); // Make sure the input has a value in it. if (matched === null || ((matched[6].length < 4 && matched[2].length == 2) || (matched[6].length == 2 && matched[2].length < 4))) { if (!obj.parent().hasClass('has-error')) { // Add the error class to the parent. obj.parent().addClass('has-error'); // Append text saying the form cannot be empty. obj.after($('

', { 'class': 'help-block', 'text': 'Please enter a valid date (mm/dd/yyyy or dd/mm/yyyy).' })); let btn = obj.closest('form').find('button'); if (btn.data('candisable') !== undefined) { // Disable the button obj.closest('form').find('button').prop('disabled', true).addClass('disabled'); } toastr.error('Bad date in field.'); return false; } } else { if (obj.parent().find('p').length > 0) { if (obj.parent().hasClass('has-error')) { // Remove error class. obj.parent().removeClass('has-error'); // Remove the help text. obj.parent().find('p').remove(); // Enabled the button again. obj.closest('form').find('button').removeClass('disabled'); return true; } } } return !obj.parent().hasClass('has-error'); }; /* * @function handles hiding info for the panels (the four dashboard info panels). * * @param {Object} obj * @param {String} id */ helpers.handlePanelToggleInfo = function(obj, id) { id = 'phantombot_' + id.substring(id.indexOf('-') + 1); if (localStorage.getItem(id) === 'false') { if (parseInt(obj.data('number').replace(/,/g, '')) < 9999) { obj.html(obj.data('number')); } else { obj.html($('.small-box').width() < 230 ? obj.data('parsed') : obj.data('number')); } localStorage.setItem(id, 'true'); } else { obj.html('Hidden'); localStorage.setItem(id, 'false'); } }; /* * @function handles setting the info for the panels (the four dashboard info panels). * * @param {Object} obj * @param {String} id */ helpers.handlePanelSetInfo = function(obj, id, parsed) { let item = localStorage.getItem('phantombot_' + id.substring(id.indexOf('-') + 1)), isSmall = $('.small-box').width() < 230; if (item === 'true' || item === null) { if (parseInt(obj.data('number').replace(/,/g, '')) < 9999) { obj.html(obj.data('number')); } else { obj.html(isSmall ? parsed : obj.data('number')); } } else { obj.html('Hidden'); } obj.data('parsed', parsed); }; /* * @function Adds padding to the date with a 0. * * @param {String} dateString * @return {String} */ helpers.getPaddedDateString = function(dateString) { let dateMatches = dateString.match(/((\d+)|([^\d]*))/g); for (let i = 0; i < dateMatches.length; i++) { if (parseInt(dateMatches[i]) < 10 && !dateMatches[i].startsWith('0')) { dateMatches[i] = ('0' + dateMatches[i]); } } return dateMatches.join(''); }; /* * @function Generates a basic modal, you have to append your own body with jQuery. * * @param {String} id * @param {String} title * @param {String} btn * @param {Object} body * @param {Function} onClose * @return {Object} */ helpers.getModal = function(id, title, btn, body, onClose) { return $('

', { 'class': 'modal fade', 'tabindex': '99', 'id': id }).append($('
', { 'class': 'modal-dialog' }).append($('
', { 'class': 'modal-content' }).append($('
', { 'class': 'modal-header', }).append($('