best_in_place 1.0.6 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md ADDED
@@ -0,0 +1,36 @@
1
+ #Changelog
2
+
3
+ ##Master branch (and part of the Rails 3.0 branch)
4
+ - v.0.1.0 Initial commit
5
+ - v.0.1.2 Fixing errors in collections (taken value[0] instead of index) and fixing test_app controller responses
6
+ - v.0.1.3 Bug in Rails Helper. Key wrongly considered an Integer.
7
+ - v.0.1.4 Adding two new parameters for further customization urlObject and nilValue and making input update on blur.
8
+ - v.0.1.5 **Attention: this release is not backwards compatible**. Changing params from list to option hash, helper's refactoring,
9
+ fixing bug with objects inside namespaces, adding feature for passing an external activator handler as param. Adding feature
10
+ of key ESCAPE for destroying changes before they are made permanent (in inputs and textarea).
11
+ - v.0.1.6-0.1.7 Avoiding request when the input is not modified and allowing the user to not sanitize input data.
12
+ - v.0.1.8 jslint compliant, sanitizing tags in the gem, getting right csrf params, controlling size of textarea (elastic script, for autogrowing textarea)
13
+ - v.0.1.9 Adding elastic autogrowing textareas
14
+ - v.1.0.0 Setting RSpec and Capybara up, and adding some utilities. Mantaining some HTML attributes. Fix a respond_with bug (thanks, @moabite). Triggering ajax:success when ajax call is complete (thanks, @indrekj). Setting up Travis CI. Updated for Rails 3.1.
15
+ - v.1.0.1 Fixing a double initialization bug
16
+ - v.1.0.2 New bip_area text helper to work with text areas.
17
+ - v.1.0.3 replace apostrophes in collection with corresponding HTML entity,
18
+ thanks @taavo. Implemented `:display_as` option and adding
19
+ `respond_with_bip` to be used in the controller.
20
+ - v.1.0.4 Depend on ActiveModel instead of ActiveRecord (thanks,
21
+ @skinnyfit). Added date type (thanks @taavo). Added new feature:
22
+ display_with.
23
+ - v.1.0.5 Fix a bug involving quotes (thanks @ygoldshtrakh). Minor fixes
24
+ by @bfalling. Add object name option (thanks @nicholassm). Check
25
+ version of Rails before booting. Minor fixes.
26
+ - v.1.0.6 Fix issue with display_with. Update test_app to 3.2.
27
+ - v.1.1.0 Changed $ by jQuery for compatibility (thanks @tschmitz), new
28
+ events for 'deactivate' (thanks @glebtv), added new 'data' attribute
29
+ to BIP's span (thanks @straydogstudio), works with dynamically added
30
+ elements to the page (thanks @enriclluelles), added object detection to
31
+ the 'path' parameter and some more bugfixes.
32
+
33
+ ##Rails 3.0 branch only
34
+ - v.0.2.0 Added RSpec and Capybara setup, and some tests. Fix countries map syntax, Allowing href and some other HTML attributes. Adding Travis CI too. Added the best_in_place_if option. Added ajax:success trigger, thanks to @indrekj.
35
+ - v.0.2.1 Fixing double initialization bug.
36
+ - v.0.2.2 New bip_area text helper.
data/README.md CHANGED
@@ -45,7 +45,7 @@ Params:
45
45
 
46
46
  Options:
47
47
 
48
- - **:type** It can be only [:input, :textarea, :select, :checkbox, :date] or if undefined it defaults to :input.
48
+ - **:type** It can be only [:input, :textarea, :select, :checkbox, :date (>= 1.0.4)] or if undefined it defaults to :input.
49
49
  - **:collection**: In case you are using the :select type then you must specify the collection of values it takes. In case you are
50
50
  using the :checkbox type you can specify the two values it can take, or otherwise they will default to Yes and No.
51
51
  - **:path**: URL to which the updating action will be sent. If not defined it defaults to the :object path.
@@ -60,6 +60,7 @@ Options:
60
60
  - **:display_as**: A model method which will be called in order to display
61
61
  this field.
62
62
  - **:object_name**: Used for overriding the default params key used for the object (the data-object attribute). Useful for e.g. STI scenarios where best_in_place should post to a common controller for different models.
63
+ - **:data**: Hash of custom data attributes to be added to span. Can be used to provide data to the ajax:success callback.
63
64
 
64
65
  ###best_in_place_if
65
66
  **best_in_place_if condition, object, field, OPTIONS**
@@ -176,6 +177,27 @@ additional `helper_options` hash:
176
177
 
177
178
  = best_in_place @user, :money, :display_with => :number_to_currency, :helper_options => {:unit => "€"}
178
179
 
180
+ You can also pass in a proc or lambda like this:
181
+
182
+ = best_in_place @post, :body, :display_with => lambda { |v| textilize(v).html_safe }
183
+
184
+ ## Ajax success callback
185
+
186
+ ### Binding to ajax:success
187
+
188
+ The 'ajax:success' event is triggered upon success. Use bind:
189
+
190
+ $('.best_in_place').bind("ajax:success", function(){$(this).closest('tr').effect('highlight'));});
191
+
192
+ ### Providing data to the callback
193
+
194
+ Use the :data option to add HTML5 data attributes to the best_in_place span. For example, in your view:
195
+
196
+ <%= best_in_place @user, :name, :data => {:user_name => @user.name} %>
197
+
198
+ And in your javascript:
199
+
200
+ $('.best_in_place').bind("ajax:success", function(){ alert('Name updated for '+$(this).data('userName')); });
179
201
 
