Commit 313f8a54d53a4fdfa651f02197813026e1660e3b

Authored by Daniela Feitosa
2 parents 7214021c 04e23d80

Merge commit 'refs/merge-requests/33' of git://gitorious.org/noosfero/noosfero i…

…nto merge-requests/33

(ActionItem2059)
app/controllers/my_profile/cms_controller.rb
@@ -177,8 +177,7 @@ class CmsController < MyProfileController @@ -177,8 +177,7 @@ class CmsController < MyProfileController
177 @article = @parent = check_parent(params[:parent_id]) 177 @article = @parent = check_parent(params[:parent_id])
178 @target = @parent ? ('/%s/%s' % [profile.identifier, @parent.full_name]) : '/%s' % profile.identifier 178 @target = @parent ? ('/%s/%s' % [profile.identifier, @parent.full_name]) : '/%s' % profile.identifier
179 @folders = Folder.find(:all, :conditions => { :profile_id => profile }) 179 @folders = Folder.find(:all, :conditions => { :profile_id => profile })
180 - @media_listing = params[:media_listing]  
181 - if @article && !@media_listing 180 + if @article
182 record_coming 181 record_coming
183 end 182 end
184 if request.post? && params[:uploaded_files] 183 if request.post? && params[:uploaded_files]
@@ -187,26 +186,14 @@ class CmsController < MyProfileController @@ -187,26 +186,14 @@ class CmsController < MyProfileController
187 end 186 end
188 @errors = @uploaded_files.select { |f| f.errors.any? } 187 @errors = @uploaded_files.select { |f| f.errors.any? }
189 if @errors.any? 188 if @errors.any?
190 - if @media_listing  
191 - flash[:notice] = _('Could not upload all files')  
192 - redirect_to :action => 'media_listing'  
193 - else  
194 - render :action => 'upload_files', :parent_id => @parent_id  
195 - end 189 + render :action => 'upload_files', :parent_id => @parent_id
196 else 190 else
197 - if @media_listing  
198 - flash[:notice] = _('All files were uploaded successfully')  
199 - redirect_to :action => 'media_listing' 191 + if @back_to
  192 + redirect_to @back_to
  193 + elsif @parent
  194 + redirect_to :action => 'view', :id => @parent.id
200 else 195 else
201 - if @back_to  
202 - redirect_to @back_to  
203 - else  
204 - redirect_to( if @parent  
205 - {:action => 'view', :id => @parent.id}  
206 - else  
207 - {:action => 'index'}  
208 - end)  
209 - end 196 + redirect_to :action => 'index'
210 end 197 end
211 end 198 end
212 end 199 end
@@ -302,37 +289,21 @@ class CmsController < MyProfileController @@ -302,37 +289,21 @@ class CmsController < MyProfileController
302 end 289 end
303 end 290 end
304 291
305 - def media_listing  
306 - if params[:image_folder_id]  
307 - folder = profile.articles.find(params[:image_folder_id]) if !params[:image_folder_id].blank?  
308 - @images = (folder ? folder.children : profile.top_level_articles).images  
309 - elsif params[:document_folder_id]  
310 - folder = profile.articles.find(params[:document_folder_id]) if !params[:document_folder_id].blank?  
311 - @documents = (folder ? folder.children : profile.top_level_articles)  
312 - else  
313 - @documents = profile.articles  
314 - @images = @documents.images  
315 - @documents -= @images  
316 - end  
317 -  
318 - @images = @images.paginate(:per_page => per_page, :page => params[:ipage], :order => "updated_at desc") if @images  
319 - @documents = @documents.paginate(:per_page => per_page, :page => params[:dpage], :order => "updated_at desc", :conditions => {:is_image => false}) if @documents  
320 -  
321 - @folders = profile.folders  
322 - @image_folders = @folders.select {|f| f.children.any? {|c| c.image?} }  
323 - @document_folders = @folders.select {|f| f.children.any? {|c| !c.image? && c.kind_of?(UploadedFile) } }  
324 -  
325 - @media_listing = true  
326 -  
327 - respond_to do |format|  
328 - format.html { render :layout => false}  
329 - format.js {  
330 - render :update do |page|  
331 - page.replace_html 'media-listing-folder-images', :partial => 'image_thumb', :locals => {:images => @images } if !@images.blank?  
332 - page.replace_html 'media-listing-folder-documents', :partial => 'document_link', :locals => {:documents => @documents } if !@documents.blank?  
333 - end  
334 - } 292 + def search
  293 + query = params[:q]
  294 + results = query.blank? ? [] : profile.articles.published.find_by_contents(query)
  295 + render :text => article_list_to_json(results), :content_type => 'application/json'
  296 + end
  297 + def media_upload
  298 + files_uploaded = []
  299 + parent = check_parent(params[:parent_id])
  300 + files = [:file1,:file2, :file3].map { |f| params[f] }.compact
  301 + if request.post?
  302 + files.each do |file|
  303 + files_uploaded << UploadedFile.create(:uploaded_data => file, :profile => profile, :parent => parent) unless file == ''
  304 + end
335 end 305 end
  306 + render :text => article_list_to_json(files_uploaded), :content_type => 'text/plain'
