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