vgapp 0.7.9 → 0.8.1
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/CHANGELOG.md +9 -0
- package/app/langs/en/buttons.json +16 -0
- package/app/langs/en/messages.json +32 -0
- package/app/langs/en/titles.json +6 -0
- package/app/langs/ru/buttons.json +16 -0
- package/app/langs/ru/messages.json +32 -0
- package/app/langs/ru/titles.json +6 -0
- package/app/modules/base-module.js +12 -1
- package/app/modules/module-fn.js +20 -9
- package/app/modules/vgalert/js/vgalert.js +12 -6
- package/app/modules/vgalert/readme.md +1 -1
- package/app/modules/vgcollapse/readme.md +1 -1
- package/app/modules/vgdropdown/js/vgdropdown.js +140 -38
- package/app/modules/vgdropdown/readme.md +225 -0
- package/app/modules/vgfiles/js/base.js +499 -0
- package/app/modules/vgfiles/js/droppable.js +159 -0
- package/app/modules/vgfiles/js/loader.js +389 -0
- package/app/modules/vgfiles/js/render.js +83 -0
- package/app/modules/vgfiles/js/sortable.js +155 -0
- package/app/modules/vgfiles/js/vgfiles.js +796 -280
- package/app/modules/vgfiles/readme.md +193 -0
- package/app/modules/vgfiles/scss/_animations.scss +18 -0
- package/app/modules/vgfiles/scss/_mixins.scss +73 -0
- package/app/modules/vgfiles/scss/_variables.scss +103 -26
- package/app/modules/vgfiles/scss/vgfiles.scss +573 -60
- package/app/modules/vgformsender/js/vgformsender.js +5 -1
- package/app/modules/vgformsender/readme.md +1 -1
- package/app/modules/vglawcookie/js/vglawcookie.js +96 -62
- package/app/modules/vglawcookie/readme.md +102 -0
- package/app/modules/vgloadmore/js/vgloadmore.js +212 -112
- package/app/modules/vgloadmore/readme.md +145 -0
- package/app/modules/vgsidebar/js/vgsidebar.js +6 -4
- package/app/utils/js/components/ajax.js +172 -122
- package/app/utils/js/components/animation.js +124 -39
- package/app/utils/js/components/backdrop.js +54 -31
- package/app/utils/js/components/lang.js +69 -88
- package/app/utils/js/components/params.js +34 -31
- package/app/utils/js/components/scrollbar.js +118 -67
- package/app/utils/js/components/templater.js +14 -4
- package/app/utils/js/dom/cookie.js +107 -64
- package/app/utils/js/dom/data.js +68 -20
- package/app/utils/js/dom/event.js +272 -239
- package/app/utils/js/dom/manipulator.js +135 -62
- package/app/utils/js/dom/selectors.js +134 -59
- package/app/utils/js/functions.js +183 -349
- package/build/vgapp.css +1 -1
- package/build/vgapp.css.map +1 -1
- package/package.json +1 -1
- package/app/utils/js/components/overflow.js +0 -28
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {execute} from "../functions";
|
|
2
|
-
import Selectors from "../dom/selectors";
|
|
1
|
+
import { execute } from "../functions";
|
|
3
2
|
import EventHandler from "../dom/event";
|
|
4
|
-
import
|
|
3
|
+
import Html from "../components/templater";
|
|
4
|
+
import { Classes } from "../dom/manipulator";
|
|
5
|
+
import ScrollBarHelper from "./scrollbar";
|
|
5
6
|
|
|
6
7
|
const NAME = 'backdrop';
|
|
7
8
|
const CLASS_NAME = 'vg-backdrop';
|
|
@@ -9,50 +10,72 @@ const CLASS_NAME_FADE = 'fade';
|
|
|
9
10
|
const CLASS_NAME_SHOW = 'show';
|
|
10
11
|
const EVENT_MOUSEDOWN = `mousedown.vg.${NAME}`;
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
const backdropDelay = 150; // Уменьшено для более плавного UX
|
|
13
14
|
|
|
14
15
|
class Backdrop {
|
|
16
|
+
static _rootEl = document.body;
|
|
17
|
+
static _scrollbar = new ScrollBarHelper();
|
|
18
|
+
static _backdrop = null;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Показывает бэкдроп
|
|
22
|
+
* @param {Function} callback - вызывается после отображения
|
|
23
|
+
*/
|
|
15
24
|
static show(callback) {
|
|
16
|
-
|
|
25
|
+
if (!this._backdrop) {
|
|
26
|
+
this._append();
|
|
27
|
+
}
|
|
28
|
+
|
|
17
29
|
execute(callback);
|
|
18
30
|
}
|
|
19
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Скрывает бэкдроп
|
|
34
|
+
* @param {Function} callback - вызывается после скрытия
|
|
35
|
+
*/
|
|
20
36
|
static hide(callback) {
|
|
21
|
-
|
|
22
|
-
|
|
37
|
+
if (!this._backdrop) return;
|
|
38
|
+
|
|
39
|
+
this._destroy().then(execute.bind(null, callback));
|
|
23
40
|
}
|
|
24
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Создаёт и добавляет элемент бэкдропа
|
|
44
|
+
* @private
|
|
45
|
+
*/
|
|
25
46
|
static _append() {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
47
|
+
const html = Html('dom');
|
|
48
|
+
this._backdrop = html.div({ class: CLASS_NAME });
|
|
29
49
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
backdrop.classList.add(CLASS_NAME_FADE)
|
|
38
|
-
}, 50);
|
|
50
|
+
this._rootEl.appendChild(this._backdrop);
|
|
51
|
+
requestAnimationFrame(() => {
|
|
52
|
+
Classes.add(this._backdrop, CLASS_NAME_SHOW);
|
|
53
|
+
setTimeout(() => {
|
|
54
|
+
Classes.add(this._backdrop, CLASS_NAME_FADE);
|
|
55
|
+
}, backdropDelay);
|
|
56
|
+
});
|
|
39
57
|
|
|
40
|
-
EventHandler.on(
|
|
41
|
-
|
|
42
|
-
Overflow.destroy();
|
|
58
|
+
EventHandler.on(this._backdrop, EVENT_MOUSEDOWN, () => {
|
|
59
|
+
this.hide();
|
|
43
60
|
});
|
|
44
61
|
}
|
|
45
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Удаляет бэкдроп с анимацией
|
|
65
|
+
* @returns {Promise}
|
|
66
|
+
* @private
|
|
67
|
+
*/
|
|
46
68
|
static _destroy() {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
69
|
+
return new Promise((resolve) => {
|
|
70
|
+
Classes.remove(this._backdrop, CLASS_NAME_FADE);
|
|
71
|
+
setTimeout(() => {
|
|
72
|
+
Classes.remove(this._backdrop, CLASS_NAME_SHOW);
|
|
73
|
+
this._backdrop.remove();
|
|
74
|
+
this._backdrop = null;
|
|
75
|
+
this._scrollbar.reset();
|
|
76
|
+
resolve();
|
|
77
|
+
}, backdropDelay);
|
|
78
|
+
});
|
|
56
79
|
}
|
|
57
80
|
}
|
|
58
81
|
|
|
@@ -1,108 +1,89 @@
|
|
|
1
|
-
import {normalizeData} from "../functions";
|
|
1
|
+
import { normalizeData } from "../functions";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
reason: 'Алерт уже открыт'
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
titles: {
|
|
28
|
-
errors: {
|
|
29
|
-
title: 'Ошибка',
|
|
30
|
-
titles: 'Ошибки'
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
buttons: {
|
|
34
|
-
alert: {
|
|
35
|
-
agree: 'Да, согласен',
|
|
36
|
-
cancel: 'Отмена'
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
},
|
|
40
|
-
en: {
|
|
41
|
-
messages: {
|
|
42
|
-
errors: {
|
|
43
|
-
went_wrong: 'Something went wrong, please repeat later',
|
|
44
|
-
"400": 'Bad Request',
|
|
45
|
-
"401": 'Unauthorized',
|
|
46
|
-
"403": 'Forbidden',
|
|
47
|
-
"404": 'Not Found',
|
|
48
|
-
"413": 'Payload Too Large',
|
|
49
|
-
"419": 'Problems with the CSRF token',
|
|
50
|
-
"422": 'Unprocessable Entity',
|
|
51
|
-
"500": 'Internal Server Error',
|
|
52
|
-
"504": 'Gateway Timeout'
|
|
53
|
-
},
|
|
54
|
-
'form-sender': {
|
|
55
|
-
'bootstrap_not_found': 'VGApp could not find bootstrap, the modals will not be closed, try to do this through the afterSend callback.'
|
|
56
|
-
},
|
|
57
|
-
alert: {
|
|
58
|
-
title: 'Default header',
|
|
59
|
-
description: 'Description of the current action',
|
|
60
|
-
reason: 'Alert already open'
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
titles: {
|
|
64
|
-
errors: {
|
|
65
|
-
title: 'Error',
|
|
66
|
-
titles: 'Errors'
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
buttons: {
|
|
70
|
-
alert: {
|
|
71
|
-
agree: 'Yeah, I agree',
|
|
72
|
-
cancel: 'Cancel'
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
},
|
|
3
|
+
// Синхронный импорт JSON-файлов (включаются в бандл Webpack/Vite)
|
|
4
|
+
import messagesRu from '../../../langs/ru/messages.json';
|
|
5
|
+
import titlesRu from '../../../langs/ru/titles.json';
|
|
6
|
+
import buttonsRu from '../../../langs/ru/buttons.json';
|
|
7
|
+
|
|
8
|
+
import messagesEn from '../../../langs/en/messages.json';
|
|
9
|
+
import titlesEn from '../../../langs/en/titles.json';
|
|
10
|
+
import buttonsEn from '../../../langs/en/buttons.json';
|
|
11
|
+
|
|
12
|
+
// Синхронные данные, загруженные при сборке
|
|
13
|
+
const langData = {
|
|
14
|
+
ru: normalizeData({
|
|
15
|
+
messages: messagesRu,
|
|
16
|
+
titles: titlesRu,
|
|
17
|
+
buttons: buttonsRu
|
|
18
|
+
}),
|
|
19
|
+
en: normalizeData({
|
|
20
|
+
messages: messagesEn,
|
|
21
|
+
titles: titlesEn,
|
|
22
|
+
buttons: buttonsEn
|
|
23
|
+
})
|
|
76
24
|
};
|
|
77
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Класс для управления языком (синхронный)
|
|
28
|
+
*/
|
|
78
29
|
class Lang {
|
|
30
|
+
/**
|
|
31
|
+
* @param {string} lang - Язык (ru, en и т.д.)
|
|
32
|
+
*/
|
|
79
33
|
constructor(lang = 'en') {
|
|
80
34
|
this.lang = lang;
|
|
81
35
|
}
|
|
82
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Получение языкового пакета
|
|
39
|
+
* @returns {Object}
|
|
40
|
+
*/
|
|
83
41
|
get() {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (!data) data = langs['en'];
|
|
87
|
-
|
|
88
|
-
return normalizeData(data);
|
|
42
|
+
return langData[this.lang] || langData['en'];
|
|
89
43
|
}
|
|
90
44
|
}
|
|
91
45
|
|
|
92
|
-
|
|
93
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Получение языкового раздела
|
|
48
|
+
* @param {string} language - Язык
|
|
49
|
+
* @param {string} mode - messages, titles, buttons
|
|
50
|
+
* @param {string} module - Модуль (files, alert и т.д.)
|
|
51
|
+
* @returns {Object}
|
|
52
|
+
*/
|
|
53
|
+
function getLangData(language = 'en', mode, module) {
|
|
54
|
+
const langInstance = new Lang(language);
|
|
55
|
+
const data = langInstance.get();
|
|
56
|
+
return data[mode]?.[module] || {};
|
|
94
57
|
}
|
|
95
58
|
|
|
96
|
-
|
|
97
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Получение заголовков
|
|
61
|
+
* @param {string} language
|
|
62
|
+
* @param {string} module
|
|
63
|
+
* @returns {Object}
|
|
64
|
+
*/
|
|
65
|
+
function lang_titles(language, module) {
|
|
66
|
+
return getLangData(language, 'titles', module);
|
|
98
67
|
}
|
|
99
68
|
|
|
100
|
-
|
|
101
|
-
|
|
69
|
+
/**
|
|
70
|
+
* Получение сообщений
|
|
71
|
+
* @param {string} language
|
|
72
|
+
* @param {string} module
|
|
73
|
+
* @returns {Object}
|
|
74
|
+
*/
|
|
75
|
+
function lang_messages(language, module) {
|
|
76
|
+
return getLangData(language, 'messages', module);
|
|
102
77
|
}
|
|
103
78
|
|
|
104
|
-
|
|
105
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Получение текстов кнопок
|
|
81
|
+
* @param {string} language
|
|
82
|
+
* @param {string} module
|
|
83
|
+
* @returns {Object}
|
|
84
|
+
*/
|
|
85
|
+
function lang_buttons(language, module) {
|
|
86
|
+
return getLangData(language, 'buttons', module);
|
|
106
87
|
}
|
|
107
88
|
|
|
108
|
-
export {
|
|
89
|
+
export { lang_messages, lang_titles, lang_buttons };
|
|
@@ -1,54 +1,57 @@
|
|
|
1
|
-
import {isElement, mergeDeepObject
|
|
2
|
-
import {Manipulator} from "../dom/manipulator";
|
|
1
|
+
import { isElement, mergeDeepObject } from "../functions";
|
|
2
|
+
import { Manipulator } from "../dom/manipulator";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Класс Params
|
|
6
|
+
* Объединяет параметры из объекта и атрибутов элемента, поддерживает вложенные параметры через дефисы
|
|
7
|
+
*/
|
|
4
8
|
class Params {
|
|
5
9
|
constructor(params, element = null) {
|
|
6
10
|
this._params = this.merge(params, element);
|
|
7
11
|
}
|
|
8
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Возвращает итоговые параметры
|
|
15
|
+
*/
|
|
9
16
|
get() {
|
|
10
17
|
return this._params;
|
|
11
18
|
}
|
|
12
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Извлекает параметры из data-атрибутов элемента
|
|
22
|
+
*/
|
|
13
23
|
fromElement(element) {
|
|
14
24
|
return isElement(element) ? Manipulator.get(element) : {};
|
|
15
25
|
}
|
|
16
26
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
let currentLevel = result;
|
|
24
|
-
|
|
25
|
-
for (let i = 0; i < keys.length; i++) {
|
|
26
|
-
const key = keys[i];
|
|
27
|
-
|
|
28
|
-
if (i < keys.length - 1) {
|
|
29
|
-
currentLevel[key] = {};
|
|
30
|
-
currentLevel = currentLevel[key];
|
|
31
|
-
} else {
|
|
32
|
-
currentLevel[key] = value;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
27
|
+
/**
|
|
28
|
+
* Преобразует строку вида 'foo-bar-baz' в вложенный объект { foo: { bar: { baz: value } } }
|
|
29
|
+
*/
|
|
30
|
+
static stringToNestedObject(str, value) {
|
|
31
|
+
return str.split('-').reduceRight((acc, key) => ({ [key]: acc }), value);
|
|
32
|
+
}
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Слияние параметров: объект + data-атрибуты + обработка вложенности и ключа 'params'
|
|
36
|
+
*/
|
|
37
|
+
merge(params, element) {
|
|
38
|
+
let merged = mergeDeepObject(params, this.fromElement(element));
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
// Обработка вложенных ключей через дефисы и ключа 'params'
|
|
41
|
+
Object.keys(merged).forEach(key => {
|
|
42
|
+
if (key === 'params') {
|
|
43
|
+
merged = mergeDeepObject(merged, merged.params);
|
|
44
|
+
delete merged.params;
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
if (key.
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
if (key.includes('-')) {
|
|
48
|
+
const nestedObj = Params.stringToNestedObject(key, merged[key]);
|
|
49
|
+
merged = mergeDeepObject(merged, nestedObj);
|
|
50
|
+
delete merged[key];
|
|
48
51
|
}
|
|
49
|
-
}
|
|
52
|
+
});
|
|
50
53
|
|
|
51
|
-
return
|
|
54
|
+
return merged;
|
|
52
55
|
}
|
|
53
56
|
}
|
|
54
57
|
|
|
@@ -1,114 +1,165 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* --------------------------------------------------------------------------
|
|
3
|
-
* Bootstrap util/scrollBar.js
|
|
3
|
+
* Bootstrap util/scrollBar.js (рефакторинг)
|
|
4
4
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|
5
5
|
* --------------------------------------------------------------------------
|
|
6
|
+
*
|
|
7
|
+
* Улучшена читаемость, вынесены дублирующиеся операции,
|
|
8
|
+
* добавлены JSDoc-комментарии, упрощена логика.
|
|
6
9
|
*/
|
|
7
10
|
|
|
8
|
-
import {Manipulator} from "../dom/manipulator";
|
|
9
|
-
import {isElement} from "../functions";
|
|
11
|
+
import { Manipulator } from "../dom/manipulator";
|
|
10
12
|
import Selectors from "../dom/selectors";
|
|
13
|
+
import { isElement } from "../functions";
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
|
-
*
|
|
16
|
+
* Константы
|
|
14
17
|
*/
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const PROPERTY_MARGIN = 'margin-right'
|
|
18
|
+
const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';
|
|
19
|
+
const SELECTOR_STICKY_CONTENT = '.sticky-top';
|
|
20
|
+
const PROPERTY_PADDING = 'padding-right';
|
|
21
|
+
const PROPERTY_MARGIN = 'margin-right';
|
|
20
22
|
|
|
21
23
|
/**
|
|
22
|
-
*
|
|
24
|
+
* Вспомогательный класс для управления скроллбаром
|
|
25
|
+
* Корректирует отступы при скрытии скролла, сохраняет исходные стили
|
|
23
26
|
*/
|
|
24
|
-
|
|
25
27
|
class ScrollBarHelper {
|
|
26
28
|
constructor() {
|
|
27
|
-
this._element = document.body
|
|
29
|
+
this._element = document.body;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Возвращает ширину вертикального скроллбара
|
|
34
|
+
* @returns {number}
|
|
35
|
+
*/
|
|
31
36
|
getWidth() {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
const documentWidth = document.documentElement.clientWidth;
|
|
38
|
+
return Math.abs(window.innerWidth - documentWidth);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Проверяет, есть ли скроллбар (ширина > 0)
|
|
43
|
+
* @returns {boolean}
|
|
44
|
+
*/
|
|
45
|
+
isOverflowing() {
|
|
46
|
+
return this.getWidth() > 0;
|
|
35
47
|
}
|
|
36
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Скрывает скроллбар и корректирует макет
|
|
51
|
+
*/
|
|
37
52
|
hide() {
|
|
38
|
-
const width = this.getWidth()
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.
|
|
42
|
-
|
|
43
|
-
this.
|
|
44
|
-
this.
|
|
53
|
+
const width = this.getWidth();
|
|
54
|
+
if (width === 0) return;
|
|
55
|
+
|
|
56
|
+
this._disableOverflow();
|
|
57
|
+
|
|
58
|
+
this._setStyle(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, width, (value) => value + width);
|
|
59
|
+
this._setStyle(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, width, (value) => value - width);
|
|
60
|
+
this._setStyle(this._element, PROPERTY_PADDING, width, (value) => value + width);
|
|
45
61
|
}
|
|
46
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Сбрасывает стили до исходных значений
|
|
65
|
+
*/
|
|
47
66
|
reset() {
|
|
48
|
-
this.
|
|
49
|
-
this.
|
|
50
|
-
this.
|
|
51
|
-
this.
|
|
67
|
+
this._resetStyle(this._element, "overflow");
|
|
68
|
+
this._resetStyle(this._element, PROPERTY_PADDING);
|
|
69
|
+
this._resetStyle(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING);
|
|
70
|
+
this._resetStyle(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN);
|
|
52
71
|
}
|
|
53
72
|
|
|
54
|
-
|
|
55
|
-
return this.getWidth() > 0
|
|
56
|
-
}
|
|
73
|
+
// === Приватные методы ===
|
|
57
74
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Блокирует overflow у body
|
|
77
|
+
* @private
|
|
78
|
+
*/
|
|
79
|
+
_disableOverflow() {
|
|
80
|
+
this._saveInitialStyle(this._element, "overflow");
|
|
81
|
+
this._element.style.overflow = "hidden";
|
|
62
82
|
}
|
|
63
83
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Устанавливает стили с сохранением начальных значений
|
|
86
|
+
* @param {string|HTMLElement} selector
|
|
87
|
+
* @param {string} property
|
|
88
|
+
* @param {number} width
|
|
89
|
+
* @param {(value: number) => number} callback
|
|
90
|
+
* @private
|
|
91
|
+
*/
|
|
92
|
+
_setStyle(selector, property, width, callback) {
|
|
93
|
+
const apply = (element) => {
|
|
94
|
+
// Исключаем элементы, у которых и так нет места под скролл
|
|
95
|
+
if (element !== this._element && window.innerWidth > element.clientWidth + width) {
|
|
96
|
+
return;
|
|
69
97
|
}
|
|
70
98
|
|
|
71
|
-
this.
|
|
72
|
-
const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)
|
|
73
|
-
element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)
|
|
74
|
-
}
|
|
99
|
+
this._saveInitialStyle(element, property);
|
|
75
100
|
|
|
76
|
-
|
|
77
|
-
|
|
101
|
+
const current = getComputedStyle(element).getPropertyValue(property);
|
|
102
|
+
const value = Number.parseFloat(current) || 0;
|
|
78
103
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
104
|
+
element.style.setProperty(property, `${callback(value)}px`);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
this._applyToElements(selector, apply);
|
|
84
108
|
}
|
|
85
109
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
110
|
+
/**
|
|
111
|
+
* Сбрасывает стили до сохранённых значений
|
|
112
|
+
* @param {string|HTMLElement} selector
|
|
113
|
+
* @param {string} property
|
|
114
|
+
* @private
|
|
115
|
+
*/
|
|
116
|
+
_resetStyle(selector, property) {
|
|
117
|
+
const apply = (element) => {
|
|
118
|
+
const value = Manipulator.get(element, property);
|
|
119
|
+
|
|
90
120
|
if (value === null) {
|
|
91
|
-
element.style.removeProperty(
|
|
92
|
-
return
|
|
121
|
+
element.style.removeProperty(property);
|
|
122
|
+
return;
|
|
93
123
|
}
|
|
94
124
|
|
|
95
|
-
Manipulator.remove(element,
|
|
96
|
-
element.style.setProperty(
|
|
97
|
-
}
|
|
125
|
+
Manipulator.remove(element, property);
|
|
126
|
+
element.style.setProperty(property, value);
|
|
127
|
+
};
|
|
98
128
|
|
|
99
|
-
this.
|
|
129
|
+
this._applyToElements(selector, apply);
|
|
100
130
|
}
|
|
101
131
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Сохраняет текущее значение inline-стиля через Manipulator
|
|
134
|
+
* (включая пустое значение, чтобы reset() работал стабильно).
|
|
135
|
+
* @param {HTMLElement} element
|
|
136
|
+
* @param {string} property
|
|
137
|
+
* @private
|
|
138
|
+
*/
|
|
139
|
+
_saveInitialStyle(element, property) {
|
|
140
|
+
const value = element.style.getPropertyValue(property);
|
|
141
|
+
|
|
142
|
+
// Важно: сохраняем даже пустую строку (если inline-стиля не было)
|
|
143
|
+
// чтобы reset() мог корректно восстановить "как было".
|
|
144
|
+
if (value !== null) {
|
|
145
|
+
Manipulator.set(element, property, value);
|
|
106
146
|
}
|
|
147
|
+
}
|
|
107
148
|
|
|
108
|
-
|
|
109
|
-
|
|
149
|
+
/**
|
|
150
|
+
* Применяет callback к элементу или списку элементов
|
|
151
|
+
* @param {string|HTMLElement} selector
|
|
152
|
+
* @param {(element: HTMLElement) => void} callback
|
|
153
|
+
* @private
|
|
154
|
+
*/
|
|
155
|
+
_applyToElements(selector, callback) {
|
|
156
|
+
if (isElement(selector)) {
|
|
157
|
+
callback(selector);
|
|
158
|
+
return;
|
|
110
159
|
}
|
|
160
|
+
|
|
161
|
+
Selectors.findAll(selector, this._element).forEach(callback);
|
|
111
162
|
}
|
|
112
163
|
}
|
|
113
164
|
|
|
114
|
-
export default ScrollBarHelper
|
|
165
|
+
export default ScrollBarHelper;
|
|
@@ -213,13 +213,23 @@ class LaravelHtmlBuilder {
|
|
|
213
213
|
return this.element('textarea', { name, ...attributes }, content);
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
ul(items = [], attributes = {}) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
)
|
|
216
|
+
ul(items = [], attributes = {}, isNative = false) {
|
|
217
|
+
let listItems = [];
|
|
218
|
+
|
|
219
|
+
if (!isNative) {
|
|
220
|
+
listItems = items.map(item =>
|
|
221
|
+
this.element('li', {}, item)
|
|
222
|
+
);
|
|
223
|
+
} else {
|
|
224
|
+
listItems = items
|
|
225
|
+
}
|
|
220
226
|
return this.element('ul', attributes, listItems);
|
|
221
227
|
}
|
|
222
228
|
|
|
229
|
+
li(attributes = {}, content, options) {
|
|
230
|
+
return this.element('li', attributes, content, options);
|
|
231
|
+
}
|
|
232
|
+
|
|
223
233
|
ol(items = [], attributes = {}) {
|
|
224
234
|
const listItems = items.map(item =>
|
|
225
235
|
this.element('li', {}, item)
|