@gitlab/ui 49.0.1 → 49.0.3
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 +14 -0
- package/dist/components/base/accordion/accordion.js +2 -8
- package/dist/components/base/accordion/accordion_item.js +0 -14
- package/dist/components/base/alert/alert.js +4 -22
- package/dist/components/base/avatar/avatar.js +0 -7
- package/dist/components/base/avatar_labeled/avatar_labeled.js +0 -2
- package/dist/components/base/avatars_inline/avatars_inline.js +2 -10
- package/dist/components/base/badge/badge.js +0 -8
- package/dist/components/base/banner/banner.js +0 -10
- package/dist/components/base/breadcrumb/breadcrumb.js +0 -12
- package/dist/components/base/breadcrumb/breadcrumb_item.js +0 -2
- package/dist/components/base/broadcast_message/broadcast_message.js +0 -3
- package/dist/components/base/button/button.js +0 -11
- package/dist/components/base/card/card.js +1 -2
- package/dist/components/base/datepicker/datepicker.js +7 -42
- package/dist/components/base/daterange_picker/daterange_picker.js +0 -23
- package/dist/components/base/drawer/drawer.js +0 -13
- package/dist/components/base/dropdown/dropdown.js +3 -17
- package/dist/components/base/dropdown/dropdown_item.js +2 -8
- package/dist/components/base/filtered_search/common_story_options.js +1 -2
- package/dist/components/base/filtered_search/filtered_search.js +9 -61
- package/dist/components/base/filtered_search/filtered_search_suggestion.js +0 -6
- package/dist/components/base/filtered_search/filtered_search_suggestion_list.js +0 -16
- package/dist/components/base/filtered_search/filtered_search_term.js +0 -9
- package/dist/components/base/filtered_search/filtered_search_token.js +10 -49
- package/dist/components/base/filtered_search/filtered_search_token_segment.js +3 -56
- package/dist/components/base/filtered_search/filtered_search_utils.js +7 -24
- package/dist/components/base/form/form_checkbox/form_checkbox.js +0 -2
- package/dist/components/base/form/form_checkbox_tree/checkbox_tree_node.js +0 -4
- package/dist/components/base/form/form_checkbox_tree/form_checkbox_tree.js +0 -10
- package/dist/components/base/form/form_checkbox_tree/models/node.js +1 -10
- package/dist/components/base/form/form_checkbox_tree/models/tree.js +16 -37
- package/dist/components/base/form/form_combobox/form_combobox.js +2 -36
- package/dist/components/base/form/form_group/form_group.js +2 -7
- package/dist/components/base/form/form_input/form_input.js +2 -8
- package/dist/components/base/form/form_input_group/form_input_group.js +0 -5
- package/dist/components/base/form/form_input_group/form_input_group_mixin.js +0 -8
- package/dist/components/base/form/form_radio_group/form_radio_group.js +0 -2
- package/dist/components/base/form/form_select/form_select.js +0 -3
- package/dist/components/base/form/form_textarea/form_textarea.js +2 -7
- package/dist/components/base/icon/icon.js +4 -14
- package/dist/components/base/infinite_scroll/infinite_scroll.js +7 -21
- package/dist/components/base/keyset_pagination/keyset_pagination.js +0 -9
- package/dist/components/base/label/label.js +0 -12
- package/dist/components/base/loading_icon/loading_icon.js +7 -10
- package/dist/components/base/markdown/markdown.js +1 -0
- package/dist/components/base/modal/modal.js +7 -27
- package/dist/components/base/new_dropdowns/base_dropdown/base_dropdown.js +0 -25
- package/dist/components/base/new_dropdowns/constants.js +4 -2
- package/dist/components/base/new_dropdowns/listbox/listbox.js +0 -63
- package/dist/components/base/new_dropdowns/listbox/listbox_group.js +0 -2
- package/dist/components/base/new_dropdowns/listbox/listbox_item.js +0 -5
- package/dist/components/base/new_dropdowns/listbox/utils.js +0 -7
- package/dist/components/base/paginated_list/paginated_list.js +0 -15
- package/dist/components/base/pagination/pagination.js +14 -72
- package/dist/components/base/path/path.js +0 -29
- package/dist/components/base/popover/popover.js +0 -5
- package/dist/components/base/search_box_by_click/search_box_by_click.js +1 -26
- package/dist/components/base/search_box_by_type/search_box_by_type.js +2 -12
- package/dist/components/base/segmented_control/segmented_control.js +0 -10
- package/dist/components/base/skeleton_loader/skeleton_loader.js +0 -19
- package/dist/components/base/skeleton_loading/skeleton_loading.js +0 -3
- package/dist/components/base/sorting/sorting.js +1 -9
- package/dist/components/base/sorting/sorting_item.js +4 -6
- package/dist/components/base/table/table.js +0 -4
- package/dist/components/base/tabs/tab/tab.js +2 -6
- package/dist/components/base/tabs/tabs/scrollable_tabs.js +0 -21
- package/dist/components/base/tabs/tabs/tabs.js +8 -33
- package/dist/components/base/toast/toast.js +4 -15
- package/dist/components/base/toggle/toggle.js +0 -18
- package/dist/components/base/token/token.js +0 -4
- package/dist/components/base/token_selector/token_container.js +0 -24
- package/dist/components/base/token_selector/token_selector.js +10 -61
- package/dist/components/base/token_selector/token_selector_dropdown.js +4 -32
- package/dist/components/charts/area/area.js +8 -32
- package/dist/components/charts/bar/bar.js +7 -19
- package/dist/components/charts/chart/chart.js +1 -22
- package/dist/components/charts/column/column.js +8 -18
- package/dist/components/charts/discrete_scatter/discrete_scatter.js +2 -13
- package/dist/components/charts/gauge/gauge.js +0 -15
- package/dist/components/charts/heatmap/heatmap.js +3 -16
- package/dist/components/charts/legend/legend.js +2 -24
- package/dist/components/charts/line/line.js +8 -34
- package/dist/components/charts/series_label/series_label.js +0 -12
- package/dist/components/charts/single_stat/single_stat.js +0 -8
- package/dist/components/charts/sparkline/sparkline.js +1 -16
- package/dist/components/charts/stacked_column/stacked_column.js +8 -26
- package/dist/components/charts/tooltip/tooltip.js +0 -6
- package/dist/components/mixins/button_mixin.js +0 -1
- package/dist/components/mixins/safe_link_mixin.js +0 -1
- package/dist/components/mixins/toolbox_mixin.js +0 -1
- package/dist/components/mixins/tooltip_mixin.js +1 -2
- package/dist/components/regions/empty_state/empty_state.js +0 -12
- package/dist/components/utilities/animated_number/animated_number.js +0 -16
- package/dist/components/utilities/friendly_wrap/friendly_wrap.js +0 -3
- package/dist/components/utilities/intersection_observer/intersection_observer.js +0 -7
- package/dist/components/utilities/intersperse/intersperse.js +3 -9
- package/dist/components/utilities/sprintf/sprintf.js +9 -23
- package/dist/components/utilities/truncate/truncate.js +0 -10
- package/dist/config.js +3 -4
- package/dist/directives/hover_load/hover_load.js +2 -8
- package/dist/directives/outside/get_event_like_time_stamp.js +4 -2
- package/dist/directives/outside/outside.js +5 -20
- package/dist/directives/resize_observer/resize_observer.js +0 -10
- package/dist/directives/safe_html/safe_html.js +5 -6
- package/dist/directives/safe_link/mock_data.js +1 -1
- package/dist/directives/safe_link/safe_link.js +0 -13
- package/dist/utils/breakpoints.js +0 -3
- package/dist/utils/charts/config.js +29 -42
- package/dist/utils/charts/constants.js +8 -8
- package/dist/utils/charts/mock_data.js +2 -2
- package/dist/utils/charts/story_config.js +1 -1
- package/dist/utils/charts/theme.js +1 -3
- package/dist/utils/charts/utils.js +2 -6
- package/dist/utils/constants.js +10 -7
- package/dist/utils/data_utils.js +5 -4
- package/dist/utils/datetime_utility.js +4 -4
- package/dist/utils/number_utils.js +7 -11
- package/dist/utils/stories_utils.js +1 -1
- package/dist/utils/story_decorators/container.js +0 -1
- package/dist/utils/string_utils.js +0 -14
- package/dist/utils/test_utils.js +3 -2
- package/dist/utils/use_fake_date.js +0 -4
- package/dist/utils/use_mock_intersection_observer.js +4 -19
- package/dist/utils/utils.js +5 -14
- package/package.json +3 -3
- package/src/components/base/pagination/pagination.vue +2 -2
- package/src/components/base/toast/toast.js +1 -0
|
@@ -7,7 +7,6 @@ const SUFFIX = '}';
|
|
|
7
7
|
const START_SUFFIX = 'Start';
|
|
8
8
|
const END_SUFFIX = 'End';
|
|
9
9
|
const PLACE_HOLDER_REGEX = new RegExp(`(${PREFIX}[a-z]+[\\w-]*[a-z0-9]+${SUFFIX})`, 'gi');
|
|
10
|
-
|
|
11
10
|
function groupPlaceholdersByStartTag() {
|
|
12
11
|
let placeholders = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
13
12
|
return Object.entries(placeholders).reduce((acc, _ref) => {
|
|
@@ -19,17 +18,15 @@ function groupPlaceholdersByStartTag() {
|
|
|
19
18
|
return acc;
|
|
20
19
|
}, {});
|
|
21
20
|
}
|
|
22
|
-
|
|
23
21
|
function getPlaceholderDefinition(chunk, placeholdersByStartTag) {
|
|
24
22
|
const tagName = chunk.slice(PREFIX.length, -SUFFIX.length);
|
|
25
|
-
|
|
26
23
|
if (_has(placeholdersByStartTag, tagName)) {
|
|
27
24
|
// Use provided custom placeholder definition
|
|
28
|
-
return {
|
|
25
|
+
return {
|
|
26
|
+
...placeholdersByStartTag[tagName],
|
|
29
27
|
tagName
|
|
30
28
|
};
|
|
31
29
|
}
|
|
32
|
-
|
|
33
30
|
if (tagName.endsWith(START_SUFFIX)) {
|
|
34
31
|
// Tag conforms to default start/end tag naming convention
|
|
35
32
|
const slotName = tagName.slice(0, -START_SUFFIX.length);
|
|
@@ -39,14 +36,12 @@ function getPlaceholderDefinition(chunk, placeholdersByStartTag) {
|
|
|
39
36
|
tagName
|
|
40
37
|
};
|
|
41
38
|
}
|
|
42
|
-
|
|
43
39
|
return {
|
|
44
40
|
slotName: tagName,
|
|
45
41
|
endTag: undefined,
|
|
46
42
|
tagName
|
|
47
43
|
};
|
|
48
44
|
}
|
|
49
|
-
|
|
50
45
|
var script = {
|
|
51
46
|
functional: true,
|
|
52
47
|
props: {
|
|
@@ -57,7 +52,6 @@ var script = {
|
|
|
57
52
|
type: String,
|
|
58
53
|
required: true
|
|
59
54
|
},
|
|
60
|
-
|
|
61
55
|
/**
|
|
62
56
|
* An object mapping slot names to custom start/end placeholders. Use this
|
|
63
57
|
* to avoid changing an existing message, and in turn invalidating existing
|
|
@@ -70,7 +64,6 @@ var script = {
|
|
|
70
64
|
validator: value => Object.values(value).every(tagPair => Array.isArray(tagPair) && tagPair.length === 2 && tagPair.every(_isString))
|
|
71
65
|
}
|
|
72
66
|
},
|
|
73
|
-
|
|
74
67
|
/**
|
|
75
68
|
* Available slots are determined by the placeholders in the provided
|
|
76
69
|
* message prop. For example, a message of "Written by %{author}" has
|
|
@@ -88,61 +81,54 @@ var script = {
|
|
|
88
81
|
// This approach is also more performant, as it minimizes (relatively) object
|
|
89
82
|
// creation/garbage collection, which is important given how frequently this
|
|
90
83
|
// code may run on a given page.
|
|
84
|
+
|
|
91
85
|
let i = 0;
|
|
92
86
|
const vnodes = [];
|
|
93
87
|
const slots = context.scopedSlots;
|
|
94
88
|
const chunks = context.props.message.split(PLACE_HOLDER_REGEX);
|
|
95
89
|
const placeholdersByStartTag = groupPlaceholdersByStartTag(context.props.placeholders);
|
|
96
|
-
|
|
97
90
|
while (i < chunks.length) {
|
|
98
|
-
const chunk = chunks[i];
|
|
99
|
-
|
|
91
|
+
const chunk = chunks[i];
|
|
92
|
+
// Skip past this chunk now we have it
|
|
100
93
|
i += 1;
|
|
101
|
-
|
|
102
94
|
if (!PLACE_HOLDER_REGEX.test(chunk)) {
|
|
103
95
|
// Not a placeholder, so pass through as-is
|
|
104
96
|
vnodes.push(chunk);
|
|
105
97
|
continue;
|
|
106
98
|
}
|
|
107
|
-
|
|
108
99
|
const {
|
|
109
100
|
slotName,
|
|
110
101
|
endTag,
|
|
111
102
|
tagName
|
|
112
103
|
} = getPlaceholderDefinition(chunk, placeholdersByStartTag);
|
|
113
|
-
|
|
114
104
|
if (endTag) {
|
|
115
105
|
// Peek ahead to find end placeholder, if any
|
|
116
106
|
const indexOfEnd = chunks.indexOf(`${PREFIX}${endTag}${SUFFIX}`, i);
|
|
117
|
-
|
|
118
107
|
if (indexOfEnd > -1) {
|
|
119
108
|
// We have a valid start/end placeholder pair! Extract the content
|
|
120
109
|
// between them and skip past the end placeholder
|
|
121
110
|
const content = chunks.slice(i, indexOfEnd);
|
|
122
111
|
i = indexOfEnd + 1;
|
|
123
|
-
|
|
124
112
|
if (!_has(slots, slotName)) {
|
|
125
113
|
// Slot hasn't been provided; return placeholders and content as-is
|
|
126
114
|
vnodes.push(chunk, ...content, chunks[indexOfEnd]);
|
|
127
115
|
continue;
|
|
128
|
-
}
|
|
129
|
-
|
|
116
|
+
}
|
|
130
117
|
|
|
118
|
+
// Provide content to provided scoped slot
|
|
131
119
|
vnodes.push(slots[slotName]({
|
|
132
120
|
content: content.join('')
|
|
133
121
|
}));
|
|
134
122
|
continue;
|
|
135
123
|
}
|
|
136
|
-
}
|
|
137
|
-
|
|
124
|
+
}
|
|
138
125
|
|
|
126
|
+
// By process of elimination, chunk must be a plain placeholder
|
|
139
127
|
vnodes.push(_has(slots, tagName) ? slots[tagName]() : chunk);
|
|
140
128
|
continue;
|
|
141
129
|
}
|
|
142
|
-
|
|
143
130
|
return vnodes;
|
|
144
131
|
}
|
|
145
|
-
|
|
146
132
|
};
|
|
147
133
|
|
|
148
134
|
/* script */
|
|
@@ -18,7 +18,6 @@ var script = {
|
|
|
18
18
|
type: String,
|
|
19
19
|
required: true
|
|
20
20
|
},
|
|
21
|
-
|
|
22
21
|
/**
|
|
23
22
|
* Ellipsis position
|
|
24
23
|
*/
|
|
@@ -28,7 +27,6 @@ var script = {
|
|
|
28
27
|
default: POSITION.END,
|
|
29
28
|
validator: value => Object.values(POSITION).includes(value)
|
|
30
29
|
},
|
|
31
|
-
|
|
32
30
|
/**
|
|
33
31
|
* Display the full text in a tooltip only if it is being truncated
|
|
34
32
|
*/
|
|
@@ -38,30 +36,24 @@ var script = {
|
|
|
38
36
|
default: false
|
|
39
37
|
}
|
|
40
38
|
},
|
|
41
|
-
|
|
42
39
|
data() {
|
|
43
40
|
return {
|
|
44
41
|
isTruncated: false
|
|
45
42
|
};
|
|
46
43
|
},
|
|
47
|
-
|
|
48
44
|
computed: {
|
|
49
45
|
middleIndex() {
|
|
50
46
|
return Math.floor(this.text.length / 2);
|
|
51
47
|
},
|
|
52
|
-
|
|
53
48
|
first() {
|
|
54
49
|
return this.text.slice(0, this.middleIndex);
|
|
55
50
|
},
|
|
56
|
-
|
|
57
51
|
last() {
|
|
58
52
|
return this.text.slice(this.middleIndex);
|
|
59
53
|
},
|
|
60
|
-
|
|
61
54
|
isTooltipDisabled() {
|
|
62
55
|
return !this.withTooltip || !this.isTruncated;
|
|
63
56
|
}
|
|
64
|
-
|
|
65
57
|
},
|
|
66
58
|
watch: {
|
|
67
59
|
withTooltip(withTooltip) {
|
|
@@ -69,7 +61,6 @@ var script = {
|
|
|
69
61
|
this.checkTruncationState();
|
|
70
62
|
}
|
|
71
63
|
}
|
|
72
|
-
|
|
73
64
|
},
|
|
74
65
|
methods: {
|
|
75
66
|
checkTruncationState() {
|
|
@@ -77,7 +68,6 @@ var script = {
|
|
|
77
68
|
this.isTruncated = this.$refs.text.scrollWidth > this.$refs.text.offsetWidth;
|
|
78
69
|
}
|
|
79
70
|
}
|
|
80
|
-
|
|
81
71
|
}
|
|
82
72
|
};
|
|
83
73
|
|
package/dist/config.js
CHANGED
|
@@ -9,6 +9,7 @@ const tooltipGlobalConfig = {
|
|
|
9
9
|
customClass: 'gl-tooltip',
|
|
10
10
|
delay: tooltipDelay
|
|
11
11
|
};
|
|
12
|
+
|
|
12
13
|
/**
|
|
13
14
|
* Guard against nonexistent localStorage,
|
|
14
15
|
* or corrupted localStorage
|
|
@@ -17,16 +18,14 @@ const tooltipGlobalConfig = {
|
|
|
17
18
|
* - in iframe usage in Chrome if embedded on another domain
|
|
18
19
|
* - tests / node
|
|
19
20
|
*/
|
|
20
|
-
|
|
21
21
|
try {
|
|
22
22
|
const glTooltipDelay = localStorage.getItem('gl-tooltip-delay');
|
|
23
|
-
|
|
24
23
|
if (glTooltipDelay) {
|
|
25
24
|
tooltipGlobalConfig.delay = JSON.parse(glTooltipDelay);
|
|
26
25
|
}
|
|
27
|
-
} catch (e) {
|
|
26
|
+
} catch (e) {
|
|
27
|
+
// localStorage doesn't exist (or the value is not properly formatted)
|
|
28
28
|
}
|
|
29
|
-
|
|
30
29
|
const setConfigs = () => {
|
|
31
30
|
Vue.use(BVConfigPlugin, {
|
|
32
31
|
BFormText: bFormTextGlobalConfig,
|
|
@@ -3,46 +3,40 @@ import isFunction from 'lodash/isFunction';
|
|
|
3
3
|
const DELAY_ON_HOVER = 100;
|
|
4
4
|
let mouseOverTimer;
|
|
5
5
|
let mouseOverHandler;
|
|
6
|
-
|
|
7
6
|
const bind = (el, _ref) => {
|
|
8
7
|
let {
|
|
9
8
|
value: loadHandler
|
|
10
9
|
} = _ref;
|
|
11
|
-
|
|
12
10
|
if (!isFunction(loadHandler)) {
|
|
13
11
|
throw TypeError('Directive value must be a function');
|
|
14
12
|
}
|
|
15
|
-
|
|
16
13
|
const mouseOutHandler = () => {
|
|
17
14
|
if (mouseOverTimer) {
|
|
18
15
|
clearTimeout(mouseOverTimer);
|
|
19
16
|
mouseOverTimer = undefined;
|
|
20
17
|
}
|
|
21
18
|
};
|
|
22
|
-
|
|
23
19
|
mouseOverHandler = () => {
|
|
24
20
|
el.addEventListener('mouseout', mouseOutHandler, {
|
|
25
21
|
passive: true
|
|
26
22
|
});
|
|
27
23
|
mouseOverTimer = setTimeout(() => {
|
|
28
|
-
loadHandler(el);
|
|
24
|
+
loadHandler(el);
|
|
29
25
|
|
|
26
|
+
// Only execute once
|
|
30
27
|
el.removeEventListener('mouseover', mouseOverHandler, true);
|
|
31
28
|
el.removeEventListener('mouseout', mouseOutHandler);
|
|
32
29
|
mouseOverTimer = undefined;
|
|
33
30
|
}, DELAY_ON_HOVER);
|
|
34
31
|
};
|
|
35
|
-
|
|
36
32
|
el.addEventListener('mouseover', mouseOverHandler, {
|
|
37
33
|
capture: true,
|
|
38
34
|
passive: true
|
|
39
35
|
});
|
|
40
36
|
};
|
|
41
|
-
|
|
42
37
|
const unbind = el => {
|
|
43
38
|
el.removeEventListener('mouseover', mouseOverHandler, true);
|
|
44
39
|
};
|
|
45
|
-
|
|
46
40
|
const HoverLoadDirective = {
|
|
47
41
|
bind,
|
|
48
42
|
unbind
|
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
*
|
|
5
5
|
* See the LICENSE file in this directory.
|
|
6
6
|
*/
|
|
7
|
+
|
|
7
8
|
const {
|
|
8
9
|
performance
|
|
9
10
|
} = window;
|
|
11
|
+
|
|
10
12
|
/**
|
|
11
13
|
* Get a current timestamp that can be meaningfully compared to an event's
|
|
12
14
|
* `timeStamp` property.
|
|
@@ -22,8 +24,8 @@ const {
|
|
|
22
24
|
*
|
|
23
25
|
* @returns {number}
|
|
24
26
|
*/
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
const getEventLikeTimeStamp =
|
|
28
|
+
// If the event timestamp, although evaluated AFTER the Date.now(), is
|
|
27
29
|
// smaller, it means the event is using a hi-res timestamp, and we need to
|
|
28
30
|
// use the hi-res version for event listener timestamps as well.
|
|
29
31
|
typeof (performance === null || performance === void 0 ? void 0 : performance.now) === 'function' && Date.now() > document.createEvent('Event').timeStamp ? () => performance.now() : () => Date.now();
|
|
@@ -3,27 +3,25 @@ import { getEventLikeTimeStamp } from './get_event_like_time_stamp';
|
|
|
3
3
|
/**
|
|
4
4
|
* Map<HTMLElement, { bindTimeStamp: number, callback: Function }>
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
6
|
const callbacks = new Map();
|
|
7
|
+
|
|
8
8
|
/**
|
|
9
9
|
* Is a global listener already set up?
|
|
10
10
|
*/
|
|
11
|
-
|
|
12
11
|
let listening = false;
|
|
13
|
-
|
|
14
12
|
const globalListener = event => {
|
|
15
13
|
callbacks.forEach((_ref, element) => {
|
|
16
14
|
let {
|
|
17
15
|
bindTimeStamp,
|
|
18
16
|
callback
|
|
19
17
|
} = _ref;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
element.contains(event.target) ||
|
|
18
|
+
if (
|
|
19
|
+
// Ignore events that aren't targeted outside the element
|
|
20
|
+
element.contains(event.target) ||
|
|
21
|
+
// Only consider events triggered after the directive was bound
|
|
23
22
|
event.timeStamp <= bindTimeStamp) {
|
|
24
23
|
return;
|
|
25
24
|
}
|
|
26
|
-
|
|
27
25
|
try {
|
|
28
26
|
callback(event);
|
|
29
27
|
} catch (e) {
|
|
@@ -34,41 +32,33 @@ const globalListener = event => {
|
|
|
34
32
|
}
|
|
35
33
|
});
|
|
36
34
|
};
|
|
37
|
-
|
|
38
35
|
const startListening = () => {
|
|
39
36
|
if (listening) {
|
|
40
37
|
return;
|
|
41
38
|
}
|
|
42
|
-
|
|
43
39
|
document.addEventListener('click', globalListener, {
|
|
44
40
|
capture: true
|
|
45
41
|
});
|
|
46
42
|
listening = true;
|
|
47
43
|
};
|
|
48
|
-
|
|
49
44
|
const stopListening = () => {
|
|
50
45
|
if (!listening) {
|
|
51
46
|
return;
|
|
52
47
|
}
|
|
53
|
-
|
|
54
48
|
document.removeEventListener('click', globalListener);
|
|
55
49
|
listening = false;
|
|
56
50
|
};
|
|
57
|
-
|
|
58
51
|
const bind = (el, _ref2) => {
|
|
59
52
|
let {
|
|
60
53
|
value,
|
|
61
54
|
arg = 'click'
|
|
62
55
|
} = _ref2;
|
|
63
|
-
|
|
64
56
|
if (typeof value !== 'function') {
|
|
65
57
|
throw new Error(`[GlOutsideDirective] Value must be a function; got ${typeof value}!`);
|
|
66
58
|
}
|
|
67
|
-
|
|
68
59
|
if (arg !== 'click') {
|
|
69
60
|
throw new Error(`[GlOutsideDirective] Cannot bind ${arg} events; only click events are currently supported!`);
|
|
70
61
|
}
|
|
71
|
-
|
|
72
62
|
if (callbacks.has(el)) {
|
|
73
63
|
// This element is already bound. This is possible if two components, which
|
|
74
64
|
// share the same root node, (i.e., one is a higher-order component
|
|
@@ -81,25 +71,20 @@ const bind = (el, _ref2) => {
|
|
|
81
71
|
// element.
|
|
82
72
|
return;
|
|
83
73
|
}
|
|
84
|
-
|
|
85
74
|
if (!listening) {
|
|
86
75
|
startListening();
|
|
87
76
|
}
|
|
88
|
-
|
|
89
77
|
callbacks.set(el, {
|
|
90
78
|
bindTimeStamp: getEventLikeTimeStamp(),
|
|
91
79
|
callback: value
|
|
92
80
|
});
|
|
93
81
|
};
|
|
94
|
-
|
|
95
82
|
const unbind = el => {
|
|
96
83
|
callbacks.delete(el);
|
|
97
|
-
|
|
98
84
|
if (callbacks.size === 0) {
|
|
99
85
|
stopListening();
|
|
100
86
|
}
|
|
101
87
|
};
|
|
102
|
-
|
|
103
88
|
const OutsideDirective = {
|
|
104
89
|
bind,
|
|
105
90
|
unbind
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import isFunction from 'lodash/isFunction';
|
|
2
2
|
|
|
3
3
|
let observer = null;
|
|
4
|
-
|
|
5
4
|
const attachObserver = (el, resizeHandler) => {
|
|
6
5
|
if (!isFunction(resizeHandler)) {
|
|
7
6
|
throw TypeError('directive value must be a function');
|
|
8
7
|
}
|
|
9
|
-
|
|
10
8
|
if (!observer) {
|
|
11
9
|
// the observer instance is shared for performance reasons
|
|
12
10
|
// more information: https://github.com/WICG/ResizeObserver/issues/59
|
|
@@ -16,45 +14,37 @@ const attachObserver = (el, resizeHandler) => {
|
|
|
16
14
|
});
|
|
17
15
|
});
|
|
18
16
|
}
|
|
19
|
-
|
|
20
17
|
el.glResizeHandler = resizeHandler;
|
|
21
18
|
observer.observe(el);
|
|
22
19
|
};
|
|
23
|
-
|
|
24
20
|
const detachObserver = el => {
|
|
25
21
|
if (el.glResizeHandler) {
|
|
26
22
|
var _observer;
|
|
27
|
-
|
|
28
23
|
delete el.glResizeHandler;
|
|
29
24
|
(_observer = observer) === null || _observer === void 0 ? void 0 : _observer.unobserve(el);
|
|
30
25
|
}
|
|
31
26
|
};
|
|
32
|
-
|
|
33
27
|
const GlResizeObserverDirective = {
|
|
34
28
|
bind(el, _ref) {
|
|
35
29
|
let {
|
|
36
30
|
value: resizeHandler,
|
|
37
31
|
arg: enabled = true
|
|
38
32
|
} = _ref;
|
|
39
|
-
|
|
40
33
|
if (enabled) {
|
|
41
34
|
attachObserver(el, resizeHandler);
|
|
42
35
|
}
|
|
43
36
|
},
|
|
44
|
-
|
|
45
37
|
update(el, _ref2) {
|
|
46
38
|
let {
|
|
47
39
|
value: resizeHandler,
|
|
48
40
|
arg: enabled = true
|
|
49
41
|
} = _ref2;
|
|
50
|
-
|
|
51
42
|
if (enabled) {
|
|
52
43
|
attachObserver(el, resizeHandler);
|
|
53
44
|
} else {
|
|
54
45
|
detachObserver(el);
|
|
55
46
|
}
|
|
56
47
|
},
|
|
57
|
-
|
|
58
48
|
unbind: detachObserver
|
|
59
49
|
};
|
|
60
50
|
|
|
@@ -3,30 +3,29 @@ import { forbiddenDataAttrs } from './constants';
|
|
|
3
3
|
|
|
4
4
|
const {
|
|
5
5
|
sanitize
|
|
6
|
-
} = DOMPurify;
|
|
6
|
+
} = DOMPurify;
|
|
7
|
+
|
|
8
|
+
// Mitigate against future dompurify mXSS bypasses by
|
|
7
9
|
// avoiding additional serialize/parse round trip.
|
|
8
10
|
// See https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/1782
|
|
9
11
|
// and https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/2127
|
|
10
12
|
// for more details.
|
|
11
|
-
|
|
12
13
|
const DEFAULT_CONFIG = {
|
|
13
14
|
RETURN_DOM_FRAGMENT: true,
|
|
14
15
|
ALLOW_UNKNOWN_PROTOCOLS: true,
|
|
15
16
|
FORBID_ATTR: [...forbiddenDataAttrs]
|
|
16
17
|
};
|
|
17
|
-
|
|
18
18
|
const transform = (el, binding) => {
|
|
19
19
|
if (binding.oldValue !== binding.value) {
|
|
20
20
|
var _binding$arg;
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
const config = {
|
|
22
|
+
...DEFAULT_CONFIG,
|
|
23
23
|
...((_binding$arg = binding.arg) !== null && _binding$arg !== void 0 ? _binding$arg : {})
|
|
24
24
|
};
|
|
25
25
|
el.textContent = '';
|
|
26
26
|
el.appendChild(sanitize(binding.value, config));
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
|
-
|
|
30
29
|
const SafeHtmlDirective = {
|
|
31
30
|
bind: transform,
|
|
32
31
|
update: transform
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const absoluteUrls = ['http://example.org', 'http://example.org:8080', 'https://example.org', 'https://example.org:8080', 'https://192.168.1.1', 'ftp://192.168.1.1', 'mailto:someone@example.com'];
|
|
2
|
-
/* eslint-disable no-script-url */
|
|
3
2
|
|
|
3
|
+
/* eslint-disable no-script-url */
|
|
4
4
|
const javascriptUrls = ['javascript:', 'javascript:alert("XSS")', 'jav\tascript:alert("XSS");'];
|
|
5
5
|
/* eslint-disable no-script-url */
|
|
6
6
|
|
|
@@ -7,25 +7,19 @@ const getBaseURL = () => {
|
|
|
7
7
|
} = window.location;
|
|
8
8
|
return `${protocol}//${host}`;
|
|
9
9
|
};
|
|
10
|
-
|
|
11
10
|
const isExternalURL = (target, hostname) => {
|
|
12
11
|
return target === '_blank' && hostname !== window.location.hostname;
|
|
13
12
|
};
|
|
14
|
-
|
|
15
13
|
const secureRel = rel => {
|
|
16
14
|
const rels = rel ? rel.trim().split(' ') : [];
|
|
17
|
-
|
|
18
15
|
if (!rels.includes('noopener')) {
|
|
19
16
|
rels.push('noopener');
|
|
20
17
|
}
|
|
21
|
-
|
|
22
18
|
if (!rels.includes('noreferrer')) {
|
|
23
19
|
rels.push('noreferrer');
|
|
24
20
|
}
|
|
25
|
-
|
|
26
21
|
return rels.join(' ');
|
|
27
22
|
};
|
|
28
|
-
|
|
29
23
|
const isSafeURL = url => {
|
|
30
24
|
try {
|
|
31
25
|
const parsedURL = new URL(url, getBaseURL());
|
|
@@ -34,41 +28,34 @@ const isSafeURL = url => {
|
|
|
34
28
|
return false;
|
|
35
29
|
}
|
|
36
30
|
};
|
|
37
|
-
|
|
38
31
|
const transform = function (el) {
|
|
39
32
|
let {
|
|
40
33
|
arg: {
|
|
41
34
|
skipSanitization = false
|
|
42
35
|
} = {}
|
|
43
36
|
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
44
|
-
|
|
45
37
|
if (skipSanitization) {
|
|
46
38
|
return;
|
|
47
39
|
}
|
|
48
|
-
|
|
49
40
|
const {
|
|
50
41
|
href,
|
|
51
42
|
target,
|
|
52
43
|
rel,
|
|
53
44
|
hostname
|
|
54
45
|
} = el;
|
|
55
|
-
|
|
56
46
|
if (!isSafeURL(href)) {
|
|
57
47
|
el.href = 'about:blank';
|
|
58
48
|
}
|
|
59
|
-
|
|
60
49
|
if (isExternalURL(target, hostname)) {
|
|
61
50
|
el.rel = secureRel(rel);
|
|
62
51
|
}
|
|
63
52
|
};
|
|
64
|
-
|
|
65
53
|
const SafeLinkDirective = {
|
|
66
54
|
inserted: transform,
|
|
67
55
|
update: function () {
|
|
68
56
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
69
57
|
args[_key] = arguments[_key];
|
|
70
58
|
}
|
|
71
|
-
|
|
72
59
|
Vue.nextTick(() => {
|
|
73
60
|
transform(...args);
|
|
74
61
|
});
|
|
@@ -7,17 +7,14 @@ const breakpoints = {
|
|
|
7
7
|
};
|
|
8
8
|
const BreakpointInstance = {
|
|
9
9
|
windowWidth: () => window.innerWidth,
|
|
10
|
-
|
|
11
10
|
getBreakpointSize() {
|
|
12
11
|
const windowWidth = this.windowWidth();
|
|
13
12
|
const breakpoint = Object.keys(breakpoints).find(key => windowWidth > breakpoints[key]);
|
|
14
13
|
return breakpoint;
|
|
15
14
|
},
|
|
16
|
-
|
|
17
15
|
isDesktop() {
|
|
18
16
|
return ['xl', 'lg'].includes(this.getBreakpointSize());
|
|
19
17
|
}
|
|
20
|
-
|
|
21
18
|
};
|
|
22
19
|
|
|
23
20
|
export default BreakpointInstance;
|