336 end 307 end
337 308
338 protected 309 protected
@@ -366,7 +337,7 @@ class CmsController &lt; MyProfileController @@ -366,7 +337,7 @@ class CmsController &lt; MyProfileController
366 end 337 end
367 338
368 def refuse_blocks 339 def refuse_blocks
369 - if ['TinyMceArticle', 'Event', 'EnterpriseHomepage'].include?(@type) 340 + if ['TinyMceArticle', 'TextileArticle', 'Event', 'EnterpriseHomepage'].include?(@type)
370 @no_design_blocks = true 341 @no_design_blocks = true
371 end 342 end
372 end 343 end
@@ -380,5 +351,17 @@ class CmsController &lt; MyProfileController @@ -380,5 +351,17 @@ class CmsController &lt; MyProfileController
380 @selected_locale = @article.language || FastGettext.locale 351 @selected_locale = @article.language || FastGettext.locale
381 end 352 end
382 353
  354 + def article_list_to_json(list)
  355 + list.map do |item|
  356 + {
  357 + 'title' => item.title,
  358 + 'url' => item.image? ? item.public_filename(:uploaded) : url_for(item.url),
  359 + :icon => icon_for_article(item),
  360 + :content_type => item.mime_type,
  361 + :error => item.errors.any? ? _('%s could not be uploaded') % item.title : nil,
  362 + }
  363 + end.to_json
  364 + end
  365 +
383 end 366 end
384 367
app/views/cms/_document_link.rhtml
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -<div id='media-listing-folder-documents' >  
2 - <ul>  
3 - <% documents.each do |document| %>  
4 - <li><%= link_to(document.name, document.view_url, :class => icon_for_article(document)) %></li>  
5 - <% end %>  
6 - </ul>  
7 - <div id='pagination-documents'>  
8 - <%= pagination_links documents, :param_name => 'dpage', :params => {:document_folder_id => params[:document_folder_id]} %>  
9 - </div>  
10 -</div>  
app/views/cms/_drag_and_drop_note.rhtml 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +<p>
  2 +<em><%= _('Drag images to add them to the text.') unless @article.is_a?(TextileArticle) %>
  3 +<%= _('Drag item names to the text to add links.') %></em>
  4 +</p>
app/views/cms/_image_thumb.rhtml
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -<div id='media-listing-folder-images' >  
2 - <ul>  
3 - <% images.each do |image| %>  
4 - <li><%= image_tag image.public_filename %></li>  
5 - <% end %>  
6 - </ul>  
7 - <div id='pagination-images'>  
8 - <%= pagination_links images, :param_name => 'ipage', :params => {:image_folder_id => params[:image_folder_id]} %>  
9 - </div>  
10 -</div>  
app/views/cms/_media_listing.rhtml
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -<iframe id='media-listing-iframe' src="<%= url_for(:controller => 'cms', :action => 'media_listing', :profile => profile.identifier, :type => @type) %>">  
2 - <p><%= _('Your browser does not support iframes.') %></p>  
3 -</iframe>  
app/views/cms/_select_folder.rhtml
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -<%= select('folder', 'folder_id', @image_folders.collect {|f| [ f.name, f.id ] }, {:include_blank => "#{profile.identifier}"}, :onchange => remote_function(:update => 'media-listing-folder-images', :with => "'folder_id=' + value", :url => { :action => :get_images }) ) %>  
app/views/cms/_text_editor_sidebar.rhtml 0 → 100644
@@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
  1 +<div class='text-editor-sidebar'>
  2 + <%= render(:partial => 'textile_quick_reference') if @article.is_a?(TextileArticle) %>
  3 + <div class='text-editor-sidebar-box' id='media-upload-box'>
  4 + <p><strong><%= _('Media upload') %></strong></p>
  5 + <div id='media-upload-form'>
  6 + <% form_tag({ :action => 'media_upload' }, :multipart => true) do %>
  7 + <div class='formfield'>
  8 + <%# TODO duplicated from partial upload_file_form %>
  9 + <%= labelled_form_field(_('Choose folder to upload files:'), select_tag('parent_id', options_for_select([[profile.identifier, '']] + profile.folders.collect {|f| [ profile.identifier + '/' + f.full_name, f.id ] }))) %>
  10 + </div>
  11 + <p><%= file_field_tag('file1') %></p>
  12 + <p><%= file_field_tag('file2') %></p>
  13 + <p><%= file_field_tag('file3') %></p>
  14 + <% button_bar do %>
  15 + <%= submit_button(:save, _('Upload')) %>
  16 + <% end %>
  17 + <% end %>
  18 + </div>
  19 + <div id='media-upload-results' style='display: none'>
  20 + <%= render :partial => 'drag_and_drop_note' %>
  21 + <div class='items'>
  22 + </div>
  23 + <p><%= link_to(_('Upload more files ...'), '#', :id => 'media-upload-more-files')%></p>
  24 + </div>
  25 + </div>
  26 + <div id='media-search-box' class='text-editor-sidebar-box'>
  27 + <p><strong><%= _('Media search') %></strong></p>
  28 + <p>
  29 + <% form_tag({ :action => 'search' }) do %>
  30 + <span class='formfield'>
  31 + <input name='q' type='text' id='media-search-query' style='width: 250px;'/>
  32 + </span>
  33 + <%= submit_button :search, _('Search'), :id => 'media-search-button' %>
  34 + <% end %>
  35 + </p>
  36 + <div id='media-search-results' style='display: none'>
  37 + <%= render :partial => 'drag_and_drop_note' %>
  38 + <div class='items'>
  39 + </div>
  40 + </div>
  41 + </div>
  42 +</div>
  43 +
  44 +
