refinerycms-videojs 0.5.5

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 (45) hide show
  1. data/app/assets/images/refinery/admin/add_video_icon.png +0 -0
  2. data/app/assets/javascripts/refinery/admin/wymeditor_monkeypatch.js +13 -0
  3. data/app/assets/stylesheets/refinery/admin/video.css +95 -0
  4. data/app/controllers/refinery/videos/admin/video_files_controller.rb +16 -0
  5. data/app/controllers/refinery/videos/admin/videos_controller.rb +59 -0
  6. data/app/models/refinery/videos/video.rb +119 -0
  7. data/app/models/refinery/videos/video_file.rb +63 -0
  8. data/app/views/refinery/admin/dashboard/_additional_dashboard_menu_items.html.erb +4 -0
  9. data/app/views/refinery/videos/admin/videos/_actions.html.erb +23 -0
  10. data/app/views/refinery/videos/admin/videos/_embed_video_fields.html.erb +45 -0
  11. data/app/views/refinery/videos/admin/videos/_file_fields.html.erb +94 -0
  12. data/app/views/refinery/videos/admin/videos/_form.html.erb +44 -0
  13. data/app/views/refinery/videos/admin/videos/_form_option_fields.html.erb +17 -0
  14. data/app/views/refinery/videos/admin/videos/_new_file_field.html.erb +75 -0
  15. data/app/views/refinery/videos/admin/videos/_preview_form.html.erb +16 -0
  16. data/app/views/refinery/videos/admin/videos/_records.html.erb +18 -0
  17. data/app/views/refinery/videos/admin/videos/_sortable_list.html.erb +5 -0
  18. data/app/views/refinery/videos/admin/videos/_video.html.erb +23 -0
  19. data/app/views/refinery/videos/admin/videos/_videojs_dependencies.html.erb +2 -0
  20. data/app/views/refinery/videos/admin/videos/_videos.html.erb +2 -0
  21. data/app/views/refinery/videos/admin/videos/append_to_wym.js.erb +4 -0
  22. data/app/views/refinery/videos/admin/videos/dialog_preview.js.erb +2 -0
  23. data/app/views/refinery/videos/admin/videos/edit.html.erb +1 -0
  24. data/app/views/refinery/videos/admin/videos/index.html.erb +7 -0
  25. data/app/views/refinery/videos/admin/videos/insert.html.erb +34 -0
  26. data/app/views/refinery/videos/admin/videos/new.html.erb +3 -0
  27. data/app/views/refinery/videos/admin/videos/show.html.erb +4 -0
  28. data/app/views/sitemap/index.xml.builder +25 -0
  29. data/config/initializers/refinery/core.rb +11 -0
  30. data/config/locales/en.yml +76 -0
  31. data/config/locales/ru.yml +77 -0
  32. data/config/routes.rb +24 -0
  33. data/db/migrate/1_create_videos_videos.rb +29 -0
  34. data/db/migrate/2_create_video_file.rb +25 -0
  35. data/lib/generators/refinery/videos/templates/assets/javascripts/videojs_loader.js +7 -0
  36. data/lib/generators/refinery/videos/templates/config/initializers/refinery/videos.rb.erb +20 -0
  37. data/lib/generators/refinery/videos_generator.rb +18 -0
  38. data/lib/refinery/videos/configuration.rb +42 -0
  39. data/lib/refinery/videos/dragonfly.rb +53 -0
  40. data/lib/refinery/videos/engine.rb +32 -0
  41. data/lib/refinery/videos/validators/file_size_validator.rb +19 -0
  42. data/lib/refinery/videos/validators.rb +7 -0
  43. data/lib/refinery/videos.rb +28 -0
  44. data/lib/refinerycms-videojs.rb +1 -0
  45. metadata +138 -0
