Commit 1f3600fdd023fefb1f7d0364a2e424ab2181e9e6

Authored by Leandro Santos
2 parents bf31eeb9 89c5fafb

fix conflit with next

HACKING.themes.md 0 → 100644
@@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
  1 +Noosfero Instructions for Theme Developers
  2 +==========================================
  3 +
  4 +To build Noosfero themes you must to know HTML and CSS. You may also get some advantages with Ruby and Noosfero hacking knowledge because all customizable pieces of the theme's HTML structure are [erb](http://en.wikipedia.org/wiki/ERuby) files.
  5 +
  6 +
  7 +Organization Basics
  8 +-------------------
  9 +
  10 +A theme is a directory and must inside `noosfero/public/designs/themes`, and you will find tis themes in a fresh installation:
  11 +`noosfero`, `aluminium`, `base`, `butter`, `chameleon`, `chocolate`, `orange`, `plum`, `scarletred` and `skyblue`. The `default` is only a link to `noosfero` and you can change this link to any other.
  12 +
  13 +`noosfero` is the default theme with a big header. All other are colored themes with a thin header. That colored ones can be used as additional themes for any environment, as they will search for `/images/thin-logo.png` inside the current environment.theme, to use as top left logo.
  14 +
  15 +Inside a theme we can found:
  16 +* `theme.yml` — Theme description with some nice configuration options.
  17 +* `preview.png` — A 100x100 screenshot of this theme to the theme selection UI.
  18 +* `style.css` — The main file. The magic happens here.
  19 +* `errors.css` — Change the error page look. (only if this theme is linked by `defaut`)
  20 +* `favicon.ico` — The identifier icon for your web site.
  21 +* `images` — Another name can be found by your CSS, but will not allow to reuse the logo.
  22 + * `thin-logo.png` — The logo to be reused by the colored themes.
  23 + * *many images...*
  24 +* `site_title.html.erb` — A nice place to put your logo, any code here will be placed inside `h1#site-title`.
  25 +* `header.html.erb` — That goes inside `div#theme-header`.
  26 +* `navigation.html.erb` — That goes inside `div#navigation ul`, so use `<li>`s.
  27 +* `footer.html.erb` — That goes inside `div#theme-footer`.
  28 +
  29 +You can add more files like javascript and modularized CSS, but you must to refer that by the described files above.
  30 +
  31 +To refer one of this files trough the web the path is `<domain>/designs/themes/<thistheme>/<somefile>`.
  32 +
  33 +
  34 +theme.yml
  35 +---------
  36 +
  37 +A simple definition file. See this example:
  38 +```yml
  39 +name: "My Cool Theme"
  40 +layout: "application-ng"
  41 +jquery_theme: "smoothness"
  42 +icon_theme: [default, pidgin]
  43 +gravatar: "retro"
  44 +```
  45 +
  46 +About non obvious:
  47 +* `layout` is about the theme structure to use. The `application-ng` is enough for 99.97358% use cases. If you want to use another structure, you must add a new `*.html.erb` file at `app/views/layouts/`.
  48 +* `icon_theme` point to something inside `public/designs/icons/`.
  49 +* `gravatar` set the default gravatar *(avatar picture)* for people without picture.
  50 +
  51 +
  52 +Theme Intervention from Environment Theme
  53 +-----------------------------------------
  54 +
  55 +Sometimes an environment (as instace http://cirandas.net) wants to allow profiles to set its own theme, but with some environment identification or functions, like a top bar with the social network logo and a top menu (as instace http://cirandas.net/rango-vegan).
  56 +To make the magic happens you can add some files to the environment theme.
  57 +All are optional:
  58 +* `global.css` — this must be used to style all extra html added by your intervention partials. As it is a free form css file you can style anything, but this is a conflict risk.
  59 +* `global_header.html.erb` — Will add content to `#global-header`.
  60 +* `global_footer.html.erb` — Will add content to `#global-footer`.
app/helpers/application_helper.rb
@@ -212,6 +212,7 @@ module ApplicationHelper @@ -212,6 +212,7 @@ module ApplicationHelper
212 end 212 end
213 213
214 def button(type, label, url, html_options = {}) 214 def button(type, label, url, html_options = {})
  215 + html_options ||= {}
215 the_class = 'with-text' 216 the_class = 'with-text'
216 if html_options.has_key?(:class) 217 if html_options.has_key?(:class)
217 the_class << ' ' << html_options[:class] 218 the_class << ' ' << html_options[:class]
@@ -398,19 +399,27 @@ module ApplicationHelper @@ -398,19 +399,27 @@ module ApplicationHelper
398 end 399 end
399 end 400 end
400 401
401 - def theme_view_file(template) 402 + def theme_view_file(template, theme=nil)
402 # Since we cannot control what people are doing in external themes, we 403 # Since we cannot control what people are doing in external themes, we
403 # will keep looking for the deprecated .rhtml extension here. 404 # will keep looking for the deprecated .rhtml extension here.
404 - file = Rails.root.join('public', theme_path[1..-1], template + '.html.erb') 405 + addr = theme ? "designs/themes/#{theme}" : theme_path[1..-1]
  406 + file = Rails.root.join('public', addr, template + '.html.erb')
405 return file if File.exists?(file) 407 return file if File.exists?(file)
406 nil 408 nil
407 end 409 end
408 410
409 def theme_include(template, options = {}) 411 def theme_include(template, options = {})
410 - file = theme_view_file(template)  
411 - options.merge!({:file => file, :use_full_path => false}) 412 + from_theme_include(nil, template, options)
  413 + end
  414 +
  415 + def env_theme_include(template, options = {})
  416 + from_theme_include(environment.theme, template, options)
  417 + end
  418 +
  419 + def from_theme_include(theme, template, options = {})
  420 + file = theme_view_file(template, theme)
412 if file 421 if file
413 - render options 422 + render options.merge(file: file, use_full_path: false)
414 else 423 else
415 nil 424 nil
416 end 425 end
@@ -446,6 +455,14 @@ module ApplicationHelper @@ -446,6 +455,14 @@ module ApplicationHelper
446 @theme_extra_navigation ||= theme_include 'navigation' 455 @theme_extra_navigation ||= theme_include 'navigation'
447 end 456 end
448 457
  458 + def global_header
  459 + @global_header ||= env_theme_include 'global_header'
  460 + end
  461 +
  462 + def global_footer
  463 + @global_footer ||= env_theme_include 'global_footer'
  464 + end
  465 +
449 def is_testing_theme 466 def is_testing_theme
450 !controller.session[:theme].nil? 467 !controller.session[:theme].nil?
451 end 468 end
app/helpers/layout_helper.rb
@@ -53,22 +53,30 @@ module LayoutHelper @@ -53,22 +53,30 @@ module LayoutHelper
53 'block-store', 53 'block-store',
54 pngfix_stylesheet_path, 54 pngfix_stylesheet_path,
55 ] + tokeninput_stylesheets 55 ] + tokeninput_stylesheets
56 - plugins_stylesheets = @plugins.select(&:stylesheet?).map { |plugin| plugin.class.public_path('style.css') }  
57 -  
58 - output = ''  
59 - output += stylesheet_link_tag standard_stylesheets, :cache => 'cache/application'  
60 - output += stylesheet_link_tag template_stylesheet_path  
61 - output += stylesheet_link_tag icon_theme_stylesheet_path  
62 - output += stylesheet_link_tag jquery_ui_theme_stylesheet_path 56 + plugins_stylesheets = @plugins.select(&:stylesheet?).map { |plugin|
  57 + plugin.class.public_path('style.css')
  58 + }
  59 + global_css_pub = "/designs/themes/#{environment.theme}/global.css"
  60 + global_css_at_fs = Rails.root.join 'public' + global_css_pub
  61 +
  62 + output = []
  63 + output << stylesheet_link_tag(standard_stylesheets, :cache => 'cache/application')
  64 + output << stylesheet_link_tag(template_stylesheet_path)
  65 + output << stylesheet_link_tag(icon_theme_stylesheet_path)
  66 + output << stylesheet_link_tag(jquery_ui_theme_stylesheet_path)
