jquery-qtip2-rails 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/README.md +16 -13
  2. data/jquery-qtip2-rails.gemspec +7 -4
  3. data/lib/jquery-qtip2-rails/version.rb +1 -1
  4. data/test/dummy/README.rdoc +261 -0
  5. data/test/dummy/Rakefile +7 -0
  6. data/test/dummy/app/assets/javascripts/application.js +16 -0
  7. data/test/dummy/app/assets/javascripts/home.js +48 -0
  8. data/test/dummy/app/assets/stylesheets/application.css +14 -0
  9. data/test/dummy/app/assets/stylesheets/home.css +4 -0
  10. data/test/dummy/app/controllers/application_controller.rb +3 -0
  11. data/test/dummy/app/controllers/home_controller.rb +5 -0
  12. data/test/dummy/app/helpers/application_helper.rb +2 -0
  13. data/test/dummy/app/helpers/home_helper.rb +2 -0
  14. data/test/dummy/app/mailers/.gitkeep +0 -0
  15. data/test/dummy/app/models/.gitkeep +0 -0
  16. data/test/dummy/app/views/home/index.html.erb +14 -0
  17. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  18. data/test/dummy/config.ru +4 -0
  19. data/test/dummy/config/application.rb +68 -0
  20. data/test/dummy/config/boot.rb +10 -0
  21. data/test/dummy/config/environment.rb +5 -0
  22. data/test/dummy/config/environments/development.rb +31 -0
  23. data/test/dummy/config/environments/production.rb +64 -0
  24. data/test/dummy/config/environments/test.rb +35 -0
  25. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  26. data/test/dummy/config/initializers/inflections.rb +15 -0
  27. data/test/dummy/config/initializers/mime_types.rb +5 -0
  28. data/test/dummy/config/initializers/secret_token.rb +7 -0
  29. data/test/dummy/config/initializers/session_store.rb +8 -0
  30. data/test/dummy/config/initializers/wrap_parameters.rb +10 -0
  31. data/test/dummy/config/locales/en.yml +5 -0
  32. data/test/dummy/config/routes.rb +3 -0
  33. data/test/dummy/lib/assets/.gitkeep +0 -0
  34. data/test/dummy/log/.gitkeep +0 -0
  35. data/test/dummy/public/404.html +26 -0
  36. data/test/dummy/public/422.html +26 -0
  37. data/test/dummy/public/500.html +25 -0
  38. data/test/dummy/public/favicon.ico +0 -0
  39. data/test/dummy/script/rails +6 -0
  40. data/vendor/assets/jquery-qtip/jquery-qtip/src/ajax/ajax.js +3 -2
  41. data/vendor/assets/jquery-qtip/jquery-qtip/src/{styles.css → basic.css} +0 -0
  42. data/vendor/assets/jquery-qtip/jquery-qtip/src/core.css +27 -22
  43. data/vendor/assets/jquery-qtip/jquery-qtip/src/core.js +162 -315
  44. data/vendor/assets/jquery-qtip/jquery-qtip/src/{extra.css → css3.css} +70 -30
  45. data/vendor/assets/jquery-qtip/jquery-qtip/src/imagemap/imagemap.js +59 -45
  46. data/vendor/assets/jquery-qtip/jquery-qtip/src/intro.js +31 -29
  47. data/vendor/assets/jquery-qtip/jquery-qtip/src/modal/modal.js +7 -5
  48. data/vendor/assets/jquery-qtip/jquery-qtip/src/outro.js +2 -2
  49. data/vendor/assets/jquery-qtip/jquery-qtip/src/svg/svg.js +8 -8
  50. data/vendor/assets/jquery-qtip/jquery-qtip/src/tips/tips.css +7 -3
  51. data/vendor/assets/jquery-qtip/jquery-qtip/src/tips/tips.js +159 -147
  52. data/vendor/assets/jquery-qtip/jquery-qtip/src/viewport/viewport.js +112 -0
  53. data/vendor/assets/jquery-qtip/jquery.qtip.basic.css +5 -0
  54. data/vendor/assets/jquery-qtip/jquery.qtip.basic.js +0 -1
  55. data/vendor/assets/jquery-qtip/jquery.qtip.css +3 -4
  56. data/vendor/assets/jquery-qtip/jquery.qtip.js +5 -5
  57. metadata +103 -8
  58. data/vendor/assets/jquery-qtip/jquery-qtip/src/header.txt +0 -14
