Skip to content

Commit

Permalink
Changed: Container config: Tab reopening rules instead of raw strings
Browse files Browse the repository at this point in the history
  • Loading branch information
mbnuqw committed Feb 18, 2023
1 parent d3d1128 commit fea076d
Show file tree
Hide file tree
Showing 22 changed files with 808 additions and 134 deletions.
59 changes: 56 additions & 3 deletions src/_locales/dict.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,8 @@ export const commonTranslations: Translations = {
},

'popup.tab_move_rules.title': {
en: 'Moving rules',
ru: 'Правила перемещения',
en: 'Tab moving rules',
ru: 'Правила перемещения вкладок',
},
'popup.tab_move_rules.editor_title.new': {
en: 'Create a move rule',
Expand All @@ -288,7 +288,7 @@ export const commonTranslations: Translations = {
},
'popup.tab_move_rules.rule_url_label': {
en: 'If tab has URL ("substring" or "/RegExp/")',
ru: 'Если вкладка с URL-адресом ("подстрока" или "/RegExp/")',
ru: 'Если вкладка имеет URL-адрес ("подстрока" или "/RegExp/")',
},
'popup.tab_move_rules.rule_top_lvl_label': {
en: 'If tab at the top level of tree',
Expand All @@ -307,6 +307,59 @@ export const commonTranslations: Translations = {
ru: 'Отмена',
},

'popup.tab_reopen_rules.title': {
en: 'Tab reopening rules',
ru: 'Правила',
},
'popup.tab_reopen_rules.enable_label': {
en: 'Enable listed rules',
ru: 'Включить перечисленные правила',
},
'popup.tab_reopen_rules.editor_title.new': {
en: 'Create new rule',
ru: 'Создать правило',
},
'popup.tab_reopen_rules.editor_title.edit': {
en: 'Edit rule',
ru: 'Редактировать правило',
},
'popup.tab_reopen_rules.rule_type_label': {
en: 'Type of the rule',
ru: 'Тип правила',
},
'popup.tab_reopen_rules.rule_type_include': {
en: 'Include rule',
ru: 'Правило включения',
},
'popup.tab_reopen_rules.rule_type_exclude': {
en: 'Exclude rule',
ru: 'Правило исключения',
},
'popup.tab_reopen_rules.rule_url_label': {
en: 'If tab has URL ("substring" or "/RegExp/")',
ru: 'Если вкладка имеет URL-адрес ("подстрока" или "/RegExp/")',
},
'popup.tab_reopen_rules.rule_suffix_include': {
en: n => `...reopen it in "${n}" container`,
ru: n => `...открыть ee в контейнере "${n}"`,
},
'popup.tab_reopen_rules.rule_suffix_exclude': {
en: n => `...and it is in "${n}" container, reopen it in default container.`,
ru: n => `...и она находится в контейнере "${n}", открыть ее в контейнере по умолчанию.`,
},
'popup.tab_reopen_rules.add_rule_btn': {
en: 'Add rule',
ru: 'Добавить правило',
},
'popup.tab_reopen_rules.edit_rule_btn.save': {
en: 'Save',
ru: 'Сохранить',
},
'popup.tab_reopen_rules.edit_rule_btn.cancel': {
en: 'Cancel',
ru: 'Отмена',
},

// ---
// -- Context menu
// -
Expand Down
8 changes: 8 additions & 0 deletions src/_locales/dict.setup-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ export const setupPageTranslations: Translations = {
de: 'Farbe',
zh_CN: '颜色',
},
'container.reopen_rules_label': {
en: 'Include / Exclude tab by URL',
ru: 'Включить / исключить вкладку по URL',
},
'container.manage_reopen_rules_label': {
en: 'Manage rules',
ru: 'Управление правилами',
},
'container.proxy_label': {
en: 'Proxy',
ru: 'Прокси',
Expand Down
1 change: 1 addition & 0 deletions src/assets/ctr-exclude.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/ctr-include.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion src/bg/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ async function upgrade(): Promise<void> {
}

// Moving data
if (stored.containers_v4) newStorage.containers = stored.containers_v4
if (stored.containers_v4) {
newStorage.containers = Containers.upgradeV4Containers(stored.containers_v4)
}
upgradeTabsDataCache(stored, newStorage)
upgrading.init = 'done'

Expand Down
279 changes: 279 additions & 0 deletions src/components/popup.tab-reopen-rules.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
<template lang="pug">
.TabReopenRulesPopup.popup-container(@mousedown.stop.self="onCancel" @mouseup.stop)
.popup(v-if="Sidebar.reactive.tabReopenRulesPopup")
h2(v-if="rules.length") {{translate('popup.tab_reopen_rules.title')}}
.rules(v-if="rules.length" :data-active="Sidebar.reactive.tabReopenRulesPopup.container.reopenRulesActive")
.rule(
v-for="rule of rules"
:key="rule.id"
:data-active="rule.active"
:data-edit="rule.id === editing"
:data-type="rule.type"
:data-color="rule.type === 'include' ? 'green' : 'red'"
@click="editRule(rule)")
.url-box
.icon-box
svg.icon: use(:xlink:href="rule.type === 'include' ? '#icon_ctr_include' : '#icon_ctr_exclude'")
.url {{rule.url}}
.controls-box(v-if="!editing")
.btn-up(@click.stop="shortcutUp(rule)"): svg: use(xlink:href="#icon_expand")
.btn-down(@click.stop="shortcutDown(rule)"): svg: use(xlink:href="#icon_expand")
.btn-rm(@click.stop="removeRule(rule)"): svg: use(xlink:href="#icon_remove")
ToggleField.-compact(
v-if="rules.length"
label="popup.tab_reopen_rules.enable_label"
:value="Sidebar.reactive.tabReopenRulesPopup.container.reopenRulesActive"
@update:value="toggleEnableRules")
.space
h2 {{editing ? translate('popup.tab_reopen_rules.editor_title.edit') : translate('popup.tab_reopen_rules.editor_title.new')}}
.type-selector
.type-opt(
data-color="green"
:data-active="newRuleType === 'include'"
@click="newRuleType = 'include'")
svg.icon: use(xlink:href="#icon_ctr_include")
.label {{translate('popup.tab_reopen_rules.rule_type_include')}}
.type-opt(
data-color="red"
:data-active="newRuleType === 'exclude'"
@click="newRuleType = 'exclude'")
svg.icon: use(xlink:href="#icon_ctr_exclude")
.label {{translate('popup.tab_reopen_rules.rule_type_exclude')}}
TextField.-no-separator.-compact(
label="popup.tab_reopen_rules.rule_url_label"
v-model:value="newRuleURL"
:or="'URL...'"
:line="true")

.note(v-if="newRuleType === 'include'").
{{translate('popup.tab_reopen_rules.rule_suffix_include', Sidebar.reactive.tabReopenRulesPopup.container.name)}}
.note(v-else).
{{translate('popup.tab_reopen_rules.rule_suffix_exclude', Sidebar.reactive.tabReopenRulesPopup.container.name)}}

.ctrls(v-if="editing")
.btn(:class="{ '-inactive': !addBtnActive }" @click="onSave").
{{translate('popup.tab_reopen_rules.edit_rule_btn.save')}}
.btn(@click="onEditCancel").
{{translate('popup.tab_reopen_rules.edit_rule_btn.cancel')}}
.ctrls(v-else)
.btn.-wide(:class="{ '-inactive': !addBtnActive }" @click="onAdd").
{{translate('popup.tab_reopen_rules.add_rule_btn')}}
</template>

<script lang="ts" setup>
import { ref, computed, onMounted } from 'vue'
import { translate } from 'src/dict'
import { TabReopenRuleConfig, TabReopenRuleType } from 'src/types'
import { Sidebar } from 'src/services/sidebar'
import { Containers } from 'src/services/containers'
import * as Utils from 'src/utils'
import TextField from './text-field.vue'
import ToggleField from './toggle-field.vue'
import { Permissions } from 'src/services/permissions'
interface ReopenRulePreview {
id: ID
type: 'include' | 'exclude'
active: boolean
url: string
urlIcon?: string
}
const rules = ref<ReopenRulePreview[]>([])
const newRuleType = ref<'include' | 'exclude'>('include')
const newRuleURL = ref('')
const editing = ref<ID | null>(null)
const addBtnActive = computed<boolean>(() => {
return !!newRuleURL.value
})
onMounted(() => {
initPopupState()
})
function initPopupState() {
if (!Sidebar.reactive.tabReopenRulesPopup) return []
const output: ReopenRulePreview[] = []
const ruleConfigs = Sidebar.reactive.tabReopenRulesPopup.container.reopenRules
for (const conf of ruleConfigs) {
output.push(createRulePreview(conf))
}
rules.value = output
}
function createRulePreview(ruleConfig: TabReopenRuleConfig): ReopenRulePreview {
const rule: ReopenRulePreview = {
id: ruleConfig.id,
type: ruleConfig.type === TabReopenRuleType.Include ? 'include' : 'exclude',
url: ruleConfig.url,
active: ruleConfig.active,
}
if (ruleConfig.url) {
rule.url = ruleConfig.url
rule.urlIcon = '#icon_ff'
}
return rule
}
async function onAdd() {
if (!Sidebar.reactive.tabReopenRulesPopup) return
if (!addBtnActive.value) return
if (!newRuleURL.value) return
const container = Sidebar.reactive.tabReopenRulesPopup.container
if (!Permissions.reactive.webData && !container.reopenRulesActive) {
const result = await Permissions.request('<all_urls>')
if (!result) return
}
// Add new rule to container config
const ruleConfig: TabReopenRuleConfig = {
id: Utils.uid(),
active: true,
type: newRuleType.value === 'include' ? TabReopenRuleType.Include : TabReopenRuleType.Exclude,
url: newRuleURL.value,
}
if (!container.reopenRules.length) container.reopenRulesActive = true
container.reopenRules.push(ruleConfig)
// Add new rule in local rules list
rules.value.push(createRulePreview(ruleConfig))
// Reset inputs
newRuleType.value = 'include'
newRuleURL.value = ''
Containers.saveContainers(1000)
}
function onCancel(): void {
if (!Sidebar.reactive.tabReopenRulesPopup) return
Sidebar.closeTabReopenRulesPopup()
}
function shortcutUp(rule: ReopenRulePreview): void {
if (!Sidebar.reactive.tabReopenRulesPopup) return
const container = Sidebar.reactive.tabReopenRulesPopup.container
const index = container.reopenRules.findIndex(r => r.id === rule.id)
if (index !== -1 && index > 0) {
const ruleConfig = container.reopenRules.splice(index, 1)[0]
if (ruleConfig) container.reopenRules.splice(index - 1, 0, ruleConfig)
}
const localIndex = rules.value.findIndex(r => r.id === rule.id)
if (localIndex !== -1 && localIndex > 0) {
rules.value.splice(localIndex, 1)
rules.value.splice(localIndex - 1, 0, rule)
}
Containers.saveContainers(1000)
}
function shortcutDown(rule: ReopenRulePreview): void {
if (!Sidebar.reactive.tabReopenRulesPopup) return
const container = Sidebar.reactive.tabReopenRulesPopup.container
const index = container.reopenRules.findIndex(r => r.id === rule.id)
if (index !== -1 && index < container.reopenRules.length - 1) {
const ruleConfig = container.reopenRules.splice(index, 1)[0]
if (ruleConfig) container.reopenRules.splice(index + 1, 0, ruleConfig)
}
const localIndex = rules.value.findIndex(r => r.id === rule.id)
if (localIndex !== -1 && localIndex < container.reopenRules.length - 1) {
rules.value.splice(localIndex, 1)
rules.value.splice(localIndex + 1, 0, rule)
}
Containers.saveContainers(1000)
}
function removeRule(rule: ReopenRulePreview): void {
if (!Sidebar.reactive.tabReopenRulesPopup) return
const container = Sidebar.reactive.tabReopenRulesPopup.container
// Remove rule from container config
const index = container.reopenRules.findIndex(r => r.id === rule.id)
if (index !== -1) container.reopenRules.splice(index, 1)
if (!container.reopenRules.length) container.reopenRulesActive = false
// Remove rule from local list
const localIndex = rules.value.findIndex(r => r.id === rule.id)
if (localIndex !== -1) rules.value.splice(localIndex, 1)
Containers.saveContainers(1000)
}
function editRule(rule: ReopenRulePreview) {
if (editing.value === rule.id) {
return onEditCancel()
}
editing.value = rule.id
if (rule.url) newRuleURL.value = rule.url
else newRuleURL.value = ''
newRuleType.value = rule.type
}
function onEditCancel() {
editing.value = null
// Reset inputs
newRuleURL.value = ''
newRuleType.value = 'include'
}
function onSave() {
if (!editing.value) return
if (!newRuleURL.value) return
if (!Sidebar.reactive.tabReopenRulesPopup) return
const container = Sidebar.reactive.tabReopenRulesPopup.container
const rule = rules.value.find(r => r.id === editing.value)
if (!rule) return
// Update rule in container config
const ruleConfig = container.reopenRules.find(r => r.id === rule.id)
if (ruleConfig) {
ruleConfig.active = true
ruleConfig.url = newRuleURL.value
const isIncludeRule = newRuleType.value === 'include'
ruleConfig.type = isIncludeRule ? TabReopenRuleType.Include : TabReopenRuleType.Exclude
Containers.saveContainers(1000)
}
// Update rule in local list
rule.url = newRuleURL.value
rule.type = newRuleType.value
rule.active = true
// Reset inputs
newRuleURL.value = ''
newRuleType.value = 'include'
editing.value = null
}
async function toggleEnableRules() {
const container = Sidebar.reactive.tabReopenRulesPopup?.container
if (!container) return
if (!Permissions.reactive.webData && !container.reopenRulesActive) {
const result = await Permissions.request('<all_urls>')
if (!result) return
}
container.reopenRulesActive = !container.reopenRulesActive
Containers.saveContainers(1000)
}
</script>
Loading

0 comments on commit fea076d

Please sign in to comment.