simple_update_field 0.2.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.rvmrc +1 -0
  2. data/Gemfile +19 -5
  3. data/Gemfile.lock +150 -0
  4. data/Rakefile +6 -0
  5. data/VERSION +1 -1
  6. data/app/assets/images/rails.png +0 -0
  7. data/app/assets/javascripts/application.js +14 -0
  8. data/app/assets/stylesheets/application.css +7 -0
  9. data/app/controllers/application_controller.rb +3 -0
  10. data/app/controllers/phrases_controller.rb +12 -0
  11. data/app/helpers/application_helper.rb +2 -0
  12. data/app/mailers/.gitkeep +0 -0
  13. data/app/models/.gitkeep +0 -0
  14. data/app/models/phrase.rb +4 -0
  15. data/app/views/layouts/application.html.erb +14 -0
  16. data/app/views/phrases/_phrase.html.erb +8 -0
  17. data/app/views/phrases/index.html.erb +1 -0
  18. data/config/application.rb +54 -0
  19. data/config/boot.rb +6 -0
  20. data/config/database.yml +25 -0
  21. data/config/environment.rb +5 -0
  22. data/config/environments/development.rb +30 -0
  23. data/config/environments/production.rb +60 -0
  24. data/config/environments/test.rb +42 -0
  25. data/config/initializers/backtrace_silencers.rb +7 -0
  26. data/config/initializers/inflections.rb +10 -0
  27. data/config/initializers/mime_types.rb +5 -0
  28. data/config/initializers/secret_token.rb +7 -0
  29. data/config/initializers/session_store.rb +8 -0
  30. data/config/initializers/wrap_parameters.rb +14 -0
  31. data/config/locales/en.yml +5 -0
  32. data/config/routes.rb +4 -0
  33. data/config.ru +4 -0
  34. data/db/migrate/20120213182817_create_phrases.rb +9 -0
  35. data/db/schema.rb +22 -0
  36. data/db/seeds.rb +7 -0
  37. data/lib/assets/.gitkeep +0 -0
  38. data/lib/tasks/.gitkeep +0 -0
  39. data/lib/tasks/admin.rake +9 -0
  40. data/lib/tasks/jasmine.rake +8 -0
  41. data/script/rails +6 -0
  42. data/simple_update_field.gemspec +76 -2
  43. data/spec/controllers/phrases_controller_spec.rb +22 -0
  44. data/spec/javascripts/editable_list_spec.js +411 -0
  45. data/spec/javascripts/helpers/mock-ajax.js +207 -0
  46. data/spec/javascripts/spec.css +3 -0
  47. data/spec/javascripts/spec.js +2 -0
  48. data/spec/{simple_update_field_spec.rb → lib/simple_update_field_spec.rb} +1 -2
  49. data/spec/models/phrase_spec.rb +11 -0
  50. data/spec/routing/phrase_spec.rb +12 -0
  51. data/spec/routing/root_spec.rb +7 -0
  52. data/spec/spec_helper.rb +28 -8
  53. data/spec/views/_phrase.html.erb_spec.rb +9 -0
  54. data/spec/views/index.html.erb_spec.rb +10 -0
  55. metadata +157 -11
