cells 3.8.6 → 3.8.7

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.
@@ -4,12 +4,12 @@ module ApplicationTests
4
4
  class RouterTest < ActionController::TestCase
5
5
  tests MusicianController
6
6
 
7
- context "A Rails app" do
8
- should "pass url_helpers to the cell instance" do
7
+ describe "A Rails app" do
8
+ it "pass url_helpers to the cell instance" do
9
9
  assert_equal "/musicians", BassistCell.new(@controller).musicians_path
10
10
  end
11
11
 
12
- should "allow cells to use url_helpers" do
12
+ it "allow cells to use url_helpers" do
13
13
  BassistCell.class_eval do
14
14
  def promote; render; end
15
15
  end
@@ -19,7 +19,7 @@ module ApplicationTests
19
19
  assert_equal "Find me at <a href=\"/musicians\">vd.com</a>\n", @response.body
20
20
  end
21
21
 
22
- should "delegate #url_options to the parent_controller" do
22
+ it "delegate #url_options to the parent_controller" do
23
23
  @controller.instance_eval do
24
24
  def default_url_options
25
25
  {:host => "cells.rails.org"}
@@ -30,13 +30,13 @@ module ApplicationTests
30
30
  assert_equal "http://cells.rails.org/musicians", BassistCell.new(@controller).musicians_url
31
31
  end
32
32
 
33
- should "allow cells to use *_url helpers when mixing in AC::UrlFor" do
33
+ it "allow cells to use *_url helpers when mixing in AC::UrlFor" do
34
34
  get "promote"
35
35
  assert_response :success
36
36
  assert_equal "Find me at <a href=\"http://test.host/musicians\">vd.com</a>\n", @response.body
37
37
  end
38
38
 
39
- should "allow cells to use #config" do
39
+ it "allow cells to use #config" do
40
40
  BassistCell.class_eval do
41
41
  def provoke; render; end
42
42
  end
@@ -1,25 +1,25 @@
1
1
  require 'test_helper'
2
2
 
3
- class RailsViewTest < ActiveSupport::TestCase
3
+ class RailsViewTest < MiniTest::Spec
4
4
  include Cell::TestCase::TestMethods
5
5
 
6
- context "A cell view" do
7
- # DISCUSS: should we allow :partial from a state, too?
8
- context "calling render :partial" do
9
- should "render the local cell partial in bassist/dii" do
6
+ describe "A cell view" do
7
+ # DISCUSS: it we allow :partial from a state, too?
8
+ describe "calling render :partial" do
9
+ it "render the local cell partial in bassist/dii" do
10
10
  assert_equal("Dii", in_view(:bassist) do
11
11
  render :partial => 'dii'
12
12
  end)
13
13
  end
14
14
 
15
- should "render the foreign cell partial in bad_guitarist/dii" do
15
+ it "render the foreign cell partial in bad_guitarist/dii" do
16
16
  assert_equal("Dooom", in_view(:bassist) do
17
17
  render :partial => "bad_guitarist/dii"
18
18
  end)
19
19
  end
20
20
 
21
21
 
22
- should "render the global partial app/views/shared/dong" do
22
+ it "render the global partial app/views/shared/dong" do
23
23
  class PercussionistCell < BassistCell
24
24
  append_view_path("test/app/views")
25
25
  end
@@ -29,13 +29,13 @@ class RailsViewTest < ActiveSupport::TestCase
29
29
  end
30
30
  end
31
31
 
32
- should "respond to render :state" do
32
+ it "respond to render :state" do
33
33
  assert_equal("Doo", in_view(:bassist) do
34
34
  render :state => :play
35
35
  end)
36
36
  end
37
37
 
38
- should "respond to render :state with options" do
38
+ it "respond to render :state with options" do
39
39
  BassistCell.class_eval do
40
40
  def listen(*args)
41
41
  render :text => "Listening to #{args.join(' ')}"
@@ -21,7 +21,7 @@ class RailsHelperAPITest < MiniTest::Spec
21
21
  end
22
22
 
23
23
 
24
- class FakeUrlFor # should be sinatra's url helper instance
24
+ class FakeUrlFor # it be sinatra's url helper instance
25
25
  def url_for(*)
26
26
  end
27
27
  end
@@ -3,8 +3,8 @@ require 'test_helper'
3
3
  class TestCaseTest < Cell::TestCase
4
4
  include ActiveSupport::Testing::Deprecation
5
5
 
6
- context "A TestCase" do
7
- setup do
6
+ describe "A TestCase" do
7
+ before do
8
8
  @test = Cell::TestCase.new(:cell_test)
9
9
 
10
10
  BassistCell.class_eval do
@@ -12,49 +12,49 @@ class TestCaseTest < Cell::TestCase
12
12
  end
13
13
  end
14
14
 
15
- context "#render_cell" do
16
- should "invokes the state" do
15
+ describe "#render_cell" do
16
+ it "invokes the state" do
17
17
  assert_equal "Doo", render_cell(:bassist, :play)
18
18
  end
19
19
 
20
- should "accept state args" do
20
+ it "accept state args" do
21
21
  assert_equal "*shouts* Listen!\n", render_cell(:bassist, :shout, :words => "Listen!")
22
22
  end
23
23
  end
24
24
 
25
- should "respond to #assert_selector with 3 args" do
25
+ it "respond to #assert_selector with 3 args" do
26
26
  assert_selector "p", "Doo", "<p>Doo</p>y"
27
27
  end
28
28
 
29
- context "#cell" do
30
- should "create a cell" do
29
+ describe "#cell" do
30
+ it "create a cell" do
31
31
  assert_kind_of BassistCell, cell(:bassist)
32
32
  end
33
33
 
34
- should "accept a block" do
34
+ it "accept a block" do
35
35
  assert_respond_to cell(:bassist){ def whatever; end }, :whatever
36
36
  end
37
37
  end
38
38
 
39
- context "#subject_cell" do
40
- should "return the last rendered cell" do
39
+ describe "#subject_cell" do
40
+ it "return the last rendered cell" do
41
41
  render_cell(:bassist, :play)
