aboutsummaryrefslogtreecommitdiff
path: root/js/src
diff options
context:
space:
mode:
authorfat <[email protected]>2015-05-12 14:28:11 -0700
committerfat <[email protected]>2015-05-12 14:35:00 -0700
commita58febf71a5eac2161ce2db08c7d723755ed1163 (patch)
tree6c7356af40f579034ef6cc85976922a3de6ea457 /js/src
parent3452e8dc8336c7a4151bcccdb9d3d4202f06f294 (diff)
downloadbootstrap-a58febf71a5eac2161ce2db08c7d723755ed1163.tar.xz
bootstrap-a58febf71a5eac2161ce2db08c7d723755ed1163.zip
popover passing as well
Diffstat (limited to 'js/src')
-rw-r--r--js/src/popover.js178
-rw-r--r--js/src/scrollspy.js2
-rw-r--r--js/src/tooltip.js191
3 files changed, 263 insertions, 108 deletions
diff --git a/js/src/popover.js b/js/src/popover.js
new file mode 100644
index 000000000..6b14a2983
--- /dev/null
+++ b/js/src/popover.js
@@ -0,0 +1,178 @@
+import Tooltip from './tooltip'
+
+
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap (v4.0.0): popover.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+const Popover = (($) => {
+
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ const NAME = 'popover'
+ const VERSION = '4.0.0'
+ const DATA_KEY = 'bs.popover'
+ const JQUERY_NO_CONFLICT = $.fn[NAME]
+
+ const Default = $.extend({}, Tooltip.Default, {
+ placement : 'right',
+ trigger : 'click',
+ content : '',
+ template : '<div class="popover" role="tooltip">'
+ + '<div class="popover-arrow"></div>'
+ + '<h3 class="popover-title"></h3>'
+ + '<div class="popover-content"></div></div>'
+ })
+
+ const ClassName = {
+ FADE : 'fade',
+ IN : 'in'
+ }
+
+ const Selector = {
+ TITLE : '.popover-title',
+ CONTENT : '.popover-content',
+ ARROW : '.popover-arrow'
+ }
+
+ const Event = {
+ HIDE : 'hide.bs.popover',
+ HIDDEN : 'hidden.bs.popover',
+ SHOW : 'show.bs.popover',
+ SHOWN : 'shown.bs.popover',
+ INSERTED : 'inserted.bs.popover',
+ CLICK : 'click.bs.popover',
+ FOCUSIN : 'focusin.bs.popover',
+ FOCUSOUT : 'focusout.bs.popover',
+ MOUSEENTER : 'mouseenter.bs.popover',
+ MOUSELEAVE : 'mouseleave.bs.popover'
+ }
+
+
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+
+ class Popover extends Tooltip {
+
+
+ // getters
+
+ static get VERSION() {
+ return VERSION
+ }
+
+ static get Default() {
+ return Default
+ }
+
+ static get NAME() {
+ return NAME
+ }
+
+ static get DATA_KEY() {
+ return DATA_KEY
+ }
+
+ static get Event() {
+ return Event
+ }
+
+
+ // overrides
+
+ isWithContent() {
+ return this.getTitle() || this._getContent()
+ }
+
+ getTipElement() {
+ return (this.tip = this.tip || $(this.config.template)[0])
+ }
+
+ setContent() {
+ let tip = this.getTipElement()
+ let title = this.getTitle()
+ let content = this._getContent()
+ let titleElement = $(tip).find(Selector.TITLE)[0]
+
+ if (titleElement) {
+ titleElement[
+ this.config.html ? 'innerHTML' : 'innerText'
+ ] = title
+ }
+
+ // we use append for html objects to maintain js events
+ $(tip).find(Selector.CONTENT).children().detach().end()[
+ this.config.html ?
+ (typeof content === 'string' ? 'html' : 'append') : 'text'
+ ](content)
+
+ $(tip)
+ .removeClass(ClassName.FADE)
+ .removeClass(ClassName.IN)
+
+ this.cleanupTether()
+ }
+
+ // private
+
+ _getContent() {
+ return this.element.getAttribute('data-content')
+ || (typeof this.config.content == 'function' ?
+ this.config.content.call(this.element) :
+ this.config.content)
+ }
+
+
+ // static
+
+ static _jQueryInterface(config) {
+ return this.each(function () {
+ let data = $(this).data(DATA_KEY)
+ let _config = typeof config === 'object' ? config : null
+
+ if (!data && /destroy|hide/.test(config)) {
+ return
+ }
+
+ if (!data) {
+ data = new Popover(this, _config)
+ $(this).data(DATA_KEY, data)
+ }
+
+ if (typeof config === 'string') {
+ data[config]()
+ }
+ })
+ }
+ }
+
+
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+
+ $.fn[NAME] = Popover._jQueryInterface
+ $.fn[NAME].Constructor = Popover
+ $.fn[NAME].noConflict = function () {
+ $.fn[NAME] = JQUERY_NO_CONFLICT
+ return Popover._jQueryInterface
+ }
+
+ return Popover
+
+})(jQuery)
+
+export default Popover
diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js
index 0ab8804c6..e41a3ae12 100644
--- a/js/src/scrollspy.js
+++ b/js/src/scrollspy.js
@@ -55,7 +55,7 @@ const ScrollSpy = (($) => {
constructor(element, config) {
this._scrollElement = element.tagName === 'BODY' ? window : element
- this._config = $.extend({}, Defaults, config)
+ this._config = $.extend({}, Default, config)
this._selector = `${this._config.target || ''} .nav li > a`
this._offsets = []
this._targets = []
diff --git a/js/src/tooltip.js b/js/src/tooltip.js
index 4c09a5baf..a04085130 100644
--- a/js/src/tooltip.js
+++ b/js/src/tooltip.js
@@ -8,7 +8,7 @@ import Util from './util'
* --------------------------------------------------------------------------
*/
-const ToolTip = (($) => {
+const Tooltip = (($) => {
/**
@@ -34,33 +34,16 @@ const ToolTip = (($) => {
delay : 0,
html : false,
selector : false,
- attachment : 'top',
+ placement : 'top',
offset : '0 0',
constraints : null
}
- const HorizontalMirror = {
- LEFT : 'right',
- CENTER : 'center',
- RIGHT : 'left'
- }
-
- const VerticalMirror = {
- TOP : 'bottom',
- MIDDLE : 'middle',
- BOTTOM : 'top'
- }
-
- const VerticalDefault = {
- LEFT : 'middle',
- CENTER : 'bottom',
- RIGHT : 'middle'
- }
-
- const HorizontalDefault = {
- TOP : 'center',
- MIDDLE : 'left',
- BOTTOM : 'center'
+ const AttachmentMap = {
+ TOP : 'bottom center',
+ RIGHT : 'middle left',
+ BOTTOM : 'top center',
+ LEFT : 'middle right'
}
const HoverState = {
@@ -88,8 +71,7 @@ const ToolTip = (($) => {
const Selector = {
TOOLTIP : '.tooltip',
- TOOLTIP_INNER : '.tooltip-inner',
- TOOLTIP_ARROW : '.tooltip-arrow'
+ TOOLTIP_INNER : '.tooltip-inner'
}
const TetherClass = {
@@ -120,12 +102,12 @@ const ToolTip = (($) => {
this._timeout = 0
this._hoverState = ''
this._activeTrigger = {}
+ this._tether = null
// protected
this.element = element
this.config = this._getConfig(config)
this.tip = null
- this.tether = null
this._setListeners()
@@ -142,6 +124,19 @@ const ToolTip = (($) => {
return Default
}
+ static get NAME() {
+ return NAME
+ }
+
+ static get DATA_KEY() {
+ return DATA_KEY
+ }
+
+ static get Event() {
+ return Event
+ }
+
+
// public
@@ -159,16 +154,17 @@ const ToolTip = (($) => {
toggle(event) {
let context = this
+ let dataKey = this.constructor.DATA_KEY
if (event) {
- context = $(event.currentTarget).data(DATA_KEY)
+ context = $(event.currentTarget).data(dataKey)
if (!context) {
context = new this.constructor(
event.currentTarget,
this._getDelegateConfig()
)
- $(event.currentTarget).data(DATA_KEY, context)
+ $(event.currentTarget).data(dataKey, context)
}
context._activeTrigger.click = !context._activeTrigger.click
@@ -190,13 +186,19 @@ const ToolTip = (($) => {
clearTimeout(this._timeout)
this.hide(() => {
$(this.element)
- .off(Selector.TOOLTIP)
- .removeData(DATA_KEY)
+ .off(`.${this.constructor.NAME}`)
+ .removeData(this.constructor.DATA_KEY)
+
+ if (this.tip) {
+ $(this.tip).detach()
+ }
+
+ this.tip = null
})
}
show() {
- let showEvent = $.Event(Event.SHOW)
+ let showEvent = $.Event(this.constructor.Event.SHOW)
if (this.isWithContent() && this._isEnabled) {
$(this.element).trigger(showEvent)
@@ -211,7 +213,7 @@ const ToolTip = (($) => {
}
let tip = this.getTipElement()
- let tipId = Util.getUID(NAME)
+ let tipId = Util.getUID(this.constructor.NAME)
tip.setAttribute('id', tipId)
this.element.setAttribute('aria-describedby', tipId)
@@ -222,19 +224,20 @@ const ToolTip = (($) => {
$(tip).addClass(ClassName.FADE)
}
- let attachment = typeof this.config.attachment === 'function' ?
- this.config.attachment.call(this, tip, this.element) :
- this.config.attachment
+ let placement = typeof this.config.placement === 'function' ?
+ this.config.placement.call(this, tip, this.element) :
+ this.config.placement
- attachment = this.getAttachment(attachment)
+ let attachment = this._getAttachment(placement)
- $(tip).data(DATA_KEY, this)
+ $(tip)
+ .data(this.constructor.DATA_KEY, this)
+ .appendTo(document.body)
- this.element.parentNode.insertBefore(tip, this.element.nextSibling)
- $(this.element).trigger(Event.INSERTED)
+ $(this.element).trigger(this.constructor.Event.INSERTED)
- this.tether = new Tether({
- element : this.tip,
+ this._tether = new Tether({
+ element : tip,
target : this.element,
attachment : attachment,
classes : TetherClass,
@@ -244,7 +247,7 @@ const ToolTip = (($) => {
})
Util.reflow(tip)
- this.tether.position()
+ this._tether.position()
$(tip).addClass(ClassName.IN)
@@ -252,7 +255,7 @@ const ToolTip = (($) => {
let prevHoverState = this._hoverState
this._hoverState = null
- $(this.element).trigger(Event.SHOWN)
+ $(this.element).trigger(this.constructor.Event.SHOWN)
if (prevHoverState === HoverState.OUT) {
this._leave(null, this)
@@ -269,14 +272,14 @@ const ToolTip = (($) => {
hide(callback) {
let tip = this.getTipElement()
- let hideEvent = $.Event(Event.HIDE)
+ let hideEvent = $.Event(this.constructor.Event.HIDE)
let complete = () => {
if (this._hoverState !== HoverState.IN && tip.parentNode) {
tip.parentNode.removeChild(tip)
}
this.element.removeAttribute('aria-describedby')
- $(this.element).trigger(Event.HIDDEN)
+ $(this.element).trigger(this.constructor.Event.HIDDEN)
this.cleanupTether()
if (callback) {
@@ -317,47 +320,6 @@ const ToolTip = (($) => {
return (this.tip = this.tip || $(this.config.template)[0])
}
- getAttachment(attachmentString) {
- let attachmentArray = attachmentString.split(' ')
- let normalizedAttachment = {}
-
- if (!attachmentArray.length) {
- throw new Error('Tooltip requires attachment')
- }
-
- for (let attachment of attachmentArray) {
- attachment = attachment.toUpperCase()
-
- if (HorizontalMirror[attachment]) {
- normalizedAttachment.horizontal = HorizontalMirror[attachment]
- }
-
- if (VerticalMirror[attachment]) {
- normalizedAttachment.vertical = VerticalMirror[attachment]
- }
- }
-
- if (!normalizedAttachment.horizontal &&
- (!normalizedAttachment.vertical)) {
- throw new Error('Tooltip requires valid attachment')
- }
-
- if (!normalizedAttachment.horizontal) {
- normalizedAttachment.horizontal =
- HorizontalDefault[normalizedAttachment.vertical.toUpperCase()]
- }
-
- if (!normalizedAttachment.vertical) {
- normalizedAttachment.vertical =
- VerticalDefault[normalizedAttachment.horizontal.toUpperCase()]
- }
-
- return [
- normalizedAttachment.vertical,
- normalizedAttachment.horizontal
- ].join(' ')
- }
-
setContent() {
let tip = this.getTipElement()
let title = this.getTitle()
@@ -384,43 +346,43 @@ const ToolTip = (($) => {
return title
}
- removeTetherClasses(i, css) {
- return ((css.baseVal || css).match(
- new RegExp(`(^|\\s)${CLASS_PREFIX}-\\S+`, 'g')) || []
- ).join(' ')
- }
-
cleanupTether() {
- if (this.tether) {
- this.tether.destroy()
+ if (this._tether) {
+ this._tether.destroy()
// clean up after tether's junk classes
// remove after they fix issue
// (https://github.com/HubSpot/tether/issues/36)
- $(this.element).removeClass(this.removeTetherClasses)
- $(this.tip).removeClass(this.removeTetherClasses)
+ $(this.element).removeClass(this._removeTetherClasses)
+ $(this.tip).removeClass(this._removeTetherClasses)
}
}
// private
+ _getAttachment(placement) {
+ return AttachmentMap[placement.toUpperCase()]
+ }
+
_setListeners() {
let triggers = this.config.trigger.split(' ')
triggers.forEach((trigger) => {
if (trigger === 'click') {
$(this.element).on(
- Event.CLICK,
+ this.constructor.Event.CLICK,
this.config.selector,
this.toggle.bind(this)
)
} else if (trigger !== Trigger.MANUAL) {
let eventIn = trigger == Trigger.HOVER ?
- Event.MOUSEENTER : Event.FOCUSIN
+ this.constructor.Event.MOUSEENTER :
+ this.constructor.Event.FOCUSIN
let eventOut = trigger == Trigger.HOVER ?
- Event.MOUSELEAVE : Event.FOCUSOUT
+ this.constructor.Event.MOUSELEAVE :
+ this.constructor.Event.FOCUSOUT
$(this.element)
.on(
@@ -446,6 +408,12 @@ const ToolTip = (($) => {
}
}
+ _removeTetherClasses(i, css) {
+ return ((css.baseVal || css).match(
+ new RegExp(`(^|\\s)${CLASS_PREFIX}-\\S+`, 'g')) || []
+ ).join(' ')
+ }
+
_fixTitle() {
let titleType = typeof this.element.getAttribute('data-original-title')
if (this.element.getAttribute('title') ||
@@ -459,14 +427,16 @@ const ToolTip = (($) => {
}
_enter(event, context) {
- context = context || $(event.currentTarget).data(DATA_KEY)
+ let dataKey = this.constructor.DATA_KEY
+
+ context = context || $(event.currentTarget).data(dataKey)
if (!context) {
context = new this.constructor(
event.currentTarget,
this._getDelegateConfig()
)
- $(event.currentTarget).data(DATA_KEY, context)
+ $(event.currentTarget).data(dataKey, context)
}
if (event) {
@@ -498,19 +468,21 @@ const ToolTip = (($) => {
}
_leave(event, context) {
- context = context || $(event.currentTarget).data(DATA_KEY)
+ let dataKey = this.constructor.DATA_KEY
+
+ context = context || $(event.currentTarget).data(dataKey)
if (!context) {
context = new this.constructor(
event.currentTarget,
this._getDelegateConfig()
)
- $(event.currentTarget).data(DATA_KEY, context)
+ $(event.currentTarget).data(dataKey, context)
}
if (event) {
context._activeTrigger[
- event.type == 'focusout' ? Triger.FOCUS : Trigger.HOVER
+ event.type == 'focusout' ? Trigger.FOCUS : Trigger.HOVER
] = false
}
@@ -545,7 +517,12 @@ const ToolTip = (($) => {
}
_getConfig(config) {
- config = $.extend({}, Default, $(this.element).data(), config)
+ config = $.extend(
+ {},
+ this.constructor.Default,
+ $(this.element).data(),
+ config
+ )
if (config.delay && typeof config.delay === 'number') {
config.delay = {
@@ -563,7 +540,7 @@ const ToolTip = (($) => {
if (this.config) {
for (let key in this.config) {
let value = this.config[key]
- if (Default[key] !== value) {
+ if (this.constructor.Default[key] !== value) {
config[key] = value
}
}