data/db/seeds.rb ADDED
@@ -0,0 +1,7 @@
1
+ # This file should contain all the record creation needed to seed the database with its default values.
2
+ # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
3
+ #
4
+ # Examples:
5
+ #
6
+ # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
7
+ # Mayor.create(name: 'Emanuel', city: cities.first)
File without changes
File without changes
@@ -0,0 +1,9 @@
1
+ namespace :admin do
2
+ desc 'create some random phrases'
3
+ task :create_phrases => :environment do
4
+ 100.times do
5
+ Phrase.create!(text: Faker::Lorem.sentence(1))
6
+ end
7
+ end
8
+
9
+ end
@@ -0,0 +1,8 @@
1
+ begin
2
+ require 'jasmine'
3
+ load 'jasmine/tasks/jasmine.rake'
4
+ rescue LoadError
5
+ task :jasmine do
6
+ abort "Jasmine is not available. In order to run jasmine, you must: (sudo) gem install jasmine"
7
+ end
8
+ end
data/script/rails ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "simple_update_field"
8
- s.version = "0.2.3"
8
+ s.version = "1.0.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Curtis Schofield"]
@@ -19,16 +19,63 @@ Gem::Specification.new do |s|
19
19
  s.files = [
20
20
  ".document",
21
21
  ".rspec",
22
+ ".rvmrc",
22
23
  "Gemfile",
23
24
  "Gemfile.lock",
24
25
  "LICENSE.txt",
25
26
  "README.rdoc",
26
27
  "Rakefile",
27
28
  "VERSION",
29
+ "app/assets/images/rails.png",
30
+ "app/assets/javascripts/application.js",
31
+ "app/assets/stylesheets/application.css",
32
+ "app/controllers/application_controller.rb",
33
+ "app/controllers/phrases_controller.rb",
34
+ "app/helpers/application_helper.rb",
35
+ "app/mailers/.gitkeep",
36
+ "app/models/.gitkeep",
37
+ "app/models/phrase.rb",
38
+ "app/views/layouts/application.html.erb",
39
+ "app/views/phrases/_phrase.html.erb",
40
+ "app/views/phrases/index.html.erb",
41
+ "config.ru",
42
+ "config/application.rb",
43
+ "config/boot.rb",
44
+ "config/database.yml",
45
+ "config/environment.rb",
46
+ "config/environments/development.rb",
47
+ "config/environments/production.rb",
48
+ "config/environments/test.rb",
49
+ "config/initializers/backtrace_silencers.rb",
50
+ "config/initializers/inflections.rb",
51
+ "config/initializers/mime_types.rb",
52
+ "config/initializers/secret_token.rb",
53
+ "config/initializers/session_store.rb",
54
+ "config/initializers/wrap_parameters.rb",
55
+ "config/locales/en.yml",
56
+ "config/routes.rb",
57
+ "db/migrate/20120213182817_create_phrases.rb",
58
+ "db/schema.rb",
59
+ "db/seeds.rb",
60
+ "lib/assets/.gitkeep",
28
61
  "lib/simple_update_field.rb",
62
+ "lib/tasks/.gitkeep",
63
+ "lib/tasks/admin.rake",
64
+ "lib/tasks/jasmine.rake",
65
+ "script/rails",
29
66
  "simple_update_field.gemspec",
30
- "spec/simple_update_field_spec.rb",
67
+ "spec/controllers/phrases_controller_spec.rb",
68
+ "spec/javascripts/editable_list_spec.js",
69
+ "spec/javascripts/helpers/mock-ajax.js",
70
+ "spec/javascripts/spec.css",
71
+ "spec/javascripts/spec.js",
72
+ "spec/lib/simple_update_field_spec.rb",
73
+ "spec/models/phrase_spec.rb",
74
+ "spec/routing/phrase_spec.rb",
75
+ "spec/routing/root_spec.rb",
31
76
  "spec/spec_helper.rb",
77
+ "spec/views/_phrase.html.erb_spec.rb",
78
+ "spec/views/index.html.erb_spec.rb",
32
79
  "vendor/assets/javascripts/editable_list.js"
33
80
  ]
34
81
  s.homepage = "http://github.com/robotarmy/simple_update_field"
@@ -45,17 +92,44 @@ Gem::Specification.new do |s|
45
92
  s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
46
93
  s.add_development_dependency(%q<bundler>, ["~> 1.1.0"])
47
94
  s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
95
+ s.add_development_dependency(%q<rails>, ["= 3.1.0"])
96
+ s.add_development_dependency(%q<sqlite3>, [">= 0"])
97
+ s.add_development_dependency(%q<jquery-rails>, [">= 0"])
98
+ s.add_development_dependency(%q<rspec-rails>, [">= 0"])
99
+ s.add_development_dependency(%q<autotest>, [">= 0"])
100
+ s.add_development_dependency(%q<capybara>, [">= 0"])
101
+ s.add_development_dependency(%q<jasminerice>, [">= 0"])
102
+ s.add_development_dependency(%q<guard-jasmine>, [">= 0"])
103
+ s.add_development_dependency(%q<faker>, [">= 0"])
48
104
  else
