jquery-qtip-wrapper-rails 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0d8b1af1c9db9dd156f3cbf8d93914eb9b11e247
4
- data.tar.gz: ef58bbd6c75fb54a5ee328e2a9cfa43d58a7be0e
3
+ metadata.gz: 9b0167914bfdd04fafb0f7ebf8c036c1831bfba3
4
+ data.tar.gz: 9a6bdd6357cfb2a703a210397b57b8777956c37f
5
5
  SHA512:
6
- metadata.gz: a81cbb1213db25bab4fb7e49e8bd2651160a9a3e867a6df22842f216a434d4b5eda4c68d86ce17d4fb981e4a9a33e32b9f311618a733db70e0d1c375d27edc2f
7
- data.tar.gz: 54fcd991857c9ff9e48409220ac804ade9738ec4640ff772cb2d7227518fb1296c68c8c5567e2ccbb25c078e5271f30b00f780d7dac402188ddb8f8cafc55715
6
+ metadata.gz: 662b79a891e02514a14a66ea201c837a9d3282f36b2429d8f4cdca2fc9f627c88af6a84a33aa3d47de45eda6361051af34be60f9d3250d65312a980b659732c7
7
+ data.tar.gz: b13cc4dfd50ac8f655685dd8159ac35ae34df5089362160c583dcfb074d02846a4d80a92c7f073aa6e381ffa0a283d641cb8501b1f5a7768d68e8995a168661d
@@ -1,12 +1,12 @@
1
- require "jquery/qtip/wrapper/rails/version"
2
-
3
- module Jquery
4
- module Qtip
5
- module Wrapper
6
- module Rails
7
- class Engine < ::Rails::Engine
8
- end
9
- end
10
- end
11
- end
12
- end
1
+ require "jquery/qtip/wrapper/rails/version"
2
+
3
+ module Jquery
4
+ module Qtip
5
+ module Wrapper
6
+ module Rails
7
+ class Engine < ::Rails::Engine
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,9 +1,9 @@
1
- module Jquery
2
- module Qtip
3
- module Wrapper
4
- module Rails
5
- VERSION = "1.0.1"
6
- end
7
- end
8
- end
9
- end
1
+ module Jquery
2
+ module Qtip
3
+ module Wrapper
4
+ module Rails
5
+ VERSION = "1.0.2"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,2155 +1,2155 @@
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 new content and reappend the button if enabled
876
- if(self.elements.button) self.elements.button = self.elements.button.clone(true);
877
- self.elements.title.html(content)
878
- if(self.elements.button) self.elements.title.prepend(self.elements.button);
879
-
880
- // Call API method and log event
881
- self.onTitleUpdate.call(self);
882
- return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_TITLE_UPDATED, 'updateTitle');
883
- },
884
-
885
- focus: function(event)
886
- {
887
- var curIndex, newIndex, elemIndex, returned;
888
-
889
- // Make sure tooltip is rendered and if not, return
890
- if(!self.status.rendered)
891
- return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'focus');
892
-
893
- else if(self.options.position.type == 'static')
894
- return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.CANNOT_FOCUS_STATIC, 'focus');
895
-
896
- // Set z-index variables
897
- curIndex = parseInt( self.elements.tooltip.css('z-index') );
898
- newIndex = 6000 + $('div.qtip[qtip]').length - 1;
899
-
900
- // Only update the z-index if it has changed and tooltip is not already focused
901
- if(!self.status.focused && curIndex !== newIndex)
902
- {
903
- // Call API method and if return value is false, halt
904
- returned = self.beforeFocus.call(self, event);
905
- if(returned === false) return self;
906
-
907
- // Loop through all other tooltips
908
- $('div.qtip[qtip]').not(self.elements.tooltip).each(function()
909
- {
910
- if($(this).qtip('api').status.rendered === true)
911
- {
912
- elemIndex = parseInt($(this).css('z-index'));
913
-
914
- // Reduce all other tooltip z-index by 1
915
- if(typeof elemIndex == 'number' && elemIndex > -1)
916
- $(this).css({ zIndex: parseInt( $(this).css('z-index') ) - 1 });
917
-
918
- // Set focused status to false
919
- $(this).qtip('api').status.focused = false;
920
- }
921
- })
922
-
923
- // Set the new z-index and set focus status to true
924
- self.elements.tooltip.css({ zIndex: newIndex });
925
- self.status.focused = true;
926
-
927
- // Call API method and log event
928
- self.onFocus.call(self, event);
929
- $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_FOCUSED, 'focus');
930
- };
931
-
932
- return self;
933
- },
934
-
935
- disable: function(state)
936
- {
937
- // Make sure tooltip is rendered and if not, return
938
- if(!self.status.rendered)
939
- return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'disable');
940
-
941
- if(state)
942
- {
943
- // Tooltip is not already disabled, proceed
944
- if(!self.status.disabled)
945
- {
946
- // Set the disabled flag and log event
947
- self.status.disabled = true;
948
- $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_DISABLED, 'disable');
949
- }
950
-
951
- // Tooltip is already disabled, inform user via log
952
- else $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.TOOLTIP_ALREADY_DISABLED, 'disable');
953
- }
954
- else
955
- {
956
- // Tooltip is not already enabled, proceed
957
- if(self.status.disabled)
958
- {
959
- // Reassign events, set disable status and log
960
- self.status.disabled = false;
961
- $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_ENABLED, 'disable');
962
- }
963
-
964
- // Tooltip is already enabled, inform the user via log
965
- else $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.TOOLTIP_ALREADY_ENABLED, 'disable');
966
- };
967
-
968
- return self;
969
- },
970
-
971
- destroy: function()
972
- {
973
- var i, returned, interfaces;
974
-
975
- // Call API method and if return value is false, halt
976
- returned = self.beforeDestroy.call(self);
977
- if(returned === false) return self;
978
-
979
- // Check if tooltip is rendered
980
- if(self.status.rendered)
981
- {
982
- // Remove event handlers and remove element
983
- self.options.show.when.target.unbind('mousemove.qtip', self.updatePosition);
984
- self.options.show.when.target.unbind('mouseout.qtip', self.hide);
985
- self.options.show.when.target.unbind(self.options.show.when.event + '.qtip');
986
- self.options.hide.when.target.unbind(self.options.hide.when.event + '.qtip');
987
- self.elements.tooltip.unbind(self.options.hide.when.event + '.qtip');
988
- self.elements.tooltip.unbind('mouseover.qtip', self.focus);
989
- self.elements.tooltip.remove();
990
- }
991
-
992
- // Tooltip isn't yet rendered, remove render event
993
- else self.options.show.when.target.unbind(self.options.show.when.event+'.qtip-create');
994
-
995
- // Check to make sure qTip data is present on target element
996
- if(typeof self.elements.target.data('qtip') == 'object')
997
- {
998
- // Remove API references from interfaces object
999
- interfaces = self.elements.target.data('qtip').interfaces;
1000
- if(typeof interfaces == 'object' && interfaces.length > 0)
1001
- {
1002
- // Remove API from interfaces array
1003
- for(i = 0; i < interfaces.length - 1; i++)
1004
- if(interfaces[i].id == self.id) interfaces.splice(i, 1)
1005
- }
1006
- }
1007
- delete $.fn.qtip.interfaces[self.id];
1008
-
1009
- // Set qTip current id to previous tooltips API if available
1010
- if(typeof interfaces == 'object' && interfaces.length > 0)
1011
- self.elements.target.data('qtip').current = interfaces.length -1;
1012
- else
1013
- self.elements.target.removeData('qtip');
1014
-
1015
- // Call API method and log destroy
1016
- self.onDestroy.call(self);
1017
- $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_DESTROYED, 'destroy');
1018
-
1019
- return self.elements.target
1020
- },
1021
-
1022
- getPosition: function()
1023
- {
1024
- var show, offset;
1025
-
1026
- // Make sure tooltip is rendered and if not, return
1027
- if(!self.status.rendered)
1028
- return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'getPosition');
1029
-
1030
- show = (self.elements.tooltip.css('display') !== 'none') ? false : true;
1031
-
1032
- // Show and hide tooltip to make sure coordinates are returned
1033
- if(show) self.elements.tooltip.css({ visiblity: 'hidden' }).show();
1034
- offset = self.elements.tooltip.offset();
1035
- if(show) self.elements.tooltip.css({ visiblity: 'visible' }).hide();
1036
-
1037
- return offset;
1038
- },
1039
-
1040
- getDimensions: function()
1041
- {
1042
- var show, dimensions;
1043
-
1044
- // Make sure tooltip is rendered and if not, return
1045
- if(!self.status.rendered)
1046
- return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'getDimensions');
1047
-
1048
- show = (!self.elements.tooltip.is(':visible')) ? true : false;
1049
-
1050
- // Show and hide tooltip to make sure dimensions are returned
1051
- if(show) self.elements.tooltip.css({ visiblity: 'hidden' }).show();
1052
- dimensions = {
1053
- height: self.elements.tooltip.outerHeight(),
1054
- width: self.elements.tooltip.outerWidth()
1055
- };
1056
- if(show) self.elements.tooltip.css({ visiblity: 'visible' }).hide();
1057
-
1058
- return dimensions;
1059
- }
1060
- });
1061
- };
1062
-
1063
- // Define priamry construct function
1064
- function construct()
1065
- {
1066
- var self, adjust, content, url, data, method, tempLength;
1067
- self = this;
1068
-
1069
- // Call API method
1070
- self.beforeRender.call(self);
1071
-
1072
- // Set rendered status to true
1073
- self.status.rendered = true;
1074
-
1075
- // Create initial tooltip elements
1076
- self.elements.tooltip = '<div qtip="'+self.id+'" ' +
1077
- 'class="qtip '+(self.options.style.classes.tooltip || self.options.style)+'"' +
1078
- 'style="display:none; -moz-border-radius:0; -webkit-border-radius:0; border-radius:0;' +
1079
- 'position:'+self.options.position.type+';">' +
1080
- ' <div class="qtip-wrapper" style="position:relative; overflow:hidden; text-align:left;">' +
1081
- ' <div class="qtip-contentWrapper" style="overflow:hidden;">' +
1082
- ' <div class="qtip-content '+self.options.style.classes.content+'"></div>' +
1083
- '</div></div></div>';
1084
-
1085
- // Append to container element
1086
- self.elements.tooltip = $(self.elements.tooltip);
1087
- self.elements.tooltip.appendTo(self.options.position.container)
1088
-
1089
- // Setup tooltip qTip data
1090
- self.elements.tooltip.data('qtip', { current: 0, interfaces: [self] });
1091
-
1092
- // Setup element references
1093
- self.elements.wrapper = self.elements.tooltip.children('div:first');
1094
- self.elements.contentWrapper = self.elements.wrapper.children('div:first').css({ background: self.options.style.background });
1095
- self.elements.content = self.elements.contentWrapper.children('div:first').css( jQueryStyle(self.options.style) );
1096
-
1097
- // Apply IE hasLayout fix to wrapper and content elements
1098
- if($.browser.msie) self.elements.wrapper.add(self.elements.content).css({ zoom: 1 });
1099
-
1100
- // Setup tooltip attributes
1101
- if(self.options.hide.when.event == 'unfocus') self.elements.tooltip.attr('unfocus', true);
1102
-
1103
- // If an explicit width is set, updateWidth prior to setting content to prevent dirty rendering
1104
- if(typeof self.options.style.width.value == 'number') self.updateWidth();
1105
-
1106
- // Create borders and tips if supported by the browser
1107
- if($('<canvas>').get(0).getContext || $.browser.msie)
1108
- {
1109
- // Create border
1110
- if(self.options.style.border.radius > 0)
1111
- createBorder.call(self);
1112
- else
1113
- self.elements.contentWrapper.css({ border: self.options.style.border.width+'px solid '+self.options.style.border.color });
1114
-
1115
- // Create tip if enabled
1116
- if(self.options.style.tip.corner !== false)
1117
- createTip.call(self);
1118
- }
1119
-
1120
- // Neither canvas or VML is supported, tips and borders cannot be drawn!
1121
- else
1122
- {
1123
- // Set defined border width
1124
- self.elements.contentWrapper.css({ border: self.options.style.border.width+'px solid '+self.options.style.border.color });
1125
-
1126
- // Reset border radius and tip
1127
- self.options.style.border.radius = 0;
1128
- self.options.style.tip.corner = false;
1129
-
1130
- // Inform via log
1131
- $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.CANVAS_VML_NOT_SUPPORTED, 'render');
1132
- };
1133
-
1134
- // Use the provided content string or DOM array
1135
- if((typeof self.options.content.text == 'string' && self.options.content.text.length > 0)
1136
- || (self.options.content.text.jquery && self.options.content.text.length > 0))
1137
- content = self.options.content.text;
1138
-
1139
- // Use title string for content if present
1140
- else if(typeof self.elements.target.attr('title') == 'string' && self.elements.target.attr('title').length > 0)
1141
- {
1142
- content = self.elements.target.attr('title').replace("\\n", '<br />');
1143
- self.elements.target.attr('title', ''); // Remove title attribute to prevent default tooltip showing
1144
- }
1145
-
1146
- // No title is present, use alt attribute instead
1147
- else if(typeof self.elements.target.attr('alt') == 'string' && self.elements.target.attr('alt').length > 0)
1148
- {
1149
- content = self.elements.target.attr('alt').replace("\\n", '<br />');
1150
- self.elements.target.attr('alt', ''); // Remove alt attribute to prevent default tooltip showing
1151
- }
1152
-
1153
- // No valid content was provided, inform via log
1154
- else
1155
- {
1156
- content = ' ';
1157
- $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.NO_VALID_CONTENT, 'render');
1158
- };
1159
-
1160
- // Set the tooltips content and create title if enabled
1161
- if(self.options.content.title.text !== false) createTitle.call(self);
1162
- self.updateContent(content);
1163
-
1164
- // Assign events and toggle tooltip with focus
1165
- assignEvents.call(self);
1166
- if(self.options.show.ready === true) self.show();
1167
-
1168
- // Retrieve ajax content if provided
1169
- if(self.options.content.url !== false)
1170
- {
1171
- url = self.options.content.url;
1172
- data = self.options.content.data;
1173
- method = self.options.content.method || 'get';
1174
- self.loadContent(url, data, method);
1175
- };
1176
-
1177
- // Call API method and log event
1178
- self.onRender.call(self);
1179
- $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_RENDERED, 'render');
1180
- };
1181
-
1182
- // Create borders using canvas and VML
1183
- function createBorder()
1184
- {
1185
- var self, i, width, radius, color, coordinates, containers, size, betweenWidth, betweenCorners, borderTop, borderBottom, borderCoord, sideWidth, vertWidth;
1186
- self = this;
1187
-
1188
- // Destroy previous border elements, if present
1189
- self.elements.wrapper.find('.qtip-borderBottom, .qtip-borderTop').remove();
1190
-
1191
- // Setup local variables
1192
- width = self.options.style.border.width;
1193
- radius = self.options.style.border.radius;
1194
- color = self.options.style.border.color || self.options.style.tip.color;
1195
-
1196
- // Calculate border coordinates
1197
- coordinates = calculateBorders(radius);
1198
-
1199
- // Create containers for the border shapes
1200
- containers = {};
1201
- for(i in coordinates)
1202
- {
1203
- // Create shape container
1204
- containers[i] = '<div rel="'+i+'" style="'+((i.search(/Left/) !== -1) ? 'left' : 'right') + ':0; ' +
1205
- 'position:absolute; height:'+radius+'px; width:'+radius+'px; overflow:hidden; line-height:0.1px; font-size:1px">';
1206
-
1207
- // Canvas is supported
1208
- if($('<canvas>').get(0).getContext)
1209
- containers[i] += '<canvas height="'+radius+'" width="'+radius+'" style="vertical-align: top"></canvas>';
1210
-
1211
- // No canvas, but if it's IE use VML
1212
- else if($.browser.msie)
1213
- {
1214
- size = radius * 2 + 3;
1215
- containers[i] += '<v:arc stroked="false" fillcolor="'+color+'" startangle="'+coordinates[i][0]+'" endangle="'+coordinates[i][1]+'" ' +
1216
- 'style="width:'+size+'px; height:'+size+'px; margin-top:'+((i.search(/bottom/) !== -1) ? -2 : -1)+'px; ' +
1217
- 'margin-left:'+((i.search(/Right/) !== -1) ? coordinates[i][2] - 3.5 : -1)+'px; ' +
1218
- 'vertical-align:top; display:inline-block; behavior:url(#default#VML)"></v:arc>';
1219
-
1220
- };
1221
-
1222
- containers[i] += '</div>';
1223
- };
1224
-
1225
- // Create between corners elements
1226
- betweenWidth = self.getDimensions().width - (Math.max(width, radius) * 2);
1227
- betweenCorners = '<div class="qtip-betweenCorners" style="height:'+radius+'px; width:'+betweenWidth+'px; ' +
1228
- 'overflow:hidden; background-color:'+color+'; line-height:0.1px; font-size:1px;">';
1229
-
1230
- // Create top border container
1231
- borderTop = '<div class="qtip-borderTop" dir="ltr" style="height:'+radius+'px; ' +
1232
- 'margin-left:'+radius+'px; line-height:0.1px; font-size:1px; padding:0;">' +
1233
- containers['topLeft'] + containers['topRight'] + betweenCorners;
1234
- self.elements.wrapper.prepend(borderTop);
1235
-
1236
- // Create bottom border container
1237
- borderBottom = '<div class="qtip-borderBottom" dir="ltr" style="height:'+radius+'px; ' +
1238
- 'margin-left:'+radius+'px; line-height:0.1px; font-size:1px; padding:0;">' +
1239
- containers['bottomLeft'] + containers['bottomRight'] + betweenCorners;
1240
- self.elements.wrapper.append(borderBottom);
1241
-
1242
- // Draw the borders if canvas were used (Delayed til after DOM creation)
1243
- if($('<canvas>').get(0).getContext)
1244
- {
1245
- self.elements.wrapper.find('canvas').each(function()
1246
- {
1247
- borderCoord = coordinates[ $(this).parent('[rel]:first').attr('rel') ];
1248
- drawBorder.call(self, $(this), borderCoord, radius, color);
1249
- })
1250
- }
1251
-
1252
- // Create a phantom VML element (IE won't show the last created VML element otherwise)
1253
- else if($.browser.msie) self.elements.tooltip.append('<v:image style="behavior:url(#default#VML);"></v:image>');
1254
-
1255
- // Setup contentWrapper border
1256
- sideWidth = Math.max(radius, (radius + (width - radius)) )
1257
- vertWidth = Math.max(width - radius, 0);
1258
- self.elements.contentWrapper.css({
1259
- border: '0px solid ' + color,
1260
- borderWidth: vertWidth + 'px ' + sideWidth + 'px'
1261
- })
1262
- };
1263
-
1264
- // Border canvas draw method
1265
- function drawBorder(canvas, coordinates, radius, color)
1266
- {
1267
- // Create corner
1268
- var context = canvas.get(0).getContext('2d');
1269
- context.fillStyle = color;
1270
- context.beginPath();
1271
- context.arc(coordinates[0], coordinates[1], radius, 0, Math.PI * 2, false);
1272
- context.fill();
1273
- };
1274
-
1275
- // Create tip using canvas and VML
1276
- function createTip(corner)
1277
- {
1278
- var self, color, coordinates, coordsize, path;
1279
- self = this;
1280
-
1281
- // Destroy previous tip, if there is one
1282
- if(self.elements.tip !== null) self.elements.tip.remove();
1283
-
1284
- // Setup color and corner values
1285
- color = self.options.style.tip.color || self.options.style.border.color;
1286
- if(self.options.style.tip.corner === false) return;
1287
- else if(!corner) corner = self.options.style.tip.corner;
1288
-
1289
- // Calculate tip coordinates
1290
- coordinates = calculateTip(corner, self.options.style.tip.size.width, self.options.style.tip.size.height);
1291
-
1292
- // Create tip element
1293
- self.elements.tip = '<div class="'+self.options.style.classes.tip+'" dir="ltr" rel="'+corner+'" style="position:absolute; ' +
1294
- 'height:'+self.options.style.tip.size.height+'px; width:'+self.options.style.tip.size.width+'px; ' +
1295
- 'margin:0 auto; line-height:0.1px; font-size:1px;">';
1296
-
1297
- // Use canvas element if supported
1298
- if($('<canvas>').get(0).getContext)
1299
- self.elements.tip += '<canvas height="'+self.options.style.tip.size.height+'" width="'+self.options.style.tip.size.width+'"></canvas>';
1300
-
1301
- // Canvas not supported - Use VML (IE)
1302
- else if($.browser.msie)
1303
- {
1304
- // Create coordize and tip path using tip coordinates
1305
- coordsize = self.options.style.tip.size.width + ',' + self.options.style.tip.size.height;
1306
- path = 'm' + coordinates[0][0] + ',' + coordinates[0][1];
1307
- path += ' l' + coordinates[1][0] + ',' + coordinates[1][1];
1308
- path += ' ' + coordinates[2][0] + ',' + coordinates[2][1];
1309
- path += ' xe';
1310
-
1311
- // Create VML element
1312
- self.elements.tip += '<v:shape fillcolor="'+color+'" stroked="false" filled="true" path="'+path+'" coordsize="'+coordsize+'" ' +
1313
- 'style="width:'+self.options.style.tip.size.width+'px; height:'+self.options.style.tip.size.height+'px; ' +
1314
- 'line-height:0.1px; display:inline-block; behavior:url(#default#VML); ' +
1315
- 'vertical-align:'+((corner.search(/top/) !== -1) ? 'bottom' : 'top')+'"></v:shape>';
1316
-
1317
- // Create a phantom VML element (IE won't show the last created VML element otherwise)
1318
- self.elements.tip += '<v:image style="behavior:url(#default#VML);"></v:image>';
1319
-
1320
- // Prevent tooltip appearing above the content (IE z-index bug)
1321
- self.elements.contentWrapper.css('position', 'relative');
1322
- };
1323
-
1324
- // Attach new tip to tooltip element
1325
- self.elements.tooltip.prepend(self.elements.tip + '</div>');
1326
-
1327
- // Create element reference and draw the canvas tip (Delayed til after DOM creation)
1328
- self.elements.tip = self.elements.tooltip.find('.'+self.options.style.classes.tip).eq(0);
1329
- if($('<canvas>').get(0).getContext)
1330
- drawTip.call(self, self.elements.tip.find('canvas:first'), coordinates, color);
1331
-
1332
- // Fix IE small tip bug
1333
- if(corner.search(/top/) !== -1 && $.browser.msie && parseInt($.browser.version.charAt(0)) === 6)
1334
- self.elements.tip.css({ marginTop: -4 });
1335
-
1336
- // Set the tip position
1337
- positionTip.call(self, corner);
1338
- };
1339
-
1340
- // Canvas tip drawing method
1341
- function drawTip(canvas, coordinates, color)
1342
- {
1343
- // Setup properties
1344
- var context = canvas.get(0).getContext('2d');
1345
- context.fillStyle = color;
1346
-
1347
- // Create tip
1348
- context.beginPath();
1349
- context.moveTo(coordinates[0][0], coordinates[0][1]);
1350
- context.lineTo(coordinates[1][0], coordinates[1][1]);
1351
- context.lineTo(coordinates[2][0], coordinates[2][1]);
1352
- context.fill();
1353
- };
1354
-
1355
- function positionTip(corner)
1356
- {
1357
- var self, ieAdjust, paddingCorner, paddingSize, newMargin;
1358
- self = this;
1359
-
1360
- // Return if tips are disabled or tip is not yet rendered
1361
- if(self.options.style.tip.corner === false || !self.elements.tip) return;
1362
- if(!corner) corner = self.elements.tip.attr('rel');
1363
-
1364
- // Setup adjustment variables
1365
- ieAdjust = positionAdjust = ($.browser.msie) ? 1 : 0;
1366
-
1367
- // Set initial position
1368
- self.elements.tip.css(corner.match(/left|right|top|bottom/)[0], 0);
1369
-
1370
- // Set position of tip to correct side
1371
- if(corner.search(/top|bottom/) !== -1)
1372
- {
1373
- // Adjustments for IE6 - 0.5px border gap bug
1374
- if($.browser.msie)
1375
- {
1376
- if(parseInt($.browser.version.charAt(0)) === 6)
1377
- positionAdjust = (corner.search(/top/) !== -1) ? -3 : 1;
1378
- else
1379
- positionAdjust = (corner.search(/top/) !== -1) ? 1 : 2;
1380
- };
1381
-
1382
- if(corner.search(/Middle/) !== -1)
1383
- self.elements.tip.css({ left: '50%', marginLeft: -(self.options.style.tip.size.width / 2) });
1384
-
1385
- else if(corner.search(/Left/) !== -1)
1386
- self.elements.tip.css({ left: self.options.style.border.radius - ieAdjust });
1387
-
1388
- else if(corner.search(/Right/) !== -1)
1389
- self.elements.tip.css({ right: self.options.style.border.radius + ieAdjust });
1390
-
1391
- if(corner.search(/top/) !== -1)
1392
- self.elements.tip.css({ top: -positionAdjust });
1393
- else
1394
- self.elements.tip.css({ bottom: positionAdjust });
1395
-
1396
- }
1397
- else if(corner.search(/left|right/) !== -1)
1398
- {
1399
- // Adjustments for IE6 - 0.5px border gap bug
1400
- if($.browser.msie)
1401
- positionAdjust = (parseInt($.browser.version.charAt(0)) === 6) ? 1 : ((corner.search(/left/) !== -1) ? 1 : 2);
1402
-
1403
- if(corner.search(/Middle/) !== -1)
1404
- self.elements.tip.css({ top: '50%', marginTop: -(self.options.style.tip.size.height / 2) });
1405
-
1406
- else if(corner.search(/Top/) !== -1)
1407
- self.elements.tip.css({ top: self.options.style.border.radius - ieAdjust });
1408
-
1409
- else if(corner.search(/Bottom/) !== -1)
1410
- self.elements.tip.css({ bottom: self.options.style.border.radius + ieAdjust });
1411
-
1412
- if(corner.search(/left/) !== -1)
1413
- self.elements.tip.css({ left: -positionAdjust });
1414
- else
1415
- self.elements.tip.css({ right: positionAdjust });
1416
- };
1417
-
1418
- // Adjust tooltip padding to compensate for tip
1419
- paddingCorner = 'padding-' + corner.match(/left|right|top|bottom/)[0];
1420
- paddingSize = self.options.style.tip.size[ (paddingCorner.search(/left|right/) !== -1) ? 'width' : 'height' ];
1421
- self.elements.tooltip.css('padding', 0);
1422
- self.elements.tooltip.css(paddingCorner, paddingSize);
1423
-
1424
- // Match content margin to prevent gap bug in IE6 ONLY
1425
- if($.browser.msie && parseInt($.browser.version.charAt(0)) == 6)
1426
- {
1427
- newMargin = parseInt(self.elements.tip.css('margin-top')) || 0;
1428
- newMargin += parseInt(self.elements.content.css('margin-top')) || 0;
1429
-
1430
- self.elements.tip.css({ marginTop: newMargin });
1431
- };
1432
- };
1433
-
1434
- // Create title bar for content
1435
- function createTitle()
1436
- {
1437
- var self = this;
1438
-
1439
- // Destroy previous title element, if present
1440
- if(self.elements.title !== null) self.elements.title.remove();
1441
-
1442
- // Create title element
1443
- self.elements.title = $('<div class="'+self.options.style.classes.title+'">')
1444
- .css( jQueryStyle(self.options.style.title, true) )
1445
- .css({ zoom: ($.browser.msie) ? 1 : 0 })
1446
- .prependTo(self.elements.contentWrapper);
1447
-
1448
- // Update title with contents if enabled
1449
- if(self.options.content.title.text) self.updateTitle.call(self, self.options.content.title.text);
1450
-
1451
- // Create title close buttons if enabled
1452
- if(self.options.content.title.button !== false
1453
- && typeof self.options.content.title.button == 'string')
1454
- {
1455
- self.elements.button = $('<a class="'+self.options.style.classes.button+'" style="float:right; position: relative"></a>')
1456
- .css( jQueryStyle(self.options.style.button, true) )
1457
- .html(self.options.content.title.button)
1458
- .prependTo(self.elements.title)
1459
- .click(function(event){ if(!self.status.disabled) self.hide(event) });
1460
- };
1461
- };
1462
-
1463
- // Assign hide and show events
1464
- function assignEvents()
1465
- {
1466
- var self, showTarget, hideTarget, inactiveEvents;
1467
- self = this;
1468
-
1469
- // Setup event target variables
1470
- showTarget = self.options.show.when.target;
1471
- hideTarget = self.options.hide.when.target;
1472
-
1473
- // Add tooltip as a hideTarget is its fixed
1474
- if(self.options.hide.fixed) hideTarget = hideTarget.add(self.elements.tooltip);
1475
-
1476
- // Check if the hide event is special 'inactive' type
1477
- if(self.options.hide.when.event == 'inactive')
1478
- {
1479
- // Define events which reset the 'inactive' event handler
1480
- inactiveEvents = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove',
1481
- 'mouseout', 'mouseenter', 'mouseleave', 'mouseover' ];
1482
-
1483
- // Define 'inactive' event timer method
1484
- function inactiveMethod(event)
1485
- {
1486
- if(self.status.disabled === true) return;
1487
-
1488
- //Clear and reset the timer
1489
- clearTimeout(self.timers.inactive);
1490
- self.timers.inactive = setTimeout(function()
1491
- {
1492
- // Unassign 'inactive' events
1493
- $(inactiveEvents).each(function()
1494
- {
1495
- hideTarget.unbind(this+'.qtip-inactive');
1496
- self.elements.content.unbind(this+'.qtip-inactive');
1497
- });
1498
-
1499
- // Hide the tooltip
1500
- self.hide(event);
1501
- }
1502
- , self.options.hide.delay);
1503
- };
1504
- }
1505
-
1506
- // Check if the tooltip is 'fixed'
1507
- else if(self.options.hide.fixed === true)
1508
- {
1509
- self.elements.tooltip.bind('mouseover.qtip', function()
1510
- {
1511
- if(self.status.disabled === true) return;
1512
-
1513
- // Reset the hide timer
1514
- clearTimeout(self.timers.hide);
1515
- });
1516
- };
1517
-
1518
- // Define show event method
1519
- function showMethod(event)
1520
- {
1521
- if(self.status.disabled === true) return;
1522
-
1523
- // If set, hide tooltip when inactive for delay period
1524
- if(self.options.hide.when.event == 'inactive')
1525
- {
1526
- // Assign each reset event
1527
- $(inactiveEvents).each(function()
1528
- {
1529
- hideTarget.bind(this+'.qtip-inactive', inactiveMethod);
1530
- self.elements.content.bind(this+'.qtip-inactive', inactiveMethod);
1531
- });
1532
-
1533
- // Start the inactive timer
1534
- inactiveMethod();
1535
- };
1536
-
1537
- // Clear hide timers
1538
- clearTimeout(self.timers.show);
1539
- clearTimeout(self.timers.hide);
1540
-
1541
- // Start show timer
1542
- self.timers.show = setTimeout(function(){ self.show(event); }, self.options.show.delay);
1543
- };
1544
-
1545
- // Define hide event method
1546
- function hideMethod(event)
1547
- {
1548
- if(self.status.disabled === true) return;
1549
-
1550
- // Prevent hiding if tooltip is fixed and event target is the tooltip
1551
- if(self.options.hide.fixed === true
1552
- && self.options.hide.when.event.search(/mouse(out|leave)/i) !== -1
1553
- && $(event.relatedTarget).parents('div.qtip[qtip]').length > 0)
1554
- {
1555
- // Prevent default and popagation
1556
- event.stopPropagation();
1557
- event.preventDefault();
1558
-
1559
- // Reset the hide timer
1560
- clearTimeout(self.timers.hide);
1561
- return false;
1562
- };
1563
-
1564
- // Clear timers and stop animation queue
1565
- clearTimeout(self.timers.show);
1566
- clearTimeout(self.timers.hide);
1567
- self.elements.tooltip.stop(true, true);
1568
-
1569
- // If tooltip has displayed, start hide timer
1570
- self.timers.hide = setTimeout(function(){ self.hide(event); }, self.options.hide.delay);
1571
- };
1572
-
1573
- // Both events and targets are identical, apply events using a toggle
1574
- if((self.options.show.when.target.add(self.options.hide.when.target).length === 1
1575
- && self.options.show.when.event == self.options.hide.when.event
1576
- && self.options.hide.when.event !== 'inactive')
1577
- || self.options.hide.when.event == 'unfocus')
1578
- {
1579
- self.cache.toggle = 0;
1580
- // Use a toggle to prevent hide/show conflicts
1581
- showTarget.bind(self.options.show.when.event + '.qtip', function(event)
1582
- {
1583
- if(self.cache.toggle == 0) showMethod(event);
1584
- else hideMethod(event);
1585
- });
1586
- }
1587
-
1588
- // Events are not identical, bind normally
1589
- else
1590
- {
1591
- showTarget.bind(self.options.show.when.event + '.qtip', showMethod);
1592
-
1593
- // If the hide event is not 'inactive', bind the hide method
1594
- if(self.options.hide.when.event !== 'inactive')
1595
- hideTarget.bind(self.options.hide.when.event + '.qtip', hideMethod);
1596
- };
1597
-
1598
- // Focus the tooltip on mouseover
1599
- if(self.options.position.type.search(/(fixed|absolute)/) !== -1)
1600
- self.elements.tooltip.bind('mouseover.qtip', self.focus);
1601
-
1602
- // If mouse is the target, update tooltip position on mousemove
1603
- if(self.options.position.target === 'mouse' && self.options.position.type !== 'static')
1604
- {
1605
- showTarget.bind('mousemove.qtip', function(event)
1606
- {
1607
- // Set the new mouse positions if adjustment is enabled
1608
- self.cache.mouse = { x: event.pageX, y: event.pageY };
1609
-
1610
- // Update the tooltip position only if the tooltip is visible and adjustment is enabled
1611
- if(self.status.disabled === false
1612
- && self.options.position.adjust.mouse === true
1613
- && self.options.position.type !== 'static'
1614
- && self.elements.tooltip.css('display') !== 'none')
1615
- self.updatePosition(event);
1616
- });
1617
- };
1618
- };
1619
-
1620
- // Screen position adjustment
1621
- function screenAdjust(position, target, tooltip)
1622
- {
1623
- var self, adjustedPosition, adjust, newCorner, overflow, corner;
1624
- self = this;
1625
-
1626
- // Setup corner and adjustment variable
1627
- if(tooltip.corner == 'center') return target.position // TODO: 'center' corner adjustment
1628
- adjustedPosition = $.extend({}, position);
1629
- newCorner = { x: false, y: false };
1630
-
1631
- // Define overflow properties
1632
- overflow = {
1633
- left: (adjustedPosition.left < $.fn.qtip.cache.screen.scroll.left),
1634
- right: (adjustedPosition.left + tooltip.dimensions.width + 2 >= $.fn.qtip.cache.screen.width + $.fn.qtip.cache.screen.scroll.left),
1635
- top: (adjustedPosition.top < $.fn.qtip.cache.screen.scroll.top),
1636
- bottom: (adjustedPosition.top + tooltip.dimensions.height + 2 >= $.fn.qtip.cache.screen.height + $.fn.qtip.cache.screen.scroll.top)
1637
- };
1638
-
1639
- // Determine new positioning properties
1640
- adjust = {
1641
- left: (overflow.left && (tooltip.corner.search(/right/i) != -1 || (tooltip.corner.search(/right/i) == -1 && !overflow.right))),
1642
- right: (overflow.right && (tooltip.corner.search(/left/i) != -1 || (tooltip.corner.search(/left/i) == -1 && !overflow.left))),
1643
- top: (overflow.top && tooltip.corner.search(/top/i) == -1),
1644
- bottom: (overflow.bottom && tooltip.corner.search(/bottom/i) == -1)
1645
- };
1646
-
1647
- // Tooltip overflows off the left side of the screen
1648
- if(adjust.left)
1649
- {
1650
- if(self.options.position.target !== 'mouse')
1651
- adjustedPosition.left = target.position.left + target.dimensions.width;
1652
- else
1653
- adjustedPosition.left = self.cache.mouse.x
1654
-
1655
- newCorner.x = 'Left';
1656
- }
1657
-
1658
- // Tooltip overflows off the right side of the screen
1659
- else if(adjust.right)
1660
- {
1661
- if(self.options.position.target !== 'mouse')
1662
- adjustedPosition.left = target.position.left - tooltip.dimensions.width;
1663
- else
1664
- adjustedPosition.left = self.cache.mouse.x - tooltip.dimensions.width;
1665
-
1666
- newCorner.x = 'Right';
1667
- };
1668
-
1669
- // Tooltip overflows off the top of the screen
1670
- if(adjust.top)
1671
- {
1672
- if(self.options.position.target !== 'mouse')
1673
- adjustedPosition.top = target.position.top + target.dimensions.height;
1674
- else
1675
- adjustedPosition.top = self.cache.mouse.y
1676
-
1677
- newCorner.y = 'top';
1678
- }
1679
-
1680
- // Tooltip overflows off the bottom of the screen
1681
- else if(adjust.bottom)
1682
- {
1683
- if(self.options.position.target !== 'mouse')
1684
- adjustedPosition.top = target.position.top - tooltip.dimensions.height;
1685
- else
1686
- adjustedPosition.top = self.cache.mouse.y - tooltip.dimensions.height;
1687
-
1688
- newCorner.y = 'bottom';
1689
- };
1690
-
1691
- // Don't adjust if resulting position is negative
1692
- if(adjustedPosition.left < 0)
1693
- {
1694
- adjustedPosition.left = position.left;
1695
- newCorner.x = false;
1696
- };
1697
- if(adjustedPosition.top < 0)
1698
- {
1699
- adjustedPosition.top = position.top;
1700
- newCorner.y = false;
1701
- };
1702
-
1703
- // Change tip corner if positioning has changed and tips are enabled
1704
- if(self.options.style.tip.corner !== false)
1705
- {
1706
- // Determine new corner properties
1707
- adjustedPosition.corner = new String(tooltip.corner);
1708
- if(newCorner.x !== false) adjustedPosition.corner = adjustedPosition.corner.replace(/Left|Right|Middle/, newCorner.x);
1709
- if(newCorner.y !== false) adjustedPosition.corner = adjustedPosition.corner.replace(/top|bottom/, newCorner.y);
1710
-
1711
- // Adjust tip if position has changed and tips are enabled
1712
- if(adjustedPosition.corner !== self.elements.tip.attr('rel'))
1713
- createTip.call(self, adjustedPosition.corner);
1714
- };
1715
-
1716
- return adjustedPosition;
1717
- };
1718
-
1719
- // Build a jQuery style object from supplied style object
1720
- function jQueryStyle(style, sub)
1721
- {
1722
- var styleObj, i;
1723
-
1724
- styleObj = $.extend(true, {}, style);
1725
- for(i in styleObj)
1726
- {
1727
- if(sub === true && i.search(/(tip|classes)/i) !== -1)
1728
- delete styleObj[i];
1729
- else if(!sub && i.search(/(width|border|tip|title|classes|user)/i) !== -1)
1730
- delete styleObj[i];
1731
- };
1732
-
1733
- return styleObj;
1734
- };
1735
-
1736
- // Sanitize styles
1737
- function sanitizeStyle(style)
1738
- {
1739
- if(typeof style.tip !== 'object') style.tip = { corner: style.tip };
1740
- if(typeof style.tip.size !== 'object') style.tip.size = { width: style.tip.size, height: style.tip.size };
1741
- if(typeof style.border !== 'object') style.border = { width: style.border };
1742
- if(typeof style.width !== 'object') style.width = { value: style.width };
1743
- if(typeof style.width.max == 'string') style.width.max = parseInt(style.width.max.replace(/([0-9]+)/i, "$1"));
1744
- if(typeof style.width.min == 'string') style.width.min = parseInt(style.width.min.replace(/([0-9]+)/i, "$1"));
1745
-
1746
- // Convert deprecated x and y tip values to width/height
1747
- if(typeof style.tip.size.x == 'number')
1748
- {
1749
- style.tip.size.width = style.tip.size.x;
1750
- delete style.tip.size.x;
1751
- };
1752
- if(typeof style.tip.size.y == 'number')
1753
- {
1754
- style.tip.size.height = style.tip.size.y;
1755
- delete style.tip.size.y;
1756
- };
1757
-
1758
- return style;
1759
- };
1760
-
1761
- // Build styles recursively with inheritance
1762
- function buildStyle()
1763
- {
1764
- var self, i, styleArray, styleExtend, finalStyle, ieAdjust;
1765
- self = this;
1766
-
1767
- // Build style options from supplied arguments
1768
- styleArray = [true, {}];
1769
- for(i = 0; i < arguments.length; i++)
1770
- styleArray.push(arguments[i]);
1771
- styleExtend = [ $.extend.apply($, styleArray) ];
1772
-
1773
- // Loop through each named style inheritance
1774
- while(typeof styleExtend[0].name == 'string')
1775
- {
1776
- // Sanitize style data and append to extend array
1777
- styleExtend.unshift( sanitizeStyle($.fn.qtip.styles[ styleExtend[0].name ]) );
1778
- };
1779
-
1780
- // Make sure resulting tooltip className represents final style
1781
- styleExtend.unshift(true, {classes:{ tooltip: 'qtip-' + (arguments[0].name || 'defaults') }}, $.fn.qtip.styles.defaults);
1782
-
1783
- // Extend into a single style object
1784
- finalStyle = $.extend.apply($, styleExtend);
1785
-
1786
- // Adjust tip size if needed (IE 1px adjustment bug fix)
1787
- ieAdjust = ($.browser.msie) ? 1 : 0;
1788
- finalStyle.tip.size.width += ieAdjust;
1789
- finalStyle.tip.size.height += ieAdjust;
1790
-
1791
- // Force even numbers for pixel precision
1792
- if(finalStyle.tip.size.width % 2 > 0) finalStyle.tip.size.width += 1;
1793
- if(finalStyle.tip.size.height % 2 > 0) finalStyle.tip.size.height += 1;
1794
-
1795
- // Sanitize final styles tip corner value
1796
- if(finalStyle.tip.corner === true)
1797
- finalStyle.tip.corner = (self.options.position.corner.tooltip === 'center') ? false : self.options.position.corner.tooltip;
1798
-
1799
- return finalStyle;
1800
- };
1801
-
1802
- // Tip coordinates calculator
1803
- function calculateTip(corner, width, height)
1804
- {
1805
- // Define tip coordinates in terms of height and width values
1806
- var tips = {
1807
- bottomRight: [[0,0], [width,height], [width,0]],
1808
- bottomLeft: [[0,0], [width,0], [0,height]],
1809
- topRight: [[0,height], [width,0], [width,height]],
1810
- topLeft: [[0,0], [0,height], [width,height]],
1811
- topMiddle: [[0,height], [width / 2,0], [width,height]],
1812
- bottomMiddle: [[0,0], [width,0], [width / 2,height]],
1813
- rightMiddle: [[0,0], [width,height / 2], [0,height]],
1814
- leftMiddle: [[width,0], [width,height], [0,height / 2]]
1815
- };
1816
- tips.leftTop = tips.bottomRight;
1817
- tips.rightTop = tips.bottomLeft;
1818
- tips.leftBottom = tips.topRight;
1819
- tips.rightBottom = tips.topLeft;
1820
-
1821
- return tips[corner];
1822
- };
1823
-
1824
- // Border coordinates calculator
1825
- function calculateBorders(radius)
1826
- {
1827
- var borders;
1828
-
1829
- // Use canvas element if supported
1830
- if($('<canvas>').get(0).getContext)
1831
- {
1832
- borders = {
1833
- topLeft: [radius,radius], topRight: [0,radius],
1834
- bottomLeft: [radius,0], bottomRight: [0,0]
1835
- };
1836
- }
1837
-
1838
- // Canvas not supported - Use VML (IE)
1839
- else if($.browser.msie)
1840
- {
1841
- borders = {
1842
- topLeft: [-90,90,0], topRight: [-90,90,-radius],
1843
- bottomLeft: [90,270,0], bottomRight: [90, 270,-radius]
1844
- };
1845
- };
1846
-
1847
- return borders;
1848
- };
1849
-
1850
- // BGIFRAME JQUERY PLUGIN ADAPTION
1851
- // Special thanks to Brandon Aaron for this plugin
1852
- // http://plugins.jquery.com/project/bgiframe
1853
- function bgiframe()
1854
- {
1855
- var self, html, dimensions;
1856
- self = this;
1857
- dimensions = self.getDimensions();
1858
-
1859
- // Setup iframe HTML string
1860
- html = '<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:false" '+
1861
- 'style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=\'0\'); border: 1px solid red; ' +
1862
- 'height:'+dimensions.height+'px; width:'+dimensions.width+'px" />';
1863
-
1864
- // Append the new HTML and setup element reference
1865
- self.elements.bgiframe = self.elements.wrapper.prepend(html).children('.qtip-bgiframe:first');
1866
- };
1867
-
1868
- // Assign cache and event initialisation on document load
1869
- $(document).ready(function()
1870
- {
1871
- // Setup library cache with window scroll and dimensions of document
1872
- $.fn.qtip.cache = {
1873
- screen: {
1874
- scroll: { left: $(window).scrollLeft(), top: $(window).scrollTop() },
1875
- width: $(window).width(),
1876
- height: $(window).height()
1877
- }
1878
- };
1879
-
1880
- // Adjust positions of the tooltips on window resize or scroll if enabled
1881
- var adjustTimer;
1882
- $(window).bind('resize scroll', function(event)
1883
- {
1884
- clearTimeout(adjustTimer);
1885
- adjustTimer = setTimeout(function()
1886
- {
1887
- // Readjust cached screen values
1888
- if(event.type === 'scroll')
1889
- $.fn.qtip.cache.screen.scroll = { left: $(window).scrollLeft(), top: $(window).scrollTop() };
1890
- else
1891
- {
1892
- $.fn.qtip.cache.screen.width = $(window).width();
1893
- $.fn.qtip.cache.screen.height = $(window).height();
1894
- };
1895
-
1896
- for(i = 0; i < $.fn.qtip.interfaces.length; i++)
1897
- {
1898
- // Access current elements API
1899
- var api = $.fn.qtip.interfaces[i];
1900
-
1901
- // Update position if resize or scroll adjustments are enabled
1902
- if(api.status.rendered === true
1903
- && (api.options.position.type !== 'static'
1904
- || api.options.position.adjust.scroll && event.type === 'scroll'
1905
- || api.options.position.adjust.resize && event.type === 'resize'))
1906
- {
1907
- // Queue the animation so positions are updated correctly
1908
- api.updatePosition(event, true);
1909
- }
1910
- };
1911
- }
1912
- , 100);
1913
- })
1914
-
1915
- // Hide unfocus toolipts on document mousedown
1916
- $(document).bind('mousedown.qtip', function(event)
1917
- {
1918
- if($(event.target).parents('div.qtip').length === 0)
1919
- {
1920
- $('.qtip[unfocus]').each(function()
1921
- {
1922
- var api = $(this).qtip("api");
1923
-
1924
- // Only hide if its visible and not the tooltips target
1925
- if($(this).is(':visible') && !api.status.disabled
1926
- && $(event.target).add(api.elements.target).length > 1)
1927
- api.hide(event);
1928
- })
1929
- };
1930
- })
1931
- });
1932
-
1933
- // Define qTip API interfaces array
1934
- $.fn.qtip.interfaces = []
1935
-
1936
- // Define log and constant place holders
1937
- $.fn.qtip.log = { error: function(){ return this; } };
1938
- $.fn.qtip.constants = {};
1939
-
1940
- // Define configuration defaults
1941
- $.fn.qtip.defaults = {
1942
- // Content
1943
- content: {
1944
- prerender: false,
1945
- text: false,
1946
- url: false,
1947
- data: null,
1948
- title: {
1949
- text: false,
1950
- button: false
1951
- }
1952
- },
1953
- // Position
1954
- position: {
1955
- target: false,
1956
- corner: {
1957
- target: 'bottomRight',
1958
- tooltip: 'topLeft'
1959
- },
1960
- adjust: {
1961
- x: 0, y: 0,
1962
- mouse: true,
1963
- screen: false,
1964
- scroll: true,
1965
- resize: true
1966
- },
1967
- type: 'absolute',
1968
- container: false
1969
- },
1970
- // Effects
1971
- show: {
1972
- when: {
1973
- target: false,
1974
- event: 'mouseover'
1975
- },
1976
- effect: {
1977
- type: 'fade',
1978
- length: 100
1979
- },
1980
- delay: 140,
1981
- solo: false,
1982
- ready: false
1983
- },
1984
- hide: {
1985
- when: {
1986
- target: false,
1987
- event: 'mouseout'
1988
- },
1989
- effect: {
1990
- type: 'fade',
1991
- length: 100
1992
- },
1993
- delay: 0,
1994
- fixed: false
1995
- },
1996
- // Callbacks
1997
- api: {
1998
- beforeRender: function(){},
1999
- onRender: function(){},
2000
- beforePositionUpdate: function(){},
2001
- onPositionUpdate: function(){},
2002
- beforeShow: function(){},
2003
- onShow: function(){},
2004
- beforeHide: function(){},
2005
- onHide: function(){},
2006
- beforeContentUpdate: function(){},
2007
- onContentUpdate: function(){},
2008
- beforeContentLoad: function(){},
2009
- onContentLoad: function(){},
2010
- beforeTitleUpdate: function(){},
2011
- onTitleUpdate: function(){},
2012
- beforeDestroy: function(){},
2013
- onDestroy: function(){},
2014
- beforeFocus: function(){},
2015
- onFocus: function(){}
2016
- }
2017
- };
2018
-
2019
- $.fn.qtip.styles = {
2020
- defaults: {
2021
- background: 'white',
2022
- color: '#111',
2023
- overflow: 'hidden',
2024
- textAlign: 'left',
2025
- width: {
2026
- min: 0,
2027
- max: 250
2028
- },
2029
- padding: '5px 9px',
2030
- border: {
2031
- width: 1,
2032
- radius: 0,
2033
- color: '#d3d3d3'
2034
- },
2035
- tip: {
2036
- corner: false,
2037
- color: false,
2038
- size: { width: 13, height: 13 },
2039
- opacity: 1
2040
- },
2041
- title: {
2042
- background: '#e1e1e1',
2043
- fontWeight: 'bold',
2044
- padding: '7px 12px'
2045
- },
2046
- button: {
2047
- cursor: 'pointer'
2048
- },
2049
- classes: {
2050
- target: '',
2051
- tip: 'qtip-tip',
2052
- title: 'qtip-title',
2053
- button: 'qtip-button',
2054
- content: 'qtip-content',
2055
- active: 'qtip-active'
2056
- }
2057
- },
2058
- cream: {
2059
- border: {
2060
- width: 3,
2061
- radius: 0,
2062
- color: '#F9E98E'
2063
- },
2064
- title: {
2065
- background: '#F0DE7D',
2066
- color: '#A27D35'
2067
- },
2068
- background: '#FBF7AA',
2069
- color: '#A27D35',
2070
-
2071
- classes: { tooltip: 'qtip-cream' }
2072
- },
2073
- light: {
2074
- border: {
2075
- width: 3,
2076
- radius: 0,
2077
- color: '#E2E2E2'
2078
- },
2079
- title: {
2080
- background: '#f1f1f1',
2081
- color: '#454545'
2082
- },
2083
- background: 'white',
2084
- color: '#454545',
2085
-
2086
- classes: { tooltip: 'qtip-light' }
2087
- },
2088
- dark: {
2089
- border: {
2090
- width: 3,
2091
- radius: 0,
2092
- color: '#303030'
2093
- },
2094
- title: {
2095
- background: '#404040',
2096
- color: '#f3f3f3'
2097
- },
2098
- background: '#505050',
2099
- color: '#f3f3f3',
2100
-
2101
- classes: { tooltip: 'qtip-dark' }
2102
- },
2103
- red: {
2104
- border: {
2105
- width: 3,
2106
- radius: 0,
2107
- color: '#CE6F6F'
2108
- },
2109
- title: {
2110
- background: '#f28279',
2111
- color: '#9C2F2F'
2112
- },
2113
- background: '#F79992',
2114
- color: '#9C2F2F',
2115
-
2116
- classes: { tooltip: 'qtip-red' }
2117
- },
2118
- green: {
2119
- border: {
2120
- width: 3,
2121
- radius: 0,
2122
- color: '#A9DB66'
2123
- },
2124
- title: {
2125
- background: '#b9db8c',
2126
- color: '#58792E'
2127
- },
2128
- background: '#CDE6AC',
2129
- color: '#58792E',
2130
-
2131
- classes: { tooltip: 'qtip-green' }
2132
- },
2133
- blue: {
2134
- border: {
2135
- width: 3,
2136
- radius: 0,
2137
- color: '#ADD9ED'
2138
- },
2139
- title: {
2140
- background: '#D0E9F5',
2141
- color: '#5E99BD'
2142
- },
2143
- background: '#E5F6FE',
2144
- color: '#4D9FBF',
2145
-
2146
- classes: { tooltip: 'qtip-blue' }
2147
- }
2148
- };
2149
- })(jQuery);
2150
-
2151
-
2152
-
2153
-
2154
-
2155
-
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 new content and reappend the button if enabled
876
+ if(self.elements.button) self.elements.button = self.elements.button.clone(true);
877
+ self.elements.title.html(content)
878
+ if(self.elements.button) self.elements.title.prepend(self.elements.button);
879
+
880
+ // Call API method and log event
881
+ self.onTitleUpdate.call(self);
882
+ return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_TITLE_UPDATED, 'updateTitle');
883
+ },
884
+
885
+ focus: function(event)
886
+ {
887
+ var curIndex, newIndex, elemIndex, returned;
888
+
889
+ // Make sure tooltip is rendered and if not, return
890
+ if(!self.status.rendered)
891
+ return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'focus');
892
+
893
+ else if(self.options.position.type == 'static')
894
+ return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.CANNOT_FOCUS_STATIC, 'focus');
895
+
896
+ // Set z-index variables
897
+ curIndex = parseInt( self.elements.tooltip.css('z-index') );
898
+ newIndex = 6000 + $('div.qtip[qtip]').length - 1;
899
+
900
+ // Only update the z-index if it has changed and tooltip is not already focused
901
+ if(!self.status.focused && curIndex !== newIndex)
902
+ {
903
+ // Call API method and if return value is false, halt
904
+ returned = self.beforeFocus.call(self, event);
905
+ if(returned === false) return self;
906
+
907
+ // Loop through all other tooltips
908
+ $('div.qtip[qtip]').not(self.elements.tooltip).each(function()
909
+ {
910
+ if($(this).qtip('api').status.rendered === true)
911
+ {
912
+ elemIndex = parseInt($(this).css('z-index'));
913
+
914
+ // Reduce all other tooltip z-index by 1
915
+ if(typeof elemIndex == 'number' && elemIndex > -1)
916
+ $(this).css({ zIndex: parseInt( $(this).css('z-index') ) - 1 });
917
+
918
+ // Set focused status to false
919
+ $(this).qtip('api').status.focused = false;
920
+ }
921
+ })
922
+
923
+ // Set the new z-index and set focus status to true
924
+ self.elements.tooltip.css({ zIndex: newIndex });
925
+ self.status.focused = true;
926
+
927
+ // Call API method and log event
928
+ self.onFocus.call(self, event);
929
+ $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_FOCUSED, 'focus');
930
+ };
931
+
932
+ return self;
933
+ },
934
+
935
+ disable: function(state)
936
+ {
937
+ // Make sure tooltip is rendered and if not, return
938
+ if(!self.status.rendered)
939
+ return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'disable');
940
+
941
+ if(state)
942
+ {
943
+ // Tooltip is not already disabled, proceed
944
+ if(!self.status.disabled)
945
+ {
946
+ // Set the disabled flag and log event
947
+ self.status.disabled = true;
948
+ $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_DISABLED, 'disable');
949
+ }
950
+
951
+ // Tooltip is already disabled, inform user via log
952
+ else $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.TOOLTIP_ALREADY_DISABLED, 'disable');
953
+ }
954
+ else
955
+ {
956
+ // Tooltip is not already enabled, proceed
957
+ if(self.status.disabled)
958
+ {
959
+ // Reassign events, set disable status and log
960
+ self.status.disabled = false;
961
+ $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_ENABLED, 'disable');
962
+ }
963
+
964
+ // Tooltip is already enabled, inform the user via log
965
+ else $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.TOOLTIP_ALREADY_ENABLED, 'disable');
966
+ };
967
+
968
+ return self;
969
+ },
970
+
971
+ destroy: function()
972
+ {
973
+ var i, returned, interfaces;
974
+
975
+ // Call API method and if return value is false, halt
976
+ returned = self.beforeDestroy.call(self);
977
+ if(returned === false) return self;
978
+
979
+ // Check if tooltip is rendered
980
+ if(self.status.rendered)
981
+ {
982
+ // Remove event handlers and remove element
983
+ self.options.show.when.target.unbind('mousemove.qtip', self.updatePosition);
984
+ self.options.show.when.target.unbind('mouseout.qtip', self.hide);
985
+ self.options.show.when.target.unbind(self.options.show.when.event + '.qtip');
986
+ self.options.hide.when.target.unbind(self.options.hide.when.event + '.qtip');
987
+ self.elements.tooltip.unbind(self.options.hide.when.event + '.qtip');
988
+ self.elements.tooltip.unbind('mouseover.qtip', self.focus);
989
+ self.elements.tooltip.remove();
990
+ }
991
+
992
+ // Tooltip isn't yet rendered, remove render event
993
+ else self.options.show.when.target.unbind(self.options.show.when.event+'.qtip-create');
994
+
995
+ // Check to make sure qTip data is present on target element
996
+ if(typeof self.elements.target.data('qtip') == 'object')
997
+ {
998
+ // Remove API references from interfaces object
999
+ interfaces = self.elements.target.data('qtip').interfaces;
1000
+ if(typeof interfaces == 'object' && interfaces.length > 0)
1001
+ {
1002
+ // Remove API from interfaces array
1003
+ for(i = 0; i < interfaces.length - 1; i++)
1004
+ if(interfaces[i].id == self.id) interfaces.splice(i, 1)
1005
+ }
1006
+ }
1007
+ delete $.fn.qtip.interfaces[self.id];
1008
+
1009
+ // Set qTip current id to previous tooltips API if available
1010
+ if(typeof interfaces == 'object' && interfaces.length > 0)
1011
+ self.elements.target.data('qtip').current = interfaces.length -1;
1012
+ else
1013
+ self.elements.target.removeData('qtip');
1014
+
1015
+ // Call API method and log destroy
1016
+ self.onDestroy.call(self);
1017
+ $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_DESTROYED, 'destroy');
1018
+
1019
+ return self.elements.target
1020
+ },
1021
+
1022
+ getPosition: function()
1023
+ {
1024
+ var show, offset;
1025
+
1026
+ // Make sure tooltip is rendered and if not, return
1027
+ if(!self.status.rendered)
1028
+ return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'getPosition');
1029
+
1030
+ show = (self.elements.tooltip.css('display') !== 'none') ? false : true;
1031
+
1032
+ // Show and hide tooltip to make sure coordinates are returned
1033
+ if(show) self.elements.tooltip.css({ visiblity: 'hidden' }).show();
1034
+ offset = self.elements.tooltip.offset();
1035
+ if(show) self.elements.tooltip.css({ visiblity: 'visible' }).hide();
1036
+
1037
+ return offset;
1038
+ },
1039
+
1040
+ getDimensions: function()
1041
+ {
1042
+ var show, dimensions;
1043
+
1044
+ // Make sure tooltip is rendered and if not, return
1045
+ if(!self.status.rendered)
1046
+ return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'getDimensions');
1047
+
1048
+ show = (!self.elements.tooltip.is(':visible')) ? true : false;
1049
+
1050
+ // Show and hide tooltip to make sure dimensions are returned
1051
+ if(show) self.elements.tooltip.css({ visiblity: 'hidden' }).show();
1052
+ dimensions = {
1053
+ height: self.elements.tooltip.outerHeight(),
1054
+ width: self.elements.tooltip.outerWidth()
1055
+ };
1056
+ if(show) self.elements.tooltip.css({ visiblity: 'visible' }).hide();
1057
+
1058
+ return dimensions;
1059
+ }
1060
+ });
1061
+ };
1062
+
1063
+ // Define priamry construct function
1064
+ function construct()
1065
+ {
1066
+ var self, adjust, content, url, data, method, tempLength;
1067
+ self = this;
1068
+
1069
+ // Call API method
1070
+ self.beforeRender.call(self);
1071
+
1072
+ // Set rendered status to true
1073
+ self.status.rendered = true;
1074
+
1075
+ // Create initial tooltip elements
1076
+ self.elements.tooltip = '<div qtip="'+self.id+'" ' +
1077
+ 'class="qtip '+(self.options.style.classes.tooltip || self.options.style)+'"' +
1078
+ 'style="display:none; -moz-border-radius:0; -webkit-border-radius:0; border-radius:0;' +
1079
+ 'position:'+self.options.position.type+';">' +
1080
+ ' <div class="qtip-wrapper" style="position:relative; overflow:hidden; text-align:left;">' +
1081
+ ' <div class="qtip-contentWrapper" style="overflow:hidden;">' +
1082
+ ' <div class="qtip-content '+self.options.style.classes.content+'"></div>' +
1083
+ '</div></div></div>';
1084
+
1085
+ // Append to container element
1086
+ self.elements.tooltip = $(self.elements.tooltip);
1087
+ self.elements.tooltip.appendTo(self.options.position.container)
1088
+
1089
+ // Setup tooltip qTip data
1090
+ self.elements.tooltip.data('qtip', { current: 0, interfaces: [self] });
1091
+
1092
+ // Setup element references
1093
+ self.elements.wrapper = self.elements.tooltip.children('div:first');
1094
+ self.elements.contentWrapper = self.elements.wrapper.children('div:first').css({ background: self.options.style.background });
1095
+ self.elements.content = self.elements.contentWrapper.children('div:first').css( jQueryStyle(self.options.style) );
1096
+
1097
+ // Apply IE hasLayout fix to wrapper and content elements
1098
+ if($.browser.msie) self.elements.wrapper.add(self.elements.content).css({ zoom: 1 });
1099
+
1100
+ // Setup tooltip attributes
1101
+ if(self.options.hide.when.event == 'unfocus') self.elements.tooltip.attr('unfocus', true);
1102
+
1103
+ // If an explicit width is set, updateWidth prior to setting content to prevent dirty rendering
1104
+ if(typeof self.options.style.width.value == 'number') self.updateWidth();
1105
+
1106
+ // Create borders and tips if supported by the browser
1107
+ if($('<canvas>').get(0).getContext || $.browser.msie)
1108
+ {
1109
+ // Create border
1110
+ if(self.options.style.border.radius > 0)
1111
+ createBorder.call(self);
1112
+ else
1113
+ self.elements.contentWrapper.css({ border: self.options.style.border.width+'px solid '+self.options.style.border.color });
1114
+
1115
+ // Create tip if enabled
1116
+ if(self.options.style.tip.corner !== false)
1117
+ createTip.call(self);
1118
+ }
1119
+
1120
+ // Neither canvas or VML is supported, tips and borders cannot be drawn!
1121
+ else
1122
+ {
1123
+ // Set defined border width
1124
+ self.elements.contentWrapper.css({ border: self.options.style.border.width+'px solid '+self.options.style.border.color });
1125
+
1126
+ // Reset border radius and tip
1127
+ self.options.style.border.radius = 0;
1128
+ self.options.style.tip.corner = false;
1129
+
1130
+ // Inform via log
1131
+ $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.CANVAS_VML_NOT_SUPPORTED, 'render');
1132
+ };
1133
+
1134
+ // Use the provided content string or DOM array
1135
+ if((typeof self.options.content.text == 'string' && self.options.content.text.length > 0)
1136
+ || (self.options.content.text.jquery && self.options.content.text.length > 0))
1137
+ content = self.options.content.text;
1138
+
1139
+ // Use title string for content if present
1140
+ else if(typeof self.elements.target.attr('title') == 'string' && self.elements.target.attr('title').length > 0)
1141
+ {
1142
+ content = self.elements.target.attr('title').replace("\\n", '<br />');
1143
+ self.elements.target.attr('title', ''); // Remove title attribute to prevent default tooltip showing
1144
+ }
1145
+
1146
+ // No title is present, use alt attribute instead
1147
+ else if(typeof self.elements.target.attr('alt') == 'string' && self.elements.target.attr('alt').length > 0)
1148
+ {
1149
+ content = self.elements.target.attr('alt').replace("\\n", '<br />');
1150
+ self.elements.target.attr('alt', ''); // Remove alt attribute to prevent default tooltip showing
1151
+ }
1152
+
1153
+ // No valid content was provided, inform via log
1154
+ else
1155
+ {
1156
+ content = ' ';
1157
+ $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.NO_VALID_CONTENT, 'render');
1158
+ };
1159
+
1160
+ // Set the tooltips content and create title if enabled
1161
+ if(self.options.content.title.text !== false) createTitle.call(self);
1162
+ self.updateContent(content);
1163
+
1164
+ // Assign events and toggle tooltip with focus
1165
+ assignEvents.call(self);
1166
+ if(self.options.show.ready === true) self.show();
1167
+
1168
+ // Retrieve ajax content if provided
1169
+ if(self.options.content.url !== false)
1170
+ {
1171
+ url = self.options.content.url;
1172
+ data = self.options.content.data;
1173
+ method = self.options.content.method || 'get';
1174
+ self.loadContent(url, data, method);
1175
+ };
1176
+
1177
+ // Call API method and log event
1178
+ self.onRender.call(self);
1179
+ $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_RENDERED, 'render');
1180
+ };
1181
+
1182
+ // Create borders using canvas and VML
1183
+ function createBorder()
1184
+ {
1185
+ var self, i, width, radius, color, coordinates, containers, size, betweenWidth, betweenCorners, borderTop, borderBottom, borderCoord, sideWidth, vertWidth;
1186
+ self = this;
1187
+
1188
+ // Destroy previous border elements, if present
1189
+ self.elements.wrapper.find('.qtip-borderBottom, .qtip-borderTop').remove();
1190
+
1191
+ // Setup local variables
1192
+ width = self.options.style.border.width;
1193
+ radius = self.options.style.border.radius;
1194
+ color = self.options.style.border.color || self.options.style.tip.color;
1195
+
1196
+ // Calculate border coordinates
1197
+ coordinates = calculateBorders(radius);
1198
+
1199
+ // Create containers for the border shapes
1200
+ containers = {};
1201
+ for(i in coordinates)
1202
+ {
1203
+ // Create shape container
1204
+ containers[i] = '<div rel="'+i+'" style="'+((i.search(/Left/) !== -1) ? 'left' : 'right') + ':0; ' +
1205
+ 'position:absolute; height:'+radius+'px; width:'+radius+'px; overflow:hidden; line-height:0.1px; font-size:1px">';
1206
+
1207
+ // Canvas is supported
1208
+ if($('<canvas>').get(0).getContext)
1209
+ containers[i] += '<canvas height="'+radius+'" width="'+radius+'" style="vertical-align: top"></canvas>';
1210
+
1211
+ // No canvas, but if it's IE use VML
1212
+ else if($.browser.msie)
1213
+ {
1214
+ size = radius * 2 + 3;
1215
+ containers[i] += '<v:arc stroked="false" fillcolor="'+color+'" startangle="'+coordinates[i][0]+'" endangle="'+coordinates[i][1]+'" ' +
1216
+ 'style="width:'+size+'px; height:'+size+'px; margin-top:'+((i.search(/bottom/) !== -1) ? -2 : -1)+'px; ' +
1217
+ 'margin-left:'+((i.search(/Right/) !== -1) ? coordinates[i][2] - 3.5 : -1)+'px; ' +
1218
+ 'vertical-align:top; display:inline-block; behavior:url(#default#VML)"></v:arc>';
1219
+
1220
+ };
1221
+
1222
+ containers[i] += '</div>';
1223
+ };
1224
+
1225
+ // Create between corners elements
1226
+ betweenWidth = self.getDimensions().width - (Math.max(width, radius) * 2);
1227
+ betweenCorners = '<div class="qtip-betweenCorners" style="height:'+radius+'px; width:'+betweenWidth+'px; ' +
1228
+ 'overflow:hidden; background-color:'+color+'; line-height:0.1px; font-size:1px;">';
1229
+
1230
+ // Create top border container
1231
+ borderTop = '<div class="qtip-borderTop" dir="ltr" style="height:'+radius+'px; ' +
1232
+ 'margin-left:'+radius+'px; line-height:0.1px; font-size:1px; padding:0;">' +
1233
+ containers['topLeft'] + containers['topRight'] + betweenCorners;
1234
+ self.elements.wrapper.prepend(borderTop);
1235
+
1236
+ // Create bottom border container
1237
+ borderBottom = '<div class="qtip-borderBottom" dir="ltr" style="height:'+radius+'px; ' +
1238
+ 'margin-left:'+radius+'px; line-height:0.1px; font-size:1px; padding:0;">' +
1239
+ containers['bottomLeft'] + containers['bottomRight'] + betweenCorners;
1240
+ self.elements.wrapper.append(borderBottom);
1241
+
1242
+ // Draw the borders if canvas were used (Delayed til after DOM creation)
1243
+ if($('<canvas>').get(0).getContext)
1244
+ {
1245
+ self.elements.wrapper.find('canvas').each(function()
1246
+ {
1247
+ borderCoord = coordinates[ $(this).parent('[rel]:first').attr('rel') ];
1248
+ drawBorder.call(self, $(this), borderCoord, radius, color);
1249
+ })
1250
+ }
1251
+
1252
+ // Create a phantom VML element (IE won't show the last created VML element otherwise)
1253
+ else if($.browser.msie) self.elements.tooltip.append('<v:image style="behavior:url(#default#VML);"></v:image>');
1254
+
1255
+ // Setup contentWrapper border
1256
+ sideWidth = Math.max(radius, (radius + (width - radius)) )
1257
+ vertWidth = Math.max(width - radius, 0);
1258
+ self.elements.contentWrapper.css({
1259
+ border: '0px solid ' + color,
1260
+ borderWidth: vertWidth + 'px ' + sideWidth + 'px'
1261
+ })
1262
+ };
1263
+
1264
+ // Border canvas draw method
1265
+ function drawBorder(canvas, coordinates, radius, color)
1266
+ {
1267
+ // Create corner
1268
+ var context = canvas.get(0).getContext('2d');
1269
+ context.fillStyle = color;
1270
+ context.beginPath();
1271
+ context.arc(coordinates[0], coordinates[1], radius, 0, Math.PI * 2, false);
1272
+ context.fill();
1273
+ };
1274
+
1275
+ // Create tip using canvas and VML
1276
+ function createTip(corner)
1277
+ {
1278
+ var self, color, coordinates, coordsize, path;
1279
+ self = this;
1280
+
1281
+ // Destroy previous tip, if there is one
1282
+ if(self.elements.tip !== null) self.elements.tip.remove();
1283
+
1284
+ // Setup color and corner values
1285
+ color = self.options.style.tip.color || self.options.style.border.color;
1286
+ if(self.options.style.tip.corner === false) return;
1287
+ else if(!corner) corner = self.options.style.tip.corner;
1288
+
1289
+ // Calculate tip coordinates
1290
+ coordinates = calculateTip(corner, self.options.style.tip.size.width, self.options.style.tip.size.height);
1291
+
1292
+ // Create tip element
1293
+ self.elements.tip = '<div class="'+self.options.style.classes.tip+'" dir="ltr" rel="'+corner+'" style="position:absolute; ' +
1294
+ 'height:'+self.options.style.tip.size.height+'px; width:'+self.options.style.tip.size.width+'px; ' +
1295
+ 'margin:0 auto; line-height:0.1px; font-size:1px;">';
1296
+
1297
+ // Use canvas element if supported
1298
+ if($('<canvas>').get(0).getContext)
1299
+ self.elements.tip += '<canvas height="'+self.options.style.tip.size.height+'" width="'+self.options.style.tip.size.width+'"></canvas>';
1300
+
1301
+ // Canvas not supported - Use VML (IE)
1302
+ else if($.browser.msie)
1303
+ {
1304
+ // Create coordize and tip path using tip coordinates
1305
+ coordsize = self.options.style.tip.size.width + ',' + self.options.style.tip.size.height;
1306
+ path = 'm' + coordinates[0][0] + ',' + coordinates[0][1];
1307
+ path += ' l' + coordinates[1][0] + ',' + coordinates[1][1];
1308
+ path += ' ' + coordinates[2][0] + ',' + coordinates[2][1];
1309
+ path += ' xe';
1310
+
1311
+ // Create VML element
1312
+ self.elements.tip += '<v:shape fillcolor="'+color+'" stroked="false" filled="true" path="'+path+'" coordsize="'+coordsize+'" ' +
1313
+ 'style="width:'+self.options.style.tip.size.width+'px; height:'+self.options.style.tip.size.height+'px; ' +
1314
+ 'line-height:0.1px; display:inline-block; behavior:url(#default#VML); ' +
1315
+ 'vertical-align:'+((corner.search(/top/) !== -1) ? 'bottom' : 'top')+'"></v:shape>';
1316
+
1317
+ // Create a phantom VML element (IE won't show the last created VML element otherwise)
1318
+ self.elements.tip += '<v:image style="behavior:url(#default#VML);"></v:image>';
1319
+
1320
+ // Prevent tooltip appearing above the content (IE z-index bug)
1321
+ self.elements.contentWrapper.css('position', 'relative');
1322
+ };
1323
+
1324
+ // Attach new tip to tooltip element
1325
+ self.elements.tooltip.prepend(self.elements.tip + '</div>');
1326
+
1327
+ // Create element reference and draw the canvas tip (Delayed til after DOM creation)
1328
+ self.elements.tip = self.elements.tooltip.find('.'+self.options.style.classes.tip).eq(0);
1329
+ if($('<canvas>').get(0).getContext)
1330
+ drawTip.call(self, self.elements.tip.find('canvas:first'), coordinates, color);
1331
+
1332
+ // Fix IE small tip bug
1333
+ if(corner.search(/top/) !== -1 && $.browser.msie && parseInt($.browser.version.charAt(0)) === 6)
1334
+ self.elements.tip.css({ marginTop: -4 });
1335
+
1336
+ // Set the tip position
1337
+ positionTip.call(self, corner);
1338
+ };
1339
+
1340
+ // Canvas tip drawing method
1341
+ function drawTip(canvas, coordinates, color)
1342
+ {
1343
+ // Setup properties
1344
+ var context = canvas.get(0).getContext('2d');
1345
+ context.fillStyle = color;
1346
+
1347
+ // Create tip
1348
+ context.beginPath();
1349
+ context.moveTo(coordinates[0][0], coordinates[0][1]);
1350
+ context.lineTo(coordinates[1][0], coordinates[1][1]);
1351
+ context.lineTo(coordinates[2][0], coordinates[2][1]);
1352
+ context.fill();
1353
+ };
1354
+
1355
+ function positionTip(corner)
1356
+ {
1357
+ var self, ieAdjust, paddingCorner, paddingSize, newMargin;
1358
+ self = this;
1359
+
1360
+ // Return if tips are disabled or tip is not yet rendered
1361
+ if(self.options.style.tip.corner === false || !self.elements.tip) return;
1362
+ if(!corner) corner = self.elements.tip.attr('rel');
1363
+
1364
+ // Setup adjustment variables
1365
+ ieAdjust = positionAdjust = ($.browser.msie) ? 1 : 0;
1366
+
1367
+ // Set initial position
1368
+ self.elements.tip.css(corner.match(/left|right|top|bottom/)[0], 0);
1369
+
1370
+ // Set position of tip to correct side
1371
+ if(corner.search(/top|bottom/) !== -1)
1372
+ {
1373
+ // Adjustments for IE6 - 0.5px border gap bug
1374
+ if($.browser.msie)
1375
+ {
1376
+ if(parseInt($.browser.version.charAt(0)) === 6)
1377
+ positionAdjust = (corner.search(/top/) !== -1) ? -3 : 1;
1378
+ else
1379
+ positionAdjust = (corner.search(/top/) !== -1) ? 1 : 2;
1380
+ };
1381
+
1382
+ if(corner.search(/Middle/) !== -1)
1383
+ self.elements.tip.css({ left: '50%', marginLeft: -(self.options.style.tip.size.width / 2) });
1384
+
1385
+ else if(corner.search(/Left/) !== -1)
1386
+ self.elements.tip.css({ left: self.options.style.border.radius - ieAdjust });
1387
+
1388
+ else if(corner.search(/Right/) !== -1)
1389
+ self.elements.tip.css({ right: self.options.style.border.radius + ieAdjust });
1390
+
1391
+ if(corner.search(/top/) !== -1)
1392
+ self.elements.tip.css({ top: -positionAdjust });
1393
+ else
1394
+ self.elements.tip.css({ bottom: positionAdjust });
1395
+
1396
+ }
1397
+ else if(corner.search(/left|right/) !== -1)
1398
+ {
1399
+ // Adjustments for IE6 - 0.5px border gap bug
1400
+ if($.browser.msie)
1401
+ positionAdjust = (parseInt($.browser.version.charAt(0)) === 6) ? 1 : ((corner.search(/left/) !== -1) ? 1 : 2);
1402
+
1403
+ if(corner.search(/Middle/) !== -1)
1404
+ self.elements.tip.css({ top: '50%', marginTop: -(self.options.style.tip.size.height / 2) });
1405
+
1406
+ else if(corner.search(/Top/) !== -1)
1407
+ self.elements.tip.css({ top: self.options.style.border.radius - ieAdjust });
1408
+
1409
+ else if(corner.search(/Bottom/) !== -1)
1410
+ self.elements.tip.css({ bottom: self.options.style.border.radius + ieAdjust });
1411
+
1412
+ if(corner.search(/left/) !== -1)
1413
+ self.elements.tip.css({ left: -positionAdjust });
1414
+ else
1415
+ self.elements.tip.css({ right: positionAdjust });
1416
+ };
1417
+
1418
+ // Adjust tooltip padding to compensate for tip
1419
+ paddingCorner = 'padding-' + corner.match(/left|right|top|bottom/)[0];
1420
+ paddingSize = self.options.style.tip.size[ (paddingCorner.search(/left|right/) !== -1) ? 'width' : 'height' ];
1421
+ self.elements.tooltip.css('padding', 0);
1422
+ self.elements.tooltip.css(paddingCorner, paddingSize);
1423
+
1424
+ // Match content margin to prevent gap bug in IE6 ONLY
1425
+ if($.browser.msie && parseInt($.browser.version.charAt(0)) == 6)
1426
+ {
1427
+ newMargin = parseInt(self.elements.tip.css('margin-top')) || 0;
1428
+ newMargin += parseInt(self.elements.content.css('margin-top')) || 0;
1429
+
1430
+ self.elements.tip.css({ marginTop: newMargin });
1431
+ };
1432
+ };
1433
+
1434
+ // Create title bar for content
1435
+ function createTitle()
1436
+ {
1437
+ var self = this;
1438
+
1439
+ // Destroy previous title element, if present
1440
+ if(self.elements.title !== null) self.elements.title.remove();
1441
+
1442
+ // Create title element
1443
+ self.elements.title = $('<div class="'+self.options.style.classes.title+'">')
1444
+ .css( jQueryStyle(self.options.style.title, true) )
1445
+ .css({ zoom: ($.browser.msie) ? 1 : 0 })
1446
+ .prependTo(self.elements.contentWrapper);
1447
+
1448
+ // Update title with contents if enabled
1449
+ if(self.options.content.title.text) self.updateTitle.call(self, self.options.content.title.text);
1450
+
1451
+ // Create title close buttons if enabled
1452
+ if(self.options.content.title.button !== false
1453
+ && typeof self.options.content.title.button == 'string')
1454
+ {
1455
+ self.elements.button = $('<a class="'+self.options.style.classes.button+'" style="float:right; position: relative"></a>')
1456
+ .css( jQueryStyle(self.options.style.button, true) )
1457
+ .html(self.options.content.title.button)
1458
+ .prependTo(self.elements.title)
1459
+ .click(function(event){ if(!self.status.disabled) self.hide(event) });
1460
+ };
1461
+ };
1462
+
1463
+ // Assign hide and show events
1464
+ function assignEvents()
1465
+ {
1466
+ var self, showTarget, hideTarget, inactiveEvents;
1467
+ self = this;
1468
+
1469
+ // Setup event target variables
1470
+ showTarget = self.options.show.when.target;
1471
+ hideTarget = self.options.hide.when.target;
1472
+
1473
+ // Add tooltip as a hideTarget is its fixed
1474
+ if(self.options.hide.fixed) hideTarget = hideTarget.add(self.elements.tooltip);
1475
+
1476
+ // Check if the hide event is special 'inactive' type
1477
+ if(self.options.hide.when.event == 'inactive')
1478
+ {
1479
+ // Define events which reset the 'inactive' event handler
1480
+ inactiveEvents = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove',
1481
+ 'mouseout', 'mouseenter', 'mouseleave', 'mouseover' ];
1482
+
1483
+ // Define 'inactive' event timer method
1484
+ function inactiveMethod(event)
1485
+ {
1486
+ if(self.status.disabled === true) return;
1487
+
1488
+ //Clear and reset the timer
1489
+ clearTimeout(self.timers.inactive);
1490
+ self.timers.inactive = setTimeout(function()
1491
+ {
1492
+ // Unassign 'inactive' events
1493
+ $(inactiveEvents).each(function()
1494
+ {
1495
+ hideTarget.unbind(this+'.qtip-inactive');
1496
+ self.elements.content.unbind(this+'.qtip-inactive');
1497
+ });
1498
+
1499
+ // Hide the tooltip
1500
+ self.hide(event);
1501
+ }
1502
+ , self.options.hide.delay);
1503
+ };
1504
+ }
1505
+
1506
+ // Check if the tooltip is 'fixed'
1507
+ else if(self.options.hide.fixed === true)
1508
+ {
1509
+ self.elements.tooltip.bind('mouseover.qtip', function()
1510
+ {
1511
+ if(self.status.disabled === true) return;
1512
+
1513
+ // Reset the hide timer
1514
+ clearTimeout(self.timers.hide);
1515
+ });
1516
+ };
1517
+
1518
+ // Define show event method
1519
+ function showMethod(event)
1520
+ {
1521
+ if(self.status.disabled === true) return;
1522
+
1523
+ // If set, hide tooltip when inactive for delay period
1524
+ if(self.options.hide.when.event == 'inactive')
1525
+ {
1526
+ // Assign each reset event
1527
+ $(inactiveEvents).each(function()
1528
+ {
1529
+ hideTarget.bind(this+'.qtip-inactive', inactiveMethod);
1530
+ self.elements.content.bind(this+'.qtip-inactive', inactiveMethod);
1531
+ });
1532
+
1533
+ // Start the inactive timer
1534
+ inactiveMethod();
1535
+ };
1536
+
1537
+ // Clear hide timers
1538
+ clearTimeout(self.timers.show);
1539
+ clearTimeout(self.timers.hide);
1540
+
1541
+ // Start show timer
1542
+ self.timers.show = setTimeout(function(){ self.show(event); }, self.options.show.delay);
1543
+ };
1544
+
1545
+ // Define hide event method
1546
+ function hideMethod(event)
1547
+ {
1548
+ if(self.status.disabled === true) return;
1549
+
1550
+ // Prevent hiding if tooltip is fixed and event target is the tooltip
1551
+ if(self.options.hide.fixed === true
1552
+ && self.options.hide.when.event.search(/mouse(out|leave)/i) !== -1
1553
+ && $(event.relatedTarget).parents('div.qtip[qtip]').length > 0)
1554
+ {
1555
+ // Prevent default and popagation
1556
+ event.stopPropagation();
1557
+ event.preventDefault();
1558
+
1559
+ // Reset the hide timer
1560
+ clearTimeout(self.timers.hide);
1561
+ return false;
1562
+ };
1563
+
1564
+ // Clear timers and stop animation queue
1565
+ clearTimeout(self.timers.show);
1566
+ clearTimeout(self.timers.hide);
1567
+ self.elements.tooltip.stop(true, true);
1568
+
1569
+ // If tooltip has displayed, start hide timer
1570
+ self.timers.hide = setTimeout(function(){ self.hide(event); }, self.options.hide.delay);
1571
+ };
1572
+
1573
+ // Both events and targets are identical, apply events using a toggle
1574
+ if((self.options.show.when.target.add(self.options.hide.when.target).length === 1
1575
+ && self.options.show.when.event == self.options.hide.when.event
1576
+ && self.options.hide.when.event !== 'inactive')
1577
+ || self.options.hide.when.event == 'unfocus')
1578
+ {
1579
+ self.cache.toggle = 0;
1580
+ // Use a toggle to prevent hide/show conflicts
1581
+ showTarget.bind(self.options.show.when.event + '.qtip', function(event)
1582
+ {
1583
+ if(self.cache.toggle == 0) showMethod(event);
1584
+ else hideMethod(event);
1585
+ });
1586
+ }
1587
+
1588
+ // Events are not identical, bind normally
1589
+ else
1590
+ {
1591
+ showTarget.bind(self.options.show.when.event + '.qtip', showMethod);
1592
+
1593
+ // If the hide event is not 'inactive', bind the hide method
1594
+ if(self.options.hide.when.event !== 'inactive')
1595
+ hideTarget.bind(self.options.hide.when.event + '.qtip', hideMethod);
1596
+ };
1597
+
1598
+ // Focus the tooltip on mouseover
1599
+ if(self.options.position.type.search(/(fixed|absolute)/) !== -1)
1600
+ self.elements.tooltip.bind('mouseover.qtip', self.focus);
1601
+
1602
+ // If mouse is the target, update tooltip position on mousemove
1603
+ if(self.options.position.target === 'mouse' && self.options.position.type !== 'static')
1604
+ {
1605
+ showTarget.bind('mousemove.qtip', function(event)
1606
+ {
1607
+ // Set the new mouse positions if adjustment is enabled
1608
+ self.cache.mouse = { x: event.pageX, y: event.pageY };
1609
+
1610
+ // Update the tooltip position only if the tooltip is visible and adjustment is enabled
1611
+ if(self.status.disabled === false
1612
+ && self.options.position.adjust.mouse === true
1613
+ && self.options.position.type !== 'static'
1614
+ && self.elements.tooltip.css('display') !== 'none')
1615
+ self.updatePosition(event);
1616
+ });
1617
+ };
1618
+ };
1619
+
1620
+ // Screen position adjustment
1621
+ function screenAdjust(position, target, tooltip)
1622
+ {
1623
+ var self, adjustedPosition, adjust, newCorner, overflow, corner;
1624
+ self = this;
1625
+
1626
+ // Setup corner and adjustment variable
1627
+ if(tooltip.corner == 'center') return target.position // TODO: 'center' corner adjustment
1628
+ adjustedPosition = $.extend({}, position);
1629
+ newCorner = { x: false, y: false };
1630
+
1631
+ // Define overflow properties
1632
+ overflow = {
1633
+ left: (adjustedPosition.left < $.fn.qtip.cache.screen.scroll.left),
1634
+ right: (adjustedPosition.left + tooltip.dimensions.width + 2 >= $.fn.qtip.cache.screen.width + $.fn.qtip.cache.screen.scroll.left),
1635
+ top: (adjustedPosition.top < $.fn.qtip.cache.screen.scroll.top),
1636
+ bottom: (adjustedPosition.top + tooltip.dimensions.height + 2 >= $.fn.qtip.cache.screen.height + $.fn.qtip.cache.screen.scroll.top)
1637
+ };
1638
+
1639
+ // Determine new positioning properties
1640
+ adjust = {
1641
+ left: (overflow.left && (tooltip.corner.search(/right/i) != -1 || (tooltip.corner.search(/right/i) == -1 && !overflow.right))),
1642
+ right: (overflow.right && (tooltip.corner.search(/left/i) != -1 || (tooltip.corner.search(/left/i) == -1 && !overflow.left))),
1643
+ top: (overflow.top && tooltip.corner.search(/top/i) == -1),
1644
+ bottom: (overflow.bottom && tooltip.corner.search(/bottom/i) == -1)
1645
+ };
1646
+
1647
+ // Tooltip overflows off the left side of the screen
1648
+ if(adjust.left)
1649
+ {
1650
+ if(self.options.position.target !== 'mouse')
1651
+ adjustedPosition.left = target.position.left + target.dimensions.width;
1652
+ else
1653
+ adjustedPosition.left = self.cache.mouse.x
1654
+
1655
+ newCorner.x = 'Left';
1656
+ }
1657
+
1658
+ // Tooltip overflows off the right side of the screen
1659
+ else if(adjust.right)
1660
+ {
1661
+ if(self.options.position.target !== 'mouse')
1662
+ adjustedPosition.left = target.position.left - tooltip.dimensions.width;
1663
+ else
1664
+ adjustedPosition.left = self.cache.mouse.x - tooltip.dimensions.width;
1665
+
1666
+ newCorner.x = 'Right';
1667
+ };
1668
+
1669
+ // Tooltip overflows off the top of the screen
1670
+ if(adjust.top)
1671
+ {
1672
+ if(self.options.position.target !== 'mouse')
1673
+ adjustedPosition.top = target.position.top + target.dimensions.height;
1674
+ else
1675
+ adjustedPosition.top = self.cache.mouse.y
1676
+
1677
+ newCorner.y = 'top';
1678
+ }
1679
+
1680
+ // Tooltip overflows off the bottom of the screen
1681
+ else if(adjust.bottom)
1682
+ {
1683
+ if(self.options.position.target !== 'mouse')
1684
+ adjustedPosition.top = target.position.top - tooltip.dimensions.height;
1685
+ else
1686
+ adjustedPosition.top = self.cache.mouse.y - tooltip.dimensions.height;
1687
+
1688
+ newCorner.y = 'bottom';
1689
+ };
1690
+
1691
+ // Don't adjust if resulting position is negative
1692
+ if(adjustedPosition.left < 0)
1693
+ {
1694
+ adjustedPosition.left = position.left;
1695
+ newCorner.x = false;
1696
+ };
1697
+ if(adjustedPosition.top < 0)
1698
+ {
1699
+ adjustedPosition.top = position.top;
1700
+ newCorner.y = false;
1701
+ };
1702
+
1703
+ // Change tip corner if positioning has changed and tips are enabled
1704
+ if(self.options.style.tip.corner !== false)
1705
+ {
1706
+ // Determine new corner properties
1707
+ adjustedPosition.corner = new String(tooltip.corner);
1708
+ if(newCorner.x !== false) adjustedPosition.corner = adjustedPosition.corner.replace(/Left|Right|Middle/, newCorner.x);
1709
+ if(newCorner.y !== false) adjustedPosition.corner = adjustedPosition.corner.replace(/top|bottom/, newCorner.y);
1710
+
1711
+ // Adjust tip if position has changed and tips are enabled
1712
+ if(adjustedPosition.corner !== self.elements.tip.attr('rel'))
1713
+ createTip.call(self, adjustedPosition.corner);
1714
+ };
1715
+
1716
+ return adjustedPosition;
1717
+ };
1718
+
1719
+ // Build a jQuery style object from supplied style object
1720
+ function jQueryStyle(style, sub)
1721
+ {
1722
+ var styleObj, i;
1723
+
1724
+ styleObj = $.extend(true, {}, style);
1725
+ for(i in styleObj)
1726
+ {
1727
+ if(sub === true && i.search(/(tip|classes)/i) !== -1)
1728
+ delete styleObj[i];
1729
+ else if(!sub && i.search(/(width|border|tip|title|classes|user)/i) !== -1)
1730
+ delete styleObj[i];
1731
+ };
1732
+
1733
+ return styleObj;
1734
+ };
1735
+
1736
+ // Sanitize styles
1737
+ function sanitizeStyle(style)
1738
+ {
1739
+ if(typeof style.tip !== 'object') style.tip = { corner: style.tip };
1740
+ if(typeof style.tip.size !== 'object') style.tip.size = { width: style.tip.size, height: style.tip.size };
1741
+ if(typeof style.border !== 'object') style.border = { width: style.border };
1742
+ if(typeof style.width !== 'object') style.width = { value: style.width };
1743
+ if(typeof style.width.max == 'string') style.width.max = parseInt(style.width.max.replace(/([0-9]+)/i, "$1"));
1744
+ if(typeof style.width.min == 'string') style.width.min = parseInt(style.width.min.replace(/([0-9]+)/i, "$1"));
1745
+
1746
+ // Convert deprecated x and y tip values to width/height
1747
+ if(typeof style.tip.size.x == 'number')
1748
+ {
1749
+ style.tip.size.width = style.tip.size.x;
1750
+ delete style.tip.size.x;
1751
+ };
1752
+ if(typeof style.tip.size.y == 'number')
1753
+ {
1754
+ style.tip.size.height = style.tip.size.y;
1755
+ delete style.tip.size.y;
1756
+ };
1757
+
1758
+ return style;
1759
+ };
1760
+
1761
+ // Build styles recursively with inheritance
1762
+ function buildStyle()
1763
+ {
1764
+ var self, i, styleArray, styleExtend, finalStyle, ieAdjust;
1765
+ self = this;
1766
+
1767
+ // Build style options from supplied arguments
1768
+ styleArray = [true, {}];
1769
+ for(i = 0; i < arguments.length; i++)
1770
+ styleArray.push(arguments[i]);
1771
+ styleExtend = [ $.extend.apply($, styleArray) ];
1772
+
1773
+ // Loop through each named style inheritance
1774
+ while(typeof styleExtend[0].name == 'string')
1775
+ {
1776
+ // Sanitize style data and append to extend array
1777
+ styleExtend.unshift( sanitizeStyle($.fn.qtip.styles[ styleExtend[0].name ]) );
1778
+ };
1779
+
1780
+ // Make sure resulting tooltip className represents final style
1781
+ styleExtend.unshift(true, {classes:{ tooltip: 'qtip-' + (arguments[0].name || 'defaults') }}, $.fn.qtip.styles.defaults);
1782
+
1783
+ // Extend into a single style object
1784
+ finalStyle = $.extend.apply($, styleExtend);
1785
+
1786
+ // Adjust tip size if needed (IE 1px adjustment bug fix)
1787
+ ieAdjust = ($.browser.msie) ? 1 : 0;
1788
+ finalStyle.tip.size.width += ieAdjust;
1789
+ finalStyle.tip.size.height += ieAdjust;
1790
+
1791
+ // Force even numbers for pixel precision
1792
+ if(finalStyle.tip.size.width % 2 > 0) finalStyle.tip.size.width += 1;
1793
+ if(finalStyle.tip.size.height % 2 > 0) finalStyle.tip.size.height += 1;
1794
+
1795
+ // Sanitize final styles tip corner value
1796
+ if(finalStyle.tip.corner === true)
1797
+ finalStyle.tip.corner = (self.options.position.corner.tooltip === 'center') ? false : self.options.position.corner.tooltip;
1798
+
1799
+ return finalStyle;
1800
+ };
1801
+
1802
+ // Tip coordinates calculator
1803
+ function calculateTip(corner, width, height)
1804
+ {
1805
+ // Define tip coordinates in terms of height and width values
1806
+ var tips = {
1807
+ bottomRight: [[0,0], [width,height], [width,0]],
1808
+ bottomLeft: [[0,0], [width,0], [0,height]],
1809
+ topRight: [[0,height], [width,0], [width,height]],
1810
+ topLeft: [[0,0], [0,height], [width,height]],
1811
+ topMiddle: [[0,height], [width / 2,0], [width,height]],
1812
+ bottomMiddle: [[0,0], [width,0], [width / 2,height]],
1813
+ rightMiddle: [[0,0], [width,height / 2], [0,height]],
1814
+ leftMiddle: [[width,0], [width,height], [0,height / 2]]
1815
+ };
1816
+ tips.leftTop = tips.bottomRight;
1817
+ tips.rightTop = tips.bottomLeft;
1818
+ tips.leftBottom = tips.topRight;
1819
+ tips.rightBottom = tips.topLeft;
1820
+
1821
+ return tips[corner];
1822
+ };
1823
+
1824
+ // Border coordinates calculator
1825
+ function calculateBorders(radius)
1826
+ {
1827
+ var borders;
1828
+
1829
+ // Use canvas element if supported
1830
+ if($('<canvas>').get(0).getContext)
1831
+ {
1832
+ borders = {
1833
+ topLeft: [radius,radius], topRight: [0,radius],
1834
+ bottomLeft: [radius,0], bottomRight: [0,0]
1835
+ };
1836
+ }
1837
+
1838
+ // Canvas not supported - Use VML (IE)
1839
+ else if($.browser.msie)
1840
+ {
1841
+ borders = {
1842
+ topLeft: [-90,90,0], topRight: [-90,90,-radius],
1843
+ bottomLeft: [90,270,0], bottomRight: [90, 270,-radius]
1844
+ };
1845
+ };
1846
+
1847
+ return borders;
1848
+ };
1849
+
1850
+ // BGIFRAME JQUERY PLUGIN ADAPTION
1851
+ // Special thanks to Brandon Aaron for this plugin
1852
+ // http://plugins.jquery.com/project/bgiframe
1853
+ function bgiframe()
1854
+ {
1855
+ var self, html, dimensions;
1856
+ self = this;
1857
+ dimensions = self.getDimensions();
1858
+
1859
+ // Setup iframe HTML string
1860
+ html = '<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:false" '+
1861
+ 'style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=\'0\'); border: 1px solid red; ' +
1862
+ 'height:'+dimensions.height+'px; width:'+dimensions.width+'px" />';
1863
+
1864
+ // Append the new HTML and setup element reference
1865
+ self.elements.bgiframe = self.elements.wrapper.prepend(html).children('.qtip-bgiframe:first');
1866
+ };
1867
+
1868
+ // Assign cache and event initialisation on document load
1869
+ $(document).ready(function()
1870
+ {
1871
+ // Setup library cache with window scroll and dimensions of document
1872
+ $.fn.qtip.cache = {
1873
+ screen: {
1874
+ scroll: { left: $(window).scrollLeft(), top: $(window).scrollTop() },
1875
+ width: $(window).width(),
1876
+ height: $(window).height()
1877
+ }
1878
+ };
1879
+
1880
+ // Adjust positions of the tooltips on window resize or scroll if enabled
1881
+ var adjustTimer;
1882
+ $(window).bind('resize scroll', function(event)
1883
+ {
1884
+ clearTimeout(adjustTimer);
1885
+ adjustTimer = setTimeout(function()
1886
+ {
1887
+ // Readjust cached screen values
1888
+ if(event.type === 'scroll')
1889
+ $.fn.qtip.cache.screen.scroll = { left: $(window).scrollLeft(), top: $(window).scrollTop() };
1890
+ else
1891
+ {
1892
+ $.fn.qtip.cache.screen.width = $(window).width();
1893
+ $.fn.qtip.cache.screen.height = $(window).height();
1894
+ };
1895
+
1896
+ for(i = 0; i < $.fn.qtip.interfaces.length; i++)
1897
+ {
1898
+ // Access current elements API
1899
+ var api = $.fn.qtip.interfaces[i];
1900
+
1901
+ // Update position if resize or scroll adjustments are enabled
1902
+ if(api.status.rendered === true
1903
+ && (api.options.position.type !== 'static'
1904
+ || api.options.position.adjust.scroll && event.type === 'scroll'
1905
+ || api.options.position.adjust.resize && event.type === 'resize'))
1906
+ {
1907
+ // Queue the animation so positions are updated correctly
1908
+ api.updatePosition(event, true);
1909
+ }
1910
+ };
1911
+ }
1912
+ , 100);
1913
+ })
1914
+
1915
+ // Hide unfocus toolipts on document mousedown
1916
+ $(document).bind('mousedown.qtip', function(event)
1917
+ {
1918
+ if($(event.target).parents('div.qtip').length === 0)
1919
+ {
1920
+ $('.qtip[unfocus]').each(function()
1921
+ {
1922
+ var api = $(this).qtip("api");
1923
+
1924
+ // Only hide if its visible and not the tooltips target
1925
+ if($(this).is(':visible') && !api.status.disabled
1926
+ && $(event.target).add(api.elements.target).length > 1)
1927
+ api.hide(event);
1928
+ })
1929
+ };
1930
+ })
1931
+ });
1932
+
1933
+ // Define qTip API interfaces array
1934
+ $.fn.qtip.interfaces = []
1935
+
1936
+ // Define log and constant place holders
1937
+ $.fn.qtip.log = { error: function(){ return this; } };
1938
+ $.fn.qtip.constants = {};
1939
+
1940
+ // Define configuration defaults
1941
+ $.fn.qtip.defaults = {
1942
+ // Content
1943
+ content: {
1944
+ prerender: false,
1945
+ text: false,
1946
+ url: false,
1947
+ data: null,
1948
+ title: {
1949
+ text: false,
1950
+ button: false
1951
+ }
1952
+ },
1953
+ // Position
1954
+ position: {
1955
+ target: false,
1956
+ corner: {
1957
+ target: 'bottomRight',
1958
+ tooltip: 'topLeft'
1959
+ },
1960
+ adjust: {
1961
+ x: 0, y: 0,
1962
+ mouse: true,
1963
+ screen: false,
1964
+ scroll: true,
1965
+ resize: true
1966
+ },
1967
+ type: 'absolute',
1968
+ container: false
1969
+ },
1970
+ // Effects
1971
+ show: {
1972
+ when: {
1973
+ target: false,
1974
+ event: 'mouseover'
1975
+ },
1976
+ effect: {
1977
+ type: 'fade',
1978
+ length: 100
1979
+ },
1980
+ delay: 140,
1981
+ solo: false,
1982
+ ready: false
1983
+ },
1984
+ hide: {
1985
+ when: {
1986
+ target: false,
1987
+ event: 'mouseout'
1988
+ },
1989
+ effect: {
1990
+ type: 'fade',
1991
+ length: 100
1992
+ },
1993
+ delay: 0,
1994
+ fixed: false
1995
+ },
1996
+ // Callbacks
1997
+ api: {
1998
+ beforeRender: function(){},
1999
+ onRender: function(){},
2000
+ beforePositionUpdate: function(){},
2001
+ onPositionUpdate: function(){},
2002
+ beforeShow: function(){},
2003
+ onShow: function(){},
2004
+ beforeHide: function(){},
2005
+ onHide: function(){},
2006
+ beforeContentUpdate: function(){},
2007
+ onContentUpdate: function(){},
2008
+ beforeContentLoad: function(){},
2009
+ onContentLoad: function(){},
2010
+ beforeTitleUpdate: function(){},
2011
+ onTitleUpdate: function(){},
2012
+ beforeDestroy: function(){},
2013
+ onDestroy: function(){},
2014
+ beforeFocus: function(){},
2015
+ onFocus: function(){}
2016
+ }
2017
+ };
2018
+
2019
+ $.fn.qtip.styles = {
2020
+ defaults: {
2021
+ background: 'white',
2022
+ color: '#111',
2023
+ overflow: 'hidden',
2024
+ textAlign: 'left',
2025
+ width: {
2026
+ min: 0,
2027
+ max: 250
2028
+ },
2029
+ padding: '5px 9px',
2030
+ border: {
2031
+ width: 1,
2032
+ radius: 0,
2033
+ color: '#d3d3d3'
2034
+ },
2035
+ tip: {
2036
+ corner: false,
2037
+ color: false,
2038
+ size: { width: 13, height: 13 },
2039
+ opacity: 1
2040
+ },
2041
+ title: {
2042
+ background: '#e1e1e1',
2043
+ fontWeight: 'bold',
2044
+ padding: '7px 12px'
2045
+ },
2046
+ button: {
2047
+ cursor: 'pointer'
2048
+ },
2049
+ classes: {
2050
+ target: '',
2051
+ tip: 'qtip-tip',
2052
+ title: 'qtip-title',
2053
+ button: 'qtip-button',
2054
+ content: 'qtip-content',
2055
+ active: 'qtip-active'
2056
+ }
2057
+ },
2058
+ cream: {
2059
+ border: {
2060
+ width: 3,
2061
+ radius: 0,
2062
+ color: '#F9E98E'
2063
+ },
2064
+ title: {
2065
+ background: '#F0DE7D',
2066
+ color: '#A27D35'
2067
+ },
2068
+ background: '#FBF7AA',
2069
+ color: '#A27D35',
2070
+
2071
+ classes: { tooltip: 'qtip-cream' }
2072
+ },
2073
+ light: {
2074
+ border: {
2075
+ width: 3,
2076
+ radius: 0,
2077
+ color: '#E2E2E2'
2078
+ },
2079
+ title: {
2080
+ background: '#f1f1f1',
2081
+ color: '#454545'
2082
+ },
2083
+ background: 'white',
2084
+ color: '#454545',
2085
+
2086
+ classes: { tooltip: 'qtip-light' }
2087
+ },
2088
+ dark: {
2089
+ border: {
2090
+ width: 3,
2091
+ radius: 0,
2092
+ color: '#303030'
2093
+ },
2094
+ title: {
2095
+ background: '#404040',
2096
+ color: '#f3f3f3'
2097
+ },
2098
+ background: '#505050',
2099
+ color: '#f3f3f3',
2100
+
2101
+ classes: { tooltip: 'qtip-dark' }
2102
+ },
2103
+ red: {
2104
+ border: {
2105
+ width: 3,
2106
+ radius: 0,
2107
+ color: '#CE6F6F'
2108
+ },
2109
+ title: {
2110
+ background: '#f28279',
2111
+ color: '#9C2F2F'
2112
+ },
2113
+ background: '#F79992',
2114
+ color: '#9C2F2F',
2115
+
2116
+ classes: { tooltip: 'qtip-red' }
2117
+ },
2118
+ green: {
2119
+ border: {
2120
+ width: 3,
2121
+ radius: 0,
2122
+ color: '#A9DB66'
2123
+ },
2124
+ title: {
2125
+ background: '#b9db8c',
2126
+ color: '#58792E'
2127
+ },
2128
+ background: '#CDE6AC',
2129
+ color: '#58792E',
2130
+
2131
+ classes: { tooltip: 'qtip-green' }
2132
+ },
2133
+ blue: {
2134
+ border: {
2135
+ width: 3,
2136
+ radius: 0,
2137
+ color: '#ADD9ED'
2138
+ },
2139
+ title: {
2140
+ background: '#D0E9F5',
2141
+ color: '#5E99BD'
2142
+ },
2143
+ background: '#E5F6FE',
2144
+ color: '#4D9FBF',
2145
+
2146
+ classes: { tooltip: 'qtip-blue' }
2147
+ }
2148
+ };
2149
+ })(jQuery);
2150
+
2151
+
2152
+
2153
+
2154
+
2155
+