Project

General

Profile

1
// Native Javascript for Bootstrap 3 | Tooltip
2
// by dnp_theme
3

    
4
(function(factory){
5

    
6
  // CommonJS/RequireJS and "native" compatibility
7
  if(typeof module !== "undefined" && typeof exports == "object") {
8
    // A commonJS/RequireJS environment
9
    if(typeof window != "undefined") {
10
      // Window and document exist, so return the factory's return value.
11
      module.exports = factory();
12
    } else {
13
      // Let the user give the factory a Window and Document.
14
      module.exports = factory;
15
    }
16
  } else {
17
    // Assume a traditional browser.
18
    window.Tooltip = factory();
19
  }
20

    
21
})(function(root){
22

    
23
  // TOOLTIP DEFINITION
24
  // ===================
25
  var Tooltip = function( element,options ) {
26
    options = options || {};
27
    
28
    this.link = typeof element === 'object' ? element : document.querySelector(element);
29
    this.title = this.link.getAttribute('title') || this.link.getAttribute('data-original-title');
30
    this.tooltip = null;
31
    this.options = {};
32
    this.options.animation = options.animation && options.animation !== 'fade' ? options.animation : 'fade';
33
    this.options.placement = options.placement ? options.placement : 'top';
34
    this.options.delay = parseInt(options.delay) || 100;
35
    this.isIE = (new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})").exec(navigator.userAgent) != null) ? parseFloat( RegExp.$1 ) : false;
36
    this.duration = 150;
37
    this.options.duration = this.isIE && this.isIE < 10 ? 0 : (options.duration || this.duration);
38
    this.options.container = options.container || document.body;
39
    if ( this.title ) this.init();
40
    this.timer = 0 // the link own event timer
41
  }
42

    
43
  // TOOLTIP METHODS
44
  // ================
45
  Tooltip.prototype = {
46

    
47
    init : function() {
48
      this.actions();
49
      this.rect = null;
50
      var events = ('onmouseleave' in this.link) ? [ 'mouseenter', 'mouseleave'] : [ 'mouseover', 'mouseout' ];
51
      this.link.addEventListener(events[0], this.open, false);
52
      this.link.addEventListener(events[1], this.close, false);
53
      
54
      //remove title from link
55
      this.link.setAttribute('data-original-title',this.title);
56
      this.link.removeAttribute('title');
57

    
58
    },
59

    
60
    actions : function() {
61
      var self = this;
62

    
63
      this.open = function(e) {
64
        clearTimeout(self.link.getAttribute('data-timer'));
65
        self.timer = setTimeout( function() {
66
          if (self.tooltip === null) {
67
            self.createToolTip();
68
            self.styleTooltip();
69
            self.updateTooltip()
70
          }
71
        }, self.options.duration );
72
        self.link.setAttribute('data-timer',self.timer);
73
      },
74

    
75
      this.close = function(e) {
76
        clearTimeout(self.link.getAttribute('data-timer'));
77
        self.timer = setTimeout( function() {
78
          if (self.tooltip && self.tooltip !== null) {
79
            self.tooltip.className = self.tooltip.className.replace(' in','');
80
            setTimeout(function() {
81
              self.removeToolTip(); // for performance/testing reasons we can keep the tooltips if we want
82
            }, self.options.duration);
83
          }
84

    
85
        }, self.options.delay + self.options.duration);
86
        self.link.setAttribute('data-timer',self.timer);
87
      },
88

    
89
      //remove the tooltip
90
      this.removeToolTip = function() {
91
        this.tooltip && this.options.container.removeChild(this.tooltip);
92
        this.tooltip = null;
93
      },
94

    
95
      //create the tooltip structure
96
      this.createToolTip = function() {
97
        this.tooltip = document.createElement('div');
98
        this.tooltip.setAttribute('role','tooltip');
99

    
100
        var tooltipArrow = document.createElement('div');
101
        tooltipArrow.setAttribute('class','tooltip-arrow');
102
        var tooltipInner = document.createElement('div');
103
        tooltipInner.setAttribute('class','tooltip-inner');
104

    
105
        this.tooltip.appendChild(tooltipArrow);
106
        this.tooltip.appendChild(tooltipInner);
107

    
108
        //set tooltip content
109
        tooltipInner.innerHTML = this.title;
110

    
111
        //append to the container
112
        this.options.container.appendChild(this.tooltip);
113
      },
114

    
115
      this.styleTooltip = function(pos) {
116
        this.rect = this.getRect();
117
        var placement = pos || this.options.placement;
118
        this.tooltip.setAttribute('class','tooltip '+placement+' '+this.options.animation);
119

    
120
        var linkDim = { w: this.link.offsetWidth, h: this.link.offsetHeight }; //link real dimensions
121

    
122
        // all tooltip dimensions
123
        var td = this.tooltipDimensions(this.tooltip);
124
        var toolDim = { w : td.w, h: td.h }; //tooltip real dimensions
125

    
126
        //window vertical and horizontal scroll
127
        var scrollYOffset = this.getScroll().y;
128
        var scrollXOffset =  this.getScroll().x;
129

    
130
        //apply styling
131
        if ( /top/.test(placement) ) { //TOP
132
          this.tooltip.style.top = this.rect.top + scrollYOffset - toolDim.h + 'px';
133
          this.tooltip.style.left = this.rect.left + scrollXOffset - toolDim.w/2 + linkDim.w/2 + 'px'
134

    
135
        } else if ( /bottom/.test(placement) ) { //BOTTOM
136
          this.tooltip.style.top = this.rect.top + scrollYOffset + linkDim.h + 'px';
137
          this.tooltip.style.left = this.rect.left + scrollXOffset - toolDim.w/2 + linkDim.w/2 + 'px';
138

    
139
        } else if ( /left/.test(placement) ) { //LEFT
140
          this.tooltip.style.top = this.rect.top + scrollYOffset - toolDim.h/2 + linkDim.h/2 + 'px';
141
          this.tooltip.style.left = this.rect.left + scrollXOffset - toolDim.w + 'px';
142

    
143
        } else if ( /right/.test(placement) ) { //RIGHT
144
          this.tooltip.style.top = this.rect.top + scrollYOffset - toolDim.h/2 + linkDim.h/2 + 'px';
145
          this.tooltip.style.left = this.rect.left + scrollXOffset + linkDim.w + 'px';
146
        }
147
      },
148

    
149
      this.updateTooltip = function() {
150
        var placement = null;
151
        if ( !this.isElementInViewport(this.tooltip) ) {
152
          placement = this.updatePlacement();
153
        } else {
154
          placement = this.options.placement;
155
        }
156

    
157
        this.styleTooltip(placement);
158
        this.tooltip.className += ' in';
159
      },
160
      this.updatePlacement = function() {
161
        var pos = this.options.placement;
162
        if ( /top/.test(pos) ) { //TOP
163
          return 'bottom';
164
        } else if ( /bottom/.test(pos) ) { //BOTTOM
165
          return 'top';
166
        } else if ( /left/.test(pos) ) { //LEFT
167
          return 'right';
168
        } else if ( /right/.test(pos) ) { //RIGHT
169
          return 'left';
170
        }
171
      },
172
      this.getRect = function() {
173
        return this.link.getBoundingClientRect()
174
      },
175
      this.getScroll = function() {
176
        return {
177
          y : window.pageYOffset || document.documentElement.scrollTop,
178
          x : window.pageXOffset || document.documentElement.scrollLeft
179
        }
180
      },
181
      this.tooltipDimensions  = function(t) {//check tooltip width and height
182
        return {
183
          w : t.offsetWidth,
184
          h : t.offsetHeight
185
        }
186
      },
187
      this.isElementInViewport = function(t) { // check if this.tooltip is in viewport
188
        var r = t.getBoundingClientRect();
189
        return (
190
          r.top >= 0 &&
191
          r.left >= 0 &&
192
          r.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
193
          r.right <= (window.innerWidth || document.documentElement.clientWidth)
194
        )
195
      }
196
    }
197
    }
198

    
199
  // TOOLTIP DATA API
200
  // =================
201
  var Tooltips = document.querySelectorAll('[data-toggle=tooltip]'), i = 0, tpl = Tooltips.length;
202
  for (i;i<tpl;i++){  
203
    var item = Tooltips[i], options = {};
204
    options.animation = item.getAttribute('data-animation');
205
    options.placement = item.getAttribute('data-placement');
206
    options.duration = item.getAttribute('data-duration');
207
    options.delay = item.getAttribute('data-delay');
208
    new Tooltip(item,options);
209
  }
210

    
211
  return Tooltip;
212

    
213
});
(17-17/17)