Commit 1f3600fdd023fefb1f7d0364a2e424ab2181e9e6
Exists in
theme-brasil-digital-from-staging
and in
9 other branches
fix conflit with next
Showing
14 changed files
with
353 additions
and
44 deletions
Show diff stats
| ... | ... | @@ -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 | 212 | end |
| 213 | 213 | |
| 214 | 214 | def button(type, label, url, html_options = {}) |
| 215 | + html_options ||= {} | |
| 215 | 216 | the_class = 'with-text' |
| 216 | 217 | if html_options.has_key?(:class) |
| 217 | 218 | the_class << ' ' << html_options[:class] |
| ... | ... | @@ -398,19 +399,27 @@ module ApplicationHelper |
| 398 | 399 | end |
| 399 | 400 | end |
| 400 | 401 | |
| 401 | - def theme_view_file(template) | |
| 402 | + def theme_view_file(template, theme=nil) | |
| 402 | 403 | # Since we cannot control what people are doing in external themes, we |
| 403 | 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 | 407 | return file if File.exists?(file) |
| 406 | 408 | nil |
| 407 | 409 | end |
| 408 | 410 | |
| 409 | 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 | 421 | if file |
| 413 | - render options | |
| 422 | + render options.merge(file: file, use_full_path: false) | |
| 414 | 423 | else |
| 415 | 424 | nil |
| 416 | 425 | end |
| ... | ... | @@ -446,6 +455,14 @@ module ApplicationHelper |
| 446 | 455 | @theme_extra_navigation ||= theme_include 'navigation' |
| 447 | 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 | 466 | def is_testing_theme |
| 450 | 467 | !controller.session[:theme].nil? |
| 451 | 468 | end | ... | ... |
app/helpers/layout_helper.rb
| ... | ... | @@ -53,22 +53,30 @@ module LayoutHelper |
| 53 | 53 | 'block-store', |
| 54 | 54 | pngfix_stylesheet_path, |
| 55 | 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 | 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 | 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 | 76 | end |
| 69 | 77 | |
| 70 | 78 | def pngfix_stylesheet_path |
| 71 | - 'iepngfix/iepngfix.css' | |
| 79 | + 'iepngfix/iepngfix.css' #TODO: deprecate it | |
| 72 | 80 | end |
| 73 | 81 | |
| 74 | 82 | def tokeninput_stylesheets | ... | ... |
app/helpers/plugins_helper.rb
| ... | ... | @@ -6,4 +6,11 @@ module PluginsHelper |
| 6 | 6 | end |
| 7 | 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 | 16 | end | ... | ... |
app/views/content_viewer/_article_toolbar.html.erb
| ... | ... | @@ -47,10 +47,9 @@ |
| 47 | 47 | <%= button(:clock, _('All versions'), {:controller => 'content_viewer', :profile => profile.identifier, :action => 'article_versions'}, :id => 'article-versions-link') %> |
| 48 | 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 | 54 | <%= report_abuse(profile, :link, @page) %> |
| 56 | 55 | </div> | ... | ... |
app/views/layouts/application-ng.html.erb
| ... | ... | @@ -25,7 +25,7 @@ |
| 25 | 25 | end.join("\n") |
| 26 | 26 | %> |
| 27 | 27 | |
| 28 | - <script type='text/javascript'> | |
| 28 | + <script type="text/javascript"> | |
| 29 | 29 | DEFAULT_LOADING_MESSAGE = <%="'#{ _('loading...') }'" %>; |
| 30 | 30 | </script> |
| 31 | 31 | |
| ... | ... | @@ -38,9 +38,12 @@ |
| 38 | 38 | if content.respond_to?(:call) then instance_exec(&content).to_s.html_safe else content.to_s.html_safe end |
| 39 | 39 | end.join("\n") |
| 40 | 40 | %> |
| 41 | + <div id="global-header"> | |
| 42 | + <%= global_header %> | |
| 43 | + </div> | |
| 41 | 44 | |
| 42 | 45 | <div id="wrap-1"> |
| 43 | - <div id='theme-header'> | |
| 46 | + <div id="theme-header"> | |
| 44 | 47 | <%= theme_header %> |
| 45 | 48 | </div> |
| 46 | 49 | <div id="wrap-2"> |
| ... | ... | @@ -60,9 +63,14 @@ |
| 60 | 63 | </div><!-- end id="wrap-2" --> |
| 61 | 64 | </div><!-- end id="wrap-1" --> |
| 62 | 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 | 74 | <%= noosfero_layout_features %> |
| 67 | 75 | <%= addthis_javascript %> |
| 68 | 76 | <%= | ... | ... |
app/views/layouts/application.html.erb
| ... | ... | @@ -52,6 +52,9 @@ |
| 52 | 52 | registerDocumentSize(); |
| 53 | 53 | // --> |
| 54 | 54 | </script> |
| 55 | + <div id="global-header"> | |
| 56 | + <%= global_header %> | |
| 57 | + </div> | |
| 55 | 58 | |
| 56 | 59 | <div id="accessibility_menu"> |
| 57 | 60 | <a href="#content" id="link_go_content"><span><%= _('Go to content') %></span></a> |
| ... | ... | @@ -112,8 +115,13 @@ |
| 112 | 115 | </div><!-- id="wrap" --> |
| 113 | 116 | |
| 114 | 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 | 126 | <%# if you need to add HTML stuff to the layout, include it in |
| 119 | 127 | app/views/shared/noosfero_layout_features.html.erb! %> | ... | ... |
lib/noosfero/plugin.rb
| ... | ... | @@ -446,10 +446,17 @@ class Noosfero::Plugin |
| 446 | 446 | [] |
| 447 | 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 | 460 | end |
| 454 | 461 | |
| 455 | 462 | # -> Adds adicional content to article |
| ... | ... | @@ -706,6 +713,8 @@ class Noosfero::Plugin |
| 706 | 713 | # returns = string with reason of expiration |
| 707 | 714 | elsif method.to_s =~ /^content_expire_(#{content_actions.join('|')})$/ |
| 708 | 715 | nil |
| 716 | + elsif context.respond_to?(method) | |
| 717 | + context.send(method) | |
| 709 | 718 | else |
| 710 | 719 | super |
| 711 | 720 | end | ... | ... |
public/stylesheets/application.css
| ... | ... | @@ -77,19 +77,6 @@ div#errorExplanation h2 { |
| 77 | 77 | #footer_content { |
| 78 | 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 | 80 | div#profile-disabled { |
| 94 | 81 | border: 2px solid #944; |
| 95 | 82 | text-align: center; | ... | ... |
test/functional/content_viewer_controller_test.rb
| ... | ... | @@ -1436,4 +1436,99 @@ class ContentViewerControllerTest < ActionController::TestCase |
| 1436 | 1436 | |
| 1437 | 1437 | assert_no_tag :tag => 'h1', :attributes => { :class => /title/ }, :content => article.name |
| 1438 | 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 | 1534 | end | ... | ... |
test/unit/application_helper_test.rb
| ... | ... | @@ -961,6 +961,47 @@ class ApplicationHelperTest < ActionView::TestCase |
| 961 | 961 | assert_equal '', manage_communities |
| 962 | 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 | 1005 | protected |
| 965 | 1006 | include NoosferoTestHelper |
| 966 | 1007 | ... | ... |
test/unit/layout_helper_test.rb
| 1 | 1 | require_relative "../test_helper" |
| 2 | 2 | |
| 3 | 3 | class LayoutHelperTest < ActionView::TestCase |
| 4 | + include ApplicationHelper | |
| 4 | 5 | |
| 5 | 6 | should 'append logged-in class in body when user is logged-in' do |
| 6 | 7 | expects(:logged_in?).returns(true) |
| ... | ... | @@ -14,4 +15,19 @@ class LayoutHelperTest < ActionView::TestCase |
| 14 | 15 | assert_not_includes body_classes.split, 'logged-in' |
| 15 | 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 | 33 | end | ... | ... |
test/unit/plugin_test.rb
| ... | ... | @@ -560,4 +560,11 @@ class PluginTest < ActiveSupport::TestCase |
| 560 | 560 | assert_equivalent [st4.term, st2.term], limited_suggestions |
| 561 | 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 | 570 | end | ... | ... |
| ... | ... | @@ -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 | ... | ... |