diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2019-09-08 13:16:05 -0400 | 
|---|---|---|
| committer | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2019-09-15 15:56:53 -0400 | 
| commit | 6c571bf8284c44bf01fe20c267fe72cce235b90d (patch) | |
| tree | 865cdde968346bb5e4d4a5ba6c9c82bc1c220bc6 /ext/bg/js | |
| parent | c8171f5ec7612f0ba147d7e0887cd8c30a527827 (diff) | |
Add UI for profiles
Diffstat (limited to 'ext/bg/js')
| -rw-r--r-- | ext/bg/js/api.js | 6 | ||||
| -rw-r--r-- | ext/bg/js/settings-profiles.js | 201 | ||||
| -rw-r--r-- | ext/bg/js/settings.js | 11 | 
3 files changed, 207 insertions, 11 deletions
| diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index 81772d08..f32b984f 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -21,9 +21,13 @@ function apiOptionsGet(optionsContext) {      return utilBackend().getOptions(optionsContext);  } +function apiOptionsGetFull() { +    return utilBackend().getFullOptions(); +} +  async function apiOptionsSave(source) {      const backend = utilBackend(); -    const options = await backend.getFullOptions(); +    const options = await apiOptionsGetFull();      await optionsSave(options);      backend.onOptionsUpdated(source);  } 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 <alex@foosoft.net> + * Author: Alex Yatskov <alex@foosoft.net> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +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($(`<option value="${i}">${profile.name}</option>`)); +    } + +    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); +} diff --git a/ext/bg/js/settings.js b/ext/bg/js/settings.js index 88929c49..b6434843 100644 --- a/ext/bg/js/settings.js +++ b/ext/bg/js/settings.js @@ -16,12 +16,6 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */ -function getOptionsContext() { -    return { -        depth: 0 -    }; -} -  async function formRead(options) {      options.general.enable = $('#enable').prop('checked');      options.general.showGuide = $('#show-usage-guide').prop('checked'); @@ -239,11 +233,8 @@ async function onFormOptionsChanged(e) {  }  async function onReady() { -    const optionsContext = getOptionsContext(); -    const options = await apiOptionsGet(optionsContext); -      formSetupEventListeners(); -    await formWrite(options); +    await profileOptionsSetup();      storageInfoInitialize(); |