63 unless plugins_stylesheets.empty? 67 unless plugins_stylesheets.empty?
64 - output += stylesheet_link_tag plugins_stylesheets, :cache => "cache/plugins-#{Digest::MD5.hexdigest plugins_stylesheets.to_s}" 68 + cacheid = "cache/plugins-#{Digest::MD5.hexdigest plugins_stylesheets.to_s}"
  69 + output << stylesheet_link_tag(plugins_stylesheets, :cache => cacheid)
65 end 70 end
66 - output += stylesheet_link_tag theme_stylesheet_path  
67 - output 71 + if File.exists? global_css_at_fs
  72 + output << stylesheet_link_tag(global_css_pub)
  73 + end
  74 + output << stylesheet_link_tag(theme_stylesheet_path)
  75 + output.join "\n"
68 end 76 end
69 77
70 def pngfix_stylesheet_path 78 def pngfix_stylesheet_path
71 - 'iepngfix/iepngfix.css' 79 + 'iepngfix/iepngfix.css' #TODO: deprecate it
72 end 80 end
73 81
74 def tokeninput_stylesheets 82 def tokeninput_stylesheets
app/helpers/plugins_helper.rb
@@ -6,4 +6,11 @@ module PluginsHelper @@ -6,4 +6,11 @@ module PluginsHelper
6 end 6 end
7 end 7 end
8 8
  9 + def plugins_toolbar_actions_for_article(article)
  10 + toolbar_actions = Array.wrap(@plugins.dispatch(:article_extra_toolbar_buttons, article))
  11 + toolbar_actions.each do |action|
  12 + [:title, :url, :icon].each { |param| raise "No #{param} was passed as parameter for #{action}" unless action.has_key?(param) }
  13 + end
  14 + end
  15 +
