inline_forms 2.23 → 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.
- checksums.yaml +9 -9
- data/.gitignore +5 -0
- data/bin/inline_forms +41 -414
- data/bin/inline_forms_app_template.rb +16 -0
- data/bin/inline_forms_installer_core.rb +423 -0
- data/lib/app/assets/javascripts/inline_forms.js +12 -32
- data/lib/app/assets/javascripts/inline_forms_application.js +7 -1
- data/lib/app/assets/stylesheets/inline_forms.css +5 -399
- data/lib/app/assets/stylesheets/inline_forms_application.css +3 -3
- data/lib/app/controllers/inline_forms_application_controller.rb +1 -2
- data/lib/app/controllers/inline_forms_controller.rb +2 -2
- data/lib/app/helpers/form_elements/check_list.rb +7 -14
- data/lib/app/helpers/form_elements/date.rb +3 -8
- data/lib/app/helpers/form_elements/decimal_field.rb +15 -0
- data/lib/app/helpers/form_elements/dropdown.rb +1 -1
- data/lib/app/helpers/form_elements/dropdown_with_other.rb +153 -0
- data/lib/app/helpers/form_elements/dropdown_with_values.rb +1 -1
- data/lib/app/helpers/form_elements/info_list.rb +22 -0
- data/lib/app/helpers/form_elements/integer_field.rb +15 -0
- data/lib/app/helpers/form_elements/kansen_slider.rb +89 -0
- data/lib/app/helpers/form_elements/month_year_picker.rb +33 -0
- data/lib/app/helpers/form_elements/move.rb +17 -0
- data/lib/app/helpers/form_elements/plain_text_area.rb +1 -1
- data/lib/app/helpers/form_elements/radio_button.rb +5 -6
- data/lib/app/helpers/form_elements/slider_with_values.rb +1 -1
- data/lib/app/helpers/form_elements/text_area.rb +12 -10
- data/lib/app/helpers/form_elements/text_area_without_ckeditor.rb +1 -1
- data/lib/app/helpers/form_elements/text_field.rb +2 -2
- data/lib/app/helpers/inline_forms_helper.rb +32 -37
- data/lib/app/views/inline_forms/_close.html.erb +12 -2
- data/lib/app/views/inline_forms/_edit.html.erb +54 -21
- data/lib/app/views/inline_forms/_flash.html.erb +13 -0
- data/lib/app/views/inline_forms/_list.html.erb +28 -24
- data/lib/app/views/inline_forms/_new.html.erb +52 -60
- data/lib/app/views/inline_forms/_new_nested.html.erb +43 -0
- data/lib/app/views/inline_forms/_show.html.erb +83 -39
- data/lib/app/views/inline_forms/_tree.html.erb +46 -0
- data/lib/app/views/layouts/devise.html.erb +4 -14
- data/lib/app/views/layouts/inline_forms.html.erb +15 -23
- data/lib/inline_forms/version.rb +1 -1
- metadata +17 -13
- data/lib/app/assets/images/add.png +0 -0
- data/lib/app/assets/images/close.png +0 -0
- data/lib/app/assets/images/tooltip-bubble-down-left.png +0 -0
- data/lib/app/assets/images/tooltip-bubble-down-right.png +0 -0
- data/lib/app/assets/images/tooltip-bubble-up-left.png +0 -0
- data/lib/app/assets/images/tooltip-bubble-up-right.png +0 -0
- data/lib/app/assets/images/trash.png +0 -0
- data/lib/app/assets/javascripts/jquery.qtip.js +0 -3395
- data/lib/app/assets/stylesheets/jquery.qtip.css +0 -567
- data/lib/app/views/inline_forms/_header.html.erb +0 -1
@@ -0,0 +1,43 @@
|
|
1
|
+
This goes in _new.html.erb
|
2
|
+
<% if form_element.to_sym == :associated -%>
|
3
|
+
<% @nested_model = @object.send(attribute) %>
|
4
|
+
<%= render 'new_nested' %>
|
5
|
+
<% end %>
|
6
|
+
********
|
7
|
+
|
8
|
+
<% @nested_object = @nested_model.build %>
|
9
|
+
|
10
|
+
<div class="new_nested_record">
|
11
|
+
<div class="row" >
|
12
|
+
<div class="large-12 column object_presentation" >
|
13
|
+
<%= t('inline_forms.view.add_new', :model => @nested_object.class ) -%>
|
14
|
+
</div>
|
15
|
+
</div>
|
16
|
+
<% nested_attributes = @nested_object.inline_forms_attribute_list -%>
|
17
|
+
<% nested_attributes.each do | nested_attribute, nested_name, nested_form_element | -%>
|
18
|
+
<% @nested_form_element = nested_form_element %>
|
19
|
+
<% @nested_attribute = nested_attribute %>
|
20
|
+
<% unless @nested_form_element.to_sym == :associated -%>
|
21
|
+
<% if @nested_form_element == :header %>
|
22
|
+
<div class="row form_element_header" >
|
23
|
+
<div class='large-12 column' >
|
24
|
+
<%= @nested_object.class.human_attribute_name(@nested_attribute) -%>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
<% else %>
|
28
|
+
<div class="row <%= cycle('odd', 'even') %>">
|
29
|
+
<div class='medium-3 large-3 column' >
|
30
|
+
<%= @nested_object.class.human_attribute_name(@nested_attribute) -%>
|
31
|
+
</div>
|
32
|
+
<div class='medium-9 large-9 column' >
|
33
|
+
<%= send("#{@nested_form_element}_edit", @nested_object, @nested_attribute) -%>
|
34
|
+
</div>
|
35
|
+
</div>
|
36
|
+
<% end -%>
|
37
|
+
<% end -%>
|
38
|
+
<% end -%>
|
39
|
+
<% if @nested_form_element.to_sym == :associated -%>
|
40
|
+
<%= render 'new_nested' %>
|
41
|
+
<% end %>
|
42
|
+
<div class="row record_footer"></div>
|
43
|
+
</div>
|
@@ -1,49 +1,93 @@
|
|
1
|
-
<
|
2
|
-
<
|
3
|
-
|
4
|
-
|
1
|
+
<div class="row">
|
2
|
+
<div class='medium-1 large-1 column'>
|
3
|
+
|
4
|
+
</div>
|
5
|
+
<div class='small-11 column'>
|
6
|
+
<% unless @skip %>
|
7
|
+
<div class="row object_presentation">
|
8
|
+
<div class="small-11 column object_presentation">
|
5
9
|
<%= h(@object._presentation) -%>
|
6
10
|
</div>
|
7
|
-
<div class="close_link" >
|
11
|
+
<div class="small-1 column close_link" >
|
8
12
|
<%= close_link(@object, @update_span) -%>
|
9
13
|
</div>
|
10
|
-
</
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
<%
|
15
|
-
<%
|
16
|
-
|
17
|
-
|
18
|
-
<
|
19
|
-
<div class='
|
14
|
+
</div>
|
15
|
+
<% end %>
|
16
|
+
<% attributes = @inline_forms_attribute_list || @object.inline_forms_attribute_list -%>
|
17
|
+
<% attributes.each do | attribute, name, form_element | -%>
|
18
|
+
<% puts "LOG: #{attribute}, #{form_element}" if Rails.env.development? %>
|
19
|
+
<% if cancan_disabled? || can?(:read, @object, attribute) %>
|
20
|
+
<% css_class_id = "#{@object.class.name.underscore}_#{@object.id}_#{attribute}" -%>
|
21
|
+
<% if form_element == :header %>
|
22
|
+
<div class="row form_element_header">
|
23
|
+
<div class='large-12 column' >
|
20
24
|
<%= @object.class.human_attribute_name(attribute) -%>
|
21
25
|
</div>
|
22
|
-
</
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
</div>
|
27
|
+
<% else %>
|
28
|
+
<% if form_element == :tree -%>
|
29
|
+
<div class="row form_element_header associated_auto_header" id="<%= css_class_id -%>_list_auto_header" >
|
30
|
+
<div class='medium-11 large-11 column' >
|
31
|
+
Children
|
32
|
+
</div>
|
33
|
+
<div class='medium-1 large-1 column'>
|
34
|
+
<%= link_to_new_record(@object.class, "new_#{@object.class.to_s.underscore.singularize}_path", css_class_id, @object.class, @object.id) -%>
|
35
|
+
</div>
|
29
36
|
</div>
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
<%= send("#{form_element}_show", @object, attribute) -%>
|
41
|
-
<% end -%>
|
42
|
-
</span>
|
37
|
+
<div class="row <%= cycle('odd', 'even') %>">
|
38
|
+
<div class='medium-1 large-1 column'>
|
39
|
+
|
40
|
+
</div>
|
41
|
+
<div id="<%= css_class_id -%>" class='small-11 column' >
|
42
|
+
<%= render :partial => "inline_forms/tree",
|
43
|
+
:locals => { :parent_class => @object.class,
|
44
|
+
:parent_id => @object.id,
|
45
|
+
:attribute => attribute } %>
|
46
|
+
</div>
|
43
47
|
</div>
|
44
|
-
|
45
|
-
|
48
|
+
<% else -%>
|
49
|
+
<% if form_element == :associated -%>
|
50
|
+
<div class="row form_element_header associated_auto_header" id="<%= css_class_id -%>_list_auto_header" >
|
51
|
+
<div class='medium-11 large-11 column' >
|
52
|
+
<%= @object.class.human_attribute_name(attribute) -%>
|
53
|
+
</div>
|
54
|
+
<div class='medium-1 large-1 column'>
|
55
|
+
<%= link_to_new_record(attribute.to_s.singularize.camelcase.constantize, "new_#{attribute.to_s.underscore.singularize}_path", css_class_id, @object.class, @object.id) -%>
|
56
|
+
</div>
|
57
|
+
</div>
|
58
|
+
<div class="row <%= cycle('odd', 'even') %>">
|
59
|
+
<div class='medium-1 large-1 column'>
|
60
|
+
|
61
|
+
</div>
|
62
|
+
<div id="<%= css_class_id -%>" class='small-11 column' >
|
63
|
+
<%= render :partial => "inline_forms/list",
|
64
|
+
:locals => { :parent_class => @object.class,
|
65
|
+
:parent_id => @object.id,
|
66
|
+
:attribute => attribute } %>
|
67
|
+
</div>
|
68
|
+
</div>
|
69
|
+
<% else -%>
|
70
|
+
<div class="row <%= cycle('odd', 'even') %>">
|
71
|
+
<div class='medium-5 large-5 column' >
|
72
|
+
<% if @object.has_validations_for?(attribute) -%>
|
73
|
+
<span data-tooltip class="has-tip tip-top" title="<%= validation_hints_as_list_for(@object, attribute).html_safe -%>">
|
74
|
+
<%= @object.class.human_attribute_name(attribute) -%>
|
75
|
+
</span>
|
76
|
+
<% else %>
|
77
|
+
<%= @object.class.human_attribute_name(attribute) -%>
|
78
|
+
<% end %>
|
79
|
+
</div>
|
80
|
+
<div class='medium-7 large-7 column' >
|
81
|
+
<span id="<%= css_class_id -%>" >
|
82
|
+
<%= send("#{form_element}_show", @object, attribute) -%>
|
83
|
+
</span>
|
84
|
+
</div>
|
85
|
+
</div>
|
86
|
+
<% end -%>
|
87
|
+
<% end -%>
|
88
|
+
<% end -%>
|
46
89
|
<% end -%>
|
47
90
|
<% end -%>
|
48
|
-
|
49
|
-
</
|
91
|
+
<div class="record_footer"></div>
|
92
|
+
</div>
|
93
|
+
</div>
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<% # here we come from _show %>
|
2
|
+
<% update_span = "#{parent_class.to_s.underscore}_#{parent_id}_#{attribute}_list" -%>
|
3
|
+
<% path_to_new='new_' + parent_class.to_s.underscore.singularize + '_path' %>
|
4
|
+
<% model = parent_class %>
|
5
|
+
<% objects = parent_class.find(parent_id).children %>
|
6
|
+
<% objects = parent_class.find(parent_id).children.accessible_by(current_ability) if cancan_enabled? %>
|
7
|
+
<% objects = objects.paginate :page => params[:page], :per_page => @PER_PAGE || 5 %>
|
8
|
+
|
9
|
+
<div class="list_container" id="<%= update_span %>">
|
10
|
+
|
11
|
+
<!-- # list of objects -->
|
12
|
+
<% for object in objects %>
|
13
|
+
<% css_class_id = parent_class.to_s.underscore + '_' + parent_id.to_s + '_' + attribute.to_s.singularize.underscore + "_" + object.id.to_s -%>
|
14
|
+
<% path_to_object = parent_class.to_s.singularize.underscore + "_path" %>
|
15
|
+
<div class="row <%= cycle('odd', 'even') %><%= " top-level" if parent_class.nil? %>" id="<%= css_class_id -%>">
|
16
|
+
<% if cancan_disabled? || ( can? :delete, object ) %>
|
17
|
+
<div class="small-1 column">
|
18
|
+
<%= link_to_destroy(object, css_class_id) -%>
|
19
|
+
</div>
|
20
|
+
<div class="small-11 column">
|
21
|
+
<%= link_to h(object._presentation),
|
22
|
+
send( path_to_object, object, :update => css_class_id),
|
23
|
+
:remote => true -%>
|
24
|
+
</div>
|
25
|
+
<% else %>
|
26
|
+
<div class="small-12 column">
|
27
|
+
<%= link_to h(object._presentation),
|
28
|
+
send( path_to_object, object, :update => css_class_id),
|
29
|
+
:remote => true -%>
|
30
|
+
</div>
|
31
|
+
<% end %>
|
32
|
+
</div>
|
33
|
+
<% end -%>
|
34
|
+
<!-- # pagination -->
|
35
|
+
<% if parent_id.nil? -%>
|
36
|
+
<% pagination = will_paginate objects -%>
|
37
|
+
<% else %>
|
38
|
+
<% pagination = will_paginate objects, :remote => true, :params => {:controller => attribute, :action => :index, :id => nil, :parent_class => parent_class, :parent_id => parent_id, :update => "#{parent_class.to_s.underscore}_#{parent_id}_#{attribute}", :ul_needed => true } -%>
|
39
|
+
<% end %>
|
40
|
+
<% if pagination %>
|
41
|
+
<div class="row <%= cycle('odd', 'even') %>">
|
42
|
+
<div class='small-11 small-centered column'>
|
43
|
+
<%= raw pagination %>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
<% end %>
|
@@ -1,24 +1,14 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
|
-
|
3
|
-
<!--[if lt IE 7 ]> <html class="ie6" lang="en"> <![endif]-->
|
4
|
-
<!--[if IE 7 ]> <html class="ie7" lang="en"> <![endif]-->
|
5
|
-
<!--[if IE 8 ]> <html class="ie8" lang="en"> <![endif]-->
|
6
|
-
<!--[if (gte IE 9)|!(IE)]><!--> <html lang="en"> <!--<![endif]-->
|
2
|
+
<html lang="en">
|
7
3
|
<head>
|
8
4
|
<meta charset="utf-8" />
|
9
|
-
|
10
|
-
<!-- Uncomment to make IE8 render like IE7 -->
|
11
|
-
<!-- <meta http-equiv="X-UA-Compatible" content="IE=7" /> -->
|
12
|
-
|
13
|
-
<!-- Set the viewport width to device width for mobile -->
|
14
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
15
|
-
<link href='
|
16
|
-
<title><%= t('
|
6
|
+
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,400italic' rel='stylesheet' type='text/css' />
|
7
|
+
<title><%= t('application_name') + " v" + InlineForms::VERSION -%></title>
|
17
8
|
|
18
9
|
<%= stylesheet_link_tag "application" %>
|
19
|
-
<%= javascript_include_tag "vendor/
|
10
|
+
<%= javascript_include_tag "vendor/modernizr" %>
|
20
11
|
<%= csrf_meta_tags %>
|
21
|
-
|
22
12
|
</head>
|
23
13
|
|
24
14
|
<body>
|
@@ -1,32 +1,24 @@
|
|
1
|
-
<!DOCTYPE html
|
2
|
-
|
3
|
-
<html>
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
4
3
|
<head>
|
4
|
+
<meta charset="utf-8" />
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
6
|
+
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,400italic' rel='stylesheet' type='text/css' />
|
7
|
+
|
5
8
|
<title><%= t('application_name') + " v" + InlineForms::VERSION -%></title>
|
6
|
-
|
7
|
-
<%=
|
8
|
-
<%=
|
9
|
-
<%=
|
10
|
-
<script>
|
11
|
-
$.datepicker.setDefaults({
|
12
|
-
dateFormat: 'dd-mm-yy',
|
13
|
-
changeMonth: true,
|
14
|
-
changeYear: true,
|
15
|
-
showOtherMonths: true,
|
16
|
-
selectOtherMonths: true,
|
17
|
-
showButtonPanel: false,
|
18
|
-
showWeek: true,
|
19
|
-
firstDay: 1,
|
20
|
-
prevText: '<<',
|
21
|
-
nextText: '>>'
|
22
|
-
})
|
23
|
-
</script>
|
9
|
+
|
10
|
+
<%= stylesheet_link_tag "application" %>
|
11
|
+
<%= javascript_include_tag "vendor/modernizr" %>
|
12
|
+
<%= csrf_meta_tags %>
|
24
13
|
</head>
|
14
|
+
|
25
15
|
<body>
|
16
|
+
|
26
17
|
<%= render "inline_forms/header" %>
|
27
18
|
<%= render "/inline_forms_tabs" %>
|
28
|
-
<div id="
|
29
|
-
|
19
|
+
<div id="outer_container">
|
20
|
+
<%= yield %>
|
30
21
|
</div>
|
22
|
+
<%= javascript_include_tag 'application', 'inline_forms_application' %>
|
31
23
|
</body>
|
32
24
|
</html>
|
data/lib/inline_forms/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inline_forms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '
|
4
|
+
version: '3.0'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ace Suares
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rvm
|
@@ -156,6 +156,8 @@ email:
|
|
156
156
|
- ace@suares.com
|
157
157
|
executables:
|
158
158
|
- inline_forms
|
159
|
+
- inline_forms_app_template.rb
|
160
|
+
- inline_forms_installer_core.rb
|
159
161
|
extensions: []
|
160
162
|
extra_rdoc_files: []
|
161
163
|
files:
|
@@ -167,42 +169,42 @@ files:
|
|
167
169
|
- README.rdoc
|
168
170
|
- Rakefile
|
169
171
|
- bin/inline_forms
|
172
|
+
- bin/inline_forms_app_template.rb
|
173
|
+
- bin/inline_forms_installer_core.rb
|
170
174
|
- inline_forms.gemspec
|
171
|
-
- lib/app/assets/images/add.png
|
172
|
-
- lib/app/assets/images/close.png
|
173
175
|
- lib/app/assets/images/devise_footer_left.png
|
174
176
|
- lib/app/assets/images/devise_footer_right.png
|
175
177
|
- lib/app/assets/images/devise_header.png
|
176
178
|
- lib/app/assets/images/glass_plate.gif
|
177
|
-
- lib/app/assets/images/tooltip-bubble-down-left.png
|
178
|
-
- lib/app/assets/images/tooltip-bubble-down-right.png
|
179
|
-
- lib/app/assets/images/tooltip-bubble-up-left.png
|
180
|
-
- lib/app/assets/images/tooltip-bubble-up-right.png
|
181
|
-
- lib/app/assets/images/trash.png
|
182
179
|
- lib/app/assets/javascripts/ckeditor/config.js
|
183
180
|
- lib/app/assets/javascripts/inline_forms.js
|
184
181
|
- lib/app/assets/javascripts/inline_forms_application.js
|
185
|
-
- lib/app/assets/javascripts/jquery.qtip.js
|
186
182
|
- lib/app/assets/stylesheets/inline_forms.css
|
187
183
|
- lib/app/assets/stylesheets/inline_forms_application.css
|
188
|
-
- lib/app/assets/stylesheets/jquery.qtip.css
|
189
184
|
- lib/app/controllers/geo_code_curacao_controller.rb
|
190
185
|
- lib/app/controllers/inline_forms_application_controller.rb
|
191
186
|
- lib/app/controllers/inline_forms_controller.rb
|
192
187
|
- lib/app/helpers/form_elements/check_box.rb
|
193
188
|
- lib/app/helpers/form_elements/check_list.rb
|
194
189
|
- lib/app/helpers/form_elements/date.rb
|
190
|
+
- lib/app/helpers/form_elements/decimal_field.rb
|
195
191
|
- lib/app/helpers/form_elements/devise_password_field.rb
|
196
192
|
- lib/app/helpers/form_elements/dns_records.rb
|
197
193
|
- lib/app/helpers/form_elements/dropdown.rb
|
198
194
|
- lib/app/helpers/form_elements/dropdown_with_integers.rb
|
195
|
+
- lib/app/helpers/form_elements/dropdown_with_other.rb
|
199
196
|
- lib/app/helpers/form_elements/dropdown_with_values.rb
|
200
197
|
- lib/app/helpers/form_elements/file_field.rb
|
201
198
|
- lib/app/helpers/form_elements/geo_code_curacao.rb
|
202
199
|
- lib/app/helpers/form_elements/header.rb
|
203
200
|
- lib/app/helpers/form_elements/image_field.rb
|
204
201
|
- lib/app/helpers/form_elements/info.rb
|
202
|
+
- lib/app/helpers/form_elements/info_list.rb
|
203
|
+
- lib/app/helpers/form_elements/integer_field.rb
|
204
|
+
- lib/app/helpers/form_elements/kansen_slider.rb
|
205
205
|
- lib/app/helpers/form_elements/money_field.rb
|
206
|
+
- lib/app/helpers/form_elements/month_year_picker.rb
|
207
|
+
- lib/app/helpers/form_elements/move.rb
|
206
208
|
- lib/app/helpers/form_elements/pdf_link.rb
|
207
209
|
- lib/app/helpers/form_elements/plain_text_area.rb
|
208
210
|
- lib/app/helpers/form_elements/question_list.rb
|
@@ -235,10 +237,12 @@ files:
|
|
235
237
|
- lib/app/views/geo_code_curacao/list_streets.js.erb
|
236
238
|
- lib/app/views/inline_forms/_close.html.erb
|
237
239
|
- lib/app/views/inline_forms/_edit.html.erb
|
238
|
-
- lib/app/views/inline_forms/
|
240
|
+
- lib/app/views/inline_forms/_flash.html.erb
|
239
241
|
- lib/app/views/inline_forms/_list.html.erb
|
240
242
|
- lib/app/views/inline_forms/_new.html.erb
|
243
|
+
- lib/app/views/inline_forms/_new_nested.html.erb
|
241
244
|
- lib/app/views/inline_forms/_show.html.erb
|
245
|
+
- lib/app/views/inline_forms/_tree.html.erb
|
242
246
|
- lib/app/views/inline_forms/close.js.erb
|
243
247
|
- lib/app/views/inline_forms/edit.js.erb
|
244
248
|
- lib/app/views/inline_forms/extract_translations.erb
|
@@ -290,7 +294,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
290
294
|
version: '0'
|
291
295
|
requirements: []
|
292
296
|
rubyforge_project: inline_forms
|
293
|
-
rubygems_version: 2.
|
297
|
+
rubygems_version: 2.1.9
|
294
298
|
signing_key:
|
295
299
|
specification_version: 4
|
296
300
|
summary: Inline editing of forms.
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -1,3395 +0,0 @@
|
|
1
|
-
/*!
|
2
|
-
* qTip2 - Pretty powerful tooltips
|
3
|
-
* http://craigsworks.com/projects/qtip2/
|
4
|
-
*
|
5
|
-
* Version: nightly
|
6
|
-
* Copyright 2009-2010 Craig Michael Thompson - http://craigsworks.com
|
7
|
-
*
|
8
|
-
* Dual licensed under MIT or GPLv2 licenses
|
9
|
-
* http://en.wikipedia.org/wiki/MIT_License
|
10
|
-
* http://en.wikipedia.org/wiki/GNU_General_Public_License
|
11
|
-
*
|
12
|
-
* Date: Sun Jul 15 16:44:57.0000000000 2012
|
13
|
-
*/
|
14
|
-
|
15
|
-
/*jslint browser: true, onevar: true, undef: true, nomen: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: true */
|
16
|
-
/*global window: false, jQuery: false, console: false, define: false */
|
17
|
-
|
18
|
-
// Uses AMD or browser globals to create a jQuery plugin.
|
19
|
-
(function(factory) {
|
20
|
-
if(typeof define === 'function' && define.amd) {
|
21
|
-
define(['jquery'], factory);
|
22
|
-
}
|
23
|
-
else if(jQuery && !jQuery.fn.qtip) {
|
24
|
-
factory(jQuery);
|
25
|
-
}
|
26
|
-
}
|
27
|
-
(function($) {
|
28
|
-
|
29
|
-
"use strict"; // Enable ECMAScript "strict" operation for this function. See more: http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
|
30
|
-
|
31
|
-
// Munge the primitives - Paul Irish tip
|
32
|
-
var TRUE = true,
|
33
|
-
FALSE = false,
|
34
|
-
NULL = null,
|
35
|
-
undefined,
|
36
|
-
|
37
|
-
// Side names and other stuff
|
38
|
-
X = 'x', Y = 'y',
|
39
|
-
WIDTH = 'width',
|
40
|
-
HEIGHT = 'height',
|
41
|
-
TOP = 'top',
|
42
|
-
LEFT = 'left',
|
43
|
-
BOTTOM = 'bottom',
|
44
|
-
RIGHT = 'right',
|
45
|
-
CENTER = 'center',
|
46
|
-
FLIP = 'flip',
|
47
|
-
FLIPINVERT = 'flipinvert',
|
48
|
-
SHIFT = 'shift',
|
49
|
-
|
50
|
-
// Shortcut vars
|
51
|
-
QTIP, PLUGINS, MOUSE,
|
52
|
-
usedIDs = {},
|
53
|
-
uitooltip = 'ui-tooltip',
|
54
|
-
widget = 'ui-widget',
|
55
|
-
disabled = 'ui-state-disabled',
|
56
|
-
selector = 'div.qtip.'+uitooltip,
|
57
|
-
defaultClass = uitooltip + '-default',
|
58
|
-
focusClass = uitooltip + '-focus',
|
59
|
-
hoverClass = uitooltip + '-hover',
|
60
|
-
fluidClass = uitooltip + '-fluid',
|
61
|
-
hideOffset = '-31000px',
|
62
|
-
replaceSuffix = '_replacedByqTip',
|
63
|
-
oldtitle = 'oldtitle',
|
64
|
-
trackingBound;
|
65
|
-
|
66
|
-
/* Thanks to Paul Irish for this one: http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/ */
|
67
|
-
function log() {
|
68
|
-
log.history = log.history || [];
|
69
|
-
log.history.push(arguments);
|
70
|
-
|
71
|
-
// Make sure console is present
|
72
|
-
if('object' === typeof console) {
|
73
|
-
|
74
|
-
// Setup console and arguments
|
75
|
-
var c = console[ console.warn ? 'warn' : 'log' ],
|
76
|
-
args = Array.prototype.slice.call(arguments), a;
|
77
|
-
|
78
|
-
// Add qTip2 marker to first argument if it's a string
|
79
|
-
if(typeof arguments[0] === 'string') { args[0] = 'qTip2: ' + args[0]; }
|
80
|
-
|
81
|
-
// Apply console.warn or .log if not supported
|
82
|
-
a = c.apply ? c.apply(console, args) : c(args);
|
83
|
-
}
|
84
|
-
}
|
85
|
-
|
86
|
-
// Option object sanitizer
|
87
|
-
function sanitizeOptions(opts)
|
88
|
-
{
|
89
|
-
var content;
|
90
|
-
|
91
|
-
if(!opts || 'object' !== typeof opts) { return FALSE; }
|
92
|
-
|
93
|
-
if(opts.metadata === NULL || 'object' !== typeof opts.metadata) {
|
94
|
-
opts.metadata = {
|
95
|
-
type: opts.metadata
|
96
|
-
};
|
97
|
-
}
|
98
|
-
|
99
|
-
if('content' in opts) {
|
100
|
-
if(opts.content === NULL || 'object' !== typeof opts.content || opts.content.jquery) {
|
101
|
-
opts.content = {
|
102
|
-
text: opts.content
|
103
|
-
};
|
104
|
-
}
|
105
|
-
|
106
|
-
content = opts.content.text || FALSE;
|
107
|
-
if(!$.isFunction(content) && ((!content && !content.attr) || content.length < 1 || ('object' === typeof content && !content.jquery))) {
|
108
|
-
opts.content.text = FALSE;
|
109
|
-
}
|
110
|
-
|
111
|
-
if('title' in opts.content) {
|
112
|
-
if(opts.content.title === NULL || 'object' !== typeof opts.content.title) {
|
113
|
-
opts.content.title = {
|
114
|
-
text: opts.content.title
|
115
|
-
};
|
116
|
-
}
|
117
|
-
|
118
|
-
content = opts.content.title.text || FALSE;
|
119
|
-
if(!$.isFunction(content) && ((!content && !content.attr) || content.length < 1 || ('object' === typeof content && !content.jquery))) {
|
120
|
-
opts.content.title.text = FALSE;
|
121
|
-
}
|
122
|
-
}
|
123
|
-
}
|
124
|
-
|
125
|
-
if('position' in opts) {
|
126
|
-
if(opts.position === NULL || 'object' !== typeof opts.position) {
|
127
|
-
opts.position = {
|
128
|
-
my: opts.position,
|
129
|
-
at: opts.position
|
130
|
-
};
|
131
|
-
}
|
132
|
-
}
|
133
|
-
|
134
|
-
if('show' in opts) {
|
135
|
-
if(opts.show === NULL || 'object' !== typeof opts.show) {
|
136
|
-
if(opts.show.jquery) {
|
137
|
-
opts.show = { target: opts.show };
|
138
|
-
}
|
139
|
-
else {
|
140
|
-
opts.show = { event: opts.show };
|
141
|
-
}
|
142
|
-
}
|
143
|
-
}
|
144
|
-
|
145
|
-
if('hide' in opts) {
|
146
|
-
if(opts.hide === NULL || 'object' !== typeof opts.hide) {
|
147
|
-
if(opts.hide.jquery) {
|
148
|
-
opts.hide = { target: opts.hide };
|
149
|
-
}
|
150
|
-
else {
|
151
|
-
opts.hide = { event: opts.hide };
|
152
|
-
}
|
153
|
-
}
|
154
|
-
}
|
155
|
-
|
156
|
-
if('style' in opts) {
|
157
|
-
if(opts.style === NULL || 'object' !== typeof opts.style) {
|
158
|
-
opts.style = {
|
159
|
-
classes: opts.style
|
160
|
-
};
|
161
|
-
}
|
162
|
-
}
|
163
|
-
|
164
|
-
// Sanitize plugin options
|
165
|
-
$.each(PLUGINS, function() {
|
166
|
-
if(this.sanitize) { this.sanitize(opts); }
|
167
|
-
});
|
168
|
-
|
169
|
-
return opts;
|
170
|
-
}
|
171
|
-
|
172
|
-
/*
|
173
|
-
* Core plugin implementation
|
174
|
-
*/
|
175
|
-
function QTip(target, options, id, attr)
|
176
|
-
{
|
177
|
-
// Declare this reference
|
178
|
-
var self = this,
|
179
|
-
docBody = document.body,
|
180
|
-
tooltipID = uitooltip + '-' + id,
|
181
|
-
isPositioning = 0,
|
182
|
-
isDrawing = 0,
|
183
|
-
tooltip = $(),
|
184
|
-
namespace = '.qtip-' + id,
|
185
|
-
elements, cache;
|
186
|
-
|
187
|
-
// Setup class attributes
|
188
|
-
self.id = id;
|
189
|
-
self.rendered = FALSE;
|
190
|
-
self.destroyed = FALSE;
|
191
|
-
self.elements = elements = { target: target };
|
192
|
-
self.timers = { img: {} };
|
193
|
-
self.options = options;
|
194
|
-
self.checks = {};
|
195
|
-
self.plugins = {};
|
196
|
-
self.cache = cache = {
|
197
|
-
event: {},
|
198
|
-
target: $(),
|
199
|
-
disabled: FALSE,
|
200
|
-
attr: attr,
|
201
|
-
onTarget: FALSE,
|
202
|
-
lastClass: ''
|
203
|
-
};
|
204
|
-
|
205
|
-
/*
|
206
|
-
* Private core functions
|
207
|
-
*/
|
208
|
-
function convertNotation(notation)
|
209
|
-
{
|
210
|
-
var i = 0, obj, option = options,
|
211
|
-
|
212
|
-
// Split notation into array
|
213
|
-
levels = notation.split('.');
|
214
|
-
|
215
|
-
// Loop through
|
216
|
-
while( option = option[ levels[i++] ] ) {
|
217
|
-
if(i < levels.length) { obj = option; }
|
218
|
-
}
|
219
|
-
|
220
|
-
return [obj || options, levels.pop()];
|
221
|
-
}
|
222
|
-
|
223
|
-
function setWidget() {
|
224
|
-
var on = options.style.widget;
|
225
|
-
|
226
|
-
tooltip.toggleClass(widget, on).toggleClass(defaultClass, options.style.def && !on);
|
227
|
-
elements.content.toggleClass(widget+'-content', on);
|
228
|
-
|
229
|
-
if(elements.titlebar){
|
230
|
-
elements.titlebar.toggleClass(widget+'-header', on);
|
231
|
-
}
|
232
|
-
if(elements.button){
|
233
|
-
elements.button.toggleClass(uitooltip+'-icon', !on);
|
234
|
-
}
|
235
|
-
}
|
236
|
-
|
237
|
-
function removeTitle(reposition)
|
238
|
-
{
|
239
|
-
if(elements.title) {
|
240
|
-
elements.titlebar.remove();
|
241
|
-
elements.titlebar = elements.title = elements.button = NULL;
|
242
|
-
|
243
|
-
// Reposition if enabled
|
244
|
-
if(reposition !== FALSE) { self.reposition(); }
|
245
|
-
}
|
246
|
-
}
|
247
|
-
|
248
|
-
function createButton()
|
249
|
-
{
|
250
|
-
var button = options.content.title.button,
|
251
|
-
isString = typeof button === 'string',
|
252
|
-
close = isString ? button : 'Close tooltip';
|
253
|
-
|
254
|
-
if(elements.button) { elements.button.remove(); }
|
255
|
-
|
256
|
-
// Use custom button if one was supplied by user, else use default
|
257
|
-
if(button.jquery) {
|
258
|
-
elements.button = button;
|
259
|
-
}
|
260
|
-
else {
|
261
|
-
elements.button = $('<a />', {
|
262
|
-
'class': 'ui-state-default ui-tooltip-close ' + (options.style.widget ? '' : uitooltip+'-icon'),
|
263
|
-
'title': close,
|
264
|
-
'aria-label': close
|
265
|
-
})
|
266
|
-
.prepend(
|
267
|
-
$('<span />', {
|
268
|
-
'class': 'ui-icon ui-icon-close',
|
269
|
-
'html': '×'
|
270
|
-
})
|
271
|
-
);
|
272
|
-
}
|
273
|
-
|
274
|
-
// Create button and setup attributes
|
275
|
-
elements.button.appendTo(elements.titlebar)
|
276
|
-
.attr('role', 'button')
|
277
|
-
.click(function(event) {
|
278
|
-
if(!tooltip.hasClass(disabled)) { self.hide(event); }
|
279
|
-
return FALSE;
|
280
|
-
});
|
281
|
-
|
282
|
-
// Redraw the tooltip when we're done
|
283
|
-
self.redraw();
|
284
|
-
}
|
285
|
-
|
286
|
-
function createTitle()
|
287
|
-
{
|
288
|
-
var id = tooltipID+'-title';
|
289
|
-
|
290
|
-
// Destroy previous title element, if present
|
291
|
-
if(elements.titlebar) { removeTitle(); }
|
292
|
-
|
293
|
-
// Create title bar and title elements
|
294
|
-
elements.titlebar = $('<div />', {
|
295
|
-
'class': uitooltip + '-titlebar ' + (options.style.widget ? 'ui-widget-header' : '')
|
296
|
-
})
|
297
|
-
.append(
|
298
|
-
elements.title = $('<div />', {
|
299
|
-
'id': id,
|
300
|
-
'class': uitooltip + '-title',
|
301
|
-
'aria-atomic': TRUE
|
302
|
-
})
|
303
|
-
)
|
304
|
-
.insertBefore(elements.content)
|
305
|
-
|
306
|
-
// Button-specific events
|
307
|
-
.delegate('.ui-tooltip-close', 'mousedown keydown mouseup keyup mouseout', function(event) {
|
308
|
-
$(this).toggleClass('ui-state-active ui-state-focus', event.type.substr(-4) === 'down');
|
309
|
-
})
|
310
|
-
.delegate('.ui-tooltip-close', 'mouseover mouseout', function(event){
|
311
|
-
$(this).toggleClass('ui-state-hover', event.type === 'mouseover');
|
312
|
-
});
|
313
|
-
|
314
|
-
// Create button if enabled
|
315
|
-
if(options.content.title.button) { createButton(); }
|
316
|
-
|
317
|
-
// Redraw the tooltip dimensions if it's rendered
|
318
|
-
else if(self.rendered){ self.redraw(); }
|
319
|
-
}
|
320
|
-
|
321
|
-
function updateButton(button)
|
322
|
-
{
|
323
|
-
var elem = elements.button,
|
324
|
-
title = elements.title;
|
325
|
-
|
326
|
-
// Make sure tooltip is rendered and if not, return
|
327
|
-
if(!self.rendered) { return FALSE; }
|
328
|
-
|
329
|
-
if(!button) {
|
330
|
-
elem.remove();
|
331
|
-
}
|
332
|
-
else {
|
333
|
-
if(!title) {
|
334
|
-
createTitle();
|
335
|
-
}
|
336
|
-
createButton();
|
337
|
-
}
|
338
|
-
}
|
339
|
-
|
340
|
-
function updateTitle(content, reposition)
|
341
|
-
{
|
342
|
-
var elem = elements.title;
|
343
|
-
|
344
|
-
// Make sure tooltip is rendered and if not, return
|
345
|
-
if(!self.rendered || !content) { return FALSE; }
|
346
|
-
|
347
|
-
// Use function to parse content
|
348
|
-
if($.isFunction(content)) {
|
349
|
-
content = content.call(target, cache.event, self);
|
350
|
-
}
|
351
|
-
|
352
|
-
// Remove title if callback returns false or null/undefined (but not '')
|
353
|
-
if(content === FALSE || (!content && content !== '')) { return removeTitle(FALSE); }
|
354
|
-
|
355
|
-
// Append new content if its a DOM array and show it if hidden
|
356
|
-
else if(content.jquery && content.length > 0) {
|
357
|
-
elem.empty().append(content.css({ display: 'block' }));
|
358
|
-
}
|
359
|
-
|
360
|
-
// Content is a regular string, insert the new content
|
361
|
-
else { elem.html(content); }
|
362
|
-
|
363
|
-
// Redraw and reposition
|
364
|
-
self.redraw();
|
365
|
-
if(reposition !== FALSE && self.rendered && tooltip[0].offsetWidth > 0) {
|
366
|
-
self.reposition(cache.event);
|
367
|
-
}
|
368
|
-
}
|
369
|
-
|
370
|
-
function updateContent(content, reposition)
|
371
|
-
{
|
372
|
-
var elem = elements.content;
|
373
|
-
|
374
|
-
// Make sure tooltip is rendered and content is defined. If not return
|
375
|
-
if(!self.rendered || !content) { return FALSE; }
|
376
|
-
|
377
|
-
// Use function to parse content
|
378
|
-
if($.isFunction(content)) {
|
379
|
-
content = content.call(target, cache.event, self) || '';
|
380
|
-
}
|
381
|
-
|
382
|
-
// Append new content if its a DOM array and show it if hidden
|
383
|
-
if(content.jquery && content.length > 0) {
|
384
|
-
elem.empty().append(content.css({ display: 'block' }));
|
385
|
-
}
|
386
|
-
|
387
|
-
// Content is a regular string, insert the new content
|
388
|
-
else { elem.html(content); }
|
389
|
-
|
390
|
-
// Image detection
|
391
|
-
function detectImages(next) {
|
392
|
-
var images, srcs = {};
|
393
|
-
|
394
|
-
function imageLoad(image) {
|
395
|
-
// Clear src from object and any timers and events associated with the image
|
396
|
-
if(image) {
|
397
|
-
delete srcs[image.src];
|
398
|
-
clearTimeout(self.timers.img[image.src]);
|
399
|
-
$(image).unbind(namespace);
|
400
|
-
}
|
401
|
-
|
402
|
-
// If queue is empty after image removal, update tooltip and continue the queue
|
403
|
-
if($.isEmptyObject(srcs)) {
|
404
|
-
self.redraw();
|
405
|
-
if(reposition !== FALSE) {
|
406
|
-
self.reposition(cache.event);
|
407
|
-
}
|
408
|
-
|
409
|
-
next();
|
410
|
-
}
|
411
|
-
}
|
412
|
-
|
413
|
-
// Find all content images without dimensions, and if no images were found, continue
|
414
|
-
if((images = elem.find('img[src]:not([height]):not([width])')).length === 0) { return imageLoad(); }
|
415
|
-
|
416
|
-
// Apply timer to each image to poll for dimensions
|
417
|
-
images.each(function(i, elem) {
|
418
|
-
// Skip if the src is already present
|
419
|
-
if(srcs[elem.src] !== undefined) { return; }
|
420
|
-
|
421
|
-
// Keep track of how many times we poll for image dimensions.
|
422
|
-
// If it doesn't return in a reasonable amount of time, it's better
|
423
|
-
// to display the tooltip, rather than hold up the queue.
|
424
|
-
var iterations = 0, maxIterations = 3;
|
425
|
-
|
426
|
-
(function timer(){
|
427
|
-
// When the dimensions are found, remove the image from the queue
|
428
|
-
if(elem.height || elem.width || (iterations > maxIterations)) { return imageLoad(elem); }
|
429
|
-
|
430
|
-
// Increase iterations and restart timer
|
431
|
-
iterations += 1;
|
432
|
-
self.timers.img[elem.src] = setTimeout(timer, 700);
|
433
|
-
}());
|
434
|
-
|
435
|
-
// Also apply regular load/error event handlers
|
436
|
-
$(elem).bind('error'+namespace+' load'+namespace, function(){ imageLoad(this); });
|
437
|
-
|
438
|
-
// Store the src and element in our object
|
439
|
-
srcs[elem.src] = elem;
|
440
|
-
});
|
441
|
-
}
|
442
|
-
|
443
|
-
/*
|
444
|
-
* If we're still rendering... insert into 'fx' queue our image dimension
|
445
|
-
* checker which will halt the showing of the tooltip until image dimensions
|
446
|
-
* can be detected properly.
|
447
|
-
*/
|
448
|
-
if(self.rendered < 0) { tooltip.queue('fx', detectImages); }
|
449
|
-
|
450
|
-
// We're fully rendered, so reset isDrawing flag and proceed without queue delay
|
451
|
-
else { isDrawing = 0; detectImages($.noop); }
|
452
|
-
|
453
|
-
return self;
|
454
|
-
}
|
455
|
-
|
456
|
-
function assignEvents()
|
457
|
-
{
|
458
|
-
var posOptions = options.position,
|
459
|
-
targets = {
|
460
|
-
show: options.show.target,
|
461
|
-
hide: options.hide.target,
|
462
|
-
viewport: $(posOptions.viewport),
|
463
|
-
document: $(document),
|
464
|
-
body: $(document.body),
|
465
|
-
window: $(window)
|
466
|
-
},
|
467
|
-
events = {
|
468
|
-
show: $.trim('' + options.show.event).split(' '),
|
469
|
-
hide: $.trim('' + options.hide.event).split(' ')
|
470
|
-
},
|
471
|
-
IE6 = $.browser.msie && parseInt($.browser.version, 10) === 6;
|
472
|
-
|
473
|
-
// Define show event method
|
474
|
-
function showMethod(event)
|
475
|
-
{
|
476
|
-
if(tooltip.hasClass(disabled)) { return FALSE; }
|
477
|
-
|
478
|
-
// Clear hide timers
|
479
|
-
clearTimeout(self.timers.show);
|
480
|
-
clearTimeout(self.timers.hide);
|
481
|
-
|
482
|
-
// Start show timer
|
483
|
-
var callback = function(){ self.toggle(TRUE, event); };
|
484
|
-
if(options.show.delay > 0) {
|
485
|
-
self.timers.show = setTimeout(callback, options.show.delay);
|
486
|
-
}
|
487
|
-
else{ callback(); }
|
488
|
-
}
|
489
|
-
|
490
|
-
// Define hide method
|
491
|
-
function hideMethod(event)
|
492
|
-
{
|
493
|
-
if(tooltip.hasClass(disabled) || isPositioning || isDrawing) { return FALSE; }
|
494
|
-
|
495
|
-
// Check if new target was actually the tooltip element
|
496
|
-
var relatedTarget = $(event.relatedTarget || event.target),
|
497
|
-
ontoTooltip = relatedTarget.closest(selector)[0] === tooltip[0],
|
498
|
-
ontoTarget = relatedTarget[0] === targets.show[0];
|
499
|
-
|
500
|
-
// Clear timers and stop animation queue
|
501
|
-
clearTimeout(self.timers.show);
|
502
|
-
clearTimeout(self.timers.hide);
|
503
|
-
|
504
|
-
// Prevent hiding if tooltip is fixed and event target is the tooltip. Or if mouse positioning is enabled and cursor momentarily overlaps
|
505
|
-
if((posOptions.target === 'mouse' && ontoTooltip) || (options.hide.fixed && ((/mouse(out|leave|move)/).test(event.type) && (ontoTooltip || ontoTarget)))) {
|
506
|
-
try { event.preventDefault(); event.stopImmediatePropagation(); } catch(e) {} return;
|
507
|
-
}
|
508
|
-
|
509
|
-
// If tooltip has displayed, start hide timer
|
510
|
-
if(options.hide.delay > 0) {
|
511
|
-
self.timers.hide = setTimeout(function(){ self.hide(event); }, options.hide.delay);
|
512
|
-
}
|
513
|
-
else{ self.hide(event); }
|
514
|
-
}
|
515
|
-
|
516
|
-
// Define inactive method
|
517
|
-
function inactiveMethod(event)
|
518
|
-
{
|
519
|
-
if(tooltip.hasClass(disabled)) { return FALSE; }
|
520
|
-
|
521
|
-
// Clear timer
|
522
|
-
clearTimeout(self.timers.inactive);
|
523
|
-
self.timers.inactive = setTimeout(function(){ self.hide(event); }, options.hide.inactive);
|
524
|
-
}
|
525
|
-
|
526
|
-
function repositionMethod(event) {
|
527
|
-
if(self.rendered && tooltip[0].offsetWidth > 0) { self.reposition(event); }
|
528
|
-
}
|
529
|
-
|
530
|
-
// On mouseenter/mouseleave...
|
531
|
-
tooltip.bind('mouseenter'+namespace+' mouseleave'+namespace, function(event) {
|
532
|
-
var state = event.type === 'mouseenter';
|
533
|
-
|
534
|
-
// Focus the tooltip on mouseenter (z-index stacking)
|
535
|
-
if(state) { self.focus(event); }
|
536
|
-
|
537
|
-
// Add hover class
|
538
|
-
tooltip.toggleClass(hoverClass, state);
|
539
|
-
});
|
540
|
-
|
541
|
-
// If using mouseout/mouseleave as a hide event...
|
542
|
-
if(/mouse(out|leave)/i.test(options.hide.event)) {
|
543
|
-
// Hide tooltips when leaving current window/frame (but not select/option elements)
|
544
|
-
if(options.hide.leave === 'window') {
|
545
|
-
targets.window.bind('mouseleave'+namespace+' blur'+namespace, function(event) {
|
546
|
-
if(!/select|option/.test(event.target.nodeName) && !event.relatedTarget) { self.hide(event); }
|
547
|
-
});
|
548
|
-
}
|
549
|
-
}
|
550
|
-
|
551
|
-
// Enable hide.fixed
|
552
|
-
if(options.hide.fixed) {
|
553
|
-
// Add tooltip as a hide target
|
554
|
-
targets.hide = targets.hide.add(tooltip);
|
555
|
-
|
556
|
-
// Clear hide timer on tooltip hover to prevent it from closing
|
557
|
-
tooltip.bind('mouseover'+namespace, function() {
|
558
|
-
if(!tooltip.hasClass(disabled)) { clearTimeout(self.timers.hide); }
|
559
|
-
});
|
560
|
-
}
|
561
|
-
|
562
|
-
/*
|
563
|
-
* Make sure hoverIntent functions properly by using mouseleave to clear show timer if
|
564
|
-
* mouseenter/mouseout is used for show.event, even if it isn't in the users options.
|
565
|
-
*/
|
566
|
-
else if(/mouse(over|enter)/i.test(options.show.event)) {
|
567
|
-
targets.hide.bind('mouseleave'+namespace, function(event) {
|
568
|
-
clearTimeout(self.timers.show);
|
569
|
-
});
|
570
|
-
}
|
571
|
-
|
572
|
-
// Hide tooltip on document mousedown if unfocus events are enabled
|
573
|
-
if(('' + options.hide.event).indexOf('unfocus') > -1) {
|
574
|
-
posOptions.container.closest('html').bind('mousedown'+namespace, function(event) {
|
575
|
-
var elem = $(event.target),
|
576
|
-
enabled = self.rendered && !tooltip.hasClass(disabled) && tooltip[0].offsetWidth > 0,
|
577
|
-
isAncestor = elem.parents(selector).filter(tooltip[0]).length > 0;
|
578
|
-
|
579
|
-
if(elem[0] !== target[0] && elem[0] !== tooltip[0] && !isAncestor &&
|
580
|
-
!target.has(elem[0]).length && !elem.attr('disabled')
|
581
|
-
) {
|
582
|
-
self.hide(event);
|
583
|
-
}
|
584
|
-
});
|
585
|
-
}
|
586
|
-
|
587
|
-
// Check if the tooltip hides when inactive
|
588
|
-
if('number' === typeof options.hide.inactive) {
|
589
|
-
// Bind inactive method to target as a custom event
|
590
|
-
targets.show.bind('qtip-'+id+'-inactive', inactiveMethod);
|
591
|
-
|
592
|
-
// Define events which reset the 'inactive' event handler
|
593
|
-
$.each(QTIP.inactiveEvents, function(index, type){
|
594
|
-
targets.hide.add(elements.tooltip).bind(type+namespace+'-inactive', inactiveMethod);
|
595
|
-
});
|
596
|
-
}
|
597
|
-
|
598
|
-
// Apply hide events
|
599
|
-
$.each(events.hide, function(index, type) {
|
600
|
-
var showIndex = $.inArray(type, events.show),
|
601
|
-
targetHide = $(targets.hide);
|
602
|
-
|
603
|
-
// Both events and targets are identical, apply events using a toggle
|
604
|
-
if((showIndex > -1 && targetHide.add(targets.show).length === targetHide.length) || type === 'unfocus')
|
605
|
-
{
|
606
|
-
targets.show.bind(type+namespace, function(event) {
|
607
|
-
if(tooltip[0].offsetWidth > 0) { hideMethod(event); }
|
608
|
-
else { showMethod(event); }
|
609
|
-
});
|
610
|
-
|
611
|
-
// Don't bind the event again
|
612
|
-
delete events.show[ showIndex ];
|
613
|
-
}
|
614
|
-
|
615
|
-
// Events are not identical, bind normally
|
616
|
-
else { targets.hide.bind(type+namespace, hideMethod); }
|
617
|
-
});
|
618
|
-
|
619
|
-
// Apply show events
|
620
|
-
$.each(events.show, function(index, type) {
|
621
|
-
targets.show.bind(type+namespace, showMethod);
|
622
|
-
});
|
623
|
-
|
624
|
-
// Check if the tooltip hides when mouse is moved a certain distance
|
625
|
-
if('number' === typeof options.hide.distance) {
|
626
|
-
// Bind mousemove to target to detect distance difference
|
627
|
-
targets.show.add(tooltip).bind('mousemove'+namespace, function(event) {
|
628
|
-
var origin = cache.origin || {},
|
629
|
-
limit = options.hide.distance,
|
630
|
-
abs = Math.abs;
|
631
|
-
|
632
|
-
// Check if the movement has gone beyond the limit, and hide it if so
|
633
|
-
if(abs(event.pageX - origin.pageX) >= limit || abs(event.pageY - origin.pageY) >= limit) {
|
634
|
-
self.hide(event);
|
635
|
-
}
|
636
|
-
});
|
637
|
-
}
|
638
|
-
|
639
|
-
// Mouse positioning events
|
640
|
-
if(posOptions.target === 'mouse') {
|
641
|
-
// Cache mousemove coords on show targets
|
642
|
-
targets.show.bind('mousemove'+namespace, function(event) {
|
643
|
-
MOUSE = { pageX: event.pageX, pageY: event.pageY, type: 'mousemove' };
|
644
|
-
});
|
645
|
-
|
646
|
-
// If mouse adjustment is on...
|
647
|
-
if(posOptions.adjust.mouse) {
|
648
|
-
// Apply a mouseleave event so we don't get problems with overlapping
|
649
|
-
if(options.hide.event) {
|
650
|
-
// Hide when we leave the tooltip and not onto the show target
|
651
|
-
tooltip.bind('mouseleave'+namespace, function(event) {
|
652
|
-
if((event.relatedTarget || event.target) !== targets.show[0]) { self.hide(event); }
|
653
|
-
});
|
654
|
-
|
655
|
-
// Track if we're on the target or not
|
656
|
-
elements.target.bind('mouseenter'+namespace+' mouseleave'+namespace, function(event) {
|
657
|
-
cache.onTarget = event.type === 'mouseenter';
|
658
|
-
});
|
659
|
-
}
|
660
|
-
|
661
|
-
// Update tooltip position on mousemove
|
662
|
-
targets.document.bind('mousemove'+namespace, function(event) {
|
663
|
-
// Update the tooltip position only if the tooltip is visible and adjustment is enabled
|
664
|
-
if(self.rendered && cache.onTarget && !tooltip.hasClass(disabled) && tooltip[0].offsetWidth > 0) {
|
665
|
-
self.reposition(event || MOUSE);
|
666
|
-
}
|
667
|
-
});
|
668
|
-
}
|
669
|
-
}
|
670
|
-
|
671
|
-
// Adjust positions of the tooltip on window resize if enabled
|
672
|
-
if(posOptions.adjust.resize || targets.viewport.length) {
|
673
|
-
($.event.special.resize ? targets.viewport : targets.window).bind('resize'+namespace, repositionMethod);
|
674
|
-
}
|
675
|
-
|
676
|
-
// Adjust tooltip position on scroll if screen adjustment is enabled
|
677
|
-
if(targets.viewport.length || (IE6 && tooltip.css('position') === 'fixed')) {
|
678
|
-
targets.viewport.bind('scroll'+namespace, repositionMethod);
|
679
|
-
}
|
680
|
-
}
|
681
|
-
|
682
|
-
function unassignEvents()
|
683
|
-
{
|
684
|
-
var targets = [
|
685
|
-
options.show.target[0],
|
686
|
-
options.hide.target[0],
|
687
|
-
self.rendered && elements.tooltip[0],
|
688
|
-
options.position.container[0],
|
689
|
-
options.position.viewport[0],
|
690
|
-
window,
|
691
|
-
document
|
692
|
-
];
|
693
|
-
|
694
|
-
// Check if tooltip is rendered
|
695
|
-
if(self.rendered) {
|
696
|
-
$([]).pushStack( $.grep(targets, function(i){ return typeof i === 'object'; }) ).unbind(namespace);
|
697
|
-
}
|
698
|
-
|
699
|
-
// Tooltip isn't yet rendered, remove render event
|
700
|
-
else { options.show.target.unbind(namespace+'-create'); }
|
701
|
-
}
|
702
|
-
|
703
|
-
// Setup builtin .set() option checks
|
704
|
-
self.checks.builtin = {
|
705
|
-
// Core checks
|
706
|
-
'^id$': function(obj, o, v) {
|
707
|
-
var id = v === TRUE ? QTIP.nextid : v,
|
708
|
-
tooltipID = uitooltip + '-' + id;
|
709
|
-
|
710
|
-
if(id !== FALSE && id.length > 0 && !$('#'+tooltipID).length) {
|
711
|
-
tooltip[0].id = tooltipID;
|
712
|
-
elements.content[0].id = tooltipID + '-content';
|
713
|
-
elements.title[0].id = tooltipID + '-title';
|
714
|
-
}
|
715
|
-
},
|
716
|
-
|
717
|
-
// Content checks
|
718
|
-
'^content.text$': function(obj, o, v){ updateContent(v); },
|
719
|
-
'^content.title.text$': function(obj, o, v) {
|
720
|
-
// Remove title if content is null
|
721
|
-
if(!v) { return removeTitle(); }
|
722
|
-
|
723
|
-
// If title isn't already created, create it now and update
|
724
|
-
if(!elements.title && v) { createTitle(); }
|
725
|
-
updateTitle(v);
|
726
|
-
},
|
727
|
-
'^content.title.button$': function(obj, o, v){ updateButton(v); },
|
728
|
-
|
729
|
-
// Position checks
|
730
|
-
'^position.(my|at)$': function(obj, o, v){
|
731
|
-
// Parse new corner value into Corner objecct
|
732
|
-
if('string' === typeof v) {
|
733
|
-
obj[o] = new PLUGINS.Corner(v);
|
734
|
-
}
|
735
|
-
},
|
736
|
-
'^position.container$': function(obj, o, v){
|
737
|
-
if(self.rendered) { tooltip.appendTo(v); }
|
738
|
-
},
|
739
|
-
|
740
|
-
// Show checks
|
741
|
-
'^show.ready$': function() {
|
742
|
-
if(!self.rendered) { self.render(1); }
|
743
|
-
else { self.toggle(TRUE); }
|
744
|
-
},
|
745
|
-
|
746
|
-
// Style checks
|
747
|
-
'^style.classes$': function(obj, o, v) {
|
748
|
-
tooltip.attr('class', uitooltip + ' qtip ui-helper-reset ' + v);
|
749
|
-
},
|
750
|
-
'^style.widget|content.title': setWidget,
|
751
|
-
|
752
|
-
// Events check
|
753
|
-
'^events.(render|show|move|hide|focus|blur)$': function(obj, o, v) {
|
754
|
-
tooltip[($.isFunction(v) ? '' : 'un') + 'bind']('tooltip'+o, v);
|
755
|
-
},
|
756
|
-
|
757
|
-
// Properties which require event reassignment
|
758
|
-
'^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)': function() {
|
759
|
-
var posOptions = options.position;
|
760
|
-
|
761
|
-
// Set tracking flag
|
762
|
-
tooltip.attr('tracking', posOptions.target === 'mouse' && posOptions.adjust.mouse);
|
763
|
-
|
764
|
-
// Reassign events
|
765
|
-
unassignEvents(); assignEvents();
|
766
|
-
}
|
767
|
-
};
|
768
|
-
|
769
|
-
/*
|
770
|
-
* Public API methods
|
771
|
-
*/
|
772
|
-
$.extend(self, {
|
773
|
-
render: function(show)
|
774
|
-
{
|
775
|
-
if(self.rendered) { return self; } // If tooltip has already been rendered, exit
|
776
|
-
|
777
|
-
var text = options.content.text,
|
778
|
-
title = options.content.title.text,
|
779
|
-
posOptions = options.position,
|
780
|
-
callback = $.Event('tooltiprender');
|
781
|
-
|
782
|
-
// Add ARIA attributes to target
|
783
|
-
$.attr(target[0], 'aria-describedby', tooltipID);
|
784
|
-
|
785
|
-
// Create tooltip element
|
786
|
-
tooltip = elements.tooltip = $('<div/>', {
|
787
|
-
'id': tooltipID,
|
788
|
-
'class': uitooltip + ' qtip ui-helper-reset ' + defaultClass + ' ' + options.style.classes + ' '+ uitooltip + '-pos-' + options.position.my.abbrev(),
|
789
|
-
'width': options.style.width || '',
|
790
|
-
'height': options.style.height || '',
|
791
|
-
'tracking': posOptions.target === 'mouse' && posOptions.adjust.mouse,
|
792
|
-
|
793
|
-
/* ARIA specific attributes */
|
794
|
-
'role': 'alert',
|
795
|
-
'aria-live': 'polite',
|
796
|
-
'aria-atomic': FALSE,
|
797
|
-
'aria-describedby': tooltipID + '-content',
|
798
|
-
'aria-hidden': TRUE
|
799
|
-
})
|
800
|
-
.toggleClass(disabled, cache.disabled)
|
801
|
-
.data('qtip', self)
|
802
|
-
.appendTo(options.position.container)
|
803
|
-
.append(
|
804
|
-
// Create content element
|
805
|
-
elements.content = $('<div />', {
|
806
|
-
'class': uitooltip + '-content',
|
807
|
-
'id': tooltipID + '-content',
|
808
|
-
'aria-atomic': TRUE
|
809
|
-
})
|
810
|
-
);
|
811
|
-
|
812
|
-
// Set rendered flag and prevent redundant redraw/reposition calls for now
|
813
|
-
self.rendered = -1;
|
814
|
-
isDrawing = 1; isPositioning = 1;
|
815
|
-
|
816
|
-
// Create title...
|
817
|
-
if(title) {
|
818
|
-
createTitle();
|
819
|
-
|
820
|
-
// Update title only if its not a callback (called in toggle if so)
|
821
|
-
if(!$.isFunction(title)) { updateTitle(title, FALSE); }
|
822
|
-
}
|
823
|
-
|
824
|
-
// Set proper rendered flag and update content if not a callback function (called in toggle)
|
825
|
-
if(!$.isFunction(text)) { updateContent(text, FALSE); }
|
826
|
-
self.rendered = TRUE;
|
827
|
-
|
828
|
-
// Setup widget classes
|
829
|
-
setWidget();
|
830
|
-
|
831
|
-
// Assign passed event callbacks (before plugins!)
|
832
|
-
$.each(options.events, function(name, callback) {
|
833
|
-
if($.isFunction(callback)) {
|
834
|
-
tooltip.bind(name === 'toggle' ? 'tooltipshow tooltiphide' : 'tooltip'+name, callback);
|
835
|
-
}
|
836
|
-
});
|
837
|
-
|
838
|
-
// Initialize 'render' plugins
|
839
|
-
$.each(PLUGINS, function() {
|
840
|
-
if(this.initialize === 'render') { this(self); }
|
841
|
-
});
|
842
|
-
|
843
|
-
// Assign events
|
844
|
-
assignEvents();
|
845
|
-
|
846
|
-
/* Queue this part of the render process in our fx queue so we can
|
847
|
-
* load images before the tooltip renders fully.
|
848
|
-
*
|
849
|
-
* See: updateContent method
|
850
|
-
*/
|
851
|
-
tooltip.queue('fx', function(next) {
|
852
|
-
// Trigger tooltiprender event and pass original triggering event as original
|
853
|
-
callback.originalEvent = cache.event;
|
854
|
-
tooltip.trigger(callback, [self]);
|
855
|
-
|
856
|
-
// Reset flags
|
857
|
-
isDrawing = 0; isPositioning = 0;
|
858
|
-
|
859
|
-
// Redraw the tooltip manually now we're fully rendered
|
860
|
-
self.redraw();
|
861
|
-
|
862
|
-
// Show tooltip if needed
|
863
|
-
if(options.show.ready || show) {
|
864
|
-
self.toggle(TRUE, cache.event, FALSE);
|
865
|
-
}
|
866
|
-
|
867
|
-
next(); // Move on to next method in queue
|
868
|
-
});
|
869
|
-
|
870
|
-
return self;
|
871
|
-
},
|
872
|
-
|
873
|
-
get: function(notation)
|
874
|
-
{
|
875
|
-
var result, o;
|
876
|
-
|
877
|
-
switch(notation.toLowerCase())
|
878
|
-
{
|
879
|
-
case 'dimensions':
|
880
|
-
result = {
|
881
|
-
height: tooltip.outerHeight(), width: tooltip.outerWidth()
|
882
|
-
};
|
883
|
-
break;
|
884
|
-
|
885
|
-
case 'offset':
|
886
|
-
result = PLUGINS.offset(tooltip, options.position.container);
|
887
|
-
break;
|
888
|
-
|
889
|
-
default:
|
890
|
-
o = convertNotation(notation.toLowerCase());
|
891
|
-
result = o[0][ o[1] ];
|
892
|
-
result = result.precedance ? result.string() : result;
|
893
|
-
break;
|
894
|
-
}
|
895
|
-
|
896
|
-
return result;
|
897
|
-
},
|
898
|
-
|
899
|
-
set: function(option, value)
|
900
|
-
{
|
901
|
-
var rmove = /^position\.(my|at|adjust|target|container)|style|content|show\.ready/i,
|
902
|
-
rdraw = /^content\.(title|attr)|style/i,
|
903
|
-
reposition = FALSE,
|
904
|
-
redraw = FALSE,
|
905
|
-
checks = self.checks,
|
906
|
-
name;
|
907
|
-
|
908
|
-
function callback(notation, args) {
|
909
|
-
var category, rule, match;
|
910
|
-
|
911
|
-
for(category in checks) {
|
912
|
-
for(rule in checks[category]) {
|
913
|
-
if(match = (new RegExp(rule, 'i')).exec(notation)) {
|
914
|
-
args.push(match);
|
915
|
-
checks[category][rule].apply(self, args);
|
916
|
-
}
|
917
|
-
}
|
918
|
-
}
|
919
|
-
}
|
920
|
-
|
921
|
-
// Convert singular option/value pair into object form
|
922
|
-
if('string' === typeof option) {
|
923
|
-
name = option; option = {}; option[name] = value;
|
924
|
-
}
|
925
|
-
else { option = $.extend(TRUE, {}, option); }
|
926
|
-
|
927
|
-
// Set all of the defined options to their new values
|
928
|
-
$.each(option, function(notation, value) {
|
929
|
-
var obj = convertNotation( notation.toLowerCase() ), previous;
|
930
|
-
|
931
|
-
// Set new obj value
|
932
|
-
previous = obj[0][ obj[1] ];
|
933
|
-
obj[0][ obj[1] ] = 'object' === typeof value && value.nodeType ? $(value) : value;
|
934
|
-
|
935
|
-
// Set the new params for the callback
|
936
|
-
option[notation] = [obj[0], obj[1], value, previous];
|
937
|
-
|
938
|
-
// Also check if we need to reposition / redraw
|
939
|
-
reposition = rmove.test(notation) || reposition;
|
940
|
-
redraw = rdraw.test(notation) || redraw;
|
941
|
-
});
|
942
|
-
|
943
|
-
// Re-sanitize options
|
944
|
-
sanitizeOptions(options);
|
945
|
-
|
946
|
-
/*
|
947
|
-
* Execute any valid callbacks for the set options
|
948
|
-
* Also set isPositioning/isDrawing so we don't get loads of redundant repositioning
|
949
|
-
* and redraw calls.
|
950
|
-
*/
|
951
|
-
isPositioning = isDrawing = 1; $.each(option, callback); isPositioning = isDrawing = 0;
|
952
|
-
|
953
|
-
// Update position / redraw if needed
|
954
|
-
if(self.rendered && tooltip[0].offsetWidth > 0) {
|
955
|
-
if(reposition) {
|
956
|
-
self.reposition( options.position.target === 'mouse' ? NULL : cache.event );
|
957
|
-
}
|
958
|
-
if(redraw) { self.redraw(); }
|
959
|
-
}
|
960
|
-
|
961
|
-
return self;
|
962
|
-
},
|
963
|
-
|
964
|
-
toggle: function(state, event)
|
965
|
-
{
|
966
|
-
// Render the tooltip if showing and it isn't already
|
967
|
-
if(!self.rendered) { return state ? self.render(1) : self; }
|
968
|
-
|
969
|
-
var type = state ? 'show' : 'hide',
|
970
|
-
opts = options[type],
|
971
|
-
otherOpts = options[ !state ? 'show' : 'hide' ],
|
972
|
-
posOptions = options.position,
|
973
|
-
contentOptions = options.content,
|
974
|
-
visible = tooltip[0].offsetWidth > 0,
|
975
|
-
animate = state || opts.target.length === 1,
|
976
|
-
sameTarget = !event || opts.target.length < 2 || cache.target[0] === event.target,
|
977
|
-
delay, callback;
|
978
|
-
|
979
|
-
// Detect state if valid one isn't provided
|
980
|
-
if((typeof state).search('boolean|number')) { state = !visible; }
|
981
|
-
|
982
|
-
// Return if element is already in correct state
|
983
|
-
if(!tooltip.is(':animated') && visible === state && sameTarget) { return self; }
|
984
|
-
|
985
|
-
// Try to prevent flickering when tooltip overlaps show element
|
986
|
-
if(event) {
|
987
|
-
if((/over|enter/).test(event.type) && (/out|leave/).test(cache.event.type) &&
|
988
|
-
options.show.target.add(event.target).length === options.show.target.length &&
|
989
|
-
tooltip.has(event.relatedTarget).length) {
|
990
|
-
return self;
|
991
|
-
}
|
992
|
-
|
993
|
-
// Cache event
|
994
|
-
cache.event = $.extend({}, event);
|
995
|
-
}
|
996
|
-
|
997
|
-
// Call API methods
|
998
|
-
callback = $.Event('tooltip'+type);
|
999
|
-
callback.originalEvent = event ? cache.event : NULL;
|
1000
|
-
tooltip.trigger(callback, [self, 90]);
|
1001
|
-
if(callback.isDefaultPrevented()){ return self; }
|
1002
|
-
|
1003
|
-
// Set ARIA hidden status attribute
|
1004
|
-
$.attr(tooltip[0], 'aria-hidden', !!!state);
|
1005
|
-
|
1006
|
-
// Execute state specific properties
|
1007
|
-
if(state) {
|
1008
|
-
// Store show origin coordinates
|
1009
|
-
cache.origin = $.extend({}, MOUSE);
|
1010
|
-
|
1011
|
-
// Focus the tooltip
|
1012
|
-
self.focus(event);
|
1013
|
-
|
1014
|
-
// Update tooltip content & title if it's a dynamic function
|
1015
|
-
if($.isFunction(contentOptions.text)) { updateContent(contentOptions.text, FALSE); }
|
1016
|
-
if($.isFunction(contentOptions.title.text)) { updateTitle(contentOptions.title.text, FALSE); }
|
1017
|
-
|
1018
|
-
// Cache mousemove events for positioning purposes (if not already tracking)
|
1019
|
-
if(!trackingBound && posOptions.target === 'mouse' && posOptions.adjust.mouse) {
|
1020
|
-
$(document).bind('mousemove.qtip', function(event) {
|
1021
|
-
MOUSE = { pageX: event.pageX, pageY: event.pageY, type: 'mousemove' };
|
1022
|
-
});
|
1023
|
-
trackingBound = TRUE;
|
1024
|
-
}
|
1025
|
-
|
1026
|
-
// Update the tooltip position
|
1027
|
-
self.reposition(event, arguments[2]);
|
1028
|
-
|
1029
|
-
// Hide other tooltips if tooltip is solo, using it as the context
|
1030
|
-
if((callback.solo = !!opts.solo)) { $(selector, opts.solo).not(tooltip).qtip('hide', callback); }
|
1031
|
-
}
|
1032
|
-
else {
|
1033
|
-
// Clear show timer if we're hiding
|
1034
|
-
clearTimeout(self.timers.show);
|
1035
|
-
|
1036
|
-
// Remove cached origin on hide
|
1037
|
-
delete cache.origin;
|
1038
|
-
|
1039
|
-
// Remove mouse tracking event if not needed (all tracking qTips are hidden)
|
1040
|
-
if(trackingBound && !$(selector+'[tracking="true"]:visible', opts.solo).not(tooltip).length) {
|
1041
|
-
$(document).unbind('mousemove.qtip');
|
1042
|
-
trackingBound = FALSE;
|
1043
|
-
}
|
1044
|
-
|
1045
|
-
// Blur the tooltip
|
1046
|
-
self.blur(event);
|
1047
|
-
}
|
1048
|
-
|
1049
|
-
// Define post-animation, state specific properties
|
1050
|
-
function after() {
|
1051
|
-
if(state) {
|
1052
|
-
// Prevent antialias from disappearing in IE by removing filter
|
1053
|
-
if($.browser.msie) { tooltip[0].style.removeAttribute('filter'); }
|
1054
|
-
|
1055
|
-
// Remove overflow setting to prevent tip bugs
|
1056
|
-
tooltip.css('overflow', '');
|
1057
|
-
|
1058
|
-
// Autofocus elements if enabled
|
1059
|
-
if('string' === typeof opts.autofocus) {
|
1060
|
-
$(opts.autofocus, tooltip).focus();
|
1061
|
-
}
|
1062
|
-
|
1063
|
-
// If set, hide tooltip when inactive for delay period
|
1064
|
-
opts.target.trigger('qtip-'+id+'-inactive');
|
1065
|
-
}
|
1066
|
-
else {
|
1067
|
-
// Reset CSS states
|
1068
|
-
tooltip.css({
|
1069
|
-
display: '',
|
1070
|
-
visibility: '',
|
1071
|
-
opacity: '',
|
1072
|
-
left: '',
|
1073
|
-
top: ''
|
1074
|
-
});
|
1075
|
-
}
|
1076
|
-
|
1077
|
-
// Call API method
|
1078
|
-
callback = $.Event('tooltip'+(state ? 'visible' : 'hidden'));
|
1079
|
-
callback.originalEvent = event ? cache.event : NULL;
|
1080
|
-
tooltip.trigger(callback, [self]);
|
1081
|
-
}
|
1082
|
-
|
1083
|
-
// If no effect type is supplied, use a simple toggle
|
1084
|
-
if(opts.effect === FALSE || animate === FALSE) {
|
1085
|
-
tooltip[ type ]();
|
1086
|
-
after.call(tooltip);
|
1087
|
-
}
|
1088
|
-
|
1089
|
-
// Use custom function if provided
|
1090
|
-
else if($.isFunction(opts.effect)) {
|
1091
|
-
tooltip.stop(1, 1);
|
1092
|
-
opts.effect.call(tooltip, self);
|
1093
|
-
tooltip.queue('fx', function(n){ after(); n(); });
|
1094
|
-
}
|
1095
|
-
|
1096
|
-
// Use basic fade function by default
|
1097
|
-
else { tooltip.fadeTo(90, state ? 1 : 0, after); }
|
1098
|
-
|
1099
|
-
// If inactive hide method is set, active it
|
1100
|
-
if(state) { opts.target.trigger('qtip-'+id+'-inactive'); }
|
1101
|
-
|
1102
|
-
return self;
|
1103
|
-
},
|
1104
|
-
|
1105
|
-
show: function(event){ return self.toggle(TRUE, event); },
|
1106
|
-
|
1107
|
-
hide: function(event){ return self.toggle(FALSE, event); },
|
1108
|
-
|
1109
|
-
focus: function(event)
|
1110
|
-
{
|
1111
|
-
if(!self.rendered) { return self; }
|
1112
|
-
|
1113
|
-
var qtips = $(selector),
|
1114
|
-
curIndex = parseInt(tooltip[0].style.zIndex, 10),
|
1115
|
-
newIndex = QTIP.zindex + qtips.length,
|
1116
|
-
cachedEvent = $.extend({}, event),
|
1117
|
-
focusedElem, callback;
|
1118
|
-
|
1119
|
-
// Only update the z-index if it has changed and tooltip is not already focused
|
1120
|
-
if(!tooltip.hasClass(focusClass))
|
1121
|
-
{
|
1122
|
-
// Call API method
|
1123
|
-
callback = $.Event('tooltipfocus');
|
1124
|
-
callback.originalEvent = cachedEvent;
|
1125
|
-
tooltip.trigger(callback, [self, newIndex]);
|
1126
|
-
|
1127
|
-
// If default action wasn't prevented...
|
1128
|
-
if(!callback.isDefaultPrevented()) {
|
1129
|
-
// Only update z-index's if they've changed
|
1130
|
-
if(curIndex !== newIndex) {
|
1131
|
-
// Reduce our z-index's and keep them properly ordered
|
1132
|
-
qtips.each(function() {
|
1133
|
-
if(this.style.zIndex > curIndex) {
|
1134
|
-
this.style.zIndex = this.style.zIndex - 1;
|
1135
|
-
}
|
1136
|
-
});
|
1137
|
-
|
1138
|
-
// Fire blur event for focused tooltip
|
1139
|
-
qtips.filter('.' + focusClass).qtip('blur', cachedEvent);
|
1140
|
-
}
|
1141
|
-
|
1142
|
-
// Set the new z-index
|
1143
|
-
tooltip.addClass(focusClass)[0].style.zIndex = newIndex;
|
1144
|
-
}
|
1145
|
-
}
|
1146
|
-
|
1147
|
-
return self;
|
1148
|
-
},
|
1149
|
-
|
1150
|
-
blur: function(event) {
|
1151
|
-
var cachedEvent = $.extend({}, event),
|
1152
|
-
callback;
|
1153
|
-
|
1154
|
-
// Set focused status to FALSE
|
1155
|
-
tooltip.removeClass(focusClass);
|
1156
|
-
|
1157
|
-
// Trigger blur event
|
1158
|
-
callback = $.Event('tooltipblur');
|
1159
|
-
callback.originalEvent = cachedEvent;
|
1160
|
-
tooltip.trigger(callback, [self]);
|
1161
|
-
|
1162
|
-
return self;
|
1163
|
-
},
|
1164
|
-
|
1165
|
-
reposition: function(event, effect)
|
1166
|
-
{
|
1167
|
-
if(!self.rendered || isPositioning) { return self; }
|
1168
|
-
|
1169
|
-
// Set positioning flag
|
1170
|
-
isPositioning = 1;
|
1171
|
-
|
1172
|
-
var target = options.position.target,
|
1173
|
-
posOptions = options.position,
|
1174
|
-
my = posOptions.my,
|
1175
|
-
at = posOptions.at,
|
1176
|
-
adjust = posOptions.adjust,
|
1177
|
-
method = adjust.method.split(' '),
|
1178
|
-
elemWidth = tooltip.outerWidth(),
|
1179
|
-
elemHeight = tooltip.outerHeight(),
|
1180
|
-
targetWidth = 0,
|
1181
|
-
targetHeight = 0,
|
1182
|
-
callback = $.Event('tooltipmove'),
|
1183
|
-
fixed = tooltip.css('position') === 'fixed',
|
1184
|
-
viewport = posOptions.viewport,
|
1185
|
-
position = { left: 0, top: 0 },
|
1186
|
-
container = posOptions.container,
|
1187
|
-
visible = tooltip[0].offsetWidth > 0,
|
1188
|
-
adjusted, offset, win;
|
1189
|
-
|
1190
|
-
// Check if absolute position was passed
|
1191
|
-
if($.isArray(target) && target.length === 2) {
|
1192
|
-
// Force left top and set position
|
1193
|
-
at = { x: LEFT, y: TOP };
|
1194
|
-
position = { left: target[0], top: target[1] };
|
1195
|
-
}
|
1196
|
-
|
1197
|
-
// Check if mouse was the target
|
1198
|
-
else if(target === 'mouse' && ((event && event.pageX) || cache.event.pageX)) {
|
1199
|
-
// Force left top to allow flipping
|
1200
|
-
at = { x: LEFT, y: TOP };
|
1201
|
-
|
1202
|
-
// Use cached event if one isn't available for positioning
|
1203
|
-
event = (event && (event.type === 'resize' || event.type === 'scroll') ? cache.event :
|
1204
|
-
event && event.pageX && event.type === 'mousemove' ? event :
|
1205
|
-
MOUSE && MOUSE.pageX && (adjust.mouse || !event || !event.pageX) ? { pageX: MOUSE.pageX, pageY: MOUSE.pageY } :
|
1206
|
-
!adjust.mouse && cache.origin && cache.origin.pageX && options.show.distance ? cache.origin :
|
1207
|
-
event) || event || cache.event || MOUSE || {};
|
1208
|
-
|
1209
|
-
// Use event coordinates for position
|
1210
|
-
position = { top: event.pageY, left: event.pageX };
|
1211
|
-
}
|
1212
|
-
|
1213
|
-
// Target wasn't mouse or absolute...
|
1214
|
-
else {
|
1215
|
-
// Check if event targetting is being used
|
1216
|
-
if(target === 'event' && event && event.target && event.type !== 'scroll' && event.type !== 'resize') {
|
1217
|
-
cache.target = $(event.target);
|
1218
|
-
}
|
1219
|
-
else if(target !== 'event'){
|
1220
|
-
cache.target = $(target.jquery ? target : elements.target);
|
1221
|
-
}
|
1222
|
-
target = cache.target;
|
1223
|
-
|
1224
|
-
// Parse the target into a jQuery object and make sure there's an element present
|
1225
|
-
target = $(target).eq(0);
|
1226
|
-
if(target.length === 0) { return self; }
|
1227
|
-
|
1228
|
-
// Check if window or document is the target
|
1229
|
-
else if(target[0] === document || target[0] === window) {
|
1230
|
-
targetWidth = PLUGINS.iOS ? window.innerWidth : target.width();
|
1231
|
-
targetHeight = PLUGINS.iOS ? window.innerHeight : target.height();
|
1232
|
-
|
1233
|
-
if(target[0] === window) {
|
1234
|
-
position = {
|
1235
|
-
top: (viewport || target).scrollTop(),
|
1236
|
-
left: (viewport || target).scrollLeft()
|
1237
|
-
};
|
1238
|
-
}
|
1239
|
-
}
|
1240
|
-
|
1241
|
-
// Use Imagemap/SVG plugins if needed
|
1242
|
-
else if(PLUGINS.imagemap && target.is('area')) {
|
1243
|
-
adjusted = PLUGINS.imagemap(self, target, at, PLUGINS.viewport ? method : FALSE);
|
1244
|
-
}
|
1245
|
-
else if(PLUGINS.svg && typeof target[0].xmlbase === 'string') {
|
1246
|
-
adjusted = PLUGINS.svg(self, target, at, PLUGINS.viewport ? method : FALSE);
|
1247
|
-
}
|
1248
|
-
|
1249
|
-
else {
|
1250
|
-
targetWidth = target.outerWidth();
|
1251
|
-
targetHeight = target.outerHeight();
|
1252
|
-
|
1253
|
-
position = PLUGINS.offset(target, container);
|
1254
|
-
}
|
1255
|
-
|
1256
|
-
// Parse returned plugin values into proper variables
|
1257
|
-
if(adjusted) {
|
1258
|
-
targetWidth = adjusted.width;
|
1259
|
-
targetHeight = adjusted.height;
|
1260
|
-
offset = adjusted.offset;
|
1261
|
-
position = adjusted.position;
|
1262
|
-
}
|
1263
|
-
|
1264
|
-
// Adjust for position.fixed tooltips (and also iOS scroll bug in v3.2-4.0 & v4.3-4.3.2)
|
1265
|
-
if((PLUGINS.iOS > 3.1 && PLUGINS.iOS < 4.1) ||
|
1266
|
-
(PLUGINS.iOS >= 4.3 && PLUGINS.iOS < 4.33) ||
|
1267
|
-
(!PLUGINS.iOS && fixed)
|
1268
|
-
){
|
1269
|
-
win = $(window);
|
1270
|
-
position.left -= win.scrollLeft();
|
1271
|
-
position.top -= win.scrollTop();
|
1272
|
-
}
|
1273
|
-
|
1274
|
-
// Adjust position relative to target
|
1275
|
-
position.left += at.x === RIGHT ? targetWidth : at.x === CENTER ? targetWidth / 2 : 0;
|
1276
|
-
position.top += at.y === BOTTOM ? targetHeight : at.y === CENTER ? targetHeight / 2 : 0;
|
1277
|
-
}
|
1278
|
-
|
1279
|
-
// Adjust position relative to tooltip
|
1280
|
-
position.left += adjust.x + (my.x === RIGHT ? -elemWidth : my.x === CENTER ? -elemWidth / 2 : 0);
|
1281
|
-
position.top += adjust.y + (my.y === BOTTOM ? -elemHeight : my.y === CENTER ? -elemHeight / 2 : 0);
|
1282
|
-
|
1283
|
-
// Use viewport adjustment plugin if enabled
|
1284
|
-
if(PLUGINS.viewport) {
|
1285
|
-
position.adjusted = PLUGINS.viewport(
|
1286
|
-
self, position, posOptions, targetWidth, targetHeight, elemWidth, elemHeight
|
1287
|
-
);
|
1288
|
-
|
1289
|
-
// Apply offsets supplied by positioning plugin (if used)
|
1290
|
-
if(offset && position.adjusted.left) { position.left += offset.left; }
|
1291
|
-
if(offset && position.adjusted.top) { position.top += offset.top; }
|
1292
|
-
}
|
1293
|
-
|
1294
|
-
// Viewport adjustment is disabled, set values to zero
|
1295
|
-
else { position.adjusted = { left: 0, top: 0 }; }
|
1296
|
-
|
1297
|
-
// Call API method
|
1298
|
-
callback.originalEvent = $.extend({}, event);
|
1299
|
-
tooltip.trigger(callback, [self, position, viewport.elem || viewport]);
|
1300
|
-
if(callback.isDefaultPrevented()){ return self; }
|
1301
|
-
delete position.adjusted;
|
1302
|
-
|
1303
|
-
// If effect is disabled, target it mouse, no animation is defined or positioning gives NaN out, set CSS directly
|
1304
|
-
if(effect === FALSE || !visible || isNaN(position.left) || isNaN(position.top) || target === 'mouse' || !$.isFunction(posOptions.effect)) {
|
1305
|
-
tooltip.css(position);
|
1306
|
-
}
|
1307
|
-
|
1308
|
-
// Use custom function if provided
|
1309
|
-
else if($.isFunction(posOptions.effect)) {
|
1310
|
-
posOptions.effect.call(tooltip, self, $.extend({}, position));
|
1311
|
-
tooltip.queue(function(next) {
|
1312
|
-
// Reset attributes to avoid cross-browser rendering bugs
|
1313
|
-
$(this).css({ opacity: '', height: '' });
|
1314
|
-
if($.browser.msie) { this.style.removeAttribute('filter'); }
|
1315
|
-
|
1316
|
-
next();
|
1317
|
-
});
|
1318
|
-
}
|
1319
|
-
|
1320
|
-
// Set positioning flag
|
1321
|
-
isPositioning = 0;
|
1322
|
-
|
1323
|
-
return self;
|
1324
|
-
},
|
1325
|
-
|
1326
|
-
// Max/min width simulator function for all browsers.. yeaaah!
|
1327
|
-
redraw: function()
|
1328
|
-
{
|
1329
|
-
if(self.rendered < 1 || isDrawing) { return self; }
|
1330
|
-
|
1331
|
-
var container = options.position.container,
|
1332
|
-
perc, width, max, min;
|
1333
|
-
|
1334
|
-
// Set drawing flag
|
1335
|
-
isDrawing = 1;
|
1336
|
-
|
1337
|
-
// If tooltip has a set height, just set it... like a boss!
|
1338
|
-
if(options.style.height) { tooltip.css(HEIGHT, options.style.height); }
|
1339
|
-
|
1340
|
-
// If tooltip has a set width, just set it... like a boss!
|
1341
|
-
if(options.style.width) { tooltip.css(WIDTH, options.style.width); }
|
1342
|
-
|
1343
|
-
// Otherwise simualte max/min width...
|
1344
|
-
else {
|
1345
|
-
// Reset width and add fluid class
|
1346
|
-
tooltip.css(WIDTH, '').addClass(fluidClass);
|
1347
|
-
|
1348
|
-
// Grab our tooltip width (add 1 so we don't get wrapping problems.. huzzah!)
|
1349
|
-
width = tooltip.width() + 1;
|
1350
|
-
|
1351
|
-
// Grab our max/min properties
|
1352
|
-
max = tooltip.css('max-width') || '';
|
1353
|
-
min = tooltip.css('min-width') || '';
|
1354
|
-
|
1355
|
-
// Parse into proper pixel values
|
1356
|
-
perc = (max + min).indexOf('%') > -1 ? container.width() / 100 : 0;
|
1357
|
-
max = ((max.indexOf('%') > -1 ? perc : 1) * parseInt(max, 10)) || width;
|
1358
|
-
min = ((min.indexOf('%') > -1 ? perc : 1) * parseInt(min, 10)) || 0;
|
1359
|
-
|
1360
|
-
// Determine new dimension size based on max/min/current values
|
1361
|
-
width = max + min ? Math.min(Math.max(width, min), max) : width;
|
1362
|
-
|
1363
|
-
// Set the newly calculated width and remvoe fluid class
|
1364
|
-
tooltip.css(WIDTH, Math.round(width)).removeClass(fluidClass);
|
1365
|
-
}
|
1366
|
-
|
1367
|
-
// Set drawing flag
|
1368
|
-
isDrawing = 0;
|
1369
|
-
|
1370
|
-
return self;
|
1371
|
-
},
|
1372
|
-
|
1373
|
-
disable: function(state)
|
1374
|
-
{
|
1375
|
-
if('boolean' !== typeof state) {
|
1376
|
-
state = !(tooltip.hasClass(disabled) || cache.disabled);
|
1377
|
-
}
|
1378
|
-
|
1379
|
-
if(self.rendered) {
|
1380
|
-
tooltip.toggleClass(disabled, state);
|
1381
|
-
$.attr(tooltip[0], 'aria-disabled', state);
|
1382
|
-
}
|
1383
|
-
else {
|
1384
|
-
cache.disabled = !!state;
|
1385
|
-
}
|
1386
|
-
|
1387
|
-
return self;
|
1388
|
-
},
|
1389
|
-
|
1390
|
-
enable: function() { return self.disable(FALSE); },
|
1391
|
-
|
1392
|
-
destroy: function()
|
1393
|
-
{
|
1394
|
-
var t = target[0],
|
1395
|
-
title = $.attr(t, oldtitle),
|
1396
|
-
elemAPI = target.data('qtip');
|
1397
|
-
|
1398
|
-
// Set flag the signify destroy is taking place to plugins
|
1399
|
-
self.destroyed = TRUE;
|
1400
|
-
|
1401
|
-
// Destroy tooltip and any associated plugins if rendered
|
1402
|
-
if(self.rendered) {
|
1403
|
-
tooltip.stop(1,0).remove();
|
1404
|
-
|
1405
|
-
$.each(self.plugins, function() {
|
1406
|
-
if(this.destroy) { this.destroy(); }
|
1407
|
-
});
|
1408
|
-
}
|
1409
|
-
|
1410
|
-
// Clear timers and remove bound events
|
1411
|
-
clearTimeout(self.timers.show);
|
1412
|
-
clearTimeout(self.timers.hide);
|
1413
|
-
unassignEvents();
|
1414
|
-
|
1415
|
-
// If the API if actually this qTip API...
|
1416
|
-
if(!elemAPI || self === elemAPI) {
|
1417
|
-
// Remove api object
|
1418
|
-
$.removeData(t, 'qtip');
|
1419
|
-
|
1420
|
-
// Reset old title attribute if removed
|
1421
|
-
if(options.suppress && title) {
|
1422
|
-
$.attr(t, 'title', title);
|
1423
|
-
target.removeAttr(oldtitle);
|
1424
|
-
}
|
1425
|
-
|
1426
|
-
// Remove ARIA attributes
|
1427
|
-
target.removeAttr('aria-describedby');
|
1428
|
-
}
|
1429
|
-
|
1430
|
-
// Remove qTip events associated with this API
|
1431
|
-
target.unbind('.qtip-'+id);
|
1432
|
-
|
1433
|
-
// Remove ID from sued id object
|
1434
|
-
delete usedIDs[self.id];
|
1435
|
-
|
1436
|
-
return target;
|
1437
|
-
}
|
1438
|
-
});
|
1439
|
-
}
|
1440
|
-
|
1441
|
-
// Initialization method
|
1442
|
-
function init(id, opts)
|
1443
|
-
{
|
1444
|
-
var obj, posOptions, attr, config, title,
|
1445
|
-
|
1446
|
-
// Setup element references
|
1447
|
-
elem = $(this),
|
1448
|
-
docBody = $(document.body),
|
1449
|
-
|
1450
|
-
// Use document body instead of document element if needed
|
1451
|
-
newTarget = this === document ? docBody : elem,
|
1452
|
-
|
1453
|
-
// Grab metadata from element if plugin is present
|
1454
|
-
metadata = (elem.metadata) ? elem.metadata(opts.metadata) : NULL,
|
1455
|
-
|
1456
|
-
// If metadata type if HTML5, grab 'name' from the object instead, or use the regular data object otherwise
|
1457
|
-
metadata5 = opts.metadata.type === 'html5' && metadata ? metadata[opts.metadata.name] : NULL,
|
1458
|
-
|
1459
|
-
// Grab data from metadata.name (or data-qtipopts as fallback) using .data() method,
|
1460
|
-
html5 = elem.data(opts.metadata.name || 'qtipopts');
|
1461
|
-
|
1462
|
-
// If we don't get an object returned attempt to parse it manualyl without parseJSON
|
1463
|
-
try { html5 = typeof html5 === 'string' ? (new Function("return " + html5))() : html5; }
|
1464
|
-
catch(e) { log('Unable to parse HTML5 attribute data: ' + html5); }
|
1465
|
-
|
1466
|
-
// Merge in and sanitize metadata
|
1467
|
-
config = $.extend(TRUE, {}, QTIP.defaults, opts,
|
1468
|
-
typeof html5 === 'object' ? sanitizeOptions(html5) : NULL,
|
1469
|
-
sanitizeOptions(metadata5 || metadata));
|
1470
|
-
|
1471
|
-
// Re-grab our positioning options now we've merged our metadata and set id to passed value
|
1472
|
-
posOptions = config.position;
|
1473
|
-
config.id = id;
|
1474
|
-
|
1475
|
-
// Setup missing content if none is detected
|
1476
|
-
if('boolean' === typeof config.content.text) {
|
1477
|
-
attr = elem.attr(config.content.attr);
|
1478
|
-
|
1479
|
-
// Grab from supplied attribute if available
|
1480
|
-
if(config.content.attr !== FALSE && attr) { config.content.text = attr; }
|
1481
|
-
|
1482
|
-
// No valid content was found, abort render
|
1483
|
-
else {
|
1484
|
-
log('Unable to locate content for tooltip! Aborting render of tooltip on element: ', elem);
|
1485
|
-
return FALSE;
|
1486
|
-
}
|
1487
|
-
}
|
1488
|
-
|
1489
|
-
// Setup target options
|
1490
|
-
if(!posOptions.container.length) { posOptions.container = docBody; }
|
1491
|
-
if(posOptions.target === FALSE) { posOptions.target = newTarget; }
|
1492
|
-
if(config.show.target === FALSE) { config.show.target = newTarget; }
|
1493
|
-
if(config.show.solo === TRUE) { config.show.solo = posOptions.container.closest('body'); }
|
1494
|
-
if(config.hide.target === FALSE) { config.hide.target = newTarget; }
|
1495
|
-
if(config.position.viewport === TRUE) { config.position.viewport = posOptions.container; }
|
1496
|
-
|
1497
|
-
// Ensure we only use a single container
|
1498
|
-
posOptions.container = posOptions.container.eq(0);
|
1499
|
-
|
1500
|
-
// Convert position corner values into x and y strings
|
1501
|
-
posOptions.at = new PLUGINS.Corner(posOptions.at);
|
1502
|
-
posOptions.my = new PLUGINS.Corner(posOptions.my);
|
1503
|
-
|
1504
|
-
// Destroy previous tooltip if overwrite is enabled, or skip element if not
|
1505
|
-
if($.data(this, 'qtip')) {
|
1506
|
-
if(config.overwrite) {
|
1507
|
-
elem.qtip('destroy');
|
1508
|
-
}
|
1509
|
-
else if(config.overwrite === FALSE) {
|
1510
|
-
return FALSE;
|
1511
|
-
}
|
1512
|
-
}
|
1513
|
-
|
1514
|
-
// Remove title attribute and store it if present
|
1515
|
-
if(config.suppress && (title = $.attr(this, 'title'))) {
|
1516
|
-
// Final attr call fixes event delegatiom and IE default tooltip showing problem
|
1517
|
-
$(this).removeAttr('title').attr(oldtitle, title).attr('title', '');
|
1518
|
-
}
|
1519
|
-
|
1520
|
-
// Initialize the tooltip and add API reference
|
1521
|
-
obj = new QTip(elem, config, id, !!attr);
|
1522
|
-
$.data(this, 'qtip', obj);
|
1523
|
-
|
1524
|
-
// Catch remove/removeqtip events on target element to destroy redundant tooltip
|
1525
|
-
elem.bind('remove.qtip-'+id+' removeqtip.qtip-'+id, function(){ obj.destroy(); });
|
1526
|
-
|
1527
|
-
return obj;
|
1528
|
-
}
|
1529
|
-
|
1530
|
-
// jQuery $.fn extension method
|
1531
|
-
QTIP = $.fn.qtip = function(options, notation, newValue)
|
1532
|
-
{
|
1533
|
-
var command = ('' + options).toLowerCase(), // Parse command
|
1534
|
-
returned = NULL,
|
1535
|
-
args = $.makeArray(arguments).slice(1),
|
1536
|
-
event = args[args.length - 1],
|
1537
|
-
opts = this[0] ? $.data(this[0], 'qtip') : NULL;
|
1538
|
-
|
1539
|
-
// Check for API request
|
1540
|
-
if((!arguments.length && opts) || command === 'api') {
|
1541
|
-
return opts;
|
1542
|
-
}
|
1543
|
-
|
1544
|
-
// Execute API command if present
|
1545
|
-
else if('string' === typeof options)
|
1546
|
-
{
|
1547
|
-
this.each(function()
|
1548
|
-
{
|
1549
|
-
var api = $.data(this, 'qtip');
|
1550
|
-
if(!api) { return TRUE; }
|
1551
|
-
|
1552
|
-
// Cache the event if possible
|
1553
|
-
if(event && event.timeStamp) { api.cache.event = event; }
|
1554
|
-
|
1555
|
-
// Check for specific API commands
|
1556
|
-
if((command === 'option' || command === 'options') && notation) {
|
1557
|
-
if($.isPlainObject(notation) || newValue !== undefined) {
|
1558
|
-
api.set(notation, newValue);
|
1559
|
-
}
|
1560
|
-
else {
|
1561
|
-
returned = api.get(notation);
|
1562
|
-
return FALSE;
|
1563
|
-
}
|
1564
|
-
}
|
1565
|
-
|
1566
|
-
// Execute API command
|
1567
|
-
else if(api[command]) {
|
1568
|
-
api[command].apply(api[command], args);
|
1569
|
-
}
|
1570
|
-
});
|
1571
|
-
|
1572
|
-
return returned !== NULL ? returned : this;
|
1573
|
-
}
|
1574
|
-
|
1575
|
-
// No API commands. validate provided options and setup qTips
|
1576
|
-
else if('object' === typeof options || !arguments.length)
|
1577
|
-
{
|
1578
|
-
opts = sanitizeOptions($.extend(TRUE, {}, options));
|
1579
|
-
|
1580
|
-
// Bind the qTips
|
1581
|
-
return QTIP.bind.call(this, opts, event);
|
1582
|
-
}
|
1583
|
-
};
|
1584
|
-
|
1585
|
-
// $.fn.qtip Bind method
|
1586
|
-
QTIP.bind = function(opts, event)
|
1587
|
-
{
|
1588
|
-
return this.each(function(i) {
|
1589
|
-
var options, targets, events, namespace, api, id;
|
1590
|
-
|
1591
|
-
// Find next available ID, or use custom ID if provided
|
1592
|
-
id = $.isArray(opts.id) ? opts.id[i] : opts.id;
|
1593
|
-
id = !id || id === FALSE || id.length < 1 || usedIDs[id] ? QTIP.nextid++ : (usedIDs[id] = id);
|
1594
|
-
|
1595
|
-
// Setup events namespace
|
1596
|
-
namespace = '.qtip-'+id+'-create';
|
1597
|
-
|
1598
|
-
// Initialize the qTip and re-grab newly sanitized options
|
1599
|
-
api = init.call(this, id, opts);
|
1600
|
-
if(api === FALSE) { return TRUE; }
|
1601
|
-
options = api.options;
|
1602
|
-
|
1603
|
-
// Initialize plugins
|
1604
|
-
$.each(PLUGINS, function() {
|
1605
|
-
if(this.initialize === 'initialize') { this(api); }
|
1606
|
-
});
|
1607
|
-
|
1608
|
-
// Determine hide and show targets
|
1609
|
-
targets = { show: options.show.target, hide: options.hide.target };
|
1610
|
-
events = {
|
1611
|
-
show: $.trim('' + options.show.event).replace(/ /g, namespace+' ') + namespace,
|
1612
|
-
hide: $.trim('' + options.hide.event).replace(/ /g, namespace+' ') + namespace
|
1613
|
-
};
|
1614
|
-
|
1615
|
-
/*
|
1616
|
-
* Make sure hoverIntent functions properly by using mouseleave as a hide event if
|
1617
|
-
* mouseenter/mouseout is used for show.event, even if it isn't in the users options.
|
1618
|
-
*/
|
1619
|
-
if(/mouse(over|enter)/i.test(events.show) && !/mouse(out|leave)/i.test(events.hide)) {
|
1620
|
-
events.hide += ' mouseleave' + namespace;
|
1621
|
-
}
|
1622
|
-
|
1623
|
-
/*
|
1624
|
-
* Also make sure initial mouse targetting works correctly by caching mousemove coords
|
1625
|
-
* on show targets before the tooltip has rendered.
|
1626
|
-
*
|
1627
|
-
* Also set onTarget when triggered to keep mouse tracking working
|
1628
|
-
*/
|
1629
|
-
targets.show.bind('mousemove'+namespace, function(event) {
|
1630
|
-
MOUSE = { pageX: event.pageX, pageY: event.pageY, type: 'mousemove' };
|
1631
|
-
api.cache.onTarget = TRUE;
|
1632
|
-
});
|
1633
|
-
|
1634
|
-
// Define hoverIntent function
|
1635
|
-
function hoverIntent(event) {
|
1636
|
-
function render() {
|
1637
|
-
// Cache mouse coords,render and render the tooltip
|
1638
|
-
api.render(typeof event === 'object' || options.show.ready);
|
1639
|
-
|
1640
|
-
// Unbind show and hide events
|
1641
|
-
targets.show.add(targets.hide).unbind(namespace);
|
1642
|
-
}
|
1643
|
-
|
1644
|
-
// Only continue if tooltip isn't disabled
|
1645
|
-
if(api.cache.disabled) { return FALSE; }
|
1646
|
-
|
1647
|
-
// Cache the event data
|
1648
|
-
api.cache.event = $.extend({}, event);
|
1649
|
-
api.cache.target = event ? $(event.target) : [undefined];
|
1650
|
-
|
1651
|
-
// Start the event sequence
|
1652
|
-
if(options.show.delay > 0) {
|
1653
|
-
clearTimeout(api.timers.show);
|
1654
|
-
api.timers.show = setTimeout(render, options.show.delay);
|
1655
|
-
if(events.show !== events.hide) {
|
1656
|
-
targets.hide.bind(events.hide, function() { clearTimeout(api.timers.show); });
|
1657
|
-
}
|
1658
|
-
}
|
1659
|
-
else { render(); }
|
1660
|
-
}
|
1661
|
-
|
1662
|
-
// Bind show events to target
|
1663
|
-
targets.show.bind(events.show, hoverIntent);
|
1664
|
-
|
1665
|
-
// Prerendering is enabled, create tooltip now
|
1666
|
-
if(options.show.ready || options.prerender) { hoverIntent(event); }
|
1667
|
-
});
|
1668
|
-
};
|
1669
|
-
|
1670
|
-
// Setup base plugins
|
1671
|
-
PLUGINS = QTIP.plugins = {
|
1672
|
-
// Corner object parser
|
1673
|
-
Corner: function(corner) {
|
1674
|
-
corner = ('' + corner).replace(/([A-Z])/, ' $1').replace(/middle/gi, CENTER).toLowerCase();
|
1675
|
-
this.x = (corner.match(/left|right/i) || corner.match(/center/) || ['inherit'])[0].toLowerCase();
|
1676
|
-
this.y = (corner.match(/top|bottom|center/i) || ['inherit'])[0].toLowerCase();
|
1677
|
-
|
1678
|
-
var f = corner.charAt(0); this.precedance = (f === 't' || f === 'b' ? Y : X);
|
1679
|
-
|
1680
|
-
this.string = function() { return this.precedance === Y ? this.y+this.x : this.x+this.y; };
|
1681
|
-
this.abbrev = function() {
|
1682
|
-
var x = this.x.substr(0,1), y = this.y.substr(0,1);
|
1683
|
-
return x === y ? x : this.precedance === Y ? y + x : x + y;
|
1684
|
-
};
|
1685
|
-
|
1686
|
-
this.invertx = function(center) { this.x = this.x === LEFT ? RIGHT : this.x === RIGHT ? LEFT : center || this.x; };
|
1687
|
-
this.inverty = function(center) { this.y = this.y === TOP ? BOTTOM : this.y === BOTTOM ? TOP : center || this.y; };
|
1688
|
-
|
1689
|
-
this.clone = function() {
|
1690
|
-
return {
|
1691
|
-
x: this.x, y: this.y, precedance: this.precedance,
|
1692
|
-
string: this.string, abbrev: this.abbrev, clone: this.clone,
|
1693
|
-
invertx: this.invertx, inverty: this.inverty
|
1694
|
-
};
|
1695
|
-
};
|
1696
|
-
},
|
1697
|
-
|
1698
|
-
// Custom (more correct for qTip!) offset calculator
|
1699
|
-
offset: function(elem, container) {
|
1700
|
-
var pos = elem.offset(),
|
1701
|
-
docBody = elem.closest('body')[0],
|
1702
|
-
parent = container, scrolled,
|
1703
|
-
coffset, overflow;
|
1704
|
-
|
1705
|
-
function scroll(e, i) {
|
1706
|
-
pos.left += i * e.scrollLeft();
|
1707
|
-
pos.top += i * e.scrollTop();
|
1708
|
-
}
|
1709
|
-
|
1710
|
-
if(parent) {
|
1711
|
-
// Compensate for non-static containers offset
|
1712
|
-
do {
|
1713
|
-
if(parent.css('position') !== 'static') {
|
1714
|
-
coffset = parent.position();
|
1715
|
-
|
1716
|
-
// Account for element positioning, borders and margins
|
1717
|
-
pos.left -= coffset.left + (parseInt(parent.css('borderLeftWidth'), 10) || 0) + (parseInt(parent.css('marginLeft'), 10) || 0);
|
1718
|
-
pos.top -= coffset.top + (parseInt(parent.css('borderTopWidth'), 10) || 0) + (parseInt(parent.css('marginTop'), 10) || 0);
|
1719
|
-
|
1720
|
-
// If this is the first parent element with an overflow of "scroll" or "auto", store it
|
1721
|
-
if(!scrolled && (overflow = parent.css('overflow')) !== 'hidden' && overflow !== 'visible') { scrolled = parent; }
|
1722
|
-
}
|
1723
|
-
}
|
1724
|
-
while((parent = $(parent[0].offsetParent)).length);
|
1725
|
-
|
1726
|
-
// Compensate for containers scroll if it also has an offsetParent
|
1727
|
-
if(scrolled && scrolled[0] !== docBody) { scroll( scrolled, 1 ); }
|
1728
|
-
}
|
1729
|
-
|
1730
|
-
return pos;
|
1731
|
-
},
|
1732
|
-
|
1733
|
-
/*
|
1734
|
-
* iOS version detection
|
1735
|
-
*/
|
1736
|
-
iOS: parseFloat(
|
1737
|
-
('' + (/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0,''])[1])
|
1738
|
-
.replace('undefined', '3_2').replace('_', '.').replace('_', '')
|
1739
|
-
) || FALSE,
|
1740
|
-
|
1741
|
-
/*
|
1742
|
-
* jQuery-specific $.fn overrides
|
1743
|
-
*/
|
1744
|
-
fn: {
|
1745
|
-
/* Allow other plugins to successfully retrieve the title of an element with a qTip applied */
|
1746
|
-
attr: function(attr, val) {
|
1747
|
-
if(this.length) {
|
1748
|
-
var self = this[0],
|
1749
|
-
title = 'title',
|
1750
|
-
api = $.data(self, 'qtip');
|
1751
|
-
|
1752
|
-
if(attr === title && api && 'object' === typeof api && api.options.suppress) {
|
1753
|
-
if(arguments.length < 2) {
|
1754
|
-
return $.attr(self, oldtitle);
|
1755
|
-
}
|
1756
|
-
else {
|
1757
|
-
// If qTip is rendered and title was originally used as content, update it
|
1758
|
-
if(api && api.options.content.attr === title && api.cache.attr) {
|
1759
|
-
api.set('content.text', val);
|
1760
|
-
}
|
1761
|
-
|
1762
|
-
// Use the regular attr method to set, then cache the result
|
1763
|
-
return this.attr(oldtitle, val);
|
1764
|
-
}
|
1765
|
-
}
|
1766
|
-
}
|
1767
|
-
|
1768
|
-
return $.fn['attr'+replaceSuffix].apply(this, arguments);
|
1769
|
-
},
|
1770
|
-
|
1771
|
-
/* Allow clone to correctly retrieve cached title attributes */
|
1772
|
-
clone: function(keepData) {
|
1773
|
-
var titles = $([]), title = 'title',
|
1774
|
-
|
1775
|
-
// Clone our element using the real clone method
|
1776
|
-
elems = $.fn['clone'+replaceSuffix].apply(this, arguments);
|
1777
|
-
|
1778
|
-
// Grab all elements with an oldtitle set, and change it to regular title attribute, if keepData is false
|
1779
|
-
if(!keepData) {
|
1780
|
-
elems.filter('['+oldtitle+']').attr('title', function() {
|
1781
|
-
return $.attr(this, oldtitle);
|
1782
|
-
})
|
1783
|
-
.removeAttr(oldtitle);
|
1784
|
-
}
|
1785
|
-
|
1786
|
-
return elems;
|
1787
|
-
}
|
1788
|
-
}
|
1789
|
-
};
|
1790
|
-
|
1791
|
-
// Apply the fn overrides above
|
1792
|
-
$.each(PLUGINS.fn, function(name, func) {
|
1793
|
-
if(!func || $.fn[name+replaceSuffix]) { return TRUE; }
|
1794
|
-
|
1795
|
-
var old = $.fn[name+replaceSuffix] = $.fn[name];
|
1796
|
-
$.fn[name] = function() {
|
1797
|
-
return func.apply(this, arguments) || old.apply(this, arguments);
|
1798
|
-
};
|
1799
|
-
});
|
1800
|
-
|
1801
|
-
/* Fire off 'removeqtip' handler in $.cleanData if jQuery UI not present (it already does similar).
|
1802
|
-
* This snippet is taken directly from jQuery UI source code found here:
|
1803
|
-
* http://code.jquery.com/ui/jquery-ui-git.js
|
1804
|
-
*/
|
1805
|
-
if(!$.ui) {
|
1806
|
-
$['cleanData'+replaceSuffix] = $.cleanData;
|
1807
|
-
$.cleanData = function( elems ) {
|
1808
|
-
for(var i = 0, elem; (elem = elems[i]) !== undefined; i++) {
|
1809
|
-
try { $( elem ).triggerHandler('removeqtip'); }
|
1810
|
-
catch( e ) {}
|
1811
|
-
}
|
1812
|
-
$['cleanData'+replaceSuffix]( elems );
|
1813
|
-
};
|
1814
|
-
}
|
1815
|
-
|
1816
|
-
// Set global qTip properties
|
1817
|
-
QTIP.version = 'nightly';
|
1818
|
-
QTIP.nextid = 0;
|
1819
|
-
QTIP.inactiveEvents = 'click dblclick mousedown mouseup mousemove mouseleave mouseenter'.split(' ');
|
1820
|
-
QTIP.zindex = 15000;
|
1821
|
-
|
1822
|
-
// Define configuration defaults
|
1823
|
-
QTIP.defaults = {
|
1824
|
-
prerender: FALSE,
|
1825
|
-
id: FALSE,
|
1826
|
-
overwrite: TRUE,
|
1827
|
-
suppress: TRUE,
|
1828
|
-
content: {
|
1829
|
-
text: TRUE,
|
1830
|
-
attr: 'title',
|
1831
|
-
title: {
|
1832
|
-
text: FALSE,
|
1833
|
-
button: FALSE
|
1834
|
-
}
|
1835
|
-
},
|
1836
|
-
position: {
|
1837
|
-
my: 'top left',
|
1838
|
-
at: 'bottom right',
|
1839
|
-
target: FALSE,
|
1840
|
-
container: FALSE,
|
1841
|
-
viewport: FALSE,
|
1842
|
-
adjust: {
|
1843
|
-
x: 0, y: 0,
|
1844
|
-
mouse: TRUE,
|
1845
|
-
resize: TRUE,
|
1846
|
-
method: 'flip flip'
|
1847
|
-
},
|
1848
|
-
effect: function(api, pos, viewport) {
|
1849
|
-
$(this).animate(pos, {
|
1850
|
-
duration: 200,
|
1851
|
-
queue: FALSE
|
1852
|
-
});
|
1853
|
-
}
|
1854
|
-
},
|
1855
|
-
show: {
|
1856
|
-
target: FALSE,
|
1857
|
-
event: 'mouseenter',
|
1858
|
-
effect: TRUE,
|
1859
|
-
delay: 90,
|
1860
|
-
solo: FALSE,
|
1861
|
-
ready: FALSE,
|
1862
|
-
autofocus: FALSE
|
1863
|
-
},
|
1864
|
-
hide: {
|
1865
|
-
target: FALSE,
|
1866
|
-
event: 'mouseleave',
|
1867
|
-
effect: TRUE,
|
1868
|
-
delay: 0,
|
1869
|
-
fixed: FALSE,
|
1870
|
-
inactive: FALSE,
|
1871
|
-
leave: 'window',
|
1872
|
-
distance: FALSE
|
1873
|
-
},
|
1874
|
-
style: {
|
1875
|
-
classes: '',
|
1876
|
-
widget: FALSE,
|
1877
|
-
width: FALSE,
|
1878
|
-
height: FALSE,
|
1879
|
-
def: TRUE
|
1880
|
-
},
|
1881
|
-
events: {
|
1882
|
-
render: NULL,
|
1883
|
-
move: NULL,
|
1884
|
-
show: NULL,
|
1885
|
-
hide: NULL,
|
1886
|
-
toggle: NULL,
|
1887
|
-
visible: NULL,
|
1888
|
-
hidden: NULL,
|
1889
|
-
focus: NULL,
|
1890
|
-
blur: NULL
|
1891
|
-
}
|
1892
|
-
};
|
1893
|
-
|
1894
|
-
function Ajax(api)
|
1895
|
-
{
|
1896
|
-
var self = this,
|
1897
|
-
tooltip = api.elements.tooltip,
|
1898
|
-
opts = api.options.content.ajax,
|
1899
|
-
defaults = QTIP.defaults.content.ajax,
|
1900
|
-
namespace = '.qtip-ajax',
|
1901
|
-
rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
1902
|
-
first = TRUE,
|
1903
|
-
stop = FALSE,
|
1904
|
-
xhr;
|
1905
|
-
|
1906
|
-
api.checks.ajax = {
|
1907
|
-
'^content.ajax': function(obj, name, v) {
|
1908
|
-
// If content.ajax object was reset, set our local var
|
1909
|
-
if(name === 'ajax') { opts = v; }
|
1910
|
-
|
1911
|
-
if(name === 'once') {
|
1912
|
-
self.init();
|
1913
|
-
}
|
1914
|
-
else if(opts && opts.url) {
|
1915
|
-
self.load();
|
1916
|
-
}
|
1917
|
-
else {
|
1918
|
-
tooltip.unbind(namespace);
|
1919
|
-
}
|
1920
|
-
}
|
1921
|
-
};
|
1922
|
-
|
1923
|
-
$.extend(self, {
|
1924
|
-
init: function() {
|
1925
|
-
// Make sure ajax options are enabled and bind event
|
1926
|
-
if(opts && opts.url) {
|
1927
|
-
tooltip.unbind(namespace)[ opts.once ? 'one' : 'bind' ]('tooltipshow'+namespace, self.load);
|
1928
|
-
}
|
1929
|
-
|
1930
|
-
return self;
|
1931
|
-
},
|
1932
|
-
|
1933
|
-
load: function(event) {
|
1934
|
-
if(stop) {stop = FALSE; return; }
|
1935
|
-
|
1936
|
-
var hasSelector = opts.url.indexOf(' '),
|
1937
|
-
url = opts.url,
|
1938
|
-
selector,
|
1939
|
-
hideFirst = !opts.loading && first;
|
1940
|
-
|
1941
|
-
// If loading option is disabled, prevent the tooltip showing until we've completed the request
|
1942
|
-
if(hideFirst) { try{ event.preventDefault(); } catch(e) {} }
|
1943
|
-
|
1944
|
-
// Make sure default event hasn't been prevented
|
1945
|
-
else if(event && event.isDefaultPrevented()) { return self; }
|
1946
|
-
|
1947
|
-
// Cancel old request
|
1948
|
-
if(xhr && xhr.abort) { xhr.abort(); }
|
1949
|
-
|
1950
|
-
// Check if user delcared a content selector like in .load()
|
1951
|
-
if(hasSelector > -1) {
|
1952
|
-
selector = url.substr(hasSelector);
|
1953
|
-
url = url.substr(0, hasSelector);
|
1954
|
-
}
|
1955
|
-
|
1956
|
-
// Define common after callback for both success/error handlers
|
1957
|
-
function after() {
|
1958
|
-
var complete;
|
1959
|
-
|
1960
|
-
// Don't proceed if tooltip is destroyed
|
1961
|
-
if(api.destroyed) { return; }
|
1962
|
-
|
1963
|
-
// Set first flag to false
|
1964
|
-
first = FALSE;
|
1965
|
-
|
1966
|
-
// Re-display tip if loading and first time, and reset first flag
|
1967
|
-
if(hideFirst) { stop = TRUE; api.show(event.originalEvent); }
|
1968
|
-
|
1969
|
-
// Call users complete method if it was defined
|
1970
|
-
if((complete = defaults.complete || opts.complete) && $.isFunction(complete)) {
|
1971
|
-
complete.apply(opts.context || api, arguments);
|
1972
|
-
}
|
1973
|
-
}
|
1974
|
-
|
1975
|
-
// Define success handler
|
1976
|
-
function successHandler(content, status, jqXHR) {
|
1977
|
-
var success;
|
1978
|
-
|
1979
|
-
// Don't proceed if tooltip is destroyed
|
1980
|
-
if(api.destroyed) { return; }
|
1981
|
-
|
1982
|
-
if(selector) {
|
1983
|
-
// Create a dummy div to hold the results and grab the selector element
|
1984
|
-
content = $('<div/>')
|
1985
|
-
// inject the contents of the document in, removing the scripts
|
1986
|
-
// to avoid any 'Permission Denied' errors in IE
|
1987
|
-
.append(content.replace(rscript, ""))
|
1988
|
-
|
1989
|
-
// Locate the specified elements
|
1990
|
-
.find(selector);
|
1991
|
-
}
|
1992
|
-
|
1993
|
-
// Call the success function if one is defined
|
1994
|
-
if((success = defaults.success || opts.success) && $.isFunction(success)) {
|
1995
|
-
success.call(opts.context || api, content, status, jqXHR);
|
1996
|
-
}
|
1997
|
-
|
1998
|
-
// Otherwise set the content
|
1999
|
-
else { api.set('content.text', content); }
|
2000
|
-
}
|
2001
|
-
|
2002
|
-
// Error handler
|
2003
|
-
function errorHandler(xhr, status, error) {
|
2004
|
-
if(api.destroyed || xhr.status === 0) { return; }
|
2005
|
-
api.set('content.text', status + ': ' + error);
|
2006
|
-
}
|
2007
|
-
|
2008
|
-
// Setup $.ajax option object and process the request
|
2009
|
-
xhr = $.ajax(
|
2010
|
-
$.extend({
|
2011
|
-
error: defaults.error || errorHandler,
|
2012
|
-
context: api
|
2013
|
-
},
|
2014
|
-
opts, { url: url, success: successHandler, complete: after })
|
2015
|
-
);
|
2016
|
-
},
|
2017
|
-
|
2018
|
-
destroy: function() {
|
2019
|
-
// Cancel ajax request if possible
|
2020
|
-
if(xhr && xhr.abort) { xhr.abort(); }
|
2021
|
-
|
2022
|
-
// Set api.destroyed flag
|
2023
|
-
api.destroyed = TRUE;
|
2024
|
-
}
|
2025
|
-
});
|
2026
|
-
|
2027
|
-
self.init();
|
2028
|
-
}
|
2029
|
-
|
2030
|
-
|
2031
|
-
PLUGINS.ajax = function(api)
|
2032
|
-
{
|
2033
|
-
var self = api.plugins.ajax;
|
2034
|
-
|
2035
|
-
return 'object' === typeof self ? self : (api.plugins.ajax = new Ajax(api));
|
2036
|
-
};
|
2037
|
-
|
2038
|
-
PLUGINS.ajax.initialize = 'render';
|
2039
|
-
|
2040
|
-
// Setup plugin sanitization
|
2041
|
-
PLUGINS.ajax.sanitize = function(options)
|
2042
|
-
{
|
2043
|
-
var content = options.content, opts;
|
2044
|
-
if(content && 'ajax' in content) {
|
2045
|
-
opts = content.ajax;
|
2046
|
-
if(typeof opts !== 'object') { opts = options.content.ajax = { url: opts }; }
|
2047
|
-
if('boolean' !== typeof opts.once && opts.once) { opts.once = !!opts.once; }
|
2048
|
-
}
|
2049
|
-
};
|
2050
|
-
|
2051
|
-
// Extend original api defaults
|
2052
|
-
$.extend(TRUE, QTIP.defaults, {
|
2053
|
-
content: {
|
2054
|
-
ajax: {
|
2055
|
-
loading: TRUE,
|
2056
|
-
once: TRUE
|
2057
|
-
}
|
2058
|
-
}
|
2059
|
-
});
|
2060
|
-
|
2061
|
-
PLUGINS.viewport = function(api, position, posOptions, targetWidth, targetHeight, elemWidth, elemHeight)
|
2062
|
-
{
|
2063
|
-
var target = posOptions.target,
|
2064
|
-
tooltip = api.elements.tooltip,
|
2065
|
-
my = posOptions.my,
|
2066
|
-
at = posOptions.at,
|
2067
|
-
adjust = posOptions.adjust,
|
2068
|
-
method = adjust.method.split(' '),
|
2069
|
-
methodX = method[0],
|
2070
|
-
methodY = method[1] || method[0],
|
2071
|
-
viewport = posOptions.viewport,
|
2072
|
-
container = posOptions.container,
|
2073
|
-
cache = api.cache,
|
2074
|
-
tip = api.plugins.tip,
|
2075
|
-
adjusted = { left: 0, top: 0 },
|
2076
|
-
fixed, newMy, newClass;
|
2077
|
-
|
2078
|
-
// If viewport is not a jQuery element, or it's the window/document or no adjustment method is used... return
|
2079
|
-
if(!viewport.jquery || target[0] === window || target[0] === document.body || adjust.method === 'none') {
|
2080
|
-
return adjusted;
|
2081
|
-
}
|
2082
|
-
|
2083
|
-
// Cache our viewport details
|
2084
|
-
fixed = tooltip.css('position') === 'fixed';
|
2085
|
-
viewport = {
|
2086
|
-
elem: viewport,
|
2087
|
-
height: viewport[ (viewport[0] === window ? 'h' : 'outerH') + 'eight' ](),
|
2088
|
-
width: viewport[ (viewport[0] === window ? 'w' : 'outerW') + 'idth' ](),
|
2089
|
-
scrollleft: fixed ? 0 : viewport.scrollLeft(),
|
2090
|
-
scrolltop: fixed ? 0 : viewport.scrollTop(),
|
2091
|
-
offset: viewport.offset() || { left: 0, top: 0 }
|
2092
|
-
};
|
2093
|
-
container = {
|
2094
|
-
elem: container,
|
2095
|
-
scrollLeft: container.scrollLeft(),
|
2096
|
-
scrollTop: container.scrollTop(),
|
2097
|
-
offset: container.offset() || { left: 0, top: 0 }
|
2098
|
-
};
|
2099
|
-
|
2100
|
-
// Generic calculation method
|
2101
|
-
function calculate(side, otherSide, type, adjust, side1, side2, lengthName, targetLength, elemLength) {
|
2102
|
-
var initialPos = position[side1],
|
2103
|
-
mySide = my[side], atSide = at[side],
|
2104
|
-
isShift = type === SHIFT,
|
2105
|
-
viewportScroll = -container.offset[side1] + viewport.offset[side1] + viewport['scroll'+side1],
|
2106
|
-
myLength = mySide === side1 ? elemLength : mySide === side2 ? -elemLength : -elemLength / 2,
|
2107
|
-
atLength = atSide === side1 ? targetLength : atSide === side2 ? -targetLength : -targetLength / 2,
|
2108
|
-
tipLength = tip && tip.size ? tip.size[lengthName] || 0 : 0,
|
2109
|
-
tipAdjust = tip && tip.corner && tip.corner.precedance === side && !isShift ? tipLength : 0,
|
2110
|
-
overflow1 = viewportScroll - initialPos + tipAdjust,
|
2111
|
-
overflow2 = initialPos + elemLength - viewport[lengthName] - viewportScroll + tipAdjust,
|
2112
|
-
offset = myLength - (my.precedance === side || mySide === my[otherSide] ? atLength : 0) - (atSide === CENTER ? targetLength / 2 : 0);
|
2113
|
-
|
2114
|
-
// shift
|
2115
|
-
if(isShift) {
|
2116
|
-
tipAdjust = tip && tip.corner && tip.corner.precedance === otherSide ? tipLength : 0;
|
2117
|
-
offset = (mySide === side1 ? 1 : -1) * myLength - tipAdjust;
|
2118
|
-
|
2119
|
-
// Adjust position but keep it within viewport dimensions
|
2120
|
-
position[side1] += overflow1 > 0 ? overflow1 : overflow2 > 0 ? -overflow2 : 0;
|
2121
|
-
position[side1] = Math.max(
|
2122
|
-
-container.offset[side1] + viewport.offset[side1] + (tipAdjust && tip.corner[side] === CENTER ? tip.offset : 0),
|
2123
|
-
initialPos - offset,
|
2124
|
-
Math.min(
|
2125
|
-
Math.max(-container.offset[side1] + viewport.offset[side1] + viewport[lengthName], initialPos + offset),
|
2126
|
-
position[side1]
|
2127
|
-
)
|
2128
|
-
);
|
2129
|
-
}
|
2130
|
-
|
2131
|
-
// flip/flipinvert
|
2132
|
-
else {
|
2133
|
-
// Update adjustment amount depending on if using flipinvert or flip
|
2134
|
-
adjust *= (type === FLIPINVERT ? 2 : 0);
|
2135
|
-
|
2136
|
-
// Check for overflow on the left/top
|
2137
|
-
if(overflow1 > 0 && (mySide !== side1 || overflow2 > 0)) {
|
2138
|
-
position[side1] -= offset + adjust;
|
2139
|
-
newMy['invert'+side](side1);
|
2140
|
-
}
|
2141
|
-
|
2142
|
-
// Check for overflow on the bottom/right
|
2143
|
-
else if(overflow2 > 0 && (mySide !== side2 || overflow1 > 0) ) {
|
2144
|
-
position[side1] -= (mySide === CENTER ? -offset : offset) + adjust;
|
2145
|
-
newMy['invert'+side](side2);
|
2146
|
-
}
|
2147
|
-
|
2148
|
-
// Make sure we haven't made things worse with the adjustment and reset if so
|
2149
|
-
if(position[side1] < viewportScroll && -position[side1] > overflow2) {
|
2150
|
-
position[side1] = initialPos; newMy = undefined;
|
2151
|
-
}
|
2152
|
-
}
|
2153
|
-
|
2154
|
-
return position[side1] - initialPos;
|
2155
|
-
}
|
2156
|
-
|
2157
|
-
// Set newMy if using flip or flipinvert methods
|
2158
|
-
if(methodX !== 'shift' || methodY !== 'shift') { newMy = my.clone(); }
|
2159
|
-
|
2160
|
-
// Adjust position based onviewport and adjustment options
|
2161
|
-
adjusted = {
|
2162
|
-
left: methodX !== 'none' ? calculate( X, Y, methodX, adjust.x, LEFT, RIGHT, WIDTH, targetWidth, elemWidth ) : 0,
|
2163
|
-
top: methodY !== 'none' ? calculate( Y, X, methodY, adjust.y, TOP, BOTTOM, HEIGHT, targetHeight, elemHeight ) : 0
|
2164
|
-
};
|
2165
|
-
|
2166
|
-
// Set tooltip position class if it's changed
|
2167
|
-
if(newMy && cache.lastClass !== (newClass = uitooltip + '-pos-' + newMy.abbrev())) {
|
2168
|
-
tooltip.removeClass(api.cache.lastClass).addClass( (api.cache.lastClass = newClass) );
|
2169
|
-
}
|
2170
|
-
|
2171
|
-
return adjusted;
|
2172
|
-
};function Modal(api)
|
2173
|
-
{
|
2174
|
-
var self = this,
|
2175
|
-
options = api.options.show.modal,
|
2176
|
-
elems = api.elements,
|
2177
|
-
tooltip = elems.tooltip,
|
2178
|
-
overlaySelector = '#qtip-overlay',
|
2179
|
-
globalNamespace = '.qtipmodal',
|
2180
|
-
namespace = globalNamespace + api.id,
|
2181
|
-
attr = 'is-modal-qtip',
|
2182
|
-
docBody = $(document.body),
|
2183
|
-
focusableSelector = PLUGINS.modal.focusable.join(','),
|
2184
|
-
focusableElems = {}, overlay;
|
2185
|
-
|
2186
|
-
// Setup option set checks
|
2187
|
-
api.checks.modal = {
|
2188
|
-
'^show.modal.(on|blur)$': function() {
|
2189
|
-
// Initialise
|
2190
|
-
self.init();
|
2191
|
-
|
2192
|
-
// Show the modal if not visible already and tooltip is visible
|
2193
|
-
elems.overlay.toggle( tooltip.is(':visible') );
|
2194
|
-
},
|
2195
|
-
'^content.text$': updateFocusable
|
2196
|
-
};
|
2197
|
-
|
2198
|
-
function updateFocusable() {
|
2199
|
-
focusableElems = $(focusableSelector, tooltip).not('[disabled]').map(function() {
|
2200
|
-
return typeof this.focus === 'function' ? this : null;
|
2201
|
-
});
|
2202
|
-
}
|
2203
|
-
|
2204
|
-
function focusInputs(blurElems) {
|
2205
|
-
// Blurring body element in IE causes window.open windows to unfocus!
|
2206
|
-
if(focusableElems.length < 1 && blurElems.length) { blurElems.not('body').blur(); }
|
2207
|
-
|
2208
|
-
// Focus the inputs
|
2209
|
-
else { focusableElems.first().focus(); }
|
2210
|
-
}
|
2211
|
-
|
2212
|
-
function stealFocus(event) {
|
2213
|
-
var target = $(event.target),
|
2214
|
-
container = target.closest('.qtip'),
|
2215
|
-
targetOnTop;
|
2216
|
-
|
2217
|
-
// Determine if input container target is above this
|
2218
|
-
targetOnTop = container.length < 1 ? FALSE :
|
2219
|
-
(parseInt(container[0].style.zIndex, 10) > parseInt(tooltip[0].style.zIndex, 10));
|
2220
|
-
|
2221
|
-
// If we're showing a modal, but focus has landed on an input below
|
2222
|
-
// this modal, divert focus to the first visible input in this modal
|
2223
|
-
// or if we can't find one... the tooltip itself
|
2224
|
-
if(!targetOnTop && ($(event.target).closest(selector)[0] !== tooltip[0])) {
|
2225
|
-
focusInputs(target);
|
2226
|
-
}
|
2227
|
-
}
|
2228
|
-
|
2229
|
-
$.extend(self, {
|
2230
|
-
init: function()
|
2231
|
-
{
|
2232
|
-
// If modal is disabled... return
|
2233
|
-
if(!options.on) { return self; }
|
2234
|
-
|
2235
|
-
// Create the overlay if needed
|
2236
|
-
overlay = self.create();
|
2237
|
-
|
2238
|
-
// Add unique attribute so we can grab modal tooltips easily via a selector
|
2239
|
-
tooltip.attr(attr, TRUE)
|
2240
|
-
|
2241
|
-
// Set z-index
|
2242
|
-
.css('z-index', PLUGINS.modal.zindex + $(selector+'['+attr+']').length)
|
2243
|
-
|
2244
|
-
// Remove previous bound events in globalNamespace
|
2245
|
-
.unbind(globalNamespace).unbind(namespace)
|
2246
|
-
|
2247
|
-
// Apply our show/hide/focus modal events
|
2248
|
-
.bind('tooltipshow'+globalNamespace+' tooltiphide'+globalNamespace, function(event, api, duration) {
|
2249
|
-
var oEvent = event.originalEvent;
|
2250
|
-
|
2251
|
-
// Make sure mouseout doesn't trigger a hide when showing the modal and mousing onto backdrop
|
2252
|
-
if(event.target === tooltip[0]) {
|
2253
|
-
if(oEvent && event.type === 'tooltiphide' && /mouse(leave|enter)/.test(oEvent.type) && $(oEvent.relatedTarget).closest(overlay[0]).length) {
|
2254
|
-
try { event.preventDefault(); } catch(e) {}
|
2255
|
-
}
|
2256
|
-
else if(!oEvent || (oEvent && !oEvent.solo)) {
|
2257
|
-
self[ event.type.replace('tooltip', '') ](event, duration);
|
2258
|
-
}
|
2259
|
-
}
|
2260
|
-
})
|
2261
|
-
|
2262
|
-
// Adjust modal z-index on tooltip focus
|
2263
|
-
.bind('tooltipfocus'+globalNamespace, function(event) {
|
2264
|
-
// If focus was cancelled before it reearch us, don't do anything
|
2265
|
-
if(event.isDefaultPrevented() || event.target !== tooltip[0]) { return; }
|
2266
|
-
|
2267
|
-
var qtips = $(selector).filter('['+attr+']'),
|
2268
|
-
|
2269
|
-
// Keep the modal's lower than other, regular qtips
|
2270
|
-
newIndex = PLUGINS.modal.zindex + qtips.length,
|
2271
|
-
curIndex = parseInt(tooltip[0].style.zIndex, 10);
|
2272
|
-
|
2273
|
-
// Set overlay z-index
|
2274
|
-
overlay[0].style.zIndex = newIndex - 2;
|
2275
|
-
|
2276
|
-
// Reduce modal z-index's and keep them properly ordered
|
2277
|
-
qtips.each(function() {
|
2278
|
-
if(this.style.zIndex > curIndex) {
|
2279
|
-
this.style.zIndex -= 1;
|
2280
|
-
}
|
2281
|
-
});
|
2282
|
-
|
2283
|
-
// Fire blur event for focused tooltip
|
2284
|
-
qtips.end().filter('.' + focusClass).qtip('blur', event.originalEvent);
|
2285
|
-
|
2286
|
-
// Set the new z-index
|
2287
|
-
tooltip.addClass(focusClass)[0].style.zIndex = newIndex;
|
2288
|
-
|
2289
|
-
// Prevent default handling
|
2290
|
-
try { event.preventDefault(); } catch(e) {}
|
2291
|
-
})
|
2292
|
-
|
2293
|
-
// Focus any other visible modals when this one hides
|
2294
|
-
.bind('tooltiphide'+globalNamespace, function(event) {
|
2295
|
-
if(event.target === tooltip[0]) {
|
2296
|
-
$('[' + attr + ']').filter(':visible').not(tooltip).last().qtip('focus', event);
|
2297
|
-
}
|
2298
|
-
});
|
2299
|
-
|
2300
|
-
// Apply keyboard "Escape key" close handler
|
2301
|
-
if(options.escape) {
|
2302
|
-
$(document).unbind(namespace).bind('keydown'+namespace, function(event) {
|
2303
|
-
if(event.keyCode === 27 && tooltip.hasClass(focusClass)) {
|
2304
|
-
api.hide(event);
|
2305
|
-
}
|
2306
|
-
});
|
2307
|
-
}
|
2308
|
-
|
2309
|
-
// Apply click handler for blur option
|
2310
|
-
if(options.blur) {
|
2311
|
-
elems.overlay.unbind(namespace).bind('click'+namespace, function(event) {
|
2312
|
-
if(tooltip.hasClass(focusClass)) { api.hide(event); }
|
2313
|
-
});
|
2314
|
-
}
|
2315
|
-
|
2316
|
-
// Update focusable elements
|
2317
|
-
updateFocusable();
|
2318
|
-
|
2319
|
-
return self;
|
2320
|
-
},
|
2321
|
-
|
2322
|
-
create: function()
|
2323
|
-
{
|
2324
|
-
var elem = $(overlaySelector);
|
2325
|
-
|
2326
|
-
// Return if overlay is already rendered
|
2327
|
-
if(elem.length) {
|
2328
|
-
// Modal overlay should always be below all tooltips if possible
|
2329
|
-
return (elems.overlay = elem.insertAfter( $(selector).last() ));
|
2330
|
-
}
|
2331
|
-
|
2332
|
-
// Create document overlay
|
2333
|
-
overlay = elems.overlay = $('<div />', {
|
2334
|
-
id: overlaySelector.substr(1),
|
2335
|
-
html: '<div></div>',
|
2336
|
-
mousedown: function() { return FALSE; }
|
2337
|
-
})
|
2338
|
-
.hide()
|
2339
|
-
.insertAfter( $(selector).last() );
|
2340
|
-
|
2341
|
-
// Update position on window resize or scroll
|
2342
|
-
function resize() {
|
2343
|
-
overlay.css({
|
2344
|
-
height: $(window).height(),
|
2345
|
-
width: $(window).width()
|
2346
|
-
});
|
2347
|
-
}
|
2348
|
-
$(window).unbind(globalNamespace).bind('resize'+globalNamespace, resize);
|
2349
|
-
resize(); // Fire it initially too
|
2350
|
-
|
2351
|
-
return overlay;
|
2352
|
-
},
|
2353
|
-
|
2354
|
-
toggle: function(event, state, duration)
|
2355
|
-
{
|
2356
|
-
// Make sure default event hasn't been prevented
|
2357
|
-
if(event && event.isDefaultPrevented()) { return self; }
|
2358
|
-
|
2359
|
-
var effect = options.effect,
|
2360
|
-
type = state ? 'show': 'hide',
|
2361
|
-
visible = overlay.is(':visible'),
|
2362
|
-
modals = $('[' + attr + ']').filter(':visible').not(tooltip),
|
2363
|
-
zindex;
|
2364
|
-
|
2365
|
-
// Create our overlay if it isn't present already
|
2366
|
-
if(!overlay) { overlay = self.create(); }
|
2367
|
-
|
2368
|
-
// Prevent modal from conflicting with show.solo, and don't hide backdrop is other modals are visible
|
2369
|
-
if((overlay.is(':animated') && visible === state) || (!state && modals.length)) { return self; }
|
2370
|
-
|
2371
|
-
// State specific...
|
2372
|
-
if(state) {
|
2373
|
-
// Set position
|
2374
|
-
overlay.css({ left: 0, top: 0 });
|
2375
|
-
|
2376
|
-
// Toggle backdrop cursor style on show
|
2377
|
-
overlay.toggleClass('blurs', options.blur);
|
2378
|
-
|
2379
|
-
// IF the modal can steal the focus
|
2380
|
-
if(options.stealfocus !== FALSE) {
|
2381
|
-
// Make sure we can't focus anything outside the tooltip
|
2382
|
-
docBody.bind('focusin'+namespace, stealFocus);
|
2383
|
-
|
2384
|
-
// Blur the current item and focus anything in the modal we an
|
2385
|
-
focusInputs( $('body *') );
|
2386
|
-
}
|
2387
|
-
}
|
2388
|
-
else {
|
2389
|
-
// Undelegate focus handler
|
2390
|
-
docBody.unbind('focusin'+namespace);
|
2391
|
-
}
|
2392
|
-
|
2393
|
-
// Stop all animations
|
2394
|
-
overlay.stop(TRUE, FALSE);
|
2395
|
-
|
2396
|
-
// Use custom function if provided
|
2397
|
-
if($.isFunction(effect)) {
|
2398
|
-
effect.call(overlay, state);
|
2399
|
-
}
|
2400
|
-
|
2401
|
-
// If no effect type is supplied, use a simple toggle
|
2402
|
-
else if(effect === FALSE) {
|
2403
|
-
overlay[ type ]();
|
2404
|
-
}
|
2405
|
-
|
2406
|
-
// Use basic fade function
|
2407
|
-
else {
|
2408
|
-
overlay.fadeTo( parseInt(duration, 10) || 90, state ? 1 : 0, function() {
|
2409
|
-
if(!state) { $(this).hide(); }
|
2410
|
-
});
|
2411
|
-
}
|
2412
|
-
|
2413
|
-
// Reset position on hide
|
2414
|
-
if(!state) {
|
2415
|
-
overlay.queue(function(next) {
|
2416
|
-
overlay.css({ left: '', top: '' });
|
2417
|
-
next();
|
2418
|
-
});
|
2419
|
-
}
|
2420
|
-
|
2421
|
-
return self;
|
2422
|
-
},
|
2423
|
-
|
2424
|
-
show: function(event, duration) { return self.toggle(event, TRUE, duration); },
|
2425
|
-
hide: function(event, duration) { return self.toggle(event, FALSE, duration); },
|
2426
|
-
|
2427
|
-
destroy: function()
|
2428
|
-
{
|
2429
|
-
var delBlanket = overlay;
|
2430
|
-
|
2431
|
-
if(delBlanket) {
|
2432
|
-
// Check if any other modal tooltips are present
|
2433
|
-
delBlanket = $('[' + attr + ']').not(tooltip).length < 1;
|
2434
|
-
|
2435
|
-
// Remove overlay if needed
|
2436
|
-
if(delBlanket) {
|
2437
|
-
elems.overlay.remove();
|
2438
|
-
$(document).unbind(globalNamespace);
|
2439
|
-
}
|
2440
|
-
else {
|
2441
|
-
elems.overlay.unbind(globalNamespace+api.id);
|
2442
|
-
}
|
2443
|
-
|
2444
|
-
// Undelegate focus handler
|
2445
|
-
docBody.undelegate('*', 'focusin'+namespace);
|
2446
|
-
}
|
2447
|
-
|
2448
|
-
// Remove bound events
|
2449
|
-
return tooltip.removeAttr(attr).unbind(globalNamespace);
|
2450
|
-
}
|
2451
|
-
});
|
2452
|
-
|
2453
|
-
self.init();
|
2454
|
-
}
|
2455
|
-
|
2456
|
-
PLUGINS.modal = function(api) {
|
2457
|
-
var self = api.plugins.modal;
|
2458
|
-
|
2459
|
-
return 'object' === typeof self ? self : (api.plugins.modal = new Modal(api));
|
2460
|
-
};
|
2461
|
-
|
2462
|
-
// Plugin needs to be initialized on render
|
2463
|
-
PLUGINS.modal.initialize = 'render';
|
2464
|
-
|
2465
|
-
// Setup sanitiztion rules
|
2466
|
-
PLUGINS.modal.sanitize = function(opts) {
|
2467
|
-
if(opts.show) {
|
2468
|
-
if(typeof opts.show.modal !== 'object') { opts.show.modal = { on: !!opts.show.modal }; }
|
2469
|
-
else if(typeof opts.show.modal.on === 'undefined') { opts.show.modal.on = TRUE; }
|
2470
|
-
}
|
2471
|
-
};
|
2472
|
-
|
2473
|
-
// Base z-index for all modal tooltips (use qTip core z-index as a base)
|
2474
|
-
PLUGINS.modal.zindex = QTIP.zindex + 1000;
|
2475
|
-
|
2476
|
-
// Defines the selector used to select all 'focusable' elements within the modal when using the show.modal.stealfocus option.
|
2477
|
-
// Selectors initially taken from http://stackoverflow.com/questions/7668525/is-there-a-jquery-selector-to-get-all-elements-that-can-get-focus
|
2478
|
-
PLUGINS.modal.focusable = ['a[href]', 'area[href]', 'input', 'select', 'textarea', 'button', 'iframe', 'object', 'embed', '[tabindex]', '[contenteditable]'];
|
2479
|
-
|
2480
|
-
// Extend original api defaults
|
2481
|
-
$.extend(TRUE, QTIP.defaults, {
|
2482
|
-
show: {
|
2483
|
-
modal: {
|
2484
|
-
on: FALSE,
|
2485
|
-
effect: TRUE,
|
2486
|
-
blur: TRUE,
|
2487
|
-
stealfocus: TRUE,
|
2488
|
-
escape: TRUE
|
2489
|
-
}
|
2490
|
-
}
|
2491
|
-
});
|
2492
|
-
|
2493
|
-
PLUGINS.imagemap = function(api, area, corner, adjustMethod)
|
2494
|
-
{
|
2495
|
-
if(!area.jquery) { area = $(area); }
|
2496
|
-
|
2497
|
-
var cache = (api.cache.areas = {}),
|
2498
|
-
shape = (area[0].shape || area.attr('shape')).toLowerCase(),
|
2499
|
-
coordsString = area[0].coords || area.attr('coords'),
|
2500
|
-
baseCoords = coordsString.split(','),
|
2501
|
-
coords = [],
|
2502
|
-
image = $('img[usemap="#'+area.parent('map').attr('name')+'"]'),
|
2503
|
-
imageOffset = image.offset(),
|
2504
|
-
result = {
|
2505
|
-
width: 0, height: 0,
|
2506
|
-
position: {
|
2507
|
-
top: 1e10, right: 0,
|
2508
|
-
bottom: 0, left: 1e10
|
2509
|
-
}
|
2510
|
-
},
|
2511
|
-
i = 0, next = 0, dimensions;
|
2512
|
-
|
2513
|
-
// POLY area coordinate calculator
|
2514
|
-
// Special thanks to Ed Cradock for helping out with this.
|
2515
|
-
// Uses a binary search algorithm to find suitable coordinates.
|
2516
|
-
function polyCoordinates(result, coords, corner)
|
2517
|
-
{
|
2518
|
-
var i = 0,
|
2519
|
-
compareX = 1, compareY = 1,
|
2520
|
-
realX = 0, realY = 0,
|
2521
|
-
newWidth = result.width,
|
2522
|
-
newHeight = result.height;
|
2523
|
-
|
2524
|
-
// Use a binary search algorithm to locate most suitable coordinate (hopefully)
|
2525
|
-
while(newWidth > 0 && newHeight > 0 && compareX > 0 && compareY > 0)
|
2526
|
-
{
|
2527
|
-
newWidth = Math.floor(newWidth / 2);
|
2528
|
-
newHeight = Math.floor(newHeight / 2);
|
2529
|
-
|
2530
|
-
if(corner.x === LEFT){ compareX = newWidth; }
|
2531
|
-
else if(corner.x === RIGHT){ compareX = result.width - newWidth; }
|
2532
|
-
else{ compareX += Math.floor(newWidth / 2); }
|
2533
|
-
|
2534
|
-
if(corner.y === TOP){ compareY = newHeight; }
|
2535
|
-
else if(corner.y === BOTTOM){ compareY = result.height - newHeight; }
|
2536
|
-
else{ compareY += Math.floor(newHeight / 2); }
|
2537
|
-
|
2538
|
-
i = coords.length; while(i--)
|
2539
|
-
{
|
2540
|
-
if(coords.length < 2){ break; }
|
2541
|
-
|
2542
|
-
realX = coords[i][0] - result.position.left;
|
2543
|
-
realY = coords[i][1] - result.position.top;
|
2544
|
-
|
2545
|
-
if((corner.x === LEFT && realX >= compareX) ||
|
2546
|
-
(corner.x === RIGHT && realX <= compareX) ||
|
2547
|
-
(corner.x === CENTER && (realX < compareX || realX > (result.width - compareX))) ||
|
2548
|
-
(corner.y === TOP && realY >= compareY) ||
|
2549
|
-
(corner.y === BOTTOM && realY <= compareY) ||
|
2550
|
-
(corner.y === CENTER && (realY < compareY || realY > (result.height - compareY)))) {
|
2551
|
-
coords.splice(i, 1);
|
2552
|
-
}
|
2553
|
-
}
|
2554
|
-
}
|
2555
|
-
|
2556
|
-
return { left: coords[0][0], top: coords[0][1] };
|
2557
|
-
}
|
2558
|
-
|
2559
|
-
// Make sure we account for padding and borders on the image
|
2560
|
-
imageOffset.left += Math.ceil((image.outerWidth() - image.width()) / 2);
|
2561
|
-
imageOffset.top += Math.ceil((image.outerHeight() - image.height()) / 2);
|
2562
|
-
|
2563
|
-
// Parse coordinates into proper array
|
2564
|
-
if(shape === 'poly') {
|
2565
|
-
i = baseCoords.length; while(i--)
|
2566
|
-
{
|
2567
|
-
next = [ parseInt(baseCoords[--i], 10), parseInt(baseCoords[i+1], 10) ];
|
2568
|
-
|
2569
|
-
if(next[0] > result.position.right){ result.position.right = next[0]; }
|
2570
|
-
if(next[0] < result.position.left){ result.position.left = next[0]; }
|
2571
|
-
if(next[1] > result.position.bottom){ result.position.bottom = next[1]; }
|
2572
|
-
if(next[1] < result.position.top){ result.position.top = next[1]; }
|
2573
|
-
|
2574
|
-
coords.push(next);
|
2575
|
-
}
|
2576
|
-
}
|
2577
|
-
else {
|
2578
|
-
i = -1; while(i++ < baseCoords.length) {
|
2579
|
-
coords.push( parseInt(baseCoords[i], 10) );
|
2580
|
-
}
|
2581
|
-
}
|
2582
|
-
|
2583
|
-
// Calculate details
|
2584
|
-
switch(shape)
|
2585
|
-
{
|
2586
|
-
case 'rect':
|
2587
|
-
result = {
|
2588
|
-
width: Math.abs(coords[2] - coords[0]),
|
2589
|
-
height: Math.abs(coords[3] - coords[1]),
|
2590
|
-
position: {
|
2591
|
-
left: Math.min(coords[0], coords[2]),
|
2592
|
-
top: Math.min(coords[1], coords[3])
|
2593
|
-
}
|
2594
|
-
};
|
2595
|
-
break;
|
2596
|
-
|
2597
|
-
case 'circle':
|
2598
|
-
result = {
|
2599
|
-
width: coords[2] + 2,
|
2600
|
-
height: coords[2] + 2,
|
2601
|
-
position: { left: coords[0], top: coords[1] }
|
2602
|
-
};
|
2603
|
-
break;
|
2604
|
-
|
2605
|
-
case 'poly':
|
2606
|
-
result.width = Math.abs(result.position.right - result.position.left);
|
2607
|
-
result.height = Math.abs(result.position.bottom - result.position.top)
|
2608
|
-
|
2609
|
-
if(corner.abbrev() === 'c') {
|
2610
|
-
result.position = {
|
2611
|
-
left: result.position.left + (result.width / 2),
|
2612
|
-
top: result.position.top + (result.height / 2)
|
2613
|
-
};
|
2614
|
-
}
|
2615
|
-
else {
|
2616
|
-
// Calculate if we can't find a cached value
|
2617
|
-
if(!cache[corner+coordsString]) {
|
2618
|
-
result.position = polyCoordinates(result, coords.slice(), corner);
|
2619
|
-
|
2620
|
-
// If flip adjustment is enabled, also calculate the closest opposite point
|
2621
|
-
if(adjustMethod && (adjustMethod[0] === 'flip' || adjustMethod[1] === 'flip')) {
|
2622
|
-
result.offset = polyCoordinates(result, coords.slice(), {
|
2623
|
-
x: corner.x === LEFT ? RIGHT : corner.x === RIGHT ? LEFT : CENTER,
|
2624
|
-
y: corner.y === TOP ? BOTTOM : corner.y === BOTTOM ? TOP : CENTER
|
2625
|
-
});
|
2626
|
-
|
2627
|
-
result.offset.left -= result.position.left;
|
2628
|
-
result.offset.top -= result.position.top;
|
2629
|
-
}
|
2630
|
-
|
2631
|
-
// Store the result
|
2632
|
-
cache[corner+coordsString] = result;
|
2633
|
-
}
|
2634
|
-
|
2635
|
-
// Grab the cached result
|
2636
|
-
result = cache[corner+coordsString];
|
2637
|
-
}
|
2638
|
-
|
2639
|
-
result.width = result.height = 0;
|
2640
|
-
break;
|
2641
|
-
}
|
2642
|
-
|
2643
|
-
// Add image position to offset coordinates
|
2644
|
-
result.position.left += imageOffset.left;
|
2645
|
-
result.position.top += imageOffset.top;
|
2646
|
-
|
2647
|
-
return result;
|
2648
|
-
};
|
2649
|
-
|
2650
|
-
// Tip coordinates calculator
|
2651
|
-
function calculateTip(corner, width, height)
|
2652
|
-
{
|
2653
|
-
var width2 = Math.ceil(width / 2), height2 = Math.ceil(height / 2),
|
2654
|
-
|
2655
|
-
// Define tip coordinates in terms of height and width values
|
2656
|
-
tips = {
|
2657
|
-
bottomright: [[0,0], [width,height], [width,0]],
|
2658
|
-
bottomleft: [[0,0], [width,0], [0,height]],
|
2659
|
-
topright: [[0,height], [width,0], [width,height]],
|
2660
|
-
topleft: [[0,0], [0,height], [width,height]],
|
2661
|
-
topcenter: [[0,height], [width2,0], [width,height]],
|
2662
|
-
bottomcenter: [[0,0], [width,0], [width2,height]],
|
2663
|
-
rightcenter: [[0,0], [width,height2], [0,height]],
|
2664
|
-
leftcenter: [[width,0], [width,height], [0,height2]]
|
2665
|
-
};
|
2666
|
-
|
2667
|
-
// Set common side shapes
|
2668
|
-
tips.lefttop = tips.bottomright; tips.righttop = tips.bottomleft;
|
2669
|
-
tips.leftbottom = tips.topright; tips.rightbottom = tips.topleft;
|
2670
|
-
|
2671
|
-
return tips[ corner.string() ];
|
2672
|
-
}
|
2673
|
-
|
2674
|
-
|
2675
|
-
function Tip(qTip, command)
|
2676
|
-
{
|
2677
|
-
var self = this,
|
2678
|
-
opts = qTip.options.style.tip,
|
2679
|
-
elems = qTip.elements,
|
2680
|
-
tooltip = elems.tooltip,
|
2681
|
-
cache = { top: 0, left: 0 },
|
2682
|
-
size = {
|
2683
|
-
width: opts.width,
|
2684
|
-
height: opts.height
|
2685
|
-
},
|
2686
|
-
color = { },
|
2687
|
-
border = opts.border || 0,
|
2688
|
-
namespace = '.qtip-tip',
|
2689
|
-
hasCanvas = !!($('<canvas />')[0] || {}).getContext;
|
2690
|
-
|
2691
|
-
self.corner = NULL;
|
2692
|
-
self.mimic = NULL;
|
2693
|
-
self.border = border;
|
2694
|
-
self.offset = opts.offset;
|
2695
|
-
self.size = size;
|
2696
|
-
|
2697
|
-
// Add new option checks for the plugin
|
2698
|
-
qTip.checks.tip = {
|
2699
|
-
'^position.my|style.tip.(corner|mimic|border)$': function() {
|
2700
|
-
// Make sure a tip can be drawn
|
2701
|
-
if(!self.init()) {
|
2702
|
-
self.destroy();
|
2703
|
-
}
|
2704
|
-
|
2705
|
-
// Reposition the tooltip
|
2706
|
-
qTip.reposition();
|
2707
|
-
},
|
2708
|
-
'^style.tip.(height|width)$': function() {
|
2709
|
-
// Re-set dimensions and redraw the tip
|
2710
|
-
size = {
|
2711
|
-
width: opts.width,
|
2712
|
-
height: opts.height
|
2713
|
-
};
|
2714
|
-
self.create();
|
2715
|
-
self.update();
|
2716
|
-
|
2717
|
-
// Reposition the tooltip
|
2718
|
-
qTip.reposition();
|
2719
|
-
},
|
2720
|
-
'^content.title.text|style.(classes|widget)$': function() {
|
2721
|
-
if(elems.tip && elems.tip.length) {
|
2722
|
-
self.update();
|
2723
|
-
}
|
2724
|
-
}
|
2725
|
-
};
|
2726
|
-
|
2727
|
-
function swapDimensions() {
|
2728
|
-
size.width = opts.height;
|
2729
|
-
size.height = opts.width;
|
2730
|
-
}
|
2731
|
-
|
2732
|
-
function resetDimensions() {
|
2733
|
-
size.width = opts.width;
|
2734
|
-
size.height = opts.height;
|
2735
|
-
}
|
2736
|
-
|
2737
|
-
function reposition(event, api, pos, viewport) {
|
2738
|
-
if(!elems.tip) { return; }
|
2739
|
-
|
2740
|
-
var newCorner = self.corner.clone(),
|
2741
|
-
adjust = pos.adjusted,
|
2742
|
-
method = qTip.options.position.adjust.method.split(' '),
|
2743
|
-
horizontal = method[0],
|
2744
|
-
vertical = method[1] || method[0],
|
2745
|
-
shift = { left: FALSE, top: FALSE, x: 0, y: 0 },
|
2746
|
-
offset, css = {}, props;
|
2747
|
-
|
2748
|
-
// If our tip position isn't fixed e.g. doesn't adjust with viewport...
|
2749
|
-
if(self.corner.fixed !== TRUE) {
|
2750
|
-
// Horizontal - Shift or flip method
|
2751
|
-
if(horizontal === SHIFT && newCorner.precedance === X && adjust.left && newCorner.y !== CENTER) {
|
2752
|
-
newCorner.precedance = newCorner.precedance === X ? Y : X;
|
2753
|
-
}
|
2754
|
-
else if(horizontal !== SHIFT && adjust.left){
|
2755
|
-
newCorner.x = newCorner.x === CENTER ? (adjust.left > 0 ? LEFT : RIGHT) : (newCorner.x === LEFT ? RIGHT : LEFT);
|
2756
|
-
}
|
2757
|
-
|
2758
|
-
// Vertical - Shift or flip method
|
2759
|
-
if(vertical === SHIFT && newCorner.precedance === Y && adjust.top && newCorner.x !== CENTER) {
|
2760
|
-
newCorner.precedance = newCorner.precedance === Y ? X : Y;
|
2761
|
-
}
|
2762
|
-
else if(vertical !== SHIFT && adjust.top) {
|
2763
|
-
newCorner.y = newCorner.y === CENTER ? (adjust.top > 0 ? TOP : BOTTOM) : (newCorner.y === TOP ? BOTTOM : TOP);
|
2764
|
-
}
|
2765
|
-
|
2766
|
-
// Update and redraw the tip if needed (check cached details of last drawn tip)
|
2767
|
-
if(newCorner.string() !== cache.corner.string() && (cache.top !== adjust.top || cache.left !== adjust.left)) {
|
2768
|
-
self.update(newCorner, FALSE);
|
2769
|
-
}
|
2770
|
-
}
|
2771
|
-
|
2772
|
-
// Setup tip offset properties
|
2773
|
-
offset = self.position(newCorner, adjust);
|
2774
|
-
offset[ newCorner.x ] += borderWidth(newCorner, newCorner.x, TRUE);
|
2775
|
-
offset[ newCorner.y ] += borderWidth(newCorner, newCorner.y, TRUE);
|
2776
|
-
|
2777
|
-
// Readjust offset object to make it left/top
|
2778
|
-
if(offset.right !== undefined) { offset.left = -offset.right; }
|
2779
|
-
if(offset.bottom !== undefined) { offset.top = -offset.bottom; }
|
2780
|
-
offset.user = Math.max(0, opts.offset);
|
2781
|
-
|
2782
|
-
// Viewport "shift" specific adjustments
|
2783
|
-
if(shift.left = (horizontal === SHIFT && !!adjust.left)) {
|
2784
|
-
if(newCorner.x === CENTER) {
|
2785
|
-
css['margin-left'] = shift.x = offset['margin-left'] - adjust.left;
|
2786
|
-
}
|
2787
|
-
else {
|
2788
|
-
props = offset.right !== undefined ?
|
2789
|
-
[ adjust.left, -offset.left ] : [ -adjust.left, offset.left ];
|
2790
|
-
|
2791
|
-
if( (shift.x = Math.max(props[0], props[1])) > props[0] ) {
|
2792
|
-
pos.left -= adjust.left;
|
2793
|
-
shift.left = FALSE;
|
2794
|
-
}
|
2795
|
-
|
2796
|
-
css[ offset.right !== undefined ? RIGHT : LEFT ] = shift.x;
|
2797
|
-
}
|
2798
|
-
}
|
2799
|
-
if(shift.top = (vertical === SHIFT && !!adjust.top)) {
|
2800
|
-
if(newCorner.y === CENTER) {
|
2801
|
-
css['margin-top'] = shift.y = offset['margin-top'] - adjust.top;
|
2802
|
-
}
|
2803
|
-
else {
|
2804
|
-
props = offset.bottom !== undefined ?
|
2805
|
-
[ adjust.top, -offset.top ] : [ -adjust.top, offset.top ];
|
2806
|
-
|
2807
|
-
if( (shift.y = Math.max(props[0], props[1])) > props[0] ) {
|
2808
|
-
pos.top -= adjust.top;
|
2809
|
-
shift.top = FALSE;
|
2810
|
-
}
|
2811
|
-
|
2812
|
-
css[ offset.bottom !== undefined ? BOTTOM : TOP ] = shift.y;
|
2813
|
-
}
|
2814
|
-
}
|
2815
|
-
|
2816
|
-
/*
|
2817
|
-
* If the tip is adjusted in both dimensions, or in a
|
2818
|
-
* direction that would cause it to be anywhere but the
|
2819
|
-
* outer border, hide it!
|
2820
|
-
*/
|
2821
|
-
elems.tip.css(css).toggle(
|
2822
|
-
!((shift.x && shift.y) || (newCorner.x === CENTER && shift.y) || (newCorner.y === CENTER && shift.x))
|
2823
|
-
);
|
2824
|
-
|
2825
|
-
// Adjust position to accomodate tip dimensions
|
2826
|
-
pos.left -= offset.left.charAt ? offset.user : horizontal !== SHIFT || shift.top || !shift.left && !shift.top ? offset.left : 0;
|
2827
|
-
pos.top -= offset.top.charAt ? offset.user : vertical !== SHIFT || shift.left || !shift.left && !shift.top ? offset.top : 0;
|
2828
|
-
|
2829
|
-
// Cache details
|
2830
|
-
cache.left = adjust.left; cache.top = adjust.top;
|
2831
|
-
cache.corner = newCorner.clone();
|
2832
|
-
}
|
2833
|
-
|
2834
|
-
/* border width calculator */
|
2835
|
-
function borderWidth(corner, side, backup) {
|
2836
|
-
side = !side ? corner[corner.precedance] : side;
|
2837
|
-
|
2838
|
-
var isFluid = tooltip.hasClass(fluidClass),
|
2839
|
-
isTitleTop = elems.titlebar && corner.y === TOP,
|
2840
|
-
elem = isTitleTop ? elems.titlebar : elems.tooltip,
|
2841
|
-
css = 'border-' + side + '-width',
|
2842
|
-
val;
|
2843
|
-
|
2844
|
-
// Grab the border-width value (add fluid class if needed)
|
2845
|
-
tooltip.addClass(fluidClass);
|
2846
|
-
val = parseInt(elem.css(css), 10);
|
2847
|
-
val = (backup ? val || parseInt(tooltip.css(css), 10) : val) || 0;
|
2848
|
-
tooltip.toggleClass(fluidClass, isFluid);
|
2849
|
-
|
2850
|
-
return val;
|
2851
|
-
}
|
2852
|
-
|
2853
|
-
function borderRadius(corner) {
|
2854
|
-
var isTitleTop = elems.titlebar && corner.y === TOP,
|
2855
|
-
elem = isTitleTop ? elems.titlebar : elems.content,
|
2856
|
-
moz = $.browser.mozilla,
|
2857
|
-
prefix = moz ? '-moz-' : $.browser.webkit ? '-webkit-' : '',
|
2858
|
-
side = corner.y + (moz ? '' : '-') + corner.x,
|
2859
|
-
css = prefix + (moz ? 'border-radius-' + side : 'border-' + side + '-radius');
|
2860
|
-
|
2861
|
-
return parseInt(elem.css(css), 10) || parseInt(tooltip.css(css), 10) || 0;
|
2862
|
-
}
|
2863
|
-
|
2864
|
-
function calculateSize(corner) {
|
2865
|
-
var y = corner.precedance === Y,
|
2866
|
-
width = size [ y ? WIDTH : HEIGHT ],
|
2867
|
-
height = size [ y ? HEIGHT : WIDTH ],
|
2868
|
-
isCenter = corner.string().indexOf(CENTER) > -1,
|
2869
|
-
base = width * (isCenter ? 0.5 : 1),
|
2870
|
-
pow = Math.pow,
|
2871
|
-
round = Math.round,
|
2872
|
-
bigHyp, ratio, result,
|
2873
|
-
|
2874
|
-
smallHyp = Math.sqrt( pow(base, 2) + pow(height, 2) ),
|
2875
|
-
|
2876
|
-
hyp = [
|
2877
|
-
(border / base) * smallHyp, (border / height) * smallHyp
|
2878
|
-
];
|
2879
|
-
hyp[2] = Math.sqrt( pow(hyp[0], 2) - pow(border, 2) );
|
2880
|
-
hyp[3] = Math.sqrt( pow(hyp[1], 2) - pow(border, 2) );
|
2881
|
-
|
2882
|
-
bigHyp = smallHyp + hyp[2] + hyp[3] + (isCenter ? 0 : hyp[0]);
|
2883
|
-
ratio = bigHyp / smallHyp;
|
2884
|
-
|
2885
|
-
result = [ round(ratio * height), round(ratio * width) ];
|
2886
|
-
return { height: result[ y ? 0 : 1 ], width: result[ y ? 1 : 0 ] };
|
2887
|
-
}
|
2888
|
-
|
2889
|
-
$.extend(self, {
|
2890
|
-
init: function()
|
2891
|
-
{
|
2892
|
-
var enabled = self.detectCorner() && (hasCanvas || $.browser.msie);
|
2893
|
-
|
2894
|
-
// Determine tip corner and type
|
2895
|
-
if(enabled) {
|
2896
|
-
// Create a new tip and draw it
|
2897
|
-
self.create();
|
2898
|
-
self.update();
|
2899
|
-
|
2900
|
-
// Bind update events
|
2901
|
-
tooltip.unbind(namespace).bind('tooltipmove'+namespace, reposition);
|
2902
|
-
}
|
2903
|
-
|
2904
|
-
return enabled;
|
2905
|
-
},
|
2906
|
-
|
2907
|
-
detectCorner: function()
|
2908
|
-
{
|
2909
|
-
var corner = opts.corner,
|
2910
|
-
posOptions = qTip.options.position,
|
2911
|
-
at = posOptions.at,
|
2912
|
-
my = posOptions.my.string ? posOptions.my.string() : posOptions.my;
|
2913
|
-
|
2914
|
-
// Detect corner and mimic properties
|
2915
|
-
if(corner === FALSE || (my === FALSE && at === FALSE)) {
|
2916
|
-
return FALSE;
|
2917
|
-
}
|
2918
|
-
else {
|
2919
|
-
if(corner === TRUE) {
|
2920
|
-
self.corner = new PLUGINS.Corner(my);
|
2921
|
-
}
|
2922
|
-
else if(!corner.string) {
|
2923
|
-
self.corner = new PLUGINS.Corner(corner);
|
2924
|
-
self.corner.fixed = TRUE;
|
2925
|
-
}
|
2926
|
-
}
|
2927
|
-
|
2928
|
-
// Cache it
|
2929
|
-
cache.corner = new PLUGINS.Corner( self.corner.string() );
|
2930
|
-
|
2931
|
-
return self.corner.string() !== 'centercenter';
|
2932
|
-
},
|
2933
|
-
|
2934
|
-
detectColours: function(actual) {
|
2935
|
-
var i, fill, border,
|
2936
|
-
tip = elems.tip.css('cssText', ''),
|
2937
|
-
corner = actual || self.corner,
|
2938
|
-
precedance = corner[ corner.precedance ],
|
2939
|
-
|
2940
|
-
borderSide = 'border-' + precedance + '-color',
|
2941
|
-
borderSideCamel = 'border' + precedance.charAt(0) + precedance.substr(1) + 'Color',
|
2942
|
-
|
2943
|
-
invalid = /rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i,
|
2944
|
-
backgroundColor = 'background-color',
|
2945
|
-
transparent = 'transparent',
|
2946
|
-
important = ' !important',
|
2947
|
-
|
2948
|
-
useTitle = elems.titlebar && (corner.y === TOP || (corner.y === CENTER && tip.position().top + (size.height / 2) + opts.offset < elems.titlebar.outerHeight(1))),
|
2949
|
-
colorElem = useTitle ? elems.titlebar : elems.tooltip;
|
2950
|
-
|
2951
|
-
// Apply the fluid class so we can see our CSS values properly
|
2952
|
-
tooltip.addClass(fluidClass);
|
2953
|
-
|
2954
|
-
// Detect tip colours from CSS styles
|
2955
|
-
color.fill = fill = tip.css(backgroundColor);
|
2956
|
-
color.border = border = tip[0].style[ borderSideCamel ] || tip.css(borderSide) || tooltip.css(borderSide);
|
2957
|
-
|
2958
|
-
// Make sure colours are valid
|
2959
|
-
if(!fill || invalid.test(fill)) {
|
2960
|
-
color.fill = colorElem.css(backgroundColor) || transparent;
|
2961
|
-
if(invalid.test(color.fill)) {
|
2962
|
-
color.fill = tooltip.css(backgroundColor) || fill;
|
2963
|
-
}
|
2964
|
-
}
|
2965
|
-
if(!border || invalid.test(border) || border === $(document.body).css('color')) {
|
2966
|
-
color.border = colorElem.css(borderSide) || transparent;
|
2967
|
-
if(invalid.test(color.border) || color.border === colorElem.css('color')) {
|
2968
|
-
color.border = tooltip.css(borderSide) || tooltip.css(borderSideCamel) || border;
|
2969
|
-
}
|
2970
|
-
}
|
2971
|
-
|
2972
|
-
// Reset background and border colours
|
2973
|
-
$('*', tip).add(tip).css('cssText', backgroundColor+':'+transparent+important+';border:0'+important+';');
|
2974
|
-
|
2975
|
-
// Remove fluid class
|
2976
|
-
tooltip.removeClass(fluidClass);
|
2977
|
-
},
|
2978
|
-
|
2979
|
-
create: function()
|
2980
|
-
{
|
2981
|
-
var width = size.width,
|
2982
|
-
height = size.height,
|
2983
|
-
vml;
|
2984
|
-
|
2985
|
-
// Remove previous tip element if present
|
2986
|
-
if(elems.tip) { elems.tip.remove(); }
|
2987
|
-
|
2988
|
-
// Create tip element and prepend to the tooltip
|
2989
|
-
elems.tip = $('<div />', { 'class': 'ui-tooltip-tip' }).css({ width: width, height: height }).prependTo(tooltip);
|
2990
|
-
|
2991
|
-
// Create tip drawing element(s)
|
2992
|
-
if(hasCanvas) {
|
2993
|
-
// save() as soon as we create the canvas element so FF2 doesn't bork on our first restore()!
|
2994
|
-
$('<canvas />').appendTo(elems.tip)[0].getContext('2d').save();
|
2995
|
-
}
|
2996
|
-
else {
|
2997
|
-
vml = '<vml:shape coordorigin="0,0" style="display:inline-block; position:absolute; behavior:url(#default#VML);"></vml:shape>';
|
2998
|
-
elems.tip.html(vml + vml);
|
2999
|
-
|
3000
|
-
// Prevent mousing down on the tip since it causes problems with .live() handling in IE due to VML
|
3001
|
-
$('*', elems.tip).bind('click mousedown', function(event) { event.stopPropagation(); });
|
3002
|
-
}
|
3003
|
-
},
|
3004
|
-
|
3005
|
-
update: function(corner, position)
|
3006
|
-
{
|
3007
|
-
var tip = elems.tip,
|
3008
|
-
inner = tip.children(),
|
3009
|
-
width = size.width,
|
3010
|
-
height = size.height,
|
3011
|
-
regular = 'px solid ',
|
3012
|
-
transparent = 'px dashed transparent', // Dashed IE6 border-transparency hack. Awesome!
|
3013
|
-
mimic = opts.mimic,
|
3014
|
-
round = Math.round,
|
3015
|
-
precedance, context, coords, translate, newSize;
|
3016
|
-
|
3017
|
-
// Re-determine tip if not already set
|
3018
|
-
if(!corner) { corner = cache.corner || self.corner; }
|
3019
|
-
|
3020
|
-
// Use corner property if we detect an invalid mimic value
|
3021
|
-
if(mimic === FALSE) { mimic = corner; }
|
3022
|
-
|
3023
|
-
// Otherwise inherit mimic properties from the corner object as necessary
|
3024
|
-
else {
|
3025
|
-
mimic = new PLUGINS.Corner(mimic);
|
3026
|
-
mimic.precedance = corner.precedance;
|
3027
|
-
|
3028
|
-
if(mimic.x === 'inherit') { mimic.x = corner.x; }
|
3029
|
-
else if(mimic.y === 'inherit') { mimic.y = corner.y; }
|
3030
|
-
else if(mimic.x === mimic.y) {
|
3031
|
-
mimic[ corner.precedance ] = corner[ corner.precedance ];
|
3032
|
-
}
|
3033
|
-
}
|
3034
|
-
precedance = mimic.precedance;
|
3035
|
-
|
3036
|
-
// Ensure the tip width.height are relative to the tip position
|
3037
|
-
if(corner.precedance === X) { swapDimensions(); }
|
3038
|
-
else { resetDimensions(); }
|
3039
|
-
|
3040
|
-
// Set the tip dimensions
|
3041
|
-
elems.tip.css({
|
3042
|
-
width: (width = size.width),
|
3043
|
-
height: (height = size.height)
|
3044
|
-
});
|
3045
|
-
|
3046
|
-
// Update our colours
|
3047
|
-
self.detectColours(corner);
|
3048
|
-
|
3049
|
-
// Detect border width, taking into account colours
|
3050
|
-
if(color.border !== 'transparent') {
|
3051
|
-
// Grab border width
|
3052
|
-
border = borderWidth(corner, NULL, TRUE);
|
3053
|
-
|
3054
|
-
// If border width isn't zero, use border color as fill (1.0 style tips)
|
3055
|
-
if(opts.border === 0 && border > 0) { color.fill = color.border; }
|
3056
|
-
|
3057
|
-
// Set border width (use detected border width if opts.border is true)
|
3058
|
-
self.border = border = opts.border !== TRUE ? opts.border : border;
|
3059
|
-
}
|
3060
|
-
|
3061
|
-
// Border colour was invalid, set border to zero
|
3062
|
-
else { self.border = border = 0; }
|
3063
|
-
|
3064
|
-
// Calculate coordinates
|
3065
|
-
coords = calculateTip(mimic, width , height);
|
3066
|
-
|
3067
|
-
// Determine tip size
|
3068
|
-
self.size = newSize = calculateSize(corner);
|
3069
|
-
tip.css(newSize);
|
3070
|
-
|
3071
|
-
// Calculate tip translation
|
3072
|
-
if(corner.precedance === Y) {
|
3073
|
-
translate = [
|
3074
|
-
round(mimic.x === LEFT ? border : mimic.x === RIGHT ? newSize.width - width - border : (newSize.width - width) / 2),
|
3075
|
-
round(mimic.y === TOP ? newSize.height - height : 0)
|
3076
|
-
];
|
3077
|
-
}
|
3078
|
-
else {
|
3079
|
-
translate = [
|
3080
|
-
round(mimic.x === LEFT ? newSize.width - width : 0),
|
3081
|
-
round(mimic.y === TOP ? border : mimic.y === BOTTOM ? newSize.height - height - border : (newSize.height - height) / 2)
|
3082
|
-
];
|
3083
|
-
}
|
3084
|
-
|
3085
|
-
// Canvas drawing implementation
|
3086
|
-
if(hasCanvas) {
|
3087
|
-
// Set the canvas size using calculated size
|
3088
|
-
inner.attr(newSize);
|
3089
|
-
|
3090
|
-
// Grab canvas context and clear/save it
|
3091
|
-
context = inner[0].getContext('2d');
|
3092
|
-
context.restore(); context.save();
|
3093
|
-
context.clearRect(0,0,3000,3000);
|
3094
|
-
|
3095
|
-
// Set properties
|
3096
|
-
context.fillStyle = color.fill;
|
3097
|
-
context.strokeStyle = color.border;
|
3098
|
-
context.lineWidth = border * 2;
|
3099
|
-
context.lineJoin = 'miter';
|
3100
|
-
context.miterLimit = 100;
|
3101
|
-
|
3102
|
-
// Translate origin
|
3103
|
-
context.translate(translate[0], translate[1]);
|
3104
|
-
|
3105
|
-
// Draw the tip
|
3106
|
-
context.beginPath();
|
3107
|
-
context.moveTo(coords[0][0], coords[0][1]);
|
3108
|
-
context.lineTo(coords[1][0], coords[1][1]);
|
3109
|
-
context.lineTo(coords[2][0], coords[2][1]);
|
3110
|
-
context.closePath();
|
3111
|
-
|
3112
|
-
// Apply fill and border
|
3113
|
-
if(border) {
|
3114
|
-
// Make sure transparent borders are supported by doing a stroke
|
3115
|
-
// of the background colour before the stroke colour
|
3116
|
-
if(tooltip.css('background-clip') === 'border-box') {
|
3117
|
-
context.strokeStyle = color.fill;
|
3118
|
-
context.stroke();
|
3119
|
-
}
|
3120
|
-
context.strokeStyle = color.border;
|
3121
|
-
context.stroke();
|
3122
|
-
}
|
3123
|
-
context.fill();
|
3124
|
-
}
|
3125
|
-
|
3126
|
-
// VML (IE Proprietary implementation)
|
3127
|
-
else {
|
3128
|
-
// Setup coordinates string
|
3129
|
-
coords = 'm' + coords[0][0] + ',' + coords[0][1] + ' l' + coords[1][0] +
|
3130
|
-
',' + coords[1][1] + ' ' + coords[2][0] + ',' + coords[2][1] + ' xe';
|
3131
|
-
|
3132
|
-
// Setup VML-specific offset for pixel-perfection
|
3133
|
-
translate[2] = border && /^(r|b)/i.test(corner.string()) ?
|
3134
|
-
parseFloat($.browser.version, 10) === 8 ? 2 : 1 : 0;
|
3135
|
-
|
3136
|
-
// Set initial CSS
|
3137
|
-
inner.css({
|
3138
|
-
antialias: ''+(mimic.string().indexOf(CENTER) > -1),
|
3139
|
-
left: translate[0] - (translate[2] * Number(precedance === X)),
|
3140
|
-
top: translate[1] - (translate[2] * Number(precedance === Y)),
|
3141
|
-
width: width + border,
|
3142
|
-
height: height + border
|
3143
|
-
})
|
3144
|
-
.each(function(i) {
|
3145
|
-
var $this = $(this);
|
3146
|
-
|
3147
|
-
// Set shape specific attributes
|
3148
|
-
$this[ $this.prop ? 'prop' : 'attr' ]({
|
3149
|
-
coordsize: (width+border) + ' ' + (height+border),
|
3150
|
-
path: coords,
|
3151
|
-
fillcolor: color.fill,
|
3152
|
-
filled: !!i,
|
3153
|
-
stroked: !i
|
3154
|
-
})
|
3155
|
-
.css({ display: border || i ? 'block' : 'none' });
|
3156
|
-
|
3157
|
-
// Check if border is enabled and add stroke element
|
3158
|
-
if(!i && $this.html() === '') {
|
3159
|
-
$this.html(
|
3160
|
-
'<vml:stroke weight="'+(border*2)+'px" color="'+color.border+'" miterlimit="1000" joinstyle="miter" ' +
|
3161
|
-
' style="behavior:url(#default#VML); display:inline-block;" />'
|
3162
|
-
);
|
3163
|
-
}
|
3164
|
-
});
|
3165
|
-
}
|
3166
|
-
|
3167
|
-
// Position if needed
|
3168
|
-
if(position !== FALSE) { self.position(corner); }
|
3169
|
-
},
|
3170
|
-
|
3171
|
-
// Tip positioning method
|
3172
|
-
position: function(corner)
|
3173
|
-
{
|
3174
|
-
var tip = elems.tip,
|
3175
|
-
position = {},
|
3176
|
-
userOffset = Math.max(0, opts.offset),
|
3177
|
-
precedance, dimensions, corners;
|
3178
|
-
|
3179
|
-
// Return if tips are disabled or tip is not yet rendered
|
3180
|
-
if(opts.corner === FALSE || !tip) { return FALSE; }
|
3181
|
-
|
3182
|
-
// Inherit corner if not provided
|
3183
|
-
corner = corner || self.corner;
|
3184
|
-
precedance = corner.precedance;
|
3185
|
-
|
3186
|
-
// Determine which tip dimension to use for adjustment
|
3187
|
-
dimensions = calculateSize(corner);
|
3188
|
-
|
3189
|
-
// Setup corners and offset array
|
3190
|
-
corners = [ corner.x, corner.y ];
|
3191
|
-
if(precedance === X) { corners.reverse(); }
|
3192
|
-
|
3193
|
-
// Calculate tip position
|
3194
|
-
$.each(corners, function(i, side) {
|
3195
|
-
var b, br;
|
3196
|
-
|
3197
|
-
if(side === CENTER) {
|
3198
|
-
b = precedance === Y ? LEFT : TOP;
|
3199
|
-
position[ b ] = '50%';
|
3200
|
-
position['margin-' + b] = -Math.round(dimensions[ precedance === Y ? WIDTH : HEIGHT ] / 2) + userOffset;
|
3201
|
-
}
|
3202
|
-
else {
|
3203
|
-
b = borderWidth(corner, side);
|
3204
|
-
br = borderRadius(corner);
|
3205
|
-
|
3206
|
-
position[ side ] = i ? 0 : (userOffset + (br > b ? br : -b));
|
3207
|
-
}
|
3208
|
-
});
|
3209
|
-
|
3210
|
-
// Adjust for tip dimensions
|
3211
|
-
position[ corner[precedance] ] -= dimensions[ precedance === X ? WIDTH : HEIGHT ];
|
3212
|
-
|
3213
|
-
// Set and return new position
|
3214
|
-
tip.css({ top: '', bottom: '', left: '', right: '', margin: '' }).css(position);
|
3215
|
-
return position;
|
3216
|
-
},
|
3217
|
-
|
3218
|
-
destroy: function()
|
3219
|
-
{
|
3220
|
-
// Remove the tip element
|
3221
|
-
if(elems.tip) { elems.tip.remove(); }
|
3222
|
-
elems.tip = false;
|
3223
|
-
|
3224
|
-
// Unbind events
|
3225
|
-
tooltip.unbind(namespace);
|
3226
|
-
}
|
3227
|
-
});
|
3228
|
-
|
3229
|
-
self.init();
|
3230
|
-
}
|
3231
|
-
|
3232
|
-
PLUGINS.tip = function(api)
|
3233
|
-
{
|
3234
|
-
var self = api.plugins.tip;
|
3235
|
-
|
3236
|
-
return 'object' === typeof self ? self : (api.plugins.tip = new Tip(api));
|
3237
|
-
};
|
3238
|
-
|
3239
|
-
// Initialize tip on render
|
3240
|
-
PLUGINS.tip.initialize = 'render';
|
3241
|
-
|
3242
|
-
// Setup plugin sanitization options
|
3243
|
-
PLUGINS.tip.sanitize = function(options)
|
3244
|
-
{
|
3245
|
-
var style = options.style, opts;
|
3246
|
-
if(style && 'tip' in style) {
|
3247
|
-
opts = options.style.tip;
|
3248
|
-
if(typeof opts !== 'object'){ options.style.tip = { corner: opts }; }
|
3249
|
-
if(!(/string|boolean/i).test(typeof opts.corner)) { opts.corner = TRUE; }
|
3250
|
-
if(typeof opts.width !== 'number'){ delete opts.width; }
|
3251
|
-
if(typeof opts.height !== 'number'){ delete opts.height; }
|
3252
|
-
if(typeof opts.border !== 'number' && opts.border !== TRUE){ delete opts.border; }
|
3253
|
-
if(typeof opts.offset !== 'number'){ delete opts.offset; }
|
3254
|
-
}
|
3255
|
-
};
|
3256
|
-
|
3257
|
-
// Extend original qTip defaults
|
3258
|
-
$.extend(TRUE, QTIP.defaults, {
|
3259
|
-
style: {
|
3260
|
-
tip: {
|
3261
|
-
corner: TRUE,
|
3262
|
-
mimic: FALSE,
|
3263
|
-
width: 6,
|
3264
|
-
height: 6,
|
3265
|
-
border: TRUE,
|
3266
|
-
offset: 0
|
3267
|
-
}
|
3268
|
-
}
|
3269
|
-
});
|
3270
|
-
|
3271
|
-
PLUGINS.svg = function(api, svg, corner, adjustMethod)
|
3272
|
-
{
|
3273
|
-
var doc = $(document),
|
3274
|
-
elem = svg[0],
|
3275
|
-
result = {
|
3276
|
-
width: 0, height: 0,
|
3277
|
-
position: { top: 1e10, left: 1e10 }
|
3278
|
-
},
|
3279
|
-
box, mtx, root, point, tPoint;
|
3280
|
-
|
3281
|
-
// Ascend the parentNode chain until we find an element with getBBox()
|
3282
|
-
while(!elem.getBBox) { elem = elem.parentNode; }
|
3283
|
-
|
3284
|
-
// Check for a valid bounding box method
|
3285
|
-
if (elem.getBBox && elem.parentNode) {
|
3286
|
-
box = elem.getBBox();
|
3287
|
-
mtx = elem.getScreenCTM();
|
3288
|
-
root = elem.farthestViewportElement || elem;
|
3289
|
-
|
3290
|
-
// Return if no method is found
|
3291
|
-
if(!root.createSVGPoint) { return result; }
|
3292
|
-
|
3293
|
-
// Create our point var
|
3294
|
-
point = root.createSVGPoint();
|
3295
|
-
|
3296
|
-
// Adjust top and left
|
3297
|
-
point.x = box.x;
|
3298
|
-
point.y = box.y;
|
3299
|
-
tPoint = point.matrixTransform(mtx);
|
3300
|
-
result.position.left = tPoint.x;
|
3301
|
-
result.position.top = tPoint.y;
|
3302
|
-
|
3303
|
-
// Adjust width and height
|
3304
|
-
point.x += box.width;
|
3305
|
-
point.y += box.height;
|
3306
|
-
tPoint = point.matrixTransform(mtx);
|
3307
|
-
result.width = tPoint.x - result.position.left;
|
3308
|
-
result.height = tPoint.y - result.position.top;
|
3309
|
-
|
3310
|
-
// Adjust by scroll offset
|
3311
|
-
result.position.left += doc.scrollLeft();
|
3312
|
-
result.position.top += doc.scrollTop();
|
3313
|
-
}
|
3314
|
-
|
3315
|
-
return result;
|
3316
|
-
};
|
3317
|
-
|
3318
|
-
/*
|
3319
|
-
* BGIFrame adaption (http://plugins.jquery.com/project/bgiframe)
|
3320
|
-
* Special thanks to Brandon Aaron
|
3321
|
-
*/
|
3322
|
-
function BGIFrame(api)
|
3323
|
-
{
|
3324
|
-
var self = this,
|
3325
|
-
elems = api.elements,
|
3326
|
-
tooltip = elems.tooltip,
|
3327
|
-
namespace = '.bgiframe-' + api.id;
|
3328
|
-
|
3329
|
-
$.extend(self, {
|
3330
|
-
init: function()
|
3331
|
-
{
|
3332
|
-
// Create the BGIFrame element
|
3333
|
-
elems.bgiframe = $('<iframe class="ui-tooltip-bgiframe" frameborder="0" tabindex="-1" src="javascript:\'\';" ' +
|
3334
|
-
' style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=0); ' +
|
3335
|
-
'-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";"></iframe>');
|
3336
|
-
|
3337
|
-
// Append the new element to the tooltip
|
3338
|
-
elems.bgiframe.appendTo(tooltip);
|
3339
|
-
|
3340
|
-
// Update BGIFrame on tooltip move
|
3341
|
-
tooltip.bind('tooltipmove'+namespace, self.adjust);
|
3342
|
-
},
|
3343
|
-
|
3344
|
-
adjust: function()
|
3345
|
-
{
|
3346
|
-
var dimensions = api.get('dimensions'), // Determine current tooltip dimensions
|
3347
|
-
plugin = api.plugins.tip,
|
3348
|
-
tip = elems.tip,
|
3349
|
-
tipAdjust, offset;
|
3350
|
-
|
3351
|
-
// Adjust border offset
|
3352
|
-
offset = parseInt(tooltip.css('border-left-width'), 10) || 0;
|
3353
|
-
offset = { left: -offset, top: -offset };
|
3354
|
-
|
3355
|
-
// Adjust for tips plugin
|
3356
|
-
if(plugin && tip) {
|
3357
|
-
tipAdjust = (plugin.corner.precedance === 'x') ? ['width', 'left'] : ['height', 'top'];
|
3358
|
-
offset[ tipAdjust[1] ] -= tip[ tipAdjust[0] ]();
|
3359
|
-
}
|
3360
|
-
|
3361
|
-
// Update bgiframe
|
3362
|
-
elems.bgiframe.css(offset).css(dimensions);
|
3363
|
-
},
|
3364
|
-
|
3365
|
-
destroy: function()
|
3366
|
-
{
|
3367
|
-
// Remove iframe
|
3368
|
-
elems.bgiframe.remove();
|
3369
|
-
|
3370
|
-
// Remove bound events
|
3371
|
-
tooltip.unbind(namespace);
|
3372
|
-
}
|
3373
|
-
});
|
3374
|
-
|
3375
|
-
self.init();
|
3376
|
-
}
|
3377
|
-
|
3378
|
-
PLUGINS.bgiframe = function(api)
|
3379
|
-
{
|
3380
|
-
var browser = $.browser,
|
3381
|
-
self = api.plugins.bgiframe;
|
3382
|
-
|
3383
|
-
// Proceed only if the browser is IE6 and offending elements are present
|
3384
|
-
if($('select, object').length < 1 || !(browser.msie && (''+browser.version).charAt(0) === '6')) {
|
3385
|
-
return FALSE;
|
3386
|
-
}
|
3387
|
-
|
3388
|
-
return 'object' === typeof self ? self : (api.plugins.bgiframe = new BGIFrame(api));
|
3389
|
-
};
|
3390
|
-
|
3391
|
-
// Plugin needs to be initialized on render
|
3392
|
-
PLUGINS.bgiframe.initialize = 'render';
|
3393
|
-
|
3394
|
-
|
3395
|
-
}));
|