123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- /* Native Javascript for Bootstrap 4 | Popover
- ----------------------------------------------*/
- // POPOVER DEFINITION
- // ==================
- var Popover = function( element, options ) {
- // initialization element
- element = queryElement(element);
- // set options
- options = options || {};
- // DATA API
- var triggerData = element[getAttribute](dataTrigger), // click / hover / focus
- animationData = element[getAttribute](dataAnimation), // true / false
- placementData = element[getAttribute](dataPlacement),
- dismissibleData = element[getAttribute](dataDismissible),
- delayData = element[getAttribute](dataDelay),
- containerData = element[getAttribute](dataContainer),
- // internal strings
- component = 'popover',
- template = 'template',
- trigger = 'trigger',
- classString = 'class',
- div = 'div',
- fade = 'fade',
- dataContent = 'data-content',
- dismissible = 'dismissible',
- closeBtn = '<button type="button" class="close">×</button>',
- // check container
- containerElement = queryElement(options[container]),
- containerDataElement = queryElement(containerData),
-
- // maybe the element is inside a modal
- modal = getClosest(element,'.modal'),
-
- // maybe the element is inside a fixed navbar
- navbarFixedTop = getClosest(element,'.'+fixedTop),
- navbarFixedBottom = getClosest(element,'.'+fixedBottom);
- // set instance options
- this[template] = options[template] ? options[template] : null; // JavaScript only
- this[trigger] = options[trigger] ? options[trigger] : triggerData || hoverEvent;
- this[animation] = options[animation] && options[animation] !== fade ? options[animation] : animationData || fade;
- this[placement] = options[placement] ? options[placement] : placementData || top;
- this[delay] = parseInt(options[delay] || delayData) || 200;
- this[dismissible] = options[dismissible] || dismissibleData === 'true' ? true : false;
- this[container] = containerElement ? containerElement
- : containerDataElement ? containerDataElement
- : navbarFixedTop ? navbarFixedTop
- : navbarFixedBottom ? navbarFixedBottom
- : modal ? modal : DOC[body];
-
- // bind, content
- var self = this,
- titleString = options.title || element[getAttribute](dataTitle) || null,
- contentString = options.content || element[getAttribute](dataContent) || null;
- if ( !contentString && !this[template] ) return; // invalidate
- // constants, vars
- var popover = null, timer = 0, placementSetting = this[placement],
-
- // handlers
- dismissibleHandler = function(e) {
- if (popover !== null && e[target] === queryElement('.close',popover)) {
- self.hide();
- }
- },
- // private methods
- removePopover = function() {
- self[container].removeChild(popover);
- timer = null; popover = null;
- },
- createPopover = function() {
- titleString = options.title || element[getAttribute](dataTitle);
- contentString = options.content || element[getAttribute](dataContent);
- // fixing https://github.com/thednp/bootstrap.native/issues/233
- contentString = !!contentString ? contentString.trim() : null;
- popover = DOC[createElement](div);
- // popover arrow
- var popoverArrow = DOC[createElement](div);
- popoverArrow[setAttribute](classString,'arrow');
- popover[appendChild](popoverArrow);
- if ( contentString !== null && self[template] === null ) { //create the popover from data attributes
- popover[setAttribute]('role','tooltip');
- if (titleString !== null) {
- var popoverTitle = DOC[createElement]('h3');
- popoverTitle[setAttribute](classString,component+'-header');
- popoverTitle[innerHTML] = self[dismissible] ? titleString + closeBtn : titleString;
- popover[appendChild](popoverTitle);
- }
- //set popover content
- var popoverContent = DOC[createElement](div);
- popoverContent[setAttribute](classString,component+'-body');
- popoverContent[innerHTML] = self[dismissible] && titleString === null ? contentString + closeBtn : contentString;
- popover[appendChild](popoverContent);
- } else { // or create the popover from template
- var popoverTemplate = DOC[createElement](div);
- self[template] = self[template].trim();
- popoverTemplate[innerHTML] = self[template];
- popover[innerHTML] = popoverTemplate.firstChild[innerHTML];
- }
- //append to the container
- self[container][appendChild](popover);
- popover[style].display = 'block';
- popover[setAttribute](classString, component+ ' bs-' + component+'-'+placementSetting + ' ' + self[animation]);
- },
- showPopover = function () {
- !hasClass(popover,showClass) && ( addClass(popover,showClass) );
- },
- updatePopover = function() {
- styleTip(element, popover, placementSetting, self[container]);
- },
- // event toggle
- dismissHandlerToggle = function(type){
- if (clickEvent == self[trigger] || 'focus' == self[trigger]) {
- !self[dismissible] && type( element, 'blur', self.hide );
- }
- self[dismissible] && type( DOC, clickEvent, dismissibleHandler );
- type( globalObject, resizeEvent, self.hide, passiveHandler );
- },
- // triggers
- showTrigger = function() {
- dismissHandlerToggle(on);
- bootstrapCustomEvent.call(element, shownEvent, component);
- },
- hideTrigger = function() {
- dismissHandlerToggle(off);
- removePopover();
- bootstrapCustomEvent.call(element, hiddenEvent, component);
- };
- // public methods / handlers
- this.toggle = function() {
- if (popover === null) { self.show(); }
- else { self.hide(); }
- };
- this.show = function() {
- clearTimeout(timer);
- timer = setTimeout( function() {
- if (popover === null) {
- placementSetting = self[placement]; // we reset placement in all cases
- createPopover();
- updatePopover();
- showPopover();
- bootstrapCustomEvent.call(element, showEvent, component);
- !!self[animation] ? emulateTransitionEnd(popover, showTrigger) : showTrigger();
- }
- }, 20 );
- };
- this.hide = function() {
- clearTimeout(timer);
- timer = setTimeout( function() {
- if (popover && popover !== null && hasClass(popover,showClass)) {
- bootstrapCustomEvent.call(element, hideEvent, component);
- removeClass(popover,showClass);
- !!self[animation] ? emulateTransitionEnd(popover, hideTrigger) : hideTrigger();
- }
- }, self[delay] );
- };
- // init
- if ( !(stringPopover in element) ) { // prevent adding event handlers twice
- if (self[trigger] === hoverEvent) {
- on( element, mouseHover[0], self.show );
- if (!self[dismissible]) { on( element, mouseHover[1], self.hide ); }
- } else if (clickEvent == self[trigger] || 'focus' == self[trigger]) {
- on( element, self[trigger], self.toggle );
- }
- }
- element[stringPopover] = self;
- };
- // POPOVER DATA API
- // ================
- supports[push]( [ stringPopover, Popover, '['+dataToggle+'="popover"]' ] );
|