Projet

Général

Profil

Paste
Télécharger (9,65 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / themes / simplecorp / js / plugins / jquery.tipsy.js @ b9383c72

1
// tipsy, facebook style tooltips for jquery
2
// version 1.0.0a
3
// (c) 2008-2010 jason frame [jason@onehackoranother.com]
4
// released under the MIT license
5

    
6
(function($) {
7
    
8
    function maybeCall(thing, ctx) {
9
        return (typeof thing == 'function') ? (thing.call(ctx)) : thing;
10
    };
11
    
12
    function isElementInDOM(ele) {
13
      while (ele = ele.parentNode) {
14
        if (ele == document) return true;
15
      }
16
      return false;
17
    };
18
    
19
    function Tipsy(element, options) {
20
        this.$element = $(element);
21
        this.options = options;
22
        this.enabled = true;
23
        this.fixTitle();
24
    };
25
    
26
    Tipsy.prototype = {
27
        show: function() {
28
            var title = this.getTitle();
29
            if (title && this.enabled) {
30
                var $tip = this.tip();
31
                
32
                $tip.find('.tipsy-inner')[this.options.html ? 'html' : 'text'](title);
33
                $tip[0].className = 'tipsy'; // reset classname in case of dynamic gravity
34
                $tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).prependTo(document.body);
35
                
36
                var pos = $.extend({}, this.$element.offset(), {
37
                    width: this.$element[0].offsetWidth,
38
                    height: this.$element[0].offsetHeight
39
                });
40
                
41
                var actualWidth = $tip[0].offsetWidth,
42
                    actualHeight = $tip[0].offsetHeight,
43
                    gravity = maybeCall(this.options.gravity, this.$element[0]);
44
                
45
                var tp;
46
                switch (gravity.charAt(0)) {
47
                    case 'n':
48
                        tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2};
49
                        break;
50
                    case 's':
51
                        tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2};
52
                        break;
53
                    case 'e':
54
                        tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset};
55
                        break;
56
                    case 'w':
57
                        tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset};
58
                        break;
59
                }
60
                
61
                if (gravity.length == 2) {
62
                    if (gravity.charAt(1) == 'w') {
63
                        tp.left = pos.left + pos.width / 2 - 15;
64
                    } else {
65
                        tp.left = pos.left + pos.width / 2 - actualWidth + 15;
66
                    }
67
                }
68
                
69
                $tip.css(tp).addClass('tipsy-' + gravity);
70
                $tip.find('.tipsy-arrow')[0].className = 'tipsy-arrow tipsy-arrow-' + gravity.charAt(0);
71
                if (this.options.className) {
72
                    $tip.addClass(maybeCall(this.options.className, this.$element[0]));
73
                }
74
                
75
                if (this.options.fade) {
76
                    $tip.stop().css({opacity: 0, display: 'block', visibility: 'visible'}).animate({opacity: this.options.opacity});
77
                } else {
78
                    $tip.css({visibility: 'visible', opacity: this.options.opacity});
79
                }
80
            }
81
        },
82
        
83
        hide: function() {
84
            if (this.options.fade) {
85
                this.tip().stop().fadeOut(function() { $(this).remove(); });
86
            } else {
87
                this.tip().remove();
88
            }
89
        },
90
        
91
        fixTitle: function() {
92
            var $e = this.$element;
93
            if ($e.attr('title') || typeof($e.attr('original-title')) != 'string') {
94
                $e.attr('original-title', $e.attr('title') || '').removeAttr('title');
95
            }
96
        },
97
        
98
        getTitle: function() {
99
            var title, $e = this.$element, o = this.options;
100
            this.fixTitle();
101
            var title, o = this.options;
102
            if (typeof o.title == 'string') {
103
                title = $e.attr(o.title == 'title' ? 'original-title' : o.title);
104
            } else if (typeof o.title == 'function') {
105
                title = o.title.call($e[0]);
106
            }
107
            title = ('' + title).replace(/(^\s*|\s*$)/, "");
108
            return title || o.fallback;
109
        },
110
        
111
        tip: function() {
112
            if (!this.$tip) {
113
                this.$tip = $('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>');
114
                this.$tip.data('tipsy-pointee', this.$element[0]);
115
            }
116
            return this.$tip;
117
        },
118
        
119
        validate: function() {
120
            if (!this.$element[0].parentNode) {
121
                this.hide();
122
                this.$element = null;
123
                this.options = null;
124
            }
125
        },
126
        
127
        enable: function() { this.enabled = true; },
128
        disable: function() { this.enabled = false; },
129
        toggleEnabled: function() { this.enabled = !this.enabled; }
130
    };
131
    
