motiro 0.6.9 → 0.6.10
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/README +1 -1
- data/Rakefile +2 -2
- data/app/core/version.rb +1 -1
- data/app/helpers/feed_helper.rb +2 -0
- data/app/reporters/darcs_reporter.rb +2 -3
- data/app/views/events/new.rhtml +14 -0
- data/app/views/feed/subversion.rhtml +26 -0
- data/app/views/report/events_detail.rhtml +12 -0
- data/build/build.rb +29 -0
- data/config/boot.rb +104 -14
- data/config/environment.rb +35 -38
- data/config/environments/development.rb +5 -7
- data/config/environments/production.rb +3 -3
- data/config/environments/test.rb +5 -2
- data/config/initializers/globalize.rb +5 -0
- data/config/initializers/inflections.rb +10 -0
- data/config/initializers/mime_types.rb +5 -0
- data/config/initializers/motiro_core.rb +5 -0
- data/config/motiro.yml +4 -4
- data/config/report/subversion.yml +26 -0
- data/doc/README_FOR_APP +1 -1
- data/lib/login_system.rb +2 -2
- data/lib/tasks/packaging.rake +4 -4
- data/public/404.html +27 -5
- data/public/422.html +30 -0
- data/public/500.html +27 -5
- data/public/dispatch.rb +2 -2
- data/public/javascripts/application.js +2 -0
- data/public/javascripts/controls.js +532 -319
- data/public/javascripts/dragdrop.js +521 -133
- data/public/javascripts/effects.js +708 -442
- data/public/javascripts/prototype.js +3393 -953
- data/public/robots.txt +5 -1
- data/public/selenium/tests/TestMainPage.html +42 -0
- data/public/selenium/tests/TestReportHTML.html +42 -0
- data/public/selenium/tests/TestReportRSS.html +37 -0
- data/public/selenium/tests/TestSubversionOnMain.html +32 -0
- data/public/selenium/tests/TestSuite.html +26 -0
- data/script/about +1 -1
- data/script/console +1 -1
- data/script/destroy +1 -1
- data/script/generate +1 -1
- data/script/performance/request +3 -0
- data/script/plugin +1 -1
- data/script/process/inspector +3 -0
- data/script/runner +1 -1
- data/script/server +1 -1
- data/test/fixtures/headlines.yml +6 -6
- data/test/functional/report_controller_test.rb +18 -18
- data/test/functional/root_controller_test.rb +1 -1
- data/test/test_helper.rb +11 -1
- data/test/unit/chief_editor_test.rb +20 -26
- data/test/unit/darcs_reporter_test.rb +6 -0
- data/test/unit/headline_test.rb +25 -8
- data/vendor/plugins/cache_test-0.2/doc/classes/Cosinux/FragmentCacheTest/Assertions.html +364 -0
- data/vendor/plugins/cache_test-0.2/doc/classes/Cosinux/PageCacheTest/IntegrationTestMethods.html +261 -0
- data/vendor/plugins/cache_test-0.2/doc/created.rid +1 -0
- data/vendor/plugins/cache_test-0.2/doc/files/CHANGELOG.html +128 -0
- data/vendor/plugins/cache_test-0.2/doc/files/MIT-LICENSE.html +129 -0
- data/vendor/plugins/cache_test-0.2/doc/files/README.html +272 -0
- data/vendor/plugins/cache_test-0.2/doc/files/init_rb.html +109 -0
- data/vendor/plugins/cache_test-0.2/doc/files/lib/fragment_cache_test_rb.html +101 -0
- data/vendor/plugins/cache_test-0.2/doc/files/lib/page_cache_test_rb.html +101 -0
- data/vendor/plugins/cache_test-0.2/doc/fr_class_index.html +28 -0
- data/vendor/plugins/cache_test-0.2/doc/fr_file_index.html +32 -0
- data/vendor/plugins/cache_test-0.2/doc/fr_method_index.html +32 -0
- data/vendor/plugins/cache_test-0.2/doc/index.html +24 -0
- data/vendor/plugins/cache_test-0.2/doc/rdoc-style.css +208 -0
- data/vendor/plugins/caching_monkey_patch/init.rb +13 -0
- data/vendor/plugins/rails_cron/CHANGELOG +8 -0
- data/vendor/plugins/rails_cron/LICENSE +7 -0
- data/vendor/plugins/rails_cron/README +77 -0
- data/vendor/plugins/rails_cron/init.rb +16 -0
- data/vendor/plugins/rails_cron/lib/acts_as_background.rb +14 -0
- data/vendor/plugins/rails_cron/lib/rails_cron.rb +128 -0
- data/vendor/plugins/rails_cron/tasks/startup.rake +50 -0
- metadata +466 -406
data/config/motiro.yml
CHANGED
|
@@ -23,13 +23,13 @@ package_size: 5
|
|
|
23
23
|
update_interval: 40
|
|
24
24
|
|
|
25
25
|
# Subversion specific settings
|
|
26
|
-
subversion:
|
|
26
|
+
# subversion:
|
|
27
27
|
|
|
28
28
|
# subversion/repo
|
|
29
29
|
#
|
|
30
30
|
# Tells the reporter where to find your project's repository
|
|
31
31
|
# Default: https://svn.sourceforge.net/svnroot/motiro
|
|
32
|
-
repo: https://motiro.svn.sourceforge.net/svnroot/motiro
|
|
32
|
+
# repo: https://motiro.svn.sourceforge.net/svnroot/motiro
|
|
33
33
|
|
|
34
34
|
# subversion/{user,password}
|
|
35
35
|
#
|
|
@@ -41,8 +41,8 @@ subversion:
|
|
|
41
41
|
|
|
42
42
|
# Darcs specific settings
|
|
43
43
|
# Uncomment the lines below to activate darcs reporting
|
|
44
|
-
|
|
44
|
+
darcs:
|
|
45
45
|
|
|
46
46
|
# darcs/repo
|
|
47
47
|
# Tells the reporter where to find the project's central repository
|
|
48
|
-
|
|
48
|
+
repo: http://repo.motiro.org/trunk
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# package_size
|
|
2
|
+
#
|
|
3
|
+
# Tells the reporter how many headlines to produce by run
|
|
4
|
+
# It is also used as the number of latest headlines to be shown
|
|
5
|
+
# Default: 5
|
|
6
|
+
package_size: 5
|
|
7
|
+
|
|
8
|
+
# update_interval
|
|
9
|
+
#
|
|
10
|
+
# The number of minutes to wait before sending the reporters out to update the
|
|
11
|
+
# local news base. The reporters can potentially use external resources like
|
|
12
|
+
# network and disk, so please exercise wisdom when setting the interval.
|
|
13
|
+
#
|
|
14
|
+
# Set to 0 to send them out everytime a request arrives and to not record
|
|
15
|
+
# anything locally (useful for testing and debugging)
|
|
16
|
+
update_interval: 10
|
|
17
|
+
|
|
18
|
+
# Subversion specific settings
|
|
19
|
+
svn:
|
|
20
|
+
|
|
21
|
+
# svn/repo
|
|
22
|
+
#
|
|
23
|
+
# Tells the reporter where to find your project's repository
|
|
24
|
+
# Default: http://svn.berlios.de/svnroot/repos/motiro
|
|
25
|
+
repo: http://svn.berlios.de/svnroot/repos/motiro
|
|
26
|
+
|
data/doc/README_FOR_APP
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
Use this README file to introduce your application and point to useful places in the API for learning more.
|
|
2
|
-
Run "rake
|
|
2
|
+
Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
|
data/lib/login_system.rb
CHANGED
data/lib/tasks/packaging.rake
CHANGED
|
@@ -33,7 +33,7 @@ unless MOTIRO_VERSION.include? 'dev'
|
|
|
33
33
|
|
|
34
34
|
s.files = Dir.glob('**/*', File::FNM_DOTMATCH).reject do |f|
|
|
35
35
|
[ /\.$/, /database\.sqlite/, /^(tmp|log)/, /(^|\/)\./,
|
|
36
|
-
/\.log$/, /^pkg/, /\.svn/, /^vendor\//,
|
|
36
|
+
/\.log$/, /^pkg/, /\.svn/, /^vendor\//, /^_darcs/,
|
|
37
37
|
/\~$/, /motiro(db|test)\.sqlite$/,
|
|
38
38
|
/^db\/(development_structure\.sql|schema.rb)/,
|
|
39
39
|
%r{public/javascript($|/)},
|
|
@@ -51,10 +51,10 @@ unless MOTIRO_VERSION.include? 'dev'
|
|
|
51
51
|
s.platform = Gem::Platform::RUBY
|
|
52
52
|
s.executables = ['motiro']
|
|
53
53
|
|
|
54
|
-
s.add_dependency("rails", "=
|
|
55
|
-
s.add_dependency("daemons", ">= 1.0.
|
|
54
|
+
s.add_dependency("rails", "= 2.0.2")
|
|
55
|
+
s.add_dependency("daemons", ">= 1.0.6")
|
|
56
56
|
s.add_dependency("sqlite3-ruby", ">= 1.2.1")
|
|
57
|
-
s.add_dependency("flexmock", ">= 0.
|
|
57
|
+
s.add_dependency("flexmock", ">= 0.6.1")
|
|
58
58
|
s.add_dependency("rails-app-installer", "= 0.2.0")
|
|
59
59
|
s.add_dependency("diff-lcs", ">= 1.1.2")
|
|
60
60
|
end
|
data/public/404.html
CHANGED
|
@@ -1,8 +1,30 @@
|
|
|
1
|
-
<!DOCTYPE
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
3
|
+
|
|
4
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
5
|
+
|
|
6
|
+
<head>
|
|
7
|
+
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
|
|
8
|
+
<title>The page you were looking for doesn't exist (404)</title>
|
|
9
|
+
<style type="text/css">
|
|
10
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
|
11
|
+
div.dialog {
|
|
12
|
+
width: 25em;
|
|
13
|
+
padding: 0 4em;
|
|
14
|
+
margin: 4em auto 0 auto;
|
|
15
|
+
border: 1px solid #ccc;
|
|
16
|
+
border-right-color: #999;
|
|
17
|
+
border-bottom-color: #999;
|
|
18
|
+
}
|
|
19
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
|
20
|
+
</style>
|
|
21
|
+
</head>
|
|
22
|
+
|
|
4
23
|
<body>
|
|
5
|
-
|
|
6
|
-
<
|
|
24
|
+
<!-- This file lives in public/404.html -->
|
|
25
|
+
<div class="dialog">
|
|
26
|
+
<h1>The page you were looking for doesn't exist.</h1>
|
|
27
|
+
<p>You may have mistyped the address or the page may have moved.</p>
|
|
28
|
+
</div>
|
|
7
29
|
</body>
|
|
8
30
|
</html>
|
data/public/422.html
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
3
|
+
|
|
4
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
5
|
+
|
|
6
|
+
<head>
|
|
7
|
+
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
|
|
8
|
+
<title>The change you wanted was rejected (422)</title>
|
|
9
|
+
<style type="text/css">
|
|
10
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
|
11
|
+
div.dialog {
|
|
12
|
+
width: 25em;
|
|
13
|
+
padding: 0 4em;
|
|
14
|
+
margin: 4em auto 0 auto;
|
|
15
|
+
border: 1px solid #ccc;
|
|
16
|
+
border-right-color: #999;
|
|
17
|
+
border-bottom-color: #999;
|
|
18
|
+
}
|
|
19
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
|
20
|
+
</style>
|
|
21
|
+
</head>
|
|
22
|
+
|
|
23
|
+
<body>
|
|
24
|
+
<!-- This file lives in public/422.html -->
|
|
25
|
+
<div class="dialog">
|
|
26
|
+
<h1>The change you wanted was rejected.</h1>
|
|
27
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
|
28
|
+
</div>
|
|
29
|
+
</body>
|
|
30
|
+
</html>
|
data/public/500.html
CHANGED
|
@@ -1,8 +1,30 @@
|
|
|
1
|
-
<!DOCTYPE
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
3
|
+
|
|
4
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
5
|
+
|
|
6
|
+
<head>
|
|
7
|
+
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
|
|
8
|
+
<title>We're sorry, but something went wrong (500)</title>
|
|
9
|
+
<style type="text/css">
|
|
10
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
|
11
|
+
div.dialog {
|
|
12
|
+
width: 25em;
|
|
13
|
+
padding: 0 4em;
|
|
14
|
+
margin: 4em auto 0 auto;
|
|
15
|
+
border: 1px solid #ccc;
|
|
16
|
+
border-right-color: #999;
|
|
17
|
+
border-bottom-color: #999;
|
|
18
|
+
}
|
|
19
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
|
20
|
+
</style>
|
|
21
|
+
</head>
|
|
22
|
+
|
|
4
23
|
<body>
|
|
5
|
-
|
|
6
|
-
<
|
|
24
|
+
<!-- This file lives in public/500.html -->
|
|
25
|
+
<div class="dialog">
|
|
26
|
+
<h1>We're sorry, but something went wrong.</h1>
|
|
27
|
+
<p>We've been notified about this issue and we'll take a look at it shortly.</p>
|
|
28
|
+
</div>
|
|
7
29
|
</body>
|
|
8
30
|
</html>
|
data/public/dispatch.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
3
|
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
|
|
4
4
|
|
|
@@ -7,4 +7,4 @@ require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_
|
|
|
7
7
|
require "dispatcher"
|
|
8
8
|
|
|
9
9
|
ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
|
|
10
|
-
Dispatcher.dispatch
|
|
10
|
+
Dispatcher.dispatch
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
|
2
|
-
// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
|
|
3
|
-
// (c) 2005 Jon Tirsen (http://www.tirsen.com)
|
|
1
|
+
// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
|
2
|
+
// (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
|
|
3
|
+
// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
|
|
4
4
|
// Contributors:
|
|
5
5
|
// Richard Livsey
|
|
6
6
|
// Rahul Bhargava
|
|
7
7
|
// Rob Wills
|
|
8
8
|
//
|
|
9
|
-
//
|
|
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/
|
|
10
11
|
|
|
11
12
|
// Autocompleter.Base handles all the autocompletion functionality
|
|
12
13
|
// that's independent of the data source for autocompletion. This
|
|
@@ -33,40 +34,50 @@
|
|
|
33
34
|
// useful when one of the tokens is \n (a newline), as it
|
|
34
35
|
// allows smart autocompletion after linebreaks.
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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({
|
|
39
42
|
baseInitialize: function(element, update, options) {
|
|
40
|
-
|
|
43
|
+
element = $(element)
|
|
44
|
+
this.element = element;
|
|
41
45
|
this.update = $(update);
|
|
42
46
|
this.hasFocus = false;
|
|
43
47
|
this.changed = false;
|
|
44
48
|
this.active = false;
|
|
45
49
|
this.index = 0;
|
|
46
50
|
this.entryCount = 0;
|
|
51
|
+
this.oldElementValue = this.element.value;
|
|
47
52
|
|
|
48
|
-
if
|
|
53
|
+
if(this.setOptions)
|
|
49
54
|
this.setOptions(options);
|
|
50
55
|
else
|
|
51
|
-
this.options = options || {};
|
|
56
|
+
this.options = options || { };
|
|
52
57
|
|
|
53
58
|
this.options.paramName = this.options.paramName || this.element.name;
|
|
54
59
|
this.options.tokens = this.options.tokens || [];
|
|
55
60
|
this.options.frequency = this.options.frequency || 0.4;
|
|
56
61
|
this.options.minChars = this.options.minChars || 1;
|
|
57
62
|
this.options.onShow = this.options.onShow ||
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
+
};
|
|
65
73
|
this.options.onHide = this.options.onHide ||
|
|
66
|
-
|
|
74
|
+
function(element, update){ new Effect.Fade(update,{duration:0.15}) };
|
|
67
75
|
|
|
68
|
-
if
|
|
76
|
+
if(typeof(this.options.tokens) == 'string')
|
|
69
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');
|
|
70
81
|
|
|
71
82
|
this.observer = null;
|
|
72
83
|
|
|
@@ -74,15 +85,14 @@ Autocompleter.Base.prototype = {
|
|
|
74
85
|
|
|
75
86
|
Element.hide(this.update);
|
|
76
87
|
|
|
77
|
-
Event.observe(this.element,
|
|
78
|
-
Event.observe(this.element,
|
|
88
|
+
Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
|
|
89
|
+
Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
|
|
79
90
|
},
|
|
80
91
|
|
|
81
92
|
show: function() {
|
|
82
93
|
if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
|
|
83
94
|
if(!this.iefix &&
|
|
84
|
-
(
|
|
85
|
-
(navigator.userAgent.indexOf('Opera')<0) &&
|
|
95
|
+
(Prototype.Browser.IE) &&
|
|
86
96
|
(Element.getStyle(this.update, 'position')=='absolute')) {
|
|
87
97
|
new Insertion.After(this.update,
|
|
88
98
|
'<iframe id="' + this.update.id + '_iefix" '+
|
|
@@ -94,7 +104,7 @@ Autocompleter.Base.prototype = {
|
|
|
94
104
|
},
|
|
95
105
|
|
|
96
106
|
fixIEOverlapping: function() {
|
|
97
|
-
Position.clone(this.update, this.iefix);
|
|
107
|
+
Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
|
|
98
108
|
this.iefix.style.zIndex = 1;
|
|
99
109
|
this.update.style.zIndex = 2;
|
|
100
110
|
Element.show(this.iefix);
|
|
@@ -132,17 +142,17 @@ Autocompleter.Base.prototype = {
|
|
|
132
142
|
case Event.KEY_UP:
|
|
133
143
|
this.markPrevious();
|
|
134
144
|
this.render();
|
|
135
|
-
|
|
145
|
+
Event.stop(event);
|
|
136
146
|
return;
|
|
137
147
|
case Event.KEY_DOWN:
|
|
138
148
|
this.markNext();
|
|
139
149
|
this.render();
|
|
140
|
-
|
|
150
|
+
Event.stop(event);
|
|
141
151
|
return;
|
|
142
152
|
}
|
|
143
153
|
else
|
|
144
|
-
|
|
145
|
-
|
|
154
|
+
if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
|
|
155
|
+
(Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
|
|
146
156
|
|
|
147
157
|
this.changed = true;
|
|
148
158
|
this.hasFocus = true;
|
|
@@ -152,6 +162,12 @@ Autocompleter.Base.prototype = {
|
|
|
152
162
|
setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
|
|
153
163
|
},
|
|
154
164
|
|
|
165
|
+
activate: function() {
|
|
166
|
+
this.changed = false;
|
|
167
|
+
this.hasFocus = true;
|
|
168
|
+
this.getUpdatedChoices();
|
|
169
|
+
},
|
|
170
|
+
|
|
155
171
|
onHover: function(event) {
|
|
156
172
|
var element = Event.findElement(event, 'LI');
|
|
157
173
|
if(this.index != element.autocompleteIndex)
|
|
@@ -182,7 +198,6 @@ Autocompleter.Base.prototype = {
|
|
|
182
198
|
this.index==i ?
|
|
183
199
|
Element.addClassName(this.getEntry(i),"selected") :
|
|
184
200
|
Element.removeClassName(this.getEntry(i),"selected");
|
|
185
|
-
|
|
186
201
|
if(this.hasFocus) {
|
|
187
202
|
this.show();
|
|
188
203
|
this.active = true;
|
|
@@ -196,11 +211,13 @@ Autocompleter.Base.prototype = {
|
|
|
196
211
|
markPrevious: function() {
|
|
197
212
|
if(this.index > 0) this.index--
|
|
198
213
|
else this.index = this.entryCount-1;
|
|
214
|
+
this.getEntry(this.index).scrollIntoView(true);
|
|
199
215
|
},
|
|
200
216
|
|
|
201
217
|
markNext: function() {
|
|
202
218
|
if(this.index < this.entryCount-1) this.index++
|
|
203
219
|
else this.index = 0;
|
|
220
|
+
this.getEntry(this.index).scrollIntoView(false);
|
|
204
221
|
},
|
|
205
222
|
|
|
206
223
|
getEntry: function(index) {
|
|
@@ -221,18 +238,24 @@ Autocompleter.Base.prototype = {
|
|
|
221
238
|
this.options.updateElement(selectedElement);
|
|
222
239
|
return;
|
|
223
240
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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+/);
|
|
230
252
|
if (whitespace)
|
|
231
253
|
newValue += whitespace[0];
|
|
232
|
-
this.element.value = newValue + value;
|
|
254
|
+
this.element.value = newValue + value + this.element.value.substr(bounds[1]);
|
|
233
255
|
} else {
|
|
234
256
|
this.element.value = value;
|
|
235
257
|
}
|
|
258
|
+
this.oldElementValue = this.element.value;
|
|
236
259
|
this.element.focus();
|
|
237
260
|
|
|
238
261
|
if (this.options.afterUpdateElement)
|
|
@@ -243,11 +266,11 @@ Autocompleter.Base.prototype = {
|
|
|
243
266
|
if(!this.changed && this.hasFocus) {
|
|
244
267
|
this.update.innerHTML = choices;
|
|
245
268
|
Element.cleanWhitespace(this.update);
|
|
246
|
-
Element.cleanWhitespace(this.update.
|
|
269
|
+
Element.cleanWhitespace(this.update.down());
|
|
247
270
|
|
|
248
|
-
if(this.update.firstChild && this.update.
|
|
271
|
+
if(this.update.firstChild && this.update.down().childNodes) {
|
|
249
272
|
this.entryCount =
|
|
250
|
-
this.update.
|
|
273
|
+
this.update.down().childNodes.length;
|
|
251
274
|
for (var i = 0; i < this.entryCount; i++) {
|
|
252
275
|
var entry = this.getEntry(i);
|
|
253
276
|
entry.autocompleteIndex = i;
|
|
@@ -258,9 +281,14 @@ Autocompleter.Base.prototype = {
|
|
|
258
281
|
}
|
|
259
282
|
|
|
260
283
|
this.stopIndicator();
|
|
261
|
-
|
|
262
284
|
this.index = 0;
|
|
263
|
-
|
|
285
|
+
|
|
286
|
+
if(this.entryCount==1 && this.options.autoSelect) {
|
|
287
|
+
this.selectEntry();
|
|
288
|
+
this.hide();
|
|
289
|
+
} else {
|
|
290
|
+
this.render();
|
|
291
|
+
}
|
|
264
292
|
}
|
|
265
293
|
},
|
|
266
294
|
|
|
@@ -271,41 +299,50 @@ Autocompleter.Base.prototype = {
|
|
|
271
299
|
|
|
272
300
|
onObserverEvent: function() {
|
|
273
301
|
this.changed = false;
|
|
302
|
+
this.tokenBounds = null;
|
|
274
303
|
if(this.getToken().length>=this.options.minChars) {
|
|
275
|
-
this.startIndicator();
|
|
276
304
|
this.getUpdatedChoices();
|
|
277
305
|
} else {
|
|
278
306
|
this.active = false;
|
|
279
307
|
this.hide();
|
|
280
308
|
}
|
|
309
|
+
this.oldElementValue = this.element.value;
|
|
281
310
|
},
|
|
282
311
|
|
|
283
312
|
getToken: function() {
|
|
284
|
-
var
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
var
|
|
295
|
-
|
|
296
|
-
for (var
|
|
297
|
-
|
|
298
|
-
if (
|
|
299
|
-
|
|
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;
|
|
300
330
|
}
|
|
301
|
-
return
|
|
331
|
+
return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
|
|
302
332
|
}
|
|
303
|
-
}
|
|
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
|
+
};
|
|
304
342
|
|
|
305
|
-
Ajax.Autocompleter = Class.create(
|
|
306
|
-
Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
|
|
343
|
+
Ajax.Autocompleter = Class.create(Autocompleter.Base, {
|
|
307
344
|
initialize: function(element, update, url, options) {
|
|
308
|
-
|
|
345
|
+
this.baseInitialize(element, update, options);
|
|
309
346
|
this.options.asynchronous = true;
|
|
310
347
|
this.options.onComplete = this.onComplete.bind(this);
|
|
311
348
|
this.options.defaultParams = this.options.parameters || null;
|
|
@@ -313,7 +350,9 @@ Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.pro
|
|
|
313
350
|
},
|
|
314
351
|
|
|
315
352
|
getUpdatedChoices: function() {
|
|
316
|
-
|
|
353
|
+
this.startIndicator();
|
|
354
|
+
|
|
355
|
+
var entry = encodeURIComponent(this.options.paramName) + '=' +
|
|
317
356
|
encodeURIComponent(this.getToken());
|
|
318
357
|
|
|
319
358
|
this.options.parameters = this.options.callback ?
|
|
@@ -321,14 +360,13 @@ Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.pro
|
|
|
321
360
|
|
|
322
361
|
if(this.options.defaultParams)
|
|
323
362
|
this.options.parameters += '&' + this.options.defaultParams;
|
|
324
|
-
|
|
363
|
+
|
|
325
364
|
new Ajax.Request(this.url, this.options);
|
|
326
365
|
},
|
|
327
366
|
|
|
328
367
|
onComplete: function(request) {
|
|
329
368
|
this.updateChoices(request.responseText);
|
|
330
369
|
}
|
|
331
|
-
|
|
332
370
|
});
|
|
333
371
|
|
|
334
372
|
// The local array autocompleter. Used when you'd prefer to
|
|
@@ -366,8 +404,7 @@ Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.pro
|
|
|
366
404
|
// In that case, the other options above will not apply unless
|
|
367
405
|
// you support them.
|
|
368
406
|
|
|
369
|
-
Autocompleter.Local = Class.create(
|
|
370
|
-
Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
|
|
407
|
+
Autocompleter.Local = Class.create(Autocompleter.Base, {
|
|
371
408
|
initialize: function(element, update, array, options) {
|
|
372
409
|
this.baseInitialize(element, update, options);
|
|
373
410
|
this.options.array = array;
|
|
@@ -423,13 +460,12 @@ Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
|
|
|
423
460
|
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
|
|
424
461
|
return "<ul>" + ret.join('') + "</ul>";
|
|
425
462
|
}
|
|
426
|
-
}, options || {});
|
|
463
|
+
}, options || { });
|
|
427
464
|
}
|
|
428
465
|
});
|
|
429
466
|
|
|
430
|
-
// AJAX in-place editor
|
|
431
|
-
//
|
|
432
|
-
// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
|
|
467
|
+
// AJAX in-place editor and collection editor
|
|
468
|
+
// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).
|
|
433
469
|
|
|
434
470
|
// Use this if you notice weird scrolling problems on some browsers,
|
|
435
471
|
// the DOM might be a bit confused when this gets called so do this
|
|
@@ -440,295 +476,472 @@ Field.scrollFreeActivate = function(field) {
|
|
|
440
476
|
}, 1);
|
|
441
477
|
}
|
|
442
478
|
|
|
443
|
-
Ajax.InPlaceEditor = Class.create(
|
|
444
|
-
Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
|
|
445
|
-
Ajax.InPlaceEditor.prototype = {
|
|
479
|
+
Ajax.InPlaceEditor = Class.create({
|
|
446
480
|
initialize: function(element, url, options) {
|
|
447
481
|
this.url = url;
|
|
448
|
-
this.element = $(element);
|
|
449
|
-
|
|
450
|
-
this.
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
onComplete: function(transport, element) {
|
|
458
|
-
new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
|
|
459
|
-
},
|
|
460
|
-
onFailure: function(transport) {
|
|
461
|
-
alert("Error communicating with the server: " + transport.responseText.stripTags());
|
|
462
|
-
},
|
|
463
|
-
callback: function(form) {
|
|
464
|
-
return Form.serialize(form);
|
|
465
|
-
},
|
|
466
|
-
handleLineBreaks: true,
|
|
467
|
-
loadingText: 'Loading...',
|
|
468
|
-
savingClassName: 'inplaceeditor-saving',
|
|
469
|
-
loadingClassName: 'inplaceeditor-loading',
|
|
470
|
-
formClassName: 'inplaceeditor-form',
|
|
471
|
-
highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
|
|
472
|
-
highlightendcolor: "#FFFFFF",
|
|
473
|
-
externalControl: null,
|
|
474
|
-
ajaxOptions: {}
|
|
475
|
-
}, options || {});
|
|
476
|
-
|
|
477
|
-
if(!this.options.formId && this.element.id) {
|
|
478
|
-
this.options.formId = this.element.id + "-inplaceeditor";
|
|
479
|
-
if ($(this.options.formId)) {
|
|
480
|
-
// there's already a form with that name, don't specify an id
|
|
481
|
-
this.options.formId = null;
|
|
482
|
-
}
|
|
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 = '';
|
|
483
491
|
}
|
|
484
|
-
|
|
485
|
-
if (this.options.externalControl) {
|
|
492
|
+
if (this.options.externalControl)
|
|
486
493
|
this.options.externalControl = $(this.options.externalControl);
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
this.
|
|
490
|
-
if (!this.originalBackground) {
|
|
491
|
-
this.originalBackground = "transparent";
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
+
if (!this.options.externalControl)
|
|
495
|
+
this.options.externalControlOnly = false;
|
|
496
|
+
this._originalBackground = this.element.getStyle('background-color') || 'transparent';
|
|
494
497
|
this.element.title = this.options.clickToEditText;
|
|
495
|
-
|
|
496
|
-
this.
|
|
497
|
-
this.
|
|
498
|
-
this.
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
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;
|
|
506
534
|
}
|
|
507
535
|
},
|
|
508
|
-
enterEditMode: function(evt) {
|
|
509
|
-
if (this.saving) return;
|
|
510
|
-
if (this.editing) return;
|
|
511
|
-
this.editing = true;
|
|
512
|
-
this.onEnterEditMode();
|
|
513
|
-
if (this.options.externalControl) {
|
|
514
|
-
Element.hide(this.options.externalControl);
|
|
515
|
-
}
|
|
516
|
-
Element.hide(this.element);
|
|
517
|
-
this.createForm();
|
|
518
|
-
this.element.parentNode.insertBefore(this.form, this.element);
|
|
519
|
-
Field.scrollFreeActivate(this.editField);
|
|
520
|
-
// stop the event to avoid a page refresh in Safari
|
|
521
|
-
if (evt) {
|
|
522
|
-
Event.stop(evt);
|
|
523
|
-
}
|
|
524
|
-
return false;
|
|
525
|
-
},
|
|
526
|
-
createForm: function() {
|
|
527
|
-
this.form = document.createElement("form");
|
|
528
|
-
this.form.id = this.options.formId;
|
|
529
|
-
Element.addClassName(this.form, this.options.formClassName)
|
|
530
|
-
this.form.onsubmit = this.onSubmit.bind(this);
|
|
531
|
-
|
|
532
|
-
this.createEditField();
|
|
533
|
-
|
|
534
|
-
if (this.options.textarea) {
|
|
535
|
-
var br = document.createElement("br");
|
|
536
|
-
this.form.appendChild(br);
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
okButton = document.createElement("input");
|
|
540
|
-
okButton.type = "submit";
|
|
541
|
-
okButton.value = this.options.okText;
|
|
542
|
-
this.form.appendChild(okButton);
|
|
543
|
-
|
|
544
|
-
cancelLink = document.createElement("a");
|
|
545
|
-
cancelLink.href = "#";
|
|
546
|
-
cancelLink.appendChild(document.createTextNode(this.options.cancelText));
|
|
547
|
-
cancelLink.onclick = this.onclickCancel.bind(this);
|
|
548
|
-
this.form.appendChild(cancelLink);
|
|
549
|
-
},
|
|
550
|
-
hasHTMLLineBreaks: function(string) {
|
|
551
|
-
if (!this.options.handleLineBreaks) return false;
|
|
552
|
-
return string.match(/<br/i) || string.match(/<p>/i);
|
|
553
|
-
},
|
|
554
|
-
convertHTMLLineBreaks: function(string) {
|
|
555
|
-
return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
|
|
556
|
-
},
|
|
557
536
|
createEditField: function() {
|
|
558
|
-
var text;
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
|
|
566
|
-
this.options.textarea = false;
|
|
567
|
-
var textField = document.createElement("input");
|
|
568
|
-
textField.type = "text";
|
|
569
|
-
textField.name = "value";
|
|
570
|
-
textField.value = text;
|
|
571
|
-
textField.style.backgroundColor = this.options.highlightcolor;
|
|
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';
|
|
572
542
|
var size = this.options.size || this.options.cols || 0;
|
|
573
|
-
if (
|
|
574
|
-
this.editField = textField;
|
|
543
|
+
if (0 < size) fld.size = size;
|
|
575
544
|
} else {
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
textArea.value = this.convertHTMLLineBreaks(text);
|
|
580
|
-
textArea.rows = this.options.rows;
|
|
581
|
-
textArea.cols = this.options.cols || 40;
|
|
582
|
-
this.editField = textArea;
|
|
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;
|
|
583
548
|
}
|
|
584
|
-
|
|
585
|
-
|
|
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)
|
|
586
556
|
this.loadExternalText();
|
|
587
|
-
|
|
588
|
-
|
|
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');
|
|
589
605
|
},
|
|
590
606
|
getText: function() {
|
|
591
607
|
return this.element.innerHTML;
|
|
592
608
|
},
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
this.
|
|
596
|
-
|
|
597
|
-
this.
|
|
598
|
-
Object.extend({
|
|
599
|
-
asynchronous: true,
|
|
600
|
-
onComplete: this.onLoadedExternalText.bind(this)
|
|
601
|
-
}, this.options.ajaxOptions)
|
|
602
|
-
);
|
|
603
|
-
},
|
|
604
|
-
onLoadedExternalText: function(transport) {
|
|
605
|
-
Element.removeClassName(this.form, this.options.loadingClassName);
|
|
606
|
-
this.editField.disabled = false;
|
|
607
|
-
this.editField.value = transport.responseText.stripTags();
|
|
608
|
-
},
|
|
609
|
-
onclickCancel: function() {
|
|
610
|
-
this.onComplete();
|
|
611
|
-
this.leaveEditMode();
|
|
612
|
-
return false;
|
|
613
|
-
},
|
|
614
|
-
onFailure: function(transport) {
|
|
615
|
-
this.options.onFailure(transport);
|
|
616
|
-
if (this.oldInnerHTML) {
|
|
617
|
-
this.element.innerHTML = this.oldInnerHTML;
|
|
618
|
-
this.oldInnerHTML = null;
|
|
609
|
+
handleAJAXFailure: function(transport) {
|
|
610
|
+
this.triggerCallback('onFailure', transport);
|
|
611
|
+
if (this._oldInnerHTML) {
|
|
612
|
+
this.element.innerHTML = this._oldInnerHTML;
|
|
613
|
+
this._oldInnerHTML = null;
|
|
619
614
|
}
|
|
620
|
-
return false;
|
|
621
615
|
},
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
this.
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
}, this.options.ajaxOptions)
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
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);
|
|
648
644
|
}
|
|
649
|
-
|
|
645
|
+
if (e) Event.stop(e);
|
|
650
646
|
},
|
|
651
|
-
|
|
652
|
-
this.
|
|
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;
|
|
653
700
|
this.removeForm();
|
|
654
701
|
this.leaveHover();
|
|
655
702
|
this.showSaving();
|
|
656
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
|
+
},
|
|
657
722
|
showSaving: function() {
|
|
658
|
-
this.
|
|
723
|
+
this._oldInnerHTML = this.element.innerHTML;
|
|
659
724
|
this.element.innerHTML = this.options.savingText;
|
|
660
|
-
|
|
661
|
-
this.element.style.backgroundColor = this.
|
|
662
|
-
|
|
725
|
+
this.element.addClassName(this.options.savingClassName);
|
|
726
|
+
this.element.style.backgroundColor = this._originalBackground;
|
|
727
|
+
this.element.show();
|
|
663
728
|
},
|
|
664
|
-
|
|
665
|
-
if(this.
|
|
666
|
-
|
|
667
|
-
this.form = null;
|
|
729
|
+
triggerCallback: function(cbName, arg) {
|
|
730
|
+
if ('function' == typeof this.options[cbName]) {
|
|
731
|
+
this.options[cbName](this, arg);
|
|
668
732
|
}
|
|
669
733
|
},
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
this.
|
|
675
|
-
|
|
676
|
-
|
|
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));
|
|
677
741
|
},
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
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
|
|
688
788
|
});
|
|
789
|
+
new Ajax.Request(this.options.loadCollectionURL, options);
|
|
689
790
|
},
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
this.
|
|
693
|
-
this.
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
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;
|
|
698
800
|
}
|
|
699
|
-
|
|
700
|
-
this.saving = false;
|
|
701
|
-
this.oldInnerHTML = null;
|
|
702
|
-
this.onLeaveEditMode();
|
|
801
|
+
tempOption.update((text || '').stripScripts().stripTags());
|
|
703
802
|
},
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
this.
|
|
803
|
+
|
|
804
|
+
checkForExternalText: function() {
|
|
805
|
+
this._text = this.getText();
|
|
806
|
+
if (this.options.loadTextURL)
|
|
807
|
+
this.loadExternalText();
|
|
808
|
+
else
|
|
809
|
+
this.buildOptionList();
|
|
707
810
|
},
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
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
|
+
});
|
|
722
926
|
}
|
|
927
|
+
},
|
|
928
|
+
Listeners: {
|
|
929
|
+
click: 'enterEditMode',
|
|
930
|
+
keydown: 'checkForEscapeOrReturn',
|
|
931
|
+
mouseover: 'enterHover',
|
|
932
|
+
mouseout: 'leaveHover'
|
|
723
933
|
}
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
Ajax.InPlaceCollectionEditor.DefaultOptions = {
|
|
937
|
+
loadingCollectionText: 'Loading options...'
|
|
724
938
|
};
|
|
725
939
|
|
|
726
940
|
// Delayed observer, like Form.Element.Observer,
|
|
727
941
|
// but waits for delay after last key input
|
|
728
942
|
// Ideal for live-search fields
|
|
729
943
|
|
|
730
|
-
Form.Element.DelayedObserver = Class.create(
|
|
731
|
-
Form.Element.DelayedObserver.prototype = {
|
|
944
|
+
Form.Element.DelayedObserver = Class.create({
|
|
732
945
|
initialize: function(element, delay, callback) {
|
|
733
946
|
this.delay = delay || 0.5;
|
|
734
947
|
this.element = $(element);
|
|
@@ -747,4 +960,4 @@ Form.Element.DelayedObserver.prototype = {
|
|
|
747
960
|
this.timer = null;
|
|
748
961
|
this.callback(this.element, $F(this.element));
|
|
749
962
|
}
|
|
750
|
-
};
|
|
963
|
+
});
|