123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- <template>
- <Window ref="window" width="600px" height="95%" @close="close">
- <template #header>
- Настроить закладки
- </template>
- <div class="col column fit">
- <div class="row items-center top-panel bg-grey-3">
- <q-btn :disabled="!selected" class="q-mr-md" round dense color="blue" icon="la la-check" size="16px" @click.stop="openSelected">
- <q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
- Открыть выбранную закладку
- </q-tooltip>
- </q-btn>
- <q-input ref="search" v-model="search" class="col" outlined dense bg-color="white" placeholder="Найти">
- <template #append>
- <q-icon v-if="search !== ''" name="la la-times" class="cursor-pointer" @click="resetSearch" />
- </template>
- </q-input>
- </div>
- <div class="col row">
- <div class="left-panel column items-center no-wrap bg-grey-3">
- <q-btn class="q-my-sm" round dense color="blue" icon="la la-plus" size="14px" @click.stop="addBookmark">
- <q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
- Добавить закладку
- </q-tooltip>
- </q-btn>
- <q-btn :disabled="!ticked.length" class="q-mb-sm" round dense color="blue" icon="la la-minus" size="14px" @click.stop="delBookmark">
- <q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
- Удалить отмеченные закладки
- </q-tooltip>
- </q-btn>
- <q-btn :disabled="!selected || selected.indexOf('r-') == 0" class="q-mb-sm" round dense color="blue" icon="la la-edit" size="14px" @click.stop="editBookmark">
- <q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
- Редактировать закладку
- </q-tooltip>
- </q-btn>
- <q-btn :disabled="!ticked.length" class="q-mb-sm" round dense color="blue" icon="la la-arrow-up" size="14px" @click.stop="moveBookmark(false)">
- <q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
- Переместить отмеченные вверх
- </q-tooltip>
- </q-btn>
- <q-btn :disabled="!ticked.length" class="q-mb-sm" round dense color="blue" icon="la la-arrow-down" size="14px" @click.stop="moveBookmark(true)">
- <q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
- Переместить отмеченные вниз
- </q-tooltip>
- </q-btn>
- <q-btn class="q-mb-sm" round dense color="blue" icon="la la-broom" size="14px" @click.stop="setDefaultBookmarks">
- <q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
- Установить по умолчанию
- </q-tooltip>
- </q-btn>
- <div class="space" />
- </div>
- <div class="col fit tree">
- <div v-show="nodes.length" class="checkbox-tick-all">
- <q-checkbox v-model="tickAll" size="36px" label="Выбрать все" @update:model-value="makeTickAll" />
- </div>
- <q-tree
- v-model:selected="selected"
- v-model:ticked="ticked"
- v-model:expanded="expanded"
- class="q-my-xs"
- :nodes="nodes"
- node-key="key"
- tick-strategy="leaf"
- selected-color="black"
- :filter="search"
- no-nodes-label="Закладок пока нет"
- no-results-label="Ничего не найдено"
- >
- <template #default-header="p">
- <div class="q-px-xs" :class="{selected: selected == p.key}">
- {{ p.node.label }}
- </div>
- </template>
- </q-tree>
- </div>
- </div>
- </div>
- </Window>
- </template>
- <script>
- //-----------------------------------------------------------------------------
- import vueComponent from '../../vueComponent.js';
- import _ from 'lodash';
- import Window from '../../share/Window.vue';
- import * as lu from '../linkUtils';
- import rstore from '../../../store/modules/reader';
- const componentOptions = {
- components: {
- Window,
- },
- watch: {
- ticked() {
- this.checkAllTicked();
- },
- }
- };
- class BookmarkSettings {
- _options = componentOptions;
- _props = {
- libs: Object,
- addBookmarkVisible: Boolean,
- };
- search = '';
- selected = '';
- ticked = [];
- expanded = [];
- tickAll = false;
- created() {
- this.afterInit = true;
- }
- mounted() {
- }
- init() {
- this.$refs.window.init();
- }
- get nodes() {
- const result = [];
- const expanded = [];
- this.links = {};
- this.libs.groups.forEach(group => {
- const rkey = `r-${group.r}`;
- const g = {label: group.r, key: rkey, children: []};
- this.links[rkey] = {l: group.r, c: ''};
- group.list.forEach(link => {
- const key = link.l;
- g.children.push({
- label: (link.c ? link.c + ' ': '') + lu.removeOrigin(link.l),
- key
- });
- this.links[key] = link;
- if (link.l == this.libs.startLink && expanded.indexOf(rkey) < 0) {
- expanded.push(rkey);
- }
- });
- result.push(g);
- });
- if (this.afterInit) {
- this.$nextTick(() => {
- this.expanded = expanded;
- });
- this.afterInit = false;
- }
- return result;
- }
- makeTickAll() {
- if (this.tickAll) {
- const newTicked = [];
- for (const key of Object.keys(this.links)) {
- if (key.indexOf('r-') != 0)
- newTicked.push(key);
- }
- this.ticked = newTicked;
- } else {
- this.ticked = [];
- }
- }
- checkAllTicked() {
- const ticked = new Set(this.ticked);
- let newTickAll = !!(this.nodes.length);
- for (const key of Object.keys(this.links)) {
- if (key.indexOf('r-') != 0 && !ticked.has(key))
- newTickAll = false;
- }
- this.tickAll = newTickAll;
- }
- resetSearch() {
- this.search = '';
- this.$refs.search.focus();
- }
- openSelected() {
- if (!this.selected)
- return;
- if (this.selected.indexOf('r-') === 0) {//rootLink
- this.$emit('do-action', {action: 'setRootLink', data: this.links[this.selected].l});
- } else {//selectedLink
- this.$emit('do-action', {action: 'setSelectedLink', data: this.links[this.selected].l});
- }
- this.close();
- }
- editBookmark() {
- this.$emit('do-action', {action: 'editBookmark', data: {link: this.links[this.selected].l, desc: this.links[this.selected].c}});
- }
- addBookmark() {
- this.$emit('do-action', {action: 'addBookmark'});
- }
- async delBookmark() {
- const newLibs = _.cloneDeep(this.libs);
- if (await this.$root.stdDialog.confirm(`Подтвердите удаление ${this.ticked.length} закладок:`, ' ')) {
- const ticked = new Set(this.ticked);
- for (let i = newLibs.groups.length - 1; i >= 0; i--) {
- const g = newLibs.groups[i];
- for (let j = g.list.length - 1; j >= 0; j--) {
- if (ticked.has(g.list[j].l)) {
- delete g.list[j];
- }
- }
- g.list = g.list.filter(v => v);
- if (!g.list.length)
- delete newLibs.groups[i];
- else {
- const item = lu.getListItemByLink(g.list, g.s);
- if (!item)
- g.s = g.list[0].l;
- }
- }
- newLibs.groups = newLibs.groups.filter(v => v);
- this.ticked = [];
- this.selected = '';
- this.$emit('do-action', {action: 'setLibs', data: newLibs});
- }
- }
- moveBookmark(down = false) {
- const newLibs = _.cloneDeep(this.libs);
- const ticked = new Set(this.ticked);
- let moved = false;
- let prevFull = false;
- if (!down) {
- for (let i = 0; i < newLibs.groups.length; i++) {
- const g = newLibs.groups[i];
- let count = 0;
- for (let j = 0; j < g.list.length; j++) {
- if (ticked.has(g.list[j].l)) {
- if (j > 0 && !ticked.has(g.list[j - 1].l)) {
- [g.list[j], g.list[j - 1]] = [g.list[j - 1], g.list[j]];
- moved = true;
- }
- count++;
- }
- }
- if (count == g.list.length && !prevFull && i > 0) {
- const gs = newLibs.groups;
- [gs[i], gs[i - 1]] = [gs[i - 1], gs[i]];
- moved = true;
- } else
- prevFull = (count == g.list.length);
- }
- } else {
- for (let i = newLibs.groups.length - 1; i >= 0; i--) {
- const g = newLibs.groups[i];
- let count = 0;
- for (let j = g.list.length - 1; j >= 0; j--) {
- if (ticked.has(g.list[j].l)) {
- if (j < g.list.length - 1 && !ticked.has(g.list[j + 1].l)) {
- [g.list[j], g.list[j + 1]] = [g.list[j + 1], g.list[j]];
- moved = true;
- }
- count++;
- }
- }
- if (count == g.list.length && !prevFull && i < newLibs.groups.length - 1) {
- const gs = newLibs.groups;
- [gs[i], gs[i + 1]] = [gs[i + 1], gs[i]];
- moved = true;
- } else
- prevFull = (count == g.list.length);
- }
- }
- if (moved)
- this.$emit('do-action', {action: 'setLibs', data: newLibs});
- }
- async setDefaultBookmarks() {
- const result = await this.$root.stdDialog.prompt(`Введите 'да' для сброса всех закладок в предустановленные значения:`, ' ', {
- inputValidator: (str) => { if (str && str.toLowerCase() === 'да') return true; else return 'Удаление не подтверждено'; },
- });
- if (result && result.value && result.value.toLowerCase() == 'да') {
- this.$emit('do-action', {action: 'setLibs', data: _.cloneDeep(
- Object.assign({helpShowed: true}, rstore.libsDefaults)
- )});
- }
- }
- close() {
- this.afterInit = false;
- this.$emit('close');
- }
- keyHook(event) {
- if (this.addBookmarkVisible)
- return false;
- if (event.type == 'keydown' && event.key == 'Escape') {
- this.close();
- return true;
- }
- return false;
- }
- }
- export default vueComponent(BookmarkSettings);
- //-----------------------------------------------------------------------------
- </script>
- <style scoped>
- .top-panel {
- height: 50px;
- border-bottom: 1px solid gray;
- padding: 0 10px 0 12px;
- }
- .left-panel {
- width: 60px;
- height: 100%;
- border-right: 1px solid gray;
- overflow-x: hidden;
- overflow-y: auto;
- }
- .tree {
- padding: 0px 10px 10px 10px;
- overflow-x: auto;
- overflow-y: auto;
- max-width: 520px;
- }
- .selected {
- text-shadow: 0 0 20px yellow, 0 0 15px yellow, 0 0 10px yellow, 0 0 10px yellow, 0 0 5px yellow;
- }
- .checkbox-tick-all {
- border-bottom: 1px solid #bbbbbb;
- margin-bottom: 7px;
- padding: 5px 5px 2px 16px;
- }
- .space {
- min-height: 1px;
- width: 1px;
- }
- </style>
|