42
42
  assert_kind_of BassistCell, subject_cell
43
43
  end
44
44
  end
45
45
 
46
46
 
47
- context "#view_assigns" do
48
- should "be emtpy when nothing was set" do
47
+ describe "#view_assigns" do
48
+ it "be emtpy when nothing was set" do
49
49
  render_cell(:bassist, :play)
50
50
  if Cell.rails3_0?
51
- assert_equal([:lookup_context], view_assigns.keys)
51
+ assert_equal([:lookup_describe], view_assigns.keys)
52
52
  else
53
53
  assert_equal({}, view_assigns)
54
54
  end
55
55
  end
56
56
 
57
- should "return the instance variables from the last #render_cell" do
57
+ it "return the instance variables from the last #render_cell" do
58
58
  BassistCell.class_eval do
59
59
  def sleep
60
60
  @duration = "8h"
@@ -62,7 +62,7 @@ class TestCaseTest < Cell::TestCase
62
62
  end
63
63
  render_cell(:bassist, :sleep)
64
64
  if Cell.rails3_0?
65
- assert_equal([:lookup_context, :duration], view_assigns.keys)
65
+ assert_equal([:lookup_describe, :duration], view_assigns.keys)
66
66
  assert_equal("8h", view_assigns[:duration])
67
67
  else
68
68
  assert_equal({:duration => "8h"}, view_assigns)
@@ -70,13 +70,13 @@ class TestCaseTest < Cell::TestCase
70
70
  end
71
71
  end
72
72
 
73
- context "in declarative tests" do
74
- should "respond to TestCase.tests" do
73
+ describe "in declarative tests" do
74
+ it "respond to TestCase.tests" do
75
75
  self.class.tests BassistCell
76
76
  assert_equal BassistCell, self.class.controller_class
77
77
  end
78
78
 
79
- should "infer the cell name" do
79
+ it "infer the cell name" do
80
80
  class SingerCell < Cell::Rails
81
81
  end
82
82
 
@@ -86,37 +86,37 @@ class TestCaseTest < Cell::TestCase
86
86
  assert_equal SingerCell, SingerCellTest.new(:cell_test).class.controller_class
87
87
  end
88
88
 
89
- context "with #invoke" do
90
- setup do
89
+ describe "with #invoke" do
90
+ before do
91
91
  self.class.tests BassistCell
92
92
  end
93
93
 
94
- should "provide #invoke" do
94
+ it "provide #invoke" do
95
95
  assert_equal "Doo", invoke(:play)
96
96
  end
97
97
 
98
- should "provide #last_invoke" do
98
+ it "provide #last_invoke" do
99
99
  assert_equal nil, last_invoke
100
100
  assert_equal "Doo", invoke(:play)
101
101
  assert_equal "Doo", last_invoke
102
102
  end
103
103
 
104
- should "provide #invoke accepting options" do
104
+ it "provide #invoke accepting options" do
105
105
  #assert_equal "Doo", invoke(:play)
106
106
  end
107
107
 
108
- should "provide #invoke accepting args" do
108
+ it "provide #invoke accepting args" do
109
109
  assert_equal "*shouts* Listen!\n", invoke(:shout, :words => "Listen!")
110
110
  end
111
111
 
112
- should "provide assert_select" do
112
+ it "provide assert_select" do
113
113
  invoke :promote
114
114
  assert_select "a", "vd.com"
115
115
  end
116
116
  end
117
117
 
118
- context "#setup_test_states_in" do
119
- should "add the :in_view state" do
118
+ describe "#before_test_states_in" do
119
+ it "add the :in_view state" do
120
120
  c = cell(:bassist)
121
121
  assert_not c.respond_to?(:in_view)
122
122
 
@@ -125,8 +125,8 @@ class TestCaseTest < Cell::TestCase
125
125
  end
126
126
  end
127
127
 
128
- context "#in_view" do
129
- should "execute the block in a real view" do
128
+ describe "#in_view" do
129
+ it "execute the block in a real view" do
130
130
  content = "Cells rule."
131
131
  @test.setup
132
132
  assert_equal("<h1>Cells rule.</h1>", @test.in_view(:bassist) do content_tag("h1", content) end)
data/test/test_helper.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # encoding: utf-8
2
2
  require 'rubygems'
3
- require 'test/unit'
4
- require 'shoulda'
5
3
  require 'minitest/spec'
6
4
 
7
5
  ENV['RAILS_ENV'] = 'test'
@@ -18,7 +16,7 @@ Cell::Rails.append_view_path(File.join(test_app_dir, 'cells'))
18
16
 
19
17
  require "cell/test_case"
20
18
  # Extend TestCase.
21
- ActiveSupport::TestCase.class_eval do
19
+ MiniTest::Spec.class_eval do
22
20
  def assert_not(assertion)
23
21
  assert !assertion
24
22
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cells
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.8.6
4
+ version: 3.8.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,14 +9,14 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-07 00:00:00.000000000 Z
12
+ date: 2013-01-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
- - - ~>
19
+ - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
21
  version: '3.0'
22
22
  type: :runtime
@@ -24,7 +24,7 @@ dependencies:
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
- - - ~>
27
+ - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: '3.0'
30
30
  - !ruby/object:Gem::Dependency
@@ -32,7 +32,7 @@ dependencies:
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
35
- - - ~>
35
+ - - ! '>='
36
36
  - !ruby/object:Gem::Version
37
37
  version: '3.0'
38
38
  type: :runtime
@@ -40,7 +40,7 @@ dependencies:
40
40
  version_requirements: !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
- - - ~>
43
+ - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '3.0'
46
46
  - !ruby/object:Gem::Dependency
@@ -59,22 +59,6 @@ dependencies:
59
59
  - - ! '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
