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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +61 -0
- data/LICENSE +18 -17
- data/Rakefile +1 -1
- data/application/css/core.css.scss +1 -1
- data/application/css/dialogue.css.scss +8 -20
- data/application/js/preview.js +28 -7
- data/application/js/publish.js +15 -4
- data/application/js/top_bar.js +0 -16
- data/application/js/views/piece_view.js +1 -1
- data/lib/spontaneous/asset/environment.rb +16 -1
- data/lib/spontaneous/box.rb +68 -0
- data/lib/spontaneous/capistrano/deploy.rb +7 -4
- data/lib/spontaneous/capistrano/sync.rb +2 -2
- data/lib/spontaneous/cli/init.rb +70 -19
- data/lib/spontaneous/cli/init/db.rb +34 -55
- data/lib/spontaneous/cli/init/mysql.rb +5 -5
- data/lib/spontaneous/cli/init/postgresql.rb +8 -9
- data/lib/spontaneous/cli/init/sqlite.rb +1 -2
- data/lib/spontaneous/cli/migrate.rb +0 -1
- data/lib/spontaneous/cli/site.rb +4 -0
- data/lib/spontaneous/collections/entry_set.rb +11 -0
- data/lib/spontaneous/data_mapper/content_model.rb +2 -0
- data/lib/spontaneous/data_mapper/content_model/serialization.rb +2 -2
- data/lib/spontaneous/extensions/array.rb +12 -2
- data/lib/spontaneous/field/base.rb +10 -0
- data/lib/spontaneous/field/file.rb +32 -2
- data/lib/spontaneous/field/image.rb +24 -2
- data/lib/spontaneous/field/select.rb +8 -0
- data/lib/spontaneous/field/webvideo.rb +8 -0
- data/lib/spontaneous/generators/site/config/initializers/fields.rb +55 -0
- data/lib/spontaneous/json.rb +3 -2
- data/lib/spontaneous/logger.rb +2 -2
- data/lib/spontaneous/media/file.rb +3 -3
- data/lib/spontaneous/media/image/attributes.rb +72 -6
- data/lib/spontaneous/media/image/renderable.rb +53 -20
- data/lib/spontaneous/media/store.rb +3 -3
- data/lib/spontaneous/media/store/backend.rb +16 -0
- data/lib/spontaneous/media/store/cloud.rb +52 -12
- data/lib/spontaneous/media/store/local.rb +6 -3
- data/lib/spontaneous/model.rb +3 -0
- data/lib/spontaneous/model/core/entries.rb +34 -13
- data/lib/spontaneous/model/core/entry.rb +3 -1
- data/lib/spontaneous/model/page/controllers.rb +1 -2
- data/lib/spontaneous/model/page/paths.rb +18 -7
- data/lib/spontaneous/output/context.rb +0 -8
- data/lib/spontaneous/output/template/renderer.rb +2 -0
- data/lib/spontaneous/plugins/application/state.rb +0 -4
- data/lib/spontaneous/prototypes/field_prototype.rb +4 -0
- data/lib/spontaneous/publishing/immediate.rb +0 -5
- data/lib/spontaneous/publishing/progress.rb +2 -2
- data/lib/spontaneous/publishing/rerender.rb +1 -4
- data/lib/spontaneous/publishing/simultaneous.rb +19 -17
- data/lib/spontaneous/publishing/steps.rb +12 -3
- data/lib/spontaneous/rack.rb +2 -0
- data/lib/spontaneous/rack/asset_server.rb +5 -2
- data/lib/spontaneous/rack/back.rb +9 -1
- data/lib/spontaneous/rack/back/base.rb +1 -0
- data/lib/spontaneous/rack/back/changes.rb +5 -0
- data/lib/spontaneous/rack/back/preview.rb +4 -4
- data/lib/spontaneous/rack/back/private.rb +11 -0
- data/lib/spontaneous/rack/middleware/scope.rb +16 -4
- data/lib/spontaneous/rack/page_controller.rb +2 -2
- data/lib/spontaneous/rack/public.rb +52 -4
- data/lib/spontaneous/sequel.rb +10 -13
- data/lib/spontaneous/site.rb +28 -8
- data/lib/spontaneous/site/publishing.rb +1 -1
- data/lib/spontaneous/site/storage.rb +7 -4
- data/lib/spontaneous/tasks/environment.rake +3 -0
- data/lib/spontaneous/utils/database/postgres_dumper.rb +23 -2
- data/lib/spontaneous/version.rb +1 -1
- data/spontaneous.gemspec +7 -12
- data/test/fixtures/assets/public1/css/data.css.scss +1 -1
- data/test/functional/test_application.rb +15 -0
- data/test/functional/test_cli.rb +109 -3
- data/test/functional/test_front.rb +108 -10
- data/test/test_helper.rb +3 -3
- data/test/unit/fields/test_boolean_fields.rb +80 -0
- data/test/unit/fields/test_date_fields.rb +47 -0
- data/test/unit/fields/test_file_field.rb +210 -0
- data/test/unit/{test_images.rb → fields/test_image_fields.rb} +133 -15
- data/test/unit/fields/test_location_fields.rb +41 -0
- data/test/unit/fields/test_option_fields.rb +61 -0
- data/test/unit/fields/test_tag_list_fields.rb +45 -0
- data/test/unit/fields/test_text_fields.rb +124 -0
- data/test/unit/fields/test_web_video_fields.rb +198 -0
- data/test/unit/test_assets.rb +22 -22
- data/test/unit/test_boxes.rb +34 -13
- data/test/unit/test_changesets.rb +1 -0
- data/test/unit/test_extensions.rb +17 -0
- data/test/unit/test_fields.rb +20 -643
- data/test/unit/test_media.rb +9 -9
- data/test/unit/test_page.rb +47 -0
- data/test/unit/test_publishing_pipeline.rb +2 -2
- data/test/unit/test_serialisation.rb +37 -0
- data/test/unit/test_storage.rb +42 -3
- 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&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
|