vgapp 0.0.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.
Files changed (48) hide show
  1. package/.gitattributes +1 -0
  2. package/CHANGELOG.md +0 -0
  3. package/LICENSE +21 -0
  4. package/README.md +1 -0
  5. package/app/modules/base-module.js +97 -0
  6. package/app/modules/module-fn.js +119 -0
  7. package/app/modules/vgcollapse/js/vgcollapse.js +219 -0
  8. package/app/modules/vgdropdown/js/vgdropdown.js +279 -0
  9. package/app/modules/vgdropdown/scss/_variables.scss +9 -0
  10. package/app/modules/vgdropdown/scss/vgdropdown.scss +41 -0
  11. package/app/modules/vgformsender/js/vgformsender.js +400 -0
  12. package/app/modules/vgformsender/scss/vgformsender.scss +19 -0
  13. package/app/modules/vgmodal/js/vgmodal.js +346 -0
  14. package/app/modules/vgmodal/scss/_variables.scss +25 -0
  15. package/app/modules/vgmodal/scss/vgmodal.scss +111 -0
  16. package/app/modules/vgnav/js/vgnav.js +498 -0
  17. package/app/modules/vgnav/scss/_breakpoints.scss +127 -0
  18. package/app/modules/vgnav/scss/_hamburger.scss +62 -0
  19. package/app/modules/vgnav/scss/_placement.scss +70 -0
  20. package/app/modules/vgnav/scss/_toggle.scss +20 -0
  21. package/app/modules/vgnav/scss/_variables.scss +68 -0
  22. package/app/modules/vgnav/scss/vgnav.scss +150 -0
  23. package/app/modules/vgsidebar/js/vgsidebar.js +165 -0
  24. package/app/modules/vgsidebar/scss/_variables.scss +19 -0
  25. package/app/modules/vgsidebar/scss/vgsidebar.scss +90 -0
  26. package/app/utils/js/components/backdrop.js +54 -0
  27. package/app/utils/js/components/overflow.js +28 -0
  28. package/app/utils/js/components/params.js +44 -0
  29. package/app/utils/js/components/placement.js +59 -0
  30. package/app/utils/js/components/responsive.js +83 -0
  31. package/app/utils/js/components/scrollbar.js +114 -0
  32. package/app/utils/js/dom/data.js +51 -0
  33. package/app/utils/js/dom/event.js +331 -0
  34. package/app/utils/js/dom/manipulator.js +62 -0
  35. package/app/utils/js/dom/selectors.js +65 -0
  36. package/app/utils/js/functions.js +272 -0
  37. package/app/utils/scss/animate.scss +4074 -0
  38. package/app/utils/scss/default.scss +277 -0
  39. package/app/utils/scss/functions.scss +3 -0
  40. package/app/utils/scss/mixin.scss +11 -0
  41. package/app/utils/scss/variables.scss +80 -0
  42. package/build/vgapp.css +4538 -0
  43. package/build/vgapp.css.map +1 -0
  44. package/build/vgapp.js +3230 -0
  45. package/build/vgapp.js.map +1 -0
  46. package/index.js +29 -0
  47. package/package.json +43 -0
  48. package/webpack.config.js +63 -0