- - !ruby/object:Gem::Dependency
63
- name: shoulda
64
- requirement: !ruby/object:Gem::Requirement
65
- none: false
66
- requirements:
67
- - - ! '>='
68
- - !ruby/object:Gem::Version
69
- version: '0'
70
- type: :development
71
- prerelease: false
72
- version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
- requirements:
75
- - - ! '>='
76
- - !ruby/object:Gem::Version
77
- version: '0'
78
62
  - !ruby/object:Gem::Dependency
79
63
  name: haml
80
64
  requirement: !ruby/object:Gem::Requirement
@@ -175,7 +159,6 @@ files:
175
159
  - gemfiles/Gemfile.rails3-0
176
160
  - gemfiles/Gemfile.rails3-1
177
161
  - gemfiles/Gemfile.rails3-2
178
- - lib/cell.rb
179
162
  - lib/cell/base.rb
180
163
  - lib/cell/builder.rb
181
164
  - lib/cell/caching.rb
@@ -267,12 +250,6 @@ files:
267
250
  - test/dummy/public/422.html
268
251
  - test/dummy/public/500.html
269
252
  - test/dummy/public/favicon.ico
270
- - test/dummy/public/javascripts/application.js
271
- - test/dummy/public/javascripts/controls.js
272
- - test/dummy/public/javascripts/dragdrop.js
273
- - test/dummy/public/javascripts/effects.js
274
- - test/dummy/public/javascripts/prototype.js
275
- - test/dummy/public/javascripts/rails.js
276
253
  - test/dummy/public/stylesheets/.gitkeep
277
254
  - test/dummy/script/rails
278
255
  - test/helper_test.rb
