vgapp 0.7.9 → 0.8.0

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/app/langs/en/buttons.json +10 -0
  3. package/app/langs/en/messages.json +32 -0
  4. package/app/langs/en/titles.json +6 -0
  5. package/app/langs/ru/buttons.json +10 -0
  6. package/app/langs/ru/messages.json +32 -0
  7. package/app/langs/ru/titles.json +6 -0
  8. package/app/modules/base-module.js +12 -1
  9. package/app/modules/module-fn.js +20 -9
  10. package/app/modules/vgalert/js/vgalert.js +12 -6
  11. package/app/modules/vgalert/readme.md +1 -1
  12. package/app/modules/vgcollapse/readme.md +1 -1
  13. package/app/modules/vgdropdown/js/vgdropdown.js +140 -38
  14. package/app/modules/vgdropdown/readme.md +225 -0
  15. package/app/modules/vgfiles/js/base.js +499 -0
  16. package/app/modules/vgfiles/js/droppable.js +159 -0
  17. package/app/modules/vgfiles/js/loader.js +389 -0
  18. package/app/modules/vgfiles/js/render.js +83 -0
  19. package/app/modules/vgfiles/js/sortable.js +155 -0
  20. package/app/modules/vgfiles/js/vgfiles.js +796 -280
  21. package/app/modules/vgfiles/readme.md +193 -0
  22. package/app/modules/vgfiles/scss/_animations.scss +18 -0
  23. package/app/modules/vgfiles/scss/_mixins.scss +73 -0
  24. package/app/modules/vgfiles/scss/_variables.scss +103 -26
  25. package/app/modules/vgfiles/scss/vgfiles.scss +573 -60
  26. package/app/modules/vgformsender/js/vgformsender.js +5 -1
  27. package/app/modules/vgformsender/readme.md +1 -1
  28. package/app/modules/vglawcookie/js/vglawcookie.js +96 -62
  29. package/app/modules/vglawcookie/readme.md +102 -0
  30. package/app/modules/vgsidebar/js/vgsidebar.js +6 -4
  31. package/app/utils/js/components/ajax.js +172 -122
  32. package/app/utils/js/components/animation.js +124 -39
  33. package/app/utils/js/components/backdrop.js +54 -31
  34. package/app/utils/js/components/lang.js +69 -88
  35. package/app/utils/js/components/params.js +34 -31
  36. package/app/utils/js/components/scrollbar.js +118 -67
  37. package/app/utils/js/components/templater.js +14 -4
  38. package/app/utils/js/dom/cookie.js +107 -64
  39. package/app/utils/js/dom/data.js +68 -20
  40. package/app/utils/js/dom/event.js +272 -239
  41. package/app/utils/js/dom/manipulator.js +135 -62
  42. package/app/utils/js/dom/selectors.js +134 -59
  43. package/app/utils/js/functions.js +183 -349
  44. package/build/vgapp.css +1 -1
  45. package/build/vgapp.css.map +1 -1
  46. package/package.json +1 -1
  47. package/app/utils/js/components/overflow.js +0 -28
@@ -1,100 +1,173 @@
1
- import {isElement, normalizeData} from "../functions";
1
+ import { isElement, normalizeData } from "../functions";
2
2
 
3
3
  /**
4
- * Манипуляции с атрибутами у элемента:
5
- * get (элемент, имя, флаг - вырезать data-) - метод выбирает значение атрибута по его имени, если в поле имени передать 'data' -> будут выбраны только дата атрибуты, если 'all' -> метод вернет значение всех атрибутов
6
- * has (элемент, имя) - есть ли атрибут у элемента
7
- * set (элемент, имя, значение) - установка у элемента атрибута или его изменение
8
- * remove (элемент, имя) - удаляет атрибут у элемента
9
- * hide(элемент) - скрыть элемент
10
- * show(элемент) - показать элемент
4
+ * Утилиты для работы с атрибутами и классами DOM-элементов.
11
5
  */
