vgapp 1.5.6 → 1.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/langs/en/buttons.json +17 -17
- package/app/langs/en/messages.json +36 -36
- package/app/langs/ru/buttons.json +17 -17
- package/app/langs/ru/messages.json +1 -1
- package/app/modules/vgalert/js/vgalert.js +6 -3
- package/app/modules/vgalert/scss/_variables.scss +16 -16
- package/app/modules/vgcollapse/scss/_variables.scss +7 -7
- package/app/modules/vgcollapse/scss/vgcollapse.scss +5 -5
- package/app/modules/vgdropdown/scss/_variables.scss +14 -14
- package/app/modules/vgdropdown/scss/vgdropdown.scss +5 -5
- package/app/modules/vgfilepreview/js/i18n.js +56 -56
- package/app/modules/vgfilepreview/js/renderers/image-modal.js +145 -145
- package/app/modules/vgfilepreview/js/renderers/image.js +92 -92
- package/app/modules/vgfilepreview/js/renderers/index.js +19 -19
- package/app/modules/vgfilepreview/js/renderers/office-modal.js +168 -168
- package/app/modules/vgfilepreview/js/renderers/office.js +79 -79
- package/app/modules/vgfilepreview/js/renderers/pdf-modal.js +260 -260
- package/app/modules/vgfilepreview/js/renderers/pdf.js +76 -76
- package/app/modules/vgfilepreview/js/renderers/playlist.js +71 -71
- package/app/modules/vgfilepreview/js/renderers/text-modal.js +343 -343
- package/app/modules/vgfilepreview/js/renderers/text.js +83 -83
- package/app/modules/vgfilepreview/js/renderers/zip-modal.js +522 -522
- package/app/modules/vgfilepreview/js/renderers/zip.js +89 -89
- package/app/modules/vgfilepreview/readme.md +68 -68
- package/app/modules/vgfiles/js/base.js +189 -194
- package/app/modules/vgfiles/js/droppable.js +17 -17
- package/app/modules/vgfiles/js/render.js +153 -153
- package/app/modules/vgfiles/js/sortable.js +52 -52
- package/app/modules/vgfiles/js/vgfiles.js +43 -43
- package/app/modules/vgfiles/readme.md +123 -123
- package/app/modules/vgfiles/scss/_mixins.scss +13 -13
- package/app/modules/vgfiles/scss/_variables.scss +10 -10
- package/app/modules/vgfiles/scss/vgfiles.scss +28 -28
- package/app/modules/vgformsender/js/hideshowpass.js +22 -22
- package/app/modules/vgformsender/readme.md +1 -1
- package/app/modules/vgformsender/scss/_variables.scss +5 -5
- package/app/modules/vgformsender/scss/vgformsender.scss +42 -42
- package/app/modules/vglawcookie/js/vglawcookie.js +19 -19
- package/app/modules/vglawcookie/scss/_variables.scss +13 -13
- package/app/modules/vglawcookie/scss/vglawcookie.scss +5 -5
- package/app/modules/vgmodal/js/vgmodal.interaction.js +216 -216
- package/app/modules/vgmodal/js/vgmodal.js +6 -0
- package/app/modules/vgmodal/js/vgmodal.minimized.js +227 -227
- package/app/modules/vgmodal/scss/_variables.scss +17 -17
- package/app/modules/vgmodal/scss/vgmodal.scss +77 -77
- package/app/modules/vgnav/js/vgnav.js +62 -62
- package/app/modules/vgnav/scss/_breakpoints.scss +36 -36
- package/app/modules/vgnav/scss/_hamburger.scss +5 -5
- package/app/modules/vgnav/scss/_placement.scss +5 -5
- package/app/modules/vgnav/scss/_toggle.scss +5 -5
- package/app/modules/vgnav/scss/_variables.scss +26 -26
- package/app/modules/vgnav/scss/vgnav.scss +41 -41
- package/app/modules/vgnestable/README.md +39 -39
- package/app/modules/vgrangeslider/js/skins.js +8 -8
- package/app/modules/vgrangeslider/js/vgrangeslider.js +29 -29
- package/app/modules/vgrangeslider/scss/_variables.scss +55 -55
- package/app/modules/vgrangeslider/scss/vgrangeslider.scss +239 -239
- package/app/modules/vgrollup/js/vgrollup.js +15 -15
- package/app/modules/vgrollup/scss/_variables.scss +15 -15
- package/app/modules/vgrollup/scss/vgrollup.scss +6 -6
- package/app/modules/vgselect/js/handlers.js +5 -52
- package/app/modules/vgselect/js/vgselect.js +128 -40
- package/app/modules/vgselect/readme.md +11 -11
- package/app/modules/vgselect/scss/_variables.scss +51 -51
- package/app/modules/vgselect/scss/vgselect.scss +1 -1
- package/app/modules/vgsidebar/js/vgsidebar.js +16 -5
- package/app/modules/vgsidebar/scss/_variables.scss +10 -10
- package/app/modules/vgsidebar/scss/vgsidebar.scss +5 -5
- package/app/modules/vgspy/js/vgspy.js +28 -7
- package/app/modules/vgtable/js/_filters.js +10 -6
- package/app/modules/vgtable/js/_options.js +16 -16
- package/app/modules/vgtable/js/_pagination.js +118 -118
- package/app/modules/vgtable/js/_responsive.js +79 -79
- package/app/modules/vgtable/js/_sticky-header.js +349 -280
- package/app/modules/vgtable/js/vgtable.js +98 -98
- package/app/modules/vgtable/scss/_sorting.scss +6 -6
- package/app/modules/vgtable/scss/_sticky-header.scss +31 -31
- package/app/modules/vgtable/scss/_variables.scss +6 -4
- package/app/modules/vgtable/scss/vgtable.scss +8 -4
- package/app/modules/vgtabs/js/vgtabs.js +82 -57
- package/app/modules/vgtabs/scss/_variables.scss +23 -23
- package/app/modules/vgtabs/scss/vgtabs.scss +5 -5
- package/app/modules/vgtoast/js/vgtoast.js +11 -5
- package/app/modules/vgtoast/scss/_variables.scss +13 -13
- package/app/modules/vgtoast/scss/vgtoast.scss +5 -5
- package/app/modules/vgtooltip/js/vgtooltip.js +121 -111
- package/app/modules/vgtooltip/scss/_variables.scss +10 -10
- package/app/modules/vgtooltip/scss/vgtooltip.scss +5 -5
- package/app/utils/js/components/audio-metadata.js +240 -240
- package/app/utils/js/components/backdrop.js +116 -116
- package/app/utils/js/components/file-icon.js +5 -0
- package/app/utils/js/components/file-preview.js +304 -304
- package/app/utils/js/components/responsive.js +165 -165
- package/app/utils/js/components/sanitize.js +150 -150
- package/app/utils/js/components/video-metadata.js +140 -140
- package/app/utils/scss/_backdrop.scss +5 -5
- package/app/utils/scss/_theme-default.scss +12 -12
- package/app/utils/scss/_theme.scss +7 -7
- package/app/utils/scss/default.scss +9 -9
- package/app/utils/scss/functions.scss +21 -21
- package/app/utils/scss/index.scss +4 -4
- package/app/utils/scss/mixin.scss +16 -16
- package/app/utils/scss/variables.scss +147 -147
- package/build/vgapp.css +1 -1
- package/build/vgapp.css.map +1 -1
- package/build/vgapp.js +1 -1
- package/build/vgapp.js.map +1 -1
- package/index.js +7 -7
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
@use "../../../utils/scss" as vg;
|
|
2
|
-
|
|
3
|
-
$sidebar-map: (
|
|
1
|
+
@use "../../../utils/scss" as vg;
|
|
2
|
+
|
|
3
|
+
$sidebar-map: (
|
|
4
4
|
horizontal: (
|
|
5
5
|
width: 400px,
|
|
6
6
|
height: 100vh,
|
|
@@ -9,13 +9,13 @@ $sidebar-map: (
|
|
|
9
9
|
width: 100vw,
|
|
10
10
|
height: 30vh,
|
|
11
11
|
),
|
|
12
|
-
bg-color: var(--vg-surface-bg, #{vg.$surface-bg}),
|
|
13
|
-
color: var(--vg-text-color, #{vg.$color}),
|
|
14
|
-
box-shadow: var(--vg-box-shadow, #{vg.$box-shadow}),
|
|
12
|
+
bg-color: var(--vg-surface-bg, #{vg.$surface-bg}),
|
|
13
|
+
color: var(--vg-text-color, #{vg.$color}),
|
|
14
|
+
box-shadow: var(--vg-box-shadow, #{vg.$box-shadow}),
|
|
15
15
|
header-height: 60px,
|
|
16
16
|
footer-height: 70px,
|
|
17
17
|
padding: 1rem,
|
|
18
|
-
border: vg.$border-width vg.$border-style var(--vg-border-color, #{vg.$border-color}),
|
|
19
|
-
z-index: vg.$sidebar-index,
|
|
20
|
-
transition: vg.$transition-base,
|
|
21
|
-
) !default;
|
|
18
|
+
border: vg.$border-width vg.$border-style var(--vg-border-color, #{vg.$border-color}),
|
|
19
|
+
z-index: vg.$sidebar-index,
|
|
20
|
+
transition: vg.$transition-base,
|
|
21
|
+
) !default;
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
*--------------------------------------------------------------------------
|
|
7
7
|
**/
|
|
8
8
|
|
|
9
|
-
@forward "variables";
|
|
10
|
-
@use "../../../utils/scss" as vg;
|
|
11
|
-
@use "variables" as vars;
|
|
9
|
+
@forward "variables";
|
|
10
|
+
@use "../../../utils/scss" as vg;
|
|
11
|
+
@use "variables" as vars;
|
|
12
12
|
|
|
13
13
|
.vg-sidebar {
|
|
14
|
-
@include vg.mix-vars('sidebar', vars.$sidebar-map);
|
|
14
|
+
@include vg.mix-vars('sidebar', vars.$sidebar-map);
|
|
15
15
|
position: fixed;
|
|
16
16
|
width: auto;
|
|
17
17
|
height: auto;
|
|
@@ -90,4 +90,4 @@
|
|
|
90
90
|
padding: var(--vg-sidebar-padding);
|
|
91
91
|
border-top: var(--vg-sidebar-border);
|
|
92
92
|
}
|
|
93
|
-
}
|
|
93
|
+
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Описание: отслеживание активных секций и навигация по якорям.
|
|
3
|
+
* Возможности: Data API, нативная и виртуальная прокрутка, вложенные меню и обновление секций.
|
|
4
|
+
*/
|
|
1
5
|
import BaseModule from "../../base-module";
|
|
2
|
-
import {
|
|
6
|
+
import { getElement, isDisabled, isVisible, normalizeData } from "../../../utils/js/functions";
|
|
3
7
|
import EventHandler from "../../../utils/js/dom/event";
|
|
4
8
|
import Selectors from "../../../utils/js/dom/selectors";
|
|
5
9
|
|
|
@@ -52,7 +56,7 @@ class VGSpy extends BaseModule {
|
|
|
52
56
|
* @property {number[]|string} threshold - пороги видимости (0.1, 0.5, 1)
|
|
53
57
|
*/
|
|
54
58
|
this._params = this._configAfterMerge(
|
|
55
|
-
|
|
59
|
+
Object.assign(
|
|
56
60
|
{
|
|
57
61
|
offset: null, // Устаревшее, для обратной совместимости
|
|
58
62
|
rootMargin: '0px 0px -25%',
|
|
@@ -60,7 +64,8 @@ class VGSpy extends BaseModule {
|
|
|
60
64
|
target: this._element,
|
|
61
65
|
threshold: [0.1, 0.5, 1],
|
|
62
66
|
},
|
|
63
|
-
params
|
|
67
|
+
params,
|
|
68
|
+
this._getDataOptions()
|
|
64
69
|
)
|
|
65
70
|
);
|
|
66
71
|
|
|
@@ -134,10 +139,22 @@ class VGSpy extends BaseModule {
|
|
|
134
139
|
return NAME_KEY;
|
|
135
140
|
}
|
|
136
141
|
|
|
142
|
+
_getDataOptions() {
|
|
143
|
+
const options = {};
|
|
144
|
+
for (const name of ['target', 'offset', 'rootMargin', 'smoothScroll', 'threshold']) {
|
|
145
|
+
const attribute = `data-${name.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`)}`;
|
|
146
|
+
if (this._element.hasAttribute(attribute)) {
|
|
147
|
+
options[name] = normalizeData(this._element.getAttribute(attribute));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return options;
|
|
151
|
+
}
|
|
152
|
+
|
|
137
153
|
/**
|
|
138
154
|
* Инициализирует или перезапускает модуль: находит ссылки и секции, создаёт observer
|
|
139
155
|
*/
|
|
140
156
|
refresh() {
|
|
157
|
+
this._process(null);
|
|
141
158
|
this._initializeTargetsAndObservables();
|
|
142
159
|
this._updateRootElement();
|
|
143
160
|
this._maybeEnableSmoothScroll();
|
|
@@ -164,7 +181,7 @@ class VGSpy extends BaseModule {
|
|
|
164
181
|
// Smooth Scrollbar can be initialized after the spy; retry once on the next tick.
|
|
165
182
|
if (this._rootElement && !this._isScrollableSelf(this._rootElement) && window.Scrollbar) {
|
|
166
183
|
setTimeout(() => {
|
|
167
|
-
if (this._scrollbar) return;
|
|
184
|
+
if (!this._element || this._scrollbar) return;
|
|
168
185
|
this._updateSmoothScrollbar();
|
|
169
186
|
if (this._scrollbar) this._setupScrollbarTracking();
|
|
170
187
|
}, 0);
|
|
@@ -357,6 +374,8 @@ class VGSpy extends BaseModule {
|
|
|
357
374
|
}
|
|
358
375
|
|
|
359
376
|
dispose() {
|
|
377
|
+
if (!this._element) return;
|
|
378
|
+
this._process(null);
|
|
360
379
|
if (this._observer) {
|
|
361
380
|
this._observer.disconnect();
|
|
362
381
|
}
|
|
@@ -416,6 +435,7 @@ class VGSpy extends BaseModule {
|
|
|
416
435
|
// don't hijack the click; allow UI to reveal it, then retry.
|
|
417
436
|
if (!isVisible(section)) {
|
|
418
437
|
setTimeout(() => {
|
|
438
|
+
if (!this._element) return;
|
|
419
439
|
const revealed = Selectors.findID(id);
|
|
420
440
|
if (!revealed || !isVisible(revealed)) return;
|
|
421
441
|
|
|
@@ -507,7 +527,7 @@ class VGSpy extends BaseModule {
|
|
|
507
527
|
|
|
508
528
|
for (const entry of entries) {
|
|
509
529
|
if (!entry.isIntersecting) {
|
|
510
|
-
|
|
530
|
+
if (getTargetLink(entry) === this._activeTarget) this._process(null);
|
|
511
531
|
continue;
|
|
512
532
|
}
|
|
513
533
|
|
|
@@ -516,7 +536,7 @@ class VGSpy extends BaseModule {
|
|
|
516
536
|
const shouldActivate =
|
|
517
537
|
(userScrollsDown && isEntryBelow) || (!userScrollsDown && !isEntryBelow);
|
|
518
538
|
|
|
519
|
-
if (shouldActivate) {
|
|
539
|
+
if (shouldActivate || !this._activeTarget) {
|
|
520
540
|
this._previousScrollData.visibleEntryTop = entryTop;
|
|
521
541
|
this._process(getTargetLink(entry));
|
|
522
542
|
}
|
|
@@ -595,7 +615,7 @@ class VGSpy extends BaseModule {
|
|
|
595
615
|
parent.classList.remove(CLASS_NAME_ACTIVE);
|
|
596
616
|
|
|
597
617
|
const activeLinks = Selectors.findAll(
|
|
598
|
-
`[href].${CLASS_NAME_ACTIVE}, [data-vg-target].${CLASS_NAME_ACTIVE}`,
|
|
618
|
+
`[href].${CLASS_NAME_ACTIVE}, [data-vg-target].${CLASS_NAME_ACTIVE}, ${SELECTOR_DROPDOWN_TOGGLE}.${CLASS_NAME_ACTIVE}`,
|
|
599
619
|
parent
|
|
600
620
|
);
|
|
601
621
|
for (const link of activeLinks) {
|
|
@@ -605,6 +625,7 @@ class VGSpy extends BaseModule {
|
|
|
605
625
|
|
|
606
626
|
_getTargetIdFromTrigger(trigger) {
|
|
607
627
|
if (!trigger || typeof trigger.getAttribute !== 'function') return null;
|
|
628
|
+
if (isDisabled(trigger) || trigger.matches(SELECTOR_DROPDOWN_TOGGLE)) return null;
|
|
608
629
|
|
|
609
630
|
const dataTarget = (trigger.getAttribute('data-vg-target') || '').trim();
|
|
610
631
|
const href = (trigger.getAttribute('href') || '').trim();
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Описание: форма локальных и remote-фильтров VGTable.
|
|
3
3
|
* Возможности: auto/manual применение, debounce, операторы, reset и публичное состояние.
|
|
4
4
|
*/
|
|
5
|
-
import EventHandler from "../../../utils/js/dom/event";
|
|
5
|
+
import EventHandler from "../../../utils/js/dom/event";
|
|
6
|
+
import VGSelect from "../../vgselect/js/vgselect";
|
|
6
7
|
|
|
7
8
|
const EVENT_CHANGE = 'filterschange.vg.table';
|
|
8
9
|
|
|
@@ -112,11 +113,14 @@ class _filters {
|
|
|
112
113
|
return this.getState();
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
reset(options = {}) {
|
|
116
|
-
this._controls.forEach((control) =>
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
reset(options = {}) {
|
|
117
|
+
this._controls.forEach((control) => {
|
|
118
|
+
this._resetControl(control);
|
|
119
|
+
if (control.tagName === 'SELECT') VGSelect.updateUI(control);
|
|
120
|
+
});
|
|
121
|
+
if (options.emit !== false) this._emit(String(options.source || 'reset'));
|
|
122
|
+
return this.getState();
|
|
123
|
+
}
|
|
120
124
|
|
|
121
125
|
_handleInput(event) {
|
|
122
126
|
if (!this._isControl(event.target) || this._isManual()) return;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Описание: константы и параметры по умолчанию базовой таблицы VGTable.
|
|
3
|
-
* Возможности: единая настройка Data API, i18n, wrapper, remote, фильтров, sticky, колонок, строк, выбора и адаптивной пагинации.
|
|
4
|
-
*/
|
|
3
|
+
* Возможности: единая настройка Data API, i18n, wrapper, remote, фильтров, sticky, колонок, строк, выбора и адаптивной пагинации.
|
|
4
|
+
*/
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Служебные константы модуля.
|
|
8
8
|
*/
|
|
9
9
|
// Имя компонента в публичном API. Варианты: фиксированное значение 'table'.
|
|
10
|
-
const NAME = 'table';
|
|
10
|
+
const NAME = 'table';
|
|
11
11
|
// Ключ экземпляра в Data API. Варианты: фиксированное значение 'vg.table'.
|
|
12
12
|
const NAME_KEY = `vg.${NAME}`;
|
|
13
13
|
// Селектор автоматической инициализации. Варианты: элементы с атрибутом data-vg-table.
|
|
@@ -21,16 +21,16 @@ const TABLE_CONTAINER_SELECTOR = '.vg-table-container';
|
|
|
21
21
|
// Маркер container, созданного компонентом. Варианты: пустой data-атрибут.
|
|
22
22
|
const GENERATED_TABLE_CONTAINER_ATTRIBUTE = 'data-vg-table-generated-container';
|
|
23
23
|
|
|
24
|
-
const DEFAULT_OPTIONS = {
|
|
25
|
-
/** Профили представления: базовые параметры + все достигнутые границы xs–xxl. */
|
|
26
|
-
responsive: {
|
|
27
|
-
// Включается явно; Data API: data-responsive-enabled.
|
|
28
|
-
enabled: false,
|
|
29
|
-
// Локальные переопределения границ общего Responsive; пустой объект сохраняет глобальные значения.
|
|
30
|
-
breakpoints: {},
|
|
31
|
-
// Профили принимают pagination: maxButtons, align, position, size.enabled/label, quick.enabled.
|
|
32
|
-
xs: {}, sm: {}, md: {}, lg: {}, xl: {}, xxl: {},
|
|
33
|
-
},
|
|
24
|
+
const DEFAULT_OPTIONS = {
|
|
25
|
+
/** Профили представления: базовые параметры + все достигнутые границы xs–xxl. */
|
|
26
|
+
responsive: {
|
|
27
|
+
// Включается явно; Data API: data-responsive-enabled.
|
|
28
|
+
enabled: false,
|
|
29
|
+
// Локальные переопределения границ общего Responsive; пустой объект сохраняет глобальные значения.
|
|
30
|
+
breakpoints: {},
|
|
31
|
+
// Профили принимают pagination: maxButtons, align, position, size.enabled/label, quick.enabled.
|
|
32
|
+
xs: {}, sm: {}, md: {}, lg: {}, xl: {}, xxl: {},
|
|
33
|
+
},
|
|
34
34
|
// Активная локаль встроенного интерфейса. Data API: data-locale. Варианты: 'ru' | 'en' | региональный BCP 47 код.
|
|
35
35
|
locale: 'ru',
|
|
36
36
|
// Пользовательские словари, объединяемые со встроенными ru/en. Data API отсутствует; варианты: объект {locale: {group: {key: value}}}.
|
|
@@ -368,9 +368,9 @@ const DEFAULT_OPTIONS = {
|
|
|
368
368
|
// Задаёт число страниц, после которого разрешены многоточие и quick='auto'. Варианты: целое число >= 1.
|
|
369
369
|
threshold: 5,
|
|
370
370
|
// Задаёт максимальное число соседних страниц между первой и последней. Варианты: целое число >= 1.
|
|
371
|
-
visible: 5,
|
|
372
|
-
// Лимит номеров и многоточий без prev/next; null сохраняет visible/threshold. Data API: data-pagination-max-buttons.
|
|
373
|
-
maxButtons: null,
|
|
371
|
+
visible: 5,
|
|
372
|
+
// Лимит номеров и многоточий без prev/next; null сохраняет visible/threshold. Data API: data-pagination-max-buttons.
|
|
373
|
+
maxButtons: null,
|
|
374
374
|
|
|
375
375
|
/** Поле и VGDropdown для выбора количества строк. */
|
|
376
376
|
size: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Описание: локальная и remote-пагинация строк базовой таблицы VGTable.
|
|
3
|
-
* Возможности: выбор страницы и размера, серверная meta, лимит кнопок, responsive-представление без запросов, многоточия, быстрый переход и сохранение.
|
|
3
|
+
* Возможности: выбор страницы и размера, серверная meta, лимит кнопок, responsive-представление без запросов, многоточия, быстрый переход и сохранение.
|
|
4
4
|
*/
|
|
5
5
|
import EventHandler from "../../../utils/js/dom/event";
|
|
6
6
|
import VGDropdown from "../../vgdropdown";
|
|
@@ -16,10 +16,10 @@ class _pagination {
|
|
|
16
16
|
this._options = options;
|
|
17
17
|
this._host = table.closest('.vg-table-wrapper') || table.parentElement;
|
|
18
18
|
this._containers = [];
|
|
19
|
-
this._dropdowns = [];
|
|
20
|
-
this._externalVisibility = new Map();
|
|
21
|
-
this._manageExternalVisibility = options.responsive === true;
|
|
22
|
-
this._updatingPresentation = false;
|
|
19
|
+
this._dropdowns = [];
|
|
20
|
+
this._externalVisibility = new Map();
|
|
21
|
+
this._manageExternalVisibility = options.responsive === true;
|
|
22
|
+
this._updatingPresentation = false;
|
|
23
23
|
this._page = this._positiveInt(options.page, 1);
|
|
24
24
|
this._perPage = this._clampPerPage(options.per);
|
|
25
25
|
this._remote = options.remote === true;
|
|
@@ -32,24 +32,24 @@ class _pagination {
|
|
|
32
32
|
this._boundFocusOut = this._handleFocusOut.bind(this);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
init() {
|
|
36
|
-
this._restoreState();
|
|
37
|
-
this._containers = this._resolveContainers();
|
|
38
|
-
this._bindContainers();
|
|
39
|
-
this.refresh();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
_bindContainers() {
|
|
43
|
-
this._containers.forEach((container) => {
|
|
35
|
+
init() {
|
|
36
|
+
this._restoreState();
|
|
37
|
+
this._containers = this._resolveContainers();
|
|
38
|
+
this._bindContainers();
|
|
39
|
+
this.refresh();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
_bindContainers() {
|
|
43
|
+
this._containers.forEach((container) => {
|
|
44
44
|
container.addEventListener('click', this._boundClick);
|
|
45
45
|
container.addEventListener('change', this._boundChange);
|
|
46
46
|
container.addEventListener('keydown', this._boundKeydown);
|
|
47
47
|
container.addEventListener('focusin', this._boundFocusIn);
|
|
48
48
|
container.addEventListener('focusout', this._boundFocusOut);
|
|
49
49
|
});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
_releaseContainers() {
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
_releaseContainers() {
|
|
53
53
|
this._disposeDropdowns();
|
|
54
54
|
this._containers.forEach((container) => {
|
|
55
55
|
container.removeEventListener('click', this._boundClick);
|
|
@@ -57,69 +57,69 @@ class _pagination {
|
|
|
57
57
|
container.removeEventListener('keydown', this._boundKeydown);
|
|
58
58
|
container.removeEventListener('focusin', this._boundFocusIn);
|
|
59
59
|
container.removeEventListener('focusout', this._boundFocusOut);
|
|
60
|
-
if (container.hasAttribute(GENERATED_ATTRIBUTE)) container.remove();
|
|
61
|
-
});
|
|
62
|
-
this._containers = [];
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
dispose() {
|
|
66
|
-
this._releaseContainers();
|
|
67
|
-
this._externalVisibility.forEach((hidden, container) => { container.hidden = hidden; });
|
|
68
|
-
this._externalVisibility.clear();
|
|
60
|
+
if (container.hasAttribute(GENERATED_ATTRIBUTE)) container.remove();
|
|
61
|
+
});
|
|
62
|
+
this._containers = [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
dispose() {
|
|
66
|
+
this._releaseContainers();
|
|
67
|
+
this._externalVisibility.forEach((hidden, container) => { container.hidden = hidden; });
|
|
68
|
+
this._externalVisibility.clear();
|
|
69
69
|
this._rows().forEach((row) => {
|
|
70
70
|
row.hidden = row.getAttribute('data-vg-table-expand-hidden') === 'true'
|
|
71
71
|
|| row.hasAttribute('data-vg-table-filter-hidden');
|
|
72
72
|
row.removeAttribute('data-vg-table-page-row');
|
|
73
73
|
});
|
|
74
|
-
this._containers = [];
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Обновляет только панели: не трогает строки, page/per, storage, scroll или onChange. */
|
|
78
|
-
updatePresentation(options) {
|
|
79
|
-
const focus = this._captureFocus();
|
|
80
|
-
const position = this._position();
|
|
81
|
-
this._updatingPresentation = true;
|
|
82
|
-
try {
|
|
83
|
-
this._options = {...this._options, ...options};
|
|
84
|
-
if (position !== this._position()) {
|
|
85
|
-
this._manageExternalVisibility = true;
|
|
86
|
-
this._releaseContainers();
|
|
87
|
-
this._containers = this._resolveContainers();
|
|
88
|
-
this._bindContainers();
|
|
89
|
-
}
|
|
90
|
-
this._renderControls();
|
|
91
|
-
} finally {
|
|
92
|
-
this._updatingPresentation = false;
|
|
93
|
-
}
|
|
94
|
-
this._restoreFocus(focus);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
_captureFocus() {
|
|
98
|
-
const active = this._table.ownerDocument.activeElement;
|
|
99
|
-
const container = this._containers.find((item) => item.contains(active));
|
|
100
|
-
if (!container) return null;
|
|
101
|
-
const attribute = ['data-pagination-page', 'data-pagination-per-page', 'data-pagination-quick-input', 'data-pagination-quick-button']
|
|
102
|
-
.find((name) => active.hasAttribute(name));
|
|
103
|
-
return {
|
|
104
|
-
position: this._positionFor(container), attribute, value: attribute ? active.getAttribute(attribute) : null,
|
|
105
|
-
inputValue: active.tagName === 'INPUT' ? active.value : null,
|
|
106
|
-
start: active.selectionStart, end: active.selectionEnd,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
_restoreFocus(focus) {
|
|
111
|
-
if (!focus) return;
|
|
112
|
-
const container = this._containers.find((item) => this._positionFor(item) === focus.position) || this._containers[0];
|
|
113
|
-
if (!container) return;
|
|
114
|
-
const matching = focus.attribute ? Array.from(container.querySelectorAll(`[${focus.attribute}]`))
|
|
115
|
-
.find((item) => !item.disabled && item.getAttribute(focus.attribute) === focus.value) : null;
|
|
116
|
-
const target = matching || container.querySelector('[aria-current="page"]');
|
|
117
|
-
target?.focus({preventScroll: true});
|
|
118
|
-
if (matching && focus.inputValue !== null) {
|
|
119
|
-
matching.value = focus.inputValue;
|
|
120
|
-
if (focus.start !== null && focus.start !== undefined) matching.setSelectionRange(focus.start, focus.end);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
74
|
+
this._containers = [];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Обновляет только панели: не трогает строки, page/per, storage, scroll или onChange. */
|
|
78
|
+
updatePresentation(options) {
|
|
79
|
+
const focus = this._captureFocus();
|
|
80
|
+
const position = this._position();
|
|
81
|
+
this._updatingPresentation = true;
|
|
82
|
+
try {
|
|
83
|
+
this._options = {...this._options, ...options};
|
|
84
|
+
if (position !== this._position()) {
|
|
85
|
+
this._manageExternalVisibility = true;
|
|
86
|
+
this._releaseContainers();
|
|
87
|
+
this._containers = this._resolveContainers();
|
|
88
|
+
this._bindContainers();
|
|
89
|
+
}
|
|
90
|
+
this._renderControls();
|
|
91
|
+
} finally {
|
|
92
|
+
this._updatingPresentation = false;
|
|
93
|
+
}
|
|
94
|
+
this._restoreFocus(focus);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
_captureFocus() {
|
|
98
|
+
const active = this._table.ownerDocument.activeElement;
|
|
99
|
+
const container = this._containers.find((item) => item.contains(active));
|
|
100
|
+
if (!container) return null;
|
|
101
|
+
const attribute = ['data-pagination-page', 'data-pagination-per-page', 'data-pagination-quick-input', 'data-pagination-quick-button']
|
|
102
|
+
.find((name) => active.hasAttribute(name));
|
|
103
|
+
return {
|
|
104
|
+
position: this._positionFor(container), attribute, value: attribute ? active.getAttribute(attribute) : null,
|
|
105
|
+
inputValue: active.tagName === 'INPUT' ? active.value : null,
|
|
106
|
+
start: active.selectionStart, end: active.selectionEnd,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
_restoreFocus(focus) {
|
|
111
|
+
if (!focus) return;
|
|
112
|
+
const container = this._containers.find((item) => this._positionFor(item) === focus.position) || this._containers[0];
|
|
113
|
+
if (!container) return;
|
|
114
|
+
const matching = focus.attribute ? Array.from(container.querySelectorAll(`[${focus.attribute}]`))
|
|
115
|
+
.find((item) => !item.disabled && item.getAttribute(focus.attribute) === focus.value) : null;
|
|
116
|
+
const target = matching || container.querySelector('[aria-current="page"]');
|
|
117
|
+
target?.focus({preventScroll: true});
|
|
118
|
+
if (matching && focus.inputValue !== null) {
|
|
119
|
+
matching.value = focus.inputValue;
|
|
120
|
+
if (focus.start !== null && focus.start !== undefined) matching.setSelectionRange(focus.start, focus.end);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
123
|
|
|
124
124
|
setPage(page, emit = false, source = 'api') {
|
|
125
125
|
const nextPage = this._clampPage(page);
|
|
@@ -192,11 +192,11 @@ class _pagination {
|
|
|
192
192
|
});
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
this._renderControls();
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
_renderControls() {
|
|
199
|
-
const markup = this._buildMarkup();
|
|
195
|
+
this._renderControls();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
_renderControls() {
|
|
199
|
+
const markup = this._buildMarkup();
|
|
200
200
|
this._disposeDropdowns();
|
|
201
201
|
this._containers.forEach((container) => {
|
|
202
202
|
container.className = `vg-table-pagination vg-table-pagination--${this._positionFor(container)}`;
|
|
@@ -286,10 +286,10 @@ class _pagination {
|
|
|
286
286
|
return `<svg class="vg-table-page__ellipsis-chevron vg-table-page__ellipsis-chevron--${direction}" viewBox="0 0 20 20" focusable="false" aria-hidden="true">${paths}</svg>`;
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
-
_buildPages() {
|
|
290
|
-
const total = this._totalPages();
|
|
291
|
-
const maxButtons = this._options.maxButtons;
|
|
292
|
-
if (Number.isInteger(maxButtons) && maxButtons >= 3) return this._buildLimitedPages(total, maxButtons);
|
|
289
|
+
_buildPages() {
|
|
290
|
+
const total = this._totalPages();
|
|
291
|
+
const maxButtons = this._options.maxButtons;
|
|
292
|
+
if (Number.isInteger(maxButtons) && maxButtons >= 3) return this._buildLimitedPages(total, maxButtons);
|
|
293
293
|
const visible = Math.max(1, this._positiveInt(this._options.visible, 5));
|
|
294
294
|
const threshold = Math.max(1, this._positiveInt(this._options.threshold, 5));
|
|
295
295
|
if (this._options.ellipsis === false || total <= threshold || total <= visible + 2) {
|
|
@@ -304,30 +304,30 @@ class _pagination {
|
|
|
304
304
|
for (let page = start; page <= end; page += 1) pages.push(page);
|
|
305
305
|
if (end < total - 1) pages.push({direction: 'next'});
|
|
306
306
|
pages.push(total);
|
|
307
|
-
return pages;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
_buildLimitedPages(total, maximum) {
|
|
311
|
-
if (total <= maximum) return this._range(1, total);
|
|
312
|
-
if (maximum < 5 || this._options.ellipsis === false) {
|
|
313
|
-
const start = Math.max(1, Math.min(this._page - Math.floor(maximum / 2), total - maximum + 1));
|
|
314
|
-
return this._range(start, start + maximum - 1);
|
|
315
|
-
}
|
|
316
|
-
// Резервируем края и подбираем наибольшее окно, учитывая оба многоточия в лимите.
|
|
317
|
-
for (let count = maximum - 2; count >= 1; count -= 1) {
|
|
318
|
-
const start = Math.max(2, Math.min(this._page - Math.floor(count / 2), total - count));
|
|
319
|
-
const end = start + count - 1;
|
|
320
|
-
const pages = [1];
|
|
321
|
-
if (start === 3) pages.push(2);
|
|
322
|
-
else if (start > 3) pages.push({direction: 'prev'});
|
|
323
|
-
pages.push(...this._range(start, end));
|
|
324
|
-
if (end === total - 2) pages.push(total - 1);
|
|
325
|
-
else if (end < total - 2) pages.push({direction: 'next'});
|
|
326
|
-
pages.push(total);
|
|
327
|
-
if (pages.length <= maximum) return pages;
|
|
328
|
-
}
|
|
329
|
-
return [this._page];
|
|
330
|
-
}
|
|
307
|
+
return pages;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
_buildLimitedPages(total, maximum) {
|
|
311
|
+
if (total <= maximum) return this._range(1, total);
|
|
312
|
+
if (maximum < 5 || this._options.ellipsis === false) {
|
|
313
|
+
const start = Math.max(1, Math.min(this._page - Math.floor(maximum / 2), total - maximum + 1));
|
|
314
|
+
return this._range(start, start + maximum - 1);
|
|
315
|
+
}
|
|
316
|
+
// Резервируем края и подбираем наибольшее окно, учитывая оба многоточия в лимите.
|
|
317
|
+
for (let count = maximum - 2; count >= 1; count -= 1) {
|
|
318
|
+
const start = Math.max(2, Math.min(this._page - Math.floor(count / 2), total - count));
|
|
319
|
+
const end = start + count - 1;
|
|
320
|
+
const pages = [1];
|
|
321
|
+
if (start === 3) pages.push(2);
|
|
322
|
+
else if (start > 3) pages.push({direction: 'prev'});
|
|
323
|
+
pages.push(...this._range(start, end));
|
|
324
|
+
if (end === total - 2) pages.push(total - 1);
|
|
325
|
+
else if (end < total - 2) pages.push({direction: 'next'});
|
|
326
|
+
pages.push(total);
|
|
327
|
+
if (pages.length <= maximum) return pages;
|
|
328
|
+
}
|
|
329
|
+
return [this._page];
|
|
330
|
+
}
|
|
331
331
|
|
|
332
332
|
_handleClick(event) {
|
|
333
333
|
const sizeOption = event.target.closest('[data-pagination-per-page-option]');
|
|
@@ -386,8 +386,8 @@ class _pagination {
|
|
|
386
386
|
if (input) input.value = String(this._perPage);
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
-
_handleFocusOut(event) {
|
|
390
|
-
if (this._updatingPresentation) return;
|
|
389
|
+
_handleFocusOut(event) {
|
|
390
|
+
if (this._updatingPresentation) return;
|
|
391
391
|
const input = event.target.closest('[data-pagination-per-page]');
|
|
392
392
|
if (!input) return;
|
|
393
393
|
const related = event.relatedTarget instanceof Element ? event.relatedTarget : null;
|
|
@@ -413,14 +413,14 @@ class _pagination {
|
|
|
413
413
|
_resolveContainers() {
|
|
414
414
|
if (!this._host) return [];
|
|
415
415
|
const position = this._position();
|
|
416
|
-
const existing = Array.from(this._host.querySelectorAll('[data-vg-table-pagination]'));
|
|
417
|
-
if (existing.length) {
|
|
418
|
-
const selected = position === 'both' ? existing : [existing.find((item) => item.getAttribute('data-position') === position) || existing[0]];
|
|
419
|
-
if (this._manageExternalVisibility) existing.forEach((container) => {
|
|
420
|
-
if (!this._externalVisibility.has(container)) this._externalVisibility.set(container, container.hidden);
|
|
421
|
-
container.hidden = !selected.includes(container);
|
|
422
|
-
});
|
|
423
|
-
return selected;
|
|
416
|
+
const existing = Array.from(this._host.querySelectorAll('[data-vg-table-pagination]'));
|
|
417
|
+
if (existing.length) {
|
|
418
|
+
const selected = position === 'both' ? existing : [existing.find((item) => item.getAttribute('data-position') === position) || existing[0]];
|
|
419
|
+
if (this._manageExternalVisibility) existing.forEach((container) => {
|
|
420
|
+
if (!this._externalVisibility.has(container)) this._externalVisibility.set(container, container.hidden);
|
|
421
|
+
container.hidden = !selected.includes(container);
|
|
422
|
+
});
|
|
423
|
+
return selected;
|
|
424
424
|
}
|
|
425
425
|
|
|
426
426
|
const positions = position === 'both' ? ['top', 'bottom'] : [position];
|