9 end 16 end
app/views/content_viewer/_article_toolbar.html.erb
@@ -47,10 +47,9 @@ @@ -47,10 +47,9 @@
47 <%= button(:clock, _('All versions'), {:controller => 'content_viewer', :profile => profile.identifier, :action => 'article_versions'}, :id => 'article-versions-link') %> 47 <%= button(:clock, _('All versions'), {:controller => 'content_viewer', :profile => profile.identifier, :action => 'article_versions'}, :id => 'article-versions-link') %>
48 <% end %> 48 <% end %>
49 49
50 - <%#*Adds extra buttons to the toolbar%>  
51 - <%= @plugins.dispatch(:article_extra_toolbar_buttons, @page).collect { |content| instance_exec(&content) }.join("") %>  
52 -  
53 - <%= @plugins.dispatch(:article_toolbar_actions, @page).collect { |content| instance_exec(&content) }.join("")%> 50 + <% plugins_toolbar_actions_for_article(@page).each do |plugin_button| %>
  51 + <%= button plugin_button[:icon], plugin_button[:title], plugin_button[:url], plugin_button[:html_options] %>
  52 + <% end %>
54 53
55 <%= report_abuse(profile, :link, @page) %> 54 <%= report_abuse(profile, :link, @page) %>
56 </div> 55 </div>
app/views/layouts/application-ng.html.erb
@@ -25,7 +25,7 @@ @@ -25,7 +25,7 @@
25 end.join("\n") 25 end.join("\n")
26 %> 26 %>
27 27
28 - <script type='text/javascript'> 28 + <script type="text/javascript">
29 DEFAULT_LOADING_MESSAGE = <%="'#{ _('loading...') }'" %>; 29 DEFAULT_LOADING_MESSAGE = <%="'#{ _('loading...') }'" %>;
30 </script> 30 </script>
31 31
@@ -38,9 +38,12 @@ @@ -38,9 +38,12 @@
38 if content.respond_to?(:call) then instance_exec(&content).to_s.html_safe else content.to_s.html_safe end 38 if content.respond_to?(:call) then instance_exec(&content).to_s.html_safe else content.to_s.html_safe end
39 end.join("\n") 39 end.join("\n")
40 %> 40 %>
  41 + <div id="global-header">
  42 + <%= global_header %>
  43 + </div>
41 44
42 <div id="wrap-1"> 45 <div id="wrap-1">
43 - <div id='theme-header'> 46 + <div id="theme-header">
44 <%= theme_header %> 47 <%= theme_header %>
45 </div> 48 </div>
46 <div id="wrap-2"> 49 <div id="wrap-2">
@@ -60,9 +63,14 @@ @@ -60,9 +63,14 @@
60 </div><!-- end id="wrap-2" --> 63 </div><!-- end id="wrap-2" -->
61 </div><!-- end id="wrap-1" --> 64 </div><!-- end id="wrap-1" -->
62 <%= render_environment_features(:logged_in) if logged_in? %> 65 <%= render_environment_features(:logged_in) if logged_in? %>
63 - <div id="theme-footer">  
64 - <%= theme_footer %>  
65 - </div><!-- end id="theme-footer" --> 66 + <div id="footer">
  67 + <div id="theme-footer">
  68 + <%= theme_footer %>
  69 + </div><!-- end id="theme-footer" -->
  70 + <div id="global-footer">
  71 + <%= global_footer %>
  72 + </div><!-- end id="global-footer" -->
  73 + </div><!-- end id="footer" -->