180
202
  ##Non Active Record environments
181
203
  We are not planning to support other ORMs apart from Active Record, at least for now. So, you can perfectly consider the following workaround as *the right way* until a specific implementation is done for your ORM.
@@ -380,33 +402,6 @@ Fork the project on [github](https://github.com/bernat/best_in_place 'bernat / b
380
402
 
381
403
  ---
382
404
 
383
- ##Changelog
384
-
385
- ###Master branch (and part of the Rails 3.0 branch)
386
- - v.0.1.0 Initial commit
387
- - v.0.1.2 Fixing errors in collections (taken value[0] instead of index) and fixing test_app controller responses
388
- - v.0.1.3 Bug in Rails Helper. Key wrongly considered an Integer.
389
- - v.0.1.4 Adding two new parameters for further customization urlObject and nilValue and making input update on blur.
390
- - v.0.1.5 **Attention: this release is not backwards compatible**. Changing params from list to option hash, helper's refactoring,
391
- fixing bug with objects inside namespaces, adding feature for passing an external activator handler as param. Adding feature
392
- of key ESCAPE for destroying changes before they are made permanent (in inputs and textarea).
393
- - v.0.1.6-0.1.7 Avoiding request when the input is not modified and allowing the user to not sanitize input data.
394
- - v.0.1.8 jslint compliant, sanitizing tags in the gem, getting right csrf params, controlling size of textarea (elastic script, for autogrowing textarea)
395
- - v.0.1.9 Adding elastic autogrowing textareas
396
- - v.1.0.0 Setting RSpec and Capybara up, and adding some utilities. Mantaining some HTML attributes. Fix a respond_with bug (thanks, @moabite). Triggering ajax:success when ajax call is complete (thanks, @indrekj). Setting up Travis CI. Updated for Rails 3.1.
397
- - v.1.0.1 Fixing a double initialization bug
398
- - v.1.0.2 New bip_area text helper to work with text areas.
399
- - v.1.0.3 replace apostrophes in collection with corresponding HTML entity,
400
- thanks @taavo. Implemented `:display_as` option and adding
401
- `respond_with_bip` to be used in the controller.
402
-
403
- ###Rails 3.0 branch only
404
- - v.0.2.0 Added RSpec and Capybara setup, and some tests. Fix countries map syntax, Allowing href and some other HTML attributes. Adding Travis CI too. Added the best_in_place_if option. Added ajax:success trigger, thanks to @indrekj.
405
- - v.0.2.1 Fixing double initialization bug.
406
- - v.0.2.2 New bip_area text helper.
407
-
408
- ---
409
-
410
405
  ##Authors, License and Stuff
411
406
 
412
407
  Code by [Bernat Farrero](http://bernatfarrero.com) from [Itnig Web Services](http://itnig.net) (it was based on the [original project](http://github.com/janv/rest_in_place/) of Jan Varwig) and released under [MIT license](http://www.opensource.org/licenses/mit-license.php).
@@ -20,11 +20,11 @@
20
20
  */
21
21
 
22
22
  function BestInPlaceEditor(e) {
23
- this.element = jQuery(e);
23
+ this.element = e;
24
24
  this.initOptions();
25
25
  this.bindForm();
26
26
  this.initNil();
27
- $(this.activator).bind('click', {editor: this}, this.clickHandler);
27
+ jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
28
28
  }
29
29
 
30
30
  BestInPlaceEditor.prototype = {
@@ -45,14 +45,17 @@ BestInPlaceEditor.prototype = {
45
45
  var elem = this.isNil ? "" : this.element.html();
46
46
  this.oldValue = elem;
47
47
  this.display_value = to_display;
48
- $(this.activator).unbind("click", this.clickHandler);
48
+ jQuery(this.activator).unbind("click", this.clickHandler);
49
+ this.element.trigger(jQuery.Event("best_in_place:activate"));
49
50
  this.activateForm();
50
51
  },
51
52
 
52
53
  abort : function() {
53
54
  if (this.isNil) this.element.html(this.nil);
54
55
  else this.element.html(this.oldValue);
55
- $(this.activator).bind('click', {editor: this}, this.clickHandler);
56
+ jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
57
+ this.element.trigger(jQuery.Event("best_in_place:abort"));
58
+ this.element.trigger(jQuery.Event("best_in_place:deactivate"));
56
59
  },
57
60
 
58
61
  abortIfConfirm : function () {
@@ -78,7 +81,7 @@ BestInPlaceEditor.prototype = {
78
81
  });
79
82
  if (this.formType == "select") {
80
83
  var value = this.getValue();
81
- $.each(this.values, function(i, v) {
84
+ jQuery.each(this.values, function(i, v) {
82
85
  if (value == v[0]) {
83
86
  editor.element.html(v[1]);
84
87
  }
@@ -89,7 +92,7 @@ BestInPlaceEditor.prototype = {
89
92
  } else {
90
93
  editor.element.html(this.getValue() != "" ? this.getValue() : this.nil);
91
94
  }
92
- editor.element.trigger($.Event("best_in_place:update"));
95
+ editor.element.trigger(jQuery.Event("best_in_place:update"));
93
96
  },
94
97
 
95
98
  activateForm : function() {
@@ -182,8 +185,8 @@ BestInPlaceEditor.prototype = {
182
185
  /* Generate the data sent in the POST request */
183
186
  requestData : function() {
184
187
  // To prevent xss attacks, a csrf token must be defined as a meta attribute
185
- csrf_token = $('meta[name=csrf-token]').attr('content');
186
- csrf_param = $('meta[name=csrf-param]').attr('content');
188
+ csrf_token = jQuery('meta[name=csrf-token]').attr('content');
189
+ csrf_param = jQuery('meta[name=csrf-param]').attr('content');
187
190
 
188
191
  var data = "_method=put";
189
192
  data += "&" + this.objectName + '[' + this.attributeName + ']=' + encodeURIComponent(this.getValue());
@@ -203,33 +206,37 @@ BestInPlaceEditor.prototype = {
203
206
  // Handlers ////////////////////////////////////////////////////////////////
204
207
 
205
208
  loadSuccessCallback : function(data) {
206
- var response = $.parseJSON($.trim(data));
209
+ var response = jQuery.parseJSON(jQuery.trim(data));
207
210
  if (response != null && response.hasOwnProperty("display_as")) {
208
211
  this.element.attr("data-original-content", this.element.html());
209
212
  this.original_content = this.element.html();
210
213
  this.element.html(response["display_as"]);
211
214
  }
212
- this.element.trigger($.Event("ajax:success"), data);
215
+ this.element.trigger(jQuery.Event("ajax:success"), data);
213
216
 
214
217
  // Binding back after being clicked
215
- $(this.activator).bind('click', {editor: this}, this.clickHandler);
218
+ jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
219
+ this.element.trigger(jQuery.Event("best_in_place:deactivate"));
216
220
  },
217
221
 
218
222
  loadErrorCallback : function(request, error) {
219
223
  this.element.html(this.oldValue);
220
224
 
221
225
  // Display all error messages from server side validation
222
- $.each(jQuery.parseJSON(request.responseText), function(index, value) {
226
+ jQuery.each(jQuery.parseJSON(request.responseText), function(index, value) {
223
227
  if( typeof(value) == "object") {value = index + " " + value.toString(); }
224
- var container = $("<span class='flash-error'></span>").html(value);
228
+ var container = jQuery("<span class='flash-error'></span>").html(value);
225
229
  container.purr();
226
230
  });
231
+ this.element.trigger(jQuery.Event("ajax:error"));
227
232
 
228
233
  // Binding back after being clicked
229
- $(this.activator).bind('click', {editor: this}, this.clickHandler);
234
+ jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
235
+ this.element.trigger(jQuery.Event("best_in_place:deactivate"));
230
236
  },
231
237
 
232
238
  clickHandler : function(event) {
239
+ event.preventDefault();
233
240
  event.data.editor.activate();
234
241
  },
235
242
 
@@ -366,7 +373,7 @@ BestInPlaceEditor.forms = {
366
373
  var output = "<form action='javascript:void(0)' style='display:inline;'><select>";
367
374
  var selected = "";
368
375
  var oldValue = this.oldValue;
369
- $.each(this.values, function(index, value) {
376
+ jQuery.each(this.values, function(index, value) {
370
377
  selected = (value[1] == oldValue ? "selected='selected'" : "");
371
378
  output += "<option value='" + value[0] + "' " + selected + ">" + value[1] + "</option>";
372
379
  });
@@ -488,11 +495,24 @@ BestInPlaceEditor.forms = {
488
495
  };
489
496
 
490
497
  jQuery.fn.best_in_place = function() {
491
- this.each(function(){
492
- if (!jQuery(this).data('bestInPlaceEditor')) {
493
- jQuery(this).data('bestInPlaceEditor', new BestInPlaceEditor(this));
498
+
499
+ function setBestInPlace(element) {
500
+ if (!element.data('bestInPlaceEditor')) {
501
+ element.data('bestInPlaceEditor', new BestInPlaceEditor(element));
502
+ return true;
494
503
  }
504
+ }
505
+
506
+ jQuery(this.context).delegate(this.selector, 'click', function () {
507
+ var el = jQuery(this);
508
+ if (setBestInPlace(el))
509
+ el.click();
495
510
  });
511
+
512
+ this.each(function () {
513
+ setBestInPlace(jQuery(this));
514
+ });
515
+
496
516
  return this;
497
517
  };
498
518
 
@@ -7,7 +7,8 @@ module BestInPlace
7
7
  private
8
8
  def respond_bip_ok(obj)
9
9
  klass = obj.class.to_s
10
- updating_attr = params[klass.underscore].keys.first
10
+ param_key = BestInPlace::Utils.object_to_key(obj)
11
+ updating_attr = params[param_key].keys.first
11
12
 
12
13
  if renderer = BestInPlace::DisplayMethods.lookup(klass, updating_attr)
13
14
  render :json => renderer.render_json(obj)
@@ -6,24 +6,25 @@ module BestInPlace
6
6
  raise ArgumentError, "Can't use both 'display_as' and 'display_with' options at the same time"
7
7
  end
8
8
 
9
- if opts[:display_with] && !ViewHelpers.respond_to?(opts[:display_with])
9
+ if opts[:display_with] && !opts[:display_with].is_a?(Proc) && !ViewHelpers.respond_to?(opts[:display_with])
10
10
  raise ArgumentError, "Can't find helper #{opts[:display_with]}"
11
11
  end
12
12
 
13
+ real_object = (object.is_a?(Array) && object.last.class.respond_to?(:model_name)) ? object.last : object
13
14
  opts[:type] ||= :input
14
15
  opts[:collection] ||= []
15
16
  field = field.to_s
16
17
 
17
- value = build_value_for(object, field, opts)
18
+ value = build_value_for(real_object, field, opts)
18
19
 
19
20
  collection = nil
20
21
  if opts[:type] == :select && !opts[:collection].blank?
21
- v = object.send(field)
22
+ v = real_object.send(field)
22
23
  value = Hash[opts[:collection]][!!(v =~ /^[0-9]+$/) ? v.to_i : v]
23
24
  collection = opts[:collection].to_json
24
25
  end
25
26
  if opts[:type] == :checkbox
26
- fieldValue = !!object.send(field)
27
+ fieldValue = !!real_object.send(field)
27
28
  if opts[:collection].blank? || opts[:collection].size != 2
28
29
  opts[:collection] = ["No", "Yes"]
29
30
  end
@@ -31,10 +32,10 @@ module BestInPlace
31
32
  collection = opts[:collection].to_json
32
33
  end
33
34
  out = "<span class='best_in_place'"
34
- out << " id='#{BestInPlace::Utils.build_best_in_place_id(object, field)}'"
35
+ out << " id='#{BestInPlace::Utils.build_best_in_place_id(real_object, field)}'"
35
36
  out << " data-url='#{opts[:path].blank? ? url_for(object) : url_for(opts[:path])}'"
36
- out << " data-object='#{opts[:object_name] || object.class.to_s.gsub("::", "_").underscore}'"
37
- out << " data-collection='#{collection.gsub(/'/, "&#39;")}'" unless collection.blank?
37
+ out << " data-object='#{opts[:object_name] || BestInPlace::Utils.object_to_key(real_object)}'"
38
+ out << " data-collection='#{attribute_escape(collection)}'" unless collection.blank?
38
39
  out << " data-attribute='#{field}'"
39
40
  out << " data-activator='#{opts[:activator]}'" unless opts[:activator].blank?
40
41
  out << " data-ok-button='#{opts[:ok_button]}'" unless opts[:ok_button].blank?
@@ -43,7 +44,15 @@ module BestInPlace
43
44
  out << " data-type='#{opts[:type]}'"
44
45
  out << " data-inner-class='#{opts[:inner_class]}'" if opts[:inner_class]
45
46
  out << " data-html-attrs='#{opts[:html_attrs].to_json}'" unless opts[:html_attrs].blank?
46
- out << " data-original-content='#{attribute_escape(object.send(field))}'" if opts[:display_as] || opts[:display_with]
47
+ out << " data-original-content='#{attribute_escape(real_object.send(field))}'" if opts[:display_as] || opts[:display_with]
48
+ if opts[:data] && opts[:data].is_a?(Hash)
49
+ opts[:data].each do |k, v|
50
+ if !v.is_a?(String) && !v.is_a?(Symbol)
51
+ v = v.to_json
52
+ end
53
+ out << %( data-#{k.to_s.dasherize}="#{v}")
54
+ end
55
+ end
47
56
  if !opts[:sanitize].nil? && !opts[:sanitize]
48
57
  out << " data-sanitize='false'>"
49
58
  out << sanitize(value, :tags => %w(b i u s a strong em p h1 h2 h3 h4 h5 ul li ol hr pre span img br), :attributes => %w(id class href))
@@ -64,10 +73,15 @@ module BestInPlace
64
73
 
65
74
  private
66
75
  def build_value_for(object, field, opts)
76
+ return "" if object.send(field).blank?
77
+
67
78
  if opts[:display_as]
68
79
  BestInPlace::DisplayMethods.add_model_method(object.class.to_s, field, opts[:display_as])
69
80
  object.send(opts[:display_as]).to_s
70
81
 
82
+ elsif opts[:display_with].try(:is_a?, Proc)
83
+ opts[:display_with].call(object.send(field))
84
+
71
85
  elsif opts[:display_with]
72
86
  BestInPlace::DisplayMethods.add_helper_method(object.class.to_s, field, opts[:display_with], opts[:helper_options])
73
87
  if opts[:helper_options]
@@ -82,7 +96,12 @@ module BestInPlace
82
96
  end
83
97
 
84
98
  def attribute_escape(data)
85
- data.to_s.gsub("&", "&amp;").gsub("'", "&apos;") unless data.nil?
99
+ return unless data
100
+
101
+ data.to_s.
102
+ gsub("&", "&amp;").
103
+ gsub("'", "&apos;").
104
+ gsub("\n", "&#10;")
86
105
  end
87
106
  end
88
107
  end
@@ -1,15 +1,21 @@
1
1
  module BestInPlace
2
- class Utils
2
+ module Utils
3
+ extend self
3
4
 
4
- def self.build_best_in_place_id(object, field)
5
+ def build_best_in_place_id(object, field)
5
6
  if object.is_a?(Symbol) || object.is_a?(String)
6
7
  return "best_in_place_#{object}_#{field}"
7
8
  end
8
9
 
9
- id = "best_in_place_#{object.class.to_s.demodulize.underscore}"
10
+ id = "best_in_place_#{object_to_key(object)}"
10
11
  id << "_#{object.id}" if object.class.ancestors.include?(ActiveModel::Serializers::JSON)
11
12
  id << "_#{field}"
12
13
  id
13
14
  end
15
+
16
+ def object_to_key(object)
17
+ return object.class.to_s.underscore unless object.class.respond_to?(:model_name)
18
+ ActiveModel::Naming.param_key(object.class)
19
+ end
14
20
  end
15
21
  end
@@ -1,3 +1,3 @@
1
1
  module BestInPlace
2
- VERSION = "1.0.6"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -16,6 +16,14 @@ describe BestInPlace::BestInPlaceHelpers do
16
16
  :money => 150
17
17
  end
18
18
 
19
+ it "should generate a proper id for namespaced models" do
20
+ @car = Cuca::Car.create :model => "Ford"
21
+
22
+ nk = Nokogiri::HTML.parse(helper.best_in_place @car, :model, :path => helper.cuca_cars_path)
23
+ span = nk.css("span")
24
+ span.attribute("id").value.should == "best_in_place_cuca_car_#{@car.id}_model"
25
+ end
26
+
19
27
  it "should generate a proper span" do
20
28
  nk = Nokogiri::HTML.parse(helper.best_in_place @user, :name)
21
29
  span = nk.css("span")
@@ -161,6 +169,14 @@ describe BestInPlace::BestInPlaceHelpers do
161
169
  end
162
170
  end
163
171
 
172
+ it "should have html5 data attributes" do
173
+ out = helper.best_in_place @user, :name, :data => { :foo => "awesome", :bar => "nasty" }
174
+ nk = Nokogiri::HTML.parse(out)
175
+ span = nk.css("span")
176
+ span.attribute("data-foo").value.should == "awesome"
177
+ span.attribute("data-bar").value.should == "nasty"
178
+ end
179
+
164
180
  describe "display_as" do
165
181
  it "should render the address with a custom renderer" do
166
182
  @user.should_receive(:address_format).and_return("the result")
@@ -179,6 +195,13 @@ describe BestInPlace::BestInPlaceHelpers do
179
195
  span.text.should == "$150.00"
180
196
  end
181
197
 
198
+ it "accepts a proc" do
199
+ out = helper.best_in_place @user, :name, :display_with => Proc.new { |v| v.upcase }
200
+ nk = Nokogiri::HTML.parse(out)
201
+ span = nk.css("span")
202
+ span.text.should == "LUCIA"
203
+ end
204
+
182
205
  it "should raise an error if the given helper can't be found" do
183
206
  lambda { helper.best_in_place @user, :money, :display_with => :fk_number_to_currency }.should raise_error(ArgumentError)
184
207
  end
@@ -18,6 +18,18 @@ describe "JS behaviour", :js => true do
18
18
  :description => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus a lectus et lacus ultrices auctor. Morbi aliquet convallis tincidunt. Praesent enim libero, iaculis at commodo nec, fermentum a dolor. Quisque eget eros id felis lacinia faucibus feugiat et ante. Aenean justo nisi, aliquam vel egestas vel, porta in ligula. Etiam molestie, lacus eget tincidunt accumsan, elit justo rhoncus urna, nec pretium neque mi et lorem. Aliquam posuere, dolor quis pulvinar luctus, felis dolor tincidunt leo, eget pretium orci purus ac nibh. Ut enim sem, suscipit ac elementum vitae, sodales vel sem."
19
19
  end
20
20
 
21
+ describe "namespaced controllers" do
22
+ it "should be able to use array-notation to describe both object and path" do
23
+ @user.save!
24
+ visit admin_user_path(@user)
25
+
26
+ within("#last_name") { page.should have_content("Napoli") }
27
+ bip_text @user, :last_name, "Other thing"
28
+
29
+ within("#last_name") { page.should have_content("Other thing") }
30
+ end
31
+ end
32
+
21
33
  describe "nil option" do
22
34
  it "should render the default '-' string when the field is empty" do
23
35
  @user.name = ""
@@ -465,6 +477,15 @@ describe "JS behaviour", :js => true do
465
477
  end
466
478
 
467
479
  describe "display_with" do
480
+ it "should show nil text when original value is nil" do
481
+ @user.description = ""
482
+ @user.save!
483
+
484
+ visit user_path(@user)
485
+
486
+ within("#dw_description") { page.should have_content("-") }
487
+ end
488
+
468
489
  it "should render the money using number_to_currency" do
469
490
  @user.save!
470
491
  visit user_path(@user)
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe "Monitor new fields", :js => true do
5
+ before do
6
+ @user = User.new :name => "Lucia",
7
+ :last_name => "Napoli",
8
+ :email => "lucianapoli@gmail.com",
9
+ :address => "Via Roma 99",
10
+ :zip => "25123",
11
+ :country => "2",
12
+ :receive_email => false,
13
+ :description => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus a lectus et lacus ultrices auctor. Morbi aliquet convallis tincidunt. Praesent enim libero, iaculis at commodo nec, fermentum a dolor. Quisque eget eros id felis lacinia faucibus feugiat et ante. Aenean justo nisi, aliquam vel egestas vel, porta in ligula. Etiam molestie, lacus eget tincidunt accumsan, elit justo rhoncus urna, nec pretium neque mi et lorem. Aliquam posuere, dolor quis pulvinar luctus, felis dolor tincidunt leo, eget pretium orci purus ac nibh. Ut enim sem, suscipit ac elementum vitae, sodales vel sem.",
14
+ :money => 100
15
+ end
16
+
17
+ it "should work when new best_in_place spans are added to the page" do
18
+ @user.save!
19
+ visit show_ajax_user_path(@user)
20
+
21
+ sleep(1) #give time to the ajax request to work
22
+
23
+ within("#email") do
24
+ page.should have_content("lucianapoli@gmail")
25
+ end
26
+
27
+ bip_text @user, :email, "new@email.com"
28
+
29
+ within("#email") do
30
+ page.should have_content("new@email.com")
31
+ end
32
+
33
+ bip_text @user, :email, "new_two@email.com"
34
+
35
+ within("#email") do
36
+ page.should have_content("new_two@email.com")
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,14 @@
1
+ class Admin::UsersController < ApplicationController
2
+ def show
3
+ @user = User.find params[:id]
4
+ end
5
+
6
+ def update
7
+ @user = User.find(params[:id])
8
+
9
+ respond_to do |format|
10
+ @user.update_attributes(params[:user])
11
+ format.json { respond_with_bip(@user) }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ module Cuca
2
+ class CarsController < ApplicationController
3
+ def show
4
+ @car = Car.find params[:id]
5
+ end
6
+
7
+ def update
8
+ @car = Car.find params[:id]
9
+
10
+ respond_to do |format|
11
+ @car.update_attributes params[:cuca_car]
12
+ format.json { respond_with_bip(@car) }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -22,6 +22,16 @@ class UsersController < ApplicationController
22
22
  end
23
23
  end
24
24
 
25
+ def email_field
26
+ @user = User.find(params[:id])
27
+ render :action => :email_field, :layout => false
28
+ end
29
+
30
+ def show_ajax
31
+ @user = User.find(params[:id])
32
+ @countries = COUNTRIES.to_a
33
+ end
34
+
25
35
  def double_init
26
36
  @user = User.find(params[:id])
27
37
  @countries = COUNTRIES.to_a
@@ -0,0 +1,5 @@
1
+ module Cuca
2
+ class Car < ActiveRecord::Base
3
+
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ <p id="notice"><%= notice %></p>
2
+ <div id="user_account">
3
+ <h1>User details</h1>
4
+ <%= link_to "Go back to USERS", users_path %>
5
+ <p style="margin-left:48em">Click to edit</p>
6
+ <table>
7
+ <tr>
8
+ <td id="name">
9
+ <%= best_in_place [:admin, @user], :name %>
10
+ </td>
11
+ </tr>
12
+ <tr>
13
+ <td>Last Name</td>
14
+ <td id="last_name">
15
+ <%= best_in_place [:admin, @user], :last_name, :nil => "Nothing to show" %>
16
+ </td>
17
+ </tr>
18
+ </table>
19
+ </div>
20
+
@@ -0,0 +1,13 @@
1
+ <p id="notice"><%= notice %></p>
2
+ <div id="user_account">
3
+ <h1>Car details</h1>
4
+ <p style="margin-left:48em">Click to edit</p>
5
+ <table>
6
+ <tr>
7
+ <td>Model</td>
8
+ <td id="model">
9
+ <%= best_in_place @car, :model %>
10
+ </td>
11
+ </tr>
12
+ </table>
13
+ </div>
@@ -0,0 +1 @@
1
+ <%= best_in_place @user, :email %>
@@ -0,0 +1,12 @@
1
+ <%= render :template => 'users/show' %>
2
+ <script>
3
+ $(document).ready(function () {
4
+ $('#email').html('');
5
+ setTimeout( function () { //give time to the other document.ready callbacks to be executed
6
+ $.get("/users/<%= params[:id]%>/email_field", function(data, status) {
7
+ $('#email').html(data);
8
+ });
9
+ },
10
+ 500);
11
+ });
12
+ </script>
@@ -3,8 +3,18 @@ BipApp::Application.routes.draw do
3
3
  member do
4
4
  put :test_respond_with
5
5
  get :double_init
6
+ get :show_ajax
7
+ get :email_field
6
8
  end
7
9
  end
8
10
 
11
+ namespace :cuca do
12
+ resources :cars
13
+ end
14
+
15
+ namespace :admin do
16
+ resources :users
17
+ end
18
+
9
19
  root :to => "users#index"
10
20
  end
@@ -0,0 +1,11 @@
1
+ class CreateCars < ActiveRecord::Migration
2
+ def up
3
+ create_table :cars do |t|
4
+ t.string :model
5
+ end
6
+ end
7
+
8
+ def down
9
+ drop_table :cars
10
+ end
11
+ end
@@ -11,7 +11,12 @@
11
11
  #
12
12
  # It's strongly recommended to check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(:version => 20111224181356) do
14
+ ActiveRecord::Schema.define(:version => 20120513003308) do
15
+
16
+ create_table "cars", :force => true do |t|
17
+ t.string "model"
18
+ end
19
+
15
20
  create_table "users", :force => true do |t|
16
21
  t.string "name"
17
22
  t.string "last_name"
@@ -19,13 +24,14 @@ ActiveRecord::Schema.define(:version => 20111224181356) do
19
24
  t.string "email", :null => false
20
25
  t.string "zip"
21
26
  t.string "country"
22
- t.datetime "created_at"
23
- t.datetime "updated_at"
27
+ t.datetime "created_at", :null => false
28
+ t.datetime "updated_at", :null => false
24
29
  t.boolean "receive_email"
25
30
  t.text "description"
26
- t.datetime "birth_date"
27
- t.float "money"
28
31
  t.string "favorite_color"
29
32
  t.text "favorite_books"
33
+ t.datetime "birth_date"
34
+ t.float "money"
30
35
  end
36
+
31
37
  end
data/test_app/db/seeds.rb CHANGED
@@ -13,3 +13,7 @@ User.create!(:name => "Lucia", :last_name => "Napoli", :email => "lucianapoli@gm
13
13
  User.create!(:name => "Carmen", :last_name => "Luciago", :email => "carmen@luciago.com", :address => "c/Ambrosio 10", :zip => "21333", :country => "2", :receive_email => true, :birth_date => Date.today - 18.years, :description => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus a lectus et lacus ultrices auctor. Morbi aliquet convallis tincidunt. Praesent enim libero, iaculis at commodo nec, fermentum a dolor. Quisque eget eros id felis lacinia faucibus feugiat et ante. Aenean justo nisi, aliquam vel egestas vel, porta in ligula. Etiam molestie, lacus eget tincidunt accumsan, elit justo rhoncus urna, nec pretium neque mi et lorem. Aliquam posuere, dolor quis pulvinar luctus, felis dolor tincidunt leo, eget pretium orci purus ac nibh. Ut enim sem, suscipit ac elementum vitae, sodales vel sem.")
14
14
  User.create!(:name => "Angels", :last_name => "Domènech", :email => "angels@gmail.com", :address => "Avinguda Sant Andreu 1", :zip => "08033", :country => "3", :receive_email => false, :birth_date => Date.today - 65.years, :description => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus a lectus et lacus ultrices auctor. Morbi aliquet convallis tincidunt. Praesent enim libero, iaculis at commodo nec, fermentum a dolor. Quisque eget eros id felis lacinia faucibus feugiat et ante. Aenean justo nisi, aliquam vel egestas vel, porta in ligula. Etiam molestie, lacus eget tincidunt accumsan, elit justo rhoncus urna, nec pretium neque mi et lorem. Aliquam posuere, dolor quis pulvinar luctus, felis dolor tincidunt leo, eget pretium orci purus ac nibh. Ut enim sem, suscipit ac elementum vitae, sodales vel sem.")
15
15
  User.create!(:name => "Dominic", :last_name => "Lepoin", :email => "dominiclepoin@gmail.com", :address => "Rue Tour Eiffel 4993", :zip => "11192", :country => "4", :receive_email => true, :birth_date => Date.today - 40.years, :description => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus a lectus et lacus ultrices auctor. Morbi aliquet convallis tincidunt. Praesent enim libero, iaculis at commodo nec, fermentum a dolor. Quisque eget eros id felis lacinia faucibus feugiat et ante. Aenean justo nisi, aliquam vel egestas vel, porta in ligula. Etiam molestie, lacus eget tincidunt accumsan, elit justo rhoncus urna, nec pretium neque mi et lorem. Aliquam posuere, dolor quis pulvinar luctus, felis dolor tincidunt leo, eget pretium orci purus ac nibh. Ut enim sem, suscipit ac elementum vitae, sodales vel sem.")
16
+
17
+
18
+ Cuca::Car.delete_all
19
+ Cuca::Car.create! :model => "Ford"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: best_in_place
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-24 00:00:00.000000000 Z
12
+ date: 2012-05-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &83802130 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: '3.1'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *83802130
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.1'
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: jquery-rails
27
- requirement: &83801750 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ! '>='
@@ -32,10 +37,15 @@ dependencies:
32
37
  version: '0'
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *83801750
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: rspec-rails
38
- requirement: &83800970 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ~>
@@ -43,10 +53,15 @@ dependencies:
43
53
  version: 2.8.0
44
54
  type: :development
45
55
  prerelease: false
46
- version_requirements: *83800970
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 2.8.0
47
62
  - !ruby/object:Gem::Dependency
48
63
  name: nokogiri
49
- requirement: &83800320 !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
50
65
  none: false
51
66
  requirements:
52
67
  - - ! '>='
@@ -54,10 +69,15 @@ dependencies:
54
69
  version: 1.5.0
55
70
  type: :development
56
71
  prerelease: false
57
- version_requirements: *83800320
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 1.5.0
58
78
  - !ruby/object:Gem::Dependency
59
79
  name: capybara
60
- requirement: &83819560 !ruby/object:Gem::Requirement
80
+ requirement: !ruby/object:Gem::Requirement
61
81
  none: false
62
82
  requirements:
63
83
  - - ! '>='
@@ -65,7 +85,12 @@ dependencies:
65
85
  version: 1.0.1
66
86
  type: :development
67
87
  prerelease: false
68
- version_requirements: *83819560
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: 1.0.1
69
94
  description: BestInPlace is a jQuery script and a Rails 3 helper that provide the
70
95
  method best_in_place to display any object field easily editable for the user by
71
96
  just clicking on it. It supports input data, text data, boolean data and custom
@@ -79,6 +104,7 @@ files:
79
104
  - .gitignore
80
105
  - .rspec
81
106
  - .travis.yml
107
+ - CHANGELOG.md
82
108
  - Gemfile
83
109
  - README.md
84
110
  - Rakefile
@@ -98,6 +124,7 @@ files:
98
124
  - spec/helpers/best_in_place_spec.rb
99
125
  - spec/integration/double_init_spec.rb
100
126
  - spec/integration/js_spec.rb
127
+ - spec/integration/live_spec.rb
101
128
  - spec/integration/text_area_spec.rb
102
129
  - spec/spec_helper.rb
103
130
  - spec/support/retry_on_timeout.rb
@@ -124,17 +151,24 @@ files:
124
151
  - test_app/app/assets/stylesheets/jquery-ui-1.8.16.custom.css.erb
125
152
  - test_app/app/assets/stylesheets/scaffold.css
126
153
  - test_app/app/assets/stylesheets/style.css.erb
154
+ - test_app/app/controllers/admin/users_controller.rb
127
155
  - test_app/app/controllers/application_controller.rb
156
+ - test_app/app/controllers/cuca/cars_controller.rb
128
157
  - test_app/app/controllers/users_controller.rb
129
158
  - test_app/app/helpers/application_helper.rb
130
159
  - test_app/app/helpers/users_helper.rb
160
+ - test_app/app/models/cuca/car.rb
131
161
  - test_app/app/models/user.rb
162
+ - test_app/app/views/admin/users/show.html.erb
163
+ - test_app/app/views/cuca/cars/show.html.erb
132
164
  - test_app/app/views/layouts/application.html.erb
133
165
  - test_app/app/views/users/_form.html.erb
134
166
  - test_app/app/views/users/double_init.html.erb
167
+ - test_app/app/views/users/email_field.html.erb
135
168
  - test_app/app/views/users/index.html.erb
136
169
  - test_app/app/views/users/new.html.erb
137
170
  - test_app/app/views/users/show.html.erb
171
+ - test_app/app/views/users/show_ajax.html.erb
138
172
  - test_app/config.ru
139
173
  - test_app/config/application.rb
140
174
  - test_app/config/boot.rb
@@ -159,6 +193,7 @@ files:
159
193
  - test_app/db/migrate/20111210084251_add_favorite_books_to_users.rb
160
194
  - test_app/db/migrate/20111217215935_add_birth_date_to_users.rb
161
195
  - test_app/db/migrate/20111224181356_add_money_to_user.rb
196
+ - test_app/db/migrate/20120513003308_create_cars.rb
162
197
  - test_app/db/schema.rb
163
198
  - test_app/db/seeds.rb
164
199
  - test_app/doc/README_FOR_APP
@@ -191,7 +226,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
191
226
  version: '0'
192
227
  segments:
193
228
  - 0
194
- hash: -802068595
229
+ hash: -3850247748831605605
195
230
  required_rubygems_version: !ruby/object:Gem::Requirement
196
231
  none: false
197
232
  requirements:
@@ -200,12 +235,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
200
235
  version: '0'
201
236
  segments:
202
237
  - 0
203
- hash: -802068595
238
+ hash: -3850247748831605605
204
239
  requirements: []
205
240
  rubyforge_project: best_in_place
206
- rubygems_version: 1.8.10
241
+ rubygems_version: 1.8.19
207
242
  signing_key:
208
243
  specification_version: 3
209
244
  summary: It makes any field in place editable by clicking on it, it works for inputs,
210
245
  textareas, select dropdowns and checkboxes
211
- test_files: []
246
+ test_files:
247
+ - spec/helpers/best_in_place_spec.rb
248
+ - spec/integration/double_init_spec.rb
249
+ - spec/integration/js_spec.rb
250
+ - spec/integration/live_spec.rb
251
+ - spec/integration/text_area_spec.rb
252
+ - spec/spec_helper.rb
253
+ - spec/support/retry_on_timeout.rb