diff --git a/dist/js/bootstrap.js b/dist/js/bootstrap.js
index 4ce288b22ef3..ac305a13d6ae 100644
--- a/dist/js/bootstrap.js
+++ b/dist/js/bootstrap.js
@@ -1220,7 +1220,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
var $tip = this.tip()
this.setContent()
-
+ this.setAriaDescribedBy()
if (this.options.animation) $tip.addClass('fade')
var placement = typeof this.options.placement == 'function' ?
@@ -1342,6 +1342,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
var $tip = this.tip()
var e = $.Event('hide.bs.' + this.type)
+ this.removeAriaDescribedBy()
function complete() {
if (that.hoverState != 'in') $tip.detach()
that.$element.trigger('hidden.bs.' + that.type)
@@ -1441,6 +1442,25 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
}
+ Tooltip.prototype.uid = function (prefix) {
+ var id = prefix + Math.floor( Math.random() * 1000000 )
+
+ while ($('#' + id).length) {
+ id += Math.floor( Math.random() * 1000000 )
+ }
+
+ return id
+ }
+
+ Tooltip.prototype.setAriaDescribedBy = function() {
+ var tipId = this.$tip.attr('id', this.uid(this.type))
+ this.$element.attr('aria-describedby', tipId)
+ }
+
+ Tooltip.prototype.removeAriaDescribedBy = function() {
+ this.$element.removeAttr('aria-describedby')
+ }
+
Tooltip.prototype.validate = function () {
if (!this.$element[0].parentNode) {
this.hide()
diff --git a/js/tests/unit/tooltip.js b/js/tests/unit/tooltip.js
index e579a9ef7f98..e95b91cbb18b 100644
--- a/js/tests/unit/tooltip.js
+++ b/js/tests/unit/tooltip.js
@@ -41,6 +41,36 @@ $(function () {
equal(tooltip.attr('data-original-title'), 'Another tooltip', 'original title preserved in data attribute')
})
+ test('should add set set aria describedby to the element called on show', function() {
+ var tooltip = $('').bootstrapTooltip()
+ .appendTo('#qunit-fixture')
+ .bootstrapTooltip('show')
+ ok(tooltip.attr('aria-describedby'), 'has the right attributes')
+ var id = $('.tooltip').attr('id')
+
+ ok($('#' + id).length == 1, 'has a unique id')
+ ok($('.tooltip').attr('aria-describedby') === tooltip.attr('id'), 'they match!')
+ ok(tooltip.attr('aria-describedby') !== undefined, 'has the right attributes')
+ })
+
+ test('should remove the aria-describedby attributes on hide', function() {
+ var tooltip = $('').bootstrapTooltip()
+ .appendTo('#qunit-fixture')
+ .bootstrapTooltip('show')
+ ok(tooltip.attr('aria-describedby'), 'has the right attributes')
+ tooltip.bootstrapTooltip('hide')
+ ok(!tooltip.attr('aria-describedby'), 'removed the attributes on hide')
+ })
+
+ test('should assign a unique id tooltip element', function () {
+ $('')
+ .appendTo('#qunit-fixture')
+ .bootstrapTooltip('show'),
+ id = $('.tooltip').attr('id')
+
+ ok( $('#' + id).length == 1 && id.indexOf('tooltip') === 0, 'generated prefixed and unique tooltip id')
+ })
+
test('should place tooltips relative to placement option', function () {
$.support.transition = false
var tooltip = $('')
diff --git a/js/tooltip.js b/js/tooltip.js
index f688b3020923..037f8870bdea 100644
--- a/js/tooltip.js
+++ b/js/tooltip.js
@@ -149,7 +149,7 @@
var $tip = this.tip()
this.setContent()
-
+ this.setAriaDescribedBy()
if (this.options.animation) $tip.addClass('fade')
var placement = typeof this.options.placement == 'function' ?
@@ -271,6 +271,7 @@
var $tip = this.tip()
var e = $.Event('hide.bs.' + this.type)
+ this.removeAriaDescribedBy()
function complete() {
if (that.hoverState != 'in') $tip.detach()
that.$element.trigger('hidden.bs.' + that.type)
@@ -370,6 +371,25 @@
return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
}
+ Tooltip.prototype.uid = function (prefix) {
+ var id = prefix + Math.floor( Math.random() * 1000000 )
+
+ while ($('#' + id).length) {
+ id += Math.floor( Math.random() * 1000000 )
+ }
+
+ return id
+ }
+
+ Tooltip.prototype.setAriaDescribedBy = function() {
+ var tipId = this.$tip.attr('id', this.uid(this.type))
+ this.$element.attr('aria-describedby', tipId)
+ }
+
+ Tooltip.prototype.removeAriaDescribedBy = function() {
+ this.$element.removeAttr('aria-describedby')
+ }
+
Tooltip.prototype.validate = function () {
if (!this.$element[0].parentNode) {
this.hide()