66 <%= noosfero_layout_features %> 74 <%= noosfero_layout_features %>
67 <%= addthis_javascript %> 75 <%= addthis_javascript %>
68 <%= 76 <%=
app/views/layouts/application.html.erb
@@ -52,6 +52,9 @@ @@ -52,6 +52,9 @@
52 registerDocumentSize(); 52 registerDocumentSize();
53 // --> 53 // -->
54 </script> 54 </script>
  55 + <div id="global-header">
  56 + <%= global_header %>
  57 + </div>
55 58
56 <div id="accessibility_menu"> 59 <div id="accessibility_menu">
57 <a href="#content" id="link_go_content"><span><%= _('Go to content') %></span></a> 60 <a href="#content" id="link_go_content"><span><%= _('Go to content') %></span></a>
@@ -112,8 +115,13 @@ @@ -112,8 +115,13 @@
112 </div><!-- id="wrap" --> 115 </div><!-- id="wrap" -->
113 116
114 <div id="footer"> 117 <div id="footer">
115 - <%= theme_footer %>  
116 - </div><!-- id="footer" --> 118 + <div id="theme-footer">
  119 + <%= theme_footer %>
  120 + </div><!-- end id="theme-footer" -->
  121 + <div id="global-footer">
  122 + <%= global_footer %>
  123 + </div><!-- end id="global-footer" -->
  124 + </div><!-- end id="footer" -->
117 125
118 <%# if you need to add HTML stuff to the layout, include it in 126 <%# if you need to add HTML stuff to the layout, include it in
119 app/views/shared/noosfero_layout_features.html.erb! %> 127 app/views/shared/noosfero_layout_features.html.erb! %>
lib/noosfero/plugin.rb
@@ -446,10 +446,17 @@ class Noosfero::Plugin @@ -446,10 +446,17 @@ class Noosfero::Plugin
446 [] 446 []
447 end 447 end
448 448
449 - # -> Adds aditional actions to article  
450 - # returns = lambda block that creates html code  
451 - def article_toolbar_actions article  
452 - nil 449 + # -> Adds aditional action buttons to article
  450 + # returns = { :title => title, :icon => icon, :url => url, :html_options => {} }
  451 + # title = name that will be displayed.
  452 + # icon = css class name (for customized icons include them in a css file).
  453 + # url = url or route to which the button will redirect.
  454 + # html_options = Html options for customization
  455 + #
  456 + # Multiple values could be passed as parameter.
  457 + # returns = [{:title => title, :icon => icon}, {:title => title, :icon => icon}]
  458 + def article_extra_toolbar_buttons(article)
  459 + []
