scaffolding_extensions 1.0.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.
- data/LICENSE +19 -0
- data/README +144 -0
- data/contrib/scaffold_associations_tree/README +9 -0
- data/contrib/scaffold_associations_tree/bullet.gif +0 -0
- data/contrib/scaffold_associations_tree/minus.gif +0 -0
- data/contrib/scaffold_associations_tree/plus.gif +0 -0
- data/contrib/scaffold_associations_tree/scaffold_associations_tree.css +20 -0
- data/contrib/scaffold_associations_tree/scaffold_associations_tree.js +57 -0
- data/contrib/scaffold_auto_complete_style/README +8 -0
- data/contrib/scaffold_auto_complete_style/auto_complete.css +23 -0
- data/contrib/scaffold_form_focus/README +12 -0
- data/contrib/scaffold_form_focus/scaffold_form_focus.js +21 -0
- data/contrib/scaffold_jquery_autocomplete/README +8 -0
- data/contrib/scaffold_jquery_autocomplete/jquery.ui.se_autocomplete.css +22 -0
- data/contrib/scaffold_jquery_autocomplete/jquery.ui.se_autocomplete.js +121 -0
- data/doc/advanced.txt +154 -0
- data/doc/camping.txt +25 -0
- data/doc/controller_spec.txt +20 -0
- data/doc/conversion.txt +102 -0
- data/doc/model_spec.txt +54 -0
- data/doc/ramaze.txt +20 -0
- data/doc/sinatra.txt +20 -0
- data/doc/testing.txt +12 -0
- data/lib/scaffolding_extensions.rb +89 -0
- data/lib/scaffolding_extensions/controller.rb +79 -0
- data/lib/scaffolding_extensions/controller/action_controller.rb +116 -0
- data/lib/scaffolding_extensions/controller/camping.rb +150 -0
- data/lib/scaffolding_extensions/controller/ramaze.rb +116 -0
- data/lib/scaffolding_extensions/controller/sinatra.rb +183 -0
- data/lib/scaffolding_extensions/helper.rb +304 -0
- data/lib/scaffolding_extensions/jquery_helper.rb +58 -0
- data/lib/scaffolding_extensions/meta_controller.rb +337 -0
- data/lib/scaffolding_extensions/meta_model.rb +571 -0
- data/lib/scaffolding_extensions/model.rb +30 -0
- data/lib/scaffolding_extensions/model/active_record.rb +184 -0
- data/lib/scaffolding_extensions/model/ardm.rb +47 -0
- data/lib/scaffolding_extensions/model/data_mapper.rb +190 -0
- data/lib/scaffolding_extensions/overridable.rb +67 -0
- data/lib/scaffolding_extensions/prototype_helper.rb +59 -0
- data/scaffolds/edit.rhtml +12 -0
- data/scaffolds/habtm.rhtml +24 -0
- data/scaffolds/index.rhtml +6 -0
- data/scaffolds/layout.rhtml +82 -0
- data/scaffolds/list.rhtml +13 -0
- data/scaffolds/listtable.rhtml +46 -0
- data/scaffolds/manage.rhtml +15 -0
- data/scaffolds/merge.rhtml +23 -0
- data/scaffolds/new.rhtml +5 -0
- data/scaffolds/search.rhtml +11 -0
- data/scaffolds/show.rhtml +19 -0
- data/test/scaffolding_extensions_test.rb +44 -0
- metadata +106 -0
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2004-2008 Jeremy Evans
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
= ScaffoldingExtensions
|
2
|
+
|
3
|
+
Scaffolding Extensions provides a powerful and simple to use administrative
|
4
|
+
interface to perform common actions on models. It has the following features:
|
5
|
+
|
6
|
+
* Creates pages for browsing, creating, deleting, displaying, updating,
|
7
|
+
searching, and merging records
|
8
|
+
* Choose which fields are displayed in the scaffolds and in which order
|
9
|
+
* Handles associated records for common one-to-many, many-to-one, and
|
10
|
+
many-to-many associations
|
11
|
+
* Extensive support for modifying the display and working of the plugin
|
12
|
+
* Advanced features such as access control, autocompleting, and eager loading
|
13
|
+
|
14
|
+
Scaffolding Extensions is not a code generator, and isn't really scaffolding at
|
15
|
+
all, as you are not expected to modify the output. Instead, you use
|
16
|
+
configuration options inside the model to control the display of the pages.
|
17
|
+
The scaffolding analogy is misleading, Scaffolding Extensions is not really
|
18
|
+
scaffolding--it is a completely functional structure that you can easily modify
|
19
|
+
to better suit your needs.
|
20
|
+
|
21
|
+
Scaffolding Extensions currently supports:
|
22
|
+
|
23
|
+
* Web Frameworks
|
24
|
+
* Rails 2.0
|
25
|
+
* Ramaze 0.3.5
|
26
|
+
* Camping 1.5
|
27
|
+
* Sinatra 0.1.7
|
28
|
+
* Object/Relational Mappers
|
29
|
+
* ActiveRecord 2.0
|
30
|
+
* DataMapper 0.2.5
|
31
|
+
* Javascript Libaries (used for Ajax/Autocompleting)
|
32
|
+
* Prototype 1.6.0.1
|
33
|
+
* JQuery 1.2.3
|
34
|
+
|
35
|
+
Support for other web frameworks and ORMs can be added, see the
|
36
|
+
controller_spec.txt and model_spec.txt files for the methods that need to be
|
37
|
+
defined.
|
38
|
+
|
39
|
+
The current version of Scaffolding Extensions is quite different from older
|
40
|
+
versions (svn revision 89 and previous). Older versions of Rails should be
|
41
|
+
able to use an older version of the plugin, which won't be discussed further as
|
42
|
+
it is substantially different from the current version (see the conversion.txt
|
43
|
+
file for details).
|
44
|
+
|
45
|
+
You can get Scaffolding Extensions via subversion or as a gem:
|
46
|
+
|
47
|
+
* svn: svn://code.jeremyevans.net/rails-plugins/scaffolding_extensions
|
48
|
+
* gem: sudo gem install scaffolding_extensions
|
49
|
+
* RDoc: http://code.jeremyevans.net/doc/scaffolding_extensions
|
50
|
+
* Bug Tracker: http://rubyforge.org/tracker/?atid=22169&group_id=5726&func=browse
|
51
|
+
* Forum: http://rubyforge.org/forum/forum.php?forum_id=22403
|
52
|
+
|
53
|
+
== Quick Start
|
54
|
+
|
55
|
+
The recommended use of the plugin is to execute:
|
56
|
+
|
57
|
+
scaffold_all_models
|
58
|
+
|
59
|
+
inside of a controller. We'll assume the path to the controller is /admin.
|
60
|
+
|
61
|
+
Then go to the index page for the controller (e.g. http://website/admin).
|
62
|
+
You'll see a link to a management page for each of your models. Each
|
63
|
+
management page has links to browse, create, delete, edit, show, search, and
|
64
|
+
merge pages for the model. The pages are usable right away, but you'll want to
|
65
|
+
add some configuration code to your models to specify the default names to
|
66
|
+
display in select boxes, attributes to show on the forms, associations to show,
|
67
|
+
whether to use select boxes or autocompleting text boxes, etc..
|
68
|
+
|
69
|
+
== Customization
|
70
|
+
|
71
|
+
The main reason to use this plugin are the features and extent of customization
|
72
|
+
it provides. Customization is done by adding methods and instance variables
|
73
|
+
to the model class itself. Here are some common customizations:
|
74
|
+
|
75
|
+
class Album < ActiveRecord::Base
|
76
|
+
has_and_belongs_to_many :artists
|
77
|
+
belongs_to :genre
|
78
|
+
@scaffold_fields = [:name, :rating, :genre, :numtracks]
|
79
|
+
@scaffold_select_order = 'name'
|
80
|
+
@scaffold_column_names = {:numtracks=>'Number of Tracks'}
|
81
|
+
@scaffold_use_auto_complete = true
|
82
|
+
def scaffold_name
|
83
|
+
name[0...50]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
@scaffold_fields determines which fields are shown in the new, edit, and search
|
88
|
+
forms (which use the order specified). It should be a list of symbols. If you
|
89
|
+
want some pages to show more fields than others, you can define variables such
|
90
|
+
as @scaffold_edit_fields or @scaffold_search_fields to override the defaults
|
91
|
+
for certain pages.
|
92
|
+
|
93
|
+
@scaffold_select_order determines which order is used in the SQL ORDER BY
|
94
|
+
clause when displaying a list of objects (for example, when choosing an object
|
95
|
+
to edit).
|
96
|
+
|
97
|
+
@scaffold_column_names specifies the visible names for each attribute.
|
98
|
+
|
99
|
+
@scaffold_use_auto_complete turns on autocompleting for the model, instead
|
100
|
+
of using select boxes (necessary for a decent response time if you have a large
|
101
|
+
number of records). See the advanced.txt for more autocompleting options.
|
102
|
+
|
103
|
+
scaffold_name is an instance method that determines the name to use for each
|
104
|
+
album inside those select boxes.
|
105
|
+
|
106
|
+
Notice in this case that genre was specified. In this case, our schema has
|
107
|
+
genre_id as a foreign key to the genres table. If you specified genre_id,
|
108
|
+
you'd get a usual text input box for the foreign key integer. If you specify
|
109
|
+
genre (the name of the belongs_to association), instead of a text input box,
|
110
|
+
you will get a select box with all genres, allowing you to pick one. It will
|
111
|
+
use the @scaffold_select_order variable and scaffold_name method in the Genre
|
112
|
+
model to format the select box (though this can be overridden with the
|
113
|
+
@scaffold_genre_select_order_association variable in the Album model).
|
114
|
+
|
115
|
+
If you have @scaffold_auto_complete_options set in the Genre model (or
|
116
|
+
@scaffold_genre_association_use_auto_complete set in the Album model), there
|
117
|
+
will be an autocompleting text box instead of a select box (though since there
|
118
|
+
aren't that many genres, you would probably be better off with a select box in
|
119
|
+
this case).
|
120
|
+
|
121
|
+
There are a ton of other customization options:
|
122
|
+
|
123
|
+
* Override the input widget type and widget options per attribute
|
124
|
+
* Choose which associations to display on the edit screen of a model
|
125
|
+
* Choose which associations to eagerly load when displaying select boxes for
|
126
|
+
the model
|
127
|
+
* Set the number of records returned in searching or browsing
|
128
|
+
* Specify different fields used in each type of scaffold (e.g. certain fields
|
129
|
+
can only be viewed, not edited)
|
130
|
+
* Control access to the model via a session variable (e.g. so a user can only
|
131
|
+
see objects with a matching user_id)
|
132
|
+
|
133
|
+
Consult advanced.txt and/or the RDoc if you would like more information on
|
134
|
+
these (and many other options).
|
135
|
+
|
136
|
+
== Testing
|
137
|
+
|
138
|
+
See the testing.txt file for details on the plugin's automated test suite and
|
139
|
+
Rails functional testing support.
|
140
|
+
|
141
|
+
== Questions?
|
142
|
+
|
143
|
+
Please post on the RubyForge forum if you have any questions about Scaffolding
|
144
|
+
Extensions.
|
@@ -0,0 +1,9 @@
|
|
1
|
+
This allows you to change the scaffolded display of associated items in the
|
2
|
+
edit view from a simple list to a explorer-style clickable tree.
|
3
|
+
|
4
|
+
To use this, include the .gifs in the /images subdirectory (or modify the .css
|
5
|
+
file), and add the .css and .js files to the layout.
|
6
|
+
|
7
|
+
Then set this in your application's environment:
|
8
|
+
|
9
|
+
ActiveRecord::Base::SCAFFOLD_OPTIONS[:association_list_class] = 'scaffold_associations_tree'
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,20 @@
|
|
1
|
+
/* Turn off list bullets */
|
2
|
+
ul.scaffold_associations_tree li { list-style: none; }
|
3
|
+
|
4
|
+
ul.scaffold_associations_tree, ul.scaffold_associations_tree ul, ul.scaffold_associations_tree li {
|
5
|
+
margin: 0;
|
6
|
+
padding: 0;
|
7
|
+
}
|
8
|
+
|
9
|
+
/* This controls the indent for each sublist */
|
10
|
+
ul.scaffold_associations_tree ul, ul.scaffold_associations_tree li a.treestatus { padding-left: 20px; }
|
11
|
+
|
12
|
+
/* Show "bullets" in the links, depending on the class of the
|
13
|
+
LI that the link's in */
|
14
|
+
ul.scaffold_associations_tree li.sat_open a.treestatus { background: url("/images/minus.gif") center left no-repeat; }
|
15
|
+
ul.scaffold_associations_tree li.sat_closed a.treestatus { background: url("/images/plus.gif") center left no-repeat; }
|
16
|
+
ul.scaffold_associations_tree li.sat_bullet a.treestatus { background: url("/images/bullet.gif") center left no-repeat; }
|
17
|
+
|
18
|
+
/* Actually show and hide sublists */
|
19
|
+
ul.scaffold_associations_tree li.sat_open ul { display: block; }
|
20
|
+
ul.scaffold_associations_tree li.sat_closed ul { display: none; }
|
@@ -0,0 +1,57 @@
|
|
1
|
+
/* Based on aqtree3clickable from http://www.kryogenix.org/code/browser/aqlists/
|
2
|
+
Modifications by Jeremy Evans (code@jeremyevans.net) */
|
3
|
+
|
4
|
+
addEvent(window, "load", makeTreesC);
|
5
|
+
|
6
|
+
function makeTreesC() {
|
7
|
+
if (!document.createElement)
|
8
|
+
return;
|
9
|
+
uls = document.getElementsByTagName("ul");
|
10
|
+
for (uli=0;uli<uls.length;uli++) {
|
11
|
+
ul = uls[uli];
|
12
|
+
if (ul.nodeName == "UL" && ul.className == "scaffold_associations_tree") {
|
13
|
+
processULELC(ul);
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
function processULELC(ul) {
|
19
|
+
if (!ul.childNodes || ul.childNodes.length == 0)
|
20
|
+
return;
|
21
|
+
for (var itemi=0;itemi<ul.childNodes.length;itemi++) {
|
22
|
+
var item = ul.childNodes[itemi];
|
23
|
+
if (item.nodeName == "LI") {
|
24
|
+
var subul;
|
25
|
+
subul = "";
|
26
|
+
for (var sitemi=0;sitemi<item.childNodes.length;sitemi++) {
|
27
|
+
if (item.childNodes[sitemi].nodeName == "UL") {
|
28
|
+
subul = item.childNodes[sitemi];
|
29
|
+
processULELC(subul);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
if (subul) {
|
33
|
+
item.className = 'sat_closed'
|
34
|
+
item.innerHTML = '<a href="#" class="treestatus" onclick=\'this.parentNode.className = (this.parentNode.className=="sat_open") ? "sat_closed" : "sat_open"; return false;\'></a>' + item.innerHTML
|
35
|
+
} else {
|
36
|
+
item.className = "sat_bullet";
|
37
|
+
item.innerHTML = '<a href="#" class="treestatus" onclick=\'return false;\'></a>' + item.innerHTML
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
/* Utility functions */
|
44
|
+
|
45
|
+
function addEvent(obj, evType, fn){
|
46
|
+
/* adds an eventListener for browsers which support it
|
47
|
+
Written by Scott Andrew: nice one, Scott */
|
48
|
+
if (obj.addEventListener){
|
49
|
+
obj.addEventListener(evType, fn, false);
|
50
|
+
return true;
|
51
|
+
} else if (obj.attachEvent){
|
52
|
+
var r = obj.attachEvent("on"+evType, fn);
|
53
|
+
return r;
|
54
|
+
} else {
|
55
|
+
return false;
|
56
|
+
}
|
57
|
+
}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
This allows you to skip the output of the style when using scaffold auto
|
2
|
+
completing. This is necessary if you want to be XHTML compliant, as style tags
|
3
|
+
aren't allowed inside form elements.
|
4
|
+
|
5
|
+
To use this, add the .css file to your layout. Then set this in your
|
6
|
+
application's environment:
|
7
|
+
|
8
|
+
ScaffoldingExtensions.auto_complete_skip_style = true
|
@@ -0,0 +1,23 @@
|
|
1
|
+
div.auto_complete {
|
2
|
+
width: 350px;
|
3
|
+
background: #fff;
|
4
|
+
}
|
5
|
+
div.auto_complete ul {
|
6
|
+
border:1px solid #888;
|
7
|
+
margin:0;
|
8
|
+
padding:0;
|
9
|
+
width:100%;
|
10
|
+
list-style-type:none;
|
11
|
+
}
|
12
|
+
div.auto_complete ul li {
|
13
|
+
margin:0;
|
14
|
+
padding:3px;
|
15
|
+
}
|
16
|
+
div.auto_complete ul li.selected {
|
17
|
+
background-color: #ffb;
|
18
|
+
}
|
19
|
+
div.auto_complete ul strong.highlight {
|
20
|
+
color: #800;
|
21
|
+
margin:0;
|
22
|
+
padding:0;
|
23
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
This allows you to auto focus the page to the first form field.
|
2
|
+
|
3
|
+
To use this, conditionally include the .js file in your layout via something
|
4
|
+
like:
|
5
|
+
|
6
|
+
<%= javascript_include_tag('scaffold_form_focus') if @scaffold_options %>
|
7
|
+
|
8
|
+
The if statement makes it take effect for the scaffolded pages (which always
|
9
|
+
define @scaffold_options). Note that the code is fairly simplistic, it just
|
10
|
+
focuses on the first text input, password input, textarea, or
|
11
|
+
select box on the page, so if your layout has a form before the scaffolded
|
12
|
+
form, you'll probably want to modify the code.
|
@@ -0,0 +1,21 @@
|
|
1
|
+
function scaffold_form_focus() {
|
2
|
+
num_forms = document.forms.length
|
3
|
+
for(i=0;i<num_forms;i++) {
|
4
|
+
elements = document.forms[i].elements
|
5
|
+
num_elements = elements.length
|
6
|
+
for(j=0;j<num_elements;j++) {
|
7
|
+
element = elements[j]
|
8
|
+
tagName = element.tagName
|
9
|
+
if(tagName == 'SELECT' || tagName == 'TEXTAREA' || (tagName == 'INPUT' && (element.type == 'text' || element.type == 'password'))) {
|
10
|
+
if(tagName != 'SELECT') {
|
11
|
+
element.selectionStart = 0
|
12
|
+
element.selectionEnd = 0
|
13
|
+
}
|
14
|
+
element.focus()
|
15
|
+
return
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
scaffold_form_focus()
|
@@ -0,0 +1,8 @@
|
|
1
|
+
If you are using JQuery javascript library with the plugin, you need to use this
|
2
|
+
plugin for autocomplete functionality. It's a modification of jq-autocomplete
|
3
|
+
[1]. It also requires the Dimensions JQuery plugin [2]. To use this plugin,
|
4
|
+
add the include the css file as a stylesheet and the js file as a script (in
|
5
|
+
addition to JQuery and the Dimensions plugin).
|
6
|
+
|
7
|
+
[1] http://plugins.jquery.com/project/jq-autocomplete
|
8
|
+
[2] http://plugins.jquery.com/project/dimensions
|
@@ -0,0 +1,22 @@
|
|
1
|
+
ul.se_autocomplete {
|
2
|
+
position: absolute;
|
3
|
+
overflow: hidden;
|
4
|
+
background-color: #fff;
|
5
|
+
border: 1px solid #aaa;
|
6
|
+
margin: 0px;
|
7
|
+
padding: 0;
|
8
|
+
list-style: none;
|
9
|
+
font: normal .75em/.75em Verdana, Arial, sans-serif;
|
10
|
+
color: #333;
|
11
|
+
}
|
12
|
+
ul.se_autocomplete li {
|
13
|
+
display: block;
|
14
|
+
padding: .3em .5em .3em .3em;
|
15
|
+
overflow: hidden;
|
16
|
+
width: 100%;
|
17
|
+
}
|
18
|
+
|
19
|
+
ul.se_autocomplete li.active {
|
20
|
+
background-color: #3875d7;
|
21
|
+
color: #fff;
|
22
|
+
}
|
@@ -0,0 +1,121 @@
|
|
1
|
+
/* Copyright 2007 Yehuda Katz, Rein Henrichs
|
2
|
+
* Copyright 2008 Jeremy Evans
|
3
|
+
*/
|
4
|
+
|
5
|
+
(function($) {
|
6
|
+
|
7
|
+
$.ui = $.ui || {}; $.ui.autocomplete = $.ui.autocomplete || {}; var active;
|
8
|
+
|
9
|
+
$.fn.autocompleteMode = function(container, input, size, opt) {
|
10
|
+
var original = input.val(); var selected = -1; var self = this;
|
11
|
+
|
12
|
+
$.data(document.body, "autocompleteMode", true);
|
13
|
+
|
14
|
+
$("body").one("cancel.autocomplete", function() {
|
15
|
+
input.trigger("cancel.autocomplete"); $("body").trigger("off.autocomplete"); input.val(original);
|
16
|
+
});
|
17
|
+
|
18
|
+
$("body").one("activate.autocomplete", function() {
|
19
|
+
input.trigger("activate.autocomplete", [$(active[0]).html()]); $("body").trigger("off.autocomplete");
|
20
|
+
});
|
21
|
+
|
22
|
+
$("body").one("off.autocomplete", function(e, reset) {
|
23
|
+
container.remove();
|
24
|
+
$.data(document.body, "autocompleteMode", false);
|
25
|
+
input.unbind("keydown.autocomplete");
|
26
|
+
$("body").add(window).unbind("click.autocomplete").unbind("cancel.autocomplete").unbind("activate.autocomplete");
|
27
|
+
});
|
28
|
+
|
29
|
+
// If a click bubbles all the way up to the window, close the autocomplete
|
30
|
+
$(window).bind("click.autocomplete", function() { $("body").trigger("cancel.autocomplete"); });
|
31
|
+
|
32
|
+
var select = function() {
|
33
|
+
active = $("> *", container).removeClass("active").slice(selected, selected + 1).addClass("active");
|
34
|
+
input.trigger("itemSelected.autocomplete", [$(active[0]).html()]);
|
35
|
+
input.val($(active[0]).html());
|
36
|
+
};
|
37
|
+
|
38
|
+
container.mouseover(function(e) {
|
39
|
+
// If you hover over the container, but not its children, return
|
40
|
+
if(e.target == container[0]) return;
|
41
|
+
// Set the selected item to the item hovered over and make it active
|
42
|
+
selected = $("> *", container).index($(e.target).is('li') ? $(e.target)[0] : $(e.target).parents('li')[0]); select();
|
43
|
+
}).bind("click.autocomplete", function(e) {
|
44
|
+
$("body").trigger("activate.autocomplete"); $.data(document.body, "suppressKey", false);
|
45
|
+
});
|
46
|
+
|
47
|
+
input
|
48
|
+
.bind("keydown.autocomplete", function(e) {
|
49
|
+
if(e.which == 27) { $("body").trigger("cancel.autocomplete"); }
|
50
|
+
else if(e.which == 13) { $("body").trigger("activate.autocomplete"); }
|
51
|
+
else if(e.which == 40 || e.which == 9 || e.which == 38) {
|
52
|
+
switch(e.which) {
|
53
|
+
case 40:
|
54
|
+
case 9:
|
55
|
+
selected = selected >= size - 1 ? 0 : selected + 1; break;
|
56
|
+
case 38:
|
57
|
+
selected = selected <= 0 ? size - 1 : selected - 1; break;
|
58
|
+
default: break;
|
59
|
+
}
|
60
|
+
select();
|
61
|
+
} else { return true; }
|
62
|
+
$.data(document.body, "suppressKey", true);
|
63
|
+
});
|
64
|
+
};
|
65
|
+
|
66
|
+
$.fn.autocomplete = function(opt) {
|
67
|
+
var ajax = opt.ajax;
|
68
|
+
var association = opt.association
|
69
|
+
opt = $.extend({}, {
|
70
|
+
timeout: 1000,
|
71
|
+
getList: function(input) {
|
72
|
+
params = "id=" + input.val()
|
73
|
+
if(association) {
|
74
|
+
params += '&association=' + association
|
75
|
+
}
|
76
|
+
$.get(ajax, params, function(html) { input.trigger("updateList", [html]); });
|
77
|
+
}
|
78
|
+
}, opt);
|
79
|
+
|
80
|
+
return this.each(function() {
|
81
|
+
|
82
|
+
$(this)
|
83
|
+
.keypress(function(e) {
|
84
|
+
var typingTimeout = $.data(this, "typingTimeout");
|
85
|
+
if(typingTimeout) window.clearInterval(typingTimeout);
|
86
|
+
|
87
|
+
if($.data(document.body, "suppressKey"))
|
88
|
+
return $.data(document.body, "suppressKey", false);
|
89
|
+
else if($.data(document.body, "autocompleteMode") && e.charCode < 32 && e.keyCode != 8 && e.keyCode != 46) return false;
|
90
|
+
else {
|
91
|
+
$.data(this, "typingTimeout", window.setTimeout(function() {
|
92
|
+
$(e.target).trigger("autocomplete");
|
93
|
+
}, opt.timeout));
|
94
|
+
}
|
95
|
+
})
|
96
|
+
.bind("autocomplete", function() {
|
97
|
+
var self = $(this);
|
98
|
+
|
99
|
+
self.one("updateList", function(e, list) {
|
100
|
+
$("body").trigger("off.autocomplete");
|
101
|
+
|
102
|
+
list = $(list);
|
103
|
+
var length = list.children().length;
|
104
|
+
if(!length) return false;
|
105
|
+
|
106
|
+
list.addClass('se_autocomplete');
|
107
|
+
|
108
|
+
var offset = self.offset();
|
109
|
+
|
110
|
+
list.css({top: offset.top + self.outerHeight(), left: offset.left, width: self.width()}).appendTo("body");
|
111
|
+
|
112
|
+
$("body").autocompleteMode(list, self, length, opt);
|
113
|
+
});
|
114
|
+
|
115
|
+
opt.getList(self);
|
116
|
+
});
|
117
|
+
|
118
|
+
});
|
119
|
+
};
|
120
|
+
|
121
|
+
})(jQuery);
|