app/views/cms/_textile_article.rhtml
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 2
3 <%# TODO add Textile help here %> 3 <%# TODO add Textile help here %>
4 4
5 -<%= required labelled_form_field(_('Title'), text_field(:article, 'name', :size => '64')) %> 5 +<%= required labelled_form_field(_('Title'), text_field(:article, 'name', :size => '72')) %>
6 6
7 <%= render :partial => 'translatable' %> 7 <%= render :partial => 'translatable' %>
8 <%= render :partial => 'shared/lead_and_body' %> 8 <%= render :partial => 'shared/lead_and_body' %>
app/views/cms/_textile_quick_reference.rhtml 0 → 100644
@@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
  1 +<div class='text-editor-sidebar-box'>
  2 + <p>
  3 + <strong><%= _('Textile markup quick reference') %></strong>
  4 + <%= link_to(_('(show)'), '#', :id => 'textile-quickref-show') %>
  5 + <%= link_to(_('(hide)'), '#', :id => 'textile-quickref-hide', :style => 'display: none') %>
  6 + </p>
  7 + <div id='textile-quickref' style='display: none;'>
  8 + <p><%= _('Simple formatting:') %> <code>_<%= _('italics') %>_</code> <code>*<%= _('bold') %>*</code>, <code>-<%= _('striked')%>-</code>.</p>
  9 + <p><%= _('Links:') %> <code>"Noosfero":http://noosfero.org/</code></p>
  10 + <p><%= _('Images:') %> <code>!http://example.com/image.png!</code></p>
  11 + <p><%= _('Bullet lists:') %></p>
  12 + <pre>* <%= _('first item') %>
  13 +* <%= _('second item') %></pre>
  14 + <p><%= _('Numbered lists:') %></p>
  15 + <pre># <%= _('first item') %>
  16 +# <%= _('second item') %></pre>
  17 + <p><%= h(_('For code, use HTML tags <pre> and <code>, and indent the code inside them:')) %>
  18 + <pre>
  19 +&lt;pre&gt;
  20 +&lt;code&gt;
  21 + a.gsub!( /&lt;/, '' )
  22 +&lt;/code&gt;
  23 +&lt;/pre&gt;
  24 +</pre>
  25 + <p><%= _('See also a more complete <a href="%s">Textile Reference</a>.') % 'http://redcloth.org/hobix.com/textile/' %></p>
  26 + </div>
  27 +</div>
  28 +
app/views/cms/_upload_file_form.rhtml
1 <% if @parent %> 1 <% if @parent %>
2 <%= hidden_field_tag('parent_id', @parent.id) %> 2 <%= hidden_field_tag('parent_id', @parent.id) %>
3 <% else %> 3 <% else %>
4 - <h4><%= _('Choose folder to upload files:') %></h4>  
5 - <%= select_tag('parent_id', options_for_select([[profile.identifier, '']] + @folders.collect {|f| [ profile.identifier + '/' + f.full_name, f.id ] })) %> 4 + <%= labelled_form_field(_('Choose folder to upload files:'), select_tag('parent_id', options_for_select([[profile.identifier, '']] + @folders.collect {|f| [ profile.identifier + '/' + f.full_name, f.id ] }))) %>
6 <% end %> 5 <% end %>
7 6
8 <div id='uploaded_files'> 7 <div id='uploaded_files'>
@@ -15,9 +14,7 @@ @@ -15,9 +14,7 @@
15 14
16 <% button_bar do %> 15 <% button_bar do %>
17 <%= add_upload_file_field(_('More files'), {:size => size}) %> 16 <%= add_upload_file_field(_('More files'), {:size => size}) %>
18 - <% if @media_listing %>  
19 - <%= submit_button :save, _('Upload') %>  
20 - <% elsif @back_to %> 17 + <% if @back_to %>
21 <%= submit_button :save, _('Upload'), :cancel => @back_to %> 18 <%= submit_button :save, _('Upload'), :cancel => @back_to %>
22 <% else %> 19 <% else %>
23 <%= submit_button :save, _('Upload'), :cancel => {:action => (@parent ? 'view' : 'index'), :id => @parent } %> 20 <%= submit_button :save, _('Upload'), :cancel => {:action => (@parent ? 'view' : 'index'), :id => @parent } %>
app/views/cms/edit.rhtml
@@ -49,8 +49,8 @@ @@ -49,8 +49,8 @@
49 <% end %> 49 <% end %>
50 </div> 50 </div>
51 51
52 -<% if environment.enabled?('media_panel') && [TinyMceArticle, Event, EnterpriseHomepage].any?{|klass| @article.kind_of?(klass)} %>  
53 - <%= render :partial => 'media_listing' %> 52 +<% if environment.enabled?('media_panel') && [TinyMceArticle, TextileArticle, Event, EnterpriseHomepage].any?{|klass| @article.kind_of?(klass)} %>
  53 + <%= render :partial => 'text_editor_sidebar' %>