132
    $.fn.tipsy = function(options) {
133
        
134
        if (options === true) {
135
            return this.data('tipsy');
136
        } else if (typeof options == 'string') {
137
            var tipsy = this.data('tipsy');
138
            if (tipsy) tipsy[options]();
139
            return this;
140
        }
141
        
142
        options = $.extend({}, $.fn.tipsy.defaults, options);
143
        
144
        function get(ele) {
145
            var tipsy = $.data(ele, 'tipsy');
146
            if (!tipsy) {
147
                tipsy = new Tipsy(ele, $.fn.tipsy.elementOptions(ele, options));
148
                $.data(ele, 'tipsy', tipsy);
149
            }
150
            return tipsy;
151
        }
152
        
153
        function enter() {
154
            var tipsy = get(this);
155
            tipsy.hoverState = 'in';
156
            if (options.delayIn == 0) {
157
                tipsy.show();
158
            } else {
159
                tipsy.fixTitle();
160
                setTimeout(function() { if (tipsy.hoverState == 'in') tipsy.show(); }, options.delayIn);
161
            }
162
        };
163
        
164
        function leave() {
165
            var tipsy = get(this);
166
            tipsy.hoverState = 'out';
167
            if (options.delayOut == 0) {
168
                tipsy.hide();
169
            } else {
170
                setTimeout(function() { if (tipsy.hoverState == 'out') tipsy.hide(); }, options.delayOut);
171
            }
172
        };
173
        
174
        if (!options.live) this.each(function() { get(this); });
175
        
176
        if (options.trigger != 'manual') {
177
            var binder   = options.live ? 'live' : 'bind',
178
                eventIn  = options.trigger == 'hover' ? 'mouseenter' : 'focus',
179
                eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur';
180
            this[binder](eventIn, enter)[binder](eventOut, leave);
181
        }
182
        
183
        return this;
184
        
185
    };
186
    
187
    $.fn.tipsy.defaults = {
188
        className: null,
189
        delayIn: 0,
190
        delayOut: 0,
191
        fade: false,
192
        fallback: '',
193
        gravity: 'n',
194
        html: false,
195
        live: false,
196
        offset: 0,
197
        opacity: 0.8,
198
        title: 'title',
199
        trigger: 'hover'
200
    };
201
    
202
    $.fn.tipsy.revalidate = function() {
203
      $('.tipsy').each(function() {
204
        var pointee = $.data(this, 'tipsy-pointee');
205
        if (!pointee || !isElementInDOM(pointee)) {
206
          $(this).remove();
207
        }
208
      });
209
    };
210
    
211
    // Overwrite this method to provide options on a per-element basis.
212
    // For example, you could store the gravity in a 'tipsy-gravity' attribute:
213
    // return $.extend({}, options, {gravity: $(ele).attr('tipsy-gravity') || 'n' });
214
    // (remember - do not modify 'options' in place!)
215
    $.fn.tipsy.elementOptions = function(ele, options) {
216
        return $.metadata ? $.extend({}, options, $(ele).metadata()) : options;
217
    };
218
    
219
    $.fn.tipsy.autoNS = function() {
220
        return $(this).offset().top > ($(document).scrollTop() + $(window).height() / 2) ? 's' : 'n';
221
    };
222
    
223
    $.fn.tipsy.autoWE = function() {
224
        return $(this).offset().left > ($(document).scrollLeft() + $(window).width() / 2) ? 'e' : 'w';
225
    };
226
    
227
    /**
228
     * yields a closure of the supplied parameters, producing a function that takes
229
     * no arguments and is suitable for use as an autogravity function like so:
230
     *
231
     * @param margin (int) - distance from the viewable region edge that an
232
     *        element should be before setting its tooltip's gravity to be away
233
     *        from that edge.
234
     * @param prefer (string, e.g. 'n', 'sw', 'w') - the direction to prefer
235
     *        if there are no viewable region edges effecting the tooltip's
236
     *        gravity. It will try to vary from this minimally, for example,
237
     *        if 'sw' is preferred and an element is near the right viewable 
238
     *        region edge, but not the top edge, it will set the gravity for
239
     *        that element's tooltip to be 'se', preserving the southern
240
     *        component.
241
     */
242
     $.fn.tipsy.autoBounds = function(margin, prefer) {
243
        return function() {
244
            var dir = {ns: prefer[0], ew: (prefer.length > 1 ? prefer[1] : false)},
245
                boundTop = $(document).scrollTop() + margin,
246
                boundLeft = $(document).scrollLeft() + margin,
247
                $this = $(this);
248

    
249
            if ($this.offset().top < boundTop) dir.ns = 'n';
250
            if ($this.offset().left < boundLeft) dir.ew = 'w';
251
            if ($(window).width() + $(document).scrollLeft() - $this.offset().left < margin) dir.ew = 'e';
252
            if ($(window).height() + $(document).scrollTop() - $this.offset().top < margin) dir.ns = 's';
253

    
254
            return dir.ns + (dir.ew ? dir.ew : '');
255
        }
256
    };
257
    
258
})(jQuery);