453 end 460 end
454 461
455 # -> Adds adicional content to article 462 # -> Adds adicional content to article
@@ -706,6 +713,8 @@ class Noosfero::Plugin @@ -706,6 +713,8 @@ class Noosfero::Plugin
706 # returns = string with reason of expiration 713 # returns = string with reason of expiration
707 elsif method.to_s =~ /^content_expire_(#{content_actions.join('|')})$/ 714 elsif method.to_s =~ /^content_expire_(#{content_actions.join('|')})$/
708 nil 715 nil
  716 + elsif context.respond_to?(method)
  717 + context.send(method)
709 else 718 else
710 super 719 super
711 end 720 end
public/stylesheets/application.css
@@ -77,19 +77,6 @@ div#errorExplanation h2 { @@ -77,19 +77,6 @@ div#errorExplanation h2 {
77 #footer_content { 77 #footer_content {
78 clear: both; 78 clear: both;
79 } 79 }
80 -#footer {  
81 - text-align: center;  
82 - clear: both;  
83 - font-size: 10px;  
84 - color: #777;  
85 -}  
86 -#footer a {  
87 - color: #777;  
88 - text-decoration: none;  
89 -}  
90 -#footer a:hover {  
91 - color: #555;  
92 -}  
93 div#profile-disabled { 80 div#profile-disabled {
94 border: 2px solid #944; 81 border: 2px solid #944;
95 text-align: center; 82 text-align: center;
test/functional/content_viewer_controller_test.rb
@@ -1436,4 +1436,99 @@ class ContentViewerControllerTest &lt; ActionController::TestCase @@ -1436,4 +1436,99 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
1436 1436
1437 assert_no_tag :tag => 'h1', :attributes => { :class => /title/ }, :content => article.name 1437 assert_no_tag :tag => 'h1', :attributes => { :class => /title/ }, :content => article.name
1438 end 1438 end
  1439 +
  1440 + should 'add extra toolbar actions on article from plugins' do
  1441 + class Plugin1 < Noosfero::Plugin
  1442 + def article_extra_toolbar_buttons(article)
  1443 + {:title => 'some_title1', :icon => 'some_icon1', :url => {}}
  1444 + end
  1445 + end
  1446 + Noosfero::Plugin.stubs(:all).returns([Plugin1.name])
  1447 +
  1448 + Environment.default.enable_plugin(Plugin1.name)
  1449 +
  1450 + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text')
  1451 +
  1452 + get :view_page, :profile => profile.identifier, :page => [ 'myarticle' ]
  1453 + assert_tag :tag => 'div', :attributes => { :id => 'article-actions' }, :descendant => { :tag => 'a', :attributes => { :title => "some_title1" }}
  1454 + end
  1455 +
  1456 + should 'add more than one extra toolbar actions on article from plugins' do
  1457 + class Plugin1 < Noosfero::Plugin
  1458 + def article_extra_toolbar_buttons(article)
  1459 + {:title => 'some_title1', :icon => 'some_icon1', :url => {}}
  1460 + end
  1461 + end
  1462 + class Plugin2 < Noosfero::Plugin
  1463 + def article_extra_toolbar_buttons(article)
  1464 + {:title => 'some_title2', :icon => 'some_icon2', :url => {}}
  1465 + end
  1466 + end
  1467 + Noosfero::Plugin.stubs(:all).returns([Plugin1.name, Plugin2.name])
  1468 +
  1469 + Environment.default.enable_plugin(Plugin1.name)
  1470 + Environment.default.enable_plugin(Plugin2.name)
  1471 +
  1472 + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text')
  1473 +
  1474 + get :view_page, :profile => profile.identifier, :page => [ 'myarticle' ]
  1475 + assert_tag :tag => 'div', :attributes => { :id => 'article-actions' }, :descendant => { :tag => 'a', :attributes => { :title => "some_title1" }}
  1476 + assert_tag :tag => 'div', :attributes => { :id => 'article-actions' }, :descendant => { :tag => 'a', :attributes => { :title => "some_title2" }}
  1477 + end
  1478 +
  1479 + should 'add icon attribute in extra toolbar actions on article from plugins' do
  1480 + class Plugin1 < Noosfero::Plugin
  1481 + def article_extra_toolbar_buttons(article)
  1482 + {:title => 'some_title', :icon => 'some_icon', :url => {}}
  1483 + end
  1484 + end
  1485 + Noosfero::Plugin.stubs(:all).returns([Plugin1.name])
  1486 +
  1487 + Environment.default.enable_plugin(Plugin1.name)
  1488 +
  1489 + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text')
  1490 +
  1491 + get :view_page, :profile => profile.identifier, :page => [ 'myarticle' ]
  1492 + assert_tag :tag => 'div', :attributes => { :id => 'article-actions' }, :descendant => { :tag => 'a', :attributes => { :class => /some_icon/ }}
  1493 + end
  1494 +
  1495 + should 'add url attribute in extra toolbar actions on article from plugins' do
  1496 + class Plugin1 < Noosfero::Plugin
  1497 + def article_extra_toolbar_buttons(article)
  1498 + {:title => 'some_title', :icon => 'some_icon', :url => '/someurl'}
  1499 + end
  1500 + end
  1501 + Noosfero::Plugin.stubs(:all).returns([Plugin1.name])
  1502 +
  1503 + Environment.default.enable_plugin(Plugin1.name)
  1504 +
  1505 + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text')
  1506 +
  1507 + get :view_page, :profile => profile.identifier, :page => [ 'myarticle' ]
  1508 + assert_tag :tag => 'div', :attributes => { :id => 'article-actions' }, :descendant => { :tag => 'a', :attributes => { :href => "/someurl" }}
  1509 + end
  1510 +
  1511 + should 'use context method in extra toolbar actions on article from plugins' do
  1512 + class Plugin1 < Noosfero::Plugin
  1513 + def article_extra_toolbar_buttons(article)
  1514 + if current_person.public?
  1515 + {:title => 'some_title', :icon => 'some_icon', :url => '/someurl'}
  1516 + else
  1517 + {:title => 'another_title', :icon => 'another_icon', :url => '/anotherurl'}
  1518 + end
  1519 + end
  1520 + end
  1521 + Noosfero::Plugin.stubs(:all).returns([Plugin1.name])
  1522 +
  1523 + Environment.default.enable_plugin(Plugin1.name)
  1524 +
  1525 + page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text')
  1526 +
  1527 + profile.public_profile = false
  1528 + profile.save
  1529 + login_as(profile.identifier)
  1530 + get :view_page, :profile => profile.identifier, :page => [ 'myarticle' ]
  1531 + assert_tag :tag => 'div', :attributes => { :id => 'article-actions' }, :descendant => { :tag => 'a', :attributes => { :href => "/anotherurl" }}
  1532 + end
  1533 +