@@ -0,0 +1,13 @@
1
+ $insert_video_link = "<ul id='add_video'><li><a href='/refinery/videos/insert?dialog=true'>Add Video</a></li></ul>";
2
+ window.onload = function ()
3
+ {
4
+ if ($.wymeditors(0)) {
5
+ $('.wym_area_top').append($insert_video_link);
6
+ init_modal_dialogs();
7
+ }
8
+ };
9
+
10
+ onCloseDialog = function(){
11
+ $('iframe#dialog_iframe').attr('src', '');
12
+ };
13
+
@@ -0,0 +1,95 @@
1
+ #add_video {
2
+ padding-top: 3px;
3
+ padding-left: 10px
4
+ }
5
+
6
+ #add_video li a{
7
+ height: 20px;
8
+ background-image: url('/assets/refinery/admin/add_video_icon.png');
9
+ background-repeat: no-repeat;
10
+ padding-left: 20px;
11
+ }
12
+
13
+ label.inline{
14
+ display: inline-block;
15
+ margin-bottom: 10px;
16
+ margin-top: 0
17
+ }
18
+
19
+ div.inline{
20
+ display: inline-block;
21
+ vertical-align: top;
22
+ margin: 1px 10px 0 0;
23
+ padding-left: 5px
24
+ }
25
+
26
+ div.parent{
27
+ margin-bottom: 20px
28
+ }
29
+
30
+ div.video_container{
31
+ margin: 10px;
32
+ }
33
+
34
+ div.tips{
35
+ margin: 10px 0 10px 0;
36
+ font-style: italic;
37
+ }
38
+
39
+ div.use_file{
40
+ padding-bottom: 5px;
41
+ padding-top: 2px;
42
+ }
43
+ a.select_video_type{
44
+ font-size: 12px;
45
+ margin: 10px 10px 10px 0
46
+ }
47
+
48
+ a.select_video_type.selected{
49
+ font-weight: bold;}
50
+
51
+
52
+ textarea.embed_tag{
53
+ height: 100px
54
+ }
55
+
56
+ span.short_info{
57
+ color: grey
58
+ }
59
+
60
+ div.add_remove_buttons{
61
+ margin-top: 10px
62
+ }
63
+
64
+ div#dialog_list{
65
+ width: 60%; float: left; min-height: 300px
66
+ }
67
+
68
+ div#dialog_list li.selected{
69
+ border: 4px solid #22A7F2
70
+ }
71
+
72
+ div#dialog_preview{
73
+ width:35%; float: right
74
+ }
75
+
76
+ div#preview_form{
77
+ width:35%; float: right
78
+ }
79
+
80
+ div#preview_form div.dimensions{
81
+ width:50%; float:left;
82
+ }
83
+
84
+ div#preview_form div.dimensions input{
85
+ width:70%;
86
+ }
87
+
88
+ div#preview_form div.options{
89
+ width:50%; float:right;
90
+ }
91
+
92
+ div#dialog_list #records{
93
+ width: 100%
94
+ }
95
+
@@ -0,0 +1,16 @@
1
+ module Refinery
2
+ module Videos
3
+ module Admin
4
+ class VideoFilesController < ::Refinery::AdminController
5
+
6
+ def destroy
7
+ @video_file = VideoFile.find(params[:id])
8
+ @video = @video_file.video
9
+ @video_file.destroy
10
+ redirect_to refinery.edit_videos_admin_video_path(@video), :notice => "#{@video_file.file_name} was successfully removed."
11
+ end
12
+
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,59 @@
1
+ module Refinery
2
+ module Videos
3
+ module Admin
4
+ class VideosController < ::Refinery::AdminController
5
+
6
+ crudify :'refinery/videos/video',
7
+ :title_attribute => 'title',
8
+ :xhr_paging => true,
9
+ :order => 'position ASC',
10
+ :sortable => true
11
+
12
+ before_filter :set_embedded, :only => [:new, :create]
13
+
14
+ def show
15
+ @video = Video.find(params[:id])
16
+ end
17
+
18
+ def new
19
+ @video = Video.new
20
+ @video.video_files.build
21
+ end
22
+
23
+ def insert
24
+ search_all_videos if searching?
25
+ find_all_videos
26
+ paginate_videos
27
+ end
28
+
29
+ def append_to_wym
30
+ @video = Video.find(params[:video_id])
31
+ params['video'].each do |key, value|
32
+ @video.config[key.to_sym] = value
33
+ end
34
+ @html_for_wym = @video.to_html
35
+ end
36
+
37
+ def dialog_preview
38
+ @video = Video.find(params[:id].delete('video_'))
39
+ w, h = @video.config[:width], @video.config[:height]
40
+ @video.config[:width], @video.config[:height] = 300, 200
41
+ @preview_html = @video.to_html
42
+ @video.config[:width], @video.config[:height] = w, h
43
+ @embedded = true if @video.use_shared
44
+ end
45
+
46
+ private
47
+
48
+ def paginate_videos
49
+ @videos = @videos.paginate(:page => params[:page], :per_page => Video.per_page(true))
50
+ end
51
+
52
+ def set_embedded
53
+ @embedded = true if params['embedded']
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,119 @@
1
+ require 'dragonfly'
2
+
3
+ module Refinery
4
+ module Videos
5
+ class Video < Refinery::Core::BaseModel
6
+
7
+ self.table_name = 'refinery_videos'
8
+ acts_as_indexed :fields => [:title]
9
+
10
+ validates :title, :presence => true
11
+ validate :one_source
12
+
13
+ has_many :video_files, :dependent => :destroy
14
+ accepts_nested_attributes_for :video_files
15
+
16
+ belongs_to :poster, :class_name => '::Refinery::Image'
17
+ accepts_nested_attributes_for :poster
18
+
19
+ ################## Video config options
20
+ serialize :config, Hash
21
+ CONFIG_OPTIONS = {
22
+ :autoplay => "false", :width => "400", :height => "300",
23
+ :controls => "true", :preload => "true", :loop => "true"
24
+ }
25
+
26
+ attr_accessible :title, :poster_id, :video_files_attributes,
27
+ :position, :config, :embed_tag, :use_shared,
28
+ *CONFIG_OPTIONS.keys
29
+
30
+ # Create getters and setters
31
+ CONFIG_OPTIONS.keys.each do |option|
32
+ define_method option do
33
+ self.config[option]
34
+ end
35
+ define_method "#{option}=" do |value|
36
+ self.config[option] = value
37
+ end
38
+ end
39
+ #######################################
40
+
41
+ ########################### Callbacks
42
+ after_initialize :set_default_config
43
+ #####################################
44
+
45
+ def to_html
46
+ if use_shared
47
+ update_from_config
48
+ return embed_tag.html_safe
49
+ end
50
+
51
+ data_setup = []
52
+ CONFIG_OPTIONS.keys.each do |option|
53
+ if option && (option != :width && option != :height)
54
+ data_setup << "\"#{option}\": #{config[option] || '\"auto\"'}"
55
+ end
56
+ end
57
+
58
+ data_setup << "\"poster\": \"#{poster.url}\"" if poster
59
+ sources = []
60
+ video_files.each do |file|
61
+ if file.use_external
62
+ sources << ["<source src='#{file.external_url}' type='#{file.file_mime_type}'/>"]
63
+ else
64
+ sources << ["<source src='#{file.url}' type='#{file.file_mime_type}'/>"]
65
+ end if file.exist?
66
+ end
67
+ html = %Q{<video id="video_#{self.id}" class="video-js vjs-default-skin" width="#{config[:width]}" height="#{config[:height]}" data-setup=' {#{data_setup.join(',')}}'>#{sources.join}</video>}
68
+
69
+ html.html_safe
70
+ end
71
+
72
+
73
+ def short_info
74
+ return [['.shared_source', embed_tag.scan(/src=".+?"/).first]] if use_shared
75
+ info = []
76
+ video_files.each do |file|
77
+ info << file.short_info
78
+ end
79
+
80
+ info
81
+ end
82
+
83
+ ####################################class methods
84
+ class << self
85
+ def per_page(dialog = false)
86
+ dialog ? Videos.pages_per_dialog : Videos.pages_per_admin_index
87
+ end
88
+ end
89
+ #################################################
90
+
91
+ private
92
+
93
+ def set_default_config
94
+ if new_record? && config.empty?
95
+ CONFIG_OPTIONS.each do |option, value|
96
+ self.send("#{option}=", value)
97
+ end
98
+ end
99
+ end
100
+
101
+ def update_from_config
102
+ embed_tag.gsub!(/width="(\d*)?"/, "width=\"#{config[:width]}\"")
103
+ embed_tag.gsub!(/height="(\d*)?"/, "height=\"#{config[:height]}\"")
104
+ #fix iframe overlay
105
+ if embed_tag.include? 'iframe'
106
+ embed_tag =~ /src="(\S+)"/
107
+ embed_tag.gsub!(/src="\S+"/, "src=\"#{$1}?wmode=transparent\"")
108
+ end
109
+ end
110
+
111
+ def one_source
112
+ errors.add(:embed_tag, 'Please embed video') if use_shared && embed_tag.nil?
113
+ errors.add(:video_files, 'Please select at least one source') if !use_shared && video_files.empty?
114
+ end
115
+
116
+ end
117
+
118
+ end
119
+ end
@@ -0,0 +1,63 @@
1
+ require 'dragonfly'
2
+
3
+ module Refinery
4
+ module Videos
5
+ class VideoFile < Refinery::Core::BaseModel
6
+
7
+ self.table_name = 'refinery_video_files'
8
+ acts_as_indexed :fields => [:file_name, :file_ext]
9
+ attr_accessible :file, :file_mime_type, :position, :use_external, :external_url
10
+ belongs_to :video
11
+
12
+ MIME_TYPES = {'.mp4' => 'mp4', '.flv' => 'flv', '.webm' => 'webm', '.ogg' => 'ogg', '.ogv' => 'ogg'}
13
+
14
+ ############################ Dragonfly
15
+ ::Refinery::Videos::Dragonfly.setup!
16
+ video_accessor :file
17
+
18
+ delegate :ext, :size, :mime_type, :url,
19
+ :to => :file,
20
+ :allow_nil => true
21
+
22
+ #######################################
23
+
24
+ ########################### Validations
25
+ validates :file, :presence => true, :unless => :use_external?
26
+ validates :mime_type, :inclusion => { :in => Refinery::Videos.config[:whitelisted_mime_types],
27
+ :message => "Wrong file mime_type" }, :if => :file_name?
28
+ validates :external_url, :presence => true, :if => :use_external?
29
+ #######################################
30
+
31
+ before_save :set_mime_type
32
+ before_update :set_mime_type
33
+
34
+ def exist?
35
+ use_external ? external_url.present? : file.present?
36
+ end
37
+
38
+ def short_info
39
+ if use_external
40
+ ['.link', external_url]
41
+ else
42
+ ['.file', file_name]
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def set_mime_type
49
+ if use_external
50
+ type = external_url.scan(/\.\w+$/)
51
+ if type.present? && MIME_TYPES.has_key?(type.first)
52
+ self.file_mime_type = "video/#{MIME_TYPES[type.first]}"
53
+ else
54
+ self.file_mime_type = 'video/mp4'
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,4 @@
1
+ <li>
2
+ <%= link_to t('.create_new'), refinery.new_videos_admin_video_path,
3
+ :class => "add_icon" %>
4
+ </li>
@@ -0,0 +1,23 @@
1
+ <ul>
2
+ <li>
3
+ <%= render '/refinery/admin/search', :url => refinery.videos_admin_videos_path %>
4
+ </li>
5
+ <li>
6
+ <%= link_to t('.create_new'), refinery.new_videos_admin_video_path,
7
+ :class => "add_icon" %>
8
+ </li>
9
+ <% if !searching? && ::Refinery::Videos::Admin::VideosController.sortable? && ::Refinery::Videos::Video.any? %>
10
+ <li>
11
+ <%= link_to t('.reorder', :what => "Videos"),
12
+ refinery.videos_admin_videos_path,
13
+ :id => "reorder_action",
14
+ :class => "reorder_icon" %>
15
+
16
+ <%= link_to t('.reorder_done', :what => "Videos"),
17
+ refinery.videos_admin_videos_path,
18
+ :id => "reorder_action_done",
19
+ :style => "display: none;",
20
+ :class => "reorder_icon" %>
21
+ </li>
22
+ <% end %>
23
+ </ul>
@@ -0,0 +1,45 @@
1
+ <div class='field'>
2
+ <%= f.label t('.copy_embed_tag_here') %>
3
+ <%= f.text_area :embed_tag, :class => 'embed_tag', :required => true %>
4
+ </div>
5
+ <%= f.hidden_field :use_shared, :value => true %>
6
+
7
+ <script type="text/javascript">
8
+ $(function(){
9
+ $('textarea.embed_tag').on('input', function(e){
10
+ set_width_and_height($(this))
11
+ });
12
+ $('#video_width').on('input', function(){
13
+ set_in_text_area_width('width', $(this));
14
+ });
15
+ $('#video_height').on('input', function(){
16
+ set_in_text_area_width('height', $(this));
17
+ });
18
+
19
+
20
+ });
21
+
22
+ function set_width_and_height(text_area){
23
+ var val = text_area.val();
24
+ var width = val.match(/width="(\d+)"/);
25
+ if (width) {
26
+ $('#video_width').val(width[1]);
27
+ }
28
+ var height = val.match(/height="(\d+)"/);
29
+ if (height){
30
+ $('#video_height').val(height[1]);
31
+ }
32
+ }
33
+
34
+ function set_in_text_area_width(what, input){
35
+ var val = input.val();
36
+ var text = $('textarea.embed_tag').val();
37
+ var new_text = ''
38
+ if (what == 'width'){
39
+ new_text = text.replace(/width="(\d*|\0)"/, 'width="' + val + '"');
40
+ } else if (what == 'height') {
41
+ new_text = text.replace(/height="(\d*|\0)"/, 'height="' + val + '"');
42
+ }
43
+ $('textarea.embed_tag').val(new_text);
44
+ }
45
+ </script>
@@ -0,0 +1,94 @@
1
+ <label><%= t('.files') %></label>
2
+ <div class='tips'><%= t('.file_tip') %></div>
3
+ <div id='file_fields'>
4
+ <%= f.fields_for :video_files do |v| %>
5
+ <div class="parent">
6
+ <label class="inline">
7
+ <%= v.radio_button :use_external, false, {:class => "use_file"}.merge(v.object.use_external ? {} : {:checked => true}) %>
8
+ <span><%= t('.use_file') %></span>
9
+ </label>
10
+ <label class="inline">
11
+ <%= v.radio_button :use_external, true, {:class => "use_external"}.merge(v.object.use_external ? {:checked => true} : {}) %>
12
+ <span><%= t('.use_external_source') %></span>
13
+ </label>
14
+
15
+ <div class='field'>
16
+ <div class="use_file" <%= "style='display: none;'" if v.object.use_external %>>
17
+ <% if v.object.file.present? %>
18
+ <% if v.object.url %>
19
+ <%= link_to(t('.download_current'), v.object.url,
20
+ :title => v.object.file_name) %>
21
+ <em><%= t('.or') %> </em><%= t('.replace') %>
22
+ <% else %>
23
+ <span><%= t('.add_file') %></span>
24
+ <% end %>
25
+ <%= v.file_field :file %>
26
+ <% else %>
27
+ <span><%= t('.add_file') %></span>
28
+ <%= v.file_field :file, {}.merge(v.object.use_external ? {} : {:required => true}) %>
29
+ <% end %>
30
+ </div>
31
+ <div class="use_external" <%= "style='display: none;'" unless v.object.use_external %>>
32
+ <span><%= t('.link_to_source') %></span>
33
+ <%= v.text_field :external_url, {}.merge(v.object.use_external ? {:required => true} : {}) %>
34
+ </div>
35
+ </div>
36
+ <div class='add_remove_buttons'>
37
+ <% if f.object.video_files.count > 1 %>
38
+ <% if f.object.persisted? %>
39
+ <%= link_to(refinery.videos_admin_video_file_path(v.object),
40
+ :class => "cancel confirm-delete",
41
+ :title => t('.delete'),
42
+ :confirm => t('message', :scope => 'refinery.admin.delete', :title => 'file'),
43
+ :method => :delete) do %>
44
+ <%= refinery_icon_tag("delete.png") %>
45
+ <div class="inline"><%= t('.delete_source') %></div>
46
+ <% end %>
47
+ <% else %>
48
+ <a href='#' onclick="remove_field($(this)); return false" class="remove_field" style='display: none'><%= refinery_icon_tag("delete.png")%>
49
+ <div class="inline"><%= t('.delete_source') %></div>
50
+ </a>
51
+ <% end %>
52
+ <% end %>
53
+ <a href='#' onclick="add_field($(this)); return false" class="add_field" style='display: none'><%= refinery_icon_tag("add.png") %>
54
+ <div class="inline"><%= t('.add_source') %></div>
55
+ </a>
56
+ </div>
57
+ </div>
58
+
59
+ <% end %>
60
+ </div>
61
+
62
+ <% @video.video_files.build %>
63
+ <%= render 'new_file_field', :f => f %>
64
+
65
+ <div class='field' id='maximum_file_size'>
66
+ <label>
67
+ <%= t('.maximum_file_size', :bytes => number_to_human_size(Refinery::Videos.max_file_size)) %>
68
+ </label>
69
+ </div>
70
+
71
+ <script type="text/javascript">
72
+ function radio_control(){
73
+ $('input.use_external').on('change', function(){
74
+ if ($(this).is(':checked')) {
75
+ var $parent = $(this).parents('div.parent');
76
+ $parent.find('div.use_external').show();
77
+ $parent.find('div.use_file').hide();
78
+ $parent.find('.use_file input').removeAttr('required');
79
+ $parent.find('.use_external input').attr('required', 'required');
80
+ }
81
+ });
82
+ $('input.use_file').on('change', function(){
83
+ if ($(this).is(':checked')) {
84
+ var $parent = $(this).parents('div.parent');
85
+ $parent.find('div.use_external').hide();
86
+ $parent.find('div.use_file').show();
87
+ $parent.find('.use_file input').attr('required', 'required');
88
+ $parent.find('.use_external input').removeAttr('required');
89
+ }
90
+ });
91
+ }
92
+
93
+
94
+ </script>
@@ -0,0 +1,44 @@
1
+ <% @embedded = true if @video.use_shared %>
2
+ <%= form_for [refinery, :videos_admin, @video] do |f| %>
3
+ <%= hidden_field_tag(:embedded, true) if @embedded %>
4
+ <%= render '/refinery/admin/error_messages',
5
+ :object => @video,
6
+ :include_object_name => true %>
7
+
8
+ <div class='field'>
9
+ <%= f.label t('.title') %>
10
+ <%= f.text_field :title, :required => true %>
11
+ </div>
12
+
13
+ <% if @embedded %>
14
+ <%= render 'embed_video_fields', :f => f %>
15
+ <% else %>
16
+ <div class='field'>
17
+ <%= f.label t('.poster') %>
18
+ <%= render '/refinery/admin/image_picker',
19
+ :f => f,
20
+ :field => :poster_id,
21
+ :image => @video.poster,
22
+ :toggle_image_display => false %>
23
+
24
+ </div>
25
+ <%= render 'file_fields', :f => f %>
26
+ <% end %>
27
+
28
+ <div class='field'>
29
+ <%= f.label t('.width') %>
30
+ <%= f.text_field :width %>
31
+ </div>
32
+ <div class='field'>
33
+ <%= f.label t('.height') %>
34
+ <%= f.text_field :height %>
35
+ </div>
36
+
37
+ <%= render('form_option_fields', :f => f) unless @embedded %>
38
+
39
+ <%= render '/refinery/admin/form_actions',
40
+ :f => f,
41
+ :continue_editing => false,
42
+ :delete_title => t('delete', :scope => 'refinery.videos.admin.videos.video'),
43
+ :delete_confirmation => t('message', :scope => 'refinery.admin.delete', :title => @video.title) %>
44
+ <% end %>
@@ -0,0 +1,17 @@
1
+ <label><%= t('.options') %></label>
2
+ <div class='field'>
3
+ <%= f.check_box :autoplay, { }, "true", "false" %>
4
+ <%= f.label :autoplay, t('.autoplay'), :class => 'input_label' %>
5
+ </div>
6
+ <div class='field'>
7
+ <%= f.check_box :controls, { }, "true", "false" %>
8
+ <%= f.label :controls, t('.show_ontrols'), :class => 'input_label' %>
9
+ </div>
10
+ <div class='field'>
11
+ <%= f.check_box :preload, { }, "true", "false" %>
12
+ <%= f.label :preload, t('.preload_video'), :class => 'input_label' %>
13
+ </div>
14
+ <div class='field'>
15
+ <%= f.check_box :loop, { }, "true", "false" %>
16
+ <%= f.label :loop, t('.loop_video'), :class => 'input_label' %>
17
+ </div>
@@ -0,0 +1,75 @@
1
+ <%= f.fields_for :video_files, @video.video_files.last do |v| %>
2
+ <div class="new_field" style="display: none">
3
+ <label class="inline">
4
+ <%= v.radio_button :use_external, false, :class => "use_file", :checked => true %>
5
+ <span><%= t('.use_file') %></span>
6
+ </label>
7
+ <label class="inline">
8
+ <%= v.radio_button :use_external, true, :class => "use_external" %>
9
+ <span><%= t('.use_external_source') %></span>
10
+ </label>
11
+ <div class='field'>
12
+ <div class="use_file">
13
+ <span><%= t('.add_file') %></span>
14
+ <%= v.file_field :file, :id => "new_file_field", :required => true %>
15
+ </div>
16
+ <div class="use_external" style='display: none'>
17
+ <span><%= t('.link_to_source') %></span>
18
+ <%= v.text_field :external_url, :id => "new_external_url_field" %>
19
+ </div>
20
+ </div>
21
+ <div class='add_remove_buttons'>
22
+ <a href='#' onclick="remove_field($(this)); return false" class="remove_field"><%= refinery_icon_tag("delete.png")%>
23
+ <div class="inline"><%= t('.delete_source') %></div>
24
+ </a>
25
+ <a href='#' onclick="add_field($(this)); return false" class="add_field"><%= refinery_icon_tag("add.png") %>
26
+ <div class="inline"><%= t('.add_source') %></div>
27
+ </a>
28
+ </div>
29
+ </div>
30
+ <% end %>
31
+
32
+ <script type="text/javascript">
33
+ function add_field(plus){
34
+ plus.parents('div.parent').find('a.add_field').hide();
35
+ plus.parents('div.parent').find('a.remove_field').show();
36
+ prepare_new_field();
37
+ $div = window.new_field.clone();
38
+ $div.addClass('parent');
39
+ $div.removeClass('new_field');
40
+ $('#file_fields').append($div.show());
41
+ radio_control();
42
+ }
43
+
44
+ function remove_field(minus){
45
+ minus.parents('div.parent').remove();
46
+ $('div.parent').last().find('a.add_field').show();
47
+ if ($('div.parent').length > 1) {
48
+ $('div.parent').last().find('a.remove_field').show();
49
+ } else {
50
+ $('div.parent').find('a.remove_field').hide();
51
+ }
52
+ }
53
+
54
+ $(function(){
55
+ radio_control();
56
+ $('div.parent').last().find('a.add_field').show();
57
+ $without_first = $('div.parent').not($('div.parent').first());
58
+ if ($('div.parent').length > 1) {
59
+ $('div.parent').find('a.remove_field').show();
60
+ }
61
+ window.new_field = $('div.new_field').remove();
62
+ $('input[checked="checked"]').attr('checked', 'checked');
63
+ });
64
+
65
+ function prepare_new_field(){
66
+ var $inputs = window.new_field.find('input');
67
+ var date = Number(new Date);
68
+ $.each($inputs, function(){
69
+ var new_name = $(this).attr('name').replace(/\[\d+\]/,'['+date+']');
70
+ $(this).attr('name', new_name);
71
+ var new_id = $(this).attr('id') + date
72
+ $(this).attr('id', new_id);
73
+ });
74
+ }
75
+ </script>