49
105
  s.add_dependency(%q<rspec>, ["~> 2.8.0"])
50
106
  s.add_dependency(%q<rdoc>, ["~> 3.12"])
51
107
  s.add_dependency(%q<bundler>, ["~> 1.1.0"])
52
108
  s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
109
+ s.add_dependency(%q<rails>, ["= 3.1.0"])
110
+ s.add_dependency(%q<sqlite3>, [">= 0"])
111
+ s.add_dependency(%q<jquery-rails>, [">= 0"])
112
+ s.add_dependency(%q<rspec-rails>, [">= 0"])
113
+ s.add_dependency(%q<autotest>, [">= 0"])
114
+ s.add_dependency(%q<capybara>, [">= 0"])
115
+ s.add_dependency(%q<jasminerice>, [">= 0"])
116
+ s.add_dependency(%q<guard-jasmine>, [">= 0"])
117
+ s.add_dependency(%q<faker>, [">= 0"])
53
118
  end
54
119
  else
55
120
  s.add_dependency(%q<rspec>, ["~> 2.8.0"])
56
121
  s.add_dependency(%q<rdoc>, ["~> 3.12"])
57
122
  s.add_dependency(%q<bundler>, ["~> 1.1.0"])
58
123
  s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
124
+ s.add_dependency(%q<rails>, ["= 3.1.0"])
125
+ s.add_dependency(%q<sqlite3>, [">= 0"])
126
+ s.add_dependency(%q<jquery-rails>, [">= 0"])
127
+ s.add_dependency(%q<rspec-rails>, [">= 0"])
128
+ s.add_dependency(%q<autotest>, [">= 0"])
129
+ s.add_dependency(%q<capybara>, [">= 0"])
130
+ s.add_dependency(%q<jasminerice>, [">= 0"])
131
+ s.add_dependency(%q<guard-jasmine>, [">= 0"])
132
+ s.add_dependency(%q<faker>, [">= 0"])
59
133
  end
60
134
  end
61
135
 