data/lib/cell.rb DELETED
@@ -1,2 +0,0 @@
1
- module Cell
2
- end
@@ -1,2 +0,0 @@
1
- // Place your application-specific JavaScript functions and classes here
2
- // This file is automatically included by javascript_include_tag :defaults
@@ -1,965 +0,0 @@
1
- // script.aculo.us controls.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
2
-
3
- // Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
4
- // (c) 2005-2009 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
5
- // (c) 2005-2009 Jon Tirsen (http://www.tirsen.com)
6
- // Contributors:
7
- // Richard Livsey
8
- // Rahul Bhargava
9
- // Rob Wills
10
- //
11
- // script.aculo.us is freely distributable under the terms of an MIT-style license.
12
- // For details, see the script.aculo.us web site: http://script.aculo.us/
13
-
14
- // Autocompleter.Base handles all the autocompletion functionality
15
- // that's independent of the data source for autocompletion. This
16
- // includes drawing the autocompletion menu, observing keyboard
17
- // and mouse events, and similar.
18
- //
19
- // Specific autocompleters need to provide, at the very least,
20
- // a getUpdatedChoices function that will be invoked every time
21
- // the text inside the monitored textbox changes. This method
22
- // should get the text for which to provide autocompletion by
23
- // invoking this.getToken(), NOT by directly accessing
24
- // this.element.value. This is to allow incremental tokenized
25
- // autocompletion. Specific auto-completion logic (AJAX, etc)
26
- // belongs in getUpdatedChoices.
27
- //
28
- // Tokenized incremental autocompletion is enabled automatically
29
- // when an autocompleter is instantiated with the 'tokens' option
30
- // in the options parameter, e.g.:
31
- // new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
32
- // will incrementally autocomplete with a comma as the token.
33
- // Additionally, ',' in the above example can be replaced with
34
- // a token array, e.g. { tokens: [',', '\n'] } which
35
- // enables autocompletion on multiple tokens. This is most
36
- // useful when one of the tokens is \n (a newline), as it
37
- // allows smart autocompletion after linebreaks.
38
-
39
- if(typeof Effect == 'undefined')
40
- throw("controls.js requires including script.aculo.us' effects.js library");
41
-
42
- var Autocompleter = { };
43
- Autocompleter.Base = Class.create({
44
- baseInitialize: function(element, update, options) {
45
- element = $(element);
46
- this.element = element;
47
- this.update = $(update);
48
- this.hasFocus = false;
49
- this.changed = false;
50
- this.active = false;
51
- this.index = 0;
52
- this.entryCount = 0;
53
- this.oldElementValue = this.element.value;
54
-
55
- if(this.setOptions)
56
- this.setOptions(options);
57
- else
58
- this.options = options || { };
59
-
60
- this.options.paramName = this.options.paramName || this.element.name;
61
- this.options.tokens = this.options.tokens || [];
62
- this.options.frequency = this.options.frequency || 0.4;
63
- this.options.minChars = this.options.minChars || 1;
64
- this.options.onShow = this.options.onShow ||
65
- function(element, update){
66
- if(!update.style.position || update.style.position=='absolute') {
67
- update.style.position = 'absolute';
68
- Position.clone(element, update, {
69
- setHeight: false,
70
- offsetTop: element.offsetHeight
71
- });
72
- }
73
- Effect.Appear(update,{duration:0.15});
74
- };
75
- this.options.onHide = this.options.onHide ||
76
- function(element, update){ new Effect.Fade(update,{duration:0.15}) };
77
-
78
- if(typeof(this.options.tokens) == 'string')
79
- this.options.tokens = new Array(this.options.tokens);
80
- // Force carriage returns as token delimiters anyway
81
- if (!this.options.tokens.include('\n'))
82
- this.options.tokens.push('\n');
83
-
84
- this.observer = null;
85
-
86
- this.element.setAttribute('autocomplete','off');
87
-
88
- Element.hide(this.update);
89
-
90
- Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
91
- Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
92
- },
93
-
94
- show: function() {
95
- if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
96
- if(!this.iefix &&
97
- (Prototype.Browser.IE) &&
98
- (Element.getStyle(this.update, 'position')=='absolute')) {
99
- new Insertion.After(this.update,
100
- '<iframe id="' + this.update.id + '_iefix" '+
101
- 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
102
- 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
103
- this.iefix = $(this.update.id+'_iefix');
104
- }
105
- if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
106
- },
107
-
108
- fixIEOverlapping: function() {
109
- Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
110
- this.iefix.style.zIndex = 1;
111
- this.update.style.zIndex = 2;
112
- Element.show(this.iefix);
113
- },
114
-
115
- hide: function() {
116
- this.stopIndicator();
117
- if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
118
- if(this.iefix) Element.hide(this.iefix);
119
- },
120
-
121
- startIndicator: function() {
122
- if(this.options.indicator) Element.show(this.options.indicator);
123
- },
124
-
125
- stopIndicator: function() {
126
- if(this.options.indicator) Element.hide(this.options.indicator);
127
- },
128
-
129
- onKeyPress: function(event) {
130
- if(this.active)
131
- switch(event.keyCode) {
132
- case Event.KEY_TAB:
133
- case Event.KEY_RETURN:
134
- this.selectEntry();
135
- Event.stop(event);
136
- case Event.KEY_ESC:
137
- this.hide();
138
- this.active = false;
139
- Event.stop(event);
140
- return;
141
- case Event.KEY_LEFT:
142
- case Event.KEY_RIGHT:
143
- return;
144
- case Event.KEY_UP:
145
- this.markPrevious();
146
- this.render();
147
- Event.stop(event);
148
- return;
149
- case Event.KEY_DOWN:
150
- this.markNext();
151
- this.render();
152
- Event.stop(event);
153
- return;
154
- }
155
- else
156
- if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
157
- (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
158
-
159
- this.changed = true;
160
- this.hasFocus = true;
161
-
162
- if(this.observer) clearTimeout(this.observer);
163
- this.observer =
164
- setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
165
- },
166
-
167
- activate: function() {
168
- this.changed = false;
169
- this.hasFocus = true;
170
- this.getUpdatedChoices();
171
- },
172
-
173
- onHover: function(event) {
174
- var element = Event.findElement(event, 'LI');
175
- if(this.index != element.autocompleteIndex)
176
- {
177
- this.index = element.autocompleteIndex;
178
- this.render();
179
- }
180
- Event.stop(event);
181
- },
182
-
183
- onClick: function(event) {
184
- var element = Event.findElement(event, 'LI');
185
- this.index = element.autocompleteIndex;
186
- this.selectEntry();
187
- this.hide();
188
- },
189
-
190
- onBlur: function(event) {
191
- // needed to make click events working
192
- setTimeout(this.hide.bind(this), 250);
193
- this.hasFocus = false;
194
- this.active = false;
195
- },
196
-
197
- render: function() {
198
- if(this.entryCount > 0) {
199
- for (var i = 0; i < this.entryCount; i++)
200
- this.index==i ?
201
- Element.addClassName(this.getEntry(i),"selected") :
202
- Element.removeClassName(this.getEntry(i),"selected");
203
- if(this.hasFocus) {
204
- this.show();
205
- this.active = true;
206
- }
207
- } else {
208
- this.active = false;
209
- this.hide();
210
- }
211
- },
212
-
213
- markPrevious: function() {
214
- if(this.index > 0) this.index--;
215
- else this.index = this.entryCount-1;
216
- this.getEntry(this.index).scrollIntoView(true);
217
- },
218
-
219
- markNext: function() {
220
- if(this.index < this.entryCount-1) this.index++;
221
- else this.index = 0;
222
- this.getEntry(this.index).scrollIntoView(false);
223
- },
224
-
225
- getEntry: function(index) {
226
- return this.update.firstChild.childNodes[index];
227
- },
228
-
229
- getCurrentEntry: function() {
230
- return this.getEntry(this.index);
231
- },
232
-
233
- selectEntry: function() {
234
- this.active = false;
235
- this.updateElement(this.getCurrentEntry());
236
- },
237
-
238
- updateElement: function(selectedElement) {
239
- if (this.options.updateElement) {
240
- this.options.updateElement(selectedElement);
241
- return;
242
- }
243
- var value = '';
244
- if (this.options.select) {
245
- var nodes = $(selectedElement).select('.' + this.options.select) || [];
246
- if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
247
- } else
248
- value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
249
-
250
- var bounds = this.getTokenBounds();
251
- if (bounds[0] != -1) {
252
- var newValue = this.element.value.substr(0, bounds[0]);
253
- var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
254
- if (whitespace)
255
- newValue += whitespace[0];
256
- this.element.value = newValue + value + this.element.value.substr(bounds[1]);
257
- } else {
258
- this.element.value = value;
259
- }
260
- this.oldElementValue = this.element.value;
261
- this.element.focus();
262
-
263
- if (this.options.afterUpdateElement)
264
- this.options.afterUpdateElement(this.element, selectedElement);
265
- },
266
-
267
- updateChoices: function(choices) {
268
- if(!this.changed && this.hasFocus) {
269
- this.update.innerHTML = choices;
270
- Element.cleanWhitespace(this.update);
271
- Element.cleanWhitespace(this.update.down());
272
-
273
- if(this.update.firstChild && this.update.down().childNodes) {
274
- this.entryCount =
275
- this.update.down().childNodes.length;
276
- for (var i = 0; i < this.entryCount; i++) {
277
- var entry = this.getEntry(i);
278
- entry.autocompleteIndex = i;
279
- this.addObservers(entry);
280
- }
281
- } else {
282
- this.entryCount = 0;
283
- }
284
-
285
- this.stopIndicator();
286
- this.index = 0;
287
-
288
- if(this.entryCount==1 && this.options.autoSelect) {
289
- this.selectEntry();
290
- this.hide();
291
- } else {
292
- this.render();
293
- }
294
- }
295
- },
296
-
297
- addObservers: function(element) {
298
- Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
299
- Event.observe(element, "click", this.onClick.bindAsEventListener(this));
300
- },
301
-
302
- onObserverEvent: function() {
303
- this.changed = false;
304
- this.tokenBounds = null;
305
- if(this.getToken().length>=this.options.minChars) {
306
- this.getUpdatedChoices();
307
- } else {
308
- this.active = false;
309
- this.hide();
310
- }
311
- this.oldElementValue = this.element.value;
312
- },
313
-
314
- getToken: function() {
315
- var bounds = this.getTokenBounds();
316
- return this.element.value.substring(bounds[0], bounds[1]).strip();
317
- },
318
-
319
- getTokenBounds: function() {
320
- if (null != this.tokenBounds) return this.tokenBounds;
321
- var value = this.element.value;
322
- if (value.strip().empty()) return [-1, 0];
323
- var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
324
- var offset = (diff == this.oldElementValue.length ? 1 : 0);
325
- var prevTokenPos = -1, nextTokenPos = value.length;
326
- var tp;
327
- for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
328
- tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
329
- if (tp > prevTokenPos) prevTokenPos = tp;
330
- tp = value.indexOf(this.options.tokens[index], diff + offset);
331
- if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
332
- }
333
- return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
334
- }
335
- });
336
-
337
- Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
338
- var boundary = Math.min(newS.length, oldS.length);
339
- for (var index = 0; index < boundary; ++index)
340
- if (newS[index] != oldS[index])
341
- return index;
342
- return boundary;
343
- };
344
-
345
- Ajax.Autocompleter = Class.create(Autocompleter.Base, {
346
- initialize: function(element, update, url, options) {
347
- this.baseInitialize(element, update, options);
348
- this.options.asynchronous = true;
349
- this.options.onComplete = this.onComplete.bind(this);
350
- this.options.defaultParams = this.options.parameters || null;
351
- this.url = url;
352
- },
353
-
354
- getUpdatedChoices: function() {
355
- this.startIndicator();
356
-
357
- var entry = encodeURIComponent(this.options.paramName) + '=' +
358
- encodeURIComponent(this.getToken());
359
-
360
- this.options.parameters = this.options.callback ?
361
- this.options.callback(this.element, entry) : entry;
362
-
363
- if(this.options.defaultParams)
364
- this.options.parameters += '&' + this.options.defaultParams;
365
-
366
- new Ajax.Request(this.url, this.options);
367
- },
368
-
369
- onComplete: function(request) {
370
- this.updateChoices(request.responseText);
371
- }
372
- });
373
-
374
- // The local array autocompleter. Used when you'd prefer to
375
- // inject an array of autocompletion options into the page, rather
376
- // than sending out Ajax queries, which can be quite slow sometimes.
377
- //
378
- // The constructor takes four parameters. The first two are, as usual,
379
- // the id of the monitored textbox, and id of the autocompletion menu.
380
- // The third is the array you want to autocomplete from, and the fourth
381
- // is the options block.
382
- //
383
- // Extra local autocompletion options:
384
- // - choices - How many autocompletion choices to offer
385
- //
386
- // - partialSearch - If false, the autocompleter will match entered
387
- // text only at the beginning of strings in the
388
- // autocomplete array. Defaults to true, which will
389
- // match text at the beginning of any *word* in the
390
- // strings in the autocomplete array. If you want to
391
- // search anywhere in the string, additionally set
392
- // the option fullSearch to true (default: off).
393
- //
394
- // - fullSsearch - Search anywhere in autocomplete array strings.
395
- //
396
- // - partialChars - How many characters to enter before triggering
397
- // a partial match (unlike minChars, which defines
398
- // how many characters are required to do any match
399
- // at all). Defaults to 2.
400
- //
401
- // - ignoreCase - Whether to ignore case when autocompleting.
402
- // Defaults to true.
403
- //
404
- // It's possible to pass in a custom function as the 'selector'
405
- // option, if you prefer to write your own autocompletion logic.
406
- // In that case, the other options above will not apply unless
407
- // you support them.
408
-
409
- Autocompleter.Local = Class.create(Autocompleter.Base, {
410
- initialize: function(element, update, array, options) {
411
- this.baseInitialize(element, update, options);
412
- this.options.array = array;
413
- },
414
-
415
- getUpdatedChoices: function() {
416
- this.updateChoices(this.options.selector(this));
417
- },
418
-
419
- setOptions: function(options) {
420
- this.options = Object.extend({
421
- choices: 10,
422
- partialSearch: true,
423
- partialChars: 2,
424
- ignoreCase: true,
425
- fullSearch: false,
426
- selector: function(instance) {
427
- var ret = []; // Beginning matches
428
- var partial = []; // Inside matches
429
- var entry = instance.getToken();
430
- var count = 0;
431
-
432
- for (var i = 0; i < instance.options.array.length &&
433
- ret.length < instance.options.choices ; i++) {
434
-
435
- var elem = instance.options.array[i];
436
- var foundPos = instance.options.ignoreCase ?
437
- elem.toLowerCase().indexOf(entry.toLowerCase()) :
438
- elem.indexOf(entry);
439
-
440
- while (foundPos != -1) {
441
- if (foundPos == 0 && elem.length != entry.length) {
442
- ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
443
- elem.substr(entry.length) + "</li>");
444
- break;
445
- } else if (entry.length >= instance.options.partialChars &&
446
- instance.options.partialSearch && foundPos != -1) {
447
- if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
448
- partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
449
- elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
450
- foundPos + entry.length) + "</li>");
451
- break;
452
- }
453
- }
454
-
455
- foundPos = instance.options.ignoreCase ?
456
- elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
457
- elem.indexOf(entry, foundPos + 1);
458
-
459
- }
460
- }
461
- if (partial.length)
462
- ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));
463
- return "<ul>" + ret.join('') + "</ul>";
464
- }
465
- }, options || { });
466
- }
467
- });
468
-
469
- // AJAX in-place editor and collection editor
470
- // Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).
471
-
472
- // Use this if you notice weird scrolling problems on some browsers,
473
- // the DOM might be a bit confused when this gets called so do this
474
- // waits 1 ms (with setTimeout) until it does the activation
475
- Field.scrollFreeActivate = function(field) {
476
- setTimeout(function() {
477
- Field.activate(field);
478
- }, 1);
479
- };
480
-
481
- Ajax.InPlaceEditor = Class.create({
482
- initialize: function(element, url, options) {
483
- this.url = url;
484
- this.element = element = $(element);
485
- this.prepareOptions();
486
- this._controls = { };
487
- arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
488
- Object.extend(this.options, options || { });
489
- if (!this.options.formId && this.element.id) {
490
- this.options.formId = this.element.id + '-inplaceeditor';
491
- if ($(this.options.formId))
492
- this.options.formId = '';
493
- }
494
- if (this.options.externalControl)
495
- this.options.externalControl = $(this.options.externalControl);
496
- if (!this.options.externalControl)
497
- this.options.externalControlOnly = false;
498
- this._originalBackground = this.element.getStyle('background-color') || 'transparent';
499
- this.element.title = this.options.clickToEditText;
500
- this._boundCancelHandler = this.handleFormCancellation.bind(this);
501
- this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
502
- this._boundFailureHandler = this.handleAJAXFailure.bind(this);
503
- this._boundSubmitHandler = this.handleFormSubmission.bind(this);
504
- this._boundWrapperHandler = this.wrapUp.bind(this);
505
- this.registerListeners();
506
- },
507
- checkForEscapeOrReturn: function(e) {
508
- if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
509
- if (Event.KEY_ESC == e.keyCode)
510
- this.handleFormCancellation(e);
511
- else if (Event.KEY_RETURN == e.keyCode)
512
- this.handleFormSubmission(e);
513
- },
514
- createControl: function(mode, handler, extraClasses) {
515
- var control = this.options[mode + 'Control'];
516
- var text = this.options[mode + 'Text'];
517
- if ('button' == control) {
518
- var btn = document.createElement('input');
519
- btn.type = 'submit';
520
- btn.value = text;
521
- btn.className = 'editor_' + mode + '_button';
522
- if ('cancel' == mode)
523
- btn.onclick = this._boundCancelHandler;
524
- this._form.appendChild(btn);
525
- this._controls[mode] = btn;
526
- } else if ('link' == control) {
527
- var link = document.createElement('a');
528
- link.href = '#';
529
- link.appendChild(document.createTextNode(text));
530
- link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
531
- link.className = 'editor_' + mode + '_link';
532
- if (extraClasses)
533
- link.className += ' ' + extraClasses;
534
- this._form.appendChild(link);
535
- this._controls[mode] = link;
536
- }
537
- },
538
- createEditField: function() {
539
- var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
540
- var fld;
541
- if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
542
- fld = document.createElement('input');
543
- fld.type = 'text';
544
- var size = this.options.size || this.options.cols || 0;
545
- if (0 < size) fld.size = size;
546
- } else {
547
- fld = document.createElement('textarea');
548
- fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
549
- fld.cols = this.options.cols || 40;
550
- }
551
- fld.name = this.options.paramName;
552
- fld.value = text; // No HTML breaks conversion anymore
553
- fld.className = 'editor_field';
554
- if (this.options.submitOnBlur)
555
- fld.onblur = this._boundSubmitHandler;
556
- this._controls.editor = fld;
557
- if (this.options.loadTextURL)
558
- this.loadExternalText();
559
- this._form.appendChild(this._controls.editor);
560
- },
561
- createForm: function() {
562
- var ipe = this;
563
- function addText(mode, condition) {
564
- var text = ipe.options['text' + mode + 'Controls'];
565
- if (!text || condition === false) return;
566
- ipe._form.appendChild(document.createTextNode(text));
567
- };
568
- this._form = $(document.createElement('form'));
569
- this._form.id = this.options.formId;
570
- this._form.addClassName(this.options.formClassName);
571
- this._form.onsubmit = this._boundSubmitHandler;
572
- this.createEditField();
573
- if ('textarea' == this._controls.editor.tagName.toLowerCase())
574
- this._form.appendChild(document.createElement('br'));
575
- if (this.options.onFormCustomization)
576
- this.options.onFormCustomization(this, this._form);
577
- addText('Before', this.options.okControl || this.options.cancelControl);
578
- this.createControl('ok', this._boundSubmitHandler);
579
- addText('Between', this.options.okControl && this.options.cancelControl);
580
- this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
581
- addText('After', this.options.okControl || this.options.cancelControl);
582
- },
583
- destroy: function() {
584
- if (this._oldInnerHTML)
585
- this.element.innerHTML = this._oldInnerHTML;
586
- this.leaveEditMode();
587
- this.unregisterListeners();
588
- },
589
- enterEditMode: function(e) {
590
- if (this._saving || this._editing) return;
591
- this._editing = true;
592
- this.triggerCallback('onEnterEditMode');
593
- if (this.options.externalControl)
594
- this.options.externalControl.hide();
595
- this.element.hide();
596
- this.createForm();
597
- this.element.parentNode.insertBefore(this._form, this.element);
598
- if (!this.options.loadTextURL)
599
- this.postProcessEditField();
600
- if (e) Event.stop(e);
601
- },
602
- enterHover: function(e) {
603
- if (this.options.hoverClassName)
604
- this.element.addClassName(this.options.hoverClassName);
605
- if (this._saving) return;
606
- this.triggerCallback('onEnterHover');
607
- },
608
- getText: function() {
609
- return this.element.innerHTML.unescapeHTML();
610
- },
611
- handleAJAXFailure: function(transport) {
612
- this.triggerCallback('onFailure', transport);
613
- if (this._oldInnerHTML) {
614
- this.element.innerHTML = this._oldInnerHTML;
615
- this._oldInnerHTML = null;
616
- }
617
- },
618
- handleFormCancellation: function(e) {
619
- this.wrapUp();
620
- if (e) Event.stop(e);
621
- },
622
- handleFormSubmission: function(e) {
623
- var form = this._form;
624
- var value = $F(this._controls.editor);
625
- this.prepareSubmission();
626
- var params = this.options.callback(form, value) || '';
627
- if (Object.isString(params))
628
- params = params.toQueryParams();
629
- params.editorId = this.element.id;
630
- if (this.options.htmlResponse) {
631
- var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
632
- Object.extend(options, {
633
- parameters: params,
634
- onComplete: this._boundWrapperHandler,
635
- onFailure: this._boundFailureHandler
636
- });
637
- new Ajax.Updater({ success: this.element }, this.url, options);
638
- } else {
639
- var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
640
- Object.extend(options, {
641
- parameters: params,
642
- onComplete: this._boundWrapperHandler,
643
- onFailure: this._boundFailureHandler
644
- });
645
- new Ajax.Request(this.url, options);
646
- }
647
- if (e) Event.stop(e);
648
- },
649
- leaveEditMode: function() {
650
- this.element.removeClassName(this.options.savingClassName);
651
- this.removeForm();
652
- this.leaveHover();
653
- this.element.style.backgroundColor = this._originalBackground;
654
- this.element.show();
655
- if (this.options.externalControl)
656
- this.options.externalControl.show();
657
- this._saving = false;
658
- this._editing = false;
659
- this._oldInnerHTML = null;
660
- this.triggerCallback('onLeaveEditMode');
661
- },
662
- leaveHover: function(e) {
663
- if (this.options.hoverClassName)
664
- this.element.removeClassName(this.options.hoverClassName);
665
- if (this._saving) return;
666
- this.triggerCallback('onLeaveHover');
667
- },
668
- loadExternalText: function() {
669
- this._form.addClassName(this.options.loadingClassName);
670
- this._controls.editor.disabled = true;
671
- var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
672
- Object.extend(options, {
673
- parameters: 'editorId=' + encodeURIComponent(this.element.id),
674
- onComplete: Prototype.emptyFunction,
675
- onSuccess: function(transport) {
676
- this._form.removeClassName(this.options.loadingClassName);
677
- var text = transport.responseText;
678
- if (this.options.stripLoadedTextTags)
679
- text = text.stripTags();
680
- this._controls.editor.value = text;
681
- this._controls.editor.disabled = false;
682
- this.postProcessEditField();
683
- }.bind(this),
684
- onFailure: this._boundFailureHandler
685
- });
686
- new Ajax.Request(this.options.loadTextURL, options);
687
- },
688
- postProcessEditField: function() {
689
- var fpc = this.options.fieldPostCreation;
690
- if (fpc)
691
- $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
692
- },
693
- prepareOptions: function() {
694
- this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
695
- Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
696
- [this._extraDefaultOptions].flatten().compact().each(function(defs) {
697
- Object.extend(this.options, defs);
698
- }.bind(this));
699
- },
700
- prepareSubmission: function() {
701
- this._saving = true;
702
- this.removeForm();
703
- this.leaveHover();
704
- this.showSaving();
705
- },
706
- registerListeners: function() {
707
- this._listeners = { };
708
- var listener;
709
- $H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
710
- listener = this[pair.value].bind(this);
711
- this._listeners[pair.key] = listener;
712
- if (!this.options.externalControlOnly)
713
- this.element.observe(pair.key, listener);
714
- if (this.options.externalControl)
715
- this.options.externalControl.observe(pair.key, listener);
716
- }.bind(this));
717
- },
718
- removeForm: function() {
719
- if (!this._form) return;
720
- this._form.remove();
721
- this._form = null;
722
- this._controls = { };
723
- },
724
- showSaving: function() {
725
- this._oldInnerHTML = this.element.innerHTML;
726
- this.element.innerHTML = this.options.savingText;
727
- this.element.addClassName(this.options.savingClassName);
728
- this.element.style.backgroundColor = this._originalBackground;
729
- this.element.show();
730
- },
731
- triggerCallback: function(cbName, arg) {
732
- if ('function' == typeof this.options[cbName]) {
733
- this.options[cbName](this, arg);
734
- }
735
- },
736
- unregisterListeners: function() {
737
- $H(this._listeners).each(function(pair) {
738
- if (!this.options.externalControlOnly)
739
- this.element.stopObserving(pair.key, pair.value);
740
- if (this.options.externalControl)
741
- this.options.externalControl.stopObserving(pair.key, pair.value);
742
- }.bind(this));
743
- },
744
- wrapUp: function(transport) {
745
- this.leaveEditMode();
746
- // Can't use triggerCallback due to backward compatibility: requires
747
- // binding + direct element
748
- this._boundComplete(transport, this.element);
749
- }
750
- });
751
-
752
- Object.extend(Ajax.InPlaceEditor.prototype, {
753
- dispose: Ajax.InPlaceEditor.prototype.destroy
754
- });
755
-
756
- Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
757
- initialize: function($super, element, url, options) {
758
- this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
759
- $super(element, url, options);
760
- },
761
-
762
- createEditField: function() {
763
- var list = document.createElement('select');
764
- list.name = this.options.paramName;
765
- list.size = 1;
766
- this._controls.editor = list;
767
- this._collection = this.options.collection || [];
768
- if (this.options.loadCollectionURL)
769
- this.loadCollection();
770
- else
771
- this.checkForExternalText();
772
- this._form.appendChild(this._controls.editor);
773
- },
774
-
775
- loadCollection: function() {
776
- this._form.addClassName(this.options.loadingClassName);
777
- this.showLoadingText(this.options.loadingCollectionText);
778
- var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
779
- Object.extend(options, {
780
- parameters: 'editorId=' + encodeURIComponent(this.element.id),
781
- onComplete: Prototype.emptyFunction,
782
- onSuccess: function(transport) {
783
- var js = transport.responseText.strip();
784
- if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
785
- throw('Server returned an invalid collection representation.');
786
- this._collection = eval(js);
787
- this.checkForExternalText();
788
- }.bind(this),
789
- onFailure: this.onFailure
790
- });
791
- new Ajax.Request(this.options.loadCollectionURL, options);
792
- },
793
-
794
- showLoadingText: function(text) {
795
- this._controls.editor.disabled = true;
796
- var tempOption = this._controls.editor.firstChild;
797
- if (!tempOption) {
798
- tempOption = document.createElement('option');
799
- tempOption.value = '';
800
- this._controls.editor.appendChild(tempOption);
801
- tempOption.selected = true;
802
- }
803
- tempOption.update((text || '').stripScripts().stripTags());
804
- },
805
-
806
- checkForExternalText: function() {
807
- this._text = this.getText();
808
- if (this.options.loadTextURL)
809
- this.loadExternalText();
810
- else
811
- this.buildOptionList();
812
- },
813
-
814
- loadExternalText: function() {
815
- this.showLoadingText(this.options.loadingText);
816
- var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
817
- Object.extend(options, {
818
- parameters: 'editorId=' + encodeURIComponent(this.element.id),
819
- onComplete: Prototype.emptyFunction,
820
- onSuccess: function(transport) {
821
- this._text = transport.responseText.strip();
822
- this.buildOptionList();
823
- }.bind(this),
824
- onFailure: this.onFailure
825
- });
826
- new Ajax.Request(this.options.loadTextURL, options);
827
- },
828
-
829
- buildOptionList: function() {
830
- this._form.removeClassName(this.options.loadingClassName);
831
- this._collection = this._collection.map(function(entry) {
832
- return 2 === entry.length ? entry : [entry, entry].flatten();
833
- });
834
- var marker = ('value' in this.options) ? this.options.value : this._text;
835
- var textFound = this._collection.any(function(entry) {
836
- return entry[0] == marker;
837
- }.bind(this));
838
- this._controls.editor.update('');
839
- var option;
840
- this._collection.each(function(entry, index) {
841
- option = document.createElement('option');
842
- option.value = entry[0];
843
- option.selected = textFound ? entry[0] == marker : 0 == index;
844
- option.appendChild(document.createTextNode(entry[1]));
845
- this._controls.editor.appendChild(option);
846
- }.bind(this));
847
- this._controls.editor.disabled = false;
848
- Field.scrollFreeActivate(this._controls.editor);
849
- }
850
- });
851
-
852
- //**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
853
- //**** This only exists for a while, in order to let ****
854
- //**** users adapt to the new API. Read up on the new ****
855
- //**** API and convert your code to it ASAP! ****
856
-
857
- Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
858
- if (!options) return;
859
- function fallback(name, expr) {
860
- if (name in options || expr === undefined) return;
861
- options[name] = expr;
862
- };
863
- fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
864
- options.cancelLink == options.cancelButton == false ? false : undefined)));
865
- fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
866
- options.okLink == options.okButton == false ? false : undefined)));
867
- fallback('highlightColor', options.highlightcolor);
868
- fallback('highlightEndColor', options.highlightendcolor);
869
- };
870
-
871
- Object.extend(Ajax.InPlaceEditor, {
872
- DefaultOptions: {
873
- ajaxOptions: { },
874
- autoRows: 3, // Use when multi-line w/ rows == 1
875
- cancelControl: 'link', // 'link'|'button'|false
876
- cancelText: 'cancel',
877
- clickToEditText: 'Click to edit',
878
- externalControl: null, // id|elt
879
- externalControlOnly: false,
880
- fieldPostCreation: 'activate', // 'activate'|'focus'|false
881
- formClassName: 'inplaceeditor-form',
882
- formId: null, // id|elt
883
- highlightColor: '#ffff99',
884
- highlightEndColor: '#ffffff',
885
- hoverClassName: '',
886
- htmlResponse: true,
887
- loadingClassName: 'inplaceeditor-loading',
888
- loadingText: 'Loading...',
889
- okControl: 'button', // 'link'|'button'|false
890
- okText: 'ok',
891
- paramName: 'value',
892
- rows: 1, // If 1 and multi-line, uses autoRows
893
- savingClassName: 'inplaceeditor-saving',
894
- savingText: 'Saving...',
895
- size: 0,
896
- stripLoadedTextTags: false,
897
- submitOnBlur: false,
898
- textAfterControls: '',
899
- textBeforeControls: '',
900
- textBetweenControls: ''
901
- },
902
- DefaultCallbacks: {
903
- callback: function(form) {
904
- return Form.serialize(form);
905
- },
906
- onComplete: function(transport, element) {
907
- // For backward compatibility, this one is bound to the IPE, and passes
908
- // the element directly. It was too often customized, so we don't break it.
909
- new Effect.Highlight(element, {
910
- startcolor: this.options.highlightColor, keepBackgroundImage: true });
911
- },
912
- onEnterEditMode: null,
913
- onEnterHover: function(ipe) {
914
- ipe.element.style.backgroundColor = ipe.options.highlightColor;
915
- if (ipe._effect)
916
- ipe._effect.cancel();
917
- },
918
- onFailure: function(transport, ipe) {
919
- alert('Error communication with the server: ' + transport.responseText.stripTags());
920
- },
921
- onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
922
- onLeaveEditMode: null,
923
- onLeaveHover: function(ipe) {
924
- ipe._effect = new Effect.Highlight(ipe.element, {
925
- startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
926
- restorecolor: ipe._originalBackground, keepBackgroundImage: true
927
- });
928
- }
929
- },
930
- Listeners: {
931
- click: 'enterEditMode',
932
- keydown: 'checkForEscapeOrReturn',
933
- mouseover: 'enterHover',
934
- mouseout: 'leaveHover'
935
- }
936
- });
937
-
938
- Ajax.InPlaceCollectionEditor.DefaultOptions = {
939
- loadingCollectionText: 'Loading options...'
940
- };
941
-
942
- // Delayed observer, like Form.Element.Observer,
943
- // but waits for delay after last key input
944
- // Ideal for live-search fields
945
-
946
- Form.Element.DelayedObserver = Class.create({
947
- initialize: function(element, delay, callback) {
948
- this.delay = delay || 0.5;
949
- this.element = $(element);
950
- this.callback = callback;
951
- this.timer = null;
952
- this.lastValue = $F(this.element);
953
- Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
954
- },
955
- delayedListener: function(event) {
956
- if(this.lastValue == $F(this.element)) return;
957
- if(this.timer) clearTimeout(this.timer);
958
- this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
959
- this.lastValue = $F(this.element);
960
- },
961
- onTimerEvent: function() {
962
- this.timer = null;
963
- this.callback(this.element, $F(this.element));
964
- }
965
- });