spontaneous 0.2.0.beta9 → 0.2.0.beta10

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.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +61 -0
  3. data/LICENSE +18 -17
  4. data/Rakefile +1 -1
  5. data/application/css/core.css.scss +1 -1
  6. data/application/css/dialogue.css.scss +8 -20
  7. data/application/js/preview.js +28 -7
  8. data/application/js/publish.js +15 -4
  9. data/application/js/top_bar.js +0 -16
  10. data/application/js/views/piece_view.js +1 -1
  11. data/lib/spontaneous/asset/environment.rb +16 -1
  12. data/lib/spontaneous/box.rb +68 -0
  13. data/lib/spontaneous/capistrano/deploy.rb +7 -4
  14. data/lib/spontaneous/capistrano/sync.rb +2 -2
  15. data/lib/spontaneous/cli/init.rb +70 -19
  16. data/lib/spontaneous/cli/init/db.rb +34 -55
  17. data/lib/spontaneous/cli/init/mysql.rb +5 -5
  18. data/lib/spontaneous/cli/init/postgresql.rb +8 -9
  19. data/lib/spontaneous/cli/init/sqlite.rb +1 -2
  20. data/lib/spontaneous/cli/migrate.rb +0 -1
  21. data/lib/spontaneous/cli/site.rb +4 -0
  22. data/lib/spontaneous/collections/entry_set.rb +11 -0
  23. data/lib/spontaneous/data_mapper/content_model.rb +2 -0
  24. data/lib/spontaneous/data_mapper/content_model/serialization.rb +2 -2
  25. data/lib/spontaneous/extensions/array.rb +12 -2
  26. data/lib/spontaneous/field/base.rb +10 -0
  27. data/lib/spontaneous/field/file.rb +32 -2
  28. data/lib/spontaneous/field/image.rb +24 -2
  29. data/lib/spontaneous/field/select.rb +8 -0
  30. data/lib/spontaneous/field/webvideo.rb +8 -0
  31. data/lib/spontaneous/generators/site/config/initializers/fields.rb +55 -0
  32. data/lib/spontaneous/json.rb +3 -2
  33. data/lib/spontaneous/logger.rb +2 -2
  34. data/lib/spontaneous/media/file.rb +3 -3
  35. data/lib/spontaneous/media/image/attributes.rb +72 -6
  36. data/lib/spontaneous/media/image/renderable.rb +53 -20
  37. data/lib/spontaneous/media/store.rb +3 -3
  38. data/lib/spontaneous/media/store/backend.rb +16 -0
  39. data/lib/spontaneous/media/store/cloud.rb +52 -12
  40. data/lib/spontaneous/media/store/local.rb +6 -3
  41. data/lib/spontaneous/model.rb +3 -0
  42. data/lib/spontaneous/model/core/entries.rb +34 -13
  43. data/lib/spontaneous/model/core/entry.rb +3 -1
  44. data/lib/spontaneous/model/page/controllers.rb +1 -2
  45. data/lib/spontaneous/model/page/paths.rb +18 -7
  46. data/lib/spontaneous/output/context.rb +0 -8
  47. data/lib/spontaneous/output/template/renderer.rb +2 -0
  48. data/lib/spontaneous/plugins/application/state.rb +0 -4
  49. data/lib/spontaneous/prototypes/field_prototype.rb +4 -0
  50. data/lib/spontaneous/publishing/immediate.rb +0 -5
  51. data/lib/spontaneous/publishing/progress.rb +2 -2
  52. data/lib/spontaneous/publishing/rerender.rb +1 -4
  53. data/lib/spontaneous/publishing/simultaneous.rb +19 -17
  54. data/lib/spontaneous/publishing/steps.rb +12 -3
  55. data/lib/spontaneous/rack.rb +2 -0
  56. data/lib/spontaneous/rack/asset_server.rb +5 -2
  57. data/lib/spontaneous/rack/back.rb +9 -1
  58. data/lib/spontaneous/rack/back/base.rb +1 -0
  59. data/lib/spontaneous/rack/back/changes.rb +5 -0
  60. data/lib/spontaneous/rack/back/preview.rb +4 -4
  61. data/lib/spontaneous/rack/back/private.rb +11 -0
  62. data/lib/spontaneous/rack/middleware/scope.rb +16 -4
  63. data/lib/spontaneous/rack/page_controller.rb +2 -2
  64. data/lib/spontaneous/rack/public.rb +52 -4
  65. data/lib/spontaneous/sequel.rb +10 -13
  66. data/lib/spontaneous/site.rb +28 -8
  67. data/lib/spontaneous/site/publishing.rb +1 -1
  68. data/lib/spontaneous/site/storage.rb +7 -4
  69. data/lib/spontaneous/tasks/environment.rake +3 -0
  70. data/lib/spontaneous/utils/database/postgres_dumper.rb +23 -2
  71. data/lib/spontaneous/version.rb +1 -1
  72. data/spontaneous.gemspec +7 -12
  73. data/test/fixtures/assets/public1/css/data.css.scss +1 -1
  74. data/test/functional/test_application.rb +15 -0
  75. data/test/functional/test_cli.rb +109 -3
  76. data/test/functional/test_front.rb +108 -10
  77. data/test/test_helper.rb +3 -3
  78. data/test/unit/fields/test_boolean_fields.rb +80 -0
  79. data/test/unit/fields/test_date_fields.rb +47 -0
  80. data/test/unit/fields/test_file_field.rb +210 -0
  81. data/test/unit/{test_images.rb → fields/test_image_fields.rb} +133 -15
  82. data/test/unit/fields/test_location_fields.rb +41 -0
  83. data/test/unit/fields/test_option_fields.rb +61 -0
  84. data/test/unit/fields/test_tag_list_fields.rb +45 -0
  85. data/test/unit/fields/test_text_fields.rb +124 -0
  86. data/test/unit/fields/test_web_video_fields.rb +198 -0
  87. data/test/unit/test_assets.rb +22 -22
  88. data/test/unit/test_boxes.rb +34 -13
  89. data/test/unit/test_changesets.rb +1 -0
  90. data/test/unit/test_extensions.rb +17 -0
  91. data/test/unit/test_fields.rb +20 -643
  92. data/test/unit/test_media.rb +9 -9
  93. data/test/unit/test_page.rb +47 -0
  94. data/test/unit/test_publishing_pipeline.rb +2 -2
  95. data/test/unit/test_serialisation.rb +37 -0
  96. data/test/unit/test_storage.rb +42 -3
  97. metadata +37 -17