1439 end 1534 end
test/unit/application_helper_test.rb
@@ -961,6 +961,47 @@ class ApplicationHelperTest &lt; ActionView::TestCase @@ -961,6 +961,47 @@ class ApplicationHelperTest &lt; ActionView::TestCase
961 assert_equal '', manage_communities 961 assert_equal '', manage_communities
962 end 962 end
963 963
  964 + should 'include file from current theme out of a profile page' do
  965 + def profile; nil; end
  966 + def environment; e={}; def e.theme; 'env-theme'; end; e; end
  967 + def render(opt); opt; end
  968 + File.stubs(:exists?).returns(false)
  969 + file = Rails.root.join 'public/designs/themes/env-theme/somefile.html.erb'
  970 + assert_nil theme_include('somefile') # exists? = false
  971 + File.expects(:exists?).with(file).returns(true).at_least_once
  972 + assert_equal file, theme_include('somefile')[:file] # exists? = true
  973 + end
  974 +
  975 + should 'include file from current theme inside a profile page' do
  976 + def profile; p={}; def p.theme; 'my-theme'; end; p; end
  977 + def render(opt); opt; end
  978 + File.stubs(:exists?).returns(false)
  979 + file = Rails.root.join 'public/designs/themes/my-theme/otherfile.html.erb'
  980 + assert_nil theme_include('otherfile') # exists? = false
  981 + File.expects(:exists?).with(file).returns(true).at_least_once
  982 + assert_equal file, theme_include('otherfile')[:file] # exists? = true
  983 + end
  984 +
  985 + should 'include file from env theme' do
  986 + def profile; p={}; def p.theme; 'my-theme'; end; p; end
  987 + def environment; e={}; def e.theme; 'env-theme'; end; e; end
  988 + def render(opt); opt; end
  989 + File.stubs(:exists?).returns(false)
  990 + file = Rails.root.join 'public/designs/themes/env-theme/afile.html.erb'
  991 + assert_nil env_theme_include('afile') # exists? = false
  992 + File.expects(:exists?).with(file).returns(true).at_least_once
  993 + assert_equal file, env_theme_include('afile')[:file] # exists? = true
  994 + end
  995 +
  996 + should 'include file from some theme' do
  997 + def render(opt); opt; end
  998 + File.stubs(:exists?).returns(false)
  999 + file = Rails.root.join 'public/designs/themes/atheme/afile.html.erb'
  1000 + assert_nil from_theme_include('atheme', 'afile') # exists? = false
  1001 + File.expects(:exists?).with(file).returns(true).at_least_once
  1002 + assert_equal file, from_theme_include('atheme', 'afile')[:file] # exists? = true
  1003 + end
  1004 +
964 protected 1005 protected
965 include NoosferoTestHelper 1006 include NoosferoTestHelper
966 1007
test/unit/layout_helper_test.rb
1 require_relative "../test_helper" 1 require_relative "../test_helper"
2 2
3 class LayoutHelperTest < ActionView::TestCase 3 class LayoutHelperTest < ActionView::TestCase
  4 + include ApplicationHelper
