2019-09-08 17:16:05 +00:00
|
|
|
/*
|
2020-04-10 18:06:55 +00:00
|
|
|
* Copyright (C) 2019-2020 Yomichan Authors
|
2019-09-08 17:16:05 +00:00
|
|
|
*
|
|
|
|
* 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
|
2020-01-01 17:00:31 +00:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2019-09-08 17:16:05 +00:00
|
|
|
*/
|
|
|
|
|
2020-03-11 02:30:36 +00:00
|
|
|
/* global
|
|
|
|
* ConditionsUI
|
2020-05-24 17:30:40 +00:00
|
|
|
* api
|
2020-03-11 02:30:36 +00:00
|
|
|
* conditionsClearCaches
|
|
|
|
* getOptionsFullMutable
|
2020-05-29 23:47:18 +00:00
|
|
|
* getProfileIndex
|
2020-05-24 17:38:48 +00:00
|
|
|
* onOptionsUpdated
|
2020-03-11 02:30:36 +00:00
|
|
|
* profileConditionsDescriptor
|
2020-05-09 15:36:00 +00:00
|
|
|
* profileConditionsDescriptorPromise
|
2020-05-29 23:47:18 +00:00
|
|
|
* setProfileIndex
|
2020-03-11 02:30:36 +00:00
|
|
|
* settingsSaveOptions
|
|
|
|
* utilBackgroundIsolate
|
|
|
|
*/
|
2020-02-01 20:00:34 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
class ProfileController {
|
|
|
|
constructor() {
|
|
|
|
this._conditionsContainer = null;
|
|
|
|
}
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
async prepare() {
|
|
|
|
const optionsFull = await getOptionsFullMutable();
|
|
|
|
setProfileIndex(optionsFull.profileCurrent);
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
this._setupEventListeners();
|
|
|
|
await this._updateTarget(optionsFull);
|
|
|
|
}
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
// Private
|
|
|
|
|
|
|
|
_setupEventListeners() {
|
|
|
|
$('#profile-target').change(this._onTargetProfileChanged.bind(this));
|
|
|
|
$('#profile-name').change(this._onNameChanged.bind(this));
|
|
|
|
$('#profile-add').click(this._onAdd.bind(this));
|
|
|
|
$('#profile-remove').click(this._onRemove.bind(this));
|
|
|
|
$('#profile-remove-confirm').click(this._onRemoveConfirm.bind(this));
|
|
|
|
$('#profile-copy').click(this._onCopy.bind(this));
|
|
|
|
$('#profile-copy-confirm').click(this._onCopyConfirm.bind(this));
|
|
|
|
$('#profile-move-up').click(() => this._onMove(-1));
|
|
|
|
$('#profile-move-down').click(() => this._onMove(1));
|
|
|
|
$('.profile-form').find('input, select, textarea').not('.profile-form-manual').change(this._onInputChanged.bind(this));
|
|
|
|
}
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
_tryGetIntegerValue(selector, min, max) {
|
|
|
|
const value = parseInt($(selector).val(), 10);
|
|
|
|
return (
|
|
|
|
typeof value === 'number' &&
|
|
|
|
Number.isFinite(value) &&
|
|
|
|
Math.floor(value) === value &&
|
|
|
|
value >= min &&
|
|
|
|
value < max
|
|
|
|
) ? value : null;
|
|
|
|
}
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
async _formRead(optionsFull) {
|
|
|
|
const currentProfileIndex = getProfileIndex();
|
|
|
|
const profile = optionsFull.profiles[currentProfileIndex];
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
// Current profile
|
|
|
|
const index = this._tryGetIntegerValue('#profile-active', 0, optionsFull.profiles.length);
|
|
|
|
if (index !== null) {
|
|
|
|
optionsFull.profileCurrent = index;
|
|
|
|
}
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
// Profile name
|
|
|
|
profile.name = $('#profile-name').val();
|
2019-09-08 17:16:05 +00:00
|
|
|
}
|
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
async _formWrite(optionsFull) {
|
|
|
|
const currentProfileIndex = getProfileIndex();
|
|
|
|
const profile = optionsFull.profiles[currentProfileIndex];
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
this._populateSelect($('#profile-active'), optionsFull.profiles, optionsFull.profileCurrent, null);
|
|
|
|
this._populateSelect($('#profile-target'), optionsFull.profiles, currentProfileIndex, null);
|
|
|
|
$('#profile-remove').prop('disabled', optionsFull.profiles.length <= 1);
|
|
|
|
$('#profile-copy').prop('disabled', optionsFull.profiles.length <= 1);
|
|
|
|
$('#profile-move-up').prop('disabled', currentProfileIndex <= 0);
|
|
|
|
$('#profile-move-down').prop('disabled', currentProfileIndex >= optionsFull.profiles.length - 1);
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
$('#profile-name').val(profile.name);
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
if (this._conditionsContainer !== null) {
|
|
|
|
this._conditionsContainer.cleanup();
|
|
|
|
}
|
2019-09-10 00:19:49 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
await profileConditionsDescriptorPromise;
|
|
|
|
this._conditionsContainer = new ConditionsUI.Container(
|
|
|
|
profileConditionsDescriptor,
|
|
|
|
'popupLevel',
|
|
|
|
profile.conditionGroups,
|
|
|
|
$('#profile-condition-groups'),
|
|
|
|
$('#profile-add-condition-group')
|
|
|
|
);
|
|
|
|
this._conditionsContainer.save = () => {
|
|
|
|
settingsSaveOptions();
|
|
|
|
conditionsClearCaches(profileConditionsDescriptor);
|
|
|
|
};
|
|
|
|
this._conditionsContainer.isolate = utilBackgroundIsolate;
|
2019-09-10 00:19:49 +00:00
|
|
|
}
|
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
_populateSelect(select, profiles, currentValue, ignoreIndices) {
|
|
|
|
select.empty();
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2019-09-11 01:20:03 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
for (let i = 0; i < profiles.length; ++i) {
|
|
|
|
if (ignoreIndices !== null && ignoreIndices.indexOf(i) >= 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const profile = profiles[i];
|
|
|
|
select.append($(`<option value="${i}">${profile.name}</option>`));
|
2019-09-11 01:20:03 +00:00
|
|
|
}
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
select.val(`${currentValue}`);
|
|
|
|
}
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
async _updateTarget(optionsFull) {
|
|
|
|
await this._formWrite(optionsFull);
|
|
|
|
await onOptionsUpdated({source: null});
|
|
|
|
}
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
_createCopyName(name, profiles, maxUniqueAttempts) {
|
|
|
|
let space, index, prefix, suffix;
|
|
|
|
const match = /^([\w\W]*\(Copy)((\s+)(\d+))?(\)\s*)$/.exec(name);
|
|
|
|
if (match === null) {
|
|
|
|
prefix = `${name} (Copy`;
|
|
|
|
space = '';
|
|
|
|
index = '';
|
|
|
|
suffix = ')';
|
2019-09-08 17:16:05 +00:00
|
|
|
} else {
|
2020-05-29 23:47:18 +00:00
|
|
|
prefix = match[1];
|
|
|
|
suffix = match[5];
|
|
|
|
if (typeof match[2] === 'string') {
|
|
|
|
space = match[3];
|
|
|
|
index = parseInt(match[4], 10) + 1;
|
|
|
|
} else {
|
|
|
|
space = ' ';
|
|
|
|
index = 2;
|
|
|
|
}
|
2019-09-08 17:16:05 +00:00
|
|
|
}
|
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
let i = 0;
|
|
|
|
while (true) {
|
|
|
|
const newName = `${prefix}${space}${index}${suffix}`;
|
|
|
|
if (i++ >= maxUniqueAttempts || profiles.findIndex((profile) => profile.name === newName) < 0) {
|
|
|
|
return newName;
|
|
|
|
}
|
|
|
|
if (typeof index !== 'number') {
|
|
|
|
index = 2;
|
|
|
|
space = ' ';
|
|
|
|
} else {
|
|
|
|
++index;
|
|
|
|
}
|
2019-09-08 17:16:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
async _onInputChanged(e) {
|
|
|
|
if (!e.originalEvent && !e.isTrigger) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const optionsFull = await getOptionsFullMutable();
|
|
|
|
await this._formRead(optionsFull);
|
|
|
|
await settingsSaveOptions();
|
2019-09-08 17:16:05 +00:00
|
|
|
}
|
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
async _onTargetProfileChanged() {
|
|
|
|
const optionsFull = await getOptionsFullMutable();
|
|
|
|
const currentProfileIndex = getProfileIndex();
|
|
|
|
const index = this._tryGetIntegerValue('#profile-target', 0, optionsFull.profiles.length);
|
|
|
|
if (index === null || currentProfileIndex === index) {
|
|
|
|
return;
|
|
|
|
}
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
setProfileIndex(index);
|
|
|
|
|
|
|
|
await this._updateTarget(optionsFull);
|
|
|
|
|
|
|
|
yomichan.trigger('modifyingProfileChange');
|
2019-09-08 17:16:05 +00:00
|
|
|
}
|
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
async _onAdd() {
|
|
|
|
const optionsFull = await getOptionsFullMutable();
|
|
|
|
const currentProfileIndex = getProfileIndex();
|
|
|
|
const profile = utilBackgroundIsolate(optionsFull.profiles[currentProfileIndex]);
|
|
|
|
profile.name = this._createCopyName(profile.name, optionsFull.profiles, 100);
|
|
|
|
optionsFull.profiles.push(profile);
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
setProfileIndex(optionsFull.profiles.length - 1);
|
2020-04-26 19:33:50 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
await this._updateTarget(optionsFull);
|
|
|
|
await settingsSaveOptions();
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
yomichan.trigger('modifyingProfileChange');
|
|
|
|
}
|
2020-04-26 19:33:50 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
async _onRemove(e) {
|
|
|
|
if (e.shiftKey) {
|
|
|
|
return await this._onRemoveConfirm();
|
|
|
|
}
|
2020-04-26 19:33:50 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
const optionsFull = await api.optionsGetFull();
|
|
|
|
if (optionsFull.profiles.length <= 1) {
|
|
|
|
return;
|
|
|
|
}
|
2020-04-26 19:33:50 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
const currentProfileIndex = getProfileIndex();
|
|
|
|
const profile = optionsFull.profiles[currentProfileIndex];
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
$('#profile-remove-modal-profile-name').text(profile.name);
|
|
|
|
$('#profile-remove-modal').modal('show');
|
2019-09-11 01:32:07 +00:00
|
|
|
}
|
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
async _onRemoveConfirm() {
|
|
|
|
$('#profile-remove-modal').modal('hide');
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
const optionsFull = await getOptionsFullMutable();
|
|
|
|
if (optionsFull.profiles.length <= 1) {
|
|
|
|
return;
|
|
|
|
}
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
const currentProfileIndex = getProfileIndex();
|
|
|
|
optionsFull.profiles.splice(currentProfileIndex, 1);
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
if (currentProfileIndex >= optionsFull.profiles.length) {
|
|
|
|
setProfileIndex(optionsFull.profiles.length - 1);
|
|
|
|
}
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
if (optionsFull.profileCurrent >= optionsFull.profiles.length) {
|
|
|
|
optionsFull.profileCurrent = optionsFull.profiles.length - 1;
|
|
|
|
}
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
await this._updateTarget(optionsFull);
|
|
|
|
await settingsSaveOptions();
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
yomichan.trigger('modifyingProfileChange');
|
2019-09-08 17:16:05 +00:00
|
|
|
}
|
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
_onNameChanged() {
|
|
|
|
const currentProfileIndex = getProfileIndex();
|
|
|
|
$('#profile-active, #profile-target').find(`[value="${currentProfileIndex}"]`).text(this.value);
|
2019-09-08 17:16:05 +00:00
|
|
|
}
|
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
async _onMove(offset) {
|
|
|
|
const optionsFull = await getOptionsFullMutable();
|
|
|
|
const currentProfileIndex = getProfileIndex();
|
|
|
|
const index = currentProfileIndex + offset;
|
|
|
|
if (index < 0 || index >= optionsFull.profiles.length) {
|
|
|
|
return;
|
|
|
|
}
|
2020-04-26 19:33:50 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
const profile = optionsFull.profiles[currentProfileIndex];
|
|
|
|
optionsFull.profiles.splice(currentProfileIndex, 1);
|
|
|
|
optionsFull.profiles.splice(index, 0, profile);
|
2019-09-08 17:16:05 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
if (optionsFull.profileCurrent === currentProfileIndex) {
|
|
|
|
optionsFull.profileCurrent = index;
|
|
|
|
}
|
2019-09-11 01:20:03 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
setProfileIndex(index);
|
2019-09-11 01:29:01 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
await this._updateTarget(optionsFull);
|
|
|
|
await settingsSaveOptions();
|
2019-09-11 01:29:01 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
yomichan.trigger('modifyingProfileChange');
|
2019-09-11 01:29:01 +00:00
|
|
|
}
|
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
async _onCopy() {
|
|
|
|
const optionsFull = await api.optionsGetFull();
|
|
|
|
if (optionsFull.profiles.length <= 1) {
|
|
|
|
return;
|
|
|
|
}
|
2019-09-11 01:29:01 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
const currentProfileIndex = getProfileIndex();
|
|
|
|
this._populateSelect($('#profile-copy-source'), optionsFull.profiles, currentProfileIndex === 0 ? 1 : 0, [currentProfileIndex]);
|
|
|
|
$('#profile-copy-modal').modal('show');
|
2019-09-11 01:20:03 +00:00
|
|
|
}
|
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
async _onCopyConfirm() {
|
|
|
|
$('#profile-copy-modal').modal('hide');
|
2019-09-11 01:20:03 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
const optionsFull = await getOptionsFullMutable();
|
|
|
|
const index = this._tryGetIntegerValue('#profile-copy-source', 0, optionsFull.profiles.length);
|
|
|
|
const currentProfileIndex = getProfileIndex();
|
|
|
|
if (index === null || index === currentProfileIndex) {
|
|
|
|
return;
|
|
|
|
}
|
2019-09-11 01:20:03 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
const profileOptions = utilBackgroundIsolate(optionsFull.profiles[index].options);
|
|
|
|
optionsFull.profiles[currentProfileIndex].options = profileOptions;
|
2019-09-11 01:20:03 +00:00
|
|
|
|
2020-05-29 23:47:18 +00:00
|
|
|
await this._updateTarget(optionsFull);
|
|
|
|
await settingsSaveOptions();
|
|
|
|
}
|
2019-09-11 01:20:03 +00:00
|
|
|
}
|