Merge pull request #14625 from Chocobo1/backport

Backport to v4_3_x (#14619, #14590)
This commit is contained in:
Mike Tzou 2021-03-27 11:14:26 +08:00 committed by GitHub
commit 81a7b0c034
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 353 additions and 265 deletions

31
.github/workflows/webui_ci.yaml vendored Normal file
View file

@ -0,0 +1,31 @@
name: WebUI CI
on: [pull_request, push]
jobs:
check_webui:
name: Check WebUI
runs-on: ubuntu-20.04
defaults:
run:
working-directory: src/webui/www
steps:
- name: checkout repository
uses: actions/checkout@v2
- name: setup nodejs
uses: actions/setup-node@v2
with:
node-version: '14'
- name: install tools
run: npm install
- name: lint code
run: npm run lint
- name: format code
run: |
npm run format
git diff --exit-code

View file

@ -47,6 +47,18 @@ namespace
return (left < right) ? -1 : 1; return (left < right) ? -1 : 1;
} }
int customCompare(const QDateTime &left, const QDateTime &right)
{
const bool isLeftValid = left.isValid();
const bool isRightValid = right.isValid();
if (isLeftValid && isRightValid)
return threeWayCompare(left, right);
if (!isLeftValid && !isRightValid)
return 0;
return isLeftValid ? -1 : 1;
}
template <typename T> template <typename T>
int customCompare(const T left, const T right) int customCompare(const T left, const T right)
{ {
@ -158,7 +170,7 @@ int TransferListSortModel::compare(const QModelIndex &left, const QModelIndex &r
case TransferListModel::TR_ADD_DATE: case TransferListModel::TR_ADD_DATE:
case TransferListModel::TR_SEED_DATE: case TransferListModel::TR_SEED_DATE:
case TransferListModel::TR_SEEN_COMPLETE_DATE: case TransferListModel::TR_SEEN_COMPLETE_DATE:
return threeWayCompare(leftValue.toDateTime(), rightValue.toDateTime()); return customCompare(leftValue.toDateTime(), rightValue.toDateTime());
case TransferListModel::TR_DLLIMIT: case TransferListModel::TR_DLLIMIT:
case TransferListModel::TR_DLSPEED: case TransferListModel::TR_DLSPEED:

View file

@ -0,0 +1,14 @@
{
"env": {
"browser": true,
"es2020": true
},
"extends": "eslint:recommended",
"plugins": [
"html"
],
"rules": {
"no-undef": "off",
"no-unused-vars": "off"
}
}

View file

@ -11,7 +11,7 @@
"space_in_empty_paren": false, "space_in_empty_paren": false,
"jslint_happy": false, "jslint_happy": false,
"space_after_anon_function": false, "space_after_anon_function": false,
"brace_style": "end-expand", "brace_style": "end-expand,preserve-inline",
"unindent_chained_methods": false, "unindent_chained_methods": false,
"break_chained_methods": false, "break_chained_methods": false,
"keep_array_indentation": false, "keep_array_indentation": false,

View file

@ -0,0 +1,17 @@
{
"name": "webui",
"description": "qBittorrent WebUI",
"repository": {
"type": "git",
"url": "https://github.com/qbittorrent/qBittorrent.git"
},
"scripts": {
"format": "js-beautify private/*.html private/scripts/*.js private/views/*.html public/*.html public/scripts/*.js",
"lint": "eslint private/*.html private/scripts/*.js private/views/*.html public/*.html public/scripts/*.js"
},
"devDependencies": {
"eslint": "*",
"eslint-plugin-html": "*",
"js-beautify": "*"
}
}

View file

@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="${LANG}"> <html lang="${LANG}">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title>QBT_TR(Add Peers)QBT_TR[CONTEXT=PeersAdditionDialog]</title> <title>QBT_TR(Add Peers)QBT_TR[CONTEXT=PeersAdditionDialog]</title>
@ -66,4 +67,5 @@
</div> </div>
</div> </div>
</body> </body>
</html> </html>

View file

@ -464,7 +464,7 @@ window.addEvent('load', function() {
const torrentsCount = torrentsTable.getRowIds().length; const torrentsCount = torrentsTable.getRowIds().length;
let untagged = 0; let untagged = 0;
for (const key in torrentsTable.rows) { for (const key in torrentsTable.rows) {
if (torrentsTable.rows.hasOwnProperty(key) && torrentsTable.rows[key]['full_data'].tags.length === 0) if (Object.prototype.hasOwnProperty.call(torrentsTable.rows, key) && (torrentsTable.rows[key]['full_data'].tags.length === 0))
untagged += 1; untagged += 1;
} }
tagFilterList.appendChild(createLink(TAGS_ALL, 'QBT_TR(All)QBT_TR[CONTEXT=TagFilterModel]', torrentsCount)); tagFilterList.appendChild(createLink(TAGS_ALL, 'QBT_TR(All)QBT_TR[CONTEXT=TagFilterModel]', torrentsCount));
@ -519,7 +519,7 @@ window.addEvent('load', function() {
trackerFilterList.appendChild(createLink(TRACKERS_ALL, 'QBT_TR(All (%1))QBT_TR[CONTEXT=TrackerFiltersList]', torrentsCount)); trackerFilterList.appendChild(createLink(TRACKERS_ALL, 'QBT_TR(All (%1))QBT_TR[CONTEXT=TrackerFiltersList]', torrentsCount));
let trackerlessTorrentsCount = 0; let trackerlessTorrentsCount = 0;
for (const key in torrentsTable.rows) { for (const key in torrentsTable.rows) {
if (torrentsTable.rows.hasOwnProperty(key) && (torrentsTable.rows[key]['full_data'].trackers_count === 0)) if (Object.prototype.hasOwnProperty.call(torrentsTable.rows, key) && (torrentsTable.rows[key]['full_data'].trackers_count === 0))
trackerlessTorrentsCount += 1; trackerlessTorrentsCount += 1;
} }
trackerFilterList.appendChild(createLink(TRACKERS_TRACKERLESS, 'QBT_TR(Trackerless (%1))QBT_TR[CONTEXT=TrackerFiltersList]', trackerlessTorrentsCount)); trackerFilterList.appendChild(createLink(TRACKERS_TRACKERLESS, 'QBT_TR(Trackerless (%1))QBT_TR[CONTEXT=TrackerFiltersList]', trackerlessTorrentsCount));
@ -744,20 +744,17 @@ window.addEvent('load', function() {
} }
switch (serverState.connection_status) { switch (serverState.connection_status) {
case 'connected': { case 'connected':
$('connectionStatus').src = 'icons/connected.svg'; $('connectionStatus').src = 'icons/connected.svg';
$('connectionStatus').alt = 'QBT_TR(Connection status: Connected)QBT_TR[CONTEXT=MainWindow]'; $('connectionStatus').alt = 'QBT_TR(Connection status: Connected)QBT_TR[CONTEXT=MainWindow]';
}
break; break;
case 'firewalled': { case 'firewalled':
$('connectionStatus').src = 'icons/firewalled.svg'; $('connectionStatus').src = 'icons/firewalled.svg';
$('connectionStatus').alt = 'QBT_TR(Connection status: Firewalled)QBT_TR[CONTEXT=MainWindow]'; $('connectionStatus').alt = 'QBT_TR(Connection status: Firewalled)QBT_TR[CONTEXT=MainWindow]';
}
break; break;
default: { default:
$('connectionStatus').src = 'icons/disconnected.svg'; $('connectionStatus').src = 'icons/disconnected.svg';
$('connectionStatus').alt = 'QBT_TR(Connection status: Disconnected)QBT_TR[CONTEXT=MainWindow]'; $('connectionStatus').alt = 'QBT_TR(Connection status: Disconnected)QBT_TR[CONTEXT=MainWindow]';
}
break; break;
} }

View file

@ -778,7 +778,7 @@ window.qBittorrent.DynamicTable = (function() {
const tds = tr.getElements('td'); const tds = tr.getElements('td');
for (let i = 0; i < this.columns.length; ++i) { for (let i = 0; i < this.columns.length; ++i) {
if (data.hasOwnProperty(this.columns[i].dataProperties[0])) if (Object.prototype.hasOwnProperty.call(data, this.columns[i].dataProperties[0]))
this.columns[i].updateTd(tds[i], row); this.columns[i].updateTd(tds[i], row);
} }
row['data'] = {}; row['data'] = {};
@ -1287,13 +1287,15 @@ window.qBittorrent.DynamicTable = (function() {
return false; return false;
break; // do nothing break; // do nothing
default: default: {
let rowTags = row['full_data'].tags.split(', '); let rowTags = row['full_data'].tags.split(', ');
rowTags = rowTags.map(function(tag) { rowTags = rowTags.map(function(tag) {
return genHash(tag); return genHash(tag);
}); });
if (!rowTags.contains(tagHashInt)) if (!rowTags.contains(tagHashInt))
return false; return false;
break;
}
} }
} }
@ -1305,12 +1307,13 @@ window.qBittorrent.DynamicTable = (function() {
if (row['full_data'].trackers_count !== 0) if (row['full_data'].trackers_count !== 0)
return false; return false;
break; break;
default: default: {
const tracker = trackerList.get(trackerHashInt); const tracker = trackerList.get(trackerHashInt);
if (tracker && !tracker.torrents.includes(row['full_data'].rowId)) if (tracker && !tracker.torrents.includes(row['full_data'].rowId))
return false; return false;
break; break;
} }
}
if ((filterTerms !== undefined) && (filterTerms !== null) if ((filterTerms !== undefined) && (filterTerms !== null)
&& (filterTerms.length > 0) && !window.qBittorrent.Misc.containsAllTerms(name, filterTerms)) && (filterTerms.length > 0) && !window.qBittorrent.Misc.containsAllTerms(name, filterTerms))
@ -2058,7 +2061,7 @@ window.qBittorrent.DynamicTable = (function() {
const tds = tr.getElements('td'); const tds = tr.getElements('td');
for (let i = 0; i < this.columns.length; ++i) { for (let i = 0; i < this.columns.length; ++i) {
if (data.hasOwnProperty(this.columns[i].dataProperties[0])) if (Object.prototype.hasOwnProperty.call(data, this.columns[i].dataProperties[0]))
this.columns[i].updateTd(tds[i], row); this.columns[i].updateTd(tds[i], row);
} }
row['data'] = {}; row['data'] = {};
@ -2203,7 +2206,7 @@ window.qBittorrent.DynamicTable = (function() {
const tds = tr.getElements('td'); const tds = tr.getElements('td');
for (let i = 0; i < this.columns.length; ++i) { for (let i = 0; i < this.columns.length; ++i) {
if (data.hasOwnProperty(this.columns[i].dataProperties[0])) if (Object.prototype.hasOwnProperty.call(data, this.columns[i].dataProperties[0]))
this.columns[i].updateTd(tds[i], row); this.columns[i].updateTd(tds[i], row);
} }
row['data'] = {}; row['data'] = {};
@ -2484,14 +2487,13 @@ window.qBittorrent.DynamicTable = (function() {
const tds = tr.getElements('td'); const tds = tr.getElements('td');
for (let i = 0; i < this.columns.length; ++i) { for (let i = 0; i < this.columns.length; ++i) {
if (data.hasOwnProperty(this.columns[i].dataProperties[0])) if (Object.prototype.hasOwnProperty.call(data, this.columns[i].dataProperties[0]))
this.columns[i].updateTd(tds[i], row); this.columns[i].updateTd(tds[i], row);
} }
row['data'] = {}; row['data'] = {};
} }
}); });
return exports(); return exports();
})(); })();

View file

@ -162,7 +162,7 @@ window.qBittorrent.Misc = (function() {
* JS counterpart of the function in src/misc.cpp * JS counterpart of the function in src/misc.cpp
*/ */
const parseHtmlLinks = function(text) { const parseHtmlLinks = function(text) {
const exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; const exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#/%?=~_|!:,.;]*[-A-Z0-9+&@#/%=~_|])/ig;
return text.replace(exp, "<a target='_blank' href='$1'>$1</a>"); return text.replace(exp, "<a target='_blank' href='$1'>$1</a>");
} }

View file

@ -151,7 +151,8 @@
<li><a name="TOC1" href="#SEC1">GNU GENERAL PUBLIC <li><a name="TOC1" href="#SEC1">GNU GENERAL PUBLIC
LICENSE LICENSE
<!--TRANSLATORS: Don't translate the license; copy msgid's <!--TRANSLATORS: Don't translate the license; copy msgid's
verbatim!--></a> verbatim!-->
</a>
<ul> <ul>
<li><a name="TOC2" href="#SEC2">Preamble</a></li> <li><a name="TOC2" href="#SEC2">Preamble</a></li>
<li><a name="TOC3" href="#SEC3">TERMS AND CONDITIONS <li><a name="TOC3" href="#SEC3">TERMS AND CONDITIONS

View file

@ -803,7 +803,8 @@
<fieldset class="settings"> <fieldset class="settings">
<legend><input type="checkbox" id="use_alt_webui_checkbox" onclick="qBittorrent.Preferences.updateAlternativeWebUISettings();" /> <legend><input type="checkbox" id="use_alt_webui_checkbox" onclick="qBittorrent.Preferences.updateAlternativeWebUISettings();" />
<label for="use_alt_webui_checkbox">QBT_TR(Use alternative Web UI)QBT_TR[CONTEXT=OptionsDialog]</label></legend> <label for="use_alt_webui_checkbox">QBT_TR(Use alternative Web UI)QBT_TR[CONTEXT=OptionsDialog]</label>
</legend>
<div class="formRow"> <div class="formRow">
<label for="webui_files_location_textarea">QBT_TR(Files location:)QBT_TR[CONTEXT=OptionsDialog]</label> <label for="webui_files_location_textarea">QBT_TR(Files location:)QBT_TR[CONTEXT=OptionsDialog]</label>
<input type="text" id="webui_files_location_textarea" /> <input type="text" id="webui_files_location_textarea" />

View file

@ -11,7 +11,8 @@
vertical-align: top; vertical-align: top;
} }
#rssFeedFixedHeaderDiv .dynamicTableHeader, #rssArticleFixedHeaderDiv .dynamicTableHeader { #rssFeedFixedHeaderDiv .dynamicTableHeader,
#rssArticleFixedHeaderDiv .dynamicTableHeader {
cursor: default; cursor: default;
} }
@ -33,7 +34,9 @@
margin: 0 10px 0 10px; margin: 0 10px 0 10px;
} }
#leftRssColumn, #centerRssColumn, #rightRssColumn { #leftRssColumn,
#centerRssColumn,
#rightRssColumn {
float: left; float: left;
/* should be 20 px but due to rounding differences some browsers don't render that properly */ /* should be 20 px but due to rounding differences some browsers don't render that properly */
width: calc(calc(100% - 21px) / 3); width: calc(calc(100% - 21px) / 3);
@ -44,7 +47,8 @@
overflow: auto; overflow: auto;
} }
#rssFeedTableDiv, #rssArticleTableDiv { #rssFeedTableDiv,
#rssArticleTableDiv {
height: calc(100vh - 180px); height: calc(100vh - 180px);
} }
@ -179,7 +183,7 @@
}; };
let feedData = {}; let feedData = {};
let pathByFeedId = new Map();; let pathByFeedId = new Map();
let feedRefreshTimer; let feedRefreshTimer;
let rssFeedTable = new window.qBittorrent.DynamicTable.RssFeedTable(); let rssFeedTable = new window.qBittorrent.DynamicTable.RssFeedTable();
let rssArticleTable = new window.qBittorrent.DynamicTable.RssArticleTable(); let rssArticleTable = new window.qBittorrent.DynamicTable.RssArticleTable();
@ -197,9 +201,9 @@
$('rssFetchingDisabled').removeClass('invisible'); $('rssFetchingDisabled').removeClass('invisible');
// recalculate heights // recalculate heights
let nonPageHeight = $('rssTopBar').getBoundingClientRect().height + let nonPageHeight = $('rssTopBar').getBoundingClientRect().height
$('desktopHeader').getBoundingClientRect().height + + $('desktopHeader').getBoundingClientRect().height
$('desktopFooterWrapper').getBoundingClientRect().height + 20; + $('desktopFooterWrapper').getBoundingClientRect().height + 20;
$('rssDetailsView').style.height = 'calc(100vh - ' + nonPageHeight + 'px)'; $('rssDetailsView').style.height = 'calc(100vh - ' + nonPageHeight + 'px)';
let nonTableHeight = nonPageHeight + $('rssFeedFixedHeaderDiv').getBoundingClientRect().height; let nonTableHeight = nonPageHeight + $('rssFeedFixedHeaderDiv').getBoundingClientRect().height;
@ -274,7 +278,6 @@
}); });
rssFeedTable.setup('rssFeedTableDiv', 'rssFeedFixedHeaderDiv', rssFeedContextMenu); rssFeedTable.setup('rssFeedTableDiv', 'rssFeedFixedHeaderDiv', rssFeedContextMenu);
const rssArticleContextMenu = new window.qBittorrent.ContextMenu.RssArticleContextMenu({ const rssArticleContextMenu = new window.qBittorrent.ContextMenu.RssArticleContextMenu({
targets: '.rssArticleElement', targets: '.rssArticleElement',
menu: 'rssArticleMenu', menu: 'rssArticleMenu',
@ -435,8 +438,8 @@
//calculate height to fill screen //calculate height to fill screen
document.getElementById('rssDescription').style.height = document.getElementById('rssDescription').style.height =
"calc(100% - " + document.getElementById('rssTorrentDetailsName').offsetHeight + "px - " + "calc(100% - " + document.getElementById('rssTorrentDetailsName').offsetHeight + "px - "
document.getElementById('rssTorrentDetailsDate').offsetHeight + "px - 5px)"; + document.getElementById('rssTorrentDetailsDate').offsetHeight + "px - 5px)";
} }
}; };
@ -479,8 +482,8 @@
if (rssFeedTable.rows.getLength() - 1 === flattenedResp.length) { if (rssFeedTable.rows.getLength() - 1 === flattenedResp.length) {
match = true; match = true;
for (let i = 0; i < flattenedResp.length; ++i) { for (let i = 0; i < flattenedResp.length; ++i) {
if ((flattenedResp[i].uid ? flattenedResp[i].uid : '') !== rssFeedTable.rows[i + 1].full_data.dataUid || if ((flattenedResp[i].uid ? flattenedResp[i].uid : '') !== rssFeedTable.rows[i + 1].full_data.dataUid
flattenedResp[i].fullName !== rssFeedTable.rows[i + 1].full_data.dataPath) { || flattenedResp[i].fullName !== rssFeedTable.rows[i + 1].full_data.dataPath) {
match = false; match = false;
break; break;
} }

View file

@ -12,7 +12,8 @@
float: left; float: left;
} }
#rulesTable, #rssDownloaderArticlesTable { #rulesTable,
#rssDownloaderArticlesTable {
overflow: auto; overflow: auto;
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -68,7 +69,9 @@
margin-bottom: 10px; margin-bottom: 10px;
} }
#rulesTable table, #rssDownloaderFeedsTable table, #rssDownloaderArticlesTable table { #rulesTable table,
#rssDownloaderFeedsTable table,
#rssDownloaderArticlesTable table {
width: 100%; width: 100%;
} }
@ -123,6 +126,7 @@
float: right; float: right;
background-image: url('icons/list-remove.svg'); background-image: url('icons/list-remove.svg');
} }
</style> </style>
<div id="RssDownloader" class="RssDownloader"> <div id="RssDownloader" class="RssDownloader">
@ -366,8 +370,8 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
$('rulesTable').style.height = 'calc(100% - ' + $('rulesTableDesc').getBoundingClientRect().height + 'px)'; $('rulesTable').style.height = 'calc(100% - ' + $('rulesTableDesc').getBoundingClientRect().height + 'px)';
$('rssDownloaderArticlesTable').style.height = 'calc(100% - ' + $('articleTableDesc').getBoundingClientRect().height + 'px)'; $('rssDownloaderArticlesTable').style.height = 'calc(100% - ' + $('articleTableDesc').getBoundingClientRect().height + 'px)';
let centerRowNotTableHeight = $('saveButton').getBoundingClientRect().height + let centerRowNotTableHeight = $('saveButton').getBoundingClientRect().height
$('ruleSettings').getBoundingClientRect().height + 15; + $('ruleSettings').getBoundingClientRect().height + 15;
$('rssDownloaderFeeds').style.height = 'calc(100% - ' + centerRowNotTableHeight + 'px)'; $('rssDownloaderFeeds').style.height = 'calc(100% - ' + centerRowNotTableHeight + 'px)';
@ -759,12 +763,12 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
mainPart = 'QBT_TR(Regex mode: use Perl-compatible regular expressions)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n'; mainPart = 'QBT_TR(Regex mode: use Perl-compatible regular expressions)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n';
} }
else { else {
mainPart = 'QBT_TR(Wildcard mode: you can use)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n' + mainPart = 'QBT_TR(Wildcard mode: you can use)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n'
' ● QBT_TR(? to match any single character)QBT_TR[CONTEXT=AutomatedRssDownloader]\n' + + ' ● QBT_TR(? to match any single character)QBT_TR[CONTEXT=AutomatedRssDownloader]\n'
' ● QBT_TR(* to match zero or more of any characters)QBT_TR[CONTEXT=AutomatedRssDownloader]\n' + + ' ● QBT_TR(* to match zero or more of any characters)QBT_TR[CONTEXT=AutomatedRssDownloader]\n'
' ● QBT_TR(Whitespaces count as AND operators (all words, any order))QBT_TR[CONTEXT=AutomatedRssDownloader]\n' + + ' ● QBT_TR(Whitespaces count as AND operators (all words, any order))QBT_TR[CONTEXT=AutomatedRssDownloader]\n'
' ● QBT_TR(| is used as OR operator)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n' + + ' ● QBT_TR(| is used as OR operator)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n'
'QBT_TR(If word order is important use * instead of whitespace.)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n'; + 'QBT_TR(If word order is important use * instead of whitespace.)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n';
} }
let secondPart = 'QBT_TR(An expression with an empty %1 clause (e.g. %2))QBT_TR[CONTEXT=AutomatedRssDownloader]' let secondPart = 'QBT_TR(An expression with an empty %1 clause (e.g. %2))QBT_TR[CONTEXT=AutomatedRssDownloader]'
.replace('%1', '|').replace('%2', 'expr|'); .replace('%1', '|').replace('%2', 'expr|');
@ -772,24 +776,23 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
$('mustContainText').title = mainPart + secondPart + 'QBT_TR( will match all articles.)QBT_TR[CONTEXT=AutomatedRssDownloader]'; $('mustContainText').title = mainPart + secondPart + 'QBT_TR( will match all articles.)QBT_TR[CONTEXT=AutomatedRssDownloader]';
$('mustNotContainText').title = mainPart + secondPart + 'QBT_TR( will exclude all articles.)QBT_TR[CONTEXT=AutomatedRssDownloader]'; $('mustNotContainText').title = mainPart + secondPart + 'QBT_TR( will exclude all articles.)QBT_TR[CONTEXT=AutomatedRssDownloader]';
let episodeFilterTitle = 'QBT_TR(Matches articles based on episode filter.)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n' + let episodeFilterTitle = 'QBT_TR(Matches articles based on episode filter.)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n'
'QBT_TR(Example: )QBT_TR[CONTEXT=AutomatedRssDownloader]' + + 'QBT_TR(Example: )QBT_TR[CONTEXT=AutomatedRssDownloader]'
'1x2;8-15;5;30-;' + + '1x2;8-15;5;30-;'
'QBT_TR( will match 2, 5, 8 through 15, 30 and onward episodes of season one)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n' + + 'QBT_TR( will match 2, 5, 8 through 15, 30 and onward episodes of season one)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n'
'QBT_TR(Episode filter rules: )QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n' + + 'QBT_TR(Episode filter rules: )QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n'
' ● QBT_TR(Season number is a mandatory non-zero value)QBT_TR[CONTEXT=AutomatedRssDownloader]\n' + + ' ● QBT_TR(Season number is a mandatory non-zero value)QBT_TR[CONTEXT=AutomatedRssDownloader]\n'
' ● QBT_TR(Episode number is a mandatory positive value)QBT_TR[CONTEXT=AutomatedRssDownloader]\n' + + ' ● QBT_TR(Episode number is a mandatory positive value)QBT_TR[CONTEXT=AutomatedRssDownloader]\n'
' ● QBT_TR(Filter must end with semicolon)QBT_TR[CONTEXT=AutomatedRssDownloader]\n' + + ' ● QBT_TR(Filter must end with semicolon)QBT_TR[CONTEXT=AutomatedRssDownloader]\n'
' ● QBT_TR(Three range types for episodes are supported: )QBT_TR[CONTEXT=AutomatedRssDownloader]\n' + + ' ● QBT_TR(Three range types for episodes are supported: )QBT_TR[CONTEXT=AutomatedRssDownloader]\n'
' ● QBT_TR(Single number: <b>1x25;</b> matches episode 25 of season one)QBT_TR[CONTEXT=AutomatedRssDownloader]\n' + + ' ● QBT_TR(Single number: <b>1x25;</b> matches episode 25 of season one)QBT_TR[CONTEXT=AutomatedRssDownloader]\n'
' ● QBT_TR(Normal range: <b>1x25-40;</b> matches episodes 25 through 40 of season one)QBT_TR[CONTEXT=AutomatedRssDownloader]\n' + + ' ● QBT_TR(Normal range: <b>1x25-40;</b> matches episodes 25 through 40 of season one)QBT_TR[CONTEXT=AutomatedRssDownloader]\n'
' ● QBT_TR(Infinite range: <b>1x25-;</b> matches episodes 25 and upward of season one, and all episodes of later seasons)QBT_TR[CONTEXT=AutomatedRssDownloader]'; + ' ● QBT_TR(Infinite range: <b>1x25-;</b> matches episodes 25 and upward of season one, and all episodes of later seasons)QBT_TR[CONTEXT=AutomatedRssDownloader]';
episodeFilterTitle = episodeFilterTitle.replace(/<b>/g, '').replace(/<\/b>/g, ''); episodeFilterTitle = episodeFilterTitle.replace(/<b>/g, '').replace(/<\/b>/g, '');
$('episodeFilterText').title = episodeFilterTitle; $('episodeFilterText').title = episodeFilterTitle;
} }
initRssDownloader(); initRssDownloader();
return exports(); return exports();
})(); })();

