From 6c571bf8284c44bf01fe20c267fe72cce235b90d Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 8 Sep 2019 13:16:05 -0400 Subject: Add UI for profiles --- ext/bg/js/settings-profiles.js | 201 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 ext/bg/js/settings-profiles.js (limited to 'ext/bg/js/settings-profiles.js') diff --git a/ext/bg/js/settings-profiles.js b/ext/bg/js/settings-profiles.js new file mode 100644 index 00000000..dca452d2 --- /dev/null +++ b/ext/bg/js/settings-profiles.js @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2019 Alex Yatskov + * Author: Alex Yatskov + * + * 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 . + */ + +let currentProfileIndex = 0; + +function getOptionsContext() { + return { + index: currentProfileIndex + }; +} + + +async function profileOptionsSetup() { + const optionsFull = await apiOptionsGetFull(); + currentProfileIndex = optionsFull.profileCurrent; + + profileOptionsSetupEventListeners(); + await profileOptionsUpdateTarget(optionsFull); +} + +function profileOptionsSetupEventListeners() { + $('#profile-target').change(utilAsync(onTargetProfileChanged)); + $('#profile-name').change(onProfileNameChanged); + $('#profile-add').click(utilAsync(onProfileAdd)); + $('#profile-remove').click(utilAsync(onProfileRemove)); + $('#profile-remove-confirm').click(utilAsync(onProfileRemoveConfirm)); + $('.profile-form').find('input, select, textarea').not('.profile-form-manual').change(utilAsync(onProfileOptionsChanged)); +} + +function 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; +} + +async function profileFormRead(optionsFull) { + const profile = optionsFull.profiles[currentProfileIndex]; + + // Current profile + const index = tryGetIntegerValue('#profile-active', 0, optionsFull.profiles.length); + if (index !== null) { + optionsFull.profileCurrent = index; + } + + // Profile name + profile.name = $('#profile-name').val(); +} + +async function profileFormWrite(optionsFull) { + const profile = optionsFull.profiles[currentProfileIndex]; + + profileOptionsPopulateSelect($('#profile-active'), optionsFull.profiles, optionsFull.profileCurrent); + profileOptionsPopulateSelect($('#profile-target'), optionsFull.profiles, currentProfileIndex); + $('#profile-remove').prop('disabled', optionsFull.profiles.length <= 1); + + $('#profile-name').val(profile.name); +} + +function profileOptionsPopulateSelect(select, profiles, currentValue) { + select.empty(); + + for (let i = 0; i < profiles.length; ++i) { + const profile = profiles[i]; + select.append($(``)); + } + + select.val(`${currentValue}`); +} + +async function profileOptionsUpdateTarget(optionsFull) { + profileFormWrite(optionsFull); + + const optionsContext = getOptionsContext(); + const options = await apiOptionsGet(optionsContext); + await formWrite(options); +} + +function profileOptionsCreateCopyName(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 = ')'; + } else { + prefix = match[1]; + suffix = match[5]; + if (typeof match[2] === 'string') { + space = match[3]; + index = parseInt(match[4], 10) + 1; + } else { + space = ' '; + index = 2; + } + } + + 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; + } + } +} + +async function onProfileOptionsChanged(e) { + if (!e.originalEvent && !e.isTrigger) { + return; + } + + const optionsFull = await apiOptionsGetFull(); + await profileFormRead(optionsFull); + await apiOptionsSave(); +} + +async function onTargetProfileChanged() { + const optionsFull = await apiOptionsGetFull(); + const index = tryGetIntegerValue('#profile-target', 0, optionsFull.profiles.length); + if (index === null || currentProfileIndex === index) { + return; + } + + currentProfileIndex = index; + + await profileOptionsUpdateTarget(optionsFull); +} + +async function onProfileAdd() { + const optionsFull = await apiOptionsGetFull(); + const profile = utilIsolate(optionsFull.profiles[currentProfileIndex]); + profile.name = profileOptionsCreateCopyName(profile.name, optionsFull.profiles, 100); + optionsFull.profiles.push(profile); + currentProfileIndex = optionsFull.profiles.length - 1; + await profileOptionsUpdateTarget(optionsFull); + await apiOptionsSave(); +} + +async function onProfileRemove() { + const optionsFull = await apiOptionsGetFull(); + if (optionsFull.profiles.length <= 1) { + return; + } + + const profile = optionsFull.profiles[currentProfileIndex]; + + $('#profile-remove-modal-profile-name').text(profile.name); + $('#profile-remove-modal').modal('show'); +} + +async function onProfileRemoveConfirm() { + $('#profile-remove-modal').modal('hide'); + + const optionsFull = await apiOptionsGetFull(); + if (optionsFull.profiles.length <= 1) { + return; + } + + optionsFull.profiles.splice(currentProfileIndex, 1); + + if (currentProfileIndex >= optionsFull.profiles.length) { + --currentProfileIndex; + } + + if (optionsFull.profileCurrent >= optionsFull.profiles.length) { + optionsFull.profileCurrent = optionsFull.profiles.length - 1; + } + + await profileOptionsUpdateTarget(optionsFull); + await apiOptionsSave(); +} + +function onProfileNameChanged() { + $('#profile-active, #profile-target').find(`[value="${currentProfileIndex}"]`).text(this.value); +} -- cgit v1.2.3 From 1f77506f43607c6d3c9c87fbf82b993d87039526 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Tue, 10 Sep 2019 21:20:03 -0400 Subject: Implement profile copy --- ext/bg/js/settings-profiles.js | 39 ++++++++++++++++++++++++++++++++++++--- ext/bg/settings.html | 19 +++++++++++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) (limited to 'ext/bg/js/settings-profiles.js') diff --git a/ext/bg/js/settings-profiles.js b/ext/bg/js/settings-profiles.js index dca452d2..fa06203e 100644 --- a/ext/bg/js/settings-profiles.js +++ b/ext/bg/js/settings-profiles.js @@ -39,6 +39,8 @@ function profileOptionsSetupEventListeners() { $('#profile-add').click(utilAsync(onProfileAdd)); $('#profile-remove').click(utilAsync(onProfileRemove)); $('#profile-remove-confirm').click(utilAsync(onProfileRemoveConfirm)); + $('#profile-copy').click(utilAsync(onProfileCopy)); + $('#profile-copy-confirm').click(utilAsync(onProfileCopyConfirm)); $('.profile-form').find('input, select, textarea').not('.profile-form-manual').change(utilAsync(onProfileOptionsChanged)); } @@ -69,17 +71,22 @@ async function profileFormRead(optionsFull) { async function profileFormWrite(optionsFull) { const profile = optionsFull.profiles[currentProfileIndex]; - profileOptionsPopulateSelect($('#profile-active'), optionsFull.profiles, optionsFull.profileCurrent); - profileOptionsPopulateSelect($('#profile-target'), optionsFull.profiles, currentProfileIndex); + profileOptionsPopulateSelect($('#profile-active'), optionsFull.profiles, optionsFull.profileCurrent, null); + profileOptionsPopulateSelect($('#profile-target'), optionsFull.profiles, currentProfileIndex, null); $('#profile-remove').prop('disabled', optionsFull.profiles.length <= 1); + $('#profile-copy').prop('disabled', optionsFull.profiles.length <= 1); $('#profile-name').val(profile.name); } -function profileOptionsPopulateSelect(select, profiles, currentValue) { +function profileOptionsPopulateSelect(select, profiles, currentValue, ignoreIndices) { select.empty(); + for (let i = 0; i < profiles.length; ++i) { + if (ignoreIndices !== null && ignoreIndices.indexOf(i) >= 0) { + continue; + } const profile = profiles[i]; select.append($(``)); } @@ -199,3 +206,29 @@ async function onProfileRemoveConfirm() { function onProfileNameChanged() { $('#profile-active, #profile-target').find(`[value="${currentProfileIndex}"]`).text(this.value); } + +async function onProfileCopy() { + const optionsFull = await apiOptionsGetFull(); + if (optionsFull.profiles.length <= 1) { + return; + } + + profileOptionsPopulateSelect($('#profile-copy-source'), optionsFull.profiles, currentProfileIndex === 0 ? 1 : 0, [currentProfileIndex]); + $('#profile-copy-modal').modal('show'); +} + +async function onProfileCopyConfirm() { + $('#profile-copy-modal').modal('hide'); + + const optionsFull = await apiOptionsGetFull(); + const index = tryGetIntegerValue('#profile-copy-source', 0, optionsFull.profiles.length); + if (index === null || index === currentProfileIndex) { + return; + } + + const profile = utilIsolate(optionsFull.profiles[index].options); + optionsFull.profiles[currentProfileIndex].options = profile; + + await profileOptionsUpdateTarget(optionsFull); + await settingsSaveOptions(); +} diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 1a1bc2ed..c0489894 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -100,6 +100,25 @@ + +