4772fe24 by Insu Mun

Add missing script file.

1 parent 919ef20b
1 /*!
2 * jquery.qtip. The jQuery tooltip plugin
3 *
4 * Copyright (c) 2009 Craig Thompson
5 * http://craigsworks.com
6 *
7 * Licensed under MIT
8 * http://www.opensource.org/licenses/mit-license.php
9 *
10 * Launch : February 2009
11 * Version : 1.0.0-rc3
12 * Released: Tuesday 12th May, 2009 - 00:00
13 * Debug: jquery.qtip.debug.js
14 */
15 (function($)
16 {
17 // Implementation
18 $.fn.qtip = function(options, blanket)
19 {
20 var i, id, interfaces, opts, obj, command, config, api;
21
22 // Return API / Interfaces if requested
23 if(typeof options == 'string')
24 {
25 // Make sure API data exists if requested
26 if(typeof $(this).data('qtip') !== 'object')
27 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.NO_TOOLTIP_PRESENT, false);
28
29 // Return requested object
30 if(options == 'api')
31 return $(this).data('qtip').interfaces[ $(this).data('qtip').current ];
32 else if(options == 'interfaces')
33 return $(this).data('qtip').interfaces;
34 }
35
36 // Validate provided options
37 else
38 {
39 // Set null options object if no options are provided
40 if(!options) options = {};
41
42 // Sanitize option data
43 if(typeof options.content !== 'object' || (options.content.jquery && options.content.length > 0)) options.content = { text: options.content };
44 if(typeof options.content.title !== 'object') options.content.title = { text: options.content.title };
45 if(typeof options.position !== 'object') options.position = { corner: options.position };
46 if(typeof options.position.corner !== 'object') options.position.corner = { target: options.position.corner, tooltip: options.position.corner };
47 if(typeof options.show !== 'object') options.show = { when: options.show };
48 if(typeof options.show.when !== 'object') options.show.when = { event: options.show.when };
49 if(typeof options.show.effect !== 'object') options.show.effect = { type: options.show.effect };
50 if(typeof options.hide !== 'object') options.hide = { when: options.hide };
51 if(typeof options.hide.when !== 'object') options.hide.when = { event: options.hide.when };
52 if(typeof options.hide.effect !== 'object') options.hide.effect = { type: options.hide.effect };
53 if(typeof options.style !== 'object') options.style = { name: options.style };
54 options.style = sanitizeStyle(options.style);
55
56 // Build main options object
57 opts = $.extend(true, {}, $.fn.qtip.defaults, options);
58
59 // Inherit all style properties into one syle object and include original options
60 opts.style = buildStyle.call({ options: opts }, opts.style);
61 opts.user = $.extend(true, {}, options);
62 };
63
64 // Iterate each matched element
65 return $(this).each(function() // Return original elements as per jQuery guidelines
66 {
67 // Check for API commands
68 if(typeof options == 'string')
69 {
70 command = options.toLowerCase();
71 interfaces = $(this).qtip('interfaces');
72
73 // Make sure API data exists$('.qtip').qtip('destroy')
74 if(typeof interfaces == 'object')
75 {
76 // Check if API call is a BLANKET DESTROY command
77 if(blanket === true && command == 'destroy')
78 while(interfaces.length > 0) interfaces[interfaces.length-1].destroy();
79
80 // API call is not a BLANKET DESTROY command
81 else
82 {
83 // Check if supplied command effects this tooltip only (NOT BLANKET)
84 if(blanket !== true) interfaces = [ $(this).qtip('api') ];
85
86 // Execute command on chosen qTips
87 for(i = 0; i < interfaces.length; i++)
88 {
89 // Destroy command doesn't require tooltip to be rendered
90 if(command == 'destroy') interfaces[i].destroy();
91
92 // Only call API if tooltip is rendered and it wasn't a destroy call
93 else if(interfaces[i].status.rendered === true)
94 {
95 if(command == 'show') interfaces[i].show();
96 else if(command == 'hide') interfaces[i].hide();
97 else if(command == 'focus') interfaces[i].focus();
98 else if(command == 'disable') interfaces[i].disable(true);
99 else if(command == 'enable') interfaces[i].disable(false);
100 };
101 };
102 };
103 };
104 }
105
106 // No API commands, continue with qTip creation
107 else
108 {
109 // Create unique configuration object
110 config = $.extend(true, {}, opts);
111 config.hide.effect.length = opts.hide.effect.length;
112 config.show.effect.length = opts.show.effect.length;
113
114 // Sanitize target options
115 if(config.position.container === false) config.position.container = $(document.body);
116 if(config.position.target === false) config.position.target = $(this);
117 if(config.show.when.target === false) config.show.when.target = $(this);
118 if(config.hide.when.target === false) config.hide.when.target = $(this);
119
120 // Determine tooltip ID (Reuse array slots if possible)
121 id = $.fn.qtip.interfaces.length;
122 for(i = 0; i < id; i++)
123 {
124 if(typeof $.fn.qtip.interfaces[i] == 'undefined'){ id = i; break; };
125 };
126
127 // Instantiate the tooltip
128 obj = new qTip($(this), config, id);
129
130 // Add API references
131 $.fn.qtip.interfaces[id] = obj;
132
133 // Check if element already has qTip data assigned
134 if(typeof $(this).data('qtip') == 'object')
135 {
136 // Set new current interface id
137 if(typeof $(this).attr('qtip') === 'undefined')
138 $(this).data('qtip').current = $(this).data('qtip').interfaces.length;
139
140 // Push new API interface onto interfaces array
141 $(this).data('qtip').interfaces.push(obj);
142 }
143
144 // No qTip data is present, create now
145 else $(this).data('qtip', { current: 0, interfaces: [obj] });
146
147 // If prerendering is disabled, create tooltip on showEvent
148 if(config.content.prerender === false && config.show.when.event !== false && config.show.ready !== true)
149 {
150 config.show.when.target.bind(config.show.when.event+'.qtip-'+id+'-create', { qtip: id }, function(event)
151 {
152 // Retrieve API interface via passed qTip Id
153 api = $.fn.qtip.interfaces[ event.data.qtip ];
154
155 // Unbind show event and cache mouse coords
156 api.options.show.when.target.unbind(api.options.show.when.event+'.qtip-'+event.data.qtip+'-create');
157 api.cache.mouse = { x: event.pageX, y: event.pageY };
158
159 // Render tooltip and start the event sequence
160 construct.call( api );
161 api.options.show.when.target.trigger(api.options.show.when.event);
162 });
163 }
164
165 // Prerendering is enabled, create tooltip now
166 else
167 {
168 // Set mouse position cache to top left of the element
169 obj.cache.mouse = {
170 x: config.show.when.target.offset().left,
171 y: config.show.when.target.offset().top
172 };
173
174 // Construct the tooltip
175 construct.call(obj);
176 }
177 };
178 });
179 };
180
181 // Instantiator
182 function qTip(target, options, id)
183 {
184 // Declare this reference
185 var self = this;
186
187 // Setup class attributes
188 self.id = id;
189 self.options = options;
190 self.status = {
191 animated: false,
192 rendered: false,
193 disabled: false,
194 focused: false
195 };
196 self.elements = {
197 target: target.addClass(self.options.style.classes.target),
198 tooltip: null,
199 wrapper: null,
200 content: null,
201 contentWrapper: null,
202 title: null,
203 button: null,
204 tip: null,
205 bgiframe: null
206 };
207 self.cache = {
208 mouse: {},
209 position: {},
210 toggle: 0
211 };
212 self.timers = {};
213
214 // Define exposed API methods
215 $.extend(self, self.options.api,
216 {
217 show: function(event)
218 {
219 var returned, solo;
220
221 // Make sure tooltip is rendered and if not, return
222 if(!self.status.rendered)
223 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'show');
224
225 // Only continue if element is visible
226 if(self.elements.tooltip.css('display') !== 'none') return self;
227
228 // Clear animation queue
229 self.elements.tooltip.stop(true, false);
230
231 // Call API method and if return value is false, halt
232 returned = self.beforeShow.call(self, event);
233 if(returned === false) return self;
234
235 // Define afterShow callback method
236 function afterShow()
237 {
238 // Call API method and focus if it isn't static
239 if(self.options.position.type !== 'static') self.focus();
240 self.onShow.call(self, event);
241
242 // Prevent antialias from disappearing in IE7 by removing filter attribute
243 if($.browser.msie) self.elements.tooltip.get(0).style.removeAttribute('filter');
244 };
245
246 // Maintain toggle functionality if enabled
247 self.cache.toggle = 1;
248
249 // Update tooltip position if it isn't static
250 if(self.options.position.type !== 'static')
251 self.updatePosition(event, (self.options.show.effect.length > 0));
252
253 // Hide other tooltips if tooltip is solo
254 if(typeof self.options.show.solo == 'object') solo = $(self.options.show.solo);
255 else if(self.options.show.solo === true) solo = $('div.qtip').not(self.elements.tooltip);
256 if(solo) solo.each(function(){ if($(this).qtip('api').status.rendered === true) $(this).qtip('api').hide(); });
257
258 // Show tooltip
259 if(typeof self.options.show.effect.type == 'function')
260 {
261 self.options.show.effect.type.call(self.elements.tooltip, self.options.show.effect.length);
262 self.elements.tooltip.queue(function(){ afterShow(); $(this).dequeue(); });
263 }
264 else
265 {
266 switch(self.options.show.effect.type.toLowerCase())
267 {
268 case 'fade':
269 self.elements.tooltip.fadeIn(self.options.show.effect.length, afterShow);
270 break;
271 case 'slide':
272 self.elements.tooltip.slideDown(self.options.show.effect.length, function()
273 {
274 afterShow();
275 if(self.options.position.type !== 'static') self.updatePosition(event, true);
276 });
277 break;
278 case 'grow':
279 self.elements.tooltip.show(self.options.show.effect.length, afterShow);
280 break;
281 default:
282 self.elements.tooltip.show(null, afterShow);
283 break;
284 };
285
286 // Add active class to tooltip
287 self.elements.tooltip.addClass(self.options.style.classes.active);
288 };
289
290 // Log event and return
291 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_SHOWN, 'show');
292 },
293
294 hide: function(event)
295 {
296 var returned;
297
298 // Make sure tooltip is rendered and if not, return
299 if(!self.status.rendered)
300 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'hide');
301
302 // Only continue if element is visible
303 else if(self.elements.tooltip.css('display') === 'none') return self;
304
305 // Stop show timer and animation queue
306 clearTimeout(self.timers.show);
307 self.elements.tooltip.stop(true, false);
308
309 // Call API method and if return value is false, halt
310 returned = self.beforeHide.call(self, event);
311 if(returned === false) return self;
312
313 // Define afterHide callback method
314 function afterHide(){ self.onHide.call(self, event); };
315
316 // Maintain toggle functionality if enabled
317 self.cache.toggle = 0;
318
319 // Hide tooltip
320 if(typeof self.options.hide.effect.type == 'function')
321 {
322 self.options.hide.effect.type.call(self.elements.tooltip, self.options.hide.effect.length);
323 self.elements.tooltip.queue(function(){ afterHide(); $(this).dequeue(); });
324 }
325 else
326 {
327 switch(self.options.hide.effect.type.toLowerCase())
328 {
329 case 'fade':
330 self.elements.tooltip.fadeOut(self.options.hide.effect.length, afterHide);
331 break;
332 case 'slide':
333 self.elements.tooltip.slideUp(self.options.hide.effect.length, afterHide);
334 break;
335 case 'grow':
336 self.elements.tooltip.hide(self.options.hide.effect.length, afterHide);
337 break;
338 default:
339 self.elements.tooltip.hide(null, afterHide);
340 break;
341 };
342
343 // Remove active class to tooltip
344 self.elements.tooltip.removeClass(self.options.style.classes.active);
345 };
346
347 // Log event and return
348 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_HIDDEN, 'hide');
349 },
350
351 updatePosition: function(event, animate)
352 {
353 var i, target, tooltip, coords, mapName, imagePos, newPosition, ieAdjust, ie6Adjust, borderAdjust, mouseAdjust, offset, curPosition, returned
354
355 // Make sure tooltip is rendered and if not, return
356 if(!self.status.rendered)
357 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updatePosition');
358
359 // If tooltip is static, return
360 else if(self.options.position.type == 'static')
361 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.CANNOT_POSITION_STATIC, 'updatePosition');
362
363 // Define property objects
364 target = {
365 position: { left: 0, top: 0 },
366 dimensions: { height: 0, width: 0 },
367 corner: self.options.position.corner.target
368 };
369 tooltip = {
370 position: self.getPosition(),
371 dimensions: self.getDimensions(),
372 corner: self.options.position.corner.tooltip
373 };
374
375 // Target is an HTML element
376 if(self.options.position.target !== 'mouse')
377 {
378 // If the HTML element is AREA, calculate position manually
379 if(self.options.position.target.get(0).nodeName.toLowerCase() == 'area')
380 {
381 // Retrieve coordinates from coords attribute and parse into integers
382 coords = self.options.position.target.attr('coords').split(',');
383 for(i = 0; i < coords.length; i++) coords[i] = parseInt(coords[i]);
384
385 // Setup target position object
386 mapName = self.options.position.target.parent('map').attr('name');
387 imagePos = $('img[usemap="#'+mapName+'"]:first').offset();
388 target.position = {
389 left: Math.floor(imagePos.left + coords[0]),
390 top: Math.floor(imagePos.top + coords[1])
391 };
392
393 // Determine width and height of the area
394 switch(self.options.position.target.attr('shape').toLowerCase())
395 {
396 case 'rect':
397 target.dimensions = {
398 width: Math.ceil(Math.abs(coords[2] - coords[0])),
399 height: Math.ceil(Math.abs(coords[3] - coords[1]))
400 };
401 break;
402
403 case 'circle':
404 target.dimensions = {
405 width: coords[2] + 1,
406 height: coords[2] + 1
407 };
408 break;
409
410 case 'poly':
411 target.dimensions = {
412 width: coords[0],
413 height: coords[1]
414 };
415
416 for(i = 0; i < coords.length; i++)
417 {
418 if(i % 2 == 0)
419 {
420 if(coords[i] > target.dimensions.width)
421 target.dimensions.width = coords[i];
422 if(coords[i] < coords[0])
423 target.position.left = Math.floor(imagePos.left + coords[i]);
424 }
425 else
426 {
427 if(coords[i] > target.dimensions.height)
428 target.dimensions.height = coords[i];
429 if(coords[i] < coords[1])
430 target.position.top = Math.floor(imagePos.top + coords[i]);
431 };
432 };
433
434 target.dimensions.width = target.dimensions.width - (target.position.left - imagePos.left);
435 target.dimensions.height = target.dimensions.height - (target.position.top - imagePos.top);
436 break;
437
438 default:
439 return $.fn.qtip.log.error.call(self, 4, $.fn.qtip.constants.INVALID_AREA_SHAPE, 'updatePosition');
440 break;
441 };
442
443 // Adjust position by 2 pixels (Positioning bug?)
444 target.dimensions.width -= 2; target.dimensions.height -= 2;
445 }
446
447 // Target is the document
448 else if(self.options.position.target.add(document.body).length === 1)
449 {
450 target.position = { left: $(document).scrollLeft(), top: $(document).scrollTop() };
451 target.dimensions = { height: $(window).height(), width: $(window).width() };
452 }
453
454 // Target is a regular HTML element, find position normally
455 else
456 {
457 // Check if the target is another tooltip. If its animated, retrieve position from newPosition data
458 if(typeof self.options.position.target.attr('qtip') !== 'undefined')
459 target.position = self.options.position.target.qtip('api').cache.position;
460 else
461 target.position = self.options.position.target.offset();
462
463 // Setup dimensions objects
464 target.dimensions = {
465 height: self.options.position.target.outerHeight(),
466 width: self.options.position.target.outerWidth()
467 };
468 };
469
470 // Calculate correct target corner position
471 newPosition = $.extend({}, target.position);
472 if(target.corner.search(/right/i) !== -1)
473 newPosition.left += target.dimensions.width;
474
475 if(target.corner.search(/bottom/i) !== -1)
476 newPosition.top += target.dimensions.height;
477
478 if(target.corner.search(/((top|bottom)Middle)|center/) !== -1)
479 newPosition.left += (target.dimensions.width / 2);
480
481 if(target.corner.search(/((left|right)Middle)|center/) !== -1)
482 newPosition.top += (target.dimensions.height / 2);
483 }
484
485 // Mouse is the target, set position to current mouse coordinates
486 else
487 {
488 // Setup target position and dimensions objects
489 target.position = newPosition = { left: self.cache.mouse.x, top: self.cache.mouse.y };
490 target.dimensions = { height: 1, width: 1 };
491 };
492
493 // Calculate correct target corner position
494 if(tooltip.corner.search(/right/i) !== -1)
495 newPosition.left -= tooltip.dimensions.width;
496
497 if(tooltip.corner.search(/bottom/i) !== -1)
498 newPosition.top -= tooltip.dimensions.height;
499
500 if(tooltip.corner.search(/((top|bottom)Middle)|center/) !== -1)
501 newPosition.left -= (tooltip.dimensions.width / 2);
502
503 if(tooltip.corner.search(/((left|right)Middle)|center/) !== -1)
504 newPosition.top -= (tooltip.dimensions.height / 2);
505
506 // Setup IE adjustment variables (Pixel gap bugs)
507 ieAdjust = ($.browser.msie) ? 1 : 0; // And this is why I hate IE...
508 ie6Adjust = ($.browser.msie && parseInt($.browser.version.charAt(0)) === 6) ? 1 : 0; // ...and even more so IE6!
509
510 // Adjust for border radius
511 if(self.options.style.border.radius > 0)
512 {
513 if(tooltip.corner.search(/Left/) !== -1)
514 newPosition.left -= self.options.style.border.radius;
515 else if(tooltip.corner.search(/Right/) !== -1)
516 newPosition.left += self.options.style.border.radius;
517
518 if(tooltip.corner.search(/Top/) !== -1)
519 newPosition.top -= self.options.style.border.radius;
520 else if(tooltip.corner.search(/Bottom/) !== -1)
521 newPosition.top += self.options.style.border.radius;
522 };
523
524 // IE only adjustments (Pixel perfect!)
525 if(ieAdjust)
526 {
527 if(tooltip.corner.search(/top/) !== -1)
528 newPosition.top -= ieAdjust
529 else if(tooltip.corner.search(/bottom/) !== -1)
530 newPosition.top += ieAdjust
531
532 if(tooltip.corner.search(/left/) !== -1)
533 newPosition.left -= ieAdjust
534 else if(tooltip.corner.search(/right/) !== -1)
535 newPosition.left += ieAdjust
536
537 if(tooltip.corner.search(/leftMiddle|rightMiddle/) !== -1)
538 newPosition.top -= 1
539 };
540
541 // If screen adjustment is enabled, apply adjustments
542 if(self.options.position.adjust.screen === true)
543 newPosition = screenAdjust.call(self, newPosition, target, tooltip);
544
545 // If mouse is the target, prevent tooltip appearing directly under the mouse
546 if(self.options.position.target === 'mouse' && self.options.position.adjust.mouse === true)
547 {
548 if(self.options.position.adjust.screen === true && self.elements.tip)
549 mouseAdjust = self.elements.tip.attr('rel');
550 else
551 mouseAdjust = self.options.position.corner.tooltip;
552
553 newPosition.left += (mouseAdjust.search(/right/i) !== -1) ? -6 : 6;
554 newPosition.top += (mouseAdjust.search(/bottom/i) !== -1) ? -6 : 6;
555 }
556
557 // Initiate bgiframe plugin in IE6 if tooltip overlaps a select box or object element
558 if(!self.elements.bgiframe && $.browser.msie && parseInt($.browser.version.charAt(0)) == 6)
559 {
560 $('select, object').each(function()
561 {
562 offset = $(this).offset();
563 offset.bottom = offset.top + $(this).height();
564 offset.right = offset.left + $(this).width();
565
566 if(newPosition.top + tooltip.dimensions.height >= offset.top
567 && newPosition.left + tooltip.dimensions.width >= offset.left)
568 bgiframe.call(self);
569 });
570 };
571
572 // Add user xy adjustments
573 newPosition.left += self.options.position.adjust.x;
574 newPosition.top += self.options.position.adjust.y;
575
576 // Set new tooltip position if its moved, animate if enabled
577 curPosition = self.getPosition();
578 if(newPosition.left != curPosition.left || newPosition.top != curPosition.top)
579 {
580 // Call API method and if return value is false, halt
581 returned = self.beforePositionUpdate.call(self, event);
582 if(returned === false) return self;
583
584 // Cache new position
585 self.cache.position = newPosition;
586
587 // Check if animation is enabled
588 if(animate === true)
589 {
590 // Set animated status
591 self.status.animated = true;
592
593 // Animate and reset animated status on animation end
594 self.elements.tooltip.animate(newPosition, 200, 'swing', function(){ self.status.animated = false });
595 }
596
597 // Set new position via CSS
598 else self.elements.tooltip.css(newPosition);
599
600 // Call API method and log event if its not a mouse move
601 self.onPositionUpdate.call(self, event);
602 if(typeof event !== 'undefined' && event.type && event.type !== 'mousemove')
603 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_POSITION_UPDATED, 'updatePosition');
604 };
605
606 return self;
607 },
608
609 updateWidth: function(newWidth)
610 {
611 var hidden;
612
613 // Make sure tooltip is rendered and if not, return
614 if(!self.status.rendered)
615 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateWidth');
616
617 // Make sure supplied width is a number and if not, return
618 else if(newWidth && typeof newWidth !== 'number')
619 return $.fn.qtip.log.error.call(self, 2, 'newWidth must be of type number', 'updateWidth');
620
621 // Setup elements which must be hidden during width update
622 hidden = self.elements.contentWrapper.siblings().add(self.elements.tip).add(self.elements.button);
623
624 // Calculate the new width if one is not supplied
625 if(!newWidth)
626 {
627 // Explicit width is set
628 if(typeof self.options.style.width.value == 'number')
629 newWidth = self.options.style.width.value;
630
631 // No width is set, proceed with auto detection
632 else
633 {
634 // Set width to auto initally to determine new width and hide other elements
635 self.elements.tooltip.css({ width: 'auto' });
636 hidden.hide();
637
638 // Set position and zoom to defaults to prevent IE hasLayout bug
639 if($.browser.msie)
640 self.elements.wrapper.add(self.elements.contentWrapper.children()).css({ zoom: 'normal' });
641
642 // Set the new width
643 newWidth = self.getDimensions().width + 1;
644
645 // Make sure its within the maximum and minimum width boundries
646 if(!self.options.style.width.value)
647 {
648 if(newWidth > self.options.style.width.max) newWidth = self.options.style.width.max
649 if(newWidth < self.options.style.width.min) newWidth = self.options.style.width.min
650 };
651 };
652 };
653
654 // Adjust newWidth by 1px if width is odd (IE6 rounding bug fix)
655 if(newWidth % 2 !== 0) newWidth -= 1;
656
657 // Set the new calculated width and unhide other elements
658 self.elements.tooltip.width(newWidth);
659 hidden.show();
660
661 // Set the border width, if enabled
662 if(self.options.style.border.radius)
663 {
664 self.elements.tooltip.find('.qtip-betweenCorners').each(function(i)
665 {
666 $(this).width(newWidth - (self.options.style.border.radius * 2));
667 })
668 };
669
670 // IE only adjustments
671 if($.browser.msie)
672 {
673 // Reset position and zoom to give the wrapper layout (IE hasLayout bug)
674 self.elements.wrapper.add(self.elements.contentWrapper.children()).css({ zoom: '1' });
675
676 // Set the new width
677 self.elements.wrapper.width(newWidth);
678
679 // Adjust BGIframe height and width if enabled
680 if(self.elements.bgiframe) self.elements.bgiframe.width(newWidth).height(self.getDimensions.height);
681 };
682
683 // Log event and return
684 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_WIDTH_UPDATED, 'updateWidth');
685 },
686
687 updateStyle: function(name)
688 {
689 var tip, borders, context, corner, coordinates;
690
691 // Make sure tooltip is rendered and if not, return
692 if(!self.status.rendered)
693 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateStyle');
694
695 // Return if style is not defined or name is not a string
696 else if(typeof name !== 'string' || !$.fn.qtip.styles[name])
697 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.STYLE_NOT_DEFINED, 'updateStyle');
698
699 // Set the new style object
700 self.options.style = buildStyle.call(self, $.fn.qtip.styles[name], self.options.user.style);
701
702 // Update initial styles of content and title elements
703 self.elements.content.css( jQueryStyle(self.options.style) );
704 if(self.options.content.title.text !== false)
705 self.elements.title.css( jQueryStyle(self.options.style.title, true) );
706
707 // Update CSS border colour
708 self.elements.contentWrapper.css({ borderColor: self.options.style.border.color });
709
710 // Update tip color if enabled
711 if(self.options.style.tip.corner !== false)
712 {
713 if($('<canvas>').get(0).getContext)
714 {
715 // Retrieve canvas context and clear
716 tip = self.elements.tooltip.find('.qtip-tip canvas:first');
717 context = tip.get(0).getContext('2d');
718 context.clearRect(0,0,300,300);
719
720 // Draw new tip
721 corner = tip.parent('div[rel]:first').attr('rel');
722 coordinates = calculateTip(corner, self.options.style.tip.size.width, self.options.style.tip.size.height);
723 drawTip.call(self, tip, coordinates, self.options.style.tip.color || self.options.style.border.color);
724 }
725 else if($.browser.msie)
726 {
727 // Set new fillcolor attribute
728 tip = self.elements.tooltip.find('.qtip-tip [nodeName="shape"]');
729 tip.attr('fillcolor', self.options.style.tip.color || self.options.style.border.color);
730 };
731 };
732
733 // Update border colors if enabled
734 if(self.options.style.border.radius > 0)
735 {
736 self.elements.tooltip.find('.qtip-betweenCorners').css({ backgroundColor: self.options.style.border.color });
737
738 if($('<canvas>').get(0).getContext)
739 {
740 borders = calculateBorders(self.options.style.border.radius)
741 self.elements.tooltip.find('.qtip-wrapper canvas').each(function()
742 {
743 // Retrieve canvas context and clear
744 context = $(this).get(0).getContext('2d');
745 context.clearRect(0,0,300,300);
746
747 // Draw new border
748 corner = $(this).parent('div[rel]:first').attr('rel')
749 drawBorder.call(self, $(this), borders[corner],
750 self.options.style.border.radius, self.options.style.border.color);
751 });
752 }
753 else if($.browser.msie)
754 {
755 // Set new fillcolor attribute on each border corner
756 self.elements.tooltip.find('.qtip-wrapper [nodeName="arc"]').each(function()
757 {
758 $(this).attr('fillcolor', self.options.style.border.color)
759 });
760 };
761 };
762
763 // Log event and return
764 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_STYLE_UPDATED, 'updateStyle');
765 },
766
767 updateContent: function(content, reposition)
768 {
769 var parsedContent, images, loadedImages;
770
771 // Make sure tooltip is rendered and if not, return
772 if(!self.status.rendered)
773 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateContent');
774
775 // Make sure content is defined before update
776 else if(!content)
777 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.NO_CONTENT_PROVIDED, 'updateContent');
778
779 // Call API method and set new content if a string is returned
780 parsedContent = self.beforeContentUpdate.call(self, content);
781 if(typeof parsedContent == 'string') content = parsedContent;
782 else if(parsedContent === false) return;
783
784 // Set position and zoom to defaults to prevent IE hasLayout bug
785 if($.browser.msie) self.elements.contentWrapper.children().css({ zoom: 'normal' });
786
787 // Append new content if its a DOM array and show it if hidden
788 if(content.jquery && content.length > 0)
789 content.clone(true).appendTo(self.elements.content).show();
790
791 // Content is a regular string, insert the new content
792 else self.elements.content.html(content);
793
794 // Check if images need to be loaded before position is updated to prevent mis-positioning
795 images = self.elements.content.find('img[complete=false]');
796 if(images.length > 0)
797 {
798 loadedImages = 0;
799 images.each(function(i)
800 {
801 $('<img src="'+ $(this).attr('src') +'" />')
802 .load(function(){ if(++loadedImages == images.length) afterLoad(); });
803 });
804 }
805 else afterLoad();
806
807 function afterLoad()
808 {
809 // Update the tooltip width
810 self.updateWidth();
811
812 // If repositioning is enabled, update positions
813 if(reposition !== false)
814 {
815 // Update position if tooltip isn't static
816 if(self.options.position.type !== 'static')
817 self.updatePosition(self.elements.tooltip.is(':visible'), true);
818
819 // Reposition the tip if enabled
820 if(self.options.style.tip.corner !== false)
821 positionTip.call(self);
822 };
823 };
824
825 // Call API method and log event
826 self.onContentUpdate.call(self);
827 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_CONTENT_UPDATED, 'loadContent');
828 },
829
830 loadContent: function(url, data, method)
831 {
832 var returned;
833
834 // Make sure tooltip is rendered and if not, return
835 if(!self.status.rendered)
836 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'loadContent');
837
838 // Call API method and if return value is false, halt
839 returned = self.beforeContentLoad.call(self);
840 if(returned === false) return self;
841
842 // Load content using specified request type
843 if(method == 'post')
844 $.post(url, data, setupContent);
845 else
846 $.get(url, data, setupContent);
847
848 function setupContent(content)
849 {
850 // Call API method and log event
851 self.onContentLoad.call(self);
852 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_CONTENT_LOADED, 'loadContent');
853
854 // Update the content
855 self.updateContent(content);
856 };
857
858 return self;
859 },
860
861 updateTitle: function(content)
862 {
863 // Make sure tooltip is rendered and if not, return
864 if(!self.status.rendered)
865 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateTitle');
866
867 // Make sure content is defined before update
868 else if(!content)
869 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.NO_CONTENT_PROVIDED, 'updateTitle');
870
871 // Call API method and if return value is false, halt
872 returned = self.beforeTitleUpdate.call(self);
873 if(returned === false) return self;
874
875 // Set the content
876 self.elements.button = self.elements.button.clone(true);
877 self.elements.title.html(content).prepend(self.elements.button);
878
879 // Call API method and log event
880 self.onTitleUpdate.call(self);
881 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_TITLE_UPDATED, 'updateTitle');
882 },
883
884 focus: function(event)
885 {
886 var curIndex, newIndex, elemIndex, returned;
887
888 // Make sure tooltip is rendered and if not, return
889 if(!self.status.rendered)
890 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'focus');
891
892 else if(self.options.position.type == 'static')
893 return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.CANNOT_FOCUS_STATIC, 'focus');
894
895 // Set z-index variables
896 curIndex = parseInt( self.elements.tooltip.css('z-index') );
897 newIndex = 6000 + $('div.qtip[qtip]').length - 1;
898
899 // Only update the z-index if it has changed and tooltip is not already focused
900 if(!self.status.focused && curIndex !== newIndex)
901 {
902 // Call API method and if return value is false, halt
903 returned = self.beforeFocus.call(self, event);
904 if(returned === false) return self;
905
906 // Loop through all other tooltips
907 $('div.qtip[qtip]').not(self.elements.tooltip).each(function()
908 {
909 if($(this).qtip('api').status.rendered === true)
910 {
911 elemIndex = parseInt($(this).css('z-index'));
912
913 // Reduce all other tooltip z-index by 1
914 if(typeof elemIndex == 'number' && elemIndex > -1)
915 $(this).css({ zIndex: parseInt( $(this).css('z-index') ) - 1 });
916
917 // Set focused status to false
918 $(this).qtip('api').status.focused = false;
919 }
920 })
921
922 // Set the new z-index and set focus status to true
923 self.elements.tooltip.css({ zIndex: newIndex });
924 self.status.focused = true;
925
926 // Call API method and log event
927 self.onFocus.call(self, event);
928 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_FOCUSED, 'focus');
929 };
930
931 return self;
932 },
933
934 disable: function(state)
935 {
936 // Make sure tooltip is rendered and if not, return
937 if(!self.status.rendered)
938 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'disable');
939
940 if(state)
941 {
942 // Tooltip is not already disabled, proceed
943 if(!self.status.disabled)
944 {
945 // Set the disabled flag and log event
946 self.status.disabled = true;
947 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_DISABLED, 'disable');
948 }
949
950 // Tooltip is already disabled, inform user via log
951 else $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.TOOLTIP_ALREADY_DISABLED, 'disable');
952 }
953 else
954 {
955 // Tooltip is not already enabled, proceed
956 if(self.status.disabled)
957 {
958 // Reassign events, set disable status and log
959 self.status.disabled = false;
960 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_ENABLED, 'disable');
961 }
962
963 // Tooltip is already enabled, inform the user via log
964 else $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.TOOLTIP_ALREADY_ENABLED, 'disable');
965 };
966
967 return self;
968 },
969
970 destroy: function()
971 {
972 var i, returned, interfaces;
973
974 // Call API method and if return value is false, halt
975 returned = self.beforeDestroy.call(self);
976 if(returned === false) return self;
977
978 // Check if tooltip is rendered
979 if(self.status.rendered)
980 {
981 // Remove event handlers and remove element
982 self.options.show.when.target.unbind('mousemove.qtip', self.updatePosition);
983 self.options.show.when.target.unbind('mouseout.qtip', self.hide);
984 self.options.show.when.target.unbind(self.options.show.when.event + '.qtip');
985 self.options.hide.when.target.unbind(self.options.hide.when.event + '.qtip');
986 self.elements.tooltip.unbind(self.options.hide.when.event + '.qtip');
987 self.elements.tooltip.unbind('mouseover.qtip', self.focus);
988 self.elements.tooltip.remove();
989 }
990
991 // Tooltip isn't yet rendered, remove render event
992 else self.options.show.when.target.unbind(self.options.show.when.event+'.qtip-create');
993
994 // Check to make sure qTip data is present on target element
995 if(typeof self.elements.target.data('qtip') == 'object')
996 {
997 // Remove API references from interfaces object
998 interfaces = self.elements.target.data('qtip').interfaces;
999 if(typeof interfaces == 'object' && interfaces.length > 0)
1000 {
1001 // Remove API from interfaces array
1002 for(i = 0; i < interfaces.length - 1; i++)
1003 if(interfaces[i].id == self.id) interfaces.splice(i, 1)
1004 }
1005 }
1006 delete $.fn.qtip.interfaces[self.id];
1007
1008 // Set qTip current id to previous tooltips API if available
1009 if(typeof interfaces == 'object' && interfaces.length > 0)
1010 self.elements.target.data('qtip').current = interfaces.length -1;
1011 else
1012 self.elements.target.removeData('qtip');
1013
1014 // Call API method and log destroy
1015 self.onDestroy.call(self);
1016 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_DESTROYED, 'destroy');
1017
1018 return self.elements.target
1019 },
1020
1021 getPosition: function()
1022 {
1023 var show, offset;
1024
1025 // Make sure tooltip is rendered and if not, return
1026 if(!self.status.rendered)
1027 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'getPosition');
1028
1029 show = (self.elements.tooltip.css('display') !== 'none') ? false : true;
1030
1031 // Show and hide tooltip to make sure coordinates are returned
1032 if(show) self.elements.tooltip.css({ visiblity: 'hidden' }).show();
1033 offset = self.elements.tooltip.offset();
1034 if(show) self.elements.tooltip.css({ visiblity: 'visible' }).hide();
1035
1036 return offset;
1037 },
1038
1039 getDimensions: function()
1040 {
1041 var show, dimensions;
1042
1043 // Make sure tooltip is rendered and if not, return
1044 if(!self.status.rendered)
1045 return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'getDimensions');
1046
1047 show = (!self.elements.tooltip.is(':visible')) ? true : false;
1048
1049 // Show and hide tooltip to make sure dimensions are returned
1050 if(show) self.elements.tooltip.css({ visiblity: 'hidden' }).show();
1051 dimensions = {
1052 height: self.elements.tooltip.outerHeight(),
1053 width: self.elements.tooltip.outerWidth()
1054 };
1055 if(show) self.elements.tooltip.css({ visiblity: 'visible' }).hide();
1056
1057 return dimensions;
1058 }
1059 });
1060 };
1061
1062 // Define priamry construct function
1063 function construct()
1064 {
1065 var self, adjust, content, url, data, method, tempLength;
1066 self = this;
1067
1068 // Call API method
1069 self.beforeRender.call(self);
1070
1071 // Set rendered status to true
1072 self.status.rendered = true;
1073
1074 // Create initial tooltip elements
1075 self.elements.tooltip = '<div qtip="'+self.id+'" ' +
1076 'class="qtip '+(self.options.style.classes.tooltip || self.options.style)+'"' +
1077 'style="display:none; -moz-border-radius:0; -webkit-border-radius:0; border-radius:0;' +
1078 'position:'+self.options.position.type+';">' +
1079 ' <div class="qtip-wrapper" style="position:relative; overflow:hidden; text-align:left;">' +
1080 ' <div class="qtip-contentWrapper" style="overflow:hidden;">' +
1081 ' <div class="qtip-content '+self.options.style.classes.content+'"></div>' +
1082 '</div></div></div>';
1083
1084 // Append to container element
1085 self.elements.tooltip = $(self.elements.tooltip);
1086 self.elements.tooltip.appendTo(self.options.position.container)
1087
1088 // Setup tooltip qTip data
1089 self.elements.tooltip.data('qtip', { current: 0, interfaces: [self] });
1090
1091 // Setup element references
1092 self.elements.wrapper = self.elements.tooltip.children('div:first');
1093 self.elements.contentWrapper = self.elements.wrapper.children('div:first').css({ background: self.options.style.background });
1094 self.elements.content = self.elements.contentWrapper.children('div:first').css( jQueryStyle(self.options.style) );
1095
1096 // Apply IE hasLayout fix to wrapper and content elements
1097 if($.browser.msie) self.elements.wrapper.add(self.elements.content).css({ zoom: 1 });
1098
1099 // Setup tooltip attributes
1100 if(self.options.hide.when.event == 'unfocus') self.elements.tooltip.attr('unfocus', true);
1101
1102 // If an explicit width is set, updateWidth prior to setting content to prevent dirty rendering
1103 if(typeof self.options.style.width.value == 'number') self.updateWidth();
1104
1105 // Create borders and tips if supported by the browser
1106 if($('<canvas>').get(0).getContext || $.browser.msie)
1107 {
1108 // Create border
1109 if(self.options.style.border.radius > 0)
1110 createBorder.call(self);
1111 else
1112 self.elements.contentWrapper.css({ border: self.options.style.border.width+'px solid '+self.options.style.border.color });
1113
1114 // Create tip if enabled
1115 if(self.options.style.tip.corner !== false)
1116 createTip.call(self);
1117 }
1118
1119 // Neither canvas or VML is supported, tips and borders cannot be drawn!
1120 else
1121 {
1122 // Set defined border width
1123 self.elements.contentWrapper.css({ border: self.options.style.border.width+'px solid '+self.options.style.border.color });
1124
1125 // Reset border radius and tip
1126 self.options.style.border.radius = 0;
1127 self.options.style.tip.corner = false;
1128
1129 // Inform via log
1130 $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.CANVAS_VML_NOT_SUPPORTED, 'render');
1131 };
1132
1133 // Use the provided content string or DOM array
1134 if((typeof self.options.content.text == 'string' && self.options.content.text.length > 0)
1135 || (self.options.content.text.jquery && self.options.content.text.length > 0))
1136 content = self.options.content.text;
1137
1138 // Use title string for content if present
1139 else if(typeof self.elements.target.attr('title') == 'string' && self.elements.target.attr('title').length > 0)
1140 {
1141 content = self.elements.target.attr('title').replace("\\n", '<br />');
1142 self.elements.target.attr('title', ''); // Remove title attribute to prevent default tooltip showing
1143 }
1144
1145 // No title is present, use alt attribute instead
1146 else if(typeof self.elements.target.attr('alt') == 'string' && self.elements.target.attr('alt').length > 0)
1147 {
1148 content = self.elements.target.attr('alt').replace("\\n", '<br />');
1149 self.elements.target.attr('alt', ''); // Remove alt attribute to prevent default tooltip showing
1150 }
1151
1152 // No valid content was provided, inform via log
1153 else
1154 {
1155 content = ' ';
1156 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.NO_VALID_CONTENT, 'render');
1157 };
1158
1159 // Set the tooltips content and create title if enabled
1160 if(self.options.content.title.text !== false) createTitle.call(self);
1161 self.updateContent(content);
1162
1163 // Assign events and toggle tooltip with focus
1164 assignEvents.call(self);
1165 if(self.options.show.ready === true) self.show();
1166
1167 // Retrieve ajax content if provided
1168 if(self.options.content.url !== false)
1169 {
1170 url = self.options.content.url;
1171 data = self.options.content.data;
1172 method = self.options.content.method || 'get';
1173 self.loadContent(url, data, method);
1174 };
1175
1176 // Call API method and log event
1177 self.onRender.call(self);
1178 $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_RENDERED, 'render');
1179 };
1180
1181 // Create borders using canvas and VML
1182 function createBorder()
1183 {
1184 var self, i, width, radius, color, coordinates, containers, size, betweenWidth, betweenCorners, borderTop, borderBottom, borderCoord, sideWidth, vertWidth;
1185 self = this;
1186
1187 // Destroy previous border elements, if present
1188 self.elements.wrapper.find('.qtip-borderBottom, .qtip-borderTop').remove();
1189
1190 // Setup local variables
1191 width = self.options.style.border.width;
1192 radius = self.options.style.border.radius;
1193 color = self.options.style.border.color || self.options.style.tip.color;
1194
1195 // Calculate border coordinates
1196 coordinates = calculateBorders(radius);
1197
1198 // Create containers for the border shapes
1199 containers = {};
1200 for(i in coordinates)
1201 {
1202 // Create shape container
1203 containers[i] = '<div rel="'+i+'" style="'+((i.search(/Left/) !== -1) ? 'left' : 'right') + ':0; ' +
1204 'position:absolute; height:'+radius+'px; width:'+radius+'px; overflow:hidden; line-height:0.1px; font-size:1px">';
1205
1206 // Canvas is supported
1207 if($('<canvas>').get(0).getContext)
1208 containers[i] += '<canvas height="'+radius+'" width="'+radius+'" style="vertical-align: top"></canvas>';
1209
1210 // No canvas, but if it's IE use VML
1211 else if($.browser.msie)
1212 {
1213 size = radius * 2 + 3;
1214 containers[i] += '<v:arc stroked="false" fillcolor="'+color+'" startangle="'+coordinates[i][0]+'" endangle="'+coordinates[i][1]+'" ' +
1215 'style="width:'+size+'px; height:'+size+'px; margin-top:'+((i.search(/bottom/) !== -1) ? -2 : -1)+'px; ' +
1216 'margin-left:'+((i.search(/Right/) !== -1) ? coordinates[i][2] - 3.5 : -1)+'px; ' +
1217 'vertical-align:top; display:inline-block; behavior:url(#default#VML)"></v:arc>';
1218
1219 };
1220
1221 containers[i] += '</div>';
1222 };
1223
1224 // Create between corners elements
1225 betweenWidth = self.getDimensions().width - (Math.max(width, radius) * 2);
1226 betweenCorners = '<div class="qtip-betweenCorners" style="height:'+radius+'px; width:'+betweenWidth+'px; ' +
1227 'overflow:hidden; background-color:'+color+'; line-height:0.1px; font-size:1px;">';
1228
1229 // Create top border container
1230 borderTop = '<div class="qtip-borderTop" dir="ltr" style="height:'+radius+'px; ' +
1231 'margin-left:'+radius+'px; line-height:0.1px; font-size:1px; padding:0;">' +
1232 containers['topLeft'] + containers['topRight'] + betweenCorners;
1233 self.elements.wrapper.prepend(borderTop);
1234
1235 // Create bottom border container
1236 borderBottom = '<div class="qtip-borderBottom" dir="ltr" style="height:'+radius+'px; ' +
1237 'margin-left:'+radius+'px; line-height:0.1px; font-size:1px; padding:0;">' +
1238 containers['bottomLeft'] + containers['bottomRight'] + betweenCorners;
1239 self.elements.wrapper.append(borderBottom);
1240
1241 // Draw the borders if canvas were used (Delayed til after DOM creation)
1242 if($('<canvas>').get(0).getContext)
1243 {
1244 self.elements.wrapper.find('canvas').each(function()
1245 {
1246 borderCoord = coordinates[ $(this).parent('[rel]:first').attr('rel') ];
1247 drawBorder.call(self, $(this), borderCoord, radius, color);
1248 })
1249 }
1250
1251 // Create a phantom VML element (IE won't show the last created VML element otherwise)
1252 else if($.browser.msie) self.elements.tooltip.append('<v:image style="behavior:url(#default#VML);"></v:image>');
1253
1254 // Setup contentWrapper border
1255 sideWidth = Math.max(radius, (radius + (width - radius)) )
1256 vertWidth = Math.max(width - radius, 0);
1257 self.elements.contentWrapper.css({
1258 border: '0px solid ' + color,
1259 borderWidth: vertWidth + 'px ' + sideWidth + 'px'
1260 })
1261 };
1262
1263 // Border canvas draw method
1264 function drawBorder(canvas, coordinates, radius, color)
1265 {
1266 // Create corner
1267 var context = canvas.get(0).getContext('2d');
1268 context.fillStyle = color;
1269 context.beginPath();
1270 context.arc(coordinates[0], coordinates[1], radius, 0, Math.PI * 2, false);
1271 context.fill();
1272 };
1273
1274 // Create tip using canvas and VML
1275 function createTip(corner)
1276 {
1277 var self, color, coordinates, coordsize, path;
1278 self = this;
1279
1280 // Destroy previous tip, if there is one
1281 if(self.elements.tip !== null) self.elements.tip.remove();
1282
1283 // Setup color and corner values
1284 color = self.options.style.tip.color || self.options.style.border.color;
1285 if(self.options.style.tip.corner === false) return;
1286 else if(!corner) corner = self.options.style.tip.corner;
1287
1288 // Calculate tip coordinates
1289 coordinates = calculateTip(corner, self.options.style.tip.size.width, self.options.style.tip.size.height);
1290
1291 // Create tip element
1292 self.elements.tip = '<div class="'+self.options.style.classes.tip+'" dir="ltr" rel="'+corner+'" style="position:absolute; ' +
1293 'height:'+self.options.style.tip.size.height+'px; width:'+self.options.style.tip.size.width+'px; ' +
1294 'margin:0 auto; line-height:0.1px; font-size:1px;">';
1295
1296 // Use canvas element if supported
1297 if($('<canvas>').get(0).getContext)
1298 self.elements.tip += '<canvas height="'+self.options.style.tip.size.height+'" width="'+self.options.style.tip.size.width+'"></canvas>';
1299
1300 // Canvas not supported - Use VML (IE)
1301 else if($.browser.msie)
1302 {
1303 // Create coordize and tip path using tip coordinates
1304 coordsize = self.options.style.tip.size.width + ',' + self.options.style.tip.size.height;
1305 path = 'm' + coordinates[0][0] + ',' + coordinates[0][1];
1306 path += ' l' + coordinates[1][0] + ',' + coordinates[1][1];
1307 path += ' ' + coordinates[2][0] + ',' + coordinates[2][1];
1308 path += ' xe';
1309
1310 // Create VML element
1311 self.elements.tip += '<v:shape fillcolor="'+color+'" stroked="false" filled="true" path="'+path+'" coordsize="'+coordsize+'" ' +
1312 'style="width:'+self.options.style.tip.size.width+'px; height:'+self.options.style.tip.size.height+'px; ' +
1313 'line-height:0.1px; display:inline-block; behavior:url(#default#VML); ' +
1314 'vertical-align:'+((corner.search(/top/) !== -1) ? 'bottom' : 'top')+'"></v:shape>';
1315
1316 // Create a phantom VML element (IE won't show the last created VML element otherwise)
1317 self.elements.tip += '<v:image style="behavior:url(#default#VML);"></v:image>';
1318
1319 // Prevent tooltip appearing above the content (IE z-index bug)
1320 self.elements.contentWrapper.css('position', 'relative');
1321 };
1322
1323 // Attach new tip to tooltip element
1324 self.elements.tooltip.prepend(self.elements.tip + '</div>');
1325
1326 // Create element reference and draw the canvas tip (Delayed til after DOM creation)
1327 self.elements.tip = self.elements.tooltip.find('.'+self.options.style.classes.tip).eq(0);
1328 if($('<canvas>').get(0).getContext)
1329 drawTip.call(self, self.elements.tip.find('canvas:first'), coordinates, color);
1330
1331 // Fix IE small tip bug
1332 if(corner.search(/top/) !== -1 && $.browser.msie && parseInt($.browser.version.charAt(0)) === 6)
1333 self.elements.tip.css({ marginTop: -4 });
1334
1335 // Set the tip position
1336 positionTip.call(self, corner);
1337 };
1338
1339 // Canvas tip drawing method
1340 function drawTip(canvas, coordinates, color)
1341 {
1342 // Setup properties
1343 var context = canvas.get(0).getContext('2d');
1344 context.fillStyle = color;
1345
1346 // Create tip
1347 context.beginPath();
1348 context.moveTo(coordinates[0][0], coordinates[0][1]);
1349 context.lineTo(coordinates[1][0], coordinates[1][1]);
1350 context.lineTo(coordinates[2][0], coordinates[2][1]);
1351 context.fill();
1352 };
1353
1354 function positionTip(corner)
1355 {
1356 var self, ieAdjust, paddingCorner, paddingSize, newMargin;
1357 self = this;
1358
1359 // Return if tips are disabled or tip is not yet rendered
1360 if(self.options.style.tip.corner === false || !self.elements.tip) return;
1361 if(!corner) corner = self.elements.tip.attr('rel');
1362
1363 // Setup adjustment variables
1364 ieAdjust = positionAdjust = ($.browser.msie) ? 1 : 0;
1365
1366 // Set initial position
1367 self.elements.tip.css(corner.match(/left|right|top|bottom/)[0], 0);
1368
1369 // Set position of tip to correct side
1370 if(corner.search(/top|bottom/) !== -1)
1371 {
1372 // Adjustments for IE6 - 0.5px border gap bug
1373 if($.browser.msie)
1374 {
1375 if(parseInt($.browser.version.charAt(0)) === 6)
1376 positionAdjust = (corner.search(/top/) !== -1) ? -3 : 1;
1377 else
1378 positionAdjust = (corner.search(/top/) !== -1) ? 1 : 2;
1379 };
1380
1381 if(corner.search(/Middle/) !== -1)
1382 self.elements.tip.css({ left: '50%', marginLeft: -(self.options.style.tip.size.width / 2) });
1383
1384 else if(corner.search(/Left/) !== -1)
1385 self.elements.tip.css({ left: self.options.style.border.radius - ieAdjust });
1386
1387 else if(corner.search(/Right/) !== -1)
1388 self.elements.tip.css({ right: self.options.style.border.radius + ieAdjust });
1389
1390 if(corner.search(/top/) !== -1)
1391 self.elements.tip.css({ top: -positionAdjust });
1392 else
1393 self.elements.tip.css({ bottom: positionAdjust });
1394
1395 }
1396 else if(corner.search(/left|right/) !== -1)
1397 {
1398 // Adjustments for IE6 - 0.5px border gap bug
1399 if($.browser.msie)
1400 positionAdjust = (parseInt($.browser.version.charAt(0)) === 6) ? 1 : ((corner.search(/left/) !== -1) ? 1 : 2);
1401
1402 if(corner.search(/Middle/) !== -1)
1403 self.elements.tip.css({ top: '50%', marginTop: -(self.options.style.tip.size.height / 2) });
1404
1405 else if(corner.search(/Top/) !== -1)
1406 self.elements.tip.css({ top: self.options.style.border.radius - ieAdjust });
1407
1408 else if(corner.search(/Bottom/) !== -1)
1409 self.elements.tip.css({ bottom: self.options.style.border.radius + ieAdjust });
1410
1411 if(corner.search(/left/) !== -1)
1412 self.elements.tip.css({ left: -positionAdjust });
1413 else
1414 self.elements.tip.css({ right: positionAdjust });
1415 };
1416
1417 // Adjust tooltip padding to compensate for tip
1418 paddingCorner = 'padding-' + corner.match(/left|right|top|bottom/)[0];
1419 paddingSize = self.options.style.tip.size[ (paddingCorner.search(/left|right/) !== -1) ? 'width' : 'height' ];
1420 self.elements.tooltip.css('padding', 0);
1421 self.elements.tooltip.css(paddingCorner, paddingSize);
1422
1423 // Match content margin to prevent gap bug in IE6 ONLY
1424 if($.browser.msie && parseInt($.browser.version.charAt(0)) == 6)
1425 {
1426 newMargin = parseInt(self.elements.tip.css('margin-top')) || 0;
1427 newMargin += parseInt(self.elements.content.css('margin-top')) || 0;
1428
1429 self.elements.tip.css({ marginTop: newMargin });
1430 };
1431 };
1432
1433 // Create title bar for content
1434 function createTitle()
1435 {
1436 var self = this;
1437
1438 // Destroy previous title element, if present
1439 if(self.elements.title !== null) self.elements.title.remove();
1440
1441 // Create title element
1442 self.elements.title = $('<div class="'+self.options.style.classes.title+'">')
1443 .css( jQueryStyle(self.options.style.title, true) )
1444 .css({ zoom: ($.browser.msie) ? 1 : 0 })
1445 .prependTo(self.elements.contentWrapper);
1446
1447 // Update title with contents if enabled
1448 if(self.options.content.title.text) self.updateTitle.call(self, self.options.content.title.text);
1449
1450 // Create title close buttons if enabled
1451 if(self.options.content.title.button !== false
1452 && typeof self.options.content.title.button == 'string')
1453 {
1454 self.elements.button = $('<a class="'+self.options.style.classes.button+'" style="float:right; position: relative"></a>')
1455 .css( jQueryStyle(self.options.style.button, true) )
1456 .html(self.options.content.title.button)
1457 .prependTo(self.elements.title)
1458 .click(function(event){ if(!self.status.disabled) self.hide(event) });
1459 };
1460 };
1461
1462 // Assign hide and show events
1463 function assignEvents()
1464 {
1465 var self, showTarget, hideTarget, inactiveEvents;
1466 self = this;
1467
1468 // Setup event target variables
1469 showTarget = self.options.show.when.target;
1470 hideTarget = self.options.hide.when.target;
1471
1472 // Add tooltip as a hideTarget is its fixed
1473 if(self.options.hide.fixed) hideTarget = hideTarget.add(self.elements.tooltip);
1474
1475 // Check if the hide event is special 'inactive' type
1476 if(self.options.hide.when.event == 'inactive')
1477 {
1478 // Define events which reset the 'inactive' event handler
1479 inactiveEvents = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove',
1480 'mouseout', 'mouseenter', 'mouseleave', 'mouseover' ];
1481
1482 // Define 'inactive' event timer method
1483 function inactiveMethod(event)
1484 {
1485 if(self.status.disabled === true) return;
1486
1487 //Clear and reset the timer
1488 clearTimeout(self.timers.inactive);
1489 self.timers.inactive = setTimeout(function()
1490 {
1491 // Unassign 'inactive' events
1492 $(inactiveEvents).each(function()
1493 {
1494 hideTarget.unbind(this+'.qtip-inactive');
1495 self.elements.content.unbind(this+'.qtip-inactive');
1496 });
1497
1498 // Hide the tooltip
1499 self.hide(event);
1500 }
1501 , self.options.hide.delay);
1502 };
1503 }
1504
1505 // Check if the tooltip is 'fixed'
1506 else if(self.options.hide.fixed === true)
1507 {
1508 self.elements.tooltip.bind('mouseover.qtip', function()
1509 {
1510 if(self.status.disabled === true) return;
1511
1512 // Reset the hide timer
1513 clearTimeout(self.timers.hide);
1514 });
1515 };
1516
1517 // Define show event method
1518 function showMethod(event)
1519 {
1520 if(self.status.disabled === true) return;
1521
1522 // If set, hide tooltip when inactive for delay period
1523 if(self.options.hide.when.event == 'inactive')
1524 {
1525 // Assign each reset event
1526 $(inactiveEvents).each(function()
1527 {
1528 hideTarget.bind(this+'.qtip-inactive', inactiveMethod);
1529 self.elements.content.bind(this+'.qtip-inactive', inactiveMethod);
1530 });
1531
1532 // Start the inactive timer
1533 inactiveMethod();
1534 };
1535
1536 // Clear hide timers
1537 clearTimeout(self.timers.show);
1538 clearTimeout(self.timers.hide);
1539
1540 // Start show timer
1541 self.timers.show = setTimeout(function(){ self.show(event); }, self.options.show.delay);
1542 };
1543
1544 // Define hide event method
1545 function hideMethod(event)
1546 {
1547 if(self.status.disabled === true) return;
1548
1549 // Prevent hiding if tooltip is fixed and event target is the tooltip
1550 if(self.options.hide.fixed === true
1551 && self.options.hide.when.event.search(/mouse(out|leave)/i) !== -1
1552 && $(event.relatedTarget).parents('div.qtip[qtip]').length > 0)
1553 {
1554 // Prevent default and popagation
1555 event.stopPropagation();
1556 event.preventDefault();
1557
1558 // Reset the hide timer
1559 clearTimeout(self.timers.hide);
1560 return false;
1561 };
1562
1563 // Clear timers and stop animation queue
1564 clearTimeout(self.timers.show);
1565 clearTimeout(self.timers.hide);
1566 self.elements.tooltip.stop(true, true);
1567
1568 // If tooltip has displayed, start hide timer
1569 self.timers.hide = setTimeout(function(){ self.hide(event); }, self.options.hide.delay);
1570 };
1571
1572 // Both events and targets are identical, apply events using a toggle
1573 if((self.options.show.when.target.add(self.options.hide.when.target).length === 1
1574 && self.options.show.when.event == self.options.hide.when.event
1575 && self.options.hide.when.event !== 'inactive')
1576 || self.options.hide.when.event == 'unfocus')
1577 {
1578 self.cache.toggle = 0;
1579 // Use a toggle to prevent hide/show conflicts
1580 showTarget.bind(self.options.show.when.event + '.qtip', function(event)
1581 {
1582 if(self.cache.toggle == 0) showMethod(event);
1583 else hideMethod(event);
1584 });
1585 }
1586
1587 // Events are not identical, bind normally
1588 else
1589 {
1590 showTarget.bind(self.options.show.when.event + '.qtip', showMethod);
1591
1592 // If the hide event is not 'inactive', bind the hide method
1593 if(self.options.hide.when.event !== 'inactive')
1594 hideTarget.bind(self.options.hide.when.event + '.qtip', hideMethod);
1595 };
1596
1597 // Focus the tooltip on mouseover
1598 if(self.options.position.type.search(/(fixed|absolute)/) !== -1)
1599 self.elements.tooltip.bind('mouseover.qtip', self.focus);
1600
1601 // If mouse is the target, update tooltip position on mousemove
1602 if(self.options.position.target === 'mouse' && self.options.position.type !== 'static')
1603 {
1604 showTarget.bind('mousemove.qtip', function(event)
1605 {
1606 // Set the new mouse positions if adjustment is enabled
1607 self.cache.mouse = { x: event.pageX, y: event.pageY };
1608
1609 // Update the tooltip position only if the tooltip is visible and adjustment is enabled
1610 if(self.status.disabled === false
1611 && self.options.position.adjust.mouse === true
1612 && self.options.position.type !== 'static'
1613 && self.elements.tooltip.css('display') !== 'none')
1614 self.updatePosition(event);
1615 });
1616 };
1617 };
1618
1619 // Screen position adjustment
1620 function screenAdjust(position, target, tooltip)
1621 {
1622 var self, adjustedPosition, adjust, newCorner, overflow, corner;
1623 self = this;
1624
1625 // Setup corner and adjustment variable
1626 if(tooltip.corner == 'center') return target.position // TODO: 'center' corner adjustment
1627 adjustedPosition = $.extend({}, position);
1628 newCorner = { x: false, y: false };
1629
1630 // Define overflow properties
1631 overflow = {
1632 left: (adjustedPosition.left < $.fn.qtip.cache.screen.scroll.left),
1633 right: (adjustedPosition.left + tooltip.dimensions.width + 2 >= $.fn.qtip.cache.screen.width + $.fn.qtip.cache.screen.scroll.left),
1634 top: (adjustedPosition.top < $.fn.qtip.cache.screen.scroll.top),
1635 bottom: (adjustedPosition.top + tooltip.dimensions.height + 2 >= $.fn.qtip.cache.screen.height + $.fn.qtip.cache.screen.scroll.top)
1636 };
1637
1638 // Determine new positioning properties
1639 adjust = {
1640 left: (overflow.left && (tooltip.corner.search(/right/i) != -1 || (tooltip.corner.search(/right/i) == -1 && !overflow.right))),
1641 right: (overflow.right && (tooltip.corner.search(/left/i) != -1 || (tooltip.corner.search(/left/i) == -1 && !overflow.left))),
1642 top: (overflow.top && tooltip.corner.search(/top/i) == -1),
1643 bottom: (overflow.bottom && tooltip.corner.search(/bottom/i) == -1)
1644 };
1645
1646 // Tooltip overflows off the left side of the screen
1647 if(adjust.left)
1648 {
1649 if(self.options.position.target !== 'mouse')
1650 adjustedPosition.left = target.position.left + target.dimensions.width;
1651 else
1652 adjustedPosition.left = self.cache.mouse.x
1653
1654 newCorner.x = 'Left';
1655 }
1656
1657 // Tooltip overflows off the right side of the screen
1658 else if(adjust.right)
1659 {
1660 if(self.options.position.target !== 'mouse')
1661 adjustedPosition.left = target.position.left - tooltip.dimensions.width;
1662 else
1663 adjustedPosition.left = self.cache.mouse.x - tooltip.dimensions.width;
1664
1665 newCorner.x = 'Right';
1666 };
1667
1668 // Tooltip overflows off the top of the screen
1669 if(adjust.top)
1670 {
1671 if(self.options.position.target !== 'mouse')
1672 adjustedPosition.top = target.position.top + target.dimensions.height;
1673 else
1674 adjustedPosition.top = self.cache.mouse.y
1675
1676 newCorner.y = 'top';
1677 }
1678
1679 // Tooltip overflows off the bottom of the screen
1680 else if(adjust.bottom)
1681 {
1682 if(self.options.position.target !== 'mouse')
1683 adjustedPosition.top = target.position.top - tooltip.dimensions.height;
1684 else
1685 adjustedPosition.top = self.cache.mouse.y - tooltip.dimensions.height;
1686
1687 newCorner.y = 'bottom';
1688 };
1689
1690 // Don't adjust if resulting position is negative
1691 if(adjustedPosition.left < 0)
1692 {
1693 adjustedPosition.left = position.left;
1694 newCorner.x = false;
1695 };
1696 if(adjustedPosition.top < 0)
1697 {
1698 adjustedPosition.top = position.top;
1699 newCorner.y = false;
1700 };
1701
1702 // Change tip corner if positioning has changed and tips are enabled
1703 if(self.options.style.tip.corner !== false)
1704 {
1705 // Determine new corner properties
1706 adjustedPosition.corner = new String(tooltip.corner);
1707 if(newCorner.x !== false) adjustedPosition.corner = adjustedPosition.corner.replace(/Left|Right|Middle/, newCorner.x);
1708 if(newCorner.y !== false) adjustedPosition.corner = adjustedPosition.corner.replace(/top|bottom/, newCorner.y);
1709
1710 // Adjust tip if position has changed and tips are enabled
1711 if(adjustedPosition.corner !== self.elements.tip.attr('rel'))
1712 createTip.call(self, adjustedPosition.corner);
1713 };
1714
1715 return adjustedPosition;
1716 };
1717
1718 // Build a jQuery style object from supplied style object
1719 function jQueryStyle(style, sub)
1720 {
1721 var styleObj, i;
1722
1723 styleObj = $.extend(true, {}, style);
1724 for(i in styleObj)
1725 {
1726 if(sub === true && i.search(/(tip|classes)/i) !== -1)
1727 delete styleObj[i];
1728 else if(!sub && i.search(/(width|border|tip|title|classes|user)/i) !== -1)
1729 delete styleObj[i];
1730 };
1731
1732 return styleObj;
1733 };
1734
1735 // Sanitize styles
1736 function sanitizeStyle(style)
1737 {
1738 if(typeof style.tip !== 'object') style.tip = { corner: style.tip };
1739 if(typeof style.tip.size !== 'object') style.tip.size = { width: style.tip.size, height: style.tip.size };
1740 if(typeof style.border !== 'object') style.border = { width: style.border };
1741 if(typeof style.width !== 'object') style.width = { value: style.width };
1742 if(typeof style.width.max == 'string') style.width.max = parseInt(style.width.max.replace(/([0-9]+)/i, "$1"));
1743 if(typeof style.width.min == 'string') style.width.min = parseInt(style.width.min.replace(/([0-9]+)/i, "$1"));
1744
1745 // Convert deprecated x and y tip values to width/height
1746 if(typeof style.tip.size.x == 'number')
1747 {
1748 style.tip.size.width = style.tip.size.x;
1749 delete style.tip.size.x;
1750 };
1751 if(typeof style.tip.size.y == 'number')
1752 {
1753 style.tip.size.height = style.tip.size.y;
1754 delete style.tip.size.y;
1755 };
1756
1757 return style;
1758 };
1759
1760 // Build styles recursively with inheritance
1761 function buildStyle()
1762 {
1763 var self, i, styleArray, styleExtend, finalStyle, ieAdjust;
1764 self = this;
1765
1766 // Build style options from supplied arguments
1767 styleArray = [true, {}];
1768 for(i = 0; i < arguments.length; i++)
1769 styleArray.push(arguments[i]);
1770 styleExtend = [ $.extend.apply($, styleArray) ];
1771
1772 // Loop through each named style inheritance
1773 while(typeof styleExtend[0].name == 'string')
1774 {
1775 // Sanitize style data and append to extend array
1776 styleExtend.unshift( sanitizeStyle($.fn.qtip.styles[ styleExtend[0].name ]) );
1777 };
1778
1779 // Make sure resulting tooltip className represents final style
1780 styleExtend.unshift(true, {classes:{ tooltip: 'qtip-' + (arguments[0].name || 'defaults') }}, $.fn.qtip.styles.defaults);
1781
1782 // Extend into a single style object
1783 finalStyle = $.extend.apply($, styleExtend);
1784
1785 // Adjust tip size if needed (IE 1px adjustment bug fix)
1786 ieAdjust = ($.browser.msie) ? 1 : 0;
1787 finalStyle.tip.size.width += ieAdjust;
1788 finalStyle.tip.size.height += ieAdjust;
1789
1790 // Force even numbers for pixel precision
1791 if(finalStyle.tip.size.width % 2 > 0) finalStyle.tip.size.width += 1;
1792 if(finalStyle.tip.size.height % 2 > 0) finalStyle.tip.size.height += 1;
1793
1794 // Sanitize final styles tip corner value
1795 if(finalStyle.tip.corner === true)
1796 finalStyle.tip.corner = (self.options.position.corner.tooltip === 'center') ? false : self.options.position.corner.tooltip;
1797
1798 return finalStyle;
1799 };
1800
1801 // Tip coordinates calculator
1802 function calculateTip(corner, width, height)
1803 {
1804 // Define tip coordinates in terms of height and width values
1805 var tips = {
1806 bottomRight: [[0,0], [width,height], [width,0]],
1807 bottomLeft: [[0,0], [width,0], [0,height]],
1808 topRight: [[0,height], [width,0], [width,height]],
1809 topLeft: [[0,0], [0,height], [width,height]],
1810 topMiddle: [[0,height], [width / 2,0], [width,height]],
1811 bottomMiddle: [[0,0], [width,0], [width / 2,height]],
1812 rightMiddle: [[0,0], [width,height / 2], [0,height]],
1813 leftMiddle: [[width,0], [width,height], [0,height / 2]]
1814 };
1815 tips.leftTop = tips.bottomRight;
1816 tips.rightTop = tips.bottomLeft;
1817 tips.leftBottom = tips.topRight;
1818 tips.rightBottom = tips.topLeft;
1819
1820 return tips[corner];
1821 };
1822
1823 // Border coordinates calculator
1824 function calculateBorders(radius)
1825 {
1826 var borders;
1827
1828 // Use canvas element if supported
1829 if($('<canvas>').get(0).getContext)
1830 {
1831 borders = {
1832 topLeft: [radius,radius], topRight: [0,radius],
1833 bottomLeft: [radius,0], bottomRight: [0,0]
1834 };
1835 }
1836
1837 // Canvas not supported - Use VML (IE)
1838 else if($.browser.msie)
1839 {
1840 borders = {
1841 topLeft: [-90,90,0], topRight: [-90,90,-radius],
1842 bottomLeft: [90,270,0], bottomRight: [90, 270,-radius]
1843 };
1844 };
1845
1846 return borders;
1847 };
1848
1849 // BGIFRAME JQUERY PLUGIN ADAPTION
1850 // Special thanks to Brandon Aaron for this plugin
1851 // http://plugins.jquery.com/project/bgiframe
1852 function bgiframe()
1853 {
1854 var self, html, dimensions;
1855 self = this;
1856 dimensions = self.getDimensions();
1857
1858 // Setup iframe HTML string
1859 html = '<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:false" '+
1860 'style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=\'0\'); border: 1px solid red; ' +
1861 'height:'+dimensions.height+'px; width:'+dimensions.width+'px" />';
1862
1863 // Append the new HTML and setup element reference
1864 self.elements.bgiframe = self.elements.wrapper.prepend(html).children('.qtip-bgiframe:first');
1865 };
1866
1867 // Assign cache and event initialisation on document load
1868 $(document).ready(function()
1869 {
1870 // Setup library cache with window scroll and dimensions of document
1871 $.fn.qtip.cache = {
1872 screen: {
1873 scroll: { left: $(window).scrollLeft(), top: $(window).scrollTop() },
1874 width: $(window).width(),
1875 height: $(window).height()
1876 }
1877 };
1878
1879 // Adjust positions of the tooltips on window resize or scroll if enabled
1880 var adjustTimer;
1881 $(window).bind('resize scroll', function(event)
1882 {
1883 clearTimeout(adjustTimer);
1884 adjustTimer = setTimeout(function()
1885 {
1886 // Readjust cached screen values
1887 if(event.type === 'scroll')
1888 $.fn.qtip.cache.screen.scroll = { left: $(window).scrollLeft(), top: $(window).scrollTop() };
1889 else
1890 {
1891 $.fn.qtip.cache.screen.width = $(window).width();
1892 $.fn.qtip.cache.screen.height = $(window).height();
1893 };
1894
1895 for(i = 0; i < $.fn.qtip.interfaces.length; i++)
1896 {
1897 // Access current elements API
1898 var api = $.fn.qtip.interfaces[i];
1899
1900 // Update position if resize or scroll adjustments are enabled
1901 if(api.status.rendered === true
1902 && (api.options.position.type !== 'static'
1903 || api.options.position.adjust.scroll && event.type === 'scroll'
1904 || api.options.position.adjust.resize && event.type === 'resize'))
1905 {
1906 // Queue the animation so positions are updated correctly
1907 api.updatePosition(event, true);
1908 }
1909 };
1910 }
1911 , 100);
1912 })
1913
1914 // Hide unfocus toolipts on document mousedown
1915 $(document).bind('mousedown.qtip', function(event)
1916 {
1917 if($(event.target).parents('div.qtip').length === 0)
1918 {
1919 $('.qtip[unfocus]').each(function()
1920 {
1921 var api = $(this).qtip("api");
1922
1923 // Only hide if its visible and not the tooltips target
1924 if($(this).is(':visible') && !api.status.disabled
1925 && $(event.target).add(api.elements.target).length > 1)
1926 api.hide(event);
1927 })
1928 };
1929 })
1930 });
1931
1932 // Define qTip API interfaces array
1933 $.fn.qtip.interfaces = []
1934
1935 // Define log and constant place holders
1936 $.fn.qtip.log = { error: function(){ return this; } };
1937 $.fn.qtip.constants = {};
1938
1939 // Define configuration defaults
1940 $.fn.qtip.defaults = {
1941 // Content
1942 content: {
1943 prerender: false,
1944 text: false,
1945 url: false,
1946 data: null,
1947 title: {
1948 text: false,
1949 button: false
1950 }
1951 },
1952 // Position
1953 position: {
1954 target: false,
1955 corner: {
1956 target: 'bottomRight',
1957 tooltip: 'topLeft'
1958 },
1959 adjust: {
1960 x: 0, y: 0,
1961 mouse: true,
1962 screen: false,
1963 scroll: true,
1964 resize: true
1965 },
1966 type: 'absolute',
1967 container: false
1968 },
1969 // Effects
1970 show: {
1971 when: {
1972 target: false,
1973 event: 'mouseover'
1974 },
1975 effect: {
1976 type: 'fade',
1977 length: 100
1978 },
1979 delay: 140,
1980 solo: false,
1981 ready: false
1982 },
1983 hide: {
1984 when: {
1985 target: false,
1986 event: 'mouseout'
1987 },
1988 effect: {
1989 type: 'fade',
1990 length: 100
1991 },
1992 delay: 0,
1993 fixed: false
1994 },
1995 // Callbacks
1996 api: {
1997 beforeRender: function(){},
1998 onRender: function(){},
1999 beforePositionUpdate: function(){},
2000 onPositionUpdate: function(){},
2001 beforeShow: function(){},
2002 onShow: function(){},
2003 beforeHide: function(){},
2004 onHide: function(){},
2005 beforeContentUpdate: function(){},
2006 onContentUpdate: function(){},
2007 beforeContentLoad: function(){},
2008 onContentLoad: function(){},
2009 beforeTitleUpdate: function(){},
2010 onTitleUpdate: function(){},
2011 beforeDestroy: function(){},
2012 onDestroy: function(){},
2013 beforeFocus: function(){},
2014 onFocus: function(){}
2015 }
2016 };
2017
2018 $.fn.qtip.styles = {
2019 defaults: {
2020 background: 'white',
2021 color: '#111',
2022 overflow: 'hidden',
2023 textAlign: 'left',
2024 width: {
2025 min: 0,
2026 max: 250
2027 },
2028 padding: '5px 9px',
2029 border: {
2030 width: 1,
2031 radius: 0,
2032 color: '#d3d3d3'
2033 },
2034 tip: {
2035 corner: false,
2036 color: false,
2037 size: { width: 13, height: 13 },
2038 opacity: 1
2039 },
2040 title: {
2041 background: '#e1e1e1',
2042 fontWeight: 'bold',
2043 padding: '7px 12px'
2044 },
2045 button: {
2046 cursor: 'pointer'
2047 },
2048 classes: {
2049 target: '',
2050 tip: 'qtip-tip',
2051 title: 'qtip-title',
2052 button: 'qtip-button',
2053 content: 'qtip-content',
2054 active: 'qtip-active'
2055 }
2056 },
2057 cream: {
2058 border: {
2059 width: 3,
2060 radius: 0,
2061 color: '#F9E98E'
2062 },
2063 title: {
2064 background: '#F0DE7D',
2065 color: '#A27D35'
2066 },
2067 background: '#FBF7AA',
2068 color: '#A27D35',
2069
2070 classes: { tooltip: 'qtip-cream' }
2071 },
2072 light: {
2073 border: {
2074 width: 3,
2075 radius: 0,
2076 color: '#E2E2E2'
2077 },
2078 title: {
2079 background: '#f1f1f1',
2080 color: '#454545'
2081 },
2082 background: 'white',
2083 color: '#454545',
2084
2085 classes: { tooltip: 'qtip-light' }
2086 },
2087 dark: {
2088 border: {
2089 width: 3,
2090 radius: 0,
2091 color: '#303030'
2092 },
2093 title: {
2094 background: '#404040',
2095 color: '#f3f3f3'
2096 },
2097 background: '#505050',
2098 color: '#f3f3f3',
2099
2100 classes: { tooltip: 'qtip-dark' }
2101 },
2102 red: {
2103 border: {
2104 width: 3,
2105 radius: 0,
2106 color: '#CE6F6F'
2107 },
2108 title: {
2109 background: '#f28279',
2110 color: '#9C2F2F'
2111 },
2112 background: '#F79992',
2113 color: '#9C2F2F',
2114
2115 classes: { tooltip: 'qtip-red' }
2116 },
2117 green: {
2118 border: {
2119 width: 3,
2120 radius: 0,
2121 color: '#A9DB66'
2122 },
2123 title: {
2124 background: '#b9db8c',
2125 color: '#58792E'
2126 },
2127 background: '#CDE6AC',
2128 color: '#58792E',
2129
2130 classes: { tooltip: 'qtip-green' }
2131 },
2132 blue: {
2133 border: {
2134 width: 3,
2135 radius: 0,
2136 color: '#ADD9ED'
2137 },
2138 title: {
2139 background: '#D0E9F5',
2140 color: '#5E99BD'
2141 },
2142 background: '#E5F6FE',
2143 color: '#4D9FBF',
2144
2145 classes: { tooltip: 'qtip-blue' }
2146 }
2147 };
2148 })(jQuery);
...\ No newline at end of file ...\ No newline at end of file