View file

@ -41,7 +41,10 @@
margin-right: 20px; margin-right: 20px;
} }
#searchMinSeedsFilter, #searchMaxSeedsFilter, #searchMinSizeFilter, #searchMaxSizeFilter { #searchMinSeedsFilter,
#searchMaxSeedsFilter,
#searchMinSizeFilter,
#searchMaxSizeFilter {
width: 4em; width: 4em;
} }

View file

@ -26,10 +26,12 @@
<form id="loginform" method="post" onsubmit="submitLoginForm();"> <form id="loginform" method="post" onsubmit="submitLoginForm();">
<div class="row"> <div class="row">
<label for="username">QBT_TR(Username)QBT_TR[CONTEXT=HttpServer]</label><br /> <label for="username">QBT_TR(Username)QBT_TR[CONTEXT=HttpServer]</label><br />
<input type="text" id="username" name="username" autocomplete="username" /></div> <input type="text" id="username" name="username" autocomplete="username" />
</div>
<div class="row"> <div class="row">
<label for="password">QBT_TR(Password)QBT_TR[CONTEXT=HttpServer]</label><br /> <label for="password">QBT_TR(Password)QBT_TR[CONTEXT=HttpServer]</label><br />
<input type="password" id="password" name="password" autocomplete="current-password" /></div> <input type="password" id="password" name="password" autocomplete="current-password" />
</div>
<div class="row"> <div class="row">
<input type="submit" id="login" value="QBT_TR(Login)QBT_TR[CONTEXT=HttpServer]" /> <input type="submit" id="login" value="QBT_TR(Login)QBT_TR[CONTEXT=HttpServer]" />
</div> </div>