@@ -0,0 +1,59 @@
1
+ import {mergeDeepObject, normalizeData} from "../functions";
2
+
3
+ /**
4
+ * Класс Placement, определяет и устанавливает местоположение элемента на странице.
5
+ * TODO класс не дописан
6
+ */
7
+
8
+ class Placement {
9
+ constructor(arg = {}) {
10
+ this.params = mergeDeepObject({
11
+ element: null,
12
+ drop: null
13
+ }, arg);
14
+ }
15
+
16
+ _getPlacement() {
17
+ const _this = this;
18
+ const _parent = (self) => {
19
+ let parent = self.parentNode,
20
+ overflow = getComputedStyle(parent).overflow;
21
+
22
+ if (parent.tagName !== 'BODY') {
23
+ if (overflow === 'visible') {
24
+ _parent(parent)
25
+ } else {
26
+ return parent;
27
+ }
28
+ } else {
29
+ return null;
30
+ }
31
+ }
32
+
33
+ let isFixed = false, top, left,
34
+ bounds = _this.params.drop.getBoundingClientRect(),
35
+ parent = _this.params.element.getBoundingClientRect();
36
+
37
+ if (_parent(_this.params.element)) {
38
+ isFixed = true;
39
+ top = bounds.top;
40
+ left = bounds.left;
41
+ } else {
42
+ let styles = getComputedStyle(_this.params.drop);
43
+ top = normalizeData(styles.top.slice(0, -2));
44
+ left = normalizeData(styles.left.slice(0, -2));
45
+ }
46
+
47
+ if ((bounds.left + bounds.width) > window.innerWidth) {
48
+ left = parent.width - bounds.width;
49
+ }
50
+
51
+ return {
52
+ isFixed: isFixed,
53
+ top: top,
54
+ left: left
55
+ }
56
+ }
57
+ }
58
+
59
+ export default Placement;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Класс Responsive, работает по таким же медиа точкам, что и bootstrap
3
+ * и определяет на тач устройства.
4
+ */
5
+
6
+ class Responsive {
7
+ constructor() {
8
+ this.breakpoints = {
9
+ xs: 0,
10
+ sm: 576,
11
+ md: 768,
12
+ lg: 992,
13
+ xl: 1200,
14
+ xxl: 1400,
15
+ xxxl: 1600,
16
+ };
17
+ }
18
+
19
+ /**
20
+ * Если наша ширина экрана совпадает с диапазоном который указан в модуле выдаем true, иначе false
21
+ * @param module
22
+ * @returns {boolean}
23
+ */
24
+ static check(module) {
25
+ let instance = new this ;
26
+ return instance.define(module);
27
+ }
28
+
29
+ /**
30
+ * Проверяет на тач устройства. TODO не совсем правильно, надо сделать по-другому
31
+ * @returns {boolean}
32
+ */
33
+ static checkMobileOrTablet() {
34
+ let check = false;
35
+ (function(a) {
36
+ if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.slice(0,4))){
37
+ check = true;
38
+ }
39
+ })(navigator.userAgent||navigator.vendor||window.opera);
40
+
41
+ return check;
42
+ }
43
+
44
+ define(module) {
45
+ let windowWidth = window.innerWidth,
46
+ responsive_size = this._checkResponsiveClass(module),
47
+ breakpoints = this.breakpoints,
48
+ point = Object.keys(breakpoints).find(key => breakpoints[key] === responsive_size);
49
+
50
+ let keys = Object.keys(breakpoints),
51
+ loc = keys.indexOf(point);
52
+
53
+ return windowWidth >= breakpoints[keys[loc + 1]];
54
+ }
55
+
56
+ _checkResponsiveClass(module) {
57
+ let element = module._element,
58
+ params = module._params,
59
+ current_responsive_size = 0;
60
+
61
+ if (element.classList.contains(params.classes.XXXL)) {
62
+ current_responsive_size = this.breakpoints.xxxl;
63
+ } else if (element.classList.contains(params.classes.XXL)) {
64
+ current_responsive_size = this.breakpoints.xxl;
65
+ } else if (element.classList.contains(params.classes.XL)) {
66
+ current_responsive_size = this.breakpoints.xl;
67
+ } else if (element.classList.contains(params.classes.LG)) {
68
+ current_responsive_size = this.breakpoints.lg;
69
+ } else if (element.classList.contains(params.classes.MD)) {
70
+ current_responsive_size = this.breakpoints.md;
71
+ } else if (element.classList.contains(params.classes.SM)) {
72
+ current_responsive_size = this.breakpoints.sm;
73
+ } else if (element.classList.contains(params.classes.XS)) {
74
+ current_responsive_size = this.breakpoints.xs;
75
+ } else {
76
+ current_responsive_size = this.breakpoints.xs;
77
+ }
78
+
79
+ return current_responsive_size
80
+ }
81
+ }
82
+
83
+ export default Responsive;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * --------------------------------------------------------------------------
3
+ * Bootstrap util/scrollBar.js
4
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
+ * --------------------------------------------------------------------------
6
+ */
7
+
8
+ import {Manipulator} from "../dom/manipulator";
9
+ import {isElement} from "../functions";
10
+ import Selectors from "../dom/selectors";
11
+
12
+ /**
13
+ * Constants
14
+ */
15
+
16
+ const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'
17
+ const SELECTOR_STICKY_CONTENT = '.sticky-top'
18
+ const PROPERTY_PADDING = 'padding-right'
19
+ const PROPERTY_MARGIN = 'margin-right'
20
+
21
+ /**
22
+ * Class definition
23
+ */
24
+
25
+ class ScrollBarHelper {
26
+ constructor() {
27
+ this._element = document.body
28
+ }
29
+
30
+ // Public
31
+ getWidth() {
32
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
33
+ const documentWidth = document.documentElement.clientWidth
34
+ return Math.abs(window.innerWidth - documentWidth)
35
+ }
36
+
37
+ hide() {
38
+ const width = this.getWidth()
39
+ this._disableOverFlow()
40
+ // give padding to element to balance the hidden scrollbar width
41
+ this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)
42
+ // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
43
+ this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)
44
+ this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)
45
+ }
46
+
47
+ reset() {
48
+ this._resetElementAttributes(this._element, 'overflow')
49
+ this._resetElementAttributes(this._element, PROPERTY_PADDING)
50
+ this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)
51
+ this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)
52
+ }
53
+
54
+ isOverflowing() {
55
+ return this.getWidth() > 0
56
+ }
57
+
58
+ // Private
59
+ _disableOverFlow() {
60
+ this._saveInitialAttribute(this._element, 'overflow')
61
+ this._element.style.overflow = 'hidden'
62
+ }
63
+
64
+ _setElementAttributes(selector, styleProperty, callback) {
65
+ const scrollbarWidth = this.getWidth()
66
+ const manipulationCallBack = element => {
67
+ if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {
68
+ return
69
+ }
70
+
71
+ this._saveInitialAttribute(element, styleProperty)
72
+ const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)
73
+ element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)
74
+ }
75
+
76
+ this._applyManipulationCallback(selector, manipulationCallBack)
77
+ }
78
+
79
+ _saveInitialAttribute(element, styleProperty) {
80
+ const actualValue = element.style.getPropertyValue(styleProperty)
81
+ if (actualValue) {
82
+ Manipulator.get(element, styleProperty, actualValue)
83
+ }
84
+ }
85
+
86
+ _resetElementAttributes(selector, styleProperty) {
87
+ const manipulationCallBack = element => {
88
+ const value = Manipulator.get(element, styleProperty)
89
+ // We only want to remove the property if the value is `null`; the value can also be zero
90
+ if (value === null) {
91
+ element.style.removeProperty(styleProperty)
92
+ return
93
+ }
94
+
95
+ Manipulator.remove(element, styleProperty)
96
+ element.style.setProperty(styleProperty, value)
97
+ }
98
+
99
+ this._applyManipulationCallback(selector, manipulationCallBack)
100
+ }
101
+
102
+ _applyManipulationCallback(selector, callBack) {
103
+ if (isElement(selector)) {
104
+ callBack(selector)
105
+ return
106
+ }
107
+
108
+ for (const sel of Selectors.findAll(selector, this._element)) {
109
+ callBack(sel)
110
+ }
111
+ }
112
+ }
113
+
114
+ export default ScrollBarHelper
@@ -0,0 +1,51 @@
1
+ /**
2
+ * --------------------------------------------------------------------------
3
+ * Bootstrap data.js
4
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
+ * --------------------------------------------------------------------------
6
+ * Скрипт работает с коллекцией модулей. Подробнее тут https://learn.javascript.ru/map-set
7
+ */
8
+
9
+ /**
10
+ * Константы
11
+ */
12
+
13
+ const elementMap = new Map()
14
+
15
+ export default {
16
+ set(element, key, instance) {
17
+ if (!elementMap.has(element)) {
18
+ elementMap.set(element, new Map())
19
+ }
20
+
21
+ const instanceMap = elementMap.get(element)
22
+ if (!instanceMap.has(key) && instanceMap.size !== 0) {
23
+ console.error(`VGApp не допускает более одного экземпляра для каждого элемента. Связанный экземпляр: ${Array.from(instanceMap.keys())[0]}.`)
24
+ return
25
+ }
26
+
27
+ instanceMap.set(key, instance)
28
+ },
29
+
30
+ get(element, key) {
31
+ if (elementMap.has(element)) {
32
+ return elementMap.get(element).get(key) || null
33
+ }
34
+
35
+ return null
36
+ },
37
+
38
+ remove(element, key) {
39
+ if (!elementMap.has(element)) {
40
+ return
41
+ }
42
+
43
+ const instanceMap = elementMap.get(element)
44
+
45
+ instanceMap.delete(key);
46
+
47
+ if (instanceMap.size === 0) {
48
+ elementMap.delete(element)
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,331 @@
1
+ /**
2
+ * --------------------------------------------------------------------------
3
+ * Bootstrap event.js
4
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
+ * --------------------------------------------------------------------------
6
+ * Скрипт для прослушивания события
7
+ */
8
+
9
+ /**
10
+ * Константы
11
+ */
12
+
13
+ const namespaceRegex = /[^.]*(?=\..*)\.|.*/
14
+ const stripNameRegex = /\..*/
15
+ const stripUidRegex = /::\d+$/
16
+ const eventRegistry = {} // Events storage
17
+ let uidEvent = 1
18
+ const customEvents = {
19
+ mouseenter: 'mouseover',
20
+ mouseleave: 'mouseout'
21
+ }
22
+
23
+ const nativeEvents = new Set([
24
+ 'click',
25
+ 'dblclick',
26
+ 'mouseup',
27
+ 'mousedown',
28
+ 'contextmenu',
29
+ 'mousewheel',
30
+ 'DOMMouseScroll',
31
+ 'mouseover',
32
+ 'mouseout',
33
+ 'mousemove',
34
+ 'selectstart',
35
+ 'selectend',
36
+ 'submit',
37
+ 'keydown',
38
+ 'keypress',
39
+ 'keyup',
40
+ 'orientationchange',
41
+ 'touchstart',
42
+ 'touchmove',
43
+ 'touchend',
44
+ 'touchcancel',
45
+ 'pointerdown',
46
+ 'pointermove',
47
+ 'pointerup',
48
+ 'pointerleave',
49
+ 'pointercancel',
50
+ 'gesturestart',
51
+ 'gesturechange',
52
+ 'gestureend',
53
+ 'focus',
54
+ 'blur',
55
+ 'change',
56
+ 'reset',
57
+ 'select',
58
+ 'submit',
59
+ 'focusin',
60
+ 'focusout',
61
+ 'load',
62
+ 'unload',
63
+ 'beforeunload',
64
+ 'resize',
65
+ 'move',
66
+ 'DOMContentLoaded',
67
+ 'readystatechange',
68
+ 'error',
69
+ 'abort',
70
+ 'scroll'
71
+ ])
72
+
73
+ /**
74
+ * Приватные методы
75
+ */
76
+
77
+ function makeEventUid(element, uid) {
78
+ return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++
79
+ }
80
+
81
+ function getElementEvents(element) {
82
+ const uid = makeEventUid(element)
83
+
84
+ element.uidEvent = uid
85
+ eventRegistry[uid] = eventRegistry[uid] || {}
86
+
87
+ return eventRegistry[uid]
88
+ }
89
+
90
+ function bootstrapHandler(element, fn) {
91
+ return function handler(event) {
92
+ hydrateObj(event, { delegateTarget: element })
93
+
94
+ if (handler.oneOff) {
95
+ EventHandler.off(element, event.type, fn)
96
+ }
97
+
98
+ return fn.apply(element, [event])
99
+ }
100
+ }
101
+
102
+ function bootstrapDelegationHandler(element, selector, fn) {
103
+ return function handler(event) {
104
+ const domElements = element.querySelectorAll(selector)
105
+
106
+ for (let { target } = event; target && target !== this; target = target.parentNode) {
107
+ for (const domElement of domElements) {
108
+ if (domElement !== target) {
109
+ continue
110
+ }
111
+
112
+ hydrateObj(event, { delegateTarget: target })
113
+
114
+ if (handler.oneOff) {
115
+ EventHandler.off(element, event.type, selector, fn)
116
+ }
117
+
118
+ return fn.apply(target, [event])
119
+ }
120
+ }
121
+ }
122
+ }
123
+
124
+ function findHandler(events, callable, delegationSelector = null) {
125
+ return Object.values(events)
126
+ .find(event => event.callable === callable && event.delegationSelector === delegationSelector)
127
+ }
128
+
129
+ function normalizeParameters(originalTypeEvent, handler, delegationFunction) {
130
+ const isDelegated = typeof handler === 'string'
131
+ // TODO: выдает "false" вместо селектора, поэтому нужно проверить. boot
132
+ const callable = isDelegated ? delegationFunction : (handler || delegationFunction)
133
+ let typeEvent = getTypeEvent(originalTypeEvent)
134
+
135
+ if (!nativeEvents.has(typeEvent)) {
136
+ typeEvent = originalTypeEvent
137
+ }
138
+
139
+ return [isDelegated, callable, typeEvent]
140
+ }
141
+
142
+ function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {
143
+ if (typeof originalTypeEvent !== 'string' || !element) {
144
+ return
145
+ }
146
+
147
+ let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)
148
+
149
+ // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position
150
+ // this prevents the handler from being dispatched the same way as mouseover or mouseout does
151
+ if (originalTypeEvent in customEvents) {
152
+ const wrapFunction = fn => {
153
+ return function (event) {
154
+ if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {
155
+ return fn.call(this, event)
156
+ }
157
+ }
158
+ }
159
+
160
+ callable = wrapFunction(callable)
161
+ }
162
+
163
+ const events = getElementEvents(element)
164
+ const handlers = events[typeEvent] || (events[typeEvent] = {})
165
+ const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)
166
+
167
+ if (previousFunction) {
168
+ previousFunction.oneOff = previousFunction.oneOff && oneOff
169
+
170
+ return
171
+ }
172
+
173
+ const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))
174
+ const fn = isDelegated ?
175
+ bootstrapDelegationHandler(element, handler, callable) :
176
+ bootstrapHandler(element, callable)
177
+
178
+ fn.delegationSelector = isDelegated ? handler : null
179
+ fn.callable = callable
180
+ fn.oneOff = oneOff
181
+ fn.uidEvent = uid
182
+ handlers[uid] = fn
183
+
184
+ element.addEventListener(typeEvent, fn, isDelegated)
185
+ }
186
+
187
+ function removeHandler(element, events, typeEvent, handler, delegationSelector) {
188
+ const fn = findHandler(events[typeEvent], handler, delegationSelector)
189
+
190
+ if (!fn) {
191
+ return
192
+ }
193
+
194
+ element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))
195
+ delete events[typeEvent][fn.uidEvent]
196
+ }
197
+
198
+ function removeNamespacedHandlers(element, events, typeEvent, namespace) {
199
+ const storeElementEvent = events[typeEvent] || {}
200
+
201
+ for (const [handlerKey, event] of Object.entries(storeElementEvent)) {
202
+ if (handlerKey.includes(namespace)) {
203
+ removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)
204
+ }
205
+ }
206
+ }
207
+
208
+ function getTypeEvent(event) {
209
+ // allow to get the native events from namespaced events ('click.bs.button' --> 'click')
210
+ event = event.replace(stripNameRegex, '')
211
+ return customEvents[event] || event
212
+ }
213
+
214
+ function hydrateObj(obj, meta = {}) {
215
+ for (const [key, value] of Object.entries(meta)) {
216
+ try {
217
+ obj[key] = value
218
+ } catch {
219
+ Object.defineProperty(obj, key, {
220
+ configurable: true,
221
+ get() {
222
+ return value
223
+ }
224
+ })
225
+ }
226
+ }
227
+
228
+ return obj
229
+ }
230
+
231
+ /**
232
+ * События
233
+ * @type {{one(*, *, *, *): void, trigger(*, *, *): (null|*), off(*, *, *, *): void, on(*, *, *, *): void}}
234
+ */
235
+ const EventHandler = {
236
+ /**
237
+ * Прослушиватель событий (элемент, событие (полный список смотри в константе nativeEvents, источник события или хендлер, функция обратного вызова))
238
+ * @param element
239
+ * @param event
240
+ * @param handler
241
+ * @param delegationFunction
242
+ */
243
+ on(element, event, handler, delegationFunction) {
244
+ addHandler(element, event, handler, delegationFunction, false)
245
+ },
246
+
247
+ /**
248
+ * Прослушиватель событий, но замыкается и больше не повторяется на элементе
249
+ * @param element
250
+ * @param event
251
+ * @param handler
252
+ * @param delegationFunction
253
+ */
254
+ one(element, event, handler, delegationFunction) {
255
+ addHandler(element, event, handler, delegationFunction, true)
256
+ },
257
+
258
+ /**
259
+ * Удаление обработчика
260
+ * @param element
261
+ * @param originalTypeEvent
262
+ * @param handler
263
+ * @param delegationFunction
264
+ */
265
+ off(element, originalTypeEvent, handler, delegationFunction) {
266
+ if (typeof originalTypeEvent !== 'string' || !element) {
267
+ return
268
+ }
269
+
270
+ const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)
271
+ const inNamespace = typeEvent !== originalTypeEvent
272
+ const events = getElementEvents(element)
273
+ const storeElementEvent = events[typeEvent] || {}
274
+ const isNamespace = originalTypeEvent.startsWith('.')
275
+
276
+ if (typeof callable !== 'undefined') {
277
+ // Simplest case: handler is passed, remove that listener ONLY.
278
+ if (!Object.keys(storeElementEvent).length) {
279
+ return
280
+ }
281
+
282
+ removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)
283
+ return
284
+ }
285
+
286
+ if (isNamespace) {
287
+ for (const elementEvent of Object.keys(events)) {
288
+ removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))
289
+ }
290
+ }
291
+
292
+ for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {
293
+ const handlerKey = keyHandlers.replace(stripUidRegex, '')
294
+
295
+ if (!inNamespace || originalTypeEvent.includes(handlerKey)) {
296
+ removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)
297
+ }
298
+ }
299
+ },
300
+
301
+ /**
302
+ * Пользовательские события. Подробнее тут https://learn.javascript.ru/dispatch-events
303
+ * @param element
304
+ * @param event
305
+ * @param args
306
+ * @returns {*|null}
307
+ */
308
+ trigger(element, event, args) {
309
+ if (typeof event !== 'string' || !element) {
310
+ return null
311
+ }
312
+
313
+ let bubbles = true;
314
+ let nativeDispatch = true;
315
+ let defaultPrevented = false;
316
+
317
+ const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)
318
+
319
+ if (defaultPrevented) {
320
+ evt.preventDefault()
321
+ }
322
+
323
+ if (nativeDispatch) {
324
+ element.dispatchEvent(evt)
325
+ }
326
+
327
+ return evt
328
+ }
329
+ }
330
+
331
+ export default EventHandler
@@ -0,0 +1,62 @@
1
+ import {isElement, normalizeData} from "../functions";
2
+
3
+ /**
4
+ * Манипуляции с атрибутами у элемента:
5
+ * get (элемент, имя, флаг - вырезать data-) - метод выбирает значение атрибута по его имени, если в поле имени передать 'data' -> будут выбраны только дата атрибуты, если 'all' -> метод вернет значение всех атрибутов
6
+ * has (элемент, имя) - есть ли атрибут у элемента
7
+ * set (элемент, имя, значение) - установка у элемента атрибута или его изменение
8
+ * remove (элемент, имя) - удаляет атрибут у элемента
9
+ */
10
+ const Manipulator = {
11
+ get(element, nameAttribute = 'data', isRemoveDataName = true) {
12
+ if (!element) {
13
+ return {}
14
+ }
15
+
16
+ if (nameAttribute === 'data') {
17
+ let elmBase = ['data-vg-toggle', 'data-vg-target', 'data-vg-dismiss'],
18
+ attributes = {};
19
+
20
+ let arr = [].filter.call(element.attributes, function (at) {
21
+ return /^data-/.test(at.name);
22
+ });
23
+
24
+ if (arr.length) {
25
+ arr.forEach(function (v) {
26
+ let name = v.name;
27
+
28
+ if (!elmBase.includes(name)) {
29
+ if (isRemoveDataName) name = name.slice(5);
30
+ attributes[name] = normalizeData(v.value)
31
+ }
32
+ });
33
+ }
34
+
35
+ return attributes;
36
+ } else if (nameAttribute === 'all') {
37
+ return element.getAttributeNames().reduce((acc, name) => {
38
+ return {...acc, [name]: element.getAttribute(name)};
39
+ }, {});
40
+ } else {
41
+ return element.getAttribute(nameAttribute);
42
+ }
43
+ },
44
+
45
+ has(element, nameAttribute) {
46
+ return element.hasAttribute(nameAttribute);
47
+ },
48
+
49
+ set(element, name, value) {
50
+ if (isElement(element) && name) {
51
+ element.setAttribute(name, value);
52
+ }
53
+ },
54
+
55
+ remove(element, nameAttribute) {
56
+ if (isElement(element) && nameAttribute) {
57
+ element.removeAttribute(nameAttribute);
58
+ }
59
+ }
60
+ }
61
+
62
+ export {Manipulator}