/** * Copyright © Dave Perrett, Malcolm Jarvis and Artem Vorotnikov * * This file is licensed under the GPLv2. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ let transmission, dialog, isMobileDevice = RegExp('(iPhone|iPod|Android)').test(navigator.userAgent), scroll_timeout; // http://forum.jquery.com/topic/combining-ui-dialog-and-tabs $.fn.tabbedDialog = function (dialog_opts) { this.tabs({ selected: 0, }); this.dialog(dialog_opts); this.find('.ui-tab-dialog-close').append(this.parent().find('.ui-dialog-titlebar-close')); this.find('.ui-tab-dialog-close').css({ position: 'absolute', right: '0', top: '16px', }); this.find('.ui-tab-dialog-close > a').css({ float: 'none', padding: '0', }); const tabul = this.find('ul:first'); this.parent().addClass('ui-tabs').prepend(tabul).draggable('option', 'handle', tabul); this.siblings('.ui-dialog-titlebar').remove(); tabul.addClass('ui-dialog-titlebar'); }; /** * Checks to see if the content actually changed before poking the DOM. */ function setInnerHTML(e, html) { if (!e) { return; } /* innerHTML is listed as a string, but the browser seems to change it. * For example, "∞" gets changed to "∞" somewhere down the line. * So, let's use an arbitrary different field to test our state... */ if (e.currentHTML != html) { e.currentHTML = html; e.innerHTML = html; } } function sanitizeText(text) { return text.replace(//g, '>'); } /** * Many of our text changes are triggered by periodic refreshes * on torrents whose state hasn't changed since the last update, * so see if the text actually changed before poking the DOM. */ function setTextContent(e, text) { if (e && e.textContent != text) { e.textContent = text; } } /* * Given a numerator and denominator, return a ratio string */ Math.ratio = function (numerator, denominator) { let result = Math.floor((100 * numerator) / denominator) / 100; // check for special cases if (result == Number.POSITIVE_INFINITY || result == Number.NEGATIVE_INFINITY) { result = -2; } else if (isNaN(result)) { result = -1; } return result; }; /** * Round a string of a number to a specified number of decimal places */ Number.prototype.toTruncFixed = function (place) { const ret = Math.floor(this * Math.pow(10, place)) / Math.pow(10, place); return ret.toFixed(place); }; Number.prototype.toStringWithCommas = function () { return this.toString().replace(/\B(?=(?:\d{3})+(?!\d))/g, ','); }; /* * Trim whitespace from a string */ String.prototype.trim = function () { return this.replace(/^\s*/, '').replace(/\s*$/, ''); }; /*** **** Preferences ***/ function Prefs() {} Prefs.prototype = {}; Prefs._RefreshRate = 'refresh_rate'; Prefs._FilterMode = 'filter'; Prefs._FilterAll = 'all'; Prefs._FilterActive = 'active'; Prefs._FilterSeeding = 'seeding'; Prefs._FilterDownloading = 'downloading'; Prefs._FilterPaused = 'paused'; Prefs._FilterFinished = 'finished'; Prefs._SortDirection = 'sort_direction'; Prefs._SortAscending = 'ascending'; Prefs._SortDescending = 'descending'; Prefs._SortMethod = 'sort_method'; Prefs._SortByAge = 'age'; Prefs._SortByActivity = 'activity'; Prefs._SortByName = 'name'; Prefs._SortByQueue = 'queue_order'; Prefs._SortBySize = 'size'; Prefs._SortByProgress = 'percent_completed'; Prefs._SortByRatio = 'ratio'; Prefs._SortByState = 'state'; Prefs._CompactDisplayState = 'compact_display_state'; Prefs._Defaults = { filter: 'all', refresh_rate: 5, sort_direction: 'ascending', sort_method: 'name', 'turtle-state': false, compact_display_state: false, }; /* * Set a preference option */ Prefs.setValue = function (key, val) { if (!(key in Prefs._Defaults)) { console.warn("unrecognized preference key '%s'", key); } const date = new Date(); date.setFullYear(date.getFullYear() + 1); document.cookie = key + '=' + val + '; expires=' + date.toGMTString() + '; path=/'; }; /** * Get a preference option * * @param key the preference's key * @param fallback if the option isn't set, return this instead */ Prefs.getValue = function (key, fallback) { let val; if (!(key in Prefs._Defaults)) { console.warn("unrecognized preference key '%s'", key); } const lines = document.cookie.split(';'); for (let i = 0, len = lines.length; !val && i < len; ++i) { const line = lines[i].trim(); const delim = line.indexOf('='); if (delim === key.length && line.indexOf(key) === 0) { val = line.substring(delim + 1); } } // FIXME: we support strings and booleans... add number support too? if (!val) { val = fallback; } else if (val === 'true') { val = true; } else if (val === 'false') { val = false; } return val; }; /** * Get an object with all the Clutch preferences set * * @pararm o object to be populated (optional) */ Prefs.getClutchPrefs = function (o) { if (!o) { o = {}; } for (const key in Prefs._Defaults) { o[key] = Prefs.getValue(key, Prefs._Defaults[key]); } return o; }; // forceNumeric() plug-in implementation jQuery.fn.forceNumeric = function () { return this.each(function () { $(this).keydown(function (e) { const key = e.which || e.keyCode; return ( (!e.shiftKey && !e.altKey && !e.ctrlKey && // numbers key >= 48 && key <= 57) || // Numeric keypad (key >= 96 && key <= 105) || // comma, period and minus, . on keypad key === 190 || key === 188 || key === 109 || key === 110 || // Backspace and Tab and Enter key === 8 || key === 9 || key === 13 || // Home and End key === 35 || key === 36 || // left and right arrows key === 37 || key === 39 || // Del and Ins key === 46 || key === 45 ); }); }); };