jquery-qtip2-rails 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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