54 <% end %> 54 <% end %>
55 55
56 <br style='clear: both'/> 56 <br style='clear: both'/>
app/views/cms/media_listing.rhtml
@@ -1,75 +0,0 @@ @@ -1,75 +0,0 @@
1 -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<%= html_language %>" lang="<%= html_language %>">  
2 -<head>  
3 - <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
4 - <%= stylesheet_link_tag 'application', 'media_listing', :cache => 'cache-media-listing' %>  
5 - <%= stylesheet_import 'button', :themed_source => true %>  
6 - <%= javascript_include_tag :defaults %>  
7 - <%= javascript_include_tag 'lowpro' %>  
8 - <%= stylesheet_link_tag icon_theme_stylesheet_path %>  
9 -</head>  
10 -<body class='noosfero'>  
11 - <script type="text/javascript">  
12 - /* Adds a class to "msie" to the body element if a Microsoft browser is  
13 - * detected. This is needed to workaround several of their limitations.  
14 - */  
15 - if ( navigator.appVersion.indexOf("MSIE") > -1 ) {  
16 - document.body.className += " msie msie" +  
17 - navigator.appVersion.replace(/^.*MSIE\s+([0-9]+).*$/, "$1");  
18 - }  
19 - function registerDocumentSize() {  
20 - document.body.className = document.body.className.replace(/(^| )docSize.+( |$)/g, " ");  
21 - for ( var x=100; x<=1500; x+=100 ) {  
22 - if ( document.body.clientWidth > x ) {  
23 - document.body.className += " docSize-GT-" + x;  
24 - } else {  
25 - document.body.className += " docSize-LT-" + x;  
26 - }  
27 - }  
28 - }  
29 - registerDocumentSize();  
30 - </script>  
31 - <div id='media-listing-upload'>  
32 - <p><%= _("Include files in some folder or select from the list below to add images and documents to the text editor beside (max size %s)") % UploadedFile.max_size.to_humanreadable %></p>  
33 -  
34 - <div id="notice" onclick="Element.hide('notice');" style="display:none">  
35 - <% unless flash[:notice].nil? %>  
36 - <%= flash[:notice] %>  
37 - <%= javascript_tag(visual_effect( :appear, 'notice')) %>  
38 - <% end %>  
39 - </div>  
40 -  
41 - <% form_for('uploaded_file', :url => {:action => 'upload_files'}, :html => {:multipart => true}) do |f| %>  
42 - <%= hidden_field_tag('media_listing', @media_listing) %>  
43 - <%= render :partial => 'upload_file_form', :locals => { :size => '30' } %>  
44 - <% end %>  
45 - </div><!-- id='media-listing-upload' -->  
46 - <hr/>  
47 -  
48 - <script type='text/javascript'>  
49 - document.observe("dom:loaded", function() {  
50 - Event.addBehavior.reassignAfterAjax = true;  
51 - Event.addBehavior({  
52 - 'div#pagination-images .pagination a' : Remote.Link,  
53 - 'div#pagination-documents .pagination a' : Remote.Link  
54 - })  
55 - });  
56 - </script>  
57 -  
58 - <div id='media-listing'>  
59 - <h3><%= _('Folders') %></h3>  
60 - <p><%= _('Drag images and documents to add them to the text. If needed, resize images by clicking the tree icon on editor.') %></p>  
61 -  
62 - <div id='media-listing-images'>  
63 - <h4><%= _('Images') %></h4>  
64 - <%= select_folder('', 'folder', 'image_folder_id', @image_folders, {}, :onchange => remote_function(:with => "'image_folder_id=' + value + '&ipage=1'", :url => { :action => :media_listing, :format => 'js' }) ) %>  
65 - <%= render :partial => 'image_thumb', :locals => { :images => @images } %>  
66 - </div><!-- id='media-listing-images' -->  
67 - <div id='media-listing-documents'>  
68 - <h4><%= _('Documents') %></h4>  
69 - <%= select_folder('', 'folder', 'document_folder_id', @document_folders, {}, :onchange => remote_function(:with => "'document_folder_id=' + value + '&dpage=1'", :url => { :action => :media_listing }) ) %>  
70 - <%= render :partial => 'document_link', :locals => { :documents => @documents } %>  
71 - </div><!-- id='media-listing-documents' -->  
72 - <br style="clear:both" />  
73 - </div><!-- id='media-listing' -->  
74 -</body>  
75 -</html>  
lib/delayed_attachment_fu.rb
@@ -38,7 +38,11 @@ module DelayedAttachmentFu @@ -38,7 +38,11 @@ module DelayedAttachmentFu
38 end 38 end
39 39
40 def public_filename(size=nil) 40 def public_filename(size=nil)
41 - if !self.thumbnailable? || self.thumbnails_processed 41 + force = (size == :uploaded)
  42 + if force
  43 + size = nil
  44 + end
  45 + if !self.thumbnailable? || self.thumbnails_processed || force
42 super(size) 46 super(size)
43 else 47 else
44 size ||= 'thumb' 48 size ||= 'thumb'
public/javascripts/article.js
1 -(function($) { 1 +jQuery(function($) {
2 $(".lead-button").live('click', function(){ 2 $(".lead-button").live('click', function(){
3 article_id = this.getAttribute("article_id"); 3 article_id = this.getAttribute("article_id");
4 $(this).toggleClass('icon-add').toggleClass('icon-remove'); 4 $(this).toggleClass('icon-add').toggleClass('icon-remove');
@@ -10,4 +10,67 @@ @@ -10,4 +10,67 @@
10 $('#article-body-field').slideToggle(); 10 $('#article-body-field').slideToggle();
11 return false; 11 return false;
12 }) 12 })
13 -})(jQuery) 13 +
  14 + $("#textile-quickref-show").click(function(){
  15 + $('#textile-quickref-hide').show();
  16 + $(this).hide();
  17 + $('#textile-quickref').slideToggle();
  18 + return false;
  19 + })
  20 + $("#textile-quickref-hide").click(function(){
  21 + $('#textile-quickref-show').show();
  22 + $(this).hide();
  23 + $('#textile-quickref').slideToggle();
  24 + return false;
  25 + })
  26 + function insert_items(items, selector) {
  27 + var html_for_items = '';
  28 + $.each(items, function(i, item) {
  29 + if (item.error) {
  30 + html_for_items += '<div class="media-upload-error">' + item.error + '</div>';
  31 + return;
  32 + }
  33 + if (item.content_type && item.content_type.match(/^image/)) {
  34 + html_for_items += '<div class="icon-photos"><img src="' + item.url + '"/><br/><a href="' + item.url + '">' + item.title + '</a></div>';
  35 + } else {
  36 + html_for_items += '<div class="' + item.icon + '"><a href="' + item.url + '">' + item.title + '</a></div>';
  37 + }
  38 + });
  39 + $(selector).html(html_for_items);
  40 + }
  41 + $('#media-search-button').click(function() {
  42 + var query = '*' + $('#media-search-query').val() + '*';
  43 + var $button = $(this);
  44 + $('#media-search-box').toggleClass('icon-loading');
  45 + $.get($(this).parent().attr('action'), { 'q': query }, function(data) {
  46 + insert_items(data, '#media-search-results .items');
  47 + if (data.length && data.length > 0) {
  48 + $('#media-search-results').slideDown();
  49 + }
  50 + $('#media-search-box').toggleClass('icon-loading');
  51 + });
  52 + return false;
  53 + });
  54 + $('#media-upload-form form').ajaxForm({
  55 + dataType: 'json',
  56 + resetForm: true,
  57 + beforeSubmit:
  58 + function() {
  59 + $('#media-upload-form').slideUp();
  60 + $('#media-upload-box').toggleClass('icon-loading');
  61 + },
  62 + success:
  63 + function(data) {
  64 + insert_items(data, '#media-upload-results .items');
  65 + if (data.length && data.length > 0) {
  66 + $('#media-upload-results').slideDown();
  67 + }
  68 + $('#media-upload-box').toggleClass('icon-loading');
  69 + }
  70 + });
  71 + $('#media-upload-more-files').click(function() {
  72 + $('#media-upload-results').hide();
  73 + $('#media-upload-form').show();
  74 + });
  75 +
  76 +});