File without changes
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -40,7 +40,7 @@ function Ajax(api)
40
40
  load: function(event) {
41
41
  if(stop) {stop = FALSE; return; }
42
42
 
43
- var hasSelector = opts.url.indexOf(' '),
43
+ var hasSelector = opts.url.lastIndexOf(' '),
44
44
  url = opts.url,
45
45
  selector,
46
46
  hideFirst = !opts.loading && first;
@@ -86,7 +86,8 @@ function Ajax(api)
86
86
  // Don't proceed if tooltip is destroyed
87
87
  if(api.destroyed) { return; }
88
88
 
89
- if(selector) {
89
+ // If URL contains a selector
90
+ if(selector && 'string' === typeof content) {
90
91
  // Create a dummy div to hold the results and grab the selector element
91
92
  content = $('<div/>')
92
93
  // inject the contents of the document in, removing the scripts
@@ -1,3 +1,20 @@
1
+ /* Fluid class for determining actual width in IE */
2
+ #qtip-rcontainer{
3
+ position: absolute;
4
+ left: -28000px;
5
+ top: -28000px;
6
+ display: block;
7
+ visibility: hidden;
8
+ }
9
+
10
+ /* Fluid class for determining actual width in IE */
11
+ #qtip-rcontainer .ui-tooltip{
12
+ display: block !important;
13
+ visibility: hidden !important;
14
+ position: static !important;
15
+ float: left !important;
16
+ }
17
+
1
18
  /* Core qTip styles */
2
19
  .ui-tooltip, .qtip{
3
20
  position: absolute;
@@ -10,19 +27,8 @@
10
27
 
11
28
  font-size: 10.5px;
12
29
  line-height: 12px;
13
-
14
- border-width: 1px;
15
- border-style: solid;
16
30
  }
17
31
 
18
- /* Fluid class for determining actual width in IE */
19
- .ui-tooltip-fluid{
20
- display: block;
21
- visibility: hidden;
22
- position: static !important;
23
- float: left !important;
24
- }
25
-
26
32
  .ui-tooltip-content{
27
33
  position: relative;
28
34
  padding: 5px 9px;
@@ -30,7 +36,6 @@
30
36
 
31
37
  text-align: left;
32
38
  word-wrap: break-word;
33
- overflow: hidden;
34
39
  }
35
40
 
36
41
  .ui-tooltip-titlebar{
@@ -43,9 +48,9 @@
43
48
  font-weight: bold;
44
49
  }
45
50
 
46
- .ui-tooltip-titlebar + .ui-tooltip-content{ border-top-width: 0px !important; }
51
+ .ui-tooltip-titlebar + .ui-tooltip-content{ border-top-width: 0 !important; }
47
52
 
48
- /*! Default close button class */
53
+ /* Default close button class */
49
54
  .ui-tooltip-titlebar .ui-state-default{
50
55
  position: absolute;
51
56
  right: 4px;
@@ -65,12 +70,14 @@
65
70
  .ui-tooltip-icon .ui-icon{
66
71
  display: block;
67
72
  text-indent: -1000em;
73
+ direction: ltr;
68
74
  }
69
75
 
70
76
  .ui-tooltip-icon, .ui-tooltip-icon .ui-icon{
71
77
  -moz-border-radius: 3px;
72
78
  -webkit-border-radius: 3px;
73
79
  border-radius: 3px;
80
+ text-decoration: none;
74
81
  }
75
82
 
76
83
  .ui-tooltip-icon .ui-icon{
@@ -87,19 +94,17 @@
87
94
 
88
95
 
89
96
  /* Applied to 'focused' tooltips e.g. most recently displayed/interacted with */
90
- .ui-tooltip-focus{
91
-
92
- }
97
+ .ui-tooltip-focus{}
93
98
 
94
99
  /* Applied on hover of tooltips i.e. added/removed on mouseenter/mouseleave respectively */
95
- .ui-tooltip-hover{
96
-
97
- }
98
-
100
+ .ui-tooltip-hover{}
99
101
 
100
- /*! Default tooltip style */
102
+ /* Default tooltip style */
101
103
  .ui-tooltip-default{
104
+ border-width: 1px;
105
+ border-style: solid;
102
106
  border-color: #F1D031;
107
+
103
108
  background-color: #FFFFA3;
104
109
  color: #555;
105
110
  }
@@ -1,79 +1,49 @@
1
1
  // Option object sanitizer
2
2
  function sanitizeOptions(opts)
3
3
  {
4
- var content;
4
+ var invalid = function(a) { return a === NULL || 'object' !== typeof a; },
5
+ invalidContent = function(c) { return !$.isFunction(c) && ((!c && !c.attr) || c.length < 1 || ('object' === typeof c && !c.jquery)); };
5
6
 
6
7
  if(!opts || 'object' !== typeof opts) { return FALSE; }
7
8
 
8
- if(opts.metadata === NULL || 'object' !== typeof opts.metadata) {
9
- opts.metadata = {
10
- type: opts.metadata
11
- };
9
+ if(invalid(opts.metadata)) {
10
+ opts.metadata = { type: opts.metadata };
12
11
  }
13
12
 
14
13
  if('content' in opts) {
15
- if(opts.content === NULL || 'object' !== typeof opts.content || opts.content.jquery) {
16
- opts.content = {
17
- text: opts.content
18
- };
14
+ if(invalid(opts.content) || opts.content.jquery) {
15
+ opts.content = { text: opts.content };
19
16
  }
20
17
 
21
- content = opts.content.text || FALSE;
22
- if(!$.isFunction(content) && ((!content && !content.attr) || content.length < 1 || ('object' === typeof content && !content.jquery))) {
18
+ if(invalidContent(opts.content.text || FALSE)) {
23
19
  opts.content.text = FALSE;
24
20
  }
25
21
 
26
22
  if('title' in opts.content) {
27
- if(opts.content.title === NULL || 'object' !== typeof opts.content.title) {
28
- opts.content.title = {
29
- text: opts.content.title
30
- };
23
+ if(invalid(opts.content.title)) {
24
+ opts.content.title = { text: opts.content.title };
31
25
  }
32
26
 
33
- content = opts.content.title.text || FALSE;
34
- if(!$.isFunction(content) && ((!content && !content.attr) || content.length < 1 || ('object' === typeof content && !content.jquery))) {
27
+ if(invalidContent(opts.content.title.text || FALSE)) {
35
28
  opts.content.title.text = FALSE;
36
29
  }
37
30
  }
38
31
  }
39
32
 
40
- if('position' in opts) {
41
- if(opts.position === NULL || 'object' !== typeof opts.position) {
42
- opts.position = {
43
- my: opts.position,
44
- at: opts.position
45
- };
46
- }
33
+ if('position' in opts && invalid(opts.position)) {
34
+ opts.position = { my: opts.position, at: opts.position };
47
35
  }
48
36
 
49
- if('show' in opts) {
50
- if(opts.show === NULL || 'object' !== typeof opts.show) {
51
- if(opts.show.jquery) {
52
- opts.show = { target: opts.show };
53
- }
54
- else {
55
- opts.show = { event: opts.show };
56
- }
57
- }
37
+ if('show' in opts && invalid(opts.show)) {
38
+ opts.show = opts.show.jquery ? { target: opts.show } : { event: opts.show };
58
39
  }
59
40
 
60
- if('hide' in opts) {
61
- if(opts.hide === NULL || 'object' !== typeof opts.hide) {
62
- if(opts.hide.jquery) {
63
- opts.hide = { target: opts.hide };
64
- }
65
- else {
66
- opts.hide = { event: opts.hide };
67
- }
68
- }
41
+ if('hide' in opts && invalid(opts.hide)) {
42
+ opts.hide = opts.hide.jquery ? { target: opts.hide } : { event: opts.hide };
69
43
  }
70
44
 
71
- if('style' in opts) {
72
- if(opts.style === NULL || 'object' !== typeof opts.style) {
73
- opts.style = {
74
- classes: opts.style
75
- };
76
- }
45
+ if('style' in opts && invalid(opts.style)) {
46
+ opts.style = { classes: opts.style };
77
47
  }
78
48
 
79
49
  // Sanitize plugin options
@@ -113,7 +83,8 @@ function QTip(target, options, id, attr)
113
83
  target: $(),
114
84
  disabled: FALSE,
115
85
  attr: attr,
116
- onTarget: FALSE
86
+ onTarget: FALSE,
87
+ lastClass: ''
117
88
  };
118
89
 
119
90
  /*
@@ -134,16 +105,28 @@ function QTip(target, options, id, attr)
134
105
  return [obj || options, levels.pop()];
135
106
  }
136
107
 
137
- function setWidget() {
108
+ function triggerEvent(type, args, event) {
109
+ var callback = $.Event('tooltip'+type);
110
+ callback.originalEvent = (event ? $.extend({}, event) : NULL) || cache.event || NULL;
111
+ tooltip.trigger(callback, [self].concat(args || []));
112
+
113
+ return !callback.isDefaultPrevented();
114
+ }
115
+
116
+ function setWidget()
117
+ {
138
118
  var on = options.style.widget;
139
119
 
140
- tooltip.toggleClass(widget, on).toggleClass(defaultClass, options.style.def && !on);
141
- elements.content.toggleClass(widget+'-content', on);
120
+ tooltip.toggleClass('ui-helper-reset '+widget, on).toggleClass(defaultClass, options.style.def && !on);
142
121
 
143
- if(elements.titlebar){
122
+ if(elements.content) {
123
+ elements.content.toggleClass(widget+'-content', on);
124
+ }
125
+
126
+ if(elements.titlebar) {
144
127
  elements.titlebar.toggleClass(widget+'-header', on);
145
128
  }
146
- if(elements.button){
129
+ if(elements.button) {
147
130
  elements.button.toggleClass(uitooltip+'-icon', !on);
148
131
  }
149
132
  }
@@ -355,10 +338,10 @@ function QTip(target, options, id, attr)
355
338
  }
356
339
 
357
340
  /*
358
- * If we're still rendering... insert into 'fx' queue our image dimension
359
- * checker which will halt the showing of the tooltip until image dimensions
360
- * can be detected properly.
361
- */
341
+ * If we're still rendering... insert into 'fx' queue our image dimension
342
+ * checker which will halt the showing of the tooltip until image dimensions
343
+ * can be detected properly.
344
+ */
362
345
  if(self.rendered < 0) { tooltip.queue('fx', detectImages); }
363
346
 
364
347
  // We're fully rendered, so reset isDrawing flag and proceed without queue delay
@@ -452,6 +435,16 @@ function QTip(target, options, id, attr)
452
435
  tooltip.toggleClass(hoverClass, state);
453
436
  });
454
437
 
438
+ // If using mouseout/mouseleave as a hide event...
439
+ if(/mouse(out|leave)/i.test(options.hide.event)) {
440
+ // Hide tooltips when leaving current window/frame (but not select/option elements)
441
+ if(options.hide.leave === 'window') {
442
+ targets.window.bind('mouseout'+namespace+' blur'+namespace, function(event) {
443
+ if(!/select|option/.test(event.target.nodeName) && !event.relatedTarget) { self.hide(event); }
444
+ });
445
+ }
446
+ }
447
+
455
448
  // Enable hide.fixed
456
449
  if(options.hide.fixed) {
457
450
  // Add tooltip as a hide target
@@ -463,20 +456,10 @@ function QTip(target, options, id, attr)
463
456
  });
464
457
  }
465
458
 
466
- // If using mouseout/mouseleave as a hide event...
467
- if(/mouse(out|leave)/i.test(options.hide.event)) {
468
- // Hide tooltips when leaving current window/frame (but not select/option elements)
469
- if(options.hide.leave === 'window') {
470
- targets.window.bind('mouseout'+namespace+' blur'+namespace, function(event) {
471
- if(/select|option/.test(event.target) && !event.relatedTarget) { self.hide(event); }
472
- });
473
- }
474
- }
475
-
476
459
  /*
477
- * Make sure hoverIntent functions properly by using mouseleave to clear show timer if
478
- * mouseenter/mouseout is used for show.event, even if it isn't in the users options.
479
- */
460
+ * Make sure hoverIntent functions properly by using mouseleave to clear show timer if
461
+ * mouseenter/mouseout is used for show.event, even if it isn't in the users options.
462
+ */
480
463
  else if(/mouse(over|enter)/i.test(options.show.event)) {
481
464
  targets.hide.bind('mouseleave'+namespace, function(event) {
482
465
  clearTimeout(self.timers.show);
@@ -601,6 +584,7 @@ function QTip(target, options, id, attr)
601
584
  self.rendered && elements.tooltip[0],
602
585
  options.position.container[0],
603
586
  options.position.viewport[0],
587
+ options.position.container.closest('html')[0], // unfocus
604
588
  window,
605
589
  document
606
590
  ];
@@ -659,7 +643,7 @@ function QTip(target, options, id, attr)
659
643
 
660
644
  // Style checks
661
645
  '^style.classes$': function(obj, o, v) {
662
- tooltip.attr('class', uitooltip + ' qtip ui-helper-reset ' + v);
646
+ tooltip.attr('class', uitooltip + ' qtip ' + v);
663
647
  },
664
648
  '^style.widget|content.title': setWidget,
665
649
 
@@ -690,8 +674,7 @@ function QTip(target, options, id, attr)
690
674
 
691
675
  var text = options.content.text,
692
676
  title = options.content.title.text,
693
- posOptions = options.position,
694
- callback = $.Event('tooltiprender');
677
+ posOptions = options.position;
695
678
 
696
679
  // Add ARIA attributes to target
697
680
  $.attr(target[0], 'aria-describedby', tooltipID);
@@ -699,7 +682,7 @@ function QTip(target, options, id, attr)
699
682
  // Create tooltip element
700
683
  tooltip = elements.tooltip = $('<div/>', {
701
684
  'id': tooltipID,
702
- 'class': uitooltip + ' qtip ui-helper-reset ' + defaultClass + ' ' + options.style.classes + ' '+ uitooltip + '-pos-' + options.position.my.abbrev(),
685
+ 'class': uitooltip + ' qtip ' + defaultClass + ' ' + options.style.classes + ' '+ uitooltip + '-pos-' + options.position.my.abbrev(),
703
686
  'width': options.style.width || '',
704
687
  'height': options.style.height || '',
705
688
  'tracking': posOptions.target === 'mouse' && posOptions.adjust.mouse,
@@ -758,14 +741,13 @@ function QTip(target, options, id, attr)
758
741
  assignEvents();
759
742
 
760
743
  /* Queue this part of the render process in our fx queue so we can
761
- * load images before the tooltip renders fully.
762
- *
763
- * See: updateContent method
744
+ * load images before the tooltip renders fully.
745
+ *
746
+ * See: updateContent method
764
747
  */
765
748
  tooltip.queue('fx', function(next) {
766
- // Trigger tooltiprender event and pass original triggering event as original
767
- callback.originalEvent = cache.event;
768
- tooltip.trigger(callback, [self]);
749
+ // tooltiprender event
750
+ triggerEvent('render');
769
751
 
770
752
  // Reset flags
771
753
  isDrawing = 0; isPositioning = 0;
@@ -858,10 +840,10 @@ function QTip(target, options, id, attr)
858
840
  sanitizeOptions(options);
859
841
 
860
842
  /*
861
- * Execute any valid callbacks for the set options
862
- * Also set isPositioning/isDrawing so we don't get loads of redundant repositioning
863
- * and redraw calls.
864
- */
843
+ * Execute any valid callbacks for the set options
844
+ * Also set isPositioning/isDrawing so we don't get loads of redundant repositioning
845
+ * and redraw calls.
846
+ */
865
847
  isPositioning = isDrawing = 1; $.each(option, callback); isPositioning = isDrawing = 0;
866
848
 
867
849
  // Update position / redraw if needed
@@ -888,7 +870,7 @@ function QTip(target, options, id, attr)
888
870
  visible = tooltip[0].offsetWidth > 0,
889
871
  animate = state || opts.target.length === 1,
890
872
  sameTarget = !event || opts.target.length < 2 || cache.target[0] === event.target,
891
- delay, callback;
873
+ showEvent, delay;
892
874
 
893
875
  // Detect state if valid one isn't provided
894
876
  if((typeof state).search('boolean|number')) { state = !visible; }
@@ -908,11 +890,8 @@ function QTip(target, options, id, attr)
908
890
  cache.event = $.extend({}, event);
909
891
  }
910
892
 
911
- // Call API methods
912
- callback = $.Event('tooltip'+type);
913
- callback.originalEvent = event ? cache.event : NULL;
914
- tooltip.trigger(callback, [self, 90]);
915
- if(callback.isDefaultPrevented()){ return self; }
893
+ // tooltipshow/tooltiphide events
894
+ if(!triggerEvent(type, [90])) { return self; }
916
895
 
917
896
  // Set ARIA hidden status attribute
918
897
  $.attr(tooltip[0], 'aria-hidden', !!!state);
@@ -940,8 +919,10 @@ function QTip(target, options, id, attr)
940
919
  // Update the tooltip position
941
920
  self.reposition(event, arguments[2]);
942
921
 
943
- // Hide other tooltips if tooltip is solo, using it as the context
944
- if((callback.solo = !!opts.solo)) { $(selector, opts.solo).not(tooltip).qtip('hide', callback); }
922
+ // Hide other tooltips if tooltip is solo
923
+ if(!!opts.solo) {
924
+ $(selector, opts.solo).not(tooltip).qtip('hide', $.Event('tooltipsolo'));
925
+ }
945
926
  }
946
927
  else {
947
928
  // Clear show timer if we're hiding
@@ -988,10 +969,8 @@ function QTip(target, options, id, attr)
988
969
  });
989
970
  }
990
971
 
991
- // Call API method
992
- callback = $.Event('tooltip'+(state ? 'visible' : 'hidden'));
993
- callback.originalEvent = event ? cache.event : NULL;
994
- tooltip.trigger(callback, [self]);
972
+ // tooltipvisible/tooltiphidden events
973
+ triggerEvent(state ? 'visible' : 'hidden');
995
974
  }
996
975
 
997
976
  // If no effect type is supplied, use a simple toggle
@@ -1028,18 +1007,13 @@ function QTip(target, options, id, attr)
1028
1007
  curIndex = parseInt(tooltip[0].style.zIndex, 10),
1029
1008
  newIndex = QTIP.zindex + qtips.length,
1030
1009
  cachedEvent = $.extend({}, event),
1031
- focusedElem, callback;
1010
+ focusedElem;
1032
1011
 
1033
1012
  // Only update the z-index if it has changed and tooltip is not already focused
1034
1013
  if(!tooltip.hasClass(focusClass))
1035
1014
  {
1036
- // Call API method
1037
- callback = $.Event('tooltipfocus');
1038
- callback.originalEvent = cachedEvent;
1039
- tooltip.trigger(callback, [self, newIndex]);
1040
-
1041
- // If default action wasn't prevented...
1042
- if(!callback.isDefaultPrevented()) {
1015
+ // tooltipfocus event
1016
+ if(triggerEvent('focus', [newIndex], cachedEvent)) {
1043
1017
  // Only update z-index's if they've changed
1044
1018
  if(curIndex !== newIndex) {
1045
1019
  // Reduce our z-index's and keep them properly ordered
@@ -1062,16 +1036,11 @@ function QTip(target, options, id, attr)
1062
1036
  },
1063
1037
 
1064
1038
  blur: function(event) {
1065
- var cachedEvent = $.extend({}, event),
1066
- callback;
1067
-
1068
1039
  // Set focused status to FALSE
1069
1040
  tooltip.removeClass(focusClass);
1070
1041
 
1071
- // Trigger blur event
1072
- callback = $.Event('tooltipblur');
1073
- callback.originalEvent = cachedEvent;
1074
- tooltip.trigger(callback, [self]);
1042
+ // tooltipblur event
1043
+ triggerEvent('blur', [tooltip.css('zIndex')], event);
1075
1044
 
1076
1045
  return self;
1077
1046
  },
@@ -1093,125 +1062,24 @@ function QTip(target, options, id, attr)
1093
1062
  elemHeight = tooltip.outerHeight(),
1094
1063
  targetWidth = 0,
1095
1064
  targetHeight = 0,
1096
- callback = $.Event('tooltipmove'),
1097
1065
  fixed = tooltip.css('position') === 'fixed',
1098
1066
  viewport = posOptions.viewport,
1099
1067
  position = { left: 0, top: 0 },
1100
1068
  container = posOptions.container,
1101
- flipoffset = FALSE,
1102
- tip = self.plugins.tip,
1103
1069
  visible = tooltip[0].offsetWidth > 0,
1104
- readjust = {
1105
- // Axis detection and readjustment indicator
1106
- horizontal: method[0],
1107
- vertical: (method[1] = method[1] || method[0]),
1108
- enabled: viewport.jquery && target[0] !== window && target[0] !== docBody && adjust.method !== 'none',
1109
-
1110
- // Reposition methods
1111
- left: function(posLeft) {
1112
- var isShift = readjust.horizontal === 'shift',
1113
- adjustx = adjust.x * (readjust.horizontal.substr(-6) === 'invert' ? 2 : 0),
1114
- viewportScroll = -container.offset.left + viewport.offset.left + viewport.scrollLeft,
1115
- myWidth = my.x === 'left' ? elemWidth : my.x === 'right' ? -elemWidth : -elemWidth / 2,
1116
- atWidth = at.x === 'left' ? targetWidth : at.x === 'right' ? -targetWidth : -targetWidth / 2,
1117
- tipWidth = tip && tip.size ? tip.size.width || 0 : 0,
1118
- tipAdjust = tip && tip.corner && tip.corner.precedance === 'x' && !isShift ? tipWidth : 0,
1119
- overflowLeft = viewportScroll - posLeft + tipAdjust,
1120
- overflowRight = posLeft + elemWidth - viewport.width - viewportScroll + tipAdjust,
1121
- offset = myWidth - (my.precedance === 'x' || my.x === my.y ? atWidth : 0) - (at.x === 'center' ? targetWidth / 2 : 0),
1122
- isCenter = my.x === 'center';
1123
-
1124
- // Optional 'shift' style repositioning
1125
- if(isShift) {
1126
- tipAdjust = tip && tip.corner && tip.corner.precedance === 'y' ? tipWidth : 0;
1127
- offset = (my.x === 'left' ? 1 : -1) * myWidth - tipAdjust;
1128
-
1129
- // Adjust position but keep it within viewport dimensions
1130
- position.left += overflowLeft > 0 ? overflowLeft : overflowRight > 0 ? -overflowRight : 0;
1131
- position.left = Math.max(
1132
- -container.offset.left + viewport.offset.left + (tipAdjust && tip.corner.x === 'center' ? tip.offset : 0),
1133
- posLeft - offset,
1134
- Math.min(
1135
- Math.max(-container.offset.left + viewport.offset.left + viewport.width, posLeft + offset),
1136
- position.left
1137
- )
1138
- );
1139
- }
1140
-
1141
- // Default 'flip' repositioning
1142
- else {
1143
- if(overflowLeft > 0 && (my.x !== 'left' || overflowRight > 0)) {
1144
- position.left -= offset + adjustx;
1145
- }
1146
- else if(overflowRight > 0 && (my.x !== 'right' || overflowLeft > 0) ) {
1147
- position.left -= (isCenter ? -offset : offset) + adjustx;
1148
- }
1149
-
1150
- // Make sure we haven't made things worse with the adjustment and return the adjusted difference
1151
- if(position.left < viewportScroll && -position.left > overflowRight) { position.left = posLeft; }
1152
- }
1153
-
1154
- return position.left - posLeft;
1155
- },
1156
- top: function(posTop) {
1157
- var isShift = readjust.vertical === 'shift',
1158
- adjusty = adjust.y * (readjust.vertical.substr(-6) === 'invert' ? 2 : 0),
1159
- viewportScroll = -container.offset.top + viewport.offset.top + viewport.scrollTop,
1160
- myHeight = my.y === 'top' ? elemHeight : my.y === 'bottom' ? -elemHeight : -elemHeight / 2,
1161
- atHeight = at.y === 'top' ? targetHeight : at.y === 'bottom' ? -targetHeight : -targetHeight / 2,
1162
- tipHeight = tip && tip.size ? tip.size.height || 0 : 0,
1163
- tipAdjust = tip && tip.corner && tip.corner.precedance === 'y' && !isShift ? tipHeight : 0,
1164
- overflowTop = viewportScroll - posTop + tipAdjust,
1165
- overflowBottom = posTop + elemHeight - viewport.height - viewportScroll + tipAdjust,
1166
- offset = myHeight - (my.precedance === 'y' || my.x === my.y ? atHeight : 0) - (at.y === 'center' ? targetHeight / 2 : 0),
1167
- isCenter = my.y === 'center';
1168
-
1169
- // Optional 'shift' style repositioning
1170
- if(isShift) {
1171
- tipAdjust = tip && tip.corner && tip.corner.precedance === 'x' ? tipHeight : 0;
1172
- offset = (my.y === 'top' ? 1 : -1) * myHeight - tipAdjust;
1173
-
1174
- // Adjust position but keep it within viewport dimensions
1175
- position.top += overflowTop > 0 ? overflowTop : overflowBottom > 0 ? -overflowBottom : 0;
1176
- position.top = Math.max(
1177
- -container.offset.top + viewport.offset.top + (tipAdjust && tip.corner.x === 'center' ? tip.offset : 0),
1178
- posTop - offset,
1179
- Math.min(
1180
- Math.max(-container.offset.top + viewport.offset.top + viewport.height, posTop + offset),
1181
- position.top
1182
- )
1183
- );
1184
- }
1185
-
1186
- // Default 'flip' repositioning
1187
- else {
1188
- if(overflowTop > 0 && (my.y !== 'top' || overflowBottom > 0)) {
1189
- position.top -= offset + adjusty;
1190
- }
1191
- else if(overflowBottom > 0 && (my.y !== 'bottom' || overflowTop > 0) ) {
1192
- position.top -= (isCenter ? -offset : offset) + adjusty;
1193
- }
1194
-
1195
- // Make sure we haven't made things worse with the adjustment and return the adjusted difference
1196
- if(position.top < 0 && -position.top > overflowBottom) { position.top = posTop; }
1197
- }
1198
-
1199
- return position.top - posTop;
1200
- }
1201
- },
1202
- win;
1070
+ adjusted, offset, win;
1203
1071
 
1204
1072
  // Check if absolute position was passed
1205
1073
  if($.isArray(target) && target.length === 2) {
1206
1074
  // Force left top and set position
1207
- at = { x: 'left', y: 'top' };
1075
+ at = { x: LEFT, y: TOP };
1208
1076
  position = { left: target[0], top: target[1] };
1209
1077
  }
1210
1078
 
1211
1079
  // Check if mouse was the target
1212
1080
  else if(target === 'mouse' && ((event && event.pageX) || cache.event.pageX)) {
1213
1081
  // Force left top to allow flipping
1214
- at = { x: 'left', y: 'top' };
1082
+ at = { x: LEFT, y: TOP };
1215
1083
 
1216
1084
  // Use cached event if one isn't available for positioning
1217
1085
  event = (event && (event.type === 'resize' || event.type === 'scroll') ? cache.event :
@@ -1227,17 +1095,13 @@ function QTip(target, options, id, attr)
1227
1095
  // Target wasn't mouse or absolute...
1228
1096
  else {
1229
1097
  // Check if event targetting is being used
1230
- if(target === 'event') {
1231
- if(event && event.target && event.type !== 'scroll' && event.type !== 'resize') {
1232
- target = cache.target = $(event.target);
1233
- }
1234
- else {
1235
- target = cache.target;
1236
- }
1098
+ if(target === 'event' && event && event.target && event.type !== 'scroll' && event.type !== 'resize') {
1099
+ cache.target = $(event.target);
1237
1100
  }
1238
- else {
1239
- target = cache.target = $(target.jquery ? target : elements.target);
1101
+ else if(target !== 'event'){
1102
+ cache.target = $(target.jquery ? target : elements.target);
1240
1103
  }
1104
+ target = cache.target;
1241
1105
 
1242
1106
  // Parse the target into a jQuery object and make sure there's an element present
1243
1107
  target = $(target).eq(0);
@@ -1257,11 +1121,11 @@ function QTip(target, options, id, attr)
1257
1121
  }
1258
1122
 
1259
1123
  // Use Imagemap/SVG plugins if needed
1260
- else if(target.is('area') && PLUGINS.imagemap) {
1261
- position = PLUGINS.imagemap(target, at, readjust.enabled ? method : FALSE);
1124
+ else if(PLUGINS.imagemap && target.is('area')) {
1125
+ adjusted = PLUGINS.imagemap(self, target, at, PLUGINS.viewport ? method : FALSE);
1262
1126
  }
1263
- else if(target[0].namespaceURI === 'http://www.w3.org/2000/svg' && PLUGINS.svg) {
1264
- position = PLUGINS.svg(target, at);
1127
+ else if(PLUGINS.svg && typeof target[0].xmlbase === 'string') {
1128
+ adjusted = PLUGINS.svg(self, target, at, PLUGINS.viewport ? method : FALSE);
1265
1129
  }
1266
1130
 
1267
1131
  else {
@@ -1272,11 +1136,11 @@ function QTip(target, options, id, attr)
1272
1136
  }
1273
1137
 
1274
1138
  // Parse returned plugin values into proper variables
1275
- if(position.offset) {
1276
- targetWidth = position.width;
1277
- targetHeight = position.height;
1278
- flipoffset = position.flipoffset;
1279
- position = position.offset;
1139
+ if(adjusted) {
1140
+ targetWidth = adjusted.width;
1141
+ targetHeight = adjusted.height;
1142
+ offset = adjusted.offset;
1143
+ position = adjusted.position;
1280
1144
  }
1281
1145
 
1282
1146
  // Adjust for position.fixed tooltips (and also iOS scroll bug in v3.2-4.0 & v4.3-4.3.2)
@@ -1290,55 +1154,30 @@ function QTip(target, options, id, attr)
1290
1154
  }
1291
1155
 
1292
1156
  // Adjust position relative to target
1293
- position.left += at.x === 'right' ? targetWidth : at.x === 'center' ? targetWidth / 2 : 0;
1294
- position.top += at.y === 'bottom' ? targetHeight : at.y === 'center' ? targetHeight / 2 : 0;
1157
+ position.left += at.x === RIGHT ? targetWidth : at.x === CENTER ? targetWidth / 2 : 0;
1158
+ position.top += at.y === BOTTOM ? targetHeight : at.y === CENTER ? targetHeight / 2 : 0;
1295
1159
  }
1296
1160
 
1297
1161
  // Adjust position relative to tooltip
1298
- position.left += adjust.x + (my.x === 'right' ? -elemWidth : my.x === 'center' ? -elemWidth / 2 : 0);
1299
- position.top += adjust.y + (my.y === 'bottom' ? -elemHeight : my.y === 'center' ? -elemHeight / 2 : 0);
1300
-
1301
- // Calculate collision offset values if viewport positioning is enabled
1302
- if(readjust.enabled) {
1303
- // Cache our viewport details
1304
- viewport = {
1305
- elem: viewport,
1306
- height: viewport[ (viewport[0] === window ? 'h' : 'outerH') + 'eight' ](),
1307
- width: viewport[ (viewport[0] === window ? 'w' : 'outerW') + 'idth' ](),
1308
- scrollLeft: fixed ? 0 : viewport.scrollLeft(),
1309
- scrollTop: fixed ? 0 : viewport.scrollTop(),
1310
- offset: viewport.offset() || { left: 0, top: 0 }
1311
- };
1312
- container = {
1313
- elem: container,
1314
- scrollLeft: container.scrollLeft(),
1315
- scrollTop: container.scrollTop(),
1316
- offset: container.offset() || { left: 0, top: 0 }
1317
- };
1318
-
1319
- // Adjust position based onviewport and adjustment options
1320
- position.adjusted = {
1321
- left: readjust.horizontal !== 'none' ? readjust.left(position.left) : 0,
1322
- top: readjust.vertical !== 'none' ? readjust.top(position.top) : 0
1323
- };
1324
-
1325
- // Set tooltip position class
1326
- if(position.adjusted.left + position.adjusted.top) {
1327
- tooltip.attr('class', tooltip[0].className.replace(/ui-tooltip-pos-\w+/i, uitooltip + '-pos-' + my.abbrev()));
1328
- }
1162
+ position.left += adjust.x + (my.x === RIGHT ? -elemWidth : my.x === CENTER ? -elemWidth / 2 : 0);
1163
+ position.top += adjust.y + (my.y === BOTTOM ? -elemHeight : my.y === CENTER ? -elemHeight / 2 : 0);
1164
+
1165
+ // Use viewport adjustment plugin if enabled
1166
+ if(PLUGINS.viewport) {
1167
+ position.adjusted = PLUGINS.viewport(
1168
+ self, position, posOptions, targetWidth, targetHeight, elemWidth, elemHeight
1169
+ );
1329
1170
 
1330
- // Apply flip offsets supplied by positioning plugins
1331
- if(flipoffset && position.adjusted.left) { position.left += flipoffset.left; }
1332
- if(flipoffset && position.adjusted.top) { position.top += flipoffset.top; }
1171
+ // Apply offsets supplied by positioning plugin (if used)
1172
+ if(offset && position.adjusted.left) { position.left += offset.left; }
1173
+ if(offset && position.adjusted.top) { position.top += offset.top; }
1333
1174
  }
1334
1175
 
1335
- //Viewport adjustment is disabled, set values to zero
1176
+ // Viewport adjustment is disabled, set values to zero
1336
1177
  else { position.adjusted = { left: 0, top: 0 }; }
1337
1178
 
1338
- // Call API method
1339
- callback.originalEvent = $.extend({}, event);
1340
- tooltip.trigger(callback, [self, position, viewport.elem || viewport]);
1341
- if(callback.isDefaultPrevented()){ return self; }
1179
+ // tooltipmove event
1180
+ if(!triggerEvent('move', [position, viewport.elem || viewport], event)) { return self; }
1342
1181
  delete position.adjusted;
1343
1182
 
1344
1183
  // If effect is disabled, target it mouse, no animation is defined or positioning gives NaN out, set CSS directly
@@ -1369,25 +1208,28 @@ function QTip(target, options, id, attr)
1369
1208
  {
1370
1209
  if(self.rendered < 1 || isDrawing) { return self; }
1371
1210
 
1372
- var container = options.position.container,
1211
+ var style = options.style,
1212
+ container = options.position.container,
1373
1213
  perc, width, max, min;
1374
1214
 
1375
1215
  // Set drawing flag
1376
1216
  isDrawing = 1;
1377
1217
 
1378
- // If tooltip has a set height, just set it... like a boss!
1379
- if(options.style.height) { tooltip.css('height', options.style.height); }
1218
+ // tooltipredraw event
1219
+ triggerEvent('redraw');
1380
1220
 
1381
- // If tooltip has a set width, just set it... like a boss!
1382
- if(options.style.width) { tooltip.css('width', options.style.width); }
1221
+ // If tooltip has a set height/width, just set it... like a boss!
1222
+ if(style.height) { tooltip.css(HEIGHT, style.height); }
1223
+ if(style.width) { tooltip.css(WIDTH, style.width); }
1383
1224
 
1384
- // Otherwise simualte max/min width...
1225
+ // Simulate max/min width if not set width present...
1385
1226
  else {
1386
1227
  // Reset width and add fluid class
1387
- tooltip.css('width', '').addClass(fluidClass);
1228
+ tooltip.css(WIDTH, '').appendTo(redrawContainer);
1388
1229
 
1389
- // Grab our tooltip width (add 1 so we don't get wrapping problems.. huzzah!)
1390
- width = tooltip.width() + 1;
1230
+ // Grab our tooltip width (add 1 if odd so we don't get wrapping problems.. huzzah!)
1231
+ width = tooltip.width();
1232
+ if(width % 2 < 1) { width += 1; }
1391
1233
 
1392
1234
  // Grab our max/min properties
1393
1235
  max = tooltip.css('max-width') || '';
@@ -1402,9 +1244,12 @@ function QTip(target, options, id, attr)
1402
1244
  width = max + min ? Math.min(Math.max(width, min), max) : width;
1403
1245
 
1404
1246
  // Set the newly calculated width and remvoe fluid class
1405
- tooltip.css('width', Math.round(width)).removeClass(fluidClass);
1247
+ tooltip.css(WIDTH, Math.round(width)).appendTo(container);
1406
1248
  }
1407
1249
 
1250
+ // tooltipredrawn event
1251
+ triggerEvent('redrawn');
1252
+
1408
1253
  // Set drawing flag
1409
1254
  isDrawing = 0;
1410
1255
 
@@ -1501,8 +1346,7 @@ function init(id, opts)
1501
1346
  html5 = elem.data(opts.metadata.name || 'qtipopts');
1502
1347
 
1503
1348
  // If we don't get an object returned attempt to parse it manualyl without parseJSON
1504
- try { html5 = typeof html5 === 'string' ? (new Function("return " + html5))() : html5; }
1505
- catch(e) { log('Unable to parse HTML5 attribute data: ' + html5); }
1349
+ try { html5 = typeof html5 === 'string' ? $.parseJSON(html5) : html5; } catch(e) {}
1506
1350
 
1507
1351
  // Merge in and sanitize metadata
1508
1352
  config = $.extend(TRUE, {}, QTIP.defaults, opts,
@@ -1521,10 +1365,7 @@ function init(id, opts)
1521
1365
  if(config.content.attr !== FALSE && attr) { config.content.text = attr; }
1522
1366
 
1523
1367
  // No valid content was found, abort render
1524
- else {
1525
- log('Unable to locate content for tooltip! Aborting render of tooltip on element: ', elem);
1526
- return FALSE;
1527
- }
1368
+ else { return FALSE; }
1528
1369
  }
1529
1370
 
1530
1371
  // Setup target options
@@ -1654,19 +1495,19 @@ QTIP.bind = function(opts, event)
1654
1495
  };
1655
1496
 
1656
1497
  /*
1657
- * Make sure hoverIntent functions properly by using mouseleave as a hide event if
1658
- * mouseenter/mouseout is used for show.event, even if it isn't in the users options.
1659
- */
1498
+ * Make sure hoverIntent functions properly by using mouseleave as a hide event if
1499
+ * mouseenter/mouseout is used for show.event, even if it isn't in the users options.
1500
+ */
1660
1501
  if(/mouse(over|enter)/i.test(events.show) && !/mouse(out|leave)/i.test(events.hide)) {
1661
1502
  events.hide += ' mouseleave' + namespace;
1662
1503
  }
1663
1504
 
1664
1505
  /*
1665
- * Also make sure initial mouse targetting works correctly by caching mousemove coords
1666
- * on show targets before the tooltip has rendered.
1667
- *
1668
- * Also set onTarget when triggered to keep mouse tracking working
1669
- */
1506
+ * Also make sure initial mouse targetting works correctly by caching mousemove coords
1507
+ * on show targets before the tooltip has rendered.
1508
+ *
1509
+ * Also set onTarget when triggered to keep mouse tracking working
1510
+ */
1670
1511
  targets.show.bind('mousemove'+namespace, function(event) {
1671
1512
  MOUSE = { pageX: event.pageX, pageY: event.pageY, type: 'mousemove' };
1672
1513
  api.cache.onTarget = TRUE;
@@ -1712,20 +1553,27 @@ QTIP.bind = function(opts, event)
1712
1553
  PLUGINS = QTIP.plugins = {
1713
1554
  // Corner object parser
1714
1555
  Corner: function(corner) {
1715
- corner = ('' + corner).replace(/([A-Z])/, ' $1').replace(/middle/gi, 'center').toLowerCase();
1556
+ corner = ('' + corner).replace(/([A-Z])/, ' $1').replace(/middle/gi, CENTER).toLowerCase();
1716
1557
  this.x = (corner.match(/left|right/i) || corner.match(/center/) || ['inherit'])[0].toLowerCase();
1717
1558
  this.y = (corner.match(/top|bottom|center/i) || ['inherit'])[0].toLowerCase();
1718
1559
 
1719
- var f = corner.charAt(0); this.precedance = (f === 't' || f === 'b' ? 'y' : 'x');
1560
+ var f = corner.charAt(0); this.precedance = (f === 't' || f === 'b' ? Y : X);
1720
1561
 
1721
- this.string = function() { return this.precedance === 'y' ? this.y+this.x : this.x+this.y; };
1562
+ this.string = function() { return this.precedance === Y ? this.y+this.x : this.x+this.y; };
1722
1563
  this.abbrev = function() {
1723
1564
  var x = this.x.substr(0,1), y = this.y.substr(0,1);
1724
- return x === y ? x : (x === 'c' || (x !== 'c' && y !== 'c')) ? y + x : x + y;
1565
+ return x === y ? x : this.precedance === Y ? y + x : x + y;
1725
1566
  };
1726
1567
 
1568
+ this.invertx = function(center) { this.x = this.x === LEFT ? RIGHT : this.x === RIGHT ? LEFT : center || this.x; };
1569
+ this.inverty = function(center) { this.y = this.y === TOP ? BOTTOM : this.y === BOTTOM ? TOP : center || this.y; };
1570
+
1727
1571
  this.clone = function() {
1728
- return { x: this.x, y: this.y, precedance: this.precedance, string: this.string, abbrev: this.abbrev, clone: this.clone };
1572
+ return {
1573
+ x: this.x, y: this.y, precedance: this.precedance,
1574
+ string: this.string, abbrev: this.abbrev, clone: this.clone,
1575
+ invertx: this.invertx, inverty: this.inverty
1576
+ };
1729
1577
  };
1730
1578
  },
1731
1579
 
@@ -1765,16 +1613,16 @@ PLUGINS = QTIP.plugins = {
1765
1613
  },
1766
1614
 
1767
1615
  /*
1768
- * iOS 3.2 - 4.0 scroll fix detection used in offset() function.
1769
- */
1616
+ * iOS version detection
1617
+ */
1770
1618
  iOS: parseFloat(
1771
1619
  ('' + (/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0,''])[1])
1772
1620
  .replace('undefined', '3_2').replace('_', '.').replace('_', '')
1773
1621
  ) || FALSE,
1774
1622
 
1775
1623
  /*
1776
- * jQuery-specific $.fn overrides
1777
- */
1624
+ * jQuery-specific $.fn overrides
1625
+ */
1778
1626
  fn: {
1779
1627
  /* Allow other plugins to successfully retrieve the title of an element with a qTip applied */
1780
1628
  attr: function(attr, val) {
@@ -1787,15 +1635,14 @@ PLUGINS = QTIP.plugins = {
1787
1635
  if(arguments.length < 2) {
1788
1636
  return $.attr(self, oldtitle);
1789
1637
  }
1790
- else {
1791
- // If qTip is rendered and title was originally used as content, update it
1792
- if(api && api.options.content.attr === title && api.cache.attr) {
1793
- api.set('content.text', val);
1794
- }
1795
1638
 
1796
- // Use the regular attr method to set, then cache the result
1797
- return this.attr(oldtitle, val);
1639
+ // If qTip is rendered and title was originally used as content, update it
1640
+ if(api && api.options.content.attr === title && api.cache.attr) {
1641
+ api.set('content.text', val);
1798
1642
  }
1643
+
1644
+ // Use the regular attr method to set, then cache the result
1645
+ return this.attr(oldtitle, val);
1799
1646
  }
1800
1647
  }
1801
1648