summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Eastwood <contact@ericeastwood.com>2017-06-06 15:46:31 -0500
committerEric Eastwood <contact@ericeastwood.com>2017-06-23 02:12:45 -0500
commit6cb575d612cd2470ee4224159fa16458f5426f73 (patch)
treeda44a611e31d2f694ed8f3e55b1e45aac3703cae
parentbf0b3d835211077cb10ee3aec9ee6e0bca2304b6 (diff)
downloadgitlab-ce-6cb575d612cd2470ee4224159fa16458f5426f73.tar.gz
Add support for multiple tooltips in the same Vue component
Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/33223
-rw-r--r--app/assets/javascripts/environments/components/environment_actions.vue11
-rw-r--r--app/assets/javascripts/environments/components/environment_external_url.vue9
-rw-r--r--app/assets/javascripts/environments/components/environment_monitoring.vue9
-rw-r--r--app/assets/javascripts/environments/components/environment_stop.vue8
-rw-r--r--app/assets/javascripts/environments/components/environment_terminal_button.vue8
-rw-r--r--app/assets/javascripts/issue_show/components/fields/project_move.vue12
-rw-r--r--app/assets/javascripts/pipelines/components/async_button.vue11
-rw-r--r--app/assets/javascripts/pipelines/components/graph/action_component.vue11
-rw-r--r--app/assets/javascripts/pipelines/components/graph/dropdown_action_component.vue11
-rw-r--r--app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue12
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_component.vue14
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_url.vue16
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_actions.vue10
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_artifacts.vue12
-rw-r--r--app/assets/javascripts/pipelines/components/stage.vue10
-rw-r--r--app/assets/javascripts/pipelines/components/time_ago.vue8
-rw-r--r--app/assets/javascripts/vue_shared/components/header_ci_component.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/header.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue10
-rw-r--r--app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue8
-rw-r--r--app/assets/javascripts/vue_shared/directives/tooltip.js13
-rw-r--r--app/assets/javascripts/vue_shared/mixins/tooltip.js13
-rw-r--r--doc/development/fe_guide/style_guide_js.md12
-rw-r--r--spec/javascripts/environments/environment_actions_spec.js9
-rw-r--r--spec/javascripts/environments/environment_monitoring_spec.js19
-rw-r--r--spec/javascripts/environments/environment_stop_spec.js9
-rw-r--r--spec/javascripts/environments/environment_terminal_button_spec.js9
-rw-r--r--spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js1
-rw-r--r--spec/javascripts/vue_shared/directives/tooltip_spec.js63
30 files changed, 251 insertions, 123 deletions
diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue
index a2448520a5f..e7495677e7c 100644
--- a/app/assets/javascripts/environments/components/environment_actions.vue
+++ b/app/assets/javascripts/environments/components/environment_actions.vue
@@ -2,6 +2,7 @@
import playIconSvg from 'icons/_icon_play.svg';
import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
+import tooltip from '../../vue_shared/directives/tooltip';
export default {
props: {
@@ -12,6 +13,10 @@ export default {
},
},
+ directives: {
+ tooltip,
+ },
+
components: {
loadingIcon,
},
@@ -33,8 +38,6 @@ export default {
onClickAction(endpoint) {
this.isLoading = true;
- $(this.$refs.tooltip).tooltip('destroy');
-
eventHub.$emit('postAction', endpoint);
},
@@ -53,11 +56,11 @@ export default {
class="btn-group"
role="group">
<button
+ v-tooltip
type="button"
- class="dropdown btn btn-default dropdown-new js-dropdown-play-icon-container has-tooltip"
+ class="dropdown btn btn-default dropdown-new js-dropdown-play-icon-container"
data-container="body"
data-toggle="dropdown"
- ref="tooltip"
:title="title"
:aria-label="title"
:disabled="isLoading">
diff --git a/app/assets/javascripts/environments/components/environment_external_url.vue b/app/assets/javascripts/environments/components/environment_external_url.vue
index eaeec2bc53c..6b749814ea4 100644
--- a/app/assets/javascripts/environments/components/environment_external_url.vue
+++ b/app/assets/javascripts/environments/components/environment_external_url.vue
@@ -1,4 +1,6 @@
<script>
+import tooltip from '../../vue_shared/directives/tooltip';
+
/**
* Renders the external url link in environments table.
*/
@@ -10,6 +12,10 @@ export default {
},
},
+ directives: {
+ tooltip,
+ },
+
computed: {
title() {
return 'Open';
@@ -19,7 +25,8 @@ export default {
</script>
<template>
<a
- class="btn external-url has-tooltip"
+ v-tooltip
+ class="btn external-url"
data-container="body"
target="_blank"
rel="noopener noreferrer nofollow"
diff --git a/app/assets/javascripts/environments/components/environment_monitoring.vue b/app/assets/javascripts/environments/components/environment_monitoring.vue
index 07cf92281a0..1655561cdd3 100644
--- a/app/assets/javascripts/environments/components/environment_monitoring.vue
+++ b/app/assets/javascripts/environments/components/environment_monitoring.vue
@@ -2,6 +2,8 @@
/**
* Renders the Monitoring (Metrics) link in environments table.
*/
+import tooltip from '../../vue_shared/directives/tooltip';
+
export default {
props: {
monitoringUrl: {
@@ -10,6 +12,10 @@ export default {
},
},
+ directives: {
+ tooltip,
+ },
+
computed: {
title() {
return 'Monitoring';
@@ -19,7 +25,8 @@ export default {
</script>
<template>
<a
- class="btn monitoring-url has-tooltip hidden-xs hidden-sm"
+ v-tooltip
+ class="btn monitoring-url hidden-xs hidden-sm"
data-container="body"
rel="noopener noreferrer nofollow"
:href="monitoringUrl"
diff --git a/app/assets/javascripts/environments/components/environment_stop.vue b/app/assets/javascripts/environments/components/environment_stop.vue
index 091c543860b..85f11d2071b 100644
--- a/app/assets/javascripts/environments/components/environment_stop.vue
+++ b/app/assets/javascripts/environments/components/environment_stop.vue
@@ -5,6 +5,7 @@
*/
import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
+import tooltip from '../../vue_shared/directives/tooltip';
export default {
props: {
@@ -14,6 +15,10 @@ export default {
},
},
+ directives: {
+ tooltip,
+ },
+
data() {
return {
isLoading: false,
@@ -46,8 +51,9 @@ export default {
</script>
<template>
<button
+ v-tooltip
type="button"
- class="btn stop-env-link has-tooltip hidden-xs hidden-sm"
+ class="btn stop-env-link hidden-xs hidden-sm"
data-container="body"
@click="onClick"
:disabled="isLoading"
diff --git a/app/assets/javascripts/environments/components/environment_terminal_button.vue b/app/assets/javascripts/environments/components/environment_terminal_button.vue
index 1ca65a79951..2037bf618e3 100644
--- a/app/assets/javascripts/environments/components/environment_terminal_button.vue
+++ b/app/assets/javascripts/environments/components/environment_terminal_button.vue
@@ -4,6 +4,7 @@
* Used in environments table.
*/
import terminalIconSvg from 'icons/_icon_terminal.svg';
+import tooltip from '../../vue_shared/directives/tooltip';
export default {
props: {
@@ -14,6 +15,10 @@ export default {
},
},
+ directives: {
+ tooltip,
+ },
+
data() {
return {
terminalIconSvg,
@@ -29,7 +34,8 @@ export default {
</script>
<template>
<a
- class="btn terminal-button has-tooltip hidden-xs hidden-sm"
+ v-tooltip
+ class="btn terminal-button hidden-xs hidden-sm"
data-container="body"
:title="title"
:aria-label="title"
diff --git a/app/assets/javascripts/issue_show/components/fields/project_move.vue b/app/assets/javascripts/issue_show/components/fields/project_move.vue
index f811fb0de24..7bf2be8b28a 100644
--- a/app/assets/javascripts/issue_show/components/fields/project_move.vue
+++ b/app/assets/javascripts/issue_show/components/fields/project_move.vue
@@ -1,10 +1,10 @@
<script>
- import tooltipMixin from '../../../vue_shared/mixins/tooltip';
+ import tooltip from '../../../vue_shared/directives/tooltip';
export default {
- mixins: [
- tooltipMixin,
- ],
+ directives: {
+ tooltip,
+ },
props: {
formState: {
type: Object,
@@ -71,9 +71,9 @@
data-placeholder="Move to a different project" />
</div>
<span
+ v-tooltip
data-placement="auto top"
- title="Moving an issue will copy the discussion to a different project and close it here. All participants will be notified of the new location."
- ref="tooltip">
+ title="Moving an issue will copy the discussion to a different project and close it here. All participants will be notified of the new location.">
<i
class="fa fa-question-circle"
aria-hidden="true">
diff --git a/app/assets/javascripts/pipelines/components/async_button.vue b/app/assets/javascripts/pipelines/components/async_button.vue
index abcd0c4ecea..16cc0761fc1 100644
--- a/app/assets/javascripts/pipelines/components/async_button.vue
+++ b/app/assets/javascripts/pipelines/components/async_button.vue
@@ -3,7 +3,7 @@
import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
-import tooltipMixin from '../../vue_shared/mixins/tooltip';
+import tooltip from '../../vue_shared/directives/tooltip';
export default {
props: {
@@ -28,12 +28,12 @@ export default {
required: false,
},
},
+ directives: {
+ tooltip,
+ },
components: {
loadingIcon,
},
- mixins: [
- tooltipMixin,
- ],
data() {
return {
isLoading: false,
@@ -58,7 +58,6 @@ export default {
makeRequest() {
this.isLoading = true;
- $(this.$refs.tooltip).tooltip('destroy');
eventHub.$emit('postAction', this.endpoint);
},
},
@@ -67,6 +66,7 @@ export default {
<template>
<button
+ v-tooltip
type="button"
@click="onClick"
:class="buttonClass"
@@ -74,7 +74,6 @@ export default {
:aria-label="title"
data-container="body"
data-placement="top"
- ref="tooltip"
:disabled="isLoading">
<i
:class="iconClass"
diff --git a/app/assets/javascripts/pipelines/components/graph/action_component.vue b/app/assets/javascripts/pipelines/components/graph/action_component.vue
index 1f9e3d39779..54227425d2a 100644
--- a/app/assets/javascripts/pipelines/components/graph/action_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/action_component.vue
@@ -1,6 +1,6 @@
<script>
import getActionIcon from '../../../vue_shared/ci_action_icons';
- import tooltipMixin from '../../../vue_shared/mixins/tooltip';
+ import tooltip from '../../../vue_shared/directives/tooltip';
/**
* Renders either a cancel, retry or play icon pointing to the given path.
@@ -29,9 +29,9 @@
},
},
- mixins: [
- tooltipMixin,
- ],
+ directives: {
+ tooltip,
+ },
computed: {
actionIconSvg() {
@@ -46,12 +46,11 @@
</script>
<template>
<a
+ v-tooltip
:data-method="actionMethod"
:title="tooltipText"
:href="link"
- ref="tooltip"
class="ci-action-icon-container"
- data-toggle="tooltip"
data-container="body">
<i
diff --git a/app/assets/javascripts/pipelines/components/graph/dropdown_action_component.vue b/app/assets/javascripts/pipelines/components/graph/dropdown_action_component.vue
index 19cafff4e1c..18fe1847eef 100644
--- a/app/assets/javascripts/pipelines/components/graph/dropdown_action_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/dropdown_action_component.vue
@@ -1,6 +1,6 @@
<script>
import getActionIcon from '../../../vue_shared/ci_action_icons';
- import tooltipMixin from '../../../vue_shared/mixins/tooltip';
+ import tooltip from '../../../vue_shared/directives/tooltip';
/**
* Renders either a cancel, retry or play icon pointing to the given path.
@@ -29,9 +29,9 @@
},
},
- mixins: [
- tooltipMixin,
- ],
+ directives: {
+ tooltip,
+ },
computed: {
actionIconSvg() {
@@ -42,13 +42,12 @@
</script>
<template>
<a
+ v-tooltip
:data-method="actionMethod"
:title="tooltipText"
:href="link"
- ref="tooltip"
rel="nofollow"
class="ci-action-icon-wrapper js-ci-status-icon"
- data-toggle="tooltip"
data-container="body"
v-html="actionIconSvg"
aria-label="Job's action">
diff --git a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue b/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue
index d597af8dfb5..2944689a5a7 100644
--- a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue
@@ -1,7 +1,7 @@
<script>
import jobNameComponent from './job_name_component.vue';
import jobComponent from './job_component.vue';
- import tooltipMixin from '../../../vue_shared/mixins/tooltip';
+ import tooltip from '../../../vue_shared/directives/tooltip';
/**
* Renders the dropdown for the pipeline graph.
@@ -34,9 +34,9 @@
},
},
- mixins: [
- tooltipMixin,
- ],
+ directives: {
+ tooltip,
+ },
components: {
jobComponent,
@@ -53,12 +53,12 @@
<template>
<div>
<button
+ v-tooltip
type="button"
data-toggle="dropdown"
data-container="body"
class="dropdown-menu-toggle build-content"
- :title="tooltipText"
- ref="tooltip">
+ :title="tooltipText">
<job-name-component
:name="job.name"
diff --git a/app/assets/javascripts/pipelines/components/graph/job_component.vue b/app/assets/javascripts/pipelines/components/graph/job_component.vue
index b39c936101e..1f5ed3f1074 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_component.vue
@@ -2,7 +2,7 @@
import actionComponent from './action_component.vue';
import dropdownActionComponent from './dropdown_action_component.vue';
import jobNameComponent from './job_name_component.vue';
- import tooltipMixin from '../../../vue_shared/mixins/tooltip';
+ import tooltip from '../../../vue_shared/directives/tooltip';
/**
* Renders the badge for the pipeline graph and the job's dropdown.
@@ -54,9 +54,9 @@
jobNameComponent,
},
- mixins: [
- tooltipMixin,
- ],
+ directives: {
+ tooltip,
+ },
computed: {
tooltipText() {
@@ -77,12 +77,11 @@
<template>
<div>
<a
+ v-tooltip
v-if="job.status.details_path"
:href="job.status.details_path"
:title="tooltipText"
:class="cssClassJobName"
- ref="tooltip"
- data-toggle="tooltip"
data-container="body">
<job-name-component
@@ -93,10 +92,9 @@
<div
v-else
+ v-tooltip
:title="tooltipText"
:class="cssClassJobName"
- ref="tooltip"
- data-toggle="tooltip"
data-container="body">
<job-name-component
diff --git a/app/assets/javascripts/pipelines/components/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipeline_url.vue
index 8333ec0fbc3..2ca5ac2912f 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_url.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_url.vue
@@ -1,6 +1,6 @@
<script>
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
-import tooltipMixin from '../../vue_shared/mixins/tooltip';
+import tooltip from '../../vue_shared/directives/tooltip';
export default {
props: {
@@ -12,9 +12,9 @@ export default {
components: {
userAvatarLink,
},
- mixins: [
- tooltipMixin,
- ],
+ directives: {
+ tooltip,
+ },
computed: {
user() {
return this.pipeline.user;
@@ -45,16 +45,16 @@ export default {
<div class="label-container">
<span
v-if="pipeline.flags.latest"
+ v-tooltip
class="js-pipeline-url-latest label label-success"
- title="Latest pipeline for this branch"
- ref="tooltip">
+ title="Latest pipeline for this branch">
latest
</span>
<span
v-if="pipeline.flags.yaml_errors"
+ v-tooltip
class="js-pipeline-url-yaml label label-danger"
- :title="pipeline.yaml_errors"
- ref="tooltip">
+ :title="pipeline.yaml_errors">
yaml invalid
</span>
<span
diff --git a/app/assets/javascripts/pipelines/components/pipelines_actions.vue b/app/assets/javascripts/pipelines/components/pipelines_actions.vue
index a6fc4f04237..01dfe51cc17 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_actions.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_actions.vue
@@ -4,6 +4,7 @@
import playIconSvg from 'icons/_icon_play.svg';
import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
+ import tooltip from '../../vue_shared/directives/tooltip';
export default {
props: {
@@ -12,6 +13,9 @@
required: true,
},
},
+ directives: {
+ tooltip,
+ },
components: {
loadingIcon,
},
@@ -25,8 +29,6 @@
onClickAction(endpoint) {
this.isLoading = true;
- $(this.$refs.tooltip).tooltip('destroy');
-
eventHub.$emit('postAction', endpoint);
},
@@ -43,13 +45,13 @@
<template>
<div class="btn-group">
<button
+ v-tooltip
type="button"
- class="dropdown-new btn btn-default has-tooltip js-pipeline-dropdown-manual-actions"
+ class="dropdown-new btn btn-default js-pipeline-dropdown-manual-actions"
title="Manual job"
data-toggle="dropdown"
data-placement="top"
aria-label="Manual job"
- ref="tooltip"
:disabled="isLoading">
<span v-html="playIconSvg"></span>
<i
diff --git a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue
index b4520481cdc..b19bd509a00 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue
@@ -1,5 +1,5 @@
<script>
- import tooltipMixin from '../../vue_shared/mixins/tooltip';
+ import tooltip from '../../vue_shared/directives/tooltip';
export default {
props: {
@@ -8,9 +8,9 @@
required: true,
},
},
- mixins: [
- tooltipMixin,
- ],
+ directives: {
+ tooltip,
+ },
};
</script>
<template>
@@ -18,12 +18,12 @@
class="btn-group"
role="group">
<button
+ v-tooltip
class="dropdown-toggle btn btn-default build-artifacts js-pipeline-dropdown-download"
title="Artifacts"
data-placement="top"
data-toggle="dropdown"
- aria-label="Artifacts"
- ref="tooltip">
+ aria-label="Artifacts">
<i
class="fa fa-download"
aria-hidden="true">
diff --git a/app/assets/javascripts/pipelines/components/stage.vue b/app/assets/javascripts/pipelines/components/stage.vue
index c05c76c9a64..e98f35bb58c 100644
--- a/app/assets/javascripts/pipelines/components/stage.vue
+++ b/app/assets/javascripts/pipelines/components/stage.vue
@@ -16,7 +16,7 @@
/* global Flash */
import { borderlessStatusIconEntityMap } from '../../vue_shared/ci_status_icons';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
-import tooltipMixin from '../../vue_shared/mixins/tooltip';
+import tooltip from '../../vue_shared/directives/tooltip';
export default {
props: {
@@ -32,9 +32,9 @@ export default {
},
},
- mixins: [
- tooltipMixin,
- ],
+ directives: {
+ tooltip,
+ },
data() {
return {
@@ -132,7 +132,7 @@ export default {
<template>
<div class="dropdown">
<button
- ref="tooltip"
+ v-tooltip
:class="triggerButtonClass"
@click="onClickStage"
class="mini-pipeline-graph-dropdown-toggle js-builds-dropdown-button"
diff --git a/app/assets/javascripts/pipelines/components/time_ago.vue b/app/assets/javascripts/pipelines/components/time_ago.vue
index be3f32afa09..037684b4e72 100644
--- a/app/assets/javascripts/pipelines/components/time_ago.vue
+++ b/app/assets/javascripts/pipelines/components/time_ago.vue
@@ -1,7 +1,7 @@
<script>
import iconTimerSvg from 'icons/_icon_timer.svg';
import '../../lib/utils/datetime_utility';
- import tooltipMixin from '../../vue_shared/mixins/tooltip';
+ import tooltip from '../../vue_shared/directives/tooltip';
import timeagoMixin from '../../vue_shared/mixins/timeago';
export default {
@@ -16,9 +16,11 @@
},
},
mixins: [
- tooltipMixin,
timeagoMixin,
],
+ directives: {
+ tooltip,
+ },
data() {
return {
iconTimerSvg,
@@ -81,7 +83,7 @@
</i>
<time
- ref="tooltip"
+ v-tooltip
data-placement="top"
data-container="body"
:title="tooltipTitle(finishedTime)">
diff --git a/app/assets/javascripts/vue_shared/components/header_ci_component.vue b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
index 1d4d90f75b6..bdc059f4a03 100644
--- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue
+++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
@@ -2,7 +2,7 @@
import ciIconBadge from './ci_badge_link.vue';
import loadingIcon from './loading_icon.vue';
import timeagoTooltip from './time_ago_tooltip.vue';
-import tooltipMixin from '../mixins/tooltip';
+import tooltip from '../directives/tooltip';
import userAvatarImage from './user_avatar/user_avatar_image.vue';
/**
@@ -47,9 +47,9 @@ export default {
},
},
- mixins: [
- tooltipMixin,
- ],
+ directives: {
+ tooltip,
+ },
components: {
ciIconBadge,
@@ -90,10 +90,10 @@ export default {
<template v-if="user">
<a
+ v-tooltip
:href="user.path"
:title="user.email"
- class="js-user-link commit-committer-link"
- ref="tooltip">
+ class="js-user-link commit-committer-link">
<user-avatar-image
:img-src="user.avatar_url"
diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue
index 1a11f493b7f..5bf2a90cc3b 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/header.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue
@@ -1,17 +1,17 @@
<script>
- import tooltipMixin from '../../mixins/tooltip';
+ import tooltip from '../../directives/tooltip';
import toolbarButton from './toolbar_button.vue';
export default {
- mixins: [
- tooltipMixin,
- ],
props: {
previewMarkdown: {
type: Boolean,
required: true,
},
},
+ directives: {
+ tooltip,
+ },
components: {
toolbarButton,
},
@@ -94,13 +94,13 @@
</div>
<div class="toolbar-group">
<button
+ v-tooltip
aria-label="Go full screen"
class="toolbar-btn js-zen-enter"
data-container="body"
tabindex="-1"
title="Go full screen"
- type="button"
- ref="tooltip">
+ type="button">
<i
aria-hidden="true"
class="fa fa-arrows-alt fa-fw">
diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
index 096be507625..f7da7ebfcfe 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
@@ -1,10 +1,7 @@
<script>
- import tooltipMixin from '../../mixins/tooltip';
+ import tooltip from '../../directives/tooltip';
export default {
- mixins: [
- tooltipMixin,
- ],
props: {
buttonTitle: {
type: String,
@@ -29,6 +26,9 @@
default: false,
},
},
+ directives: {
+ tooltip,
+ },
computed: {
iconClass() {
return `fa-${this.icon}`;
@@ -39,10 +39,10 @@
<template>
<button
+ v-tooltip
type="button"
class="toolbar-btn js-md hidden-xs"
tabindex="-1"
- ref="tooltip"
data-container="body"
:data-md-tag="tag"
:data-md-block="tagBlock"
diff --git a/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue b/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
index 1c6ef071a6d..3ff7f6e2c4e 100644
--- a/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
+++ b/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
@@ -1,5 +1,5 @@
<script>
-import tooltipMixin from '../mixins/tooltip';
+import tooltip from '../directives/tooltip';
import timeagoMixin from '../mixins/timeago';
import '../../lib/utils/datetime_utility';
@@ -28,19 +28,21 @@ export default {
},
mixins: [
- tooltipMixin,
timeagoMixin,
],
+
+ directives: {
+ tooltip,
+ },
};
</script>
<template>
<time
+ v-tooltip
:class="cssClass"
- class="js-vue-timeago"
:title="tooltipTitle(time)"
:data-placement="tooltipPlacement"
- data-container="body"
- ref="tooltip">
+ data-container="body">
{{timeFormated(time)}}
</time>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue
index cd6f8c7aee4..dd9a2ebb184 100644
--- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue
+++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue
@@ -16,11 +16,10 @@
*/
import defaultAvatarUrl from 'images/no_avatar.png';
-import TooltipMixin from '../../mixins/tooltip';
+import tooltip from '../../directives/tooltip';
export default {
name: 'UserAvatarImage',
- mixins: [TooltipMixin],
props: {
imgSrc: {
type: String,
@@ -53,6 +52,9 @@ export default {
default: 'top',
},
},
+ directives: {
+ tooltip,
+ },
computed: {
tooltipContainer() {
return this.tooltipText ? 'body' : null;
@@ -72,6 +74,7 @@ export default {
<template>
<img
+ v-tooltip
class="avatar"
:class="[avatarSizeClass, cssClasses]"
:src="imageSource"
@@ -81,6 +84,5 @@ export default {
:data-container="tooltipContainer"
:data-placement="tooltipPlacement"
:title="tooltipText"
- ref="tooltip"
/>
</template>
diff --git a/app/assets/javascripts/vue_shared/directives/tooltip.js b/app/assets/javascripts/vue_shared/directives/tooltip.js
new file mode 100644
index 00000000000..dc896cf5c7d
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/directives/tooltip.js
@@ -0,0 +1,13 @@
+export default {
+ bind(el) {
+ $(el).tooltip();
+ },
+
+ componentUpdated(el) {
+ $(el).tooltip('fixTitle');
+ },
+
+ unbind(el) {
+ $(el).tooltip('destroy');
+ },
+};
diff --git a/app/assets/javascripts/vue_shared/mixins/tooltip.js b/app/assets/javascripts/vue_shared/mixins/tooltip.js
deleted file mode 100644
index 995c0c98505..00000000000
--- a/app/assets/javascripts/vue_shared/mixins/tooltip.js
+++ /dev/null
@@ -1,13 +0,0 @@
-export default {
- mounted() {
- $(this.$refs.tooltip).tooltip();
- },
-
- updated() {
- $(this.$refs.tooltip).tooltip('fixTitle');
- },
-
- beforeDestroy() {
- $(this.$refs.tooltip).tooltip('destroy');
- },
-};
diff --git a/doc/development/fe_guide/style_guide_js.md b/doc/development/fe_guide/style_guide_js.md
index d2d89517241..ae844fa1051 100644
--- a/doc/development/fe_guide/style_guide_js.md
+++ b/doc/development/fe_guide/style_guide_js.md
@@ -463,20 +463,24 @@ A forEach will cause side effects, it will be mutating the array being iterated.
1. `destroyed`
#### Vue and Boostrap
-1. Tooltips: Do not rely on `has-tooltip` class name for vue components
+1. Tooltips: Do not rely on `has-tooltip` class name for Vue components
```javascript
// bad
- <span class="has-tooltip">
+ <span
+ class="has-tooltip"
+ title="Some tooltip text">
Text
</span>
// good
- <span data-toggle="tooltip">
+ <span
+ v-tooltip
+ title="Some tooltip text">
Text
</span>
```
-1. Tooltips: When using a tooltip, include the tooltip mixin
+1. Tooltips: When using a tooltip, include the tooltip directive, `./app/assets/javascripts/vue_shared/directives/tooltip.js`
1. Don't change `data-original-title`.
```javascript
diff --git a/spec/javascripts/environments/environment_actions_spec.js b/spec/javascripts/environments/environment_actions_spec.js
index 596d812c724..ea40a1fcd4b 100644
--- a/spec/javascripts/environments/environment_actions_spec.js
+++ b/spec/javascripts/environments/environment_actions_spec.js
@@ -32,9 +32,16 @@ describe('Actions Component', () => {
}).$mount();
});
+ describe('computed', () => {
+ it('title', () => {
+ expect(component.title).toEqual('Deploy to...');
+ });
+ });
+
it('should render a dropdown button with icon and title attribute', () => {
expect(component.$el.querySelector('.fa-caret-down')).toBeDefined();
- expect(component.$el.querySelector('.dropdown-new').getAttribute('title')).toEqual('Deploy to...');
+ expect(component.$el.querySelector('.dropdown-new').getAttribute('data-original-title')).toEqual('Deploy to...');
+ expect(component.$el.querySelector('.dropdown-new').getAttribute('aria-label')).toEqual('Deploy to...');
});
it('should render a dropdown with the provided list of actions', () => {
diff --git a/spec/javascripts/environments/environment_monitoring_spec.js b/spec/javascripts/environments/environment_monitoring_spec.js
index 0f3dba66230..f8d8223967a 100644
--- a/spec/javascripts/environments/environment_monitoring_spec.js
+++ b/spec/javascripts/environments/environment_monitoring_spec.js
@@ -3,21 +3,30 @@ import monitoringComp from '~/environments/components/environment_monitoring.vue
describe('Monitoring Component', () => {
let MonitoringComponent;
+ let component;
+
+ const monitoringUrl = 'https://gitlab.com';
beforeEach(() => {
MonitoringComponent = Vue.extend(monitoringComp);
- });
- it('should render a link to environment monitoring page', () => {
- const monitoringUrl = 'https://gitlab.com';
- const component = new MonitoringComponent({
+ component = new MonitoringComponent({
propsData: {
monitoringUrl,
},
}).$mount();
+ });
+ describe('computed', () => {
+ it('title', () => {
+ expect(component.title).toEqual('Monitoring');
+ });
+ });
+
+ it('should render a link to environment monitoring page', () => {
expect(component.$el.getAttribute('href')).toEqual(monitoringUrl);
expect(component.$el.querySelector('.fa-area-chart')).toBeDefined();
- expect(component.$el.getAttribute('title')).toEqual('Monitoring');
+ expect(component.$el.getAttribute('data-original-title')).toEqual('Monitoring');
+ expect(component.$el.getAttribute('aria-label')).toEqual('Monitoring');
});
});
diff --git a/spec/javascripts/environments/environment_stop_spec.js b/spec/javascripts/environments/environment_stop_spec.js
index 8131f1e5b11..3f95faf466a 100644
--- a/spec/javascripts/environments/environment_stop_spec.js
+++ b/spec/javascripts/environments/environment_stop_spec.js
@@ -17,8 +17,15 @@ describe('Stop Component', () => {
}).$mount();
});
+ describe('computed', () => {
+ it('title', () => {
+ expect(component.title).toEqual('Stop');
+ });
+ });
+
it('should render a button to stop the environment', () => {
expect(component.$el.tagName).toEqual('BUTTON');
- expect(component.$el.getAttribute('title')).toEqual('Stop');
+ expect(component.$el.getAttribute('data-original-title')).toEqual('Stop');
+ expect(component.$el.getAttribute('aria-label')).toEqual('Stop');
});
});
diff --git a/spec/javascripts/environments/environment_terminal_button_spec.js b/spec/javascripts/environments/environment_terminal_button_spec.js
index 858472af4b6..f1576b19d1b 100644
--- a/spec/javascripts/environments/environment_terminal_button_spec.js
+++ b/spec/javascripts/environments/environment_terminal_button_spec.js
@@ -16,9 +16,16 @@ describe('Stop Component', () => {
}).$mount();
});
+ describe('computed', () => {
+ it('title', () => {
+ expect(component.title).toEqual('Terminal');
+ });
+ });
+
it('should render a link to open a web terminal with the provided path', () => {
expect(component.$el.tagName).toEqual('A');
- expect(component.$el.getAttribute('title')).toEqual('Terminal');
+ expect(component.$el.getAttribute('data-original-title')).toEqual('Terminal');
+ expect(component.$el.getAttribute('aria-label')).toEqual('Terminal');
expect(component.$el.getAttribute('href')).toEqual(terminalPath);
});
});
diff --git a/spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js b/spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js
index f3b4adc0b70..b4c1f70ed1e 100644
--- a/spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js
+++ b/spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js
@@ -22,7 +22,6 @@ describe('Time ago with tooltip component', () => {
}).$mount();
expect(vm.$el.tagName).toEqual('TIME');
- expect(vm.$el.classList.contains('js-vue-timeago')).toEqual(true);
expect(
vm.$el.getAttribute('data-original-title'),
).toEqual(gl.utils.formatDate('2017-05-08T14:57:39.781Z'));
diff --git a/spec/javascripts/vue_shared/directives/tooltip_spec.js b/spec/javascripts/vue_shared/directives/tooltip_spec.js
new file mode 100644
index 00000000000..b1b3071527b
--- /dev/null
+++ b/spec/javascripts/vue_shared/directives/tooltip_spec.js
@@ -0,0 +1,63 @@
+import Vue from 'vue';
+import tooltip from '~/vue_shared/directives/tooltip';
+
+describe('Tooltip directive', () => {
+ let vm;
+
+ afterEach(() => {
+ if (vm) {
+ vm.$destroy();
+ }
+ });
+
+ describe('with a single tooltip', () => {
+ beforeEach(() => {
+ const SomeComponent = Vue.extend({
+ directives: {
+ tooltip,
+ },
+ template: `
+ <div
+ v-tooltip
+ title="foo">
+ </div>
+ `,
+ });
+
+ vm = new SomeComponent().$mount();
+ });
+
+ it('should have tooltip plugin applied', () => {
+ expect($(vm.$el).data('bs.tooltip')).toBeDefined();
+ });
+ });
+
+ describe('with multiple tooltips', () => {
+ beforeEach(() => {
+ const SomeComponent = Vue.extend({
+ directives: {
+ tooltip,
+ },
+ template: `
+ <div>
+ <div
+ v-tooltip
+ class="js-look-for-tooltip"
+ title="foo">
+ </div>
+ <div
+ v-tooltip
+ title="bar">
+ </div>
+ </div>
+ `,
+ });
+
+ vm = new SomeComponent().$mount();
+ });
+
+ it('should have tooltip plugin applied to all instances', () => {
+ expect($(vm.$el).find('.js-look-for-tooltip').data('bs.tooltip')).toBeDefined();
+ });
+ });
+});