public/stylesheets/application.css
@@ -2768,6 +2768,7 @@ div#activation_enterprise div { @@ -2768,6 +2768,7 @@ div#activation_enterprise div {
2768 border-top: none; 2768 border-top: none;
2769 border-left: none; 2769 border-left: none;
2770 color: #585858; 2770 color: #585858;
  2771 + font-size: 11px;
2771 } 2772 }
2772 .formfield input { 2773 .formfield input {
2773 text-indent: 5px; 2774 text-indent: 5px;
@@ -3343,21 +3344,7 @@ table.cms-articles .icon:hover { @@ -3343,21 +3344,7 @@ table.cms-articles .icon:hover {
3343 display: block; 3344 display: block;
3344 } 3345 }
3345 3346
3346 -/* Media listing */  
3347 -  
3348 -.controller-cms #media-listing-iframe {  
3349 - float: right;  
3350 - width: 380px;  
3351 - height: 630px;  
3352 - border: none;  
3353 - margin-top: 104px;  
3354 - padding: 0px;  
3355 - overflow: hidden;  
3356 -}  
3357 -  
3358 -.controller-cms .msie #media-listing-iframe {  
3359 - height: 610px;  
3360 -} 3347 +/* Text editors sidebar */
3361 3348
3362 .controller-cms div.with_media_panel { 3349 .controller-cms div.with_media_panel {
3363 float: left; 3350 float: left;
@@ -3368,6 +3355,64 @@ div.with_media_panel .formfield input { @@ -3368,6 +3355,64 @@ div.with_media_panel .formfield input {
3368 width: 100%; 3355 width: 100%;
3369 } 3356 }
3370 3357
  3358 +.text-editor-sidebar {
  3359 + position: absolute;
  3360 + width: 380px;
  3361 + right: 20px;
  3362 + top: 70px;
  3363 +}
  3364 +
  3365 +.text-editor-sidebar-box {
  3366 + background: #eeeeec;
  3367 + border: 1px solid #d3d7cf;
  3368 + padding: 10px 10px 0px 10px;
  3369 + margin-bottom: 10px;
  3370 +}
  3371 +.text-editor-sidebar-box p {
  3372 + margin-top: 0px;
  3373 +}
  3374 +.text-editor-sidebar code,
  3375 +.text-editor-sidebar pre {
  3376 + border: 1px solid #d3d7cf;
  3377 + color: black;
  3378 + padding: 2px;
  3379 +}
  3380 +.text-editor-sidebar .icon-loading {
  3381 + background-image: url(../images/loading-small.gif);
  3382 +}
  3383 +.text-editor-sidebar .items {
  3384 + margin-bottom: 10px;
  3385 +}
  3386 +.text-editor-sidebar .items div {
  3387 + background-repeat: no-repeat;
  3388 + background-position: 0px 0px;
  3389 + padding-left: 20px;
  3390 + padding-top: 2px;
  3391 + padding-bottom: 2px;
  3392 + border: none;
  3393 + margin-bottom: 2px;
  3394 +}
  3395 +.text-editor-sidebar .items :hover {
  3396 + background-color: transparent;
  3397 + border: none;
  3398 +}
  3399 +.text-editor-sidebar #media-upload-box,
  3400 +.text-editor-sidebar #media-search-box {
  3401 + background-repeat: no-repeat;
  3402 + background-position: 98% 10px;
  3403 +}
  3404 +.text-editor-sidebar img {
  3405 + max-height: 96px;
  3406 + max-width: 96px;
  3407 + border: 1px solid #d3d7cf;
  3408 +}
  3409 +.text-editor-sidebar .media-upload-error {
  3410 + color: red;
  3411 +}
  3412 +.text-editor-sidebar select {
  3413 + max-width: 355px;
  3414 +}
  3415 +
3371 /* ==> public/stylesheets/controller_contact.css <== */ 3416 /* ==> public/stylesheets/controller_contact.css <== */
3372 /*** SELECT CITY ***/ 3417 /*** SELECT CITY ***/
3373 3418
public/stylesheets/media_listing.css
@@ -1,167 +0,0 @@ @@ -1,167 +0,0 @@
1 -body {  
2 - padding: 0px;  
3 - margin: 0px;  
4 - font-family: Verdana, sans-serif;  
5 - font-size: 14px;  
6 - color: #444;  
7 - background-color: #F0F0EE;  
8 - overflow: hidden;  
9 -}  
10 -  
11 -h3, h4, h5 {  
12 - margin: 5px 0px;  
13 -}  
14 -  
15 -h3 {  
16 - font-size: 18px;  
17 -}  
18 -  
19 -h4 {  
20 - font-size: 16px;  
21 -}  
22 -  
23 -#media-listing {  
24 - width: 100%;  
25 - height: 48%;  
26 - margin: 0px;  
27 - padding: 0px;  
28 - padding-bottom: 5px;  
29 -}  
30 -  
31 -#media-listing-upload p,  
32 -#media-listing p {  
33 - font-size: 13px;  
34 - font-weight: bold;  
35 - margin: 5px 5px;  
36 -}  
37 -  
38 -#media-listing li {  
39 - list-style: none;  
40 - margin: 0px;  
41 -}  
42 -  
43 -#media-listing li:hover {  
44 - background-color: #CCC;  
45 -}  
46 -  
47 -#media-listing a {  
48 - text-decoration: none;  
49 -}  
50 -  
51 -#media-listing select {  
52 - width: 80%;  
53 -}  
54 -  
55 -#media-listing-images {  
56 - width: 46%;  
57 - float: left;  
58 - text-align: center;  
59 -}  
60 -  
61 -#media-listing-images img {  
62 - max-width: 80px;  
63 - max-height: 60px;  
64 -}  
65 -  
66 -.msie6 #media-listing-images img,  
67 -.msie7 #media-listing-images img {  
68 - width: 80px;  
69 - height: 60px;  
70 -}  
71 -  
72 -#media-listing-folder-images,  
73 -#media-listing-folder-documents {  
74 - height: 80%;  
75 -}  
76 -  
77 -#media-listing ul {  
78 - padding: 0px;  
79 - margin: 5px;  
80 - height: 40%;  
81 - overflow: auto;  
82 - width: 98%;  
83 -}  
84 -  
85 -#media-listing ul {  
86 - height: 85%;  
87 -}  
88 -  
89 -#media-listing-images,  
90 -#media-listing-documents {  
91 - height: 55%;  
92 -}  
93 -  
94 -#media-listing-documents ul {  
95 - text-align: left;  
96 -}  
97 -  
98 -#media-listing-documents {  
99 - width: 52%;  
100 - float: left;  
101 - text-align: center;  
102 -}  
103 -  
104 -#media-listing-documents li {  
105 - padding-bottom: 5px;  
106 -}  
107 -  
108 -#media-listing-folder-documents a.icon {  
109 - background-repeat: no-repeat;  
110 - padding-left: 20px;  
111 - border: none;  
112 -}  
113 -  
114 -#media-listing-folder-documents .icon:hover {  
115 - background-color: transparent;  
116 -}  
117 -  
118 -#media-listing .icon-rss-feed {  
119 - background-image: url(../images/icons-mime/rss-feed-16.png);  
120 -}  
121 -  
122 -#media-listing-upload {  
123 - width: 98%;  
124 - padding: 3px;  
125 -}  
126 -  
127 -#media-listing-upload p {  
128 - margin: 5px 0px;  
129 -}  
130 -  
131 -#media-listing-upload select {  
132 - width: 90%;  
133 -}  
134 -  
135 -#uploaded_files {  
136 - overflow-x: hidden;  
137 - overflow-y: scroll;  
138 - height: 100px;  
139 - margin-top: 5px;  
140 -}  
141 -  
142 -.msie #uploaded_files {  
143 - height: 100px;  
144 - padding: 0px;  
145 -}  
146 -  
147 -.formlabel {  
148 - font-size: 11px;  
149 - display: block;  
150 -}  
151 -  
152 -/* Notice */  
153 -  
154 -div#notice {  
155 - background: #fee;  
156 - border: 1px solid #933;  
157 - top: 150px;  
158 - color: black;  
159 - cursor: pointer;  
160 - font-weight: bold;  
161 - left: 50%;  
162 - margin-left: -150px;  
163 - padding: 5px;  
164 - position: absolute;  
165 - text-align: center;  
166 - width: 300px;  
167 -}  
test/functional/cms_controller_test.rb
@@ -1064,7 +1064,7 @@ class CmsControllerTest &lt; Test::Unit::TestCase @@ -1064,7 +1064,7 @@ class CmsControllerTest &lt; Test::Unit::TestCase
1064 assert_tag :tag => 'input', :attributes => { :name => 'article[external_feed_builder][only_once]', :checked => 'checked', :value => 'true' } 1064 assert_tag :tag => 'input', :attributes => { :name => 'article[external_feed_builder][only_once]', :checked => 'checked', :value => 'true' }
1065 end 1065 end
1066 1066
1067 - should 'display iframe for media listing when it is TinyMceArticle and enabled on environment' do 1067 + should 'display media listing when it is TinyMceArticle and enabled on environment' do
1068 e = Environment.default 1068 e = Environment.default
1069 e.enable('media_panel') 1069 e.enable('media_panel')
1070 e.save! 1070 e.save!
@@ -1076,10 +1076,10 @@ class CmsControllerTest &lt; Test::Unit::TestCase @@ -1076,10 +1076,10 @@ class CmsControllerTest &lt; Test::Unit::TestCase
1076 file = UploadedFile.create!(:profile => profile, :parent => non_image_folder, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain')) 1076 file = UploadedFile.create!(:profile => profile, :parent => non_image_folder, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'))
1077 1077
1078 get :new, :profile => profile.identifier, :type => 'TinyMceArticle' 1078 get :new, :profile => profile.identifier, :type => 'TinyMceArticle'
1079 - assert_tag :tag => 'iframe', :attributes => { :src => "/myprofile/#{profile.identifier}/cms/media_listing?type=TinyMceArticle" } 1079 + assert_tag :div, :attributes => { :class => "text-editor-sidebar" }
1080 end 1080 end
1081 1081
1082 - should 'not display iframe for media listing when it is Folder' do 1082 + should 'not display media listing when it is Folder' do
1083 image_folder = Folder.create(:profile => profile, :name => 'Image folder') 1083 image_folder = Folder.create(:profile => profile, :name => 'Image folder')
1084 non_image_folder = Folder.create(:profile => profile, :name => 'Non image folder') 1084 non_image_folder = Folder.create(:profile => profile, :name => 'Non image folder')
1085 1085
@@ -1087,145 +1087,7 @@ class CmsControllerTest &lt; Test::Unit::TestCase @@ -1087,145 +1087,7 @@ class CmsControllerTest &lt; Test::Unit::TestCase
1087 file = UploadedFile.create!(:profile => profile, :parent => non_image_folder, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain')) 1087 file = UploadedFile.create!(:profile => profile, :parent => non_image_folder, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'))
1088 1088
1089 get :new, :profile => profile.identifier, :type => 'Folder' 1089 get :new, :profile => profile.identifier, :type => 'Folder'
1090 - assert_no_tag :tag => 'iframe', :attributes => { :src => "/myprofile/#{profile.identifier}/cms/media_listing" }  
1091 - end  
1092 -  
1093 - should 'display list of images' do  
1094 - file = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))  
1095 - process_delayed_job_queue  
1096 - get :media_listing, :profile => profile.identifier  
1097 -  
1098 - assert_tag :tag => 'div', :attributes => { :id => 'media-listing-images' }, :descendant => { :tag => 'img', :attributes => {:src => /rails.png/}}  
1099 - end  
1100 -  
1101 - should 'display loading image if not processed yet' do  
1102 - file = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))  
1103 - get :media_listing, :profile => profile.identifier  
1104 -  
1105 - assert_tag :tag => 'div', :attributes => { :id => 'media-listing-images' }, :descendant => { :tag => 'img', :attributes => {:src => /image-loading-thumb.png/}}  
1106 - end  
1107 -  
1108 -  
1109 - should 'display list of documents' do  
1110 - file = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'))  
1111 - get :media_listing, :profile => profile.identifier  
1112 - assert_tag :tag => 'div', :attributes => { :id => 'media-listing-documents' }, :descendant => { :tag => 'a', :attributes => {:href => /#{file.name}/}}  
1113 - end  
1114 -  
1115 - should 'list image folders to select' do  
1116 - image_folder = Folder.create(:profile => profile, :name => 'Image folder')  
1117 - non_image_folder = Folder.create(:profile => profile, :name => 'Non image folder')  
1118 -  
1119 - image = UploadedFile.create!(:profile => profile, :parent => image_folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))  
1120 - file = UploadedFile.create!(:profile => profile, :parent => non_image_folder, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'))  
1121 -  
1122 - get :media_listing, :profile => profile.identifier  
1123 - assert_tag :tag => 'div', :attributes => { :id => 'media-listing-images' }, :descendant => { :tag => 'option', :content => /#{image_folder.name}/, :attributes => { :value => image_folder.id}}  
1124 - assert_no_tag :tag => 'div', :attributes => { :id => 'media-listing-images' }, :descendant => { :tag => 'option', :content => /#{non_image_folder.name}/, :attributes => { :value => non_image_folder.id}}  
1125 - end  
1126 -  
1127 - should 'list documents folders to select' do  
1128 - image_folder = Folder.create(:profile => profile, :name => 'Image folder')  
1129 - non_image_folder = Folder.create(:profile => profile, :name => 'Non image folder')  
1130 -  
1131 - image = UploadedFile.create!(:profile => profile, :parent => image_folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))  
1132 - file = UploadedFile.create!(:profile => profile, :parent => non_image_folder, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'))  
1133 -  
1134 - get :media_listing, :profile => profile.identifier  
1135 - assert_no_tag :tag => 'div', :attributes => { :id => 'media-listing-documents' }, :descendant => { :tag => 'option', :content => /#{image_folder.name}/, :attributes => { :value => image_folder.id}}  
1136 - assert_tag :tag => 'div', :attributes => { :id => 'media-listing-documents' }, :descendant => { :tag => 'option', :content => /#{non_image_folder.name}/, :attributes => { :value => non_image_folder.id}}  
1137 - end  
1138 -  
1139 - should 'get a list of images from a image folder' do  
1140 - folder = Folder.create(:profile => profile, :name => 'Image folder')  
1141 - other_folder = Folder.create(:profile => profile, :name => 'Non image folder')  
1142 - image = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))  
1143 - file_in_folder = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'))  
1144 - image_in_other_folder = UploadedFile.create!(:profile => profile, :parent => other_folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))  
1145 -  
1146 - get :media_listing, :profile => profile.identifier, :image_folder_id => folder.id, :format => 'js'  
1147 -  
1148 - assert_includes assigns(:images), image  
1149 - assert_not_includes assigns(:images), file_in_folder  
1150 - assert_not_includes assigns(:images), image_in_other_folder  
1151 - end  
1152 -  
1153 - should 'get a list of images from profile' do  
1154 - image = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))  
1155 - folder = Folder.create(:profile => profile, :name => 'Image folder')  
1156 - image_in_folder = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))  
1157 - get :media_listing, :profile => profile.identifier, :image_folder_id => '', :format => 'js'  
1158 -  
1159 - assert_includes assigns(:images), image  
1160 - assert_not_includes assigns(:images), image_in_folder  
1161 - end  
1162 -  
1163 - should 'get a list of documents from a document folder' do  
1164 - folder = Folder.create(:profile => profile, :name => 'Non images folder')  
1165 - other_folder = Folder.create(:profile => profile, :name => 'Image folder')  
1166 - file = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'))  
1167 - image = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'))  
1168 - file_in_other_folder = UploadedFile.create!(:profile => profile, :parent => other_folder, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'))  
1169 -  
1170 - get :media_listing, :profile => profile.identifier, :document_folder_id => folder.id, :format => 'js'  
1171 -  
1172 - assert_includes assigns(:documents), file  
1173 - assert_not_includes assigns(:documents), image  
1174 - assert_not_includes assigns(:documents), file_in_other_folder  
1175 - end  
1176 -  
1177 - should 'get a list of documents from profile' do  
1178 - file = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'))  
1179 - folder = Folder.create(:profile => profile, :name => 'Image folder')  
1180 - file_in_folder = UploadedFile.create!(:profile => profile, :parent => folder, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'))  
1181 -  
1182 - get :media_listing, :profile => profile.identifier, :document_folder_id => '', :format => 'js'  
1183 -  
1184 - assert_includes assigns(:documents), file  
1185 - assert_not_includes assigns(:documents), file_in_folder  
1186 - end  
1187 -  
1188 - should 'display pagination links of images' do  
1189 - @controller.stubs(:per_page).returns(1)  
1190 -  
1191 - image = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/other-pic.jpg', 'image/jpg'))  
1192 - image2 = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :created_at => 1.day.ago)  
1193 - image2.updated_at = 1.day.ago  
1194 - image2.send :update_without_callbacks  
1195 -  
1196 - get :media_listing, :profile => profile.identifier  
1197 -  
1198 - assert_includes assigns(:images), image  
1199 - assert_not_includes assigns(:images), image2  
1200 - end  
1201 -  
1202 - should 'display pagination links of documents' do  
1203 - @controller.stubs(:per_page).returns(1)  
1204 - profile.articles.destroy_all  
1205 - file = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/feed.xml', 'text/xml'))  
1206 - file2 = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'))  
1207 - file2.created_at = 1.day.ago  
1208 - file2.save!  
1209 -  
1210 - get :media_listing, :profile => profile.identifier  
1211 -  
1212 - assert_includes assigns(:documents), file  
1213 - assert_not_includes assigns(:documents), file2  
1214 - end  
1215 -  
1216 -  
1217 - should 'redirect to media listing when upload files from there' do  
1218 - post :upload_files, :profile => profile.identifier, :media_listing => true, :uploaded_files => [fixture_file_upload('files/rails.png', 'image/png')]  
1219 - assert_template nil  
1220 - assert_redirected_to :action => 'media_listing'  
1221 - end  
1222 -  
1223 - should 'redirect to media listing when occur errors when upload files from there' do  
1224 - file = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('files/rails.png', 'image/png'))  
1225 -  
1226 - post :upload_files, :profile => profile.identifier, :media_listing => true, :uploaded_files => [fixture_file_upload('files/rails.png', 'image/png')]  
1227 - assert_template nil  
1228 - assert_redirected_to :action => 'media_listing' 1090 + assert_no_tag :div, :attributes => { :id => "text-editor-sidebar" }
1229 end 1091 end
1230 1092
1231 should "display 'Publish' when profile is a person" do 1093 should "display 'Publish' when profile is a person" do
@@ -1618,4 +1480,67 @@ class CmsControllerTest &lt; Test::Unit::TestCase @@ -1618,4 +1480,67 @@ class CmsControllerTest &lt; Test::Unit::TestCase
1618 end 1480 end
1619 end 1481 end
1620 1482
  1483 + should 'search for content for inclusion in articles' do
  1484 + file = UploadedFile.create!(:profile => @profile, :uploaded_data => fixture_file_upload('files/test.txt', 'text/plain'))
  1485 + get :search, :profile => @profile.identifier, :q => 'test.txt'
  1486 + assert_match /test.txt/, @response.body
  1487 + assert_equal 'application/json', @response.content_type
  1488 +
  1489 + data = parse_json_response
  1490 + assert_equal 'test.txt', data.first['title']
  1491 + assert_match /\/testinguser\/test.txt$/, data.first['url']
  1492 + assert_match /text/, data.first['icon']
  1493 + assert_match /text/, data.first['content_type']
  1494 + end
  1495 +
  1496 + should 'upload media by AJAX' do
  1497 + post :media_upload, :profile => profile.identifier, :file1 => fixture_file_upload('/files/test.txt', 'text/plain'), :file2 => fixture_file_upload('/files/rails.png', 'image/png'), :file3 => ''
  1498 + assert_match 'test.txt', @response.body
  1499 + assert_equal 'text/plain', @response.content_type
  1500 +
  1501 + data = parse_json_response
  1502 +
  1503 + assert_equal 'test.txt', data[0]['title']
  1504 + assert_match /\/testinguser\/test.txt$/, data[0]['url']
  1505 + assert_match /text/, data[0]['icon']
  1506 + assert_match /text/, data[0]['content_type']
  1507 + assert_nil data[0]['error']
  1508 +
  1509 + assert_equal 'rails.png', data[1]['title']
  1510 + assert_no_match /\/public\/articles\/.*\/rails.png$/, data[1]['url']
  1511 + assert_match /png$/, data[1]['icon']
  1512 + assert_match /image/, data[1]['content_type']
  1513 + assert_nil data[1]['error']
  1514 +
  1515 + end
  1516 +
  1517 + should 'not when media upload via AJAX contains empty files' do
  1518 + post :media_upload, :profile => @profile.identifier
  1519 + end
  1520 +
  1521 + should 'mark unsuccessfull uploads' do
  1522 + file = UploadedFile.create!(:profile => profile, :uploaded_data => fixture_file_upload('files/rails.png', 'image/png'))
  1523 +
  1524 + post :media_upload, :profile => profile.identifier, :media_listing => true, :file1 => fixture_file_upload('files/rails.png', 'image/png'), :file2 => fixture_file_upload('/files/test.txt', 'text/plain')
  1525 +
  1526 + assert_equal 'text/plain', @response.content_type
  1527 + data = parse_json_response
  1528 +
  1529 + assert_equal 'rails.png', data[0]['title']
  1530 + assert_not_nil data[0]['error']
  1531 + assert_match /rails.png/, data[0]['error']
  1532 +
  1533 + assert_equal 'test.txt', data[1]['title']
  1534 + assert_nil data[1]['error']
  1535 + end
  1536 +
  1537 + protected
  1538 +
  1539 + # FIXME this is to avoid adding an extra dependency for a proper JSON parser.
  1540 + # For now we are assuming that the JSON is close enough to Ruby and just
  1541 + # making some adjustments.
  1542 + def parse_json_response
  1543 + eval(@response.body.gsub('":', '"=>').gsub('null', 'nil'))
  1544 + end
  1545 +
1621 end 1546 end