12
6
  const Manipulator = {
13
- get(element, nameAttribute = 'data', isRemoveDataName = true) {
14
- if (!element) {
15
- return {}
7
+ /**
8
+ * Получает значение атрибута, data-атрибутов или всех атрибутов.
9
+ * @param {Element} element - DOM-элемент.
10
+ * @param {string} nameAttribute - Имя атрибута ('data', 'all' или конкретное имя).
11
+ * @param {boolean} isRemoveDataName - Убрать префикс 'data-' у data-атрибутов.
12
+ * @returns {any|Object} - Значение атрибута или объект атрибутов.
13
+ */
14
+ get(element, nameAttribute = "data", isRemoveDataName = true) {
15
+ if (!isElement(element)) return {};
16
+
17
+ // Все атрибуты
18
+ if (nameAttribute === "all") {
19
+ return Array.from(element.attributes).reduce((acc, attr) => {
20
+ acc[attr.name] = attr.value;
21
+ return acc;
22
+ }, {});
16
23
  }
17
24
 
18
- if (nameAttribute === 'data') {
19
- let elmBase = ['data-vg-toggle', 'data-vg-target', 'data-vg-dismiss'],
20
- attributes = {};
21
-
22
- let arr = [].filter.call(element.attributes, function (at) {
23
- return /^data-/.test(at.name);
24
- });
25
-
26
- if (arr.length) {
27
- arr.forEach(function (v) {
28
- let name = v.name;
29
-
30
- if (!elmBase.includes(name)) {
31
- if (isRemoveDataName) name = name.slice(5);
32
- attributes[name] = normalizeData(v.value)
25
+ // Data-атрибуты
26
+ if (nameAttribute === "data") {
27
+ const baseKeys = new Set(['data-vg-toggle', 'data-vg-target', 'data-vg-dismiss', 'data-vg-loaded']);
28
+ const dataAttrs = {};
29
+
30
+ Array.from(element.attributes)
31
+ .filter(attr => attr.name.startsWith('data-'))
32
+ .forEach(attr => {
33
+ if (!baseKeys.has(attr.name)) {
34
+ const key = isRemoveDataName ? attr.name.slice(5) : attr.name;
35
+ dataAttrs[key] = normalizeData(attr.value);
33
36
  }
34
37
  });
35
- }
36
38
 
37
- return attributes;
38
- } else if (nameAttribute === 'all') {
39
- return element.getAttributeNames().reduce((acc, name) => {
40
- return {...acc, [name]: element.getAttribute(name)};
41
- }, {});
42
- } else {
43
- return element.getAttribute(nameAttribute);
39
+ return dataAttrs;
44
40
  }
41
+
42
+ // Конкретный атрибут
43
+ return element.getAttribute(nameAttribute);
45
44
  },
46
45
 
46
+ /**
47
+ * Проверяет наличие атрибута у элемента.
48
+ * @param {Element} element - DOM-элемент.
49
+ * @param {string} nameAttribute - Имя атрибута.
50
+ * @returns {boolean}
51
+ */
47
52
  has(element, nameAttribute) {
48
- return element.hasAttribute(nameAttribute);
53
+ return isElement(element) && element.hasAttribute(nameAttribute);
49
54
  },
50
55
 
56
+ /**
57
+ * Устанавливает атрибут элементу.
58
+ * @param {Element} element - DOM-элемент.
59
+ * @param {string} name - Имя атрибута.
60
+ * @param {string} value - Значение атрибута.
61
+ */
51
62
  set(element, name, value) {
52
63
  if (isElement(element) && name) {
53
64
  element.setAttribute(name, value);
54
65
  }
55
66
  },
56
67
 
68
+ /**
69
+ * Удаляет атрибут у элемента.
70
+ * @param {Element} element - DOM-элемент.
71
+ * @param {string} nameAttribute - Имя атрибута.
72
+ */
57
73
  remove(element, nameAttribute) {
58
74
  if (isElement(element) && nameAttribute) {
59
75
  element.removeAttribute(nameAttribute);
60
76
  }
61
77
  },
62
78
 
63
- hide(el) {
64
- el.style.display = 'none';
79
+ /**
80
+ * Скрывает элемент.
81
+ * @param {Element} element - DOM-элемент.
82
+ */
83
+ hide(element) {
84
+ if (isElement(element)) {
85
+ element.style.display = 'none';
86
+ }
65
87
  },
66
88
 
67
- show(el, state = 'block') {
68
- el.style.display = state;
89
+ /**
90
+ * Отображает элемент.
91
+ * @param {Element} element - DOM-элемент.
92
+ * @param {string} state - display-значение (по умолчанию 'block').
93
+ */
94
+ show(element, state = 'block') {
95
+ if (isElement(element)) {
96
+ element.style.display = state;
97
+ }
69
98
  },
70
- }
99
+ };
71
100
 
72
- let Classes = {
101
+ /**
102
+ * Утилиты для работы с classList элемента.
103
+ */
104
+ const Classes = {
105
+ /**
106
+ * Удаляет класс(ы) у элемента.
107
+ * @param {Element} element - DOM-элемент.
108
+ * @param {string|string[]} className - Класс или массив классов.
109
+ */
73
110
  remove(element, className) {
74
- if (className && element) {
75
- if (typeof className === 'string') {
76
- className = className.split(' ');
77
- }
111
+ if (!isElement(element) || !className) return;
78
112
 
79
- element.classList.remove(...className);
80
- }
113
+ const classes = Array.isArray(className) ? className : className.split(' ').filter(Boolean);
114
+ element.classList.remove(...classes);
81
115
  },
82
116
 
117
+ /**
118
+ * Добавляет класс(ы) к элементу.
119
+ * @param {Element} element - DOM-элемент.
120
+ * @param {string|string[]} className - Класс или массив классов.
121
+ * @param {boolean} isString - Если true — возвращает строку вместо применения.
122
+ * @returns {string|undefined} - Строка с классами (если isString=true).
123
+ */
83
124
  add(element, className, isString = false) {
84
- if (className) {
85
- if (typeof className === 'string') {
86
- className = className.split(' ');
87
- }
88
-
89
- if (isString) {
90
- return '' + className.join(' ');
91
- }
92
-
93
- if (element) {
94
- element.classList.add(...className);
95
- }
125
+ if (!className) return;
126
+
127
+ const classes = Array.isArray(className) ? className : className.split(' ').filter(Boolean);
128
+
129
+ if (isString) {
130
+ return classes.join(' ');
131
+ }
132
+
133
+ if (isElement(element)) {
134
+ element.classList.add(...classes);
135
+ }
136
+ },
137
+
138
+ /**
139
+ * Переключает класс у элемента.
140
+ * @param {Element} element - DOM-элемент.
141
+ * @param {string} className - Имя класса.
142
+ * @param {boolean} condition - Условие переключения.
143
+ */
144
+ toggle(element, className, condition = true) {
145
+ if (isElement(element) && className) {
146
+ element.classList.toggle(className, !!condition);
96
147
  }
97
- }
98
- }
148
+ },
149
+
150
+ /**
151
+ * Заменяет один класс на другой.
152
+ * @param {Element} element - DOM-элемент.
153
+ * @param {string} oldClass - Старый класс.
154
+ * @param {string} newClass - Новый класс.
155
+ */
156
+ replace(element, oldClass, newClass) {
157
+ if (isElement(element) && oldClass && newClass) {
158
+ element.classList.replace(oldClass, newClass);
159
+ }
160
+ },
161
+
162
+ /**
163
+ * Проверяет наличие класса у элемента.
164
+ * @param {Element} element - DOM-элемент.
165
+ * @param {string} className - Имя класса.
166
+ * @returns {boolean} - Возвращает true, если элемент содержит указанный класс.
167
+ */
168
+ has(element, className) {
169
+ return isElement(element) && element.classList.contains(className);
170
+ },
171
+ };
99
172
 
100
- export {Manipulator, Classes}
173
+ export { Manipulator, Classes };
@@ -1,105 +1,180 @@
1
1
  /**
2
- * Работа с DOM
3
- * @param selector
4
- * @returns {*}
2
+ * Утилиты для работы с DOM-селекторами
3
+ * Поддержка data-атрибутов, href и CSS-экранирование
5
4
  */
6
- import {isElement} from "../functions";
7
5
 
8
- const parseSelector = selector => {
9
- if (selector && window.CSS && window.CSS.escape) {
10
- selector = selector.replace(/#([^\s"#']+)/g, (match, id) => `#${CSS.escape(id)}`)
11
- }
12
-
13
- return selector
14
- }
6
+ import { isElement } from '../functions';
15
7
 
16
- const getSelector = element => {
17
- let selector = element.getAttribute('data-vg-target');
18
-
19
- if (!selector || selector === '#') {
20
- let hrefAttribute = element.getAttribute('href');
21
- if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {
22
- return null;
23
- }
8
+ /**
9
+ * Экранирует ID в CSS-селекторах, если поддерживается браузером
10
+ * @param {string} id
11
+ * @returns {string}
12
+ */
13
+ const escapeId = (id) => {
14
+ if (id && window.CSS?.escape) {
15
+ return CSS.escape(id);
16
+ }
17
+ // Резервное экранирование для старых браузеров
18
+ return id.replace(/([:.#[]])/g, '\\$1');
19
+ };
24
20
 
25
- if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {
26
- hrefAttribute = `#${hrefAttribute.split('#')[1]}`;
27
- }
21
+ /**
22
+ * Извлекает селектор из элемента через data-атрибут или href
23
+ * @param {Element} element
24
+ * @returns {string|null}
25
+ */
26
+ const getSelector = (element) => {
27
+ const dataTarget = element.getAttribute('data-vg-target');
28
+ if (dataTarget && dataTarget !== '#') {
29
+ return dataTarget.trim();
30
+ }
28
31
 
29
- selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null;
32
+ const href = element.getAttribute('href');
33
+ if (!href || (!href.includes('#') && !href.startsWith('.'))) {
34
+ return null;
30
35
  }
31
36
 
32
- return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null;
33
- }
37
+ const selector = href.includes('#') && !href.startsWith('#')
38
+ ? `#${href.split('#')[1]}`
39
+ : href;
34
40
 
41
+ return selector !== '#' ? selector.trim() : null;
42
+ };
43
+
44
+ /**
45
+ * Основной объект для работы с селекторами
46
+ */
35
47
  const Selectors = {
36
- find(selector, element = document.documentElement) {
48
+ /**
49
+ * Находит один элемент по селектору или возвращает сам элемент
50
+ * @param {string|Element} selector
51
+ * @param {Element} [container=document.documentElement]
52
+ * @returns {Element|null}
53
+ */
54
+ find(selector, container = document.documentElement) {
37
55
  if (isElement(selector)) {
38
56
  return selector;
39
- } else {
40
- return Element.prototype.querySelector.call(element, selector);
57
+ }
58
+ try {
59
+ return container.querySelector(selector);
60
+ } catch (e) {
61
+ console.warn('Invalid selector:', selector, e);
62
+ return null;
63
+ }
64
+ },
65
+
66
+ /**
67
+ * Находит элемент по ID с экранированием
68
+ * @param {string} id
69
+ * @param {Element} [container=document]
70
+ * @returns {Element|null}
71
+ */
72
+ findID(id, container = document) {
73
+ try {
74
+ const escaped = escapeId(id);
75
+ return container.getElementById(escaped) || container.querySelector(`#${escaped}`);
76
+ } catch (e) {
77
+ console.warn('Invalid ID in findID:', id, e);
78
+ return null;
41
79
  }
42
80
  },
43
81
 
82
+ /**
83
+ * Находит все элементы по селектору
84
+ * @param {string} selector
85
+ * @param {Element} [container=document.documentElement]
86
+ * @returns {Element[]}
87
+ */
44
88
  findAll(selector, container = document.documentElement) {
45
- return [].concat(...Element.prototype.querySelectorAll.call(container, selector));
89
+ try {
90
+ return Array.from(container.querySelectorAll(selector));
91
+ } catch (e) {
92
+ console.warn('Invalid selector in findAll:', selector, e);
93
+ return [];
94
+ }
46
95
  },
47
96
 
97
+ /**
98
+ * Получает валидный селектор из элемента
99
+ * @param {Element} element
100
+ * @returns {string|null}
101
+ */
48
102
  getSelectorFromElement(element) {
49
103
  const selector = getSelector(element);
50
- if (selector) return Selectors.find(selector) ? selector : null
51
- return null
104
+ return selector && this.find(selector) ? selector : null;
52
105
  },
53
106
 
107
+ /**
108
+ * Получает целевой элемент по селектору из элемента
109
+ * @param {Element} element
110
+ * @returns {Element|null}
111
+ */
54
112
  getElementFromSelector(element) {
55
113
  const selector = getSelector(element);
56
- return selector ? Selectors.find(selector) : null
114
+ return selector ? this.find(selector) : null;
57
115
  },
58
116
 
117
+ /**
118
+ * Получает все целевые элементы (для множественного выбора)
119
+ * @param {Element} element
120
+ * @returns {Element[]}
121
+ */
59
122
  getMultipleElementsFromSelector(element) {
60
123
  const selector = getSelector(element);
61
- return selector ? Selectors.findAll(selector) : []
124
+ return selector ? this.findAll(selector) : [];
62
125
  },
63
126
 
127
+ /**
128
+ * Находит всех родителей, соответствующих селектору
129
+ * @param {Element} element
130
+ * @param {string} selector
131
+ * @returns {Element[]}
132
+ */
64
133
  parents(element, selector) {
65
- const parents = []
66
- let ancestor = element.parentNode.closest(selector)
134
+ const parents = [];
135
+ let parent = element.parentElement?.closest(selector);
67
136
 
68
- while (ancestor) {
69
- parents.push(ancestor)
70
- ancestor = ancestor.parentNode.closest(selector)
137
+ while (parent) {
138
+ parents.push(parent);
139
+ parent = parent.parentElement?.closest(selector);
71
140
  }
72
141
 
73
- return parents
142
+ return parents;
74
143
  },
75
144
 
145
+ /**
146
+ * Находит следующий соседний элемент, соответствующий селектору
147
+ * @param {Element} element
148
+ * @param {string} selector
149
+ * @returns {Element[]}
150
+ */
76
151
  next(element, selector) {
77
- let next = element.nextElementSibling
78
-
79
- while (next) {
80
- if (next.matches(selector)) {
81
- return [next]
152
+ let sibling = element.nextElementSibling;
153
+ while (sibling) {
154
+ if (sibling.matches(selector)) {
155
+ return [sibling];
82
156
  }
83
-
84
- next = next.nextElementSibling;
157
+ sibling = sibling.nextElementSibling;
85
158
  }
86
-
87
- return []
159
+ return [];
88
160
  },
89
161
 
162
+ /**
163
+ * Находит предыдущий соседний элемент, соответствующий селектору
164
+ * @param {Element} element
165
+ * @param {string} selector
166
+ * @returns {Element[]}
167
+ */
90
168
  prev(element, selector) {
91
- let previous = element.previousElementSibling
92
-
93
- while (previous) {
94
- if (previous.matches(selector)) {
95
- return [previous]
169
+ let sibling = element.previousElementSibling;
170
+ while (sibling) {
171
+ if (sibling.matches(selector)) {
172
+ return [sibling];
96
173
  }
97
-
98
- previous = previous.previousElementSibling
174
+ sibling = sibling.previousElementSibling;
99
175
  }
100
-
101
- return []
102
- }
103
- }
176
+ return [];
177
+ },
178
+ };
104
179
 
105
180
  export default Selectors;