hobo-jquery 1.3.0pre2
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.
- data/.gitmodules +3 -0
- data/LICENSE.txt +22 -0
- data/README.markdown +54 -0
- data/TODO.markdown +0 -0
- data/hobo-jquery.gemspec +9 -0
- data/jquery/javascripts/jquery-1.5.2.min.js +16 -0
- data/jquery/javascripts/jquery-ui-1.8.11.custom.min.js +783 -0
- data/jquery/stylesheets/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/jquery/stylesheets/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/jquery/stylesheets/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/jquery/stylesheets/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/jquery/stylesheets/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/jquery/stylesheets/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/jquery/stylesheets/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/jquery/stylesheets/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/jquery/stylesheets/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/jquery/stylesheets/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/jquery/stylesheets/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/jquery/stylesheets/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/jquery/stylesheets/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/jquery/stylesheets/smoothness/jquery-ui-1.8.11.custom.css +573 -0
- data/lib/doc.dryml +75 -0
- data/lib/doc.rb +15 -0
- data/lib/doc_generator.dryml +79 -0
- data/lib/generators/hobo_jquery/install_generator.rb +23 -0
- data/lib/hobo-jquery.rb +6 -0
- data/lib/hobo-jquery/railtie.rb +9 -0
- data/lib/html2markdown.pl +7 -0
- data/lib/render.rake +39 -0
- data/lib/tasks/hobo-contrib.rake +2 -0
- data/public/javascripts/event.simulate.js +64 -0
- data/public/javascripts/hobo-jquery.js +663 -0
- data/public/stylesheets/hobo-jquery.css +16 -0
- data/rails/init.rb +0 -0
- data/taglibs/hobo-jquery.dryml +613 -0
- data/update-docs.sh +16 -0
- metadata +89 -0
data/lib/doc.dryml
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
<def tag="param-list" >
|
2
|
+
<ul if="&this.any?">
|
3
|
+
<% this.each {|param| %>
|
4
|
+
<li><%= param.first %>
|
5
|
+
<param-list with="¶m.last"/>
|
6
|
+
</li>
|
7
|
+
<% } %>
|
8
|
+
</ul>
|
9
|
+
</def>
|
10
|
+
|
11
|
+
<def tag="tag-link" attrs="link, content">
|
12
|
+
<li>
|
13
|
+
<a href="##{link}">
|
14
|
+
<span>
|
15
|
+
<%= content %>
|
16
|
+
</span>
|
17
|
+
</a>
|
18
|
+
</li>
|
19
|
+
</def>
|
20
|
+
|
21
|
+
|
22
|
+
<html>
|
23
|
+
<head>
|
24
|
+
<link type="text/css" href="stylesheets/themes/smoothness/ui.all.css" rel="stylesheet" />
|
25
|
+
<script type="text/javascript" src="javascripts/jquery-1.5.2.min.js"></script>
|
26
|
+
<script type="text/javascript" src="javascripts/jquery-ui-1.8.11.custom.min.js"></script>
|
27
|
+
<script type="text/javascript">
|
28
|
+
jQuery(document).ready(function(){
|
29
|
+
jQuery("#tabs-top").tabs();
|
30
|
+
jQuery(".taglib").tabs();
|
31
|
+
jQuery(".source").accordion({collapsible: true, active: false, autoHeight: false });
|
32
|
+
});
|
33
|
+
</script>
|
34
|
+
</head>
|
35
|
+
<body>
|
36
|
+
<div id="tabs-top">
|
37
|
+
<ul>
|
38
|
+
<repeat with="&this">
|
39
|
+
<tag-link content="&this.name" link="#{this.name}-taglib"/>
|
40
|
+
</repeat>
|
41
|
+
</ul>
|
42
|
+
<repeat>
|
43
|
+
<div class="taglib" id="#{this.name}-taglib">
|
44
|
+
<%= this.comment_html %>
|
45
|
+
<ul>
|
46
|
+
<repeat:tag_defs>
|
47
|
+
<tag-link content="&this.name" link="#{this.name}-tag"/>
|
48
|
+
</repeat>
|
49
|
+
</ul>
|
50
|
+
<repeat:tag_defs>
|
51
|
+
<div id="#{this.name}-tag">
|
52
|
+
|
53
|
+
<h2><%= this.name %></h2>
|
54
|
+
|
55
|
+
<%= this.comment_intro_html %>
|
56
|
+
|
57
|
+
<unless test="&this.parameters.empty?">
|
58
|
+
<h3>Parameters</h3>
|
59
|
+
<param-list with="&this.parameters"/>
|
60
|
+
</unless>
|
61
|
+
|
62
|
+
<%= this.comment_rest_html %>
|
63
|
+
|
64
|
+
<div class="source">
|
65
|
+
<h3><a href="#">Source</a></h3>
|
66
|
+
<pre><code><%= h this.source %></code></pre>
|
67
|
+
</div>
|
68
|
+
|
69
|
+
</div>
|
70
|
+
</repeat>
|
71
|
+
</div>
|
72
|
+
</repeat>
|
73
|
+
</div>
|
74
|
+
</body>
|
75
|
+
</html>
|
data/lib/doc.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'maruku'
|
3
|
+
require 'dryml'
|
4
|
+
require 'action_view'
|
5
|
+
require 'action_controller'
|
6
|
+
|
7
|
+
taglibs = Dir["../taglibs/**/*.dryml"].reject {|filename|
|
8
|
+
File.basename(filename).match(/^hobo-jquery-.*/)
|
9
|
+
}.map {|filename|
|
10
|
+
Dryml::DrymlDoc::Taglib.new("../taglibs", filename)
|
11
|
+
}
|
12
|
+
|
13
|
+
out=Dryml.render(open("doc.dryml").read, {:this => taglibs}, "doc.dryml")
|
14
|
+
|
15
|
+
open("../documentation/doc.html", "w").write(out)
|
@@ -0,0 +1,79 @@
|
|
1
|
+
<include src="core" plugin="hobo/hobo"/>
|
2
|
+
<include src="rapid" plugin="hobo/hobo"/>
|
3
|
+
|
4
|
+
<def tag="param-list" >
|
5
|
+
<ul if="&this.any?">
|
6
|
+
<% this.each {|param| %>
|
7
|
+
<li><%= param.first %>
|
8
|
+
<param-list with="¶m.last"/>
|
9
|
+
</li>
|
10
|
+
<% } %>
|
11
|
+
</ul>
|
12
|
+
</def>
|
13
|
+
|
14
|
+
<def tag="tag-link" attrs="link, content">
|
15
|
+
<li>
|
16
|
+
<a href="##{link}">
|
17
|
+
<span>
|
18
|
+
<%= content %>
|
19
|
+
</span>
|
20
|
+
</a>
|
21
|
+
</li>
|
22
|
+
</def>
|
23
|
+
|
24
|
+
|
25
|
+
<html>
|
26
|
+
<head>
|
27
|
+
<link type="text/css" href="stylesheets/themes/smoothness/ui.all.css" rel="stylesheet" />
|
28
|
+
<script type="text/javascript" src="javascripts/jquery-1.5.2.min.js"></script>
|
29
|
+
<script type="text/javascript" src="javascripts/jquery-ui-1.8.11.custom.min.js"></script>
|
30
|
+
<script type="text/javascript">
|
31
|
+
jQuery(document).ready(function(){
|
32
|
+
jQuery("#tabs-top").tabs();
|
33
|
+
jQuery(".taglib").tabs();
|
34
|
+
jQuery(".source").accordion({collapsible: true, active: false, autoHeight: false });
|
35
|
+
});
|
36
|
+
</script>
|
37
|
+
</head>
|
38
|
+
<body>
|
39
|
+
<div id="tabs-top">
|
40
|
+
<ul>
|
41
|
+
<% this.each {|taglib| %>
|
42
|
+
<tag-link content="&taglib.name" link="#{taglib.name}-taglib"/>
|
43
|
+
<% } %>
|
44
|
+
</ul>
|
45
|
+
<!-- unfortunately, <repeat> is problematic here -->
|
46
|
+
<% this.each {|taglib| %>
|
47
|
+
<div class="taglib" id="#{taglib.name}-taglib">
|
48
|
+
<%= taglib.comment_html %>
|
49
|
+
<ul>
|
50
|
+
<% taglib.tag_defs.each {|tag| %>
|
51
|
+
<tag-link content="&tag.name" link="#{tag.name}-tag"/>
|
52
|
+
<% } %>
|
53
|
+
</ul>
|
54
|
+
<% taglib.tag_defs.each {|tag| %>
|
55
|
+
<div id="#{tag.name}-tag">
|
56
|
+
|
57
|
+
<h2><%= tag.name %></h2>
|
58
|
+
|
59
|
+
<%= tag.comment_intro_html %>
|
60
|
+
|
61
|
+
<% if !tag.parameters.empty? %>
|
62
|
+
<h3>Parameters</h3>
|
63
|
+
<param-list with="&tag.parameters"/>
|
64
|
+
<% end %>
|
65
|
+
|
66
|
+
<%= tag.comment_rest_html %>
|
67
|
+
|
68
|
+
<div class="source">
|
69
|
+
<h3><a href="#">Source</a></h3>
|
70
|
+
<pre><code><%= h tag.source %></code></pre>
|
71
|
+
</div>
|
72
|
+
|
73
|
+
</div>
|
74
|
+
<% } %>
|
75
|
+
</div>
|
76
|
+
<% } %>
|
77
|
+
</div>
|
78
|
+
</body>
|
79
|
+
</html>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module HoboJquery
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < ::Rails::Generators::Base
|
4
|
+
source_root File.expand_path('../../../..', __FILE__)
|
5
|
+
|
6
|
+
desc "Installs javascript and css files for hobo-jquery, jquery and jquery-ui into public/"
|
7
|
+
def install
|
8
|
+
base_pathname = Pathname.new(File.expand_path('../../../../public', __FILE__))
|
9
|
+
Dir[File.expand_path('../../../../public/**/*.*', __FILE__)].each do |fn|
|
10
|
+
rfn=Pathname.new(fn).relative_path_from(base_pathname)
|
11
|
+
copy_file "public/#{rfn}", "public/#{rfn}"
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
base_pathname = Pathname.new(File.expand_path('../../../../jquery', __FILE__))
|
16
|
+
Dir[File.expand_path('../../../../jquery/**/*.*', __FILE__)].each do |fn|
|
17
|
+
rfn=Pathname.new(fn).relative_path_from(base_pathname)
|
18
|
+
copy_file "jquery/#{rfn}", "public/#{rfn}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/hobo-jquery.rb
ADDED
data/lib/render.rake
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# This requires a working hobo skeleton. Rather than create a
|
2
|
+
# symbolic dependency, I haven't included the skeleton.
|
3
|
+
#
|
4
|
+
# Link this file from lib/tasks/render.rake and link
|
5
|
+
# doc_generator.dryml to app/views/taglibs in your skeleton
|
6
|
+
|
7
|
+
desc "generate all"
|
8
|
+
task :generate_all => ["../hobo-jquery-gh-pages/README.html", "../hobo-jquery-gh-pages/documentation.html"]
|
9
|
+
|
10
|
+
desc "generate README.html"
|
11
|
+
file "../hobo-jquery-gh-pages/README.html" => [:environment, "#{RAILS_ROOT}/../hobo-jquery/README.markdown"] do |t|
|
12
|
+
sh "maruku --html #{RAILS_ROOT}/../hobo-jquery/README.markdown -o #{RAILS_ROOT}/../hobo-jquery-gh-pages/README.html"
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "generate documentation"
|
16
|
+
file "../hobo-jquery-gh-pages/documentation.html" => ["#{RAILS_ROOT}/app/views/taglibs/doc_generator.dryml", :environment]+Dir["#{RAILS_ROOT}/../hobo-jquery/taglibs/**/*.dryml"] do |t|
|
17
|
+
|
18
|
+
require 'maruku'
|
19
|
+
|
20
|
+
taglibs = Dir["#{RAILS_ROOT}/../hobo-jquery/taglibs/**/*.dryml"].reject {|filename|
|
21
|
+
File.basename(filename).match(/^hobo-jquery-.*/)
|
22
|
+
}.map {|filename|
|
23
|
+
Hobo::Dryml::DrymlDoc::Taglib.new("#{RAILS_ROOT}/../hobo-jquery/taglibs", filename)
|
24
|
+
}
|
25
|
+
|
26
|
+
src = open(t.prerequisites.first).read
|
27
|
+
locals = []
|
28
|
+
imports = []
|
29
|
+
renderer_class = Hobo::Dryml.make_renderer_class(src, File.dirname(t.prerequisites.first), locals, imports)
|
30
|
+
assigns = {}
|
31
|
+
view = ActionView::Base.new(ActionController::Base.view_paths, assigns)
|
32
|
+
view.extend(ActionView::Helpers::TagHelper)
|
33
|
+
view.extend(Hobo::HoboHelper)
|
34
|
+
view.extend(Hobo::RapidHelper)
|
35
|
+
renderer = renderer_class.new(File.basename(t.prerequisites.first, ".dryml"), view)
|
36
|
+
page_locals = ""
|
37
|
+
open(t.name, "w").write(renderer.render_page(taglibs, page_locals).strip)
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
/**
|
2
|
+
* Event.simulate(@element, eventName[, options]) -> Element
|
3
|
+
*
|
4
|
+
* - @element: element to fire event on
|
5
|
+
* - eventName: name of event to fire (only MouseEvents and HTMLEvents interfaces are supported)
|
6
|
+
* - options: optional object to fine-tune event properties - pointerX, pointerY, ctrlKey, etc.
|
7
|
+
*
|
8
|
+
* $('foo').simulate('click'); // => fires "click" event on an element with id=foo
|
9
|
+
*
|
10
|
+
**/
|
11
|
+
(function(){
|
12
|
+
|
13
|
+
var eventMatchers = {
|
14
|
+
'HTMLEvents': /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/,
|
15
|
+
'MouseEvents': /^(?:click|mouse(?:down|up|over|move|out))$/
|
16
|
+
}
|
17
|
+
var defaultOptions = {
|
18
|
+
pointerX: 0,
|
19
|
+
pointerY: 0,
|
20
|
+
button: 0,
|
21
|
+
ctrlKey: false,
|
22
|
+
altKey: false,
|
23
|
+
shiftKey: false,
|
24
|
+
metaKey: false,
|
25
|
+
bubbles: true,
|
26
|
+
cancelable: true
|
27
|
+
}
|
28
|
+
|
29
|
+
Event.simulate = function(element, eventName) {
|
30
|
+
var options = Object.extend(defaultOptions, arguments[2] || { });
|
31
|
+
var oEvent, eventType = null;
|
32
|
+
|
33
|
+
element = $(element);
|
34
|
+
|
35
|
+
for (var name in eventMatchers) {
|
36
|
+
if (eventMatchers[name].test(eventName)) { eventType = name; break; }
|
37
|
+
}
|
38
|
+
|
39
|
+
if (!eventType)
|
40
|
+
throw new SyntaxError('Only HTMLEvents and MouseEvents interfaces are supported');
|
41
|
+
|
42
|
+
if (document.createEvent) {
|
43
|
+
oEvent = document.createEvent(eventType);
|
44
|
+
if (eventType == 'HTMLEvents') {
|
45
|
+
oEvent.initEvent(eventName, options.bubbles, options.cancelable);
|
46
|
+
}
|
47
|
+
else {
|
48
|
+
oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView,
|
49
|
+
options.button, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
|
50
|
+
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element);
|
51
|
+
}
|
52
|
+
element.dispatchEvent(oEvent);
|
53
|
+
}
|
54
|
+
else {
|
55
|
+
options.clientX = options.pointerX;
|
56
|
+
options.clientY = options.pointerY;
|
57
|
+
oEvent = Object.extend(document.createEventObject(), options);
|
58
|
+
element.fireEvent('on' + eventName, oEvent);
|
59
|
+
}
|
60
|
+
return element;
|
61
|
+
}
|
62
|
+
|
63
|
+
Element.addMethods({ simulate: Event.simulate });
|
64
|
+
})()
|
@@ -0,0 +1,663 @@
|
|
1
|
+
// our monkey patches to Function, properly namespaced.
|
2
|
+
|
3
|
+
/* bind the context and return a lambda */
|
4
|
+
Function.prototype.hjq_bind = function(context) {
|
5
|
+
var that=this;
|
6
|
+
return function() {
|
7
|
+
return that.apply(context, arguments);
|
8
|
+
}
|
9
|
+
};
|
10
|
+
|
11
|
+
/* return a lambda that calls "this" and then calls "f". Depending on the return value of the lambda is probably a bad idea. */
|
12
|
+
Function.prototype.hjq_chain = function(f) {
|
13
|
+
var that=this;
|
14
|
+
return function() {
|
15
|
+
var r=that.apply(this, arguments);
|
16
|
+
if(f) {
|
17
|
+
r=f.apply(this, arguments);
|
18
|
+
}
|
19
|
+
return r;
|
20
|
+
}
|
21
|
+
};
|
22
|
+
|
23
|
+
// we add our own hide and show to jQuery so that we get consistent behaviour and so we can plug our tests in.
|
24
|
+
jQuery.fn.hjq_hide = function(options, callback) {
|
25
|
+
var settings = jQuery.extend({
|
26
|
+
effect: 'blind', speed: 500
|
27
|
+
}, options);
|
28
|
+
var cb = callback;
|
29
|
+
if(callback && hjq.hideComplete) {
|
30
|
+
cb = (function() {
|
31
|
+
callback.apply(this, arguments);
|
32
|
+
hjq.hideComplete.apply(this, arguments);
|
33
|
+
});
|
34
|
+
} else if (hjq.hideComplete) {
|
35
|
+
cb = hjq.hideComplete;
|
36
|
+
}
|
37
|
+
return this.hide(settings.effect, settings, settings.speed, cb);
|
38
|
+
};
|
39
|
+
|
40
|
+
jQuery.fn.hjq_show = function(options, callback) {
|
41
|
+
var cb = callback;
|
42
|
+
var settings = jQuery.extend({
|
43
|
+
effect: 'blind', speed: 500, callback: undefined
|
44
|
+
}, options);
|
45
|
+
if(callback && hjq.showComplete) {
|
46
|
+
cb = (function() {
|
47
|
+
settings.callback.apply(this, arguments);
|
48
|
+
hjq.showComplete.apply(this, arguments);
|
49
|
+
});
|
50
|
+
} else if (hjq.showComplete) {
|
51
|
+
cb = hjq.showComplete;
|
52
|
+
}
|
53
|
+
return this.show(settings.effect, settings, settings.speed, cb);
|
54
|
+
};
|
55
|
+
|
56
|
+
// Our monkey patches to Prototype
|
57
|
+
|
58
|
+
// the Hobo part mechanism uses Element.update to do it's work
|
59
|
+
Element.addMethods({update: Element.Methods.update.hjq_chain(function(id, content) {
|
60
|
+
if(!id.nodeType) id="#"+id; // assume it's a string
|
61
|
+
hjq.initialize.apply(jQuery(id));
|
62
|
+
})});
|
63
|
+
|
64
|
+
var hjq = (function() {
|
65
|
+
return {
|
66
|
+
|
67
|
+
/* calls all "init" functions with their this and their annotations */
|
68
|
+
initialize: function() {
|
69
|
+
jQuery(this).find('.hjq-annotated').each(function() {
|
70
|
+
var annotations = hjq.getAnnotations.call(this);
|
71
|
+
if(annotations.init) {
|
72
|
+
hjq.util.createFunction(annotations.init).call(this, annotations);
|
73
|
+
};
|
74
|
+
});
|
75
|
+
},
|
76
|
+
|
77
|
+
/* returns JSON annotations for *this* */
|
78
|
+
getAnnotations: function() {
|
79
|
+
// Unforunately, jQuery does not traverse comment nodes, so we're using the DOM methods directly
|
80
|
+
|
81
|
+
// previous is probably a textNode containing whitespace
|
82
|
+
var comment = this.previousSibling;
|
83
|
+
if(comment.nodeType!=Node.COMMENT_NODE) { comment = comment.previousSibling; }
|
84
|
+
if(comment.nodeType!=Node.COMMENT_NODE) { return ({}); }
|
85
|
+
|
86
|
+
var json = RegExp(/^\s*json_annotation\s*(\(\{.*\}\)\;)\s*$/).exec(comment.nodeValue)[1];
|
87
|
+
return eval(json);
|
88
|
+
},
|
89
|
+
|
90
|
+
/* given annotations, turns the values in the _events_ object into functions, merges them into _options_ and returns _options_ */
|
91
|
+
getOptions: function(annotations) {
|
92
|
+
for(var key in annotations.events) {
|
93
|
+
annotations.options[key] = hjq.util.createFunction(annotations.events[key]);
|
94
|
+
}
|
95
|
+
return annotations.options;
|
96
|
+
},
|
97
|
+
|
98
|
+
|
99
|
+
/* hooks for debugging & testing */
|
100
|
+
|
101
|
+
hideComplete: undefined,
|
102
|
+
|
103
|
+
bindHideCallback: function(f) {
|
104
|
+
/* FIXME: I suppose we should properly chain here....*/
|
105
|
+
hjq.hideComplete = f;
|
106
|
+
},
|
107
|
+
|
108
|
+
showComplete: undefined,
|
109
|
+
|
110
|
+
bindShowCallback: function(f) {
|
111
|
+
/* FIXME:chain */
|
112
|
+
hjq.showComplete = f;
|
113
|
+
},
|
114
|
+
|
115
|
+
/* these are functions I shouldn't be writing myself -- should be in a library somewhere! */
|
116
|
+
util: {
|
117
|
+
/* given a global function name, find the function */
|
118
|
+
functionByName: function(name) {
|
119
|
+
var descend = window; // find function by name on the root object
|
120
|
+
jQuery.each(name.split("."), function() {
|
121
|
+
if(descend) descend = descend[this];
|
122
|
+
});
|
123
|
+
return descend;
|
124
|
+
},
|
125
|
+
|
126
|
+
/* Given a function name or javascript fragment, return a function */
|
127
|
+
createFunction: function(script) {
|
128
|
+
if(!script) return function() {};
|
129
|
+
var f=hjq.util.functionByName(script);
|
130
|
+
if(f) return f;
|
131
|
+
return function() { return eval(script); };
|
132
|
+
},
|
133
|
+
|
134
|
+
/* Iterates through this and arguments until either a jQuery or an element is found, and returns it, jQuerified */
|
135
|
+
jQuerifyFirstElement: function() {
|
136
|
+
if(this.nodeType==1) return jQuery(this);
|
137
|
+
if(this.jquery) return this;
|
138
|
+
for(var i=0; i<arguments.length; i++) {
|
139
|
+
if(arguments[i].nodeType==1) return jQuery(arguments[i]);
|
140
|
+
if(arguments[i].jquery) return arguments[i];
|
141
|
+
}
|
142
|
+
return [];
|
143
|
+
},
|
144
|
+
|
145
|
+
/* log to console, if available */
|
146
|
+
log: function(s) {
|
147
|
+
if(console && console.log) console.log(s);
|
148
|
+
}
|
149
|
+
},
|
150
|
+
|
151
|
+
input_many: {
|
152
|
+
init: function (annotations) {
|
153
|
+
var me = jQuery(this);
|
154
|
+
|
155
|
+
// disable all elements inside our template, and mark them so we can find them later.
|
156
|
+
me.find(".input-many-template :input[disabled=false]").each(function() {
|
157
|
+
this.disabled = true;
|
158
|
+
jQuery(this).addClass("input_many_template_input");
|
159
|
+
});
|
160
|
+
|
161
|
+
// bind event handlers
|
162
|
+
me.find(".remove-item").click(hjq.input_many.removeOne);
|
163
|
+
me.find(".add-item").click(hjq.input_many.addOne);
|
164
|
+
},
|
165
|
+
|
166
|
+
addOne: function () {
|
167
|
+
var me = jQuery(this).parent().parent();
|
168
|
+
var top = me.parent();
|
169
|
+
var template = top.children("li.input-many-template");
|
170
|
+
var clone = template.clone(true).removeClass("input-many-template");
|
171
|
+
// length-2 because ignore the template li and the empty li
|
172
|
+
var name_updater = hjq.input_many.getNameUpdater.call(top, top.children().length-2);
|
173
|
+
var params = hjq.getAnnotations.call(top.get(0));
|
174
|
+
|
175
|
+
// enable previously marked elements
|
176
|
+
clone.find(".input_many_template_input").each(function() {
|
177
|
+
this.disabled = false;
|
178
|
+
jQuery(this).removeClass("input_many_template_input");
|
179
|
+
});
|
180
|
+
|
181
|
+
// update id & name
|
182
|
+
clone.find("*").each(function() {
|
183
|
+
name_updater.call(this);
|
184
|
+
});
|
185
|
+
name_updater.call(clone.get(0));
|
186
|
+
|
187
|
+
// do the add with anim
|
188
|
+
clone.css("display", "none").insertAfter(me).hjq_show();
|
189
|
+
|
190
|
+
// initialize subelements
|
191
|
+
hjq.initialize.call(me.next().get(0));
|
192
|
+
|
193
|
+
// and reinitialize low-pro too
|
194
|
+
Event.addBehavior.reload();
|
195
|
+
|
196
|
+
// visibility
|
197
|
+
if(me.hasClass("empty")) {
|
198
|
+
me.addClass("hidden");
|
199
|
+
me.find("input.empty-input").attr("disabled", true);
|
200
|
+
} else {
|
201
|
+
// now that we've added an element after us, we should only have a '-' button
|
202
|
+
me.children("div.buttons").children("button.remove-item").removeClass("hidden");
|
203
|
+
me.children("div.buttons").children("button.add-item").addClass("hidden");
|
204
|
+
}
|
205
|
+
|
206
|
+
hjq.util.createFunction(params.add_hook).call(me.get(0));
|
207
|
+
|
208
|
+
return false; // prevent bubbling
|
209
|
+
},
|
210
|
+
|
211
|
+
removeOne: function() {
|
212
|
+
var me = jQuery(this).parent().parent();
|
213
|
+
var top = me.parent();
|
214
|
+
var params = hjq.getAnnotations.call(top.get(0));
|
215
|
+
|
216
|
+
if(params.remove_hook) {
|
217
|
+
if(!hjq.util.createFunction(params.remove_hook).call(me.get(0))) {
|
218
|
+
return false;
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
// rename everybody from me onwards
|
223
|
+
var i=hjq.input_many.getIndex.call(me.get(0))
|
224
|
+
var n=me.next();
|
225
|
+
for(; n.length>0; i+=1, n=n.next()) {
|
226
|
+
var name_updater = hjq.input_many.getNameUpdater.call(top, i);
|
227
|
+
n.find("*").each(function() {
|
228
|
+
name_updater.call(this);
|
229
|
+
});
|
230
|
+
name_updater.call(n.get(0));
|
231
|
+
}
|
232
|
+
|
233
|
+
// adjust +/- buttons on the button element as appropriate
|
234
|
+
var last=top.children("li:last");
|
235
|
+
if(last.get(0)==me.get(0)) {
|
236
|
+
last = last.prev();
|
237
|
+
}
|
238
|
+
|
239
|
+
if(last.hasClass("empty")) {
|
240
|
+
last.removeClass("hidden");
|
241
|
+
last.find("input.empty-input").removeAttr("disabled");
|
242
|
+
} else {
|
243
|
+
// if we've reached the minimum, we don't want to add the '-' button
|
244
|
+
if(top.children().length-3 <= (params['minimum']||0)) {
|
245
|
+
last.children("div.buttons").children("button.remove-item").addClass("hidden");
|
246
|
+
} else {
|
247
|
+
last.children("div.buttons").children("button.remove-item").removeClass("hidden");
|
248
|
+
}
|
249
|
+
last.children("div.buttons").children("button.add-item").removeClass("hidden");
|
250
|
+
}
|
251
|
+
|
252
|
+
// remove with animation
|
253
|
+
me.hjq_hide({}, function() { jQuery(this).remove(); });
|
254
|
+
|
255
|
+
return false; //prevent bubbling
|
256
|
+
},
|
257
|
+
|
258
|
+
// given this==the input-many, returns a lambda that updates the name & id for an element
|
259
|
+
getNameUpdater: function(new_index) {
|
260
|
+
var name_prefix = Hobo.getClassData(this.get(0), 'input-many-prefix');
|
261
|
+
var id_prefix = name_prefix.replace(/\[/g, "_").replace(/\]/g, "");
|
262
|
+
var name_re = RegExp("^" + RegExp.escape(name_prefix)+ "\[\-?[0-9]+\]");
|
263
|
+
var name_sub = name_prefix + '[' + new_index.toString() + ']';
|
264
|
+
var id_re = RegExp("^" + RegExp.escape(id_prefix)+ "_\-?[0-9]+");
|
265
|
+
var id_sub = id_prefix + '_' + new_index.toString();
|
266
|
+
var class_re = RegExp(RegExp.escape(name_prefix)+ "\[\-?[0-9]+\]");
|
267
|
+
var class_sub = name_sub;
|
268
|
+
|
269
|
+
return function() {
|
270
|
+
if(this.name) {
|
271
|
+
this.name = this.name.replace(name_re, name_sub);
|
272
|
+
}
|
273
|
+
if (id_prefix==this.id.slice(0, id_prefix.length)) {
|
274
|
+
this.id = this.id.replace(id_re, id_sub);
|
275
|
+
} else {
|
276
|
+
// silly rails. text_area_tag and text_field_tag use different conventions for the id.
|
277
|
+
if(name_prefix==this.id.slice(0, name_prefix.length)) {
|
278
|
+
this.id = this.id.replace(name_re, name_sub);
|
279
|
+
} /* else {
|
280
|
+
hjq.util.log("hjq.input_many.update_id: id_prefix "+id_prefix+" didn't match input "+this.id);
|
281
|
+
} */
|
282
|
+
}
|
283
|
+
if (class_re.test(this.className)) {
|
284
|
+
this.className = this.className.replace(class_re, class_sub);
|
285
|
+
}
|
286
|
+
return this;
|
287
|
+
};
|
288
|
+
},
|
289
|
+
|
290
|
+
// given this==an input-many item, get the submit index
|
291
|
+
getIndex: function() {
|
292
|
+
return Number(this.id.match(/\[([0-9])+\]$/)[1]);
|
293
|
+
}
|
294
|
+
|
295
|
+
},
|
296
|
+
|
297
|
+
form: {
|
298
|
+
/* this function uses the jquery form plugin to submit the
|
299
|
+
form via jquery form plugin ajax, rather than using the
|
300
|
+
standard HTTP or Hobo form submission mechanisms. The
|
301
|
+
main advantage this has is that the jquery form plugin
|
302
|
+
supports ajax submission of attachments.
|
303
|
+
|
304
|
+
You must have the jquery form plugin installed. It is
|
305
|
+
not installed automatically by hobo-jquery.
|
306
|
+
|
307
|
+
FIXME: this function HARD CODES it's ajax options, in
|
308
|
+
particular update="attachments-div". It does not (yet)
|
309
|
+
get the parameters from the form, nor does it get them
|
310
|
+
through the standard hobo-jquery mechanism.
|
311
|
+
*/
|
312
|
+
submit: function() {
|
313
|
+
var attrs = {
|
314
|
+
update: ['attachments-div']
|
315
|
+
};
|
316
|
+
var options = {
|
317
|
+
complete: Hobo.hideSpinner,
|
318
|
+
data: {},
|
319
|
+
dataType: 'script',
|
320
|
+
beforeSend: function(xhr) { xhr.setRequestHeader("Accept", "text/javascript"); }
|
321
|
+
};
|
322
|
+
var form = jQuery(this).closest("form");
|
323
|
+
|
324
|
+
for(i=0; i<attrs.update.length; i++) {
|
325
|
+
var id = attrs.update[i];
|
326
|
+
if(id=="self") {
|
327
|
+
for(var el=jQuery(this); el.length && !hoboParts[el.attr("id")]; el=el.parent());
|
328
|
+
id = ( el.length ? el.attr("id") : undefined) ;
|
329
|
+
}
|
330
|
+
if(id) {
|
331
|
+
options.data["render["+i+"][part_context]"] = hoboParts[id];
|
332
|
+
options.data["render["+i+"][id]"] = id;
|
333
|
+
}
|
334
|
+
}
|
335
|
+
|
336
|
+
Hobo.showSpinner(attrs.message || "Saving...", attrs.spinner_next_to);
|
337
|
+
form.ajaxSubmit(options);
|
338
|
+
|
339
|
+
//prevent bubbling
|
340
|
+
return false;
|
341
|
+
}
|
342
|
+
},
|
343
|
+
|
344
|
+
formlet: {
|
345
|
+
// call with this==the formlet or a child of the formlet to submit the formlet
|
346
|
+
submit: function(extra_callbacks, extra_options) {
|
347
|
+
var formlet = jQuery(jQuery(this).closest(".formlet").get(0));
|
348
|
+
var annotations = hjq.getAnnotations.call(formlet.get(0));
|
349
|
+
|
350
|
+
var options = annotations.ajax_options;
|
351
|
+
var attrs = annotations.ajax_attrs;
|
352
|
+
jQuery.extend(options, extra_options);
|
353
|
+
|
354
|
+
if(!extra_callbacks) extra_callbacks = {};
|
355
|
+
|
356
|
+
if(attrs.before) {
|
357
|
+
if(!hjq.util.createFunction(attrs.before).call(formlet.get(0))) {
|
358
|
+
return false;
|
359
|
+
}
|
360
|
+
}
|
361
|
+
|
362
|
+
if(attrs.confirm) {
|
363
|
+
if(!confirm(attrs.confirm)) {
|
364
|
+
return false;
|
365
|
+
}
|
366
|
+
}
|
367
|
+
|
368
|
+
// make sure we don't serialize any nested forms
|
369
|
+
options.data = formlet.find(":input").
|
370
|
+
not(formlet.find("form :input")).
|
371
|
+
not(formlet.find(".formlet :input")).
|
372
|
+
serialize();
|
373
|
+
options.dataType = 'script';
|
374
|
+
|
375
|
+
// we tell our controller which parts to return by sending it a "render" array.
|
376
|
+
for(i=0; i<attrs.update.length; i++) {
|
377
|
+
var id = attrs.update[i];
|
378
|
+
if(id=="self") {
|
379
|
+
for(var el=jQuery(this); el.length && !hoboParts[el.attr("id")]; el=el.parent());
|
380
|
+
id = ( el.length ? el.attr("id") : undefined) ;
|
381
|
+
}
|
382
|
+
if(id) {
|
383
|
+
options.data += "&" + encodeURIComponent("render["+i+"][part_context]") + "=" + encodeURIComponent(hoboParts[id]);
|
384
|
+
options.data += "&" + encodeURIComponent("render["+i+"][id]") + "=" + id;
|
385
|
+
}
|
386
|
+
}
|
387
|
+
|
388
|
+
Hobo.showSpinner(attrs.message || "Saving...", attrs.spinner_next_to);
|
389
|
+
|
390
|
+
options.success = hjq.util.createFunction(attrs.success).hjq_chain(extra_callbacks.success).hjq_bind(formlet.get(0));
|
391
|
+
options.error = hjq.util.createFunction(attrs.error).hjq_chain(extra_callbacks.error).hjq_bind(formlet.get(0));
|
392
|
+
options.complete = Hobo.hideSpinner.hjq_chain(hjq.util.createFunction(attrs.complete)).hjq_chain(extra_callbacks.complete).hjq_bind(formlet.get(0));
|
393
|
+
|
394
|
+
jQuery.ajax(options);
|
395
|
+
|
396
|
+
//prevent bubbling
|
397
|
+
return false;
|
398
|
+
}
|
399
|
+
},
|
400
|
+
|
401
|
+
datepicker: {
|
402
|
+
init: function(annotations) {
|
403
|
+
if(!this.disabled) {
|
404
|
+
jQuery(this).datepicker(hjq.getOptions(annotations));
|
405
|
+
}
|
406
|
+
}
|
407
|
+
},
|
408
|
+
|
409
|
+
autocomplete: {
|
410
|
+
init: function(annotations) {
|
411
|
+
if(!this.disabled) {
|
412
|
+
jQuery(this).autocomplete(hjq.getOptions(annotations));
|
413
|
+
}
|
414
|
+
}
|
415
|
+
},
|
416
|
+
|
417
|
+
combobox: {
|
418
|
+
init: function(annotations) {
|
419
|
+
var select = jQuery(this).find('select');
|
420
|
+
if(!select.attr('disabled')) {
|
421
|
+
var options = hjq.getOptions(annotations);
|
422
|
+
options.selected = options.selected || function(event, ui) {
|
423
|
+
// fire the prototype.js event on the <select/> for backwards compatibility
|
424
|
+
$(this).simulate('change');
|
425
|
+
}
|
426
|
+
select.combobox(options);
|
427
|
+
}
|
428
|
+
}
|
429
|
+
},
|
430
|
+
|
431
|
+
dialog: {
|
432
|
+
init: function(annotations) {
|
433
|
+
var options=hjq.getOptions(annotations);
|
434
|
+
if(!options.position) {
|
435
|
+
var pos = jQuery(this).prev().position();
|
436
|
+
options.position = [pos.left, pos.top];
|
437
|
+
}
|
438
|
+
if(annotations.buttons) {
|
439
|
+
options.buttons = {};
|
440
|
+
for(var i=0; i<annotations.buttons.length; i++) {
|
441
|
+
options.buttons[annotations.buttons[i][0]] = hjq.util.createFunction(annotations.buttons[i][1])
|
442
|
+
}
|
443
|
+
}
|
444
|
+
jQuery(this).dialog(options);
|
445
|
+
},
|
446
|
+
|
447
|
+
/* useful in the "buttons" option. Dialog is an optional parameter -- if not set, 'this' is closed instead. */
|
448
|
+
close: function() {
|
449
|
+
var jq=hjq.util.jQuerifyFirstElement.apply(this, arguments);
|
450
|
+
if(!jq.hasClass("hjq-dialog")) jq=jq.parents(".hjq-dialog");
|
451
|
+
jq.dialog('close');
|
452
|
+
},
|
453
|
+
|
454
|
+
/* useful in the "buttons" option. Will submit any enclosed formlets. */
|
455
|
+
submit_formlet: function(extra_options, extra_attrs) {
|
456
|
+
jQuery(this).find(".formlet").each(function() {
|
457
|
+
hjq.formlet.submit.call(this, extra_options, extra_attrs);
|
458
|
+
});
|
459
|
+
},
|
460
|
+
|
461
|
+
/* useful in the "buttons" option. Will submit all enclosed forms, whether AJAX or not */
|
462
|
+
submit_form: function() {
|
463
|
+
jQuery(this).find("form").each(function() {
|
464
|
+
if(jQuery(this).attr("onsubmit")) {
|
465
|
+
eval("onsubmit_func = function() {\n"+jQuery(this).attr("onsubmit")+"\n}");
|
466
|
+
onsubmit_func.apply(this);
|
467
|
+
} else {
|
468
|
+
this.submit();
|
469
|
+
}
|
470
|
+
});
|
471
|
+
},
|
472
|
+
|
473
|
+
/* calls submit_form, and then closes the dialog box. */
|
474
|
+
|
475
|
+
/* useful in the "buttons" option. Submits any enclosed formlets, and closes them */
|
476
|
+
submit_formlet_and_close: function() {
|
477
|
+
var dialog = jQuery(this);
|
478
|
+
hjq.dialog.submit_formlet.call(this, {success: function() {hjq.dialog.close.call(dialog);}});
|
479
|
+
}
|
480
|
+
},
|
481
|
+
|
482
|
+
dialog_opener: {
|
483
|
+
click: function(button, selector) {
|
484
|
+
var dialog = jQuery(selector);
|
485
|
+
if(dialog.dialog('isOpen')) {
|
486
|
+
dialog.dialog('close');
|
487
|
+
} else {
|
488
|
+
dialog.dialog('open');
|
489
|
+
}
|
490
|
+
}
|
491
|
+
}
|
492
|
+
};
|
493
|
+
})();
|
494
|
+
|
495
|
+
|
496
|
+
/* stolen from http://jqueryui.com/demos/autocomplete/#combobox
|
497
|
+
*
|
498
|
+
* and these options added.
|
499
|
+
*
|
500
|
+
* - autoFill (default: true): select first value rather than clearing if there's a match
|
501
|
+
*
|
502
|
+
* - clearButton (default: true): add a "clear" button
|
503
|
+
*
|
504
|
+
* - adjustWidth (default: true): if true, will set the autocomplete width the same as
|
505
|
+
* the old select. (requires jQuery 1.4.4 to work on IE8)
|
506
|
+
*
|
507
|
+
* - uiStyle (default: false): if true, will add classes so that the autocomplete input
|
508
|
+
* takes a jQuery-UI style
|
509
|
+
*/
|
510
|
+
(function( $ ) {
|
511
|
+
$.widget( "ui.combobox", {
|
512
|
+
options: {
|
513
|
+
autoFill: true,
|
514
|
+
clearButton: true,
|
515
|
+
adjustWidth: true,
|
516
|
+
uiStyle: false,
|
517
|
+
selected: null,
|
518
|
+
},
|
519
|
+
_create: function() {
|
520
|
+
var self = this,
|
521
|
+
select = this.element.hide(),
|
522
|
+
selected = select.children( ":selected" ),
|
523
|
+
value = selected.val() ? selected.text() : "",
|
524
|
+
found = false;
|
525
|
+
var input = this.input = $( "<input>" )
|
526
|
+
.attr('title', '' + select.attr("title") + '')
|
527
|
+
.insertAfter( select )
|
528
|
+
.val( value )
|
529
|
+
.autocomplete({
|
530
|
+
delay: 0,
|
531
|
+
minLength: 0,
|
532
|
+
source: function( request, response ) {
|
533
|
+
var matcher = new RegExp( $.ui.autocomplete.escapeRegex(request.term), "i" );
|
534
|
+
var resp = select.children( "option" ).map(function() {
|
535
|
+
var text = $( this ).text();
|
536
|
+
if ( this.value && ( !request.term || matcher.test(text) ) )
|
537
|
+
return {
|
538
|
+
label: text.replace(
|
539
|
+
new RegExp(
|
540
|
+
"(?![^&;]+;)(?!<[^<>]*)(" +
|
541
|
+
$.ui.autocomplete.escapeRegex(request.term) +
|
542
|
+
")(?![^<>]*>)(?![^&;]+;)", "gi"
|
543
|
+
), "<strong>$1</strong>" ),
|
544
|
+
value: text,
|
545
|
+
option: this
|
546
|
+
};
|
547
|
+
});
|
548
|
+
found = resp.length > 0;
|
549
|
+
response( resp );
|
550
|
+
},
|
551
|
+
select: function( event, ui ) {
|
552
|
+
ui.item.option.selected = true;
|
553
|
+
self._trigger( "selected", event, {
|
554
|
+
item: ui.item.option
|
555
|
+
});
|
556
|
+
},
|
557
|
+
change: function( event, ui ) {
|
558
|
+
if ( !ui.item ) {
|
559
|
+
var matcher = new RegExp( "^" + $.ui.autocomplete.escapeRegex( $(this).val() ) + "$", "i" ),
|
560
|
+
valid = false;
|
561
|
+
select.children( "option" ).each(function() {
|
562
|
+
if ( $( this ).text().match( matcher ) ) {
|
563
|
+
this.selected = valid = true;
|
564
|
+
return false;
|
565
|
+
}
|
566
|
+
});
|
567
|
+
if ( !valid || input.data("autocomplete").term=="" ) {
|
568
|
+
// set to first suggestion, unless blank or autoFill is turned off
|
569
|
+
var suggestion;
|
570
|
+
if(!self.options.autoFill || input.data("autocomplete").term=="") found=false;
|
571
|
+
if(found) {
|
572
|
+
suggestion = jQuery(input.data("autocomplete").widget()).find("li:first");
|
573
|
+
var option = select.find("option:contains('"+suggestion.text()+"')").attr('selected', true);
|
574
|
+
$(this).val(suggestion.text());
|
575
|
+
input.data("autocomplete").term = suggestion.text();
|
576
|
+
self._trigger( "selected", event, { item: option[0] });
|
577
|
+
} else {
|
578
|
+
select.find("option:selected").removeAttr("selected");
|
579
|
+
$(this).val('');
|
580
|
+
input.data( "autocomplete" ).term = '';
|
581
|
+
self._trigger( "selected", event, { item: null });
|
582
|
+
}
|
583
|
+
return found;
|
584
|
+
}
|
585
|
+
}
|
586
|
+
}
|
587
|
+
});
|
588
|
+
|
589
|
+
if( self.options.adjustWidth ) { input.width(select.width()); }
|
590
|
+
|
591
|
+
if( self.options.uiStyle ) {
|
592
|
+
input.addClass( "ui-widget ui-widget-content ui-corner-left" );
|
593
|
+
}
|
594
|
+
|
595
|
+
|
596
|
+
input.data( "autocomplete" )._renderItem = function( ul, item ) {
|
597
|
+
return $( "<li></li>" )
|
598
|
+
.data( "item.autocomplete", item )
|
599
|
+
.append( "<a>" + item.label + "</a>" )
|
600
|
+
.appendTo( ul );
|
601
|
+
};
|
602
|
+
|
603
|
+
this.button = $( "<button type='button'> </button>" )
|
604
|
+
.attr( "tabIndex", -1 )
|
605
|
+
.attr( "title", "Show All Items" )
|
606
|
+
.insertAfter( input )
|
607
|
+
.button({
|
608
|
+
icons: {
|
609
|
+
primary: "ui-icon-triangle-1-s"
|
610
|
+
},
|
611
|
+
text: false
|
612
|
+
})
|
613
|
+
.removeClass( "ui-corner-all" )
|
614
|
+
.addClass( "ui-corner-right ui-button-icon" )
|
615
|
+
.click(function() {
|
616
|
+
// close if already visible
|
617
|
+
if ( input.autocomplete( "widget" ).is( ":visible" ) ) {
|
618
|
+
input.autocomplete( "close" );
|
619
|
+
return;
|
620
|
+
}
|
621
|
+
|
622
|
+
// work around a bug (likely same cause as #5265)
|
623
|
+
$( this ).blur();
|
624
|
+
|
625
|
+
// pass empty string as value to search for, displaying all results
|
626
|
+
input.autocomplete( "search", "" );
|
627
|
+
input.focus();
|
628
|
+
});
|
629
|
+
|
630
|
+
if( self.options.clearButton ) {
|
631
|
+
this.clear_button = $( "<button type='button'> </button>" )
|
632
|
+
.attr( "tabIndex", -1 )
|
633
|
+
.attr( "title", "Clear Entry" )
|
634
|
+
.insertAfter( input )
|
635
|
+
.button({
|
636
|
+
icons: {
|
637
|
+
primary: "ui-icon-close"
|
638
|
+
},
|
639
|
+
text: false
|
640
|
+
})
|
641
|
+
.removeClass( "ui-corner-all" )
|
642
|
+
.click(function(event, ui) {
|
643
|
+
|
644
|
+
select.find("option:selected").removeAttr("selected");
|
645
|
+
input.val( "" );
|
646
|
+
input.data( "autocomplete" ).term = "";
|
647
|
+
self._trigger( "selected", event, { item: null });
|
648
|
+
|
649
|
+
// work around a bug (likely same cause as #5265)
|
650
|
+
$( this ).blur();
|
651
|
+
});
|
652
|
+
}
|
653
|
+
|
654
|
+
},
|
655
|
+
|
656
|
+
destroy: function() {
|
657
|
+
this.input.remove();
|
658
|
+
this.button.remove();
|
659
|
+
this.element.show();
|
660
|
+
$.Widget.prototype.destroy.call( this );
|
661
|
+
}
|
662
|
+
});
|
663
|
+
})( jQuery );
|