diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-button.js b/app/assets/javascripts/app/lib/bootstrap/button.js similarity index 94% rename from app/assets/javascripts/app/lib/bootstrap/bootstrap-button.js rename to app/assets/javascripts/app/lib/bootstrap/button.js index 539e9fead..fc73b555f 100644 --- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-button.js +++ b/app/assets/javascripts/app/lib/bootstrap/button.js @@ -56,7 +56,9 @@ var $parent = this.$element.closest('[data-toggle="buttons"]') if ($parent.length) { - var $input = this.$element.find('input').prop('checked', !this.$element.hasClass('active')) + var $input = this.$element.find('input') + .prop('checked', !this.$element.hasClass('active')) + .trigger('change') if ($input.prop('type') === 'radio') $parent.find('.active').removeClass('active') } @@ -72,7 +74,7 @@ $.fn.button = function (option) { return this.each(function () { var $this = $(this) - var data = $this.data('button') + var data = $this.data('bs.button') var options = typeof option == 'object' && option if (!data) $this.data('bs.button', (data = new Button(this, options))) diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-collapse.js b/app/assets/javascripts/app/lib/bootstrap/collapse.js similarity index 97% rename from app/assets/javascripts/app/lib/bootstrap/bootstrap-collapse.js rename to app/assets/javascripts/app/lib/bootstrap/collapse.js index 34ac3c7fa..92cc0bc76 100644 --- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-collapse.js +++ b/app/assets/javascripts/app/lib/bootstrap/collapse.js @@ -48,7 +48,7 @@ this.$element.trigger(startEvent) if (startEvent.isDefaultPrevented()) return - var actives = this.$parent && this.$parent.find('> .accordion-group > .in') + var actives = this.$parent && this.$parent.find('> .panel > .in') if (actives && actives.length) { var hasData = actives.data('bs.collapse') @@ -169,7 +169,7 @@ var $parent = parent && $(parent) if (!data || !data.transitioning) { - if ($parent) $parent.find('[data-toggle=collapse][data-parent=' + parent + ']').not($this).addClass('collapsed') + if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') } diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-dropdown.js b/app/assets/javascripts/app/lib/bootstrap/dropdown.js similarity index 97% rename from app/assets/javascripts/app/lib/bootstrap/bootstrap-dropdown.js rename to app/assets/javascripts/app/lib/bootstrap/dropdown.js index 69bbd802c..6093f11a8 100644 --- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-dropdown.js +++ b/app/assets/javascripts/app/lib/bootstrap/dropdown.js @@ -40,7 +40,7 @@ clearMenus() if (!isActive) { - if ('ontouchstart' in document.documentElement) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { // if mobile we we use a backdrop because click events don't delegate $('
').insertAfter($(this)).on('click', clearMenus) } @@ -52,9 +52,9 @@ $parent .toggleClass('open') .trigger('shown.bs.dropdown') - } - $this.focus() + $this.focus() + } return false } diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-modal.js b/app/assets/javascripts/app/lib/bootstrap/modal.js similarity index 82% rename from app/assets/javascripts/app/lib/bootstrap/bootstrap-modal.js rename to app/assets/javascripts/app/lib/bootstrap/modal.js index d53cc9eaf..65eba481e 100644 --- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-modal.js +++ b/app/assets/javascripts/app/lib/bootstrap/modal.js @@ -25,11 +25,11 @@ var Modal = function (element, options) { this.options = options - this.$element = $(element).on('click.dismiss.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) + this.$element = $(element) this.$backdrop = this.isShown = null - if (this.options.remote) this.$element.find('.modal-body').load(this.options.remote) + if (this.options.remote) this.$element.load(this.options.remote) } Modal.DEFAULTS = { @@ -38,13 +38,13 @@ , show: true } - Modal.prototype.toggle = function () { - return this[!this.isShown ? 'show' : 'hide']() + Modal.prototype.toggle = function (_relatedTarget) { + return this[!this.isShown ? 'show' : 'hide'](_relatedTarget) } - Modal.prototype.show = function () { + Modal.prototype.show = function (_relatedTarget) { var that = this - var e = $.Event('show.bs.modal') + var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) this.$element.trigger(e) @@ -54,6 +54,8 @@ this.escape() + this.$element.on('click.dismiss.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) + this.backdrop(function () { var transition = $.support.transition && that.$element.hasClass('fade') @@ -73,13 +75,15 @@ that.enforceFocus() + var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) + transition ? - that.$element + that.$element.find('.modal-dialog') // wait for modal to slide in .one($.support.transition.end, function () { - that.$element.focus().trigger('shown.bs.modal') + that.$element.focus().trigger(e) }) .emulateTransitionEnd(300) : - that.$element.focus().trigger('shown.bs.modal') + that.$element.focus().trigger(e) }) } @@ -101,6 +105,7 @@ this.$element .removeClass('in') .attr('aria-hidden', true) + .off('click.dismiss.modal') $.support.transition && this.$element.hasClass('fade') ? this.$element @@ -153,7 +158,7 @@ this.$backdrop = $('') .appendTo(document.body) - this.$element.on('click', $.proxy(function (e) { + this.$element.on('click.dismiss.modal', $.proxy(function (e) { if (e.target !== e.currentTarget) return this.options.backdrop == 'static' ? this.$element[0].focus.call(this.$element[0]) @@ -192,15 +197,15 @@ var old = $.fn.modal - $.fn.modal = function (option) { + $.fn.modal = function (option, _relatedTarget) { return this.each(function () { var $this = $(this) var data = $this.data('bs.modal') var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) if (!data) $this.data('bs.modal', (data = new Modal(this, options))) - if (typeof option == 'string') data[option]() - else if (options.show) data.show() + if (typeof option == 'string') data[option](_relatedTarget) + else if (options.show) data.show(_relatedTarget) }) } @@ -223,21 +228,19 @@ var $this = $(this) var href = $this.attr('href') var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7 - var option = $target.data('modal') ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data()) + var option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) e.preventDefault() $target - .modal(option) + .modal(option, this) .one('hide', function () { $this.is(':visible') && $this.focus() }) }) - $(function () { - var $body = $(document.body) - .on('shown.bs.modal', '.modal', function () { $body.addClass('modal-open') }) - .on('hidden.bs.modal', '.modal', function () { $body.removeClass('modal-open') }) - }) + $(document) + .on('show.bs.modal', '.modal', function () { $(document.body).addClass('modal-open') }) + .on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open') }) }(window.jQuery); diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-popover.js b/app/assets/javascripts/app/lib/bootstrap/popover.js similarity index 90% rename from app/assets/javascripts/app/lib/bootstrap/bootstrap-popover.js rename to app/assets/javascripts/app/lib/bootstrap/popover.js index 7abca8acb..ecd37ac23 100644 --- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-popover.js +++ b/app/assets/javascripts/app/lib/bootstrap/popover.js @@ -58,7 +58,9 @@ $tip.removeClass('fade top bottom left right in') - $tip.find('.popover-title:empty').hide() + // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do + // this manually by checking the contents. + if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() } Popover.prototype.hasContent = function () { @@ -75,15 +77,15 @@ o.content) } + Popover.prototype.arrow = function () { + return this.$arrow = this.$arrow || this.tip().find('.arrow') + } + Popover.prototype.tip = function () { if (!this.$tip) this.$tip = $(this.options.template) return this.$tip } - Popover.prototype.destroy = function () { - this.hide().$element.off('.' + this.type).removeData(this.type) - } - // POPOVER PLUGIN DEFINITION // ========================= diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-tab.js b/app/assets/javascripts/app/lib/bootstrap/tab.js similarity index 100% rename from app/assets/javascripts/app/lib/bootstrap/bootstrap-tab.js rename to app/assets/javascripts/app/lib/bootstrap/tab.js diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-tooltip.js b/app/assets/javascripts/app/lib/bootstrap/tooltip.js similarity index 81% rename from app/assets/javascripts/app/lib/bootstrap/bootstrap-tooltip.js rename to app/assets/javascripts/app/lib/bootstrap/tooltip.js index a954923be..89802287a 100644 --- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-tooltip.js +++ b/app/assets/javascripts/app/lib/bootstrap/tooltip.js @@ -1,6 +1,6 @@ /* ======================================================================== * Bootstrap: tooltip.js v3.0.0 - * http://twbs.github.com/bootstrap/javascript.html#affix + * http://twbs.github.com/bootstrap/javascript.html#tooltip * Inspired by the original jQuery.tipsy by Jason Frame * ======================================================================== * Copyright 2012 Twitter, Inc. @@ -64,7 +64,7 @@ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focus' var eventOut = trigger == 'hover' ? 'mouseleave' : 'blur' - this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) + this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) } } @@ -91,37 +91,43 @@ return options } - Tooltip.prototype.enter = function (obj) { - var defaults = this.getDefaults() + Tooltip.prototype.getDelegateOptions = function () { var options = {} + var defaults = this.getDefaults() this._options && $.each(this._options, function (key, value) { if (defaults[key] != value) options[key] = value }) + return options + } + + Tooltip.prototype.enter = function (obj) { var self = obj instanceof this.constructor ? - obj : $(obj.currentTarget)[this.type](options).data('bs.' + this.type) + obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) clearTimeout(self.timeout) + self.hoverState = 'in' + if (!self.options.delay || !self.options.delay.show) return self.show() - self.hoverState = 'in' - self.timeout = setTimeout(function () { + self.timeout = setTimeout(function () { if (self.hoverState == 'in') self.show() }, self.options.delay.show) } Tooltip.prototype.leave = function (obj) { var self = obj instanceof this.constructor ? - obj : $(obj.currentTarget)[this.type](this._options).data('bs.' + this.type) + obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) clearTimeout(self.timeout) + self.hoverState = 'out' + if (!self.options.delay || !self.options.delay.hide) return self.hide() - self.hoverState = 'out' - self.timeout = setTimeout(function () { + self.timeout = setTimeout(function () { if (self.hoverState == 'out') self.hide() }, self.options.delay.hide) } @@ -179,12 +185,9 @@ .addClass(placement) } - var tp = placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : - placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : - placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : - /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } + var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) - this.applyPlacement(tp, placement) + this.applyPlacement(calculatedOffset, placement) this.$element.trigger('shown.bs.' + this.type) } } @@ -196,25 +199,33 @@ var height = $tip[0].offsetHeight // manually read margins because getBoundingClientRect includes difference - offset.top = offset.top + parseInt($tip.css('margin-top'), 10) - offset.left = offset.left + parseInt($tip.css('margin-left'), 10) + var marginTop = parseInt($tip.css('margin-top'), 10) + var marginLeft = parseInt($tip.css('margin-left'), 10) + + // we must check for NaN for ie 8/9 + if (isNaN(marginTop)) marginTop = 0 + if (isNaN(marginLeft)) marginLeft = 0 + + offset.top = offset.top + marginTop + offset.left = offset.left + marginLeft $tip .offset(offset) .addClass('in') + // check to see if placing tip in new offset caused the tip to resize itself var actualWidth = $tip[0].offsetWidth var actualHeight = $tip[0].offsetHeight if (placement == 'top' && actualHeight != height) { replace = true - offset.top = offset.top + height - actualHeight + offset.top = offset.top + height - actualHeight } - if (placement == 'bottom' || placement == 'top') { + if (/bottom|top/.test(placement)) { var delta = 0 - if (offset.left < 0){ + if (offset.left < 0) { delta = offset.left * -2 offset.left = 0 @@ -249,6 +260,10 @@ var $tip = this.tip() var e = $.Event('hide.bs.' + this.type) + function complete() { + if (that.hoverState != 'in') $tip.detach() + } + this.$element.trigger(e) if (e.isDefaultPrevented()) return @@ -257,9 +272,9 @@ $.support.transition && this.$tip.hasClass('fade') ? $tip - .one($.support.transition.end, $tip.detach) + .one($.support.transition.end, complete) .emulateTransitionEnd(150) : - $tip.detach() + complete() this.$element.trigger('hidden.bs.' + this.type) @@ -285,6 +300,13 @@ }, this.$element.offset()) } + Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { + return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : + placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : + placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : + /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } + } + Tooltip.prototype.getTitle = function () { var title var $e = this.$element @@ -300,8 +322,8 @@ return this.$tip = this.$tip || $(this.options.template) } - Tooltip.prototype.arrow =function(){ - return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow") + Tooltip.prototype.arrow = function () { + return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow') } Tooltip.prototype.validate = function () { @@ -325,7 +347,7 @@ } Tooltip.prototype.toggle = function (e) { - var self = e ? $(e.currentTarget)[this.type](this._options).data('bs.' + this.type) : this + var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this self.tip().hasClass('in') ? self.leave(self) : self.enter(self) } diff --git a/app/assets/javascripts/app/lib/bootstrap/bootstrap-transition.js b/app/assets/javascripts/app/lib/bootstrap/transition.js similarity index 98% rename from app/assets/javascripts/app/lib/bootstrap/bootstrap-transition.js rename to app/assets/javascripts/app/lib/bootstrap/transition.js index 0cdcf9ea3..e8f318beb 100644 --- a/app/assets/javascripts/app/lib/bootstrap/bootstrap-transition.js +++ b/app/assets/javascripts/app/lib/bootstrap/transition.js @@ -42,7 +42,7 @@ // http://blog.alexmaccaw.com/css-transitions $.fn.emulateTransitionEnd = function (duration) { - var called = false, $el = this + var called = false, $el = this $(this).one($.support.transition.end, function () { called = true }) var callback = function () { if (!called) $($el).trigger($.support.transition.end) } setTimeout(callback, duration)