refinerycms 0.9.5.31 → 0.9.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/VERSION +1 -1
- data/bin/refinery +2 -1
- data/config/environment.rb +1 -1
- data/config/environments/development.rb +3 -0
- data/contributors.md +2 -0
- data/db/migrate/20100202034802_remove_custom_title_image_id_and_image_id_from_pages.rb +13 -0
- data/db/migrate/20100204011654_change_part_titles_to_titleized_version_for_new_format.rb +13 -0
- data/db/schema.rb +6 -10
- data/public/javascripts/admin.js +1 -1
- data/public/javascripts/jquery-ui-1.8rc1.min.js +375 -0
- data/public/javascripts/jquery.js +4231 -2529
- data/public/javascripts/refinery/admin.js +609 -38
- data/public/javascripts/refinery/boot_wym.js +3 -3
- data/public/javascripts/thickbox.js +116 -129
- data/public/javascripts/wymeditor/jquery.refinery.wymeditor.js +3674 -3732
- data/public/javascripts/wymeditor/skins/refinery/skin.js +8 -8
- data/public/stylesheets/refinery/refinery.css +142 -32
- data/public/stylesheets/wymeditor/skins/refinery/skin.css +8 -1
- data/readme.md +35 -21
- data/test/fixtures/page_parts.yml +9 -0
- data/test/fixtures/pages.yml +88 -0
- data/test/performance/browsing_test.rb +9 -0
- data/test/test_helper.rb +38 -0
- data/test/unit/image_test.rb +14 -0
- data/test/unit/page_part_test.rb +19 -0
- data/test/unit/page_test.rb +130 -0
- data/vendor/plugins/authentication/app/controllers/sessions_controller.rb +1 -1
- data/vendor/plugins/authentication/app/views/admin/users/index.html.erb +1 -2
- data/vendor/plugins/authentication/authentication.md +9 -1
- data/vendor/plugins/dashboard/dashboard.md +3 -3
- data/vendor/plugins/images/app/controllers/admin/images_controller.rb +17 -13
- data/vendor/plugins/images/app/helpers/admin/images_helper.rb +6 -0
- data/vendor/plugins/images/app/models/image.rb +24 -39
- data/vendor/plugins/images/app/views/admin/images/_form.html.erb +11 -4
- data/vendor/plugins/images/app/views/admin/images/_grid_view.html.erb +1 -2
- data/vendor/plugins/images/app/views/admin/images/_list_view_image.html.erb +1 -2
- data/vendor/plugins/images/app/views/admin/images/index.html.erb +1 -1
- data/vendor/plugins/images/app/views/admin/images/insert.html.erb +8 -71
- data/vendor/plugins/images/images.md +12 -7
- data/vendor/plugins/inquiries/app/views/admin/inquiries/_inquiry.html.erb +6 -13
- data/vendor/plugins/inquiries/app/views/admin/inquiry_settings/index.html.erb +1 -2
- data/vendor/plugins/inquiries/inquiries.md +8 -8
- data/vendor/plugins/news/app/views/admin/news_items/_news_item.html.erb +1 -2
- data/vendor/plugins/news/news.md +4 -4
- data/vendor/plugins/pages/app/controllers/admin/page_dialogs_controller.rb +11 -10
- data/vendor/plugins/pages/app/controllers/admin/page_parts_controller.rb +5 -1
- data/vendor/plugins/pages/app/controllers/admin/pages_controller.rb +2 -2
- data/vendor/plugins/pages/app/models/page.rb +75 -29
- data/vendor/plugins/pages/app/models/page_part.rb +1 -1
- data/vendor/plugins/pages/app/views/admin/page_dialogs/_page_link.html.erb +2 -2
- data/vendor/plugins/pages/app/views/admin/page_dialogs/link_to.html.erb +8 -112
- data/vendor/plugins/pages/app/views/admin/pages/_form.html.erb +50 -154
- data/vendor/plugins/pages/app/views/admin/pages/_list.html.erb +10 -10
- data/vendor/plugins/pages/app/views/admin/pages/_page_part_field.html.erb +4 -4
- data/vendor/plugins/pages/app/views/admin/pages/_sortable_list.html.erb +1 -1
- data/vendor/plugins/pages/pages.md +30 -25
- data/vendor/plugins/refinery/app/views/admin/_head.html.erb +5 -14
- data/vendor/plugins/refinery/app/views/admin/_menu.html.erb +2 -64
- data/vendor/plugins/refinery/app/views/shared/_message.html.erb +0 -6
- data/vendor/plugins/refinery/app/views/shared/admin/_error_messages_for.html.erb +1 -6
- data/vendor/plugins/refinery/app/views/shared/admin/_form_actions.html.erb +8 -10
- data/vendor/plugins/refinery/app/views/shared/admin/_image_picker.html.erb +22 -38
- data/vendor/plugins/refinery/app/views/shared/admin/_make_sortable.html.erb +6 -65
- data/vendor/plugins/refinery/app/views/shared/admin/_resource_picker.html.erb +16 -16
- data/vendor/plugins/refinery/app/views/shared/admin/_sortable_list.html.erb +3 -4
- data/vendor/plugins/refinery/lib/crud.rb +1 -1
- data/vendor/plugins/refinery/lib/generators/refinery/templates/views/admin/_singular_name.html.erb +1 -1
- data/vendor/plugins/refinery/lib/generators/refinery/templates/views/admin/_sortable_list.html.erb +1 -1
- data/vendor/plugins/refinery/plugins.md +19 -12
- data/vendor/plugins/refinery_dialogs/app/controllers/admin/dialogs_controller.rb +6 -4
- data/vendor/plugins/refinery_dialogs/app/views/admin/dialogs/show.html.erb +3 -3
- data/vendor/plugins/refinery_dialogs/app/views/layouts/admin_dialog.html.erb +7 -14
- data/vendor/plugins/refinery_settings/app/views/admin/refinery_settings/_refinery_setting.html.erb +1 -1
- data/vendor/plugins/refinery_settings/settings.md +51 -1
- data/vendor/plugins/resources/app/controllers/admin/resources_controller.rb +16 -11
- data/vendor/plugins/resources/app/views/admin/resources/_form.html.erb +9 -2
- data/vendor/plugins/resources/app/views/admin/resources/_resource.html.erb +1 -3
- data/vendor/plugins/resources/app/views/admin/resources/index.html.erb +2 -2
- data/vendor/plugins/resources/app/views/admin/resources/insert.html.erb +14 -60
- data/vendor/plugins/resources/resources.md +1 -1
- data/vendor/plugins/themes/app/controllers/admin/themes_controller.rb +6 -6
- data/vendor/plugins/themes/app/models/theme.rb +3 -3
- data/vendor/plugins/themes/app/views/admin/themes/_theme.html.erb +14 -20
- data/vendor/plugins/themes/themes.md +21 -19
- metadata +18 -19
- data/public/javascripts/builder.js +0 -136
- data/public/javascripts/controls.js +0 -963
- data/public/javascripts/dragdrop.js +0 -973
- data/public/javascripts/effects.js +0 -1128
- data/public/javascripts/fastinit.js +0 -84
- data/public/javascripts/livepipe.js +0 -180
- data/public/javascripts/prototype.js +0 -4874
- data/public/javascripts/refinery/dialog.js +0 -52
- data/public/javascripts/refinery/parse_url.js +0 -38
- data/public/javascripts/refinery/prototype.enhancements.js +0 -24
- data/public/javascripts/refinery/tooltips.js +0 -173
- data/public/javascripts/scriptaculous.js +0 -47
- data/public/javascripts/slider.js +0 -275
- data/public/javascripts/tabs.js +0 -149
- data/vendor/plugins/refinery_settings/app/views/admin/refinery_settings/_make_sortable.html.erb +0 -7
@@ -6,4 +6,4 @@ The Resources plugin allows you to upload files such as PDFs and other files you
|
|
6
6
|
|
7
7
|
## How it works
|
8
8
|
|
9
|
-
The resources plugins is made up of attachment_fu and the Crudfiy mixin
|
9
|
+
The resources plugins is made up of [attachment_fu](http://github.com/technoweenie/attachment_fu) for handling the store and upload of the images and the [Crudfiy mixin](http://github.com/resolve/refinerycms/blob/master/vendor/plugins/refinery/crud.md).
|
@@ -1,9 +1,9 @@
|
|
1
1
|
class Admin::ThemesController < Admin::BaseController
|
2
2
|
|
3
3
|
crudify :theme, :order => "updated_at DESC"
|
4
|
-
|
4
|
+
|
5
5
|
before_filter :find_theme, :only => [:update, :destroy, :edit, :preview_image, :activate]
|
6
|
-
|
6
|
+
|
7
7
|
# accessor method for theme preview image
|
8
8
|
def preview_image
|
9
9
|
if File.exists? @theme.preview_image
|
@@ -14,12 +14,12 @@ class Admin::ThemesController < Admin::BaseController
|
|
14
14
|
return error_404
|
15
15
|
end
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def activate
|
19
|
-
RefinerySetting[:theme] = @theme.
|
20
|
-
|
19
|
+
RefinerySetting[:theme] = @theme.folder_title
|
20
|
+
|
21
21
|
flash[:notice] = "'#{@theme.title}' applied to live site."
|
22
22
|
redirect_to admin_themes_url
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
end
|
@@ -31,12 +31,12 @@ class Theme < ActiveRecord::Base
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
def
|
34
|
+
def folder_title
|
35
35
|
File.basename(self.full_filename).split(".").first
|
36
36
|
end
|
37
37
|
|
38
38
|
def theme_path
|
39
|
-
File.join(RAILS_ROOT, "themes",
|
39
|
+
File.join(RAILS_ROOT, "themes", folder_title)
|
40
40
|
end
|
41
41
|
|
42
42
|
def preview_image
|
@@ -50,7 +50,7 @@ class Theme < ActiveRecord::Base
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def self.directory_is_writable?
|
53
|
-
File.writable? File.join(RAILS_ROOT, "themes") # Heroku users will receive false here
|
53
|
+
File.writable? File.join(RAILS_ROOT, "themes") # Heroku users (or users with read-only filesystem) will receive false here
|
54
54
|
end
|
55
55
|
|
56
56
|
end
|
@@ -1,24 +1,18 @@
|
|
1
|
-
<li
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
<
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
<%= link_to refinery_icon_tag('page_white_put.png'), theme.public_filename,
|
1
|
+
<li>
|
2
|
+
<p>
|
3
|
+
<%=h theme.title %>
|
4
|
+
</p>
|
5
|
+
<%= image_tag(preview_image_admin_theme_url(theme), :width => 135, :height => 135) %>
|
6
|
+
<p>
|
7
|
+
<span class='actions'>
|
8
|
+
<%= link_to refinery_icon_tag('star.png'), activate_admin_theme_url(theme),
|
9
|
+
:title => "Activate this theme" %>
|
10
|
+
<%= link_to refinery_icon_tag('page_white_put.png'), theme.public_filename,
|
12
11
|
:title => "Download this theme (#{number_to_human_size(theme.size)})" %>
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
<%= link_to refinery_icon_tag('delete.png'), admin_theme_path(theme),
|
18
|
-
:confirm => "Are you sure you want to delete '#{theme.title}'?",
|
19
|
-
:class => "cancel", :method => :delete,
|
20
|
-
:title => "Remove this theme forever" %>
|
12
|
+
<%= link_to refinery_icon_tag('application_edit.png'), edit_admin_theme_url(theme),
|
13
|
+
:title => "Edit this theme" if Theme::directory_is_writable? %>
|
14
|
+
<%= link_to refinery_icon_tag('delete.png'), admin_theme_path(theme), :class => "cancel confirm-delete",
|
15
|
+
:title => "Remove this theme forever" %>
|
21
16
|
</span>
|
22
17
|
</p>
|
23
|
-
|
24
18
|
</li>
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# Themes
|
2
2
|
|
3
|
-
![Refinery Dashboard](http://refinerycms.com/system/images/0000/0576/dashboard.png)
|
4
|
-
|
5
3
|
## Introduction
|
6
4
|
|
7
5
|
__Themes allow you to wrap up the design of your Refinery site into a single folder that is portable.__
|
@@ -11,9 +9,9 @@ ERB views you're used to in Rails. This means creating a theme from your existin
|
|
11
9
|
|
12
10
|
Think of a theme as your ``app/views`` directory with a few extra things like images, css and javascript.
|
13
11
|
|
14
|
-
It's worth noting you don't need to use a theme if you don't want to. Placing files in the ``app/views`` directory like any other Rails app will work just fine. It's only if you want to wrap your design up into a single location that you would use a theme or allow your client to easily change designs.
|
12
|
+
It's worth noting you don't need to use a theme if you don't want to. Placing files in the ``app/views`` directory like any other Rails app will work just fine. It's only if you want to wrap your design up into a single location that you would use a theme or allow your client to easily change between designs.
|
15
13
|
|
16
|
-
## The
|
14
|
+
## The Structure of a Theme
|
17
15
|
|
18
16
|
Themes sit in your Rails app like this
|
19
17
|
|
@@ -28,7 +26,7 @@ Themes sit in your Rails app like this
|
|
28
26
|
plugins/
|
29
27
|
tests/
|
30
28
|
|
31
|
-
|
29
|
+
Let's take the ``mytheme`` example theme shown above. This is how the theme is structured:
|
32
30
|
|
33
31
|
mytheme/
|
34
32
|
|- images
|
@@ -55,7 +53,7 @@ Usually this would be just what you have in ``public/images`` except we move tha
|
|
55
53
|
|
56
54
|
### Javascripts
|
57
55
|
|
58
|
-
Same with javascripts, just what you normally have in ``public/javascripts``
|
56
|
+
Same with javascripts, just what you normally have in ``public/javascripts`` but in this theme directory instead.
|
59
57
|
|
60
58
|
### Readme
|
61
59
|
|
@@ -63,21 +61,21 @@ The ``README`` file is just a description of your theme.
|
|
63
61
|
|
64
62
|
### Views
|
65
63
|
|
66
|
-
This is exactly the same as how you lay your views out in app/views
|
64
|
+
This is exactly the same as how you lay your views out in ``app/views/`` just instead of putting them in ``app/views/`` you put them into ``themes/mytheme/views/``
|
67
65
|
|
68
66
|
### Preview Image
|
69
67
|
|
70
|
-
The ``preview.png`` image is used when selecting the theme in the backend. It must be a png and ideally
|
68
|
+
The ``preview.png`` image is used when selecting the theme in the backend. It must be a png file and is ideally 135 x 135 pixels.
|
71
69
|
|
72
|
-
## How do I make my own
|
70
|
+
## How do I make my own Theme?
|
73
71
|
|
74
|
-
Create a folder with the name if your theme inside ``/themes`` e.g. ``/themes/mytheme`` and follow the directory structure outlined in 'The structure of a
|
72
|
+
Create a folder with the name if your theme inside ``/themes`` e.g. ``/themes/mytheme`` and follow the directory structure outlined in 'The structure of a Theme'.
|
75
73
|
|
76
|
-
## How do I select which
|
74
|
+
## How do I select which Theme Refinery should use?
|
77
75
|
|
78
76
|
In the admin area of Refinery go to the "Settings" area, locate the setting called "theme" and edit it.
|
79
77
|
|
80
|
-
Set the value of that setting to the name of your themes folder. For example if your theme is sitting in:
|
78
|
+
Set the value of that setting to the name of your themes folder. For example, if your theme is sitting in:
|
81
79
|
|
82
80
|
themes/my_theme
|
83
81
|
|
@@ -87,7 +85,7 @@ set it to ``my_theme`` and hit save.
|
|
87
85
|
|
88
86
|
If you want to share a theme and install it on another site you have to zip it first.
|
89
87
|
|
90
|
-
It's important to note you don't zip the theme's directory itself just the contents.
|
88
|
+
It's important to note you don't zip the theme's directory itself, just the contents.
|
91
89
|
|
92
90
|
If I had a theme sitting in:
|
93
91
|
|
@@ -98,15 +96,15 @@ The zip file would look like this
|
|
98
96
|
mytheme.zip
|
99
97
|
|- [theme files here]
|
100
98
|
|
101
|
-
Read 'How do I install someone else's
|
99
|
+
Read 'How do I install someone else's Theme?' to take that zip file and install the theme.
|
102
100
|
|
103
|
-
## How do I install someone else's
|
101
|
+
## How do I install someone else's Theme?
|
104
102
|
|
105
103
|
If you have the themes plugin added to your admin user, you should see in the admin area of Refinery a "Themes" tab in the main navigation. Click on that, then click "Upload new theme". Upload the theme zip file and then click on the "star" below the preview image for the theme to activate that theme as the one to use right now.
|
106
104
|
|
107
|
-
## How can I
|
105
|
+
## How can I Convert my Current Views into a Theme?
|
108
106
|
|
109
|
-
This should be fairly straightforward just
|
107
|
+
This should be fairly straightforward, just follow the directory structure outlined in 'The structure of a Theme'.
|
110
108
|
|
111
109
|
But there is one important difference that need to be addressed to convert your current site into a theme.
|
112
110
|
|
@@ -116,7 +114,7 @@ If you have some CSS which refers to an image or URL:
|
|
116
114
|
background: url('/images/footer_background.png') repeat-x;
|
117
115
|
}
|
118
116
|
|
119
|
-
You need to update the URL so it requests
|
117
|
+
You need to update the URL so it requests ``/images/themes`` instead of just ``/images``. This tells Refinery we need to actually load this image from the theme and not just the public directory.
|
120
118
|
|
121
119
|
So the result is simply:
|
122
120
|
|
@@ -130,4 +128,8 @@ This is the same with linking to Javascript and Stylesheets in your view. Say ou
|
|
130
128
|
|
131
129
|
You just need to change that to:
|
132
130
|
|
133
|
-
<%= stylesheet_link_tag 'theme/application' %>
|
131
|
+
<%= stylesheet_link_tag 'theme/application' %>
|
132
|
+
|
133
|
+
## I'm Stuck, is there an Example Theme?
|
134
|
+
|
135
|
+
Yep, there is an example theme called "demolicious" that comes with Refinery located in ``/themes/demolicious``. If you find yourself getting stuck, just check out that theme and get a feel for how it works.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: refinerycms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Resolve Digital
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2010-
|
14
|
+
date: 2010-02-05 00:00:00 +13:00
|
15
15
|
default_executable:
|
16
16
|
dependencies: []
|
17
17
|
|
@@ -60,6 +60,8 @@ files:
|
|
60
60
|
- db/migrate/20091207033335_add_superuser_to_users.rb
|
61
61
|
- db/migrate/20100114092849_add_themes_table.rb
|
62
62
|
- db/migrate/20100127004649_add_reset_code_to_users.rb
|
63
|
+
- db/migrate/20100202034802_remove_custom_title_image_id_and_image_id_from_pages.rb
|
64
|
+
- db/migrate/20100204011654_change_part_titles_to_titleized_version_for_new_format.rb
|
63
65
|
- db/schema.rb
|
64
66
|
- db/seeds.rb
|
65
67
|
- doc/.yardoc/checksums
|
@@ -147,25 +149,12 @@ files:
|
|
147
149
|
- public/images/wymeditor/skins/wymeditor_icon.png
|
148
150
|
- public/javascripts/admin.js
|
149
151
|
- public/javascripts/application.js
|
150
|
-
- public/javascripts/
|
151
|
-
- public/javascripts/controls.js
|
152
|
-
- public/javascripts/dragdrop.js
|
153
|
-
- public/javascripts/effects.js
|
154
|
-
- public/javascripts/fastinit.js
|
152
|
+
- public/javascripts/jquery-ui-1.8rc1.min.js
|
155
153
|
- public/javascripts/jquery.js
|
156
154
|
- public/javascripts/jquery/GPL-LICENSE.txt
|
157
155
|
- public/javascripts/jquery/MIT-LICENSE.txt
|
158
|
-
- public/javascripts/livepipe.js
|
159
|
-
- public/javascripts/prototype.js
|
160
156
|
- public/javascripts/refinery/admin.js
|
161
157
|
- public/javascripts/refinery/boot_wym.js
|
162
|
-
- public/javascripts/refinery/dialog.js
|
163
|
-
- public/javascripts/refinery/parse_url.js
|
164
|
-
- public/javascripts/refinery/prototype.enhancements.js
|
165
|
-
- public/javascripts/refinery/tooltips.js
|
166
|
-
- public/javascripts/scriptaculous.js
|
167
|
-
- public/javascripts/slider.js
|
168
|
-
- public/javascripts/tabs.js
|
169
158
|
- public/javascripts/thickbox.js
|
170
159
|
- public/javascripts/wymeditor/jquery.refinery.wymeditor.js
|
171
160
|
- public/javascripts/wymeditor/lang/ca.js
|
@@ -223,6 +212,13 @@ files:
|
|
223
212
|
- script/process/spawner
|
224
213
|
- script/runner
|
225
214
|
- script/server
|
215
|
+
- test/fixtures/page_parts.yml
|
216
|
+
- test/fixtures/pages.yml
|
217
|
+
- test/performance/browsing_test.rb
|
218
|
+
- test/test_helper.rb
|
219
|
+
- test/unit/image_test.rb
|
220
|
+
- test/unit/page_part_test.rb
|
221
|
+
- test/unit/page_test.rb
|
226
222
|
- themes/demolicious.zip
|
227
223
|
- themes/hemingway.zip
|
228
224
|
- vendor/plugins/acts_as_indexed/CHANGELOG
|
@@ -500,7 +496,6 @@ files:
|
|
500
496
|
- vendor/plugins/refinery_settings/app/controllers/admin/refinery_settings_controller.rb
|
501
497
|
- vendor/plugins/refinery_settings/app/models/refinery_setting.rb
|
502
498
|
- vendor/plugins/refinery_settings/app/views/admin/refinery_settings/_form.html.erb
|
503
|
-
- vendor/plugins/refinery_settings/app/views/admin/refinery_settings/_make_sortable.html.erb
|
504
499
|
- vendor/plugins/refinery_settings/app/views/admin/refinery_settings/_refinery_setting.html.erb
|
505
500
|
- vendor/plugins/refinery_settings/app/views/admin/refinery_settings/edit.html.erb
|
506
501
|
- vendor/plugins/refinery_settings/app/views/admin/refinery_settings/index.html.erb
|
@@ -559,5 +554,9 @@ rubygems_version: 1.3.5
|
|
559
554
|
signing_key:
|
560
555
|
specification_version: 3
|
561
556
|
summary: A beautiful open source Ruby on Rails content manager for small business.
|
562
|
-
test_files:
|
563
|
-
|
557
|
+
test_files:
|
558
|
+
- test/performance/browsing_test.rb
|
559
|
+
- test/test_helper.rb
|
560
|
+
- test/unit/image_test.rb
|
561
|
+
- test/unit/page_part_test.rb
|
562
|
+
- test/unit/page_test.rb
|
@@ -1,136 +0,0 @@
|
|
1
|
-
// script.aculo.us builder.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008
|
2
|
-
|
3
|
-
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
4
|
-
//
|
5
|
-
// script.aculo.us is freely distributable under the terms of an MIT-style license.
|
6
|
-
// For details, see the script.aculo.us web site: http://script.aculo.us/
|
7
|
-
|
8
|
-
var Builder = {
|
9
|
-
NODEMAP: {
|
10
|
-
AREA: 'map',
|
11
|
-
CAPTION: 'table',
|
12
|
-
COL: 'table',
|
13
|
-
COLGROUP: 'table',
|
14
|
-
LEGEND: 'fieldset',
|
15
|
-
OPTGROUP: 'select',
|
16
|
-
OPTION: 'select',
|
17
|
-
PARAM: 'object',
|
18
|
-
TBODY: 'table',
|
19
|
-
TD: 'table',
|
20
|
-
TFOOT: 'table',
|
21
|
-
TH: 'table',
|
22
|
-
THEAD: 'table',
|
23
|
-
TR: 'table'
|
24
|
-
},
|
25
|
-
// note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
|
26
|
-
// due to a Firefox bug
|
27
|
-
node: function(elementName) {
|
28
|
-
elementName = elementName.toUpperCase();
|
29
|
-
|
30
|
-
// try innerHTML approach
|
31
|
-
var parentTag = this.NODEMAP[elementName] || 'div';
|
32
|
-
var parentElement = document.createElement(parentTag);
|
33
|
-
try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
|
34
|
-
parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
|
35
|
-
} catch(e) {}
|
36
|
-
var element = parentElement.firstChild || null;
|
37
|
-
|
38
|
-
// see if browser added wrapping tags
|
39
|
-
if(element && (element.tagName.toUpperCase() != elementName))
|
40
|
-
element = element.getElementsByTagName(elementName)[0];
|
41
|
-
|
42
|
-
// fallback to createElement approach
|
43
|
-
if(!element) element = document.createElement(elementName);
|
44
|
-
|
45
|
-
// abort if nothing could be created
|
46
|
-
if(!element) return;
|
47
|
-
|
48
|
-
// attributes (or text)
|
49
|
-
if(arguments[1])
|
50
|
-
if(this._isStringOrNumber(arguments[1]) ||
|
51
|
-
(arguments[1] instanceof Array) ||
|
52
|
-
arguments[1].tagName) {
|
53
|
-
this._children(element, arguments[1]);
|
54
|
-
} else {
|
55
|
-
var attrs = this._attributes(arguments[1]);
|
56
|
-
if(attrs.length) {
|
57
|
-
try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
|
58
|
-
parentElement.innerHTML = "<" +elementName + " " +
|
59
|
-
attrs + "></" + elementName + ">";
|
60
|
-
} catch(e) {}
|
61
|
-
element = parentElement.firstChild || null;
|
62
|
-
// workaround firefox 1.0.X bug
|
63
|
-
if(!element) {
|
64
|
-
element = document.createElement(elementName);
|
65
|
-
for(attr in arguments[1])
|
66
|
-
element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
|
67
|
-
}
|
68
|
-
if(element.tagName.toUpperCase() != elementName)
|
69
|
-
element = parentElement.getElementsByTagName(elementName)[0];
|
70
|
-
}
|
71
|
-
}
|
72
|
-
|
73
|
-
// text, or array of children
|
74
|
-
if(arguments[2])
|
75
|
-
this._children(element, arguments[2]);
|
76
|
-
|
77
|
-
return $(element);
|
78
|
-
},
|
79
|
-
_text: function(text) {
|
80
|
-
return document.createTextNode(text);
|
81
|
-
},
|
82
|
-
|
83
|
-
ATTR_MAP: {
|
84
|
-
'className': 'class',
|
85
|
-
'htmlFor': 'for'
|
86
|
-
},
|
87
|
-
|
88
|
-
_attributes: function(attributes) {
|
89
|
-
var attrs = [];
|
90
|
-
for(attribute in attributes)
|
91
|
-
attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
|
92
|
-
'="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'"') + '"');
|
93
|
-
return attrs.join(" ");
|
94
|
-
},
|
95
|
-
_children: function(element, children) {
|
96
|
-
if(children.tagName) {
|
97
|
-
element.appendChild(children);
|
98
|
-
return;
|
99
|
-
}
|
100
|
-
if(typeof children=='object') { // array can hold nodes and text
|
101
|
-
children.flatten().each( function(e) {
|
102
|
-
if(typeof e=='object')
|
103
|
-
element.appendChild(e);
|
104
|
-
else
|
105
|
-
if(Builder._isStringOrNumber(e))
|
106
|
-
element.appendChild(Builder._text(e));
|
107
|
-
});
|
108
|
-
} else
|
109
|
-
if(Builder._isStringOrNumber(children))
|
110
|
-
element.appendChild(Builder._text(children));
|
111
|
-
},
|
112
|
-
_isStringOrNumber: function(param) {
|
113
|
-
return(typeof param=='string' || typeof param=='number');
|
114
|
-
},
|
115
|
-
build: function(html) {
|
116
|
-
var element = this.node('div');
|
117
|
-
$(element).update(html.strip());
|
118
|
-
return element.down();
|
119
|
-
},
|
120
|
-
dump: function(scope) {
|
121
|
-
if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope
|
122
|
-
|
123
|
-
var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
|
124
|
-
"BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
|
125
|
-
"FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
|
126
|
-
"KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
|
127
|
-
"PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
|
128
|
-
"TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
|
129
|
-
|
130
|
-
tags.each( function(tag){
|
131
|
-
scope[tag] = function() {
|
132
|
-
return Builder.node.apply(Builder, [tag].concat($A(arguments)));
|
133
|
-
};
|
134
|
-
});
|
135
|
-
}
|
136
|
-
};
|
@@ -1,963 +0,0 @@
|
|
1
|
-
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
2
|
-
// (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
|
3
|
-
// (c) 2005-2008 Jon Tirsen (http://www.tirsen.com)
|
4
|
-
// Contributors:
|
5
|
-
// Richard Livsey
|
6
|
-
// Rahul Bhargava
|
7
|
-
// Rob Wills
|
8
|
-
//
|
9
|
-
// script.aculo.us is freely distributable under the terms of an MIT-style license.
|
10
|
-
// For details, see the script.aculo.us web site: http://script.aculo.us/
|
11
|
-
|
12
|
-
// Autocompleter.Base handles all the autocompletion functionality
|
13
|
-
// that's independent of the data source for autocompletion. This
|
14
|
-
// includes drawing the autocompletion menu, observing keyboard
|
15
|
-
// and mouse events, and similar.
|
16
|
-
//
|
17
|
-
// Specific autocompleters need to provide, at the very least,
|
18
|
-
// a getUpdatedChoices function that will be invoked every time
|
19
|
-
// the text inside the monitored textbox changes. This method
|
20
|
-
// should get the text for which to provide autocompletion by
|
21
|
-
// invoking this.getToken(), NOT by directly accessing
|
22
|
-
// this.element.value. This is to allow incremental tokenized
|
23
|
-
// autocompletion. Specific auto-completion logic (AJAX, etc)
|
24
|
-
// belongs in getUpdatedChoices.
|
25
|
-
//
|
26
|
-
// Tokenized incremental autocompletion is enabled automatically
|
27
|
-
// when an autocompleter is instantiated with the 'tokens' option
|
28
|
-
// in the options parameter, e.g.:
|
29
|
-
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
|
30
|
-
// will incrementally autocomplete with a comma as the token.
|
31
|
-
// Additionally, ',' in the above example can be replaced with
|
32
|
-
// a token array, e.g. { tokens: [',', '\n'] } which
|
33
|
-
// enables autocompletion on multiple tokens. This is most
|
34
|
-
// useful when one of the tokens is \n (a newline), as it
|
35
|
-
// allows smart autocompletion after linebreaks.
|
36
|
-
|
37
|
-
if(typeof Effect == 'undefined')
|
38
|
-
throw("controls.js requires including script.aculo.us' effects.js library");
|
39
|
-
|
40
|
-
var Autocompleter = { };
|
41
|
-
Autocompleter.Base = Class.create({
|
42
|
-
baseInitialize: function(element, update, options) {
|
43
|
-
element = $(element);
|
44
|
-
this.element = element;
|
45
|
-
this.update = $(update);
|
46
|
-
this.hasFocus = false;
|
47
|
-
this.changed = false;
|
48
|
-
this.active = false;
|
49
|
-
this.index = 0;
|
50
|
-
this.entryCount = 0;
|
51
|
-
this.oldElementValue = this.element.value;
|
52
|
-
|
53
|
-
if(this.setOptions)
|
54
|
-
this.setOptions(options);
|
55
|
-
else
|
56
|
-
this.options = options || { };
|
57
|
-
|
58
|
-
this.options.paramName = this.options.paramName || this.element.name;
|
59
|
-
this.options.tokens = this.options.tokens || [];
|
60
|
-
this.options.frequency = this.options.frequency || 0.4;
|
61
|
-
this.options.minChars = this.options.minChars || 1;
|
62
|
-
this.options.onShow = this.options.onShow ||
|
63
|
-
function(element, update){
|
64
|
-
if(!update.style.position || update.style.position=='absolute') {
|
65
|
-
update.style.position = 'absolute';
|
66
|
-
Position.clone(element, update, {
|
67
|
-
setHeight: false,
|
68
|
-
offsetTop: element.offsetHeight
|
69
|
-
});
|
70
|
-
}
|
71
|
-
Effect.Appear(update,{duration:0.15});
|
72
|
-
};
|
73
|
-
this.options.onHide = this.options.onHide ||
|
74
|
-
function(element, update){ new Effect.Fade(update,{duration:0.15}) };
|
75
|
-
|
76
|
-
if(typeof(this.options.tokens) == 'string')
|
77
|
-
this.options.tokens = new Array(this.options.tokens);
|
78
|
-
// Force carriage returns as token delimiters anyway
|
79
|
-
if (!this.options.tokens.include('\n'))
|
80
|
-
this.options.tokens.push('\n');
|
81
|
-
|
82
|
-
this.observer = null;
|
83
|
-
|
84
|
-
this.element.setAttribute('autocomplete','off');
|
85
|
-
|
86
|
-
Element.hide(this.update);
|
87
|
-
|
88
|
-
Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
|
89
|
-
Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
|
90
|
-
},
|
91
|
-
|
92
|
-
show: function() {
|
93
|
-
if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
|
94
|
-
if(!this.iefix &&
|
95
|
-
(Prototype.Browser.IE) &&
|
96
|
-
(Element.getStyle(this.update, 'position')=='absolute')) {
|
97
|
-
new Insertion.After(this.update,
|
98
|
-
'<iframe id="' + this.update.id + '_iefix" '+
|
99
|
-
'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
|
100
|
-
'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
|
101
|
-
this.iefix = $(this.update.id+'_iefix');
|
102
|
-
}
|
103
|
-
if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
|
104
|
-
},
|
105
|
-
|
106
|
-
fixIEOverlapping: function() {
|
107
|
-
Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
|
108
|
-
this.iefix.style.zIndex = 1;
|
109
|
-
this.update.style.zIndex = 2;
|
110
|
-
Element.show(this.iefix);
|
111
|
-
},
|
112
|
-
|
113
|
-
hide: function() {
|
114
|
-
this.stopIndicator();
|
115
|
-
if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
|
116
|
-
if(this.iefix) Element.hide(this.iefix);
|
117
|
-
},
|
118
|
-
|
119
|
-
startIndicator: function() {
|
120
|
-
if(this.options.indicator) Element.show(this.options.indicator);
|
121
|
-
},
|
122
|
-
|
123
|
-
stopIndicator: function() {
|
124
|
-
if(this.options.indicator) Element.hide(this.options.indicator);
|
125
|
-
},
|
126
|
-
|
127
|
-
onKeyPress: function(event) {
|
128
|
-
if(this.active)
|
129
|
-
switch(event.keyCode) {
|
130
|
-
case Event.KEY_TAB:
|
131
|
-
case Event.KEY_RETURN:
|
132
|
-
this.selectEntry();
|
133
|
-
Event.stop(event);
|
134
|
-
case Event.KEY_ESC:
|
135
|
-
this.hide();
|
136
|
-
this.active = false;
|
137
|
-
Event.stop(event);
|
138
|
-
return;
|
139
|
-
case Event.KEY_LEFT:
|
140
|
-
case Event.KEY_RIGHT:
|
141
|
-
return;
|
142
|
-
case Event.KEY_UP:
|
143
|
-
this.markPrevious();
|
144
|
-
this.render();
|
145
|
-
Event.stop(event);
|
146
|
-
return;
|
147
|
-
case Event.KEY_DOWN:
|
148
|
-
this.markNext();
|
149
|
-
this.render();
|
150
|
-
Event.stop(event);
|
151
|
-
return;
|
152
|
-
}
|
153
|
-
else
|
154
|
-
if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
|
155
|
-
(Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
|
156
|
-
|
157
|
-
this.changed = true;
|
158
|
-
this.hasFocus = true;
|
159
|
-
|
160
|
-
if(this.observer) clearTimeout(this.observer);
|
161
|
-
this.observer =
|
162
|
-
setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
|
163
|
-
},
|
164
|
-
|
165
|
-
activate: function() {
|
166
|
-
this.changed = false;
|
167
|
-
this.hasFocus = true;
|
168
|
-
this.getUpdatedChoices();
|
169
|
-
},
|
170
|
-
|
171
|
-
onHover: function(event) {
|
172
|
-
var element = Event.findElement(event, 'LI');
|
173
|
-
if(this.index != element.autocompleteIndex)
|
174
|
-
{
|
175
|
-
this.index = element.autocompleteIndex;
|
176
|
-
this.render();
|
177
|
-
}
|
178
|
-
Event.stop(event);
|
179
|
-
},
|
180
|
-
|
181
|
-
onClick: function(event) {
|
182
|
-
var element = Event.findElement(event, 'LI');
|
183
|
-
this.index = element.autocompleteIndex;
|
184
|
-
this.selectEntry();
|
185
|
-
this.hide();
|
186
|
-
},
|
187
|
-
|
188
|
-
onBlur: function(event) {
|
189
|
-
// needed to make click events working
|
190
|
-
setTimeout(this.hide.bind(this), 250);
|
191
|
-
this.hasFocus = false;
|
192
|
-
this.active = false;
|
193
|
-
},
|
194
|
-
|
195
|
-
render: function() {
|
196
|
-
if(this.entryCount > 0) {
|
197
|
-
for (var i = 0; i < this.entryCount; i++)
|
198
|
-
this.index==i ?
|
199
|
-
Element.addClassName(this.getEntry(i),"selected") :
|
200
|
-
Element.removeClassName(this.getEntry(i),"selected");
|
201
|
-
if(this.hasFocus) {
|
202
|
-
this.show();
|
203
|
-
this.active = true;
|
204
|
-
}
|
205
|
-
} else {
|
206
|
-
this.active = false;
|
207
|
-
this.hide();
|
208
|
-
}
|
209
|
-
},
|
210
|
-
|
211
|
-
markPrevious: function() {
|
212
|
-
if(this.index > 0) this.index--;
|
213
|
-
else this.index = this.entryCount-1;
|
214
|
-
this.getEntry(this.index).scrollIntoView(true);
|
215
|
-
},
|
216
|
-
|
217
|
-
markNext: function() {
|
218
|
-
if(this.index < this.entryCount-1) this.index++;
|
219
|
-
else this.index = 0;
|
220
|
-
this.getEntry(this.index).scrollIntoView(false);
|
221
|
-
},
|
222
|
-
|
223
|
-
getEntry: function(index) {
|
224
|
-
return this.update.firstChild.childNodes[index];
|
225
|
-
},
|
226
|
-
|
227
|
-
getCurrentEntry: function() {
|
228
|
-
return this.getEntry(this.index);
|
229
|
-
},
|
230
|
-
|
231
|
-
selectEntry: function() {
|
232
|
-
this.active = false;
|
233
|
-
this.updateElement(this.getCurrentEntry());
|
234
|
-
},
|
235
|
-
|
236
|
-
updateElement: function(selectedElement) {
|
237
|
-
if (this.options.updateElement) {
|
238
|
-
this.options.updateElement(selectedElement);
|
239
|
-
return;
|
240
|
-
}
|
241
|
-
var value = '';
|
242
|
-
if (this.options.select) {
|
243
|
-
var nodes = $(selectedElement).select('.' + this.options.select) || [];
|
244
|
-
if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
|
245
|
-
} else
|
246
|
-
value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
|
247
|
-
|
248
|
-
var bounds = this.getTokenBounds();
|
249
|
-
if (bounds[0] != -1) {
|
250
|
-
var newValue = this.element.value.substr(0, bounds[0]);
|
251
|
-
var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
|
252
|
-
if (whitespace)
|
253
|
-
newValue += whitespace[0];
|
254
|
-
this.element.value = newValue + value + this.element.value.substr(bounds[1]);
|
255
|
-
} else {
|
256
|
-
this.element.value = value;
|
257
|
-
}
|
258
|
-
this.oldElementValue = this.element.value;
|
259
|
-
this.element.focus();
|
260
|
-
|
261
|
-
if (this.options.afterUpdateElement)
|
262
|
-
this.options.afterUpdateElement(this.element, selectedElement);
|
263
|
-
},
|
264
|
-
|
265
|
-
updateChoices: function(choices) {
|
266
|
-
if(!this.changed && this.hasFocus) {
|
267
|
-
this.update.innerHTML = choices;
|
268
|
-
Element.cleanWhitespace(this.update);
|
269
|
-
Element.cleanWhitespace(this.update.down());
|
270
|
-
|
271
|
-
if(this.update.firstChild && this.update.down().childNodes) {
|
272
|
-
this.entryCount =
|
273
|
-
this.update.down().childNodes.length;
|
274
|
-
for (var i = 0; i < this.entryCount; i++) {
|
275
|
-
var entry = this.getEntry(i);
|
276
|
-
entry.autocompleteIndex = i;
|
277
|
-
this.addObservers(entry);
|
278
|
-
}
|
279
|
-
} else {
|
280
|
-
this.entryCount = 0;
|
281
|
-
}
|
282
|
-
|
283
|
-
this.stopIndicator();
|
284
|
-
this.index = 0;
|
285
|
-
|
286
|
-
if(this.entryCount==1 && this.options.autoSelect) {
|
287
|
-
this.selectEntry();
|
288
|
-
this.hide();
|
289
|
-
} else {
|
290
|
-
this.render();
|
291
|
-
}
|
292
|
-
}
|
293
|
-
},
|
294
|
-
|
295
|
-
addObservers: function(element) {
|
296
|
-
Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
|
297
|
-
Event.observe(element, "click", this.onClick.bindAsEventListener(this));
|
298
|
-
},
|
299
|
-
|
300
|
-
onObserverEvent: function() {
|
301
|
-
this.changed = false;
|
302
|
-
this.tokenBounds = null;
|
303
|
-
if(this.getToken().length>=this.options.minChars) {
|
304
|
-
this.getUpdatedChoices();
|
305
|
-
} else {
|
306
|
-
this.active = false;
|
307
|
-
this.hide();
|
308
|
-
}
|
309
|
-
this.oldElementValue = this.element.value;
|
310
|
-
},
|
311
|
-
|
312
|
-
getToken: function() {
|
313
|
-
var bounds = this.getTokenBounds();
|
314
|
-
return this.element.value.substring(bounds[0], bounds[1]).strip();
|
315
|
-
},
|
316
|
-
|
317
|
-
getTokenBounds: function() {
|
318
|
-
if (null != this.tokenBounds) return this.tokenBounds;
|
319
|
-
var value = this.element.value;
|
320
|
-
if (value.strip().empty()) return [-1, 0];
|
321
|
-
var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
|
322
|
-
var offset = (diff == this.oldElementValue.length ? 1 : 0);
|
323
|
-
var prevTokenPos = -1, nextTokenPos = value.length;
|
324
|
-
var tp;
|
325
|
-
for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
|
326
|
-
tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
|
327
|
-
if (tp > prevTokenPos) prevTokenPos = tp;
|
328
|
-
tp = value.indexOf(this.options.tokens[index], diff + offset);
|
329
|
-
if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
|
330
|
-
}
|
331
|
-
return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
|
332
|
-
}
|
333
|
-
});
|
334
|
-
|
335
|
-
Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
|
336
|
-
var boundary = Math.min(newS.length, oldS.length);
|
337
|
-
for (var index = 0; index < boundary; ++index)
|
338
|
-
if (newS[index] != oldS[index])
|
339
|
-
return index;
|
340
|
-
return boundary;
|
341
|
-
};
|
342
|
-
|
343
|
-
Ajax.Autocompleter = Class.create(Autocompleter.Base, {
|
344
|
-
initialize: function(element, update, url, options) {
|
345
|
-
this.baseInitialize(element, update, options);
|
346
|
-
this.options.asynchronous = true;
|
347
|
-
this.options.onComplete = this.onComplete.bind(this);
|
348
|
-
this.options.defaultParams = this.options.parameters || null;
|
349
|
-
this.url = url;
|
350
|
-
},
|
351
|
-
|
352
|
-
getUpdatedChoices: function() {
|
353
|
-
this.startIndicator();
|
354
|
-
|
355
|
-
var entry = encodeURIComponent(this.options.paramName) + '=' +
|
356
|
-
encodeURIComponent(this.getToken());
|
357
|
-
|
358
|
-
this.options.parameters = this.options.callback ?
|
359
|
-
this.options.callback(this.element, entry) : entry;
|
360
|
-
|
361
|
-
if(this.options.defaultParams)
|
362
|
-
this.options.parameters += '&' + this.options.defaultParams;
|
363
|
-
|
364
|
-
new Ajax.Request(this.url, this.options);
|
365
|
-
},
|
366
|
-
|
367
|
-
onComplete: function(request) {
|
368
|
-
this.updateChoices(request.responseText);
|
369
|
-
}
|
370
|
-
});
|
371
|
-
|
372
|
-
// The local array autocompleter. Used when you'd prefer to
|
373
|
-
// inject an array of autocompletion options into the page, rather
|
374
|
-
// than sending out Ajax queries, which can be quite slow sometimes.
|
375
|
-
//
|
376
|
-
// The constructor takes four parameters. The first two are, as usual,
|
377
|
-
// the id of the monitored textbox, and id of the autocompletion menu.
|
378
|
-
// The third is the array you want to autocomplete from, and the fourth
|
379
|
-
// is the options block.
|
380
|
-
//
|
381
|
-
// Extra local autocompletion options:
|
382
|
-
// - choices - How many autocompletion choices to offer
|
383
|
-
//
|
384
|
-
// - partialSearch - If false, the autocompleter will match entered
|
385
|
-
// text only at the beginning of strings in the
|
386
|
-
// autocomplete array. Defaults to true, which will
|
387
|
-
// match text at the beginning of any *word* in the
|
388
|
-
// strings in the autocomplete array. If you want to
|
389
|
-
// search anywhere in the string, additionally set
|
390
|
-
// the option fullSearch to true (default: off).
|
391
|
-
//
|
392
|
-
// - fullSsearch - Search anywhere in autocomplete array strings.
|
393
|
-
//
|
394
|
-
// - partialChars - How many characters to enter before triggering
|
395
|
-
// a partial match (unlike minChars, which defines
|
396
|
-
// how many characters are required to do any match
|
397
|
-
// at all). Defaults to 2.
|
398
|
-
//
|
399
|
-
// - ignoreCase - Whether to ignore case when autocompleting.
|
400
|
-
// Defaults to true.
|
401
|
-
//
|
402
|
-
// It's possible to pass in a custom function as the 'selector'
|
403
|
-
// option, if you prefer to write your own autocompletion logic.
|
404
|
-
// In that case, the other options above will not apply unless
|
405
|
-
// you support them.
|
406
|
-
|
407
|
-
Autocompleter.Local = Class.create(Autocompleter.Base, {
|
408
|
-
initialize: function(element, update, array, options) {
|
409
|
-
this.baseInitialize(element, update, options);
|
410
|
-
this.options.array = array;
|
411
|
-
},
|
412
|
-
|
413
|
-
getUpdatedChoices: function() {
|
414
|
-
this.updateChoices(this.options.selector(this));
|
415
|
-
},
|
416
|
-
|
417
|
-
setOptions: function(options) {
|
418
|
-
this.options = Object.extend({
|
419
|
-
choices: 10,
|
420
|
-
partialSearch: true,
|
421
|
-
partialChars: 2,
|
422
|
-
ignoreCase: true,
|
423
|
-
fullSearch: false,
|
424
|
-
selector: function(instance) {
|
425
|
-
var ret = []; // Beginning matches
|
426
|
-
var partial = []; // Inside matches
|
427
|
-
var entry = instance.getToken();
|
428
|
-
var count = 0;
|
429
|
-
|
430
|
-
for (var i = 0; i < instance.options.array.length &&
|
431
|
-
ret.length < instance.options.choices ; i++) {
|
432
|
-
|
433
|
-
var elem = instance.options.array[i];
|
434
|
-
var foundPos = instance.options.ignoreCase ?
|
435
|
-
elem.toLowerCase().indexOf(entry.toLowerCase()) :
|
436
|
-
elem.indexOf(entry);
|
437
|
-
|
438
|
-
while (foundPos != -1) {
|
439
|
-
if (foundPos == 0 && elem.length != entry.length) {
|
440
|
-
ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
|
441
|
-
elem.substr(entry.length) + "</li>");
|
442
|
-
break;
|
443
|
-
} else if (entry.length >= instance.options.partialChars &&
|
444
|
-
instance.options.partialSearch && foundPos != -1) {
|
445
|
-
if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
|
446
|
-
partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
|
447
|
-
elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
|
448
|
-
foundPos + entry.length) + "</li>");
|
449
|
-
break;
|
450
|
-
}
|
451
|
-
}
|
452
|
-
|
453
|
-
foundPos = instance.options.ignoreCase ?
|
454
|
-
elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
|
455
|
-
elem.indexOf(entry, foundPos + 1);
|
456
|
-
|
457
|
-
}
|
458
|
-
}
|
459
|
-
if (partial.length)
|
460
|
-
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));
|
461
|
-
return "<ul>" + ret.join('') + "</ul>";
|
462
|
-
}
|
463
|
-
}, options || { });
|
464
|
-
}
|
465
|
-
});
|
466
|
-
|
467
|
-
// AJAX in-place editor and collection editor
|
468
|
-
// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).
|
469
|
-
|
470
|
-
// Use this if you notice weird scrolling problems on some browsers,
|
471
|
-
// the DOM might be a bit confused when this gets called so do this
|
472
|
-
// waits 1 ms (with setTimeout) until it does the activation
|
473
|
-
Field.scrollFreeActivate = function(field) {
|
474
|
-
setTimeout(function() {
|
475
|
-
Field.activate(field);
|
476
|
-
}, 1);
|
477
|
-
};
|
478
|
-
|
479
|
-
Ajax.InPlaceEditor = Class.create({
|
480
|
-
initialize: function(element, url, options) {
|
481
|
-
this.url = url;
|
482
|
-
this.element = element = $(element);
|
483
|
-
this.prepareOptions();
|
484
|
-
this._controls = { };
|
485
|
-
arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
|
486
|
-
Object.extend(this.options, options || { });
|
487
|
-
if (!this.options.formId && this.element.id) {
|
488
|
-
this.options.formId = this.element.id + '-inplaceeditor';
|
489
|
-
if ($(this.options.formId))
|
490
|
-
this.options.formId = '';
|
491
|
-
}
|
492
|
-
if (this.options.externalControl)
|
493
|
-
this.options.externalControl = $(this.options.externalControl);
|
494
|
-
if (!this.options.externalControl)
|
495
|
-
this.options.externalControlOnly = false;
|
496
|
-
this._originalBackground = this.element.getStyle('background-color') || 'transparent';
|
497
|
-
this.element.title = this.options.clickToEditText;
|
498
|
-
this._boundCancelHandler = this.handleFormCancellation.bind(this);
|
499
|
-
this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
|
500
|
-
this._boundFailureHandler = this.handleAJAXFailure.bind(this);
|
501
|
-
this._boundSubmitHandler = this.handleFormSubmission.bind(this);
|
502
|
-
this._boundWrapperHandler = this.wrapUp.bind(this);
|
503
|
-
this.registerListeners();
|
504
|
-
},
|
505
|
-
checkForEscapeOrReturn: function(e) {
|
506
|
-
if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
|
507
|
-
if (Event.KEY_ESC == e.keyCode)
|
508
|
-
this.handleFormCancellation(e);
|
509
|
-
else if (Event.KEY_RETURN == e.keyCode)
|
510
|
-
this.handleFormSubmission(e);
|
511
|
-
},
|
512
|
-
createControl: function(mode, handler, extraClasses) {
|
513
|
-
var control = this.options[mode + 'Control'];
|
514
|
-
var text = this.options[mode + 'Text'];
|
515
|
-
if ('button' == control) {
|
516
|
-
var btn = document.createElement('input');
|
517
|
-
btn.type = 'submit';
|
518
|
-
btn.value = text;
|
519
|
-
btn.className = 'editor_' + mode + '_button';
|
520
|
-
if ('cancel' == mode)
|
521
|
-
btn.onclick = this._boundCancelHandler;
|
522
|
-
this._form.appendChild(btn);
|
523
|
-
this._controls[mode] = btn;
|
524
|
-
} else if ('link' == control) {
|
525
|
-
var link = document.createElement('a');
|
526
|
-
link.href = '#';
|
527
|
-
link.appendChild(document.createTextNode(text));
|
528
|
-
link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
|
529
|
-
link.className = 'editor_' + mode + '_link';
|
530
|
-
if (extraClasses)
|
531
|
-
link.className += ' ' + extraClasses;
|
532
|
-
this._form.appendChild(link);
|
533
|
-
this._controls[mode] = link;
|
534
|
-
}
|
535
|
-
},
|
536
|
-
createEditField: function() {
|
537
|
-
var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
|
538
|
-
var fld;
|
539
|
-
if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
|
540
|
-
fld = document.createElement('input');
|
541
|
-
fld.type = 'text';
|
542
|
-
var size = this.options.size || this.options.cols || 0;
|
543
|
-
if (0 < size) fld.size = size;
|
544
|
-
} else {
|
545
|
-
fld = document.createElement('textarea');
|
546
|
-
fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
|
547
|
-
fld.cols = this.options.cols || 40;
|
548
|
-
}
|
549
|
-
fld.name = this.options.paramName;
|
550
|
-
fld.value = text; // No HTML breaks conversion anymore
|
551
|
-
fld.className = 'editor_field';
|
552
|
-
if (this.options.submitOnBlur)
|
553
|
-
fld.onblur = this._boundSubmitHandler;
|
554
|
-
this._controls.editor = fld;
|
555
|
-
if (this.options.loadTextURL)
|
556
|
-
this.loadExternalText();
|
557
|
-
this._form.appendChild(this._controls.editor);
|
558
|
-
},
|
559
|
-
createForm: function() {
|
560
|
-
var ipe = this;
|
561
|
-
function addText(mode, condition) {
|
562
|
-
var text = ipe.options['text' + mode + 'Controls'];
|
563
|
-
if (!text || condition === false) return;
|
564
|
-
ipe._form.appendChild(document.createTextNode(text));
|
565
|
-
};
|
566
|
-
this._form = $(document.createElement('form'));
|
567
|
-
this._form.id = this.options.formId;
|
568
|
-
this._form.addClassName(this.options.formClassName);
|
569
|
-
this._form.onsubmit = this._boundSubmitHandler;
|
570
|
-
this.createEditField();
|
571
|
-
if ('textarea' == this._controls.editor.tagName.toLowerCase())
|
572
|
-
this._form.appendChild(document.createElement('br'));
|
573
|
-
if (this.options.onFormCustomization)
|
574
|
-
this.options.onFormCustomization(this, this._form);
|
575
|
-
addText('Before', this.options.okControl || this.options.cancelControl);
|
576
|
-
this.createControl('ok', this._boundSubmitHandler);
|
577
|
-
addText('Between', this.options.okControl && this.options.cancelControl);
|
578
|
-
this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
|
579
|
-
addText('After', this.options.okControl || this.options.cancelControl);
|
580
|
-
},
|
581
|
-
destroy: function() {
|
582
|
-
if (this._oldInnerHTML)
|
583
|
-
this.element.innerHTML = this._oldInnerHTML;
|
584
|
-
this.leaveEditMode();
|
585
|
-
this.unregisterListeners();
|
586
|
-
},
|
587
|
-
enterEditMode: function(e) {
|
588
|
-
if (this._saving || this._editing) return;
|
589
|
-
this._editing = true;
|
590
|
-
this.triggerCallback('onEnterEditMode');
|
591
|
-
if (this.options.externalControl)
|
592
|
-
this.options.externalControl.hide();
|
593
|
-
this.element.hide();
|
594
|
-
this.createForm();
|
595
|
-
this.element.parentNode.insertBefore(this._form, this.element);
|
596
|
-
if (!this.options.loadTextURL)
|
597
|
-
this.postProcessEditField();
|
598
|
-
if (e) Event.stop(e);
|
599
|
-
},
|
600
|
-
enterHover: function(e) {
|
601
|
-
if (this.options.hoverClassName)
|
602
|
-
this.element.addClassName(this.options.hoverClassName);
|
603
|
-
if (this._saving) return;
|
604
|
-
this.triggerCallback('onEnterHover');
|
605
|
-
},
|
606
|
-
getText: function() {
|
607
|
-
return this.element.innerHTML.unescapeHTML();
|
608
|
-
},
|
609
|
-
handleAJAXFailure: function(transport) {
|
610
|
-
this.triggerCallback('onFailure', transport);
|
611
|
-
if (this._oldInnerHTML) {
|
612
|
-
this.element.innerHTML = this._oldInnerHTML;
|
613
|
-
this._oldInnerHTML = null;
|
614
|
-
}
|
615
|
-
},
|
616
|
-
handleFormCancellation: function(e) {
|
617
|
-
this.wrapUp();
|
618
|
-
if (e) Event.stop(e);
|
619
|
-
},
|
620
|
-
handleFormSubmission: function(e) {
|
621
|
-
var form = this._form;
|
622
|
-
var value = $F(this._controls.editor);
|
623
|
-
this.prepareSubmission();
|
624
|
-
var params = this.options.callback(form, value) || '';
|
625
|
-
if (Object.isString(params))
|
626
|
-
params = params.toQueryParams();
|
627
|
-
params.editorId = this.element.id;
|
628
|
-
if (this.options.htmlResponse) {
|
629
|
-
var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
|
630
|
-
Object.extend(options, {
|
631
|
-
parameters: params,
|
632
|
-
onComplete: this._boundWrapperHandler,
|
633
|
-
onFailure: this._boundFailureHandler
|
634
|
-
});
|
635
|
-
new Ajax.Updater({ success: this.element }, this.url, options);
|
636
|
-
} else {
|
637
|
-
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
|
638
|
-
Object.extend(options, {
|
639
|
-
parameters: params,
|
640
|
-
onComplete: this._boundWrapperHandler,
|
641
|
-
onFailure: this._boundFailureHandler
|
642
|
-
});
|
643
|
-
new Ajax.Request(this.url, options);
|
644
|
-
}
|
645
|
-
if (e) Event.stop(e);
|
646
|
-
},
|
647
|
-
leaveEditMode: function() {
|
648
|
-
this.element.removeClassName(this.options.savingClassName);
|
649
|
-
this.removeForm();
|
650
|
-
this.leaveHover();
|
651
|
-
this.element.style.backgroundColor = this._originalBackground;
|
652
|
-
this.element.show();
|
653
|
-
if (this.options.externalControl)
|
654
|
-
this.options.externalControl.show();
|
655
|
-
this._saving = false;
|
656
|
-
this._editing = false;
|
657
|
-
this._oldInnerHTML = null;
|
658
|
-
this.triggerCallback('onLeaveEditMode');
|
659
|
-
},
|
660
|
-
leaveHover: function(e) {
|
661
|
-
if (this.options.hoverClassName)
|
662
|
-
this.element.removeClassName(this.options.hoverClassName);
|
663
|
-
if (this._saving) return;
|
664
|
-
this.triggerCallback('onLeaveHover');
|
665
|
-
},
|
666
|
-
loadExternalText: function() {
|
667
|
-
this._form.addClassName(this.options.loadingClassName);
|
668
|
-
this._controls.editor.disabled = true;
|
669
|
-
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
|
670
|
-
Object.extend(options, {
|
671
|
-
parameters: 'editorId=' + encodeURIComponent(this.element.id),
|
672
|
-
onComplete: Prototype.emptyFunction,
|
673
|
-
onSuccess: function(transport) {
|
674
|
-
this._form.removeClassName(this.options.loadingClassName);
|
675
|
-
var text = transport.responseText;
|
676
|
-
if (this.options.stripLoadedTextTags)
|
677
|
-
text = text.stripTags();
|
678
|
-
this._controls.editor.value = text;
|
679
|
-
this._controls.editor.disabled = false;
|
680
|
-
this.postProcessEditField();
|
681
|
-
}.bind(this),
|
682
|
-
onFailure: this._boundFailureHandler
|
683
|
-
});
|
684
|
-
new Ajax.Request(this.options.loadTextURL, options);
|
685
|
-
},
|
686
|
-
postProcessEditField: function() {
|
687
|
-
var fpc = this.options.fieldPostCreation;
|
688
|
-
if (fpc)
|
689
|
-
$(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
|
690
|
-
},
|
691
|
-
prepareOptions: function() {
|
692
|
-
this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
|
693
|
-
Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
|
694
|
-
[this._extraDefaultOptions].flatten().compact().each(function(defs) {
|
695
|
-
Object.extend(this.options, defs);
|
696
|
-
}.bind(this));
|
697
|
-
},
|
698
|
-
prepareSubmission: function() {
|
699
|
-
this._saving = true;
|
700
|
-
this.removeForm();
|
701
|
-
this.leaveHover();
|
702
|
-
this.showSaving();
|
703
|
-
},
|
704
|
-
registerListeners: function() {
|
705
|
-
this._listeners = { };
|
706
|
-
var listener;
|
707
|
-
$H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
|
708
|
-
listener = this[pair.value].bind(this);
|
709
|
-
this._listeners[pair.key] = listener;
|
710
|
-
if (!this.options.externalControlOnly)
|
711
|
-
this.element.observe(pair.key, listener);
|
712
|
-
if (this.options.externalControl)
|
713
|
-
this.options.externalControl.observe(pair.key, listener);
|
714
|
-
}.bind(this));
|
715
|
-
},
|
716
|
-
removeForm: function() {
|
717
|
-
if (!this._form) return;
|
718
|
-
this._form.remove();
|
719
|
-
this._form = null;
|
720
|
-
this._controls = { };
|
721
|
-
},
|
722
|
-
showSaving: function() {
|
723
|
-
this._oldInnerHTML = this.element.innerHTML;
|
724
|
-
this.element.innerHTML = this.options.savingText;
|
725
|
-
this.element.addClassName(this.options.savingClassName);
|
726
|
-
this.element.style.backgroundColor = this._originalBackground;
|
727
|
-
this.element.show();
|
728
|
-
},
|
729
|
-
triggerCallback: function(cbName, arg) {
|
730
|
-
if ('function' == typeof this.options[cbName]) {
|
731
|
-
this.options[cbName](this, arg);
|
732
|
-
}
|
733
|
-
},
|
734
|
-
unregisterListeners: function() {
|
735
|
-
$H(this._listeners).each(function(pair) {
|
736
|
-
if (!this.options.externalControlOnly)
|
737
|
-
this.element.stopObserving(pair.key, pair.value);
|
738
|
-
if (this.options.externalControl)
|
739
|
-
this.options.externalControl.stopObserving(pair.key, pair.value);
|
740
|
-
}.bind(this));
|
741
|
-
},
|
742
|
-
wrapUp: function(transport) {
|
743
|
-
this.leaveEditMode();
|
744
|
-
// Can't use triggerCallback due to backward compatibility: requires
|
745
|
-
// binding + direct element
|
746
|
-
this._boundComplete(transport, this.element);
|
747
|
-
}
|
748
|
-
});
|
749
|
-
|
750
|
-
Object.extend(Ajax.InPlaceEditor.prototype, {
|
751
|
-
dispose: Ajax.InPlaceEditor.prototype.destroy
|
752
|
-
});
|
753
|
-
|
754
|
-
Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
|
755
|
-
initialize: function($super, element, url, options) {
|
756
|
-
this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
|
757
|
-
$super(element, url, options);
|
758
|
-
},
|
759
|
-
|
760
|
-
createEditField: function() {
|
761
|
-
var list = document.createElement('select');
|
762
|
-
list.name = this.options.paramName;
|
763
|
-
list.size = 1;
|
764
|
-
this._controls.editor = list;
|
765
|
-
this._collection = this.options.collection || [];
|
766
|
-
if (this.options.loadCollectionURL)
|
767
|
-
this.loadCollection();
|
768
|
-
else
|
769
|
-
this.checkForExternalText();
|
770
|
-
this._form.appendChild(this._controls.editor);
|
771
|
-
},
|
772
|
-
|
773
|
-
loadCollection: function() {
|
774
|
-
this._form.addClassName(this.options.loadingClassName);
|
775
|
-
this.showLoadingText(this.options.loadingCollectionText);
|
776
|
-
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
|
777
|
-
Object.extend(options, {
|
778
|
-
parameters: 'editorId=' + encodeURIComponent(this.element.id),
|
779
|
-
onComplete: Prototype.emptyFunction,
|
780
|
-
onSuccess: function(transport) {
|
781
|
-
var js = transport.responseText.strip();
|
782
|
-
if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
|
783
|
-
throw('Server returned an invalid collection representation.');
|
784
|
-
this._collection = eval(js);
|
785
|
-
this.checkForExternalText();
|
786
|
-
}.bind(this),
|
787
|
-
onFailure: this.onFailure
|
788
|
-
});
|
789
|
-
new Ajax.Request(this.options.loadCollectionURL, options);
|
790
|
-
},
|
791
|
-
|
792
|
-
showLoadingText: function(text) {
|
793
|
-
this._controls.editor.disabled = true;
|
794
|
-
var tempOption = this._controls.editor.firstChild;
|
795
|
-
if (!tempOption) {
|
796
|
-
tempOption = document.createElement('option');
|
797
|
-
tempOption.value = '';
|
798
|
-
this._controls.editor.appendChild(tempOption);
|
799
|
-
tempOption.selected = true;
|
800
|
-
}
|
801
|
-
tempOption.update((text || '').stripScripts().stripTags());
|
802
|
-
},
|
803
|
-
|
804
|
-
checkForExternalText: function() {
|
805
|
-
this._text = this.getText();
|
806
|
-
if (this.options.loadTextURL)
|
807
|
-
this.loadExternalText();
|
808
|
-
else
|
809
|
-
this.buildOptionList();
|
810
|
-
},
|
811
|
-
|
812
|
-
loadExternalText: function() {
|
813
|
-
this.showLoadingText(this.options.loadingText);
|
814
|
-
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
|
815
|
-
Object.extend(options, {
|
816
|
-
parameters: 'editorId=' + encodeURIComponent(this.element.id),
|
817
|
-
onComplete: Prototype.emptyFunction,
|
818
|
-
onSuccess: function(transport) {
|
819
|
-
this._text = transport.responseText.strip();
|
820
|
-
this.buildOptionList();
|
821
|
-
}.bind(this),
|
822
|
-
onFailure: this.onFailure
|
823
|
-
});
|
824
|
-
new Ajax.Request(this.options.loadTextURL, options);
|
825
|
-
},
|
826
|
-
|
827
|
-
buildOptionList: function() {
|
828
|
-
this._form.removeClassName(this.options.loadingClassName);
|
829
|
-
this._collection = this._collection.map(function(entry) {
|
830
|
-
return 2 === entry.length ? entry : [entry, entry].flatten();
|
831
|
-
});
|
832
|
-
var marker = ('value' in this.options) ? this.options.value : this._text;
|
833
|
-
var textFound = this._collection.any(function(entry) {
|
834
|
-
return entry[0] == marker;
|
835
|
-
}.bind(this));
|
836
|
-
this._controls.editor.update('');
|
837
|
-
var option;
|
838
|
-
this._collection.each(function(entry, index) {
|
839
|
-
option = document.createElement('option');
|
840
|
-
option.value = entry[0];
|
841
|
-
option.selected = textFound ? entry[0] == marker : 0 == index;
|
842
|
-
option.appendChild(document.createTextNode(entry[1]));
|
843
|
-
this._controls.editor.appendChild(option);
|
844
|
-
}.bind(this));
|
845
|
-
this._controls.editor.disabled = false;
|
846
|
-
Field.scrollFreeActivate(this._controls.editor);
|
847
|
-
}
|
848
|
-
});
|
849
|
-
|
850
|
-
//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
|
851
|
-
//**** This only exists for a while, in order to let ****
|
852
|
-
//**** users adapt to the new API. Read up on the new ****
|
853
|
-
//**** API and convert your code to it ASAP! ****
|
854
|
-
|
855
|
-
Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
|
856
|
-
if (!options) return;
|
857
|
-
function fallback(name, expr) {
|
858
|
-
if (name in options || expr === undefined) return;
|
859
|
-
options[name] = expr;
|
860
|
-
};
|
861
|
-
fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
|
862
|
-
options.cancelLink == options.cancelButton == false ? false : undefined)));
|
863
|
-
fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
|
864
|
-
options.okLink == options.okButton == false ? false : undefined)));
|
865
|
-
fallback('highlightColor', options.highlightcolor);
|
866
|
-
fallback('highlightEndColor', options.highlightendcolor);
|
867
|
-
};
|
868
|
-
|
869
|
-
Object.extend(Ajax.InPlaceEditor, {
|
870
|
-
DefaultOptions: {
|
871
|
-
ajaxOptions: { },
|
872
|
-
autoRows: 3, // Use when multi-line w/ rows == 1
|
873
|
-
cancelControl: 'link', // 'link'|'button'|false
|
874
|
-
cancelText: 'cancel',
|
875
|
-
clickToEditText: 'Click to edit',
|
876
|
-
externalControl: null, // id|elt
|
877
|
-
externalControlOnly: false,
|
878
|
-
fieldPostCreation: 'activate', // 'activate'|'focus'|false
|
879
|
-
formClassName: 'inplaceeditor-form',
|
880
|
-
formId: null, // id|elt
|
881
|
-
highlightColor: '#ffff99',
|
882
|
-
highlightEndColor: '#ffffff',
|
883
|
-
hoverClassName: '',
|
884
|
-
htmlResponse: true,
|
885
|
-
loadingClassName: 'inplaceeditor-loading',
|
886
|
-
loadingText: 'Loading...',
|
887
|
-
okControl: 'button', // 'link'|'button'|false
|
888
|
-
okText: 'ok',
|
889
|
-
paramName: 'value',
|
890
|
-
rows: 1, // If 1 and multi-line, uses autoRows
|
891
|
-
savingClassName: 'inplaceeditor-saving',
|
892
|
-
savingText: 'Saving...',
|
893
|
-
size: 0,
|
894
|
-
stripLoadedTextTags: false,
|
895
|
-
submitOnBlur: false,
|
896
|
-
textAfterControls: '',
|
897
|
-
textBeforeControls: '',
|
898
|
-
textBetweenControls: ''
|
899
|
-
},
|
900
|
-
DefaultCallbacks: {
|
901
|
-
callback: function(form) {
|
902
|
-
return Form.serialize(form);
|
903
|
-
},
|
904
|
-
onComplete: function(transport, element) {
|
905
|
-
// For backward compatibility, this one is bound to the IPE, and passes
|
906
|
-
// the element directly. It was too often customized, so we don't break it.
|
907
|
-
new Effect.Highlight(element, {
|
908
|
-
startcolor: this.options.highlightColor, keepBackgroundImage: true });
|
909
|
-
},
|
910
|
-
onEnterEditMode: null,
|
911
|
-
onEnterHover: function(ipe) {
|
912
|
-
ipe.element.style.backgroundColor = ipe.options.highlightColor;
|
913
|
-
if (ipe._effect)
|
914
|
-
ipe._effect.cancel();
|
915
|
-
},
|
916
|
-
onFailure: function(transport, ipe) {
|
917
|
-
alert('Error communication with the server: ' + transport.responseText.stripTags());
|
918
|
-
},
|
919
|
-
onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
|
920
|
-
onLeaveEditMode: null,
|
921
|
-
onLeaveHover: function(ipe) {
|
922
|
-
ipe._effect = new Effect.Highlight(ipe.element, {
|
923
|
-
startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
|
924
|
-
restorecolor: ipe._originalBackground, keepBackgroundImage: true
|
925
|
-
});
|
926
|
-
}
|
927
|
-
},
|
928
|
-
Listeners: {
|
929
|
-
click: 'enterEditMode',
|
930
|
-
keydown: 'checkForEscapeOrReturn',
|
931
|
-
mouseover: 'enterHover',
|
932
|
-
mouseout: 'leaveHover'
|
933
|
-
}
|
934
|
-
});
|
935
|
-
|
936
|
-
Ajax.InPlaceCollectionEditor.DefaultOptions = {
|
937
|
-
loadingCollectionText: 'Loading options...'
|
938
|
-
};
|
939
|
-
|
940
|
-
// Delayed observer, like Form.Element.Observer,
|
941
|
-
// but waits for delay after last key input
|
942
|
-
// Ideal for live-search fields
|
943
|
-
|
944
|
-
Form.Element.DelayedObserver = Class.create({
|
945
|
-
initialize: function(element, delay, callback) {
|
946
|
-
this.delay = delay || 0.5;
|
947
|
-
this.element = $(element);
|
948
|
-
this.callback = callback;
|
949
|
-
this.timer = null;
|
950
|
-
this.lastValue = $F(this.element);
|
951
|
-
Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
|
952
|
-
},
|
953
|
-
delayedListener: function(event) {
|
954
|
-
if(this.lastValue == $F(this.element)) return;
|
955
|
-
if(this.timer) clearTimeout(this.timer);
|
956
|
-
this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
|
957
|
-
this.lastValue = $F(this.element);
|
958
|
-
},
|
959
|
-
onTimerEvent: function() {
|
960
|
-
this.timer = null;
|
961
|
-
this.callback(this.element, $F(this.element));
|
962
|
-
}
|
963
|
-
});
|