4 5
5 should 'append logged-in class in body when user is logged-in' do 6 should 'append logged-in class in body when user is logged-in' do
6 expects(:logged_in?).returns(true) 7 expects(:logged_in?).returns(true)
@@ -14,4 +15,19 @@ class LayoutHelperTest &lt; ActionView::TestCase @@ -14,4 +15,19 @@ class LayoutHelperTest &lt; ActionView::TestCase
14 assert_not_includes body_classes.split, 'logged-in' 15 assert_not_includes body_classes.split, 'logged-in'
15 end 16 end
16 17
  18 + should 'add global.css to noosfero_stylesheets if env theme has it' do
  19 + env = fast_create Environment
  20 + env.theme = 'my-theme'
  21 + @plugins = []
  22 + expects(:profile).returns(nil).at_least_once
  23 + expects(:environment).returns(env).at_least_once
  24 + expects(:theme_option).with(:icon_theme).returns(['my-icons']).at_least_once
  25 + expects(:jquery_theme).returns('jquery-nice').at_least_once
  26 + global_css = Rails.root.join "public/designs/themes/#{env.theme}/global.css"
  27 + File.stubs(:exists?).returns(false)
  28 + File.expects(:exists?).with(global_css).returns(true).at_least_once
  29 + css = noosfero_stylesheets
  30 + assert_match /<link [^<]*href="\/designs\/themes\/my-theme\/global.css"/, css
  31 + end
  32 +
17 end 33 end
test/unit/plugin_test.rb
@@ -560,4 +560,11 @@ class PluginTest &lt; ActiveSupport::TestCase @@ -560,4 +560,11 @@ class PluginTest &lt; ActiveSupport::TestCase
560 assert_equivalent [st4.term, st2.term], limited_suggestions 560 assert_equivalent [st4.term, st2.term], limited_suggestions
561 end 561 end
562 562
  563 + should 'article_extra_toolbar_buttons return an empty array by default' do
  564 + class Plugin1 < Noosfero::Plugin
  565 + end
  566 + p = Plugin1.new
  567 + assert_equal [], p.article_extra_toolbar_buttons(nil)
  568 + end
  569 +
563 end 570 end
test/unit/plugins_helper_test.rb 0 → 100644
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +require_relative "../test_helper"
  2 +
  3 +class PluginsHelperTest < ActionView::TestCase
  4 +
  5 + def setup
  6 + @environment = Environment.default
  7 + @plugins = mock
  8 + end
  9 +
  10 + attr_accessor :environment, :plugins
  11 +
  12 + should 'plugins_toolbar_actions_for_article return an array if the plugin return a single hash' do
  13 + hash = {:title => 'some title', :url => 'some_url', :icon => 'some icon'}
  14 + plugins.expects(:dispatch).with(:article_extra_toolbar_buttons, nil).returns(hash)
  15 + assert_equal [hash], plugins_toolbar_actions_for_article(nil)
  16 + end
  17 +
  18 + should 'plugins_toolbar_actions_for_article return an empty array if an array is passed as parameter' do
  19 + plugins.expects(:dispatch).with(:article_extra_toolbar_buttons, nil).returns([])
  20 + assert_equal [], plugins_toolbar_actions_for_article(nil)
  21 + end
  22 +
  23 + should 'plugins_toolbar_actions_for_article throw raise if no title is passed as parameter' do
  24 + plugins.expects(:dispatch).with(:article_extra_toolbar_buttons, nil).returns({:url => 'some_url', :icon => 'some icon'})
  25 +
  26 + assert_raise(RuntimeError) do
  27 + plugins_toolbar_actions_for_article(nil)
  28 + end
  29 + end
  30 +
  31 + should 'plugins_toolbar_actions_for_article throw raise if no icon is passed as parameter' do
  32 + plugins.expects(:dispatch).with(:article_extra_toolbar_buttons, nil).returns({:title => 'some title', :url => 'some_url'})
  33 +
  34 + assert_raise(RuntimeError) do
  35 + plugins_toolbar_actions_for_article(nil)
  36 + end
  37 + end
  38 +
  39 + should 'plugins_toolbar_actions_for_article throw raise if no url is passed as parameter' do
  40 + plugins.expects(:dispatch).with(:article_extra_toolbar_buttons, nil).returns({:title => 'some title', :icon => 'some icon'})
  41 +
  42 + assert_raise(RuntimeError) do
  43 + plugins_toolbar_actions_for_article(nil)
  44 + end
  45 + end
  46 +
  47 +end