From 5071325345101c7246edfe7b49a39d7ca6a0dc43 Mon Sep 17 00:00:00 2001 From: Aman Agrawal Date: Tue, 25 Aug 2020 18:28:59 +0530 Subject: [PATCH] popovers: Reapply changes to bootstrap.js. We don't modify bootstrap.js here but override its popover and tooltip plugins. In future we will not import these plugins via npm. We also copy all the popover code from bootstrap.css v2.1.1 to popovers.scss since all the code in bootstrap-tooltip.js is based upon this css or vice versa. Update THIRDPARTY info about bootstrap libraries. There were 4 types of changes to bootstrap.js - bugfixes, file moves, changes to typeahead plugin and changes to tooltip + popover plugin. Bugfixes were automatically fixed when upgrading to v2.3.2, file moves are irrelevant to this upgrade and the plugins were extracted into separate files. 46e562f - POPOVER 8779e55 - POPOVER 66c6423 - POPOVER 21ccf45 - POPOVER cb9b526 - TYPEAHEAD EXTRACTED 3079cf8 - TYPEAHEAD 9ea4f50 - TYPEAHEAD b961093 - TYPEAHEAD 0e2c509 - TYPEAHEAD 28589c5 - TYPEAHEAD 70a14d8 - TYPEAHEAD 0c42e4a - TYPEAHEAD 213b8ce - FIXED IN 2.3.2 0bac986 - TYPEAHEAD 0e3332d - FIXED IN V2.3.2 eaa777b - TYPEAHEAD f944a8e - TYPEAHEAD 546ae10 - TYPEAHEAD 3bba0cc - FILE MOVED b8794e1 - TYPEAHEAD 6217c1a - TYPEAHEAD dc85fa7 - TYPEAHEAD d329317 - TYPEAHEAD b3ef776 - TYPEAHEAD fcb3999 - TYPEAHEAD 0975cfa - TYPEAHEAD fbed3e2 - TYPEAHEAD 0fa857d - POPOVER 68b890a - TYPEAHEAD b5cadec - typeahead 441e429 - copyright 22ce2c0 Fixed In v2.3.2 d78d761- typeahead bff933e- typeahead ef585cf- typeahead 7e35369 - typeahead 8f1cee0 - Files moving around 1490ae1 - add file --- docs/THIRDPARTY | 6 +- static/js/bundles/app.js | 2 + static/third/bootstrap-tooltip/tooltip.css | 191 +++++++++ static/third/bootstrap-tooltip/tooltip.js | 433 +++++++++++++++++++++ 4 files changed, 631 insertions(+), 1 deletion(-) create mode 100644 static/third/bootstrap-tooltip/tooltip.css create mode 100644 static/third/bootstrap-tooltip/tooltip.js diff --git a/docs/THIRDPARTY b/docs/THIRDPARTY index 689bd89e56..bd11f050f6 100644 --- a/docs/THIRDPARTY +++ b/docs/THIRDPARTY @@ -85,13 +85,17 @@ Comment: The software has been modified. Files: static/third/bootstrap/js/bootstrap.js Copyright: 2012 Twitter, Inc License: Apache-2.0 -Comment: The software has been modified. Files: static/third/bootstrap-typeahead/* Copyright: 2012 Twitter, Inc License: Apache-2.0 Comment: Bootstrap typeahead. The software has been modified. +Files: static/third/bootstrap-tooltip/* +Copyright: 2012 Twitter, Inc +License: Apache-2.0 +Comment: Bootstrap tooltip and bootstrap popover. The software has been modified. + Files: static/third/bootstrap-notify/* Copyright: 2013 Nijiko Yonskai 2012 Goodybag, Inc. diff --git a/static/js/bundles/app.js b/static/js/bundles/app.js index 532b934e47..1bd6062bc5 100644 --- a/static/js/bundles/app.js +++ b/static/js/bundles/app.js @@ -3,6 +3,8 @@ import "./common.js"; // Import Third party libraries import "../../third/bootstrap-notify/js/bootstrap-notify.js"; import "../../third/bootstrap-typeahead/typeahead.js"; +import "../../third/bootstrap-tooltip/tooltip.js"; +import "../../third/bootstrap-tooltip/tooltip.css"; import "jquery-caret-plugin/src/jquery.caret.js"; import "../../third/jquery-idle/jquery.idle.js"; import "spectrum-colorpicker"; diff --git a/static/third/bootstrap-tooltip/tooltip.css b/static/third/bootstrap-tooltip/tooltip.css new file mode 100644 index 0000000000..0889904063 --- /dev/null +++ b/static/third/bootstrap-tooltip/tooltip.css @@ -0,0 +1,191 @@ + +.tooltip { + position: absolute; + z-index: 1030; + display: block; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.tooltip.top { + margin-top: -3px; +} +.tooltip.right { + margin-left: 3px; +} +.tooltip.bottom { + margin-top: 3px; +} +.tooltip.left { + margin-left: -3px; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top-color: #000000; + border-width: 5px 5px 0; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-right-color: #000000; + border-width: 5px 5px 5px 0; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-left-color: #000000; + border-width: 5px 0 5px 5px; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + width: 236px; + padding: 1px; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} +.popover.top { + margin-bottom: 10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-right: 10px; +} +.popover-title { + padding: 8px 14px; + margin: 0; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + -webkit-border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; +} +.popover-content { + padding: 9px 14px; +} +.popover-content p, +.popover-content ul, +.popover-content ol { + margin-bottom: 0; +} +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: inline-block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover .arrow:after { + z-index: -1; + content: ""; +} +.popover.top .arrow { + bottom: -10px; + left: 50%; + margin-left: -10px; + border-top-color: #ffffff; + border-width: 10px 10px 0; +} +.popover.top .arrow:after { + bottom: -1px; + left: -11px; + border-top-color: rgba(0, 0, 0, 0.25); + border-width: 11px 11px 0; +} +.popover.right .arrow { + top: 50%; + left: -10px; + margin-top: -10px; + border-right-color: #ffffff; + border-width: 10px 10px 10px 0; +} +.popover.right .arrow:after { + bottom: -11px; + left: -1px; + border-right-color: rgba(0, 0, 0, 0.25); + border-width: 11px 11px 11px 0; +} +.popover.bottom .arrow { + top: -10px; + left: 50%; + margin-left: -10px; + border-bottom-color: #ffffff; + border-width: 0 10px 10px; +} +.popover.bottom .arrow:after { + top: -1px; + left: -11px; + border-bottom-color: rgba(0, 0, 0, 0.25); + border-width: 0 11px 11px; +} +.popover.left .arrow { + top: 50%; + right: -10px; + margin-top: -10px; + border-left-color: #ffffff; + border-width: 10px 0 10px 10px; +} +.popover.left .arrow:after { + right: -1px; + bottom: -11px; + border-left-color: rgba(0, 0, 0, 0.25); + border-width: 11px 0 11px 11px; +} diff --git a/static/third/bootstrap-tooltip/tooltip.js b/static/third/bootstrap-tooltip/tooltip.js new file mode 100644 index 0000000000..cbb3d2bbd2 --- /dev/null +++ b/static/third/bootstrap-tooltip/tooltip.js @@ -0,0 +1,433 @@ +/* =========================================================== + * bootstrap-tooltip.js v2.1.0 + * http://twitter.github.com/bootstrap/javascript.html#tooltips + * Inspired by the original jQuery.tipsy by Jason Frame + * =========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* TOOLTIP PUBLIC CLASS DEFINITION + * =============================== */ + + var Tooltip = function (element, options) { + this.init('tooltip', element, options) + } + + Tooltip.prototype = { + + constructor: Tooltip + + , init: function (type, element, options) { + var eventIn + , eventOut + + this.type = type + this.$element = $(element) + this.options = this.getOptions(options) + this.enabled = true + + if (this.options.trigger == 'click') { + this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) + } else if (this.options.trigger != 'manual') { + eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus' + eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur' + 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)) + } + + this.options.selector ? + (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : + this.fixTitle() + } + + , getOptions: function (options) { + options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data()) + + if (options.delay && typeof options.delay == 'number') { + options.delay = { + show: options.delay + , hide: options.delay + } + } + + return options + } + + , enter: function (e) { + var self = $(e.currentTarget)[this.type](this._options).data(this.type) + + if (!self.options.delay || !self.options.delay.show) return self.show() + + clearTimeout(this.timeout) + self.hoverState = 'in' + this.timeout = setTimeout(function() { + if (self.hoverState == 'in') self.show() + }, self.options.delay.show) + } + + , leave: function (e) { + var self = $(e.currentTarget)[this.type](this._options).data(this.type) + + if (this.timeout) clearTimeout(this.timeout) + if (!self.options.delay || !self.options.delay.hide) return self.hide() + + self.hoverState = 'out' + this.timeout = setTimeout(function() { + if (self.hoverState == 'out') self.hide() + }, self.options.delay.hide) + } + + , show: function () { + var $tip + , inside + , pos + , actualWidth + , actualHeight + , placement + , tp + , newtop + , left + , top + + if (this.hasContent() && this.enabled) { + $tip = this.tip() + this.setContent() + + if (this.options.animation) { + $tip.addClass('fade') + } + + placement = typeof this.options.placement == 'function' ? + this.options.placement.call(this, $tip[0], this.$element[0]) : + this.options.placement + + inside = /in/.test(placement) + + $tip + .remove() + .css({ top: 0, left: 0, display: 'block' }) + .appendTo(inside ? this.$element : document.body) + + pos = this.getPosition(inside) + + actualWidth = $tip[0].offsetWidth + actualHeight = $tip[0].offsetHeight + + switch (inside ? placement.split(' ')[1] : placement) { + case 'bottom': + top = pos.top + pos.height; + left = pos.left + pos.width / 2 - actualWidth / 2; + break + case 'top': + top = pos.top - actualHeight; + left = pos.left + pos.width / 2 - actualWidth / 2; + break + case 'left': + top = pos.top + pos.height / 2 - actualHeight / 2; + if (this.options.top_offset) { + top = this.options.top_offset; + } + left = pos.left - actualWidth; + break + case 'right': + top = pos.top + pos.height / 2 - actualHeight / 2; + left = pos.left + pos.width; + break + } + + if (this.options.fix_positions) { + var win_height = $(window).height(); + var win_width = $(window).width(); + + /* Ensure that the popover stays fully onscreen, + as best as we can. It might still not look + great--in some cases, we should probably just + center--but this patch makes the popover more + likely to be usable. (If the screen is super + small, obviously we can't fit it completely.) + + If you use this fix_positions option, you want + to also use the "no_arrow_popover" template. + */ + if (top < 0) { + top = 0; + $tip.find("div.arrow").hide(); + } else if (top + actualHeight > win_height - 20) { + top = win_height - actualHeight - 20; + if (top < 0) { + top = 0; + } + $tip.find("div.arrow").hide(); + } + + if (left < 0) { + left = 0; + $tip.find("div.arrow").hide(); + } else if (left + actualWidth > win_width) { + left = win_width - actualWidth; + $tip.find("div.arrow").hide(); + } + } + + tp = {top: top, left: left}; + + if (this.options.fixed) { + // If using position: fixed, position relative to top of + // viewport + newtop = tp.top - $(document).scrollTop() + tp = $.extend(tp, {top: newtop, + position: 'fixed'}) + } + + $tip + .css(tp) + .addClass(placement) + .addClass('in') + } + } + + , setContent: function () { + var $tip = this.tip() + , title = this.getTitle() + + $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) + $tip.removeClass('fade in top bottom left right') + } + + , hide: function () { + var that = this + , $tip = this.tip() + + $tip.removeClass('in') + + function removeWithAnimation() { + var timeout = setTimeout(function () { + $tip.off($.support.transition.end).remove() + }, 500) + + $tip.one($.support.transition.end, function () { + clearTimeout(timeout) + $tip.remove() + }) + } + + $.support.transition && this.$tip.hasClass('fade') ? + removeWithAnimation() : + $tip.remove() + + return this + } + + , fixTitle: function () { + var $e = this.$element + if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { + $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title') + } + } + + , hasContent: function () { + return this.getTitle() + } + + , getPosition: function (inside) { + return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), { + width: this.$element[0].offsetWidth + , height: this.$element[0].offsetHeight + }) + } + + , getTitle: function () { + var title + , $e = this.$element + , o = this.options + + title = $e.attr('data-original-title') + || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) + + return title + } + + , tip: function () { + return this.$tip = this.$tip || $(this.options.template) + } + + , validate: function () { + if (!this.$element[0].parentNode) { + this.hide() + this.$element = null + this.options = null + } + } + + , enable: function () { + this.enabled = true + } + + , disable: function () { + this.enabled = false + } + + , toggleEnabled: function () { + this.enabled = !this.enabled + } + + , toggle: function () { + this[this.tip().hasClass('in') ? 'hide' : 'show']() + } + + , destroy: function () { + this.hide().$element.off('.' + this.type).removeData(this.type) + } + + } + + + /* TOOLTIP PLUGIN DEFINITION + * ========================= */ + + $.fn.tooltip = function ( option ) { + return this.each(function () { + var $this = $(this) + , data = $this.data('tooltip') + , options = typeof option == 'object' && option + if (!data) $this.data('tooltip', (data = new Tooltip(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.tooltip.Constructor = Tooltip + + $.fn.tooltip.defaults = { + animation: true + , placement: 'top' + , selector: false + , template: '
' + , trigger: 'hover' + , title: '' + , delay: 0 + , html: false + , fixed: false + } + +}(window.jQuery); +/* =========================================================== + * bootstrap-popover.js v2.1.1 + * http://twitter.github.com/bootstrap/javascript.html#popovers + * =========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * =========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* POPOVER PUBLIC CLASS DEFINITION + * =============================== */ + + var Popover = function (element, options) { + this.init('popover', element, options) + } + + + /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js + ========================================== */ + + Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, { + + constructor: Popover + + , setContent: function () { + var $tip = this.tip() + , title = this.getTitle() + , content = this.getContent() + + $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) + $tip.find('.popover-content > *')[this.options.html ? 'html' : 'text'](content) + + $tip.removeClass('fade top bottom left right in') + } + + , hasContent: function () { + return this.getTitle() || this.getContent() + } + + , getContent: function () { + var content + , $e = this.$element + , o = this.options + + content = $e.attr('data-content') + || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content) + + return content + } + + , tip: function () { + if (!this.$tip) { + this.$tip = $(this.options.template) + } + return this.$tip + } + + , destroy: function () { + this.hide().$element.off('.' + this.type).removeData(this.type) + } + + }) + + + /* POPOVER PLUGIN DEFINITION + * ======================= */ + + $.fn.popover = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('popover') + , options = typeof option == 'object' && option + if (!data) $this.data('popover', (data = new Popover(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.popover.Constructor = Popover + + $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, { + placement: 'right' + , trigger: 'click' + , content: '' + , template: '

' + }) + +}(window.jQuery);