@@ -0,0 +1,41 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path('../../../test_helper', __FILE__)
4
+
5
+
6
+ describe "Location fields" do
7
+ before do
8
+ @site = setup_site
9
+ @now = Time.now
10
+ stub_time(@now)
11
+ Spontaneous::State.delete
12
+ @site.background_mode = :immediate
13
+ @content_class = Class.new(::Piece) do
14
+ field :location
15
+ end
16
+ @content_class.stubs(:name).returns("ContentClass")
17
+ @instance = @content_class.new
18
+ @field = @instance.location
19
+ end
20
+
21
+ it "use a standard string editor" do
22
+ @content_class.fields.location.export(nil)[:type].must_equal "Spontaneous.Field.String"
23
+ end
24
+
25
+ it "successfully geolocate an address" do
26
+ # TODO: use mocking to avoid an external API request to googles geolocation service
27
+ @field.value = "Cambridge, England"
28
+ @field.value(:lat).must_equal 52.2053370
29
+ @field.value(:lng).must_equal 0.1218170
30
+ @field.value(:country).must_equal "United Kingdom"
31
+ @field.value(:formatted_address).must_equal "Cambridge, Cambridge, UK"
32
+
33
+ @field.latitude.must_equal 52.2053370
34
+ @field.longitude.must_equal 0.1218170
35
+ @field.lat.must_equal 52.2053370
36
+ @field.lng.must_equal 0.1218170
37
+
38
+ @field.country.must_equal "United Kingdom"
39
+ @field.formatted_address.must_equal "Cambridge, Cambridge, UK"
40
+ end
41
+ end
@@ -0,0 +1,61 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path('../../../test_helper', __FILE__)
4
+
5
+ describe "Option fields" do
6
+ before do
7
+ @site = setup_site
8
+ @now = Time.now
9
+ stub_time(@now)
10
+ Spontaneous::State.delete
11
+ @site.background_mode = :immediate
12
+ @content_class = Class.new(::Piece) do
13
+ field :options, :select, :options => [
14
+ ["a", "Value A"],
15
+ ["b", "Value B"],
16
+ ["c", "Value C"]
17
+ ]
18
+ end
19
+ @content_class.stubs(:name).returns("ContentClass")
20
+ @instance = @content_class.new
21
+ @field = @instance.options
22
+ end
23
+
24
+ it "use a specific editor class" do
25
+ @content_class.fields.options.export(nil)[:type].must_equal "Spontaneous.Field.Select"
26
+ end
27
+
28
+ it "select the options class for fields named options" do
29
+ @content_class.field :type, :select, :options => [["a", "A"]]
30
+ assert @content_class.fields.options.instance_class.ancestors.include?(Spontaneous::Field::Select)
31
+ end
32
+
33
+ it "accept a list of strings as options" do
34
+ @content_class.field :type, :select, :options => ["a", "b"]
35
+ @instance = @content_class.new
36
+ @instance.type.option_list.must_equal [["a", "a"], ["b", "b"]]
37
+ end
38
+
39
+ it "accept a json string as a value and convert it properly" do
40
+ @field.value = %(["a", "Value A"])
41
+ @field.value.must_equal "a"
42
+ @field.value(:label).must_equal "Value A"
43
+ @field.label.must_equal "Value A"
44
+ @field.unprocessed_value.must_equal %(["a", "Value A"])
45
+ end
46
+
47
+ it 'allows for the setting of a default value' do
48
+ @content_class.field :type, :select, :options => [["a", "A Label"], ["b", "B Label"], ["c", "C Label"]], default: "b"
49
+ @instance = @content_class.new
50
+ @instance.type.value.must_equal "b"
51
+ @instance.type.value(:label).must_equal "B Label"
52
+ end
53
+
54
+ it 'exports properly with a null value' do
55
+ @content_class.field :type, :select, :options => [["a", "A Label"], ["b", "B Label"], ["c", "C Label"]]
56
+ @instance = @content_class.new
57
+ e = @instance.fields[:type].export(nil)
58
+ e[:unprocessed_value].must_equal ""
59
+ e[:processed_value].must_equal ""
60
+ end
61
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path('../../../test_helper', __FILE__)
4
+
5
+ describe "Tag list fields" do
6
+ before do
7
+ @site = setup_site
8
+ @now = Time.now
9
+ stub_time(@now)
10
+ Spontaneous::State.delete
11
+ @site.background_mode = :immediate
12
+ @content_class = Class.new(::Piece)
13
+ @prototype = @content_class.field :tags
14
+ @content_class.stubs(:name).returns("ContentClass")
15
+ @instance = @content_class.create
16
+ @field = @instance.tags
17
+ end
18
+
19
+ it "has a distinct editor class" # eventually...
20
+
21
+ it "adopts any field called 'tags'" do
22
+ assert @field.is_a?(Spontaneous::Field::Tags), "Field should be an instance of TagsField but instead has the following ancestors #{ @prototype.instance_class.ancestors }"
23
+ end
24
+
25
+ it "defaults to an empty list" do
26
+ @field.value(:html).must_equal ""
27
+ @field.value(:tags).must_equal []
28
+ end
29
+
30
+ it "correctly parses strings" do
31
+ @field.value = 'this that "the other" more'
32
+ @field.value(:html).must_equal 'this that "the other" more'
33
+ @field.value(:tags).must_equal ["this", "that", "the other", "more"]
34
+ end
35
+
36
+ it "includes Enumerable" do
37
+ @field.value = 'this that "the other" more'
38
+ @field.map(&:upcase).must_equal ["THIS", "THAT", "THE OTHER", "MORE"]
39
+ end
40
+
41
+ it "allows for tags with commas" do
42
+ @field.value = %(this that "the, other" more)
43
+ @field.map(&:upcase).must_equal ["THIS", "THAT", "THE, OTHER", "MORE"]
44
+ end
45
+ end
@@ -0,0 +1,124 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path('../../../test_helper', __FILE__)
4
+
5
+ describe "Text fields" do
6
+ before do
7
+ @site = setup_site
8
+ @now = Time.now
9
+ stub_time(@now)
10
+ Spontaneous::State.delete
11
+ @site.background_mode = :immediate
12
+ end
13
+
14
+ after do
15
+ teardown_site
16
+ end
17
+ describe "String fields" do
18
+ before do
19
+ @content_class = Class.new(::Piece) do
20
+ field :title, :string
21
+ end
22
+ @instance = @content_class.new
23
+ @field = @instance.title
24
+ end
25
+
26
+ it "should escape ampersands for the html format" do
27
+ @field.value = "This & That"
28
+ @field.value(:html).must_equal "This & That"
29
+ end
30
+
31
+ it "be aliased to the :title type" do
32
+ @content_class = Class.new(::Piece) do
33
+ field :title, default: "Right"
34
+ field :something, :title
35
+ end
36
+ instance = @content_class.new
37
+ assert instance.fields.title.class.ancestors.include?(Spontaneous::Field::String), ":title type should inherit from StringField"
38
+ instance.title.value.must_equal "Right"
39
+ end
40
+ end
41
+ describe "Markdown fields" do
42
+ before do
43
+ class ::MarkdownContent < Piece
44
+ field :text1, :markdown
45
+ field :text2, :richtext
46
+ field :text3, :markup
47
+ end
48
+ @instance = MarkdownContent.new
49
+ end
50
+ after do
51
+ Object.send(:remove_const, :MarkdownContent)
52
+ end
53
+
54
+ it "be available as the :markdown type" do
55
+ assert MarkdownContent.field_prototypes[:text1].field_class < Spontaneous::Field::Markdown
56
+ end
57
+ it "be available as the :richtext type" do
58
+ assert MarkdownContent.field_prototypes[:text2].field_class < Spontaneous::Field::Markdown
59
+ end
60
+ it "be available as the :markup type" do
61
+ assert MarkdownContent.field_prototypes[:text3].field_class < Spontaneous::Field::Markdown
62
+ end
63
+
64
+ it "process input into HTML" do
65
+ @instance.text1 = "*Hello* **World**"
66
+ @instance.text1.value.must_equal "<p><em>Hello</em> <strong>World</strong></p>\n"
67
+ end
68
+
69
+ it "use more sensible linebreaks" do
70
+ @instance.text1 = "With\nLinebreak"
71
+ @instance.text1.value.must_equal "<p>With<br />\nLinebreak</p>\n"
72
+ @instance.text2 = "With \nLinebreak"
73
+ @instance.text2.value.must_equal "<p>With<br />\nLinebreak</p>\n"
74
+ end
75
+ end
76
+
77
+ describe "LongString fields" do
78
+ before do
79
+ class ::LongStringContent < Piece
80
+ field :long1, :longstring
81
+ field :long2, :long_string
82
+ field :long3, :text
83
+ end
84
+ @instance = LongStringContent.new
85
+ end
86
+ after do
87
+ Object.send(:remove_const, :LongStringContent)
88
+ end
89
+
90
+ it "is available as the :longstring type" do
91
+ assert LongStringContent.field_prototypes[:long1].field_class < Spontaneous::Field::LongString
92
+ end
93
+
94
+ it "is available as the :long_string type" do
95
+ assert LongStringContent.field_prototypes[:long2].field_class < Spontaneous::Field::LongString
96
+ end
97
+
98
+ it "is available as the :text type" do
99
+ assert LongStringContent.field_prototypes[:long3].field_class < Spontaneous::Field::LongString
100
+ end
101
+
102
+ it "translates newlines to <br/> tags" do
103
+ @instance.long1 = "this\nlong\nstring"
104
+ @instance.long1.value.must_equal "this<br />\nlong<br />\nstring"
105
+ end
106
+ end
107
+
108
+ describe "HTML fields" do
109
+ before do
110
+ @content_class = Class.new(::Piece) do
111
+ field :raw, :html
112
+ end
113
+ @content_class.stubs(:name).returns("ContentClass")
114
+ @instance = @content_class.new
115
+ @field = @instance.raw
116
+ end
117
+
118
+ it "does no escaping of input" do
119
+ @field.value = "<script>\n</script>"
120
+ @field.value(:html).must_equal "<script>\n</script>"
121
+ end
122
+ end
123
+
124
+ end
@@ -0,0 +1,198 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path('../../../test_helper', __FILE__)
4
+
5
+ describe "WebVideo fields" do
6
+ before do
7
+ @site = setup_site
8
+ @now = Time.now
9
+ stub_time(@now)
10
+ Spontaneous::State.delete
11
+ @site.background_mode = :immediate
12
+ @content_class = Class.new(::Piece) do
13
+ field :video, :webvideo
14
+ end
15
+ @content_class.stubs(:name).returns("ContentClass")
16
+ @instance = @content_class.new
17
+ @field = @instance.video
18
+ end
19
+
20
+ after do
21
+ teardown_site
22
+ end
23
+
24
+ it "have their own editor type" do
25
+ @content_class.fields.video.export(nil)[:type].must_equal "Spontaneous.Field.WebVideo"
26
+ @instance.video = "http://www.youtube.com/watch?v=_0jroAM_pO4&feature=feedrec_grec_index"
27
+ fields = @instance.export(nil)[:fields]
28
+ fields[0][:processed_value].must_equal @instance.video.src
29
+ end
30
+
31
+ it "recognise youtube URLs" do
32
+ @instance.video = "http://www.youtube.com/watch?v=_0jroAM_pO4&feature=feedrec_grec_index"
33
+ @instance.video.value.must_equal "http://www.youtube.com/watch?v=_0jroAM_pO4&amp;feature=feedrec_grec_index"
34
+ @instance.video.video_id.must_equal "_0jroAM_pO4"
35
+ @instance.video.provider_id.must_equal "youtube"
36
+ end
37
+
38
+ it "recognise Vimeo URLs" do
39
+ @instance.video = "http://vimeo.com/31836285"
40
+ @instance.video.value.must_equal "http://vimeo.com/31836285"
41
+ @instance.video.video_id.must_equal "31836285"
42
+ @instance.video.provider_id.must_equal "vimeo"
43
+ end
44
+
45
+ it "recognise Vine URLs" do
46
+ @instance.video = "https://vine.co/v/brI7pTPb3qU"
47
+ @instance.video.value.must_equal "https://vine.co/v/brI7pTPb3qU"
48
+ @instance.video.video_id.must_equal "brI7pTPb3qU"
49
+ @instance.video.provider_id.must_equal "vine"
50
+ end
51
+
52
+ it "silently handles unknown providers" do
53
+ @instance.video = "https://idontdovideo.com/video?id=brI7pTPb3qU"
54
+ @instance.video.value.must_equal "https://idontdovideo.com/video?id=brI7pTPb3qU"
55
+ @instance.video.video_id.must_equal "https://idontdovideo.com/video?id=brI7pTPb3qU"
56
+ @instance.video.provider_id.must_equal nil
57
+ end
58
+
59
+
60
+ it "use the YouTube api to extract video metadata" do
61
+ youtube_info = {"thumbnail_large" => "http://i.ytimg.com/vi/_0jroAM_pO4/hqdefault.jpg", "thumbnail_small"=>"http://i.ytimg.com/vi/_0jroAM_pO4/default.jpg", "title" => "Hilarious QI Moment - Cricket", "description" => "Rob Brydon makes a rather embarassing choice of words whilst discussing the relationship between a cricket's chirping and the temperature. Taken from QI XL Series H episode 11 - Highs and Lows", "user_name" => "morthasa", "upload_date" => "2011-01-14 19:49:44", "tags" => "Hilarious, QI, Moment, Cricket, fun, 11, stephen, fry, alan, davies, Rob, Brydon, SeriesH, Fred, MacAulay, Sandi, Toksvig", "duration" => 78, "stats_number_of_likes" => 297, "stats_number_of_plays" => 53295, "stats_number_of_comments" => 46}#.symbolize_keys
62
+
63
+ response_xml_file = File.expand_path("../../../fixtures/fields/youtube_api_response.xml", __FILE__)
64
+ connection = mock()
65
+ Spontaneous::Field::WebVideo::YouTube.any_instance.expects(:open).with("http://gdata.youtube.com/feeds/api/videos/_0jroAM_pO4?v=2").returns(connection)
66
+ doc = Nokogiri::XML(File.open(response_xml_file))
67
+ Nokogiri.expects(:XML).with(connection).returns(doc)
68
+ @field.value = "http://www.youtube.com/watch?v=_0jroAM_pO4"
69
+ @field.values.must_equal youtube_info.merge(:video_id => "_0jroAM_pO4", :provider => "youtube", :html => "http://www.youtube.com/watch?v=_0jroAM_pO4")
70
+ end
71
+
72
+ it "use the Vimeo api to extract video metadata" do
73
+ vimeo_info = {"id"=>29987529, "title"=>"Neon Indian Plays The UO Music Shop", "description"=>"Neon Indian plays electronic instruments from the UO Music Shop, Fall 2011. Read more at blog.urbanoutfitters.com.", "url"=>"http://vimeo.com/29987529", "upload_date"=>"2011-10-03 18:32:47", "mobile_url"=>"http://vimeo.com/m/29987529", "thumbnail_small"=>"http://b.vimeocdn.com/ts/203/565/203565974_100.jpg", "thumbnail_medium"=>"http://b.vimeocdn.com/ts/203/565/203565974_200.jpg", "thumbnail_large"=>"http://b.vimeocdn.com/ts/203/565/203565974_640.jpg", "user_name"=>"Urban Outfitters", "user_url"=>"http://vimeo.com/urbanoutfitters", "user_portrait_small"=>"http://b.vimeocdn.com/ps/251/111/2511118_30.jpg", "user_portrait_medium"=>"http://b.vimeocdn.com/ps/251/111/2511118_75.jpg", "user_portrait_large"=>"http://b.vimeocdn.com/ps/251/111/2511118_100.jpg", "user_portrait_huge"=>"http://b.vimeocdn.com/ps/251/111/2511118_300.jpg", "stats_number_of_likes"=>85, "stats_number_of_plays"=>26633, "stats_number_of_comments"=>0, "duration"=>100, "width"=>1280, "height"=>360, "tags"=>"neon indian, analog, korg, moog, theremin, micropiano, microkorg, kaossilator, kaossilator pro", "embed_privacy"=>"anywhere"}.symbolize_keys
74
+
75
+ connection = mock()
76
+ connection.expects(:read).returns(Spontaneous.encode_json([vimeo_info]))
77
+ Spontaneous::Field::WebVideo::Vimeo.any_instance.expects(:open).with("http://vimeo.com/api/v2/video/29987529.json").returns(connection)
78
+ @field.value = "http://vimeo.com/29987529"
79
+ @field.values.must_equal vimeo_info.merge(:video_id => "29987529", :provider => "vimeo", :html => "http://vimeo.com/29987529")
80
+ end
81
+
82
+ describe "with player settings" do
83
+ before do
84
+ @content_class.field :video2, :webvideo, :player => {
85
+ :width => 680, :height => 384,
86
+ :fullscreen => true, :autoplay => true, :loop => true,
87
+ :showinfo => false,
88
+ :youtube => { :theme => 'light', :hd => true, :controls => false },
89
+ :vimeo => { :color => "ccc", :api => true }
90
+ }
91
+ @instance = @content_class.new
92
+ @field = @instance.video2
93
+ end
94
+
95
+ it "use the configuration in the youtube player HTML" do
96
+ @field.value = "http://www.youtube.com/watch?v=_0jroAM_pO4&feature=feedrec_grec_index"
97
+ html = @field.render(:html)
98
+ html.must_match /^<iframe/
99
+ html.must_match %r{src="//www\.youtube\.com/embed/_0jroAM_pO4}
100
+ html.must_match /width="680"/
101
+ html.must_match /height="384"/
102
+ html.must_match /theme=light/
103
+ html.must_match /hd=1/
104
+ html.must_match /fs=1/
105
+ html.must_match /controls=0/
106
+ html.must_match /autoplay=1/
107
+ html.must_match /showinfo=0/
108
+ html.must_match /showsearch=0/
109
+ @field.render(:html, :youtube => {:showsearch => 1}).must_match /showsearch=1/
110
+ @field.render(:html, :youtube => {:theme => 'dark'}).must_match /theme=dark/
111
+ @field.render(:html, :width => 100).must_match /width="100"/
112
+ @field.render(:html, :loop => true).must_match /loop=1/
113
+ end
114
+
115
+ it "use the configuration in the Vimeo player HTML" do
116
+ @field.value = "http://vimeo.com/31836285"
117
+ html = @field.render(:html)
118
+ html.must_match /^<iframe/
119
+ html.must_match %r{src="//player\.vimeo\.com/video/31836285}
120
+ html.must_match /width="680"/
121
+ html.must_match /height="384"/
122
+ html.must_match /color=ccc/
123
+ html.must_match /webkitAllowFullScreen="yes"/
124
+ html.must_match /allowFullScreen="yes"/
125
+ html.must_match /autoplay=1/
126
+ html.must_match /title=0/
127
+ html.must_match /byline=0/
128
+ html.must_match /portrait=0/
129
+ html.must_match /api=1/
130
+ @field.render(:html, :vimeo => {:color => 'f0abcd'}).must_match /color=f0abcd/
131
+ @field.render(:html, :loop => true).must_match /loop=1/
132
+ @field.render(:html, :title => true).must_match /title=1/
133
+ @field.render(:html, :title => true).must_match /byline=0/
134
+ end
135
+
136
+ it "provide a version of the YouTube player params in JSON/JS format" do
137
+ @field.value = "http://www.youtube.com/watch?v=_0jroAM_pO4&feature=feedrec_grec_index"
138
+ json = Spontaneous::JSON.parse(@field.render(:json))
139
+ json[:"tagname"].must_equal "iframe"
140
+ json[:"tag"].must_equal "<iframe/>"
141
+ attr = json[:"attr"]
142
+ attr.must_be_instance_of(Hash)
143
+ attr[:"src"].must_match %r{^//www\.youtube\.com/embed/_0jroAM_pO4}
144
+ attr[:"src"].must_match /theme=light/
145
+ attr[:"src"].must_match /hd=1/
146
+ attr[:"src"].must_match /fs=1/
147
+ attr[:"src"].must_match /controls=0/
148
+ attr[:"src"].must_match /autoplay=1/
149
+ attr[:"src"].must_match /showinfo=0/
150
+ attr[:"src"].must_match /showsearch=0/
151
+ attr[:"width"].must_equal 680
152
+ attr[:"height"].must_equal 384
153
+ attr[:"frameborder"].must_equal "0"
154
+ attr[:"type"].must_equal "text/html"
155
+ end
156
+
157
+ it "provide a version of the Vimeo player params in JSON/JS format" do
158
+ @field.value = "http://vimeo.com/31836285"
159
+ json = Spontaneous::JSON.parse(@field.render(:json))
160
+ json[:"tagname"].must_equal "iframe"
161
+ json[:"tag"].must_equal "<iframe/>"
162
+ attr = json[:"attr"]
163
+ attr.must_be_instance_of(Hash)
164
+ attr[:"src"].must_match /color=ccc/
165
+ attr[:"src"].must_match /autoplay=1/
166
+ attr[:"src"].must_match /title=0/
167
+ attr[:"src"].must_match /byline=0/
168
+ attr[:"src"].must_match /portrait=0/
169
+ attr[:"src"].must_match /api=1/
170
+ attr[:"webkitAllowFullScreen"].must_equal "yes"
171
+ attr[:"allowFullScreen"].must_equal "yes"
172
+ attr[:"width"].must_equal 680
173
+ attr[:"height"].must_equal 384
174
+ attr[:"frameborder"].must_equal "0"
175
+ attr[:"type"].must_equal "text/html"
176
+ end
177
+
178
+
179
+ it "can properly embed a Vine video" do
180
+ @field.value = "https://vine.co/v/brI7pTPb3qU"
181
+ embed = @field.render(:html)
182
+ embed.must_match %r(iframe)
183
+ embed.must_match %r(src=["']//vine\.co/v/brI7pTPb3qU/card["'])
184
+ # Vine videos are square
185
+ embed.must_match %r(width=["']680["'])
186
+ embed.must_match %r(height=["']680["'])
187
+ end
188
+
189
+ it "falls back to a simple iframe for unknown providers xxx" do
190
+ @field.value = "https://unknownprovider.net/xx/brI7pTPb3qU"
191
+ embed = @field.render(:html)
192
+ embed.must_match %r(iframe)
193
+ embed.must_match %r(src=["']https://unknownprovider.net/xx/brI7pTPb3qU["'])
194
+ embed.must_match %r(width=["']680["'])
195
+ embed.must_match %r(height=["']384["'])
196
+ end
197
+ end
198
+ end