UNPKG

8.55 kBJavaScriptView Raw
1/* ==========================================================
2 * bootstrap-twipsy.js v1.4.0
3 * http://twitter.github.com/bootstrap/javascript.html#twipsy
4 * Adapted from the original jQuery.tipsy by Jason Frame
5 * ==========================================================
6 * Copyright 2011 Twitter, Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ========================================================== */
20
21
22!function( $ ) {
23
24 "use strict"
25
26 /* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
27 * ======================================================= */
28
29 var transitionEnd
30
31 $(document).ready(function () {
32
33 $.support.transition = (function () {
34 var thisBody = document.body || document.documentElement
35 , thisStyle = thisBody.style
36 , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
37 return support
38 })()
39
40 // set CSS transition event type
41 if ( $.support.transition ) {
42 transitionEnd = "TransitionEnd"
43 if ( $.browser.webkit ) {
44 transitionEnd = "webkitTransitionEnd"
45 } else if ( $.browser.mozilla ) {
46 transitionEnd = "transitionend"
47 } else if ( $.browser.opera ) {
48 transitionEnd = "oTransitionEnd"
49 }
50 }
51
52 })
53
54
55 /* TWIPSY PUBLIC CLASS DEFINITION
56 * ============================== */
57
58 var Twipsy = function ( element, options ) {
59 this.$element = $(element)
60 this.options = options
61 this.enabled = true
62 this.fixTitle()
63 }
64
65 Twipsy.prototype = {
66
67 show: function() {
68 var pos
69 , actualWidth
70 , actualHeight
71 , placement
72 , $tip
73 , tp
74
75 if (this.hasContent() && this.enabled) {
76 $tip = this.tip()
77 this.setContent()
78
79 if (this.options.animate) {
80 $tip.addClass('fade')
81 }
82
83 $tip
84 .remove()
85 .css({ top: 0, left: 0, display: 'block' })
86 .prependTo(document.body)
87
88 pos = $.extend({}, this.$element.offset(), {
89 width: this.$element[0].offsetWidth
90 , height: this.$element[0].offsetHeight
91 })
92
93 actualWidth = $tip[0].offsetWidth
94 actualHeight = $tip[0].offsetHeight
95
96 placement = maybeCall(this.options.placement, this, [ $tip[0], this.$element[0] ])
97
98 switch (placement) {
99 case 'below':
100 tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}
101 break
102 case 'above':
103 tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}
104 break
105 case 'left':
106 tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset}
107 break
108 case 'right':
109 tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset}
110 break
111 }
112
113 $tip
114 .css(tp)
115 .addClass(placement)
116 .addClass('in')
117 }
118 }
119
120 , setContent: function () {
121 var $tip = this.tip()
122 $tip.find('.twipsy-inner')[this.options.html ? 'html' : 'text'](this.getTitle())
123 $tip[0].className = 'twipsy'
124 }
125
126 , hide: function() {
127 var that = this
128 , $tip = this.tip()
129
130 $tip.removeClass('in')
131
132 function removeElement () {
133 $tip.remove()
134 }
135
136 $.support.transition && this.$tip.hasClass('fade') ?
137 $tip.bind(transitionEnd, removeElement) :
138 removeElement()
139 }
140
141 , fixTitle: function() {
142 var $e = this.$element
143 if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
144 $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
145 }
146 }
147
148 , hasContent: function () {
149 return this.getTitle()
150 }
151
152 , getTitle: function() {
153 var title
154 , $e = this.$element
155 , o = this.options
156
157 this.fixTitle()
158
159 if (typeof o.title == 'string') {
160 title = $e.attr(o.title == 'title' ? 'data-original-title' : o.title)
161 } else if (typeof o.title == 'function') {
162 title = o.title.call($e[0])
163 }
164
165 title = ('' + title).replace(/(^\s*|\s*$)/, "")
166
167 return title || o.fallback
168 }
169
170 , tip: function() {
171 return this.$tip = this.$tip || $('<div class="twipsy" />').html(this.options.template)
172 }
173
174 , validate: function() {
175 if (!this.$element[0].parentNode) {
176 this.hide()
177 this.$element = null
178 this.options = null
179 }
180 }
181
182 , enable: function() {
183 this.enabled = true
184 }
185
186 , disable: function() {
187 this.enabled = false
188 }
189
190 , toggleEnabled: function() {
191 this.enabled = !this.enabled
192 }
193
194 , toggle: function () {
195 this[this.tip().hasClass('in') ? 'hide' : 'show']()
196 }
197
198 }
199
200
201 /* TWIPSY PRIVATE METHODS
202 * ====================== */
203
204 function maybeCall ( thing, ctx, args ) {
205 return typeof thing == 'function' ? thing.apply(ctx, args) : thing
206 }
207
208 /* TWIPSY PLUGIN DEFINITION
209 * ======================== */
210
211 $.fn.twipsy = function (options) {
212 $.fn.twipsy.initWith.call(this, options, Twipsy, 'twipsy')
213 return this
214 }
215
216 $.fn.twipsy.initWith = function (options, Constructor, name) {
217 var twipsy
218 , binder
219 , eventIn
220 , eventOut
221
222 if (options === true) {
223 return this.data(name)
224 } else if (typeof options == 'string') {
225 twipsy = this.data(name)
226 if (twipsy) {
227 twipsy[options]()
228 }
229 return this
230 }
231
232 options = $.extend({}, $.fn[name].defaults, options)
233
234 function get(ele) {
235 var twipsy = $.data(ele, name)
236
237 if (!twipsy) {
238 twipsy = new Constructor(ele, $.fn.twipsy.elementOptions(ele, options))
239 $.data(ele, name, twipsy)
240 }
241
242 return twipsy
243 }
244
245 function enter() {
246 var twipsy = get(this)
247 twipsy.hoverState = 'in'
248
249 if (options.delayIn == 0) {
250 twipsy.show()
251 } else {
252 twipsy.fixTitle()
253 setTimeout(function() {
254 if (twipsy.hoverState == 'in') {
255 twipsy.show()
256 }
257 }, options.delayIn)
258 }
259 }
260
261 function leave() {
262 var twipsy = get(this)
263 twipsy.hoverState = 'out'
264 if (options.delayOut == 0) {
265 twipsy.hide()
266 } else {
267 setTimeout(function() {
268 if (twipsy.hoverState == 'out') {
269 twipsy.hide()
270 }
271 }, options.delayOut)
272 }
273 }
274
275 if (!options.live) {
276 this.each(function() {
277 get(this)
278 })
279 }
280
281 if (options.trigger != 'manual') {
282 binder = options.live ? 'live' : 'bind'
283 eventIn = options.trigger == 'hover' ? 'mouseenter' : 'focus'
284 eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur'
285 this[binder](eventIn, enter)[binder](eventOut, leave)
286 }
287
288 return this
289 }
290
291 $.fn.twipsy.Twipsy = Twipsy
292
293 $.fn.twipsy.defaults = {
294 animate: true
295 , delayIn: 0
296 , delayOut: 0
297 , fallback: ''
298 , placement: 'above'
299 , html: false
300 , live: false
301 , offset: 0
302 , title: 'title'
303 , trigger: 'hover'
304 , template: '<div class="twipsy-arrow"></div><div class="twipsy-inner"></div>'
305 }
306
307 $.fn.twipsy.rejectAttrOptions = [ 'title' ]
308
309 $.fn.twipsy.elementOptions = function(ele, options) {
310 var data = $(ele).data()
311 , rejects = $.fn.twipsy.rejectAttrOptions
312 , i = rejects.length
313
314 while (i--) {
315 delete data[rejects[i]]
316 }
317
318 return $.extend({}, options, data)
319 }
320
321}( window.jQuery || window.ender );
\No newline at end of file