@@ -0,0 +1,22 @@
1
+ require "spec_helper"
2
+ describe PhrasesController do
3
+ context "GET" do
4
+ context "index" do
5
+ it "should be ok" do
6
+ get :index
7
+ response.should be_success
8
+ end
9
+ it "should render template" do
10
+ get :index
11
+ response.should render_template('index')
12
+ end
13
+
14
+ it "assigns phrases to @phrases" do
15
+ Phrase.create!(:text => 'Cake')
16
+ Phrase.create!(:text => 'Cake 2')
17
+ get :index
18
+ assigns[:phrases].should == Phrase.limit(2).all # all executes the ActiveRecord::Relation
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,411 @@
1
+ describe("Editable",function() {
2
+ var selector = '.phrase .text'
3
+
4
+ var should_be_an_input_after_click = function() {
5
+ // best jquery practice - use pseudo selectors after
6
+ // using natural css selectors
7
+ expect($(selector)
8
+ .filter(':input')
9
+ .size()
10
+ ).toBe(0)
11
+ $(selector)
12
+ .filter(':first')
13
+ .trigger('click.editable')
14
+ expect($(selector)
15
+ .filter(':input')
16
+ .size()
17
+ ).toBe(1)
18
+ }
19
+
20
+
21
+ it("it has a constructor", function() {
22
+ expect(Editable).toBeDefined()
23
+ expect(Editable()).toBeDefined()
24
+ })
25
+
26
+ describe("needs an attribute editable-resource-uri", function() {
27
+ beforeEach(function(){
28
+ var fixture = "<div class='phrase'>"+
29
+ "<span class='text'>CAKE</span>"+
30
+ "</div>"
31
+ // removed from dom each
32
+ // test
33
+ setFixtures(fixture)
34
+ });
35
+ describe("with editable declared",function() {
36
+ beforeEach(function() {
37
+ // Construct
38
+ Editable(selector)
39
+ })
40
+ describe("error messages in dom",function() {
41
+ it("resource-attribute attribute",function() {
42
+
43
+ $(selector)
44
+ .filter(':first')
45
+ .trigger('click.editable')
46
+ $(selector)
47
+ .filter(':first')
48
+ .trigger('blur.editable')
49
+
50
+ expect($('.editable-errors')
51
+ .text()
52
+ ).toMatch(
53
+ "expected editable-resource-attribute attribute"
54
+ )
55
+ })
56
+ it("resource-model attribute",function() {
57
+
58
+ $(selector)
59
+ .filter(':first')
60
+ .trigger('click.editable')
61
+ $(selector)
62
+ .filter(':first')
63
+ .trigger('blur.editable')
64
+
65
+ expect($('.editable-errors')
66
+ .text()
67
+ ).toMatch(
68
+ "expected editable-resource-model attribute"
69
+ )
70
+ })
71
+ it("resource-uri attribute",function() {
72
+
73
+ $(selector)
74
+ .filter(':first')
75
+ .trigger('click.editable')
76
+ $(selector)
77
+ .filter(':first')
78
+ .trigger('blur.editable')
79
+
80
+ expect($('.editable-errors')
81
+ .text()
82
+ ).toMatch(
83
+ "expected editable-resource-uri attribute"
84
+ )
85
+ })
86
+ })
87
+ })
88
+ })
89
+
90
+ describe("with a single match in dom",function() {
91
+
92
+ beforeEach(function(){
93
+ var fixture = "<div class='phrase'>"+
94
+ "<span "+
95
+ " editable-resource-uri='http://s/r/i' "+
96
+ " class='text'>CAKE</span>"+
97
+ "</div>"
98
+ setFixtures(fixture)
99
+ });
100
+
101
+ it("selector modifies dom",function() {
102
+ Editable(selector)
103
+ expect($(selector).data('editable')).toBeDefined()
104
+ })
105
+
106
+ describe("after installation",function() {
107
+ beforeEach(function() {
108
+
109
+ Editable(selector)
110
+ })
111
+
112
+ describe("ajax request is sent",function() {
113
+ beforeEach(function() {
114
+ spyOn(jQuery.ajaxSettings, 'xhr').andCallFake(function() {
115
+ var newXhr = new FakeXMLHttpRequest();
116
+ ajaxRequests.push(newXhr);
117
+ return newXhr;
118
+ })
119
+ })
120
+ it("when editing is complete",function() {
121
+ $(selector).filter(':first').attr('editable-resource-uri',"http://cake123/")
122
+ $(selector).filter(':first').attr('editable-resource-model',"phrase")
123
+ $(selector).filter(':first').attr('editable-resource-attribute',"text")
124
+
125
+ // become editable
126
+ $(selector).filter(':first').trigger('click.editable')
127
+ // change value
128
+ $(selector).filter(':first').val("passion")
129
+ // complete editing
130
+ $(selector).filter(':first').trigger('blur.editable')
131
+
132
+ request = mostRecentAjaxRequest()
133
+ console.log(request)
134
+ expect(request).not.toBeNull()
135
+ expect(request.params).toMatch(/phrase%5Btext%5D=passion/)
136
+ expect(request.method).toMatch(/PUT/)
137
+ expect(request.url).toMatch("http://cake123/")
138
+ })
139
+ })
140
+
141
+ describe("when editing begins", function() {
142
+ describe("an element ",function() {
143
+ it("is an input",should_be_an_input_after_click)
144
+ it("has same classes",function() {
145
+ $(selector).addClass('cake').addClass('oat')
146
+ $(selector).filter(':first').trigger('click.editable')
147
+ expect($(selector).filter('.cake').size()).toBe(1)
148
+ expect($(selector).filter('.oat').size()).toBe(1)
149
+ })
150
+ it("has same id",function() {
151
+ $(selector).attr('id','boom')
152
+ $(selector).filter(':first').trigger('click.editable')
153
+ expect($(selector).filter('#boom').size()).toBe(1)
154
+ })
155
+ it("stores its text as input value",function() {
156
+ $(selector).filter(':first').text("Lily")
157
+ $(selector).filter(':first').trigger('click.editable')
158
+ expect($(selector).filter(':first').val()).toEqual("Lily")
159
+ })
160
+ it("has a unique position attribute: editable-index",function() {
161
+ $(selector).attr('editable-index','333')
162
+ $(selector).filter(':first').trigger('click.editable')
163
+ expect($(selector).filter(':input').attr('editable-index')).toBe('333')
164
+ })
165
+ it("has a resource uri : editable-resource-uri",function() {
166
+ $(selector).attr('editable-resource-uri','http://11')
167
+ $(selector).filter(':first').trigger('click.editable')
168
+ expect($(selector)
169
+ .filter(':input')
170
+ .attr('editable-resource-uri')).toBe('http://11')
171
+ })
172
+ it("has a resource name : editable-resource-model",function() {
173
+ $(selector).attr('editable-resource-model','dream')
174
+ $(selector).filter(':first').trigger('click.editable')
175
+ expect($(selector)
176
+ .filter(':input')
177
+ .attr('editable-resource-model')).toBe('dream')
178
+ })
179
+ it("has a resource attribute : editable-resource-attribute",function() {
180
+ $(selector).attr('editable-resource-attribute','vision')
181
+ $(selector).filter(':first').trigger('click.editable')
182
+ expect($(selector)
183
+ .filter(':input')
184
+ .attr('editable-resource-attribute')).toBe('vision')
185
+ })
186
+ it("has same jquery data",function() {
187
+ // data is used in rails and jquery for storage of various properties
188
+ $(selector).data('hi',1)
189
+ $(selector).data('hello',2)
190
+ var expected_data = $(selector).data();
191
+ $(selector).filter(':first').trigger('click.editable')
192
+ // this is the general pattern for iterating correctly in a hash
193
+ // in javascript
194
+ for(var prop in expected_data) {
195
+ // ignore parent prototype properties
196
+ if(expected_data.hasOwnProperty(prop)) {
197
+ // use proprety expected_data[prop]
198
+ expect($(selector).filter(':input').data(prop)).toEqual(expected_data[prop])
199
+ }
200
+ }
201
+ $(selector).filter(':input').data()
202
+ })
203
+ it("stores previous incarnation: tagName",function() {
204
+ var expected_tag = $(selector).filter(':first').get(0).tagName
205
+ $(selector).filter(':first').trigger('click.editable')
206
+ expect($(selector).filter(':input').data('editable-was')).toEqual(expected_tag)
207
+ })
208
+ it("is focused",function() {
209
+ expect($(selector).filter(':focus').size()).toBe(0)
210
+ $(selector).filter(':first').trigger('click.editable')
211
+ expect($(selector).filter(':focus').size()).toBe(1)
212
+
213
+ })
214
+ })
215
+ })
216
+ describe("when editing is complete", function() {
217
+ it("an element becomes again editable-was",function() {
218
+ // first there is a mountain
219
+ var expected_tag = $(selector).filter(':first').get(0).tagName
220
+ expect($(selector).filter(expected_tag).size()).toBe(1)
221
+ $(selector).filter(':first').trigger('click.editable')
222
+ // then there is no mountain
223
+ expect($(selector).filter(expected_tag).size()).toBe(0)
224
+ $(selector).filter(':first').trigger('blur.editable')
225
+ // then there is
226
+ expect($(selector).filter(expected_tag).size()).toBe(1)
227
+ })
228
+ it("the input value becomes the CDATA",function () {
229
+ $(selector).filter(':first').text("SOUP")
230
+ $(selector).filter(':first').trigger('click.editable')
231
+ expect($(selector).filter(':first').val()).toEqual("SOUP")
232
+ $(selector).filter(':first').val("are you a kitty?")
233
+ $(selector).filter(':first').trigger('blur.editable')
234
+ expect($(selector).filter(':first').text()).toEqual("are you a kitty?")
235
+
236
+ })
237
+ })
238
+ describe("hover event handler", function() {
239
+ it("turns on editable hover class",function() {
240
+ expect($(selector).filter(':first').hasClass('editable-hover')).toBeFalsy()
241
+ $(selector).filter(':first').trigger('mouseover.editable')
242
+ expect($(selector).filter(':first').hasClass('editable-hover')).toBeTruthy()
243
+ })
244
+ it("turns off editable hover class",function() {
245
+ expect($(selector).filter(':first').hasClass('editable-hover')).toBeFalsy()
246
+ $(selector).filter(':first').trigger('mouseover.editable')
247
+ expect($(selector).filter(':first').hasClass('editable-hover')).toBeTruthy()
248
+ $(selector).filter(':first').trigger('mouseout.editable')
249
+ expect($(selector).filter(':first').hasClass('editable-hover')).toBeFalsy()
250
+ })
251
+ })
252
+
253
+ describe("editable life-cycle",function() {
254
+
255
+ it("moves from editable to to completed to editable to completed to editable",function() {
256
+ // invariant:
257
+ // the selector always exists in the dom
258
+ //
259
+ // invariant:
260
+ // the selector must become and input on click
261
+ //
262
+ expect($(selector).size()).toBe(1)
263
+ expect($(selector).filter(':input').size()).toBe(0)
264
+ $(selector).filter(':first').trigger('click.editable')
265
+ expect($(selector).size()).toBe(1)
266
+ expect($(selector).filter(':input').size()).toBe(1)
267
+ $(selector).filter(':first').trigger('blur.editable')
268
+ expect($(selector).size()).toBe(1)
269
+ expect($(selector).filter(':input').size()).toBe(0)
270
+ $(selector).filter(':first').trigger('click.editable')
271
+ expect($(selector).size()).toBe(1)
272
+ expect($(selector).filter(':input').size()).toBe(1)
273
+ $(selector).filter(':first').trigger('blur.editable')
274
+ expect($(selector).size()).toBe(1)
275
+ expect($(selector).filter(':input').size()).toBe(0)
276
+ $(selector).filter(':first').trigger('click.editable')
277
+ expect($(selector).size()).toBe(1)
278
+ expect($(selector).filter(':input').size()).toBe(1)
279
+ })
280
+ })
281
+
282
+
283
+ describe("escape key", function() {
284
+ beforeEach(function() {
285
+ $(selector).filter(':first').trigger('click.editable')
286
+ // triffer ESC event
287
+ var e = jQuery.Event("keydown.editable", { keyCode: Editable.ESC_KEY })
288
+ $(selector).filter(':first').trigger(e)
289
+ })
290
+ describe("followed by a click",function() {
291
+ it("is an input",should_be_an_input_after_click)
292
+ })
293
+ })
294
+ })
295
+ })
296
+
297
+ describe("with multiple matches in dom",function() {
298
+ beforeEach(function(){
299
+ var fixture = "<div class='phrase'><span id='first' editable-resource-uri='http://s/r/i' class='text'>CAKE1</span></div>"
300
+ fixture += "<div class='phrase'><span id='second' editable-resource-uri='http://s/r/i' class='text'>CAKE2</span></div>"
301
+ fixture += "<div class='phrase'><span id='third' editable-resource-uri='http://s/r/i' class='text'>CAKE3</span></div>"
302
+ setFixtures(fixture)
303
+ });
304
+ describe("with editable declared",function() {
305
+ beforeEach(function() {
306
+ Editable(selector)
307
+ })
308
+ it("has a data editable-index",function() {
309
+ expect($(selector).filter('#first').attr("editable-index")).toEqual('1')
310
+ expect($(selector).filter('#second').attr("editable-index")).toEqual('2')
311
+ expect($(selector).filter('#third').attr("editable-index")).toEqual('3')
312
+
313
+ })
314
+ describe("editable life-cycle",function() {
315
+ describe("on editing node there is a keydown handler", function() {
316
+
317
+ describe("the esc key", function() {
318
+ it("returns the input to it's original value", function () {
319
+ // nothing if focused
320
+ expect($(selector).filter(':focus').size()).toBe(0)
321
+ $(selector).filter(':first').trigger('click.editable')
322
+ // #first becomes focused
323
+ expect($(selector).filter('#first').filter(':focus').size()).toBe(1)
324
+
325
+ var expected_value = $(selector).filter(':first').val()
326
+
327
+ // modify element value
328
+ $(selector).filter('#first').val("are you a kitty?")
329
+ // triffer ESC event
330
+ var e = jQuery.Event("keydown.editable", { keyCode: Editable.ESC_KEY })
331
+ $(selector).filter('#first').trigger(e)
332
+
333
+ expect($(selector).filter('#first').text()).toEqual(expected_value)
334
+
335
+ })
336
+ })
337
+
338
+ describe("the enter key",function() {
339
+ it("completes edit and moves to next editable", function () {
340
+ // nothing if focused
341
+ expect($(selector).filter(':focus').size()).toBe(0)
342
+ $(selector).filter(':first').trigger('click.editable')
343
+ // #first becomes focused
344
+ expect($(selector).filter('#first').filter(':focus').size()).toBe(1)
345
+ var e = jQuery.Event("keydown.editable", { keyCode: Editable.ENTER_KEY })
346
+ $(selector).filter(':first').trigger(e)
347
+
348
+ // #second becomes focused
349
+ expect($(selector).filter('#second').filter(':focus').size()).toBe(1)
350
+ // #second becomes input
351
+ expect($(selector).filter('#second').filter(':input').size()).toBe(1)
352
+ })
353
+ it("moves back to first editable after last", function () {
354
+ expect($(selector).filter(':focus').size()).toBe(0)
355
+
356
+ $(selector).filter('#third').trigger('click.editable')
357
+ expect($(selector).filter('#third').filter(':focus').size()).toBe(1)
358
+
359
+ var e = jQuery.Event("keydown.editable", { keyCode: Editable.ENTER_KEY })
360
+ $(selector).filter('#third').trigger(e)
361
+
362
+ expect($(selector).filter('#first').filter(':focus').size()).toBe(1)
363
+ expect($(selector).filter('#first').filter(':input').size()).toBe(1)
364
+ })
365
+ })
366
+ describe("the tab key",function() {
367
+ it("completes edit and moves to next editable", function () {
368
+ // nothing if focused
369
+ expect($(selector).filter(':focus').size()).toBe(0)
370
+ $(selector).filter(':first').trigger('click.editable')
371
+ // #first becomes focused
372
+ expect($(selector).filter('#first').filter(':focus').size()).toBe(1)
373
+ var e = jQuery.Event("keydown.editable", { keyCode: Editable.TAB_KEY })
374
+ $(selector).filter(':first').trigger(e)
375
+
376
+ // #second becomes focused
377
+ expect($(selector).filter('#second').filter(':focus').size()).toBe(1)
378
+ // #second becomes input
379
+ expect($(selector).filter('#second').filter(':input').size()).toBe(1)
380
+ })
381
+ it("moves back to first editable after last", function () {
382
+ expect($(selector).filter(':focus').size()).toBe(0)
383
+
384
+ $(selector).filter('#third').trigger('click.editable')
385
+ expect($(selector).filter('#third').filter(':focus').size()).toBe(1)
386
+
387
+ var e = jQuery.Event("keydown.editable", { keyCode: Editable.TAB_KEY })
388
+ $(selector).filter('#third').trigger(e)
389
+
390
+ expect($(selector).filter('#first').filter(':focus').size()).toBe(1)
391
+ expect($(selector).filter('#first').filter(':input').size()).toBe(1)
392
+ })
393
+ })
394
+ it("other keys do nothing", function () {
395
+ // nothing if focused
396
+ expect($(selector).filter(':focus').size()).toBe(0)
397
+ $(selector).filter(':first').trigger('click.editable')
398
+ // #first becomes focused
399
+ expect($(selector).filter('#first').filter(':focus').size()).toBe(1)
400
+ var e = jQuery.Event("keydown.editable", { keyCode: 99 })
401
+ $(selector).filter(':first').trigger(e)
402
+ // nothing changes - still only one
403
+ expect($(selector).filter(':input').size()).toBe(1)
404
+ // and it is the same one
405
+ expect($(selector).filter('#first').filter(':focus').size()).toBe(1)
406
+ })
407
+ })
408
+ })
409
+ })
410
+ })
411
+ })