best_in_place_mongoid 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,161 @@
1
+ /**
2
+ * jquery.purr.js
3
+ * Copyright (c) 2008 Net Perspective (net-perspective.com)
4
+ * Licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php)
5
+ *
6
+ * @author R.A. Ray
7
+ * @projectDescription jQuery plugin for dynamically displaying unobtrusive messages in the browser. Mimics the behavior of the MacOS program "Growl."
8
+ * @version 0.1.0
9
+ *
10
+ * @requires jquery.js (tested with 1.2.6)
11
+ *
12
+ * @param fadeInSpeed int - Duration of fade in animation in miliseconds
13
+ * default: 500
14
+ * @param fadeOutSpeed int - Duration of fade out animationin miliseconds
15
+ default: 500
16
+ * @param removeTimer int - Timeout, in miliseconds, before notice is removed once it is the top non-sticky notice in the list
17
+ default: 4000
18
+ * @param isSticky bool - Whether the notice should fade out on its own or wait to be manually closed
19
+ default: false
20
+ * @param usingTransparentPNG bool - Whether or not the notice is using transparent .png images in its styling
21
+ default: false
22
+ */
23
+
24
+ (function($) {
25
+
26
+ $.purr = function(notice, options)
27
+ {
28
+ // Convert notice to a jQuery object
29
+ notice = $(notice);
30
+
31
+ // Add a class to denote the notice as not sticky
32
+ notice.addClass('purr');
33
+
34
+ // Get the container element from the page
35
+ var cont = document.getElementById('purr-container');
36
+
37
+ // If the container doesn't yet exist, we need to create it
38
+ if (!cont)
39
+ {
40
+ cont = '<div id="purr-container"></div>';
41
+ }
42
+
43
+ // Convert cont to a jQuery object
44
+ cont = $(cont);
45
+
46
+ // Add the container to the page
47
+ $('body').append(cont);
48
+
49
+ notify();
50
+
51
+ function notify ()
52
+ {
53
+ // Set up the close button
54
+ var close = document.createElement('a');
55
+ $(close).attr({
56
+ className: 'close',
57
+ href: '#close'
58
+ }).appendTo(notice).click(function() {
59
+ removeNotice();
60
+ return false;
61
+ });
62
+
63
+ // If ESC is pressed remove notice
64
+ $(document).keyup(function(e) {
65
+ if (e.keyCode == 27) {
66
+ removeNotice();
67
+ }
68
+ });
69
+
70
+ // Add the notice to the page and keep it hidden initially
71
+ notice.appendTo(cont).hide();
72
+
73
+ if (jQuery.browser.msie && options.usingTransparentPNG)
74
+ {
75
+ // IE7 and earlier can't handle the combination of opacity and transparent pngs, so if we're using transparent pngs in our
76
+ // notice style, we'll just skip the fading in.
77
+ notice.show();
78
+ }
79
+ else
80
+ {
81
+ //Fade in the notice we just added
82
+ notice.fadeIn(options.fadeInSpeed);
83
+ }
84
+
85
+ // Set up the removal interval for the added notice if that notice is not a sticky
86
+ if (!options.isSticky)
87
+ {
88
+ var topSpotInt = setInterval(function() {
89
+ // Check to see if our notice is the first non-sticky notice in the list
90
+ if (notice.prevAll('.purr').length == 0)
91
+ {
92
+ // Stop checking once the condition is met
93
+ clearInterval(topSpotInt);
94
+
95
+ // Call the close action after the timeout set in options
96
+ setTimeout(function() {
97
+ removeNotice();
98
+ }, options.removeTimer);
99
+ }
100
+ }, 200);
101
+ }
102
+ }
103
+
104
+ function removeNotice()
105
+ {
106
+ // IE7 and earlier can't handle the combination of opacity and transparent pngs, so if we're using transparent pngs in our
107
+ // notice style, we'll just skip the fading out.
108
+ if (jQuery.browser.msie && options.usingTransparentPNG)
109
+ {
110
+ notice.css({ opacity: 0 }).animate({ height: '0px'},
111
+ {
112
+ duration: options.fadeOutSpeed,
113
+ complete: function ()
114
+ {
115
+ notice.remove();
116
+ }
117
+ }
118
+ );
119
+ }
120
+ else
121
+ {
122
+ // Fade the object out before reducing its height to produce the sliding effect
123
+ notice.animate({ opacity: '0' },
124
+ {
125
+ duration: options.fadeOutSpeed,
126
+ complete: function ()
127
+ {
128
+ notice.animate({ height: '0px' },
129
+ {
130
+ duration: options.fadeOutSpeed,
131
+ complete: function()
132
+ {
133
+ notice.remove();
134
+ }
135
+ }
136
+ );
137
+ }
138
+ }
139
+ );
140
+ }
141
+ };
142
+ };
143
+
144
+ $.fn.purr = function(options)
145
+ {
146
+ options = options || {};
147
+ options.fadeInSpeed = options.fadeInSpeed || 500;
148
+ options.fadeOutSpeed = options.fadeOutSpeed || 500;
149
+ options.removeTimer = options.removeTimer || 4000;
150
+ options.isSticky = options.isSticky || false;
151
+ options.usingTransparentPNG = options.usingTransparentPNG || false;
152
+
153
+ this.each(function()
154
+ {
155
+ new $.purr( this, options );
156
+ }
157
+ );
158
+
159
+ return this;
160
+ };
161
+ })( jQuery );
@@ -0,0 +1,7 @@
1
+ require "best_in_place_mongoid/utils"
2
+ require "best_in_place_mongoid/helper"
3
+ require "best_in_place_mongoid/engine"
4
+
5
+ module BestInPlaceMongoid
6
+ autoload :TestHelpers, "best_in_place_mongoid/test_helpers"
7
+ end
@@ -0,0 +1,7 @@
1
+ module BestInPlaceMongoid
2
+ class Engine < Rails::Engine
3
+ initializer "setup for rails" do
4
+ ActionView::Base.send(:include, BestInPlaceMongoid::BestInPlaceMongoidHelpers)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,53 @@
1
+ module BestInPlaceMongoid
2
+ module BestInPlaceMongoidHelpers
3
+
4
+ def best_in_place(object, field, opts = {})
5
+ opts[:type] ||= :input
6
+ opts[:collection] ||= []
7
+ field = field.to_s
8
+ value = object.send(field).blank? ? "" : object.send(field)
9
+ collection = nil
10
+ if opts[:type] == :select && !opts[:collection].blank?
11
+ v = object.send(field)
12
+ value = Hash[opts[:collection]][!!(v =~ /^[0-9]+$/) ? v.to_i : v]
13
+ collection = opts[:collection].to_json
14
+ end
15
+ if opts[:type] == :checkbox
16
+ fieldValue = !!object.send(field)
17
+ if opts[:collection].blank? || opts[:collection].size != 2
18
+ opts[:collection] = ["No", "Yes"]
19
+ end
20
+ value = fieldValue ? opts[:collection][1] : opts[:collection][0]
21
+ collection = opts[:collection].to_json
22
+ end
23
+ out = "<span class='best_in_place'"
24
+ out << " id='#{BestInPlaceMongoid::Utils.build_best_in_place_id(object, field)}'"
25
+ out << " data-url='#{opts[:path].blank? ? url_for(object).to_s : url_for(opts[:path])}'"
26
+ out << " data-object='#{object.class.to_s.gsub("::", "_").underscore}'"
27
+ out << " data-collection='#{collection}'" unless collection.blank?
28
+ out << " data-attribute='#{field}'"
29
+ out << " data-activator='#{opts[:activator]}'" unless opts[:activator].blank?
30
+ out << " data-nil='#{opts[:nil].to_s}'" unless opts[:nil].blank?
31
+ out << " data-type='#{opts[:type].to_s}'"
32
+ out << " data-inner-class='#{opts[:inner_class].to_s}'" if opts[:inner_class]
33
+ out << " data-html-attrs='#{opts[:html_attrs].to_json}'" unless opts[:html_attrs].blank?
34
+ if !opts[:sanitize].nil? && !opts[:sanitize]
35
+ out << " data-sanitize='false'>"
36
+ out << sanitize(value.to_s, :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))
37
+ else
38
+ out << ">#{sanitize(value.to_s, :tags => nil, :attributes => nil)}"
39
+ end
40
+ out << "</span>"
41
+ raw out
42
+ end
43
+
44
+ def best_in_place_if(condition, object, field, opts={})
45
+ if condition
46
+ best_in_place(object, field, opts)
47
+ else
48
+ object.send field
49
+ end
50
+ end
51
+ end
52
+ end
53
+
@@ -0,0 +1,39 @@
1
+ module BestInPlaceMongoid
2
+ module TestHelpers
3
+
4
+ def bip_area(model, attr, new_value)
5
+ id = BestInPlaceMongoid::Utils.build_best_in_place_id model, attr
6
+ page.execute_script <<-JS
7
+ $("##{id}").click();
8
+ $("##{id} form textarea").val('#{new_value}');
9
+ $("##{id} form textarea").blur();
10
+ JS
11
+ end
12
+
13
+ def bip_text(model, attr, new_value)
14
+ id = BestInPlaceMongoid::Utils.build_best_in_place_id model, attr
15
+ page.execute_script <<-JS
16
+ $("##{id}").click();
17
+ $("##{id} input[name='#{attr}']").val('#{new_value}');
18
+ $("##{id} form").submit();
19
+ JS
20
+ end
21
+
22
+ def bip_bool(model, attr)
23
+ id = BestInPlaceMongoid::Utils.build_best_in_place_id model, attr
24
+ page.execute_script("$('##{id}').click();")
25
+ end
26
+
27
+ def bip_select(model, attr, name)
28
+ id = BestInPlaceMongoid::Utils.build_best_in_place_id model, attr
29
+ page.execute_script <<-JS
30
+ (function() {
31
+ $("##{id}").click();
32
+ var opt_value = $("##{id} select option:contains('#{name}')").attr('value');
33
+ $("##{id} select option[value='" + opt_value + "']").attr('selected', true);
34
+ $("##{id} select").change();
35
+ })();
36
+ JS
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,15 @@
1
+ module BestInPlaceMongoid
2
+ class Utils
3
+
4
+ def self.build_best_in_place_id(object, field)
5
+ if object.is_a?(Symbol) || object.is_a?(String)
6
+ return "best_in_place_#{object}_#{field}"
7
+ end
8
+
9
+ id = "best_in_place_#{object.class.to_s.demodulize.underscore}"
10
+ id << "_#{object.id}" if object.class.ancestors.include?(Mongoid::Document)
11
+ id << "_#{field}"
12
+ id
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module BestInPlaceMongoid
2
+ VERSION = "1.0.2"
3
+ end
@@ -0,0 +1,239 @@
1
+ # encoding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe BestInPlaceMongoid::BestInPlaceMongoidHelpers do
5
+ describe "#best_in_place" do
6
+ before do
7
+ @user = User.new :name => "Lucia",
8
+ :last_name => "Napoli",
9
+ :email => "lucianapoli@gmail.com",
10
+ :address => "Via Roma 99",
11
+ :zip => "25123",
12
+ :country => "2",
13
+ :receive_email => false,
14
+ :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
+ end
16
+
17
+ it "should generate a proper span" do
18
+ nk = Nokogiri::HTML.parse(helper.best_in_place @user, :name)
19
+ span = nk.css("span")
20
+ span.should_not be_empty
21
+ end
22
+
23
+ describe "general properties" do
24
+ before do
25
+ nk = Nokogiri::HTML.parse(helper.best_in_place @user, :name)
26
+ @span = nk.css("span")
27
+ end
28
+
29
+ context "when it's an Mongoid document" do
30
+ it "should have a proper id" do
31
+ @span.attribute("id").value.should == "best_in_place_user_#{@user.id}_name"
32
+ end
33
+ end
34
+
35
+ context "when it's not an AR model" do
36
+ it "shold generate an html id without any id" do
37
+ nk = Nokogiri::HTML.parse(helper.best_in_place [1,2,3], :first, :path => @user)
38
+ span = nk.css("span")
39
+ span.attribute("id").value.should == "best_in_place_array_first"
40
+ end
41
+ end
42
+
43
+ it "should have the best_in_place class" do
44
+ @span.attribute("class").value.should == "best_in_place"
45
+ end
46
+
47
+ it "should have the correct data-attribute" do
48
+ @span.attribute("data-attribute").value.should == "name"
49
+ end
50
+
51
+ it "should have the correct data-object" do
52
+ @span.attribute("data-object").value.should == "user"
53
+ end
54
+
55
+ it "should have no activator by default" do
56
+ @span.attribute("data-activator").should be_nil
57
+ end
58
+
59
+ it "should have no inner_class by default" do
60
+ @span.attribute("data-inner-class").should be_nil
61
+ end
62
+
63
+ describe "url generation" do
64
+ it "should have the correct default url" do
65
+ @user.save!
66
+ nk = Nokogiri::HTML.parse(helper.best_in_place @user, :name)
67
+ span = nk.css("span")
68
+ span.attribute("data-url").value.should == "/users/#{@user.id}"
69
+ end
70
+
71
+ it "should use the custom url specified in string format" do
72
+ out = helper.best_in_place @user, :name, :path => "/custom/path"
73
+ nk = Nokogiri::HTML.parse(out)
74
+ span = nk.css("span")
75
+ span.attribute("data-url").value.should == "/custom/path"
76
+ end
77
+
78
+ it "should use the path given in a named_path format" do
79
+ out = helper.best_in_place @user, :name, :path => helper.users_path
80
+ nk = Nokogiri::HTML.parse(out)
81
+ span = nk.css("span")
82
+ span.attribute("data-url").value.should == "/users"
83
+ end
84
+
85
+ it "should use the given path in a hash format" do
86
+ out = helper.best_in_place @user, :name, :path => {:controller => :users, :action => :edit, :id => 23}
87
+ nk = Nokogiri::HTML.parse(out)
88
+ span = nk.css("span")
89
+ span.attribute("data-url").value.should == "/users/23/edit"
90
+ end
91
+ end
92
+
93
+ describe "nil option" do
94
+ it "should have no nil data by default" do
95
+ @span.attribute("data-nil").should be_nil
96
+ end
97
+
98
+ it "should show '' if the object responds with nil for the passed attribute" do
99
+ @user.stub!(:name).and_return(nil)
100
+ nk = Nokogiri::HTML.parse(helper.best_in_place @user, :name)
101
+ span = nk.css("span")
102
+ span.text.should == ""
103
+ end
104
+
105
+ it "should show '' if the object responds with an empty string for the passed attribute" do
106
+ @user.stub!(:name).and_return("")
107
+ nk = Nokogiri::HTML.parse(helper.best_in_place @user, :name)
108
+ span = nk.css("span")
109
+ span.text.should == ""
110
+ end
111
+ end
112
+
113
+ it "should have the given inner_class" do
114
+ out = helper.best_in_place @user, :name, :inner_class => "awesome"
115
+ nk = Nokogiri::HTML.parse(out)
116
+ span = nk.css("span")
117
+ span.attribute("data-inner-class").value.should == "awesome"
118
+ end
119
+
120
+ it "should have the given activator" do
121
+ out = helper.best_in_place @user, :name, :activator => "awesome"
122
+ nk = Nokogiri::HTML.parse(out)
123
+ span = nk.css("span")
124
+ span.attribute("data-activator").value.should == "awesome"
125
+ end
126
+ end
127
+
128
+
129
+ context "with a text field attribute" do
130
+ before do
131
+ nk = Nokogiri::HTML.parse(helper.best_in_place @user, :name)
132
+ @span = nk.css("span")
133
+ end
134
+
135
+ it "should render the name as text" do
136
+ @span.text.should == "Lucia"
137
+ end
138
+
139
+ it "should have an input data-type" do
140
+ @span.attribute("data-type").value.should == "input"
141
+ end
142
+
143
+ it "should have no data-collection" do
144
+ @span.attribute("data-collection").should be_nil
145
+ end
146
+ end
147
+
148
+ context "with a boolean attribute" do
149
+ before do
150
+ nk = Nokogiri::HTML.parse(helper.best_in_place @user, :receive_email, :type => :checkbox)
151
+ @span = nk.css("span")
152
+ end
153
+
154
+ it "should have a checkbox data-type" do
155
+ @span.attribute("data-type").value.should == "checkbox"
156
+ end
157
+
158
+ it "should have the default data-collection" do
159
+ data = ["No", "Yes"]
160
+ @span.attribute("data-collection").value.should == data.to_json
161
+ end
162
+
163
+ it "should render the current option as No" do
164
+ @span.text.should == "No"
165
+ end
166
+
167
+ describe "custom collection" do
168
+ before do
169
+ nk = Nokogiri::HTML.parse(helper.best_in_place @user, :receive_email, :type => :checkbox, :collection => ["Nain", "Da"])
170
+ @span = nk.css("span")
171
+ end
172
+
173
+ it "should show the message with the custom values" do
174
+ @span.text.should == "Nain"
175
+ end
176
+
177
+ it "should render the proper data-collection" do
178
+ @span.attribute("data-collection").value.should == ["Nain", "Da"].to_json
179
+ end
180
+ end
181
+
182
+ end
183
+
184
+ context "with a select attribute" do
185
+ before do
186
+ @countries = COUNTRIES.to_a
187
+ nk = Nokogiri::HTML.parse(helper.best_in_place @user, :country, :type => :select, :collection => @countries)
188
+ @span = nk.css("span")
189
+ end
190
+
191
+ it "should have a select data-type" do
192
+ @span.attribute("data-type").value.should == "select"
193
+ end
194
+
195
+ it "should have a proper data collection" do
196
+ @span.attribute("data-collection").value.should == @countries.to_json
197
+ end
198
+
199
+ it "should show the current country" do
200
+ @span.text.should == "Italy"
201
+ end
202
+ end
203
+ end
204
+
205
+ describe "#best_in_place_if" do
206
+ context "when the parameters are valid" do
207
+ before(:each) do
208
+ @output = "Some Value"
209
+ @field = :somefield
210
+ @object = mock("object", @field => @output)
211
+ @options = mock("options")
212
+ end
213
+ context "when the condition is true" do
214
+ before {@condition = true}
215
+ context "when the options parameter is left off" do
216
+ it "should call best_in_place with the rest of the parameters and empty options" do
217
+ helper.should_receive(:best_in_place).with(@object, @field, {})
218
+ helper.best_in_place_if @condition, @object, @field
219
+ end
220
+ end
221
+ context "when the options parameter is included" do
222
+ it "should call best_in_place with the rest of the parameters" do
223
+ helper.should_receive(:best_in_place).with(@object, @field, @options)
224
+ helper.best_in_place_if @condition, @object, @field, @options
225
+ end
226
+ end
227
+ end
228
+ context "when the condition is false" do
229
+ before {@condition = false}
230
+ it "should return the value of the field when the options value is left off" do
231
+ helper.best_in_place_if(@condition, @object, @field).should eq @output
232
+ end
233
+ it "should return the value of the field when the options value is included" do
234
+ helper.best_in_place_if(@condition, @object, @field, @options).should eq @output
235
+ end
236
+ end
237
+ end
238
+ end
239
+ end