Commit 8f42e790ed5d0191e62237e24a6e0a68514ff087

Authored by Leandro Nunes dos Santos
1 parent e22e8356

merging with stable

Showing 1039 changed files with 144546 additions and 114933 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 1039 files displayed.

AUTHORS
... ... @@ -13,16 +13,30 @@ Alessandro Palmeira + Caio Salgado <alessandro.palmeira@gmail.com>
13 13 Alessandro Palmeira + Caio Salgado <caio.csalgado@gmail.com>
14 14 Alessandro Palmeira + Caio Salgado + Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>
15 15 Alessandro Palmeira + Carlos Morais <alessandro.palmeira@gmail.com>
  16 +Alessandro Palmeira + Daniel Alves <alessandro.palmeira@gmail.com>
  17 +Alessandro Palmeira + Daniel Alves + Diego Araújo <diegoamc90@gmail.com>
  18 +Alessandro Palmeira + Daniel Alves + Diego Araújo + Guilherme Rojas <danpaulalves@gmail.com>
  19 +Alessandro Palmeira + Diego Araujo <alessandro.palmeira@gmail.com>
16 20 Alessandro Palmeira + Diego Araújo <alessandro.palmeira@gmail.com>
  21 +Alessandro Palmeira + Diego Araujo + Daniela Feitosa <alessandro.palmeira@gmail.com>
  22 +Alessandro Palmeira + Diego Araujo <diegoamc90@gmail.com>
17 23 Alessandro Palmeira + Diego Araújo <diegoamc90@gmail.com>
  24 +Alessandro Palmeira + Diego Araujo + Eduardo Morais <alessandro.palmeira@gmail.com>
  25 +Alessandro Palmeira + Diego Araújo + João M. M. da Silva <alessandro.palmeira@gmail.com>
  26 +Alessandro Palmeira + Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>
  27 +Alessandro Palmeira + Diego Araujo + João M. M. da Silva + Paulo Meirelles <alessandro.palmeira@gmail.com>
18 28 Alessandro Palmeira + Diego Araújo + Pedro Leal <diegoamc90@gmail.com>
19 29 Alessandro Palmeira + Diego Araújo + Pedro Leal + João M. M. da Silva <diegoamc90@gmail.com>
20 30 Alessandro Palmeira + Diego Araujo + Rafael Manzo <alessandro.palmeira@gmail.com>
  31 +Alessandro Palmeira + Eduardo Morais <alessandro.palmeira@gmail.com>
  32 +Alessandro Palmeira + Guilherme Rojas <alessandro.palmeira@gmail.com>
21 33 Alessandro Palmeira + Jefferson Fernandes <alessandro.palmeira@gmail.com>
22 34 Alessandro Palmeira + João M. M. da Silva <alessandro.palmeira@gmail.com>
  35 +Alessandro Palmeira + Joao M. M. da Silva + Diego Araujo <alessandro.palmeira@gmail.com>
23 36 Alessandro Palmeira + João M. M. da Silva + Renan Teruo <alessandro.palmeira@gmail.com>
24 37 Alessandro Palmeira + João M. M. Silva <alessandro.palmeira@gmail.com>
25 38 Alessandro Palmeira + Paulo Meirelles <alessandro.palmeira@gmail.com>
  39 +Alessandro Palmeira + Paulo Meirelles + João M. M. da Silva <alessandro.palmeira@gmail.com>
26 40 Alessandro Palmeira + Rafael Manzo <alessandro.palmeira@gmail.com>
27 41 Antonio Terceiro + Carlos Morais <terceiro@colivre.coop.br>
28 42 Antonio Terceiro + Paulo Meirelles <terceiro@colivre.coop.br>
... ... @@ -32,6 +46,7 @@ Braulio Bhavamitra &lt;brauliobo@gmail.com&gt;
32 46 Bráulio Bhavamitra <brauliobo@gmail.com>
33 47 Caio <caio.csalgado@gmail.com>
34 48 Caio + Diego + Pedro + João <caio.csalgado@gmail.com>
  49 +Caio Formiga <caio.formiga@gmail.com>
35 50 Caio, Pedro <caio.csalgado@gmail.com>
36 51 Caio Salgado + Alessandro Palmeira <caio.csalgado@gmail.com>
37 52 Caio Salgado <caio.csalgado@gmail.com>
... ... @@ -57,26 +72,42 @@ Carlos Morais + Diego Araújo &lt;diegoamc90@gmail.com&gt;
57 72 Carlos Morais + Eduardo Morais <carlos88morais@gmail.com>
58 73 Carlos Morais + Paulo Meirelles <carlos88morais@gmail.com>
59 74 Carlos Morais + Pedro Leal <carlos88morais@gmail.com>
  75 +Daniel Alves + Diego Araújo <danpaulalves@gmail.com>
  76 +Daniel Alves + Diego Araújo <diegoamc90@gmail.com>
  77 +Daniel Alves + Diego Araújo + Guilherme Rojas <danpaulalves@gmail.com>
  78 +Daniel Alves + Diego Araújo + Guilherme Rojas <diegoamc90@gmail.com>
  79 +Daniel Alves + Diego Araújo + Guilherme Rojas <guilhermehrojas@gmail.com>
  80 +Daniel Alves + Guilherme Rojas <danpaulalves@gmail.com>
  81 +Daniel Alves + Rafael Manzo <rr.manzo@gmail.com>
60 82 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br>
61 83 Daniel Cunha <daniel@colivre.coop.br>
62 84 diegoamc <diegoamc90@gmail.com>
63 85 Diego Araújo + Alessandro Palmeira <diegoamc90@gmail.com>
  86 +Diego Araújo + Alessandro Palmeira + João M. M. da Silva <diegoamc90@gmail.com>
  87 +Diego Araújo + Alessandro Palmeira + Rafael Manzo <rr.manzo@gmail.com>
64 88 Diego Araujo + Caio Salgado <diegoamc90@gmail.com>
  89 +Diego Araújo + Daniel Alves + Rafael Manzo <rr.manzo@gmail.com>
65 90 Diego Araújo <diegoamc90@gmail.com>
  91 +Diego Araújo + Eduardo Morais + Paulo Meirelles <diegoamc90@gmail.com>
  92 +Diego Araújo + Guilherme Rojas <diegoamc90@gmail.com>
66 93 Diego Araújo + Jefferson Fernandes <diegoamc90@gmail.com>
67 94 Diego Araujo + Jefferson Fernandes <jeffs.fernandes@gmail.com>
68 95 Diego Araújo + João Machini <diegoamc90@gmail.com>
69 96 Diego Araújo + João Machini <digoamc90@gmail.com>
  97 +Diego Araújo + João M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
70 98 Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>
71 99 Diego Araújo + João M. M. da Silva + João Machini <diegoamc90@gmail.com>
72 100 Diego Araújo + João M. M. da Silva + Pedro Leal <diegoamc90@gmail.com>
73 101 Diego Araújo + Paulo Meirelles <diegoamc90@gmail.com>
74 102 Diego Araújo + Pedro Leal <diegoamc90@gmail.com>
  103 +Diego Araujo + Rafael Manzo <diegoamc90@gmail.com>
75 104 Diego Araújo + Rafael Manzo <diegoamc90@gmail.com>
76 105 Diego Araújo + Renan Teruo + Alessandro Palmeira <diegoamc90@gmail.com>
77 106 Diego Araújo + Renan Teruo <diegoamc90@gmail.com>
  107 +Diego Araujo + Rodrigo Souto + Rafael Manzo <rr.manzo@gmail.com>
78 108 Diego + Jefferson <diegoamc90@gmail.com>
79 109 Diego Martinez <diegoamc90@gmail.com>
  110 +Diego Martinez <diego@diego-K55A.(none)>
80 111 Diego + Renan <renanteruoc@gmail.com>
81 112 Fernanda Lopes <nanda.listas+psl@gmail.com>
82 113 Grazieno Pellegrino <grazieno@gmail.com>
... ... @@ -89,6 +120,7 @@ João da Silva &lt;jaodsilv@linux.ime.usp.br&gt;
89 120 João Marco Maciel da Silva + Rafael Manzo + Renan Teruo <jaodsilv@linux.ime.usp.br>
90 121 João M. M. da Silva + Alessandro Palmeira + Diego Araújo + Caio Salgado <jaodsilv@linux.ime.usp.br>
91 122 João M. M. da Silva + Alessandro Palmeira + Diego Araújo <jaodsilv@linux.ime.usp.br>
  123 +Joao M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
92 124 João M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
93 125 João M. M. da Silva + Alessandro Palmeira + João Machini <jaodsilv@linux.ime.usp.br>
94 126 João M. M. da Silva + Caio Salgado + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
... ... @@ -120,21 +152,30 @@ Larissa Reis &lt;reiss.larissa@gmail.com&gt;
120 152 Leandro Nunes dos Santos <leandronunes@gmail.com>
121 153 Leandro Nunes dos Santos <leandro.santos@serpro.gov.br>
122 154 LinguÁgil 2010 <linguagil.bahia@gmail.com>
  155 +Lucas Melo <lucas@colivre.coop.br>
123 156 Luis David Aguilar Carlos <ludwig9003@gmail.com>
124 157 Martín Olivera <molivera@solar.org.ar>
125 158 Moises Machado <moises@colivre.coop.br>
126 159 Nanda Lopes <nanda.listas+psl@gmail.com>
  160 +Paulo Meirelles + Alessandro Palmeira + João M. M. da Silva <paulo@softwarelivre.org>
127 161 Paulo Meirelles + Alessandro Palmeira <paulo@softwarelivre.org>
128 162 Paulo Meirelles + Carlos Morais <paulo@softwarelivre.org>
129 163 Paulo Meirelles + Diego Araújo <paulo@softwarelivre.org>
130 164 Paulo Meirelles + João M. M. da Silva <paulo@softwarelivre.org>
131 165 Paulo Meirelles <paulo@softwarelivre.org>
  166 +Paulo Meirelles + Rafael Manzo <paulo@softwarelivre.org>
132 167 Rafael Gomes <rafaelgomes@techfree.com.br>
  168 +Rafael Manzo + Alessandro Palmeira <rr.manzo@gmail.com>
  169 +Rafael Manzo + Daniel Alves <danpaulalves@gmail.com>
  170 +Rafael Manzo + Diego Araújo <rr.manzo@gmail.com>
133 171 Rafael Manzo + João M. M. Silva <rr.manzo@gmail.com>
  172 +Rafael Manzo + Paulo Meirelles <rr.manzo@gmail.com>
134 173 Rafael Martins <rmmartins@gmail.com>
135 174 Rafael Reggiani Manzo + Caio Salgado + Jefferson Fernandes <rr.manzo@gmail.com>
136 175 Rafael Reggiani Manzo + Diego Araujo <diegoamc90@gmail.com>
137 176 Rafael Reggiani Manzo + Diego Araujo <rr.manzo@gmail.com>
  177 +Rafael Reggiani Manzo + Diego Araújo <rr.manzo@gmail.com>
  178 +Rafael Reggiani Manzo + João M. M. da Silva <rr.manzo@gmail.com>
138 179 Rafael Reggiani Manzo <rr.manzo@gmail.com>
139 180 Raphaël Rousseau <raph@r4f.org>
140 181 Raquel Lira <raquel.lira@gmail.com>
... ... @@ -146,8 +187,11 @@ Renan Teruo + Paulo Meirelles &lt;renanteruoc@gmail.com&gt;
146 187 Renan Teruo + Rafael Manzo <renanteruoc@gmail.com>
147 188 Rodrigo Souto <rodrigo@colivre.coop.br>
148 189 Ronny Kursawe <kursawe.ronny@googlemail.com>
  190 +root <root@debian.sdr.serpro>
149 191 Samuel R. C. Vale <srcvale@holoscopio.com>
150 192 Valessio Brito <valessio@gmail.com>
  193 +vfcosta <vfcosta@gmail.com>
  194 +Visita <visita@debian.(none)>
151 195 Yann Lugrin <yann.lugrin@liquid-concept.ch>
152 196  
153 197 Ideas, specifications and incentive
... ...
Gemfile
1   -source :rubygems
2   -gem 'cucumber', '0.4.0'
3   -gem 'webrat', '0.5.1'
4   -gem 'rspec', '1.2.9'
5   -gem 'rspec-rails', '1.2.9'
6   -gem 'Selenium', '>= 1.1.14'
7   -gem 'selenium-client', '>= 1.2.17'
8   -gem 'database_cleaner'
  1 +source "https://rubygems.org"
  2 +
9 3 gem 'exception_notification', '1.0.20090728'
10 4 gem 'system_timer'
11 5  
  6 +group :test do
  7 + gem 'rspec', '1.2.9'
  8 + gem 'rspec-rails', '1.2.9'
  9 +end
  10 +
  11 +group :cucumber do
  12 + gem 'rake', '0.8.7'
  13 + gem 'cucumber-rails', '0.3.2'
  14 + gem 'capybara', '1.1.1'
  15 + gem 'cucumber', '1.1.0'
  16 + gem 'database_cleaner'
  17 +end
  18 +
12 19 def program(name)
13 20 unless system("which #{name} > /dev/null")
14 21 puts "W: Program #{name} is needed, but was not found in your PATH"
... ...
Gemfile.lock
1 1 GEM
2   - remote: http://rubygems.org/
  2 + remote: https://rubygems.org/
3 3 specs:
4   - Selenium (1.1.14)
5   - builder (3.0.0)
6   - cucumber (0.4.0)
  4 + builder (3.1.4)
  5 + capybara (1.1.1)
  6 + mime-types (>= 1.16)
  7 + nokogiri (>= 1.3.3)
  8 + rack (>= 1.0.0)
  9 + rack-test (>= 0.5.4)
  10 + selenium-webdriver (~> 2.0)
  11 + xpath (~> 0.1.4)
  12 + childprocess (0.3.6)
  13 + ffi (~> 1.0, >= 1.0.6)
  14 + cucumber (1.1.0)
7 15 builder (>= 2.1.2)
8 16 diff-lcs (>= 1.1.2)
9   - polyglot (>= 0.2.9)
10   - term-ansicolor (>= 1.0.3)
11   - treetop (>= 1.4.2)
12   - database_cleaner (0.7.0)
  17 + gherkin (~> 2.5.0)
  18 + json (>= 1.4.6)
  19 + term-ansicolor (>= 1.0.6)
  20 + cucumber-rails (0.3.2)
  21 + cucumber (>= 0.8.0)
  22 + database_cleaner (0.9.1)
13 23 diff-lcs (1.1.3)
14 24 exception_notification (1.0.20090728)
15   - nokogiri (1.5.0)
16   - polyglot (0.3.3)
17   - rack (1.3.5)
  25 + ffi (1.2.0)
  26 + gherkin (2.5.4)
  27 + json (>= 1.4.6)
  28 + json (1.7.5)
  29 + libwebsocket (0.1.6.1)
  30 + websocket
  31 + mime-types (1.19)
  32 + multi_json (1.3.7)
  33 + nokogiri (1.5.5)
  34 + rack (1.1.0)
  35 + rack-test (0.6.2)
  36 + rack (>= 1.0)
  37 + rake (0.8.7)
18 38 rspec (1.2.9)
19 39 rspec-rails (1.2.9)
20 40 rack (>= 1.0.0)
21 41 rspec (>= 1.2.9)
22   - selenium-client (1.2.18)
  42 + rubyzip (0.9.9)
  43 + selenium-webdriver (2.26.0)
  44 + childprocess (>= 0.2.5)
  45 + libwebsocket (~> 0.1.3)
  46 + multi_json (~> 1.0)
  47 + rubyzip
23 48 system_timer (1.2.4)
24 49 term-ansicolor (1.0.7)
25   - treetop (1.4.10)
26   - polyglot
27   - polyglot (>= 0.3.1)
28   - webrat (0.5.1)
29   - nokogiri (>= 1.2.0)
30   - rack (>= 1.0)
  50 + websocket (1.0.4)
  51 + xpath (0.1.4)
  52 + nokogiri (~> 1.3)
31 53  
32 54 PLATFORMS
33 55 ruby
34 56  
35 57 DEPENDENCIES
36   - Selenium (>= 1.1.14)
37   - cucumber (= 0.4.0)
  58 + capybara (= 1.1.1)
  59 + cucumber (= 1.1.0)
  60 + cucumber-rails (= 0.3.2)
38 61 database_cleaner
39 62 exception_notification (= 1.0.20090728)
  63 + rake (= 0.8.7)
40 64 rspec (= 1.2.9)
41 65 rspec-rails (= 1.2.9)
42   - selenium-client (>= 1.2.17)
43 66 system_timer
44   - webrat (= 0.5.1)
... ...
INSTALL
... ... @@ -33,7 +33,7 @@ You need to install some packages Noosfero depends on. On Debian GNU/Linux or
33 33 Debian-based systems, all of these packages are available through the Debian
34 34 archive. You can install them with the following command:
35 35  
36   - # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby1.8 libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libwill-paginate-ruby iso-codes libfeedparser-ruby openjdk-6-jre libdaemons-ruby thin tango-icon-theme libhpricot-ruby
  36 + # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby1.8 libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libwill-paginate-ruby iso-codes libfeedparser-ruby libdaemons-ruby thin tango-icon-theme libhpricot-ruby
37 37  
38 38 On other systems, they may or may not be available through your regular package
39 39 management system. Below are the links to their homepages.
... ... @@ -43,7 +43,6 @@ management system. Below are the links to their homepages.
43 43 * po4a: http://po4a.alioth.debian.org/
44 44 * Ruby-sqlite3: http://rubyforge.org/projects/sqlite-ruby
45 45 * rcov: http://eigenclass.org/hiki/rcov
46   -* Solr: http://lucene.apache.org/solr
47 46 * RMagick: http://rmagick.rubyforge.org/
48 47 * RedCloth: http://redcloth.org/
49 48 * will_paginate: http://github.com/mislav/will_paginate/wikis
... ... @@ -111,9 +110,6 @@ $ tar -zxvf noosfero-0.39.0.tar.gz
111 110 $ ln -s noosfero-0.39.0 current
112 111 $ cd current
113 112  
114   -Copy config/solr.yml.dist to config/solr.yml. You will
115   -probably not need to customize this configuration, but have a look at it.
116   -
117 113 Create the thin configuration file:
118 114  
119 115 $ thin -C config/thin.yml -e production config
... ... @@ -195,10 +191,6 @@ Compile the translations:
195 191  
196 192 $ RAILS_ENV=production rake noosfero:translations:compile
197 193  
198   -Run Solr:
199   -
200   -$ rake solr:start
201   -
202 194 Now we must create some initial data. To create your default environment
203 195 (the first one), run the command below:
204 196  
... ...
INSTALL.chat
... ... @@ -6,15 +6,13 @@ To configure XMPP/BOSH in Noosfero you need:
6 6 * SystemTimer - http://ph7spot.com/musings/system-timer
7 7 * Pidgin data files - http://www.pidgin.im/
8 8  
9   -If you use Debian Lenny:
  9 +If you use Debian Wheezy:
10 10  
11   -# apt-get install librestclient-ruby (from backports)
12   -# apt-get install pidgin-data
13   -# apt-get install ruby1.8-dev
  11 +# apt-get install librestclient-ruby pidgin-data ruby1.8-dev
14 12 # gem install SystemTimer
15 13  
16   -Take a look at util/chat directory to see samples of config file to configure a
17   -XMPP/BOSH server with ejabberd, postgresql and apache2.
  14 +The samples of config file to configure a XMPP/BOSH server with
  15 +ejabberd, postgresql and apache2 can be found at util/chat directory.
18 16  
19 17 == XMPP/Chat Server Setup
20 18  
... ... @@ -22,8 +20,7 @@ This is a step-by-step guide to get a XMPP service working, in a Debian system.
22 20  
23 21 1. Install the required packages
24 22  
25   -# apt-get -t lenny-backports install ejabberd
26   -# apt-get install odbc-postgresql
  23 +# apt-get install ejabberd odbc-postgresql
27 24  
28 25 2. Ejabberd configuration
29 26  
... ... @@ -108,7 +105,7 @@ Unused modules can be disabled, for example:
108 105 * web_admin
109 106 * mod_pubsub
110 107 * mod_irc
111   - * mod_offine
  108 + * mod_offline
112 109 * mod_admin_extra
113 110 * mod_register
114 111  
... ... @@ -132,7 +129,7 @@ This will create a new schema inside the noosfero database, called &#39;ejabberd&#39;.
132 129  
133 130 Note 'noosfero' user should have permission to create Postgresql schemas. Also,
134 131 there should be at least one domain with 'is_default = true' in 'domains'
135   -table, otherwise people couldn't see your friends online.
  132 +table, otherwise people won't be able to see their friends online.
136 133  
137 134  
138 135 4. ODBC configuration
... ... @@ -168,9 +165,12 @@ Debug = 0
168 165 CommLog = 1
169 166 UsageCount = 3
170 167  
171   - * testing all:
  168 + 4.1 testing all:
172 169  
173   -# isql 'PostgreSQLEjabberdNoosfero' DBUSER
  170 +# isql 'PostgreSQLEjabberdNoosfero'
  171 +
  172 +If the configuration was done right, the message "Connected!"
  173 +will be displayed.
174 174  
175 175  
176 176 5. Enabling kernel polling and SMP in /etc/default/ejabberd
... ...
RELEASING
... ... @@ -19,11 +19,12 @@ To prepare a release of noosfero, you must follow the steps below:
19 19  
20 20 * Finish all requirements and bugs assigned to the to-be-released version
21 21 * Make sure all tests pass
22   -* Change the version in lib/noosfero.rb and debian/changelog to the
23   - to-be-released version (e.g. 0.2.0, 0.3.1)
24 22 * Write release notes at the version's wiki topic
25   -* Generate packages with <tt>rake noosfero:release</tt>. Your tarball and deb
26   - pkg will be under the pkg/ directory. This task will create a git tag too.
  23 +* Generate packages with <tt>rake noosfero:release[(stable|test)]</tt>. This task will:
  24 + * Update the version in lib/noosfero.rb and debian/changelog.
  25 + * Create the tarbal and the deb pkg under pkg/ directory.
  26 + * Create a git tag and push it.
  27 + * Upload the pkg to the configured repository (if configured) on ~/.dput.cf.
27 28 * Test that the tarball and deb package are ok
28 29 * Go to the version's wiki topic and edit it to reflect the new reality
29 30 * Edit the topic WebPreferences and update DEBIAN_REPOSITORY_TOPICS setting
... ...
Rakefile
... ... @@ -7,6 +7,10 @@ require &#39;rake&#39;
7 7 require 'rake/testtask'
8 8 require 'rake/rdoctask'
9 9  
10   -ACTS_AS_SEARCHABLE_ENABLED = false if Rake.application.top_level_tasks.detect{|t| t == 'db:data:minimal'}
11   -
  10 +# rails tasks
12 11 require 'tasks/rails'
  12 +
  13 +# plugins' tasks
  14 +plugins_tasks = Dir.glob("config/plugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake").sort +
  15 + Dir.glob("config/plugins/*/vendor/plugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake").sort
  16 +plugins_tasks.each{ |ext| load ext }
... ...
app/controllers/admin/environment_design_controller.rb
... ... @@ -3,7 +3,8 @@ class EnvironmentDesignController &lt; BoxOrganizerController
3 3 protect 'edit_environment_design', :environment
4 4  
5 5 def available_blocks
6   - @available_blocks ||= [ ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock ]
  6 + @available_blocks ||= [ ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
  7 + @available_blocks += plugins.dispatch(:extra_blocks, :type => Environment)
7 8 end
8 9  
9 10 end
... ...
app/controllers/admin/region_validators_controller.rb
... ... @@ -33,7 +33,7 @@ class RegionValidatorsController &lt; AdminController
33 33 def load_region_and_search
34 34 @region = environment.regions.find(params[:id])
35 35 if params[:search]
36   - @search = @region.search_possible_validators(params[:search])
  36 + @search = find_by_contents(:organizations, Organization, params[:search])[:results].reject {|item| @region.validator_ids.include?(item.id) }
37 37 end
38 38 end
39 39  
... ...
app/controllers/admin/users_controller.rb
  1 +require 'csv'
  2 +
1 3 class UsersController < AdminController
2 4  
3 5 protect 'manage_environment_users', :environment
... ... @@ -15,8 +17,16 @@ class UsersController &lt; AdminController
15 17 :disposition => "attachment; filename=users.xml"
16 18 end
17 19 format.csv do
18   - @users = User.find(:all, :conditions => {:environment_id => environment.id}, :include => [:person])
19   - render :template => "users/index_csv.rhtml", :content_type => 'text/csv', :layout => false
  20 + # using a direct connection with the dbms to optimize
  21 + command = User.send(:sanitize_sql, ["SELECT profiles.name, users.email FROM profiles
  22 + INNER JOIN users ON profiles.user_id=users.id
  23 + WHERE profiles.environment_id = ?", environment.id])
  24 + users = User.connection.execute(command)
  25 + csv_content = "name;email\n"
  26 + users.each { |u|
  27 + CSV.generate_row([u['name'], u['email']], 2, csv_content, fs=';')
  28 + }
  29 + render :text => csv_content, :content_type => 'text/csv', :layout => false
20 30 end
21 31 end
22 32 end
... ...
app/controllers/application_controller.rb
... ... @@ -154,4 +154,18 @@ class ApplicationController &lt; ActionController::Base
154 154 end
155 155 end
156 156  
  157 + def find_by_contents(asset, scope, query, paginate_options={:page => 1}, options={})
  158 + scope = scope.send(options[:filter]) if options[:filter]
  159 +
  160 + @plugins.first(:find_by_contents, asset, scope, query, paginate_options, options) ||
  161 + fallback_find_by_contents(asset, scope, query, paginate_options, options)
  162 + end
  163 +
  164 + private
  165 +
  166 + def fallback_find_by_contents(asset, scope, query, paginate_options, options)
  167 + return {:results => scope.paginate(paginate_options)} if query.blank?
  168 + {:results => scope.like_search(query).paginate(paginate_options)}
  169 + end
  170 +
157 171 end
... ...
app/controllers/box_organizer_controller.rb
... ... @@ -68,8 +68,8 @@ class BoxOrganizerController &lt; ApplicationController
68 68 raise ArgumentError.new("Type %s is not allowed. Go away." % type)
69 69 end
70 70 else
71   - @center_block_types = Box.acceptable_center_blocks & available_blocks
72   - @side_block_types = Box.acceptable_side_blocks & available_blocks
  71 + @center_block_types = (Box.acceptable_center_blocks & available_blocks) + plugins.dispatch(:extra_blocks, :type => boxes_holder.class, :position => 1)
  72 + @side_block_types = (Box.acceptable_side_blocks & available_blocks) + plugins.dispatch(:extra_blocks, :type => boxes_holder.class, :position => [2,3])
73 73 @boxes = boxes_holder.boxes
74 74 render :action => 'add_block', :layout => false
75 75 end
... ...
app/controllers/my_profile/cms_controller.rb
... ... @@ -270,7 +270,7 @@ class CmsController &lt; MyProfileController
270 270  
271 271 def search
272 272 query = params[:q]
273   - results = profile.files.published.find_by_contents(query)[:results]
  273 + results = find_by_contents(:uploaded_files, profile.files.published, query)[:results]
274 274 render :text => article_list_to_json(results), :content_type => 'application/json'
275 275 end
276 276  
... ...
app/controllers/my_profile/profile_design_controller.rb
... ... @@ -7,17 +7,25 @@ class ProfileDesignController &lt; BoxOrganizerController
7 7 def available_blocks
8 8 blocks = [ ArticleBlock, TagsBlock, RecentDocumentsBlock, ProfileInfoBlock, LinkListBlock, MyNetworkBlock, FeedReaderBlock, ProfileImageBlock, LocationBlock, SlideshowBlock, ProfileSearchBlock, HighlightsBlock ]
9 9  
  10 + blocks += plugins.dispatch(:extra_blocks)
  11 +
10 12 # blocks exclusive for organizations
11 13 if profile.has_members?
12 14 blocks << MembersBlock
13 15 end
14 16  
15   - # blocks exclusive to person
  17 + # blocks exclusive to people
16 18 if profile.person?
17 19 blocks << FriendsBlock
18 20 blocks << FavoriteEnterprisesBlock
19 21 blocks << CommunitiesBlock
20 22 blocks << EnterprisesBlock
  23 + blocks += plugins.dispatch(:extra_blocks, :type => Person)
  24 + end
  25 +
  26 + # blocks exclusive to communities
  27 + if profile.community?
  28 + blocks += plugins.dispatch(:extra_blocks, :type => Community)
21 29 end
22 30  
23 31 # blocks exclusive for enterprises
... ... @@ -26,6 +34,7 @@ class ProfileDesignController &lt; BoxOrganizerController
26 34 blocks << HighlightsBlock
27 35 blocks << FeaturedProductsBlock
28 36 blocks << FansBlock
  37 + blocks += plugins.dispatch(:extra_blocks, :type => Enterprise)
29 38 end
30 39  
31 40 # product block exclusive for enterprises in environments that permits it
... ... @@ -33,7 +42,7 @@ class ProfileDesignController &lt; BoxOrganizerController
33 42 blocks << ProductsBlock
34 43 end
35 44  
36   - # block exclusive to profile has blog
  45 + # block exclusive to profiles that have blog
37 46 if profile.has_blog?
38 47 blocks << BlogArchivesBlock
39 48 end
... ...
app/controllers/my_profile/profile_members_controller.rb
... ... @@ -32,7 +32,6 @@ class ProfileMembersController &lt; MyProfileController
32 32  
33 33 def last_admin
34 34 @roles = [Profile::Roles.admin(environment.id)]
35   - @pre_population = [].to_json
36 35 end
37 36  
38 37 def add_role
... ...
app/controllers/public/account_controller.rb
... ... @@ -71,10 +71,6 @@ class AccountController &lt; ApplicationController
71 71 @block_bot = !!session[:may_be_a_bot]
72 72 @invitation_code = params[:invitation_code]
73 73 begin
74   - if params[:user]
75   - params[:user].delete(:password_confirmation_clear)
76   - params[:user].delete(:password_clear)
77   - end
78 74 @user = User.new(params[:user])
79 75 @user.terms_of_use = environment.terms_of_use
80 76 @user.environment = environment
... ...
app/controllers/public/catalog_controller.rb
... ... @@ -7,7 +7,7 @@ class CatalogController &lt; PublicController
7 7 def index
8 8 @category = params[:level] ? ProductCategory.find(params[:level]) : nil
9 9 @products = @profile.products.from_category(@category).paginate(:order => 'available desc, highlighted desc, name asc', :per_page => 9, :page => params[:page])
10   - @categories = ProductCategory.on_level(params[:level])
  10 + @categories = ProductCategory.on_level(params[:level]).order(:name)
11 11 end
12 12  
13 13 protected
... ...
app/controllers/public/profile_search_controller.rb
... ... @@ -11,7 +11,7 @@ class ProfileSearchController &lt; PublicController
11 11 if params[:where] == 'environment'
12 12 redirect_to :controller => 'search', :query => @q
13 13 else
14   - @results = profile.articles.published.find_by_contents(@q, {:per_page => 10, :page => params[:page]})[:results]
  14 + @results = find_by_contents(:articles, profile.articles.published, @q, {:per_page => 10, :page => params[:page]})[:results]
15 15 end
16 16 end
17 17 end
... ...
app/controllers/public/search_controller.rb
... ... @@ -4,10 +4,11 @@ class SearchController &lt; PublicController
4 4 include SearchHelper
5 5 include ActionView::Helpers::NumberHelper
6 6  
7   - before_filter :redirect_asset_param, :except => [:facets_browse, :assets]
  7 + before_filter :redirect_asset_param, :except => :assets
8 8 before_filter :load_category
9 9 before_filter :load_search_assets
10 10 before_filter :load_query
  11 + before_filter :load_filter
11 12  
12 13 # Backwards compatibility with old URLs
13 14 def redirect_asset_param
... ... @@ -17,25 +18,51 @@ class SearchController &lt; PublicController
17 18  
18 19 no_design_blocks
19 20  
20   - def facets_browse
21   - @asset = params[:asset]
22   - @asset_class = asset_class(@asset)
  21 + def index
  22 + @searches = {}
  23 + @order = []
  24 + @names = {}
  25 + @results_only = true
23 26  
24   - @facets_only = true
25   - send(@asset)
  27 + @enabled_searches.select { |key,description| @searching[key] }.each do |key, description|
  28 + load_query
  29 + @asset = key
  30 + send(key)
  31 + @order << key
  32 + @names[key] = getterm(description)
  33 + end
  34 + @asset = nil
26 35  
27   - @facet = @asset_class.map_facets_for(environment).find { |facet| facet[:id] == params[:facet_id] }
28   - raise 'Facet not found' if @facet.nil?
  36 + if @searches.keys.size == 1
  37 + @asset = @searches.keys.first
  38 + render :action => @asset
  39 + end
  40 + end
29 41  
30   - render :layout => false
  42 + # view the summary of one category
  43 + def category_index
  44 + @searches = {}
  45 + @order = []
  46 + @names = {}
  47 + limit = MULTIPLE_SEARCH_LIMIT
  48 + [
  49 + [ :people, _('People'), :recent_people ],
  50 + [ :enterprises, _('Enterprises'), :recent_enterprises ],
  51 + [ :products, _('Products'), :recent_products ],
  52 + [ :events, _('Upcoming events'), :upcoming_events ],
  53 + [ :communities, _('Communities'), :recent_communities ],
  54 + [ :articles, _('Contents'), :recent_articles ]
  55 + ].each do |asset, name, filter|
  56 + @order << asset
  57 + @searches[asset]= {:results => @category.send(filter, limit)}
  58 + raise "No total_entries for: #{asset}" unless @searches[asset][:results].respond_to?(:total_entries)
  59 + @names[asset] = name
  60 + end
31 61 end
32 62  
33 63 def articles
34   - if !@empty_query
35   - full_text_search ['public:true']
36   - else
37   - @results[@asset] = @environment.articles.public.send(@filter).paginate(paginate_options)
38   - end
  64 + @scope = @environment.articles.public
  65 + full_text_search
39 66 end
40 67  
41 68 def contents
... ... @@ -43,49 +70,23 @@ class SearchController &lt; PublicController
43 70 end
44 71  
45 72 def people
46   - if !@empty_query
47   - full_text_search ['public:true']
48   - else
49   - @results[@asset] = visible_profiles(Person).send(@filter).paginate(paginate_options)
50   - end
  73 + @scope = visible_profiles(Person)
  74 + full_text_search
51 75 end
52 76  
53 77 def products
54   - public_filters = ['public:true', 'enabled:true']
55   - if !@empty_query
56   - full_text_search public_filters
57   - else
58   - @one_page = true
59   - @geosearch = logged_in? && current_user.person.lat && current_user.person.lng
60   -
61   - extra_limit = LIST_SEARCH_LIMIT*5
62   - sql_options = {:limit => LIST_SEARCH_LIMIT, :order => 'random()'}
63   - if @geosearch
64   - full_text_search public_filters, :sql_options => sql_options, :extra_limit => extra_limit,
65   - :alternate_query => "{!boost b=recip(geodist(),#{"%e" % (1.to_f/DistBoost)},1,1)}",
66   - :radius => DistFilt, :latitude => current_user.person.lat, :longitude => current_user.person.lng
67   - else
68   - full_text_search public_filters, :sql_options => sql_options, :extra_limit => extra_limit,
69   - :boost_functions => ['recip(ms(NOW/HOUR,updated_at),1.3e-10,1,1)']
70   - end
71   - end
  78 + @scope = @environment.products
  79 + full_text_search
72 80 end
73 81  
74 82 def enterprises
75   - if !@empty_query
76   - full_text_search ['public:true']
77   - else
78   - @filter_title = _('Enterprises from network')
79   - @results[@asset] = visible_profiles(Enterprise, [{:products => :product_category}]).paginate(paginate_options)
80   - end
  83 + @scope = visible_profiles(Enterprise, [{:products => :product_category}])
  84 + full_text_search
81 85 end
82 86  
83 87 def communities
84   - if !@empty_query
85   - full_text_search ['public:true']
86   - else
87   - @results[@asset] = visible_profiles(Community).send(@filter).paginate(paginate_options)
88   - end
  88 + @scope = visible_profiles(Community)
  89 + full_text_search
89 90 end
90 91  
91 92 def events
... ... @@ -93,7 +94,7 @@ class SearchController &lt; PublicController
93 94 month = (params[:month] ? params[:month].to_i : Date.today.month)
94 95 day = (params[:day] ? params[:day].to_i : Date.today.day)
95 96 date = build_date(params[:year], params[:month], params[:day])
96   - date_range = (date - 1.month)..(date + 1.month).at_end_of_month
  97 + date_range = (date - 1.month).at_beginning_of_month..(date + 1.month).at_end_of_month
97 98  
98 99 @selected_day = nil
99 100 @events_of_the_day = []
... ... @@ -104,64 +105,21 @@ class SearchController &lt; PublicController
104 105 environment.events.by_day(@selected_day)
105 106 end
106 107  
107   - if !@empty_query
108   - full_text_search
109   - else
110   - @results[@asset] = date_range ? environment.events.by_range(date_range) : environment.events
111   - end
  108 + @scope = date_range && params[:action] == 'events' ? environment.events.by_range(date_range) : environment.events
  109 + full_text_search
112 110  
113   - events = @results[@asset]
  111 + events = @searches[@asset][:results]
114 112 @calendar = populate_calendar(date, events)
115 113 @previous_calendar = populate_calendar(date - 1.month, events)
116 114 @next_calendar = populate_calendar(date + 1.month, events)
117 115 end
118 116  
119   - def index
120   - @results = {}
121   - @order = []
122   - @names = {}
123   - @results_only = true
124   -
125   - @enabled_searches.select { |key,description| @searching[key] }.each do |key, description|
126   - load_query
127   - @asset = key
128   - send(key)
129   - @order << key
130   - @names[key] = getterm(description)
131   - end
132   - @asset = nil
133   - @facets = {}
134   -
135   - render :action => @results.keys.first if @results.keys.size == 1
136   - end
137   -
138 117 # keep old URLs workings
139 118 def assets
140 119 params[:action] = params[:asset].is_a?(Array) ? :index : params.delete(:asset)
141 120 redirect_to params
142 121 end
143 122  
144   - # view the summary of one category
145   - def category_index
146   - @results = {}
147   - @order = []
148   - @names = {}
149   - limit = MULTIPLE_SEARCH_LIMIT
150   - [
151   - [ :people, _('People'), :recent_people ],
152   - [ :enterprises, _('Enterprises'), :recent_enterprises ],
153   - [ :products, _('Products'), :recent_products ],
154   - [ :events, _('Upcoming events'), :upcoming_events ],
155   - [ :communities, _('Communities'), :recent_communities ],
156   - [ :articles, _('Contents'), :recent_articles ]
157   - ].each do |asset, name, filter|
158   - @order << asset
159   - @results[asset] = @category.send(filter, limit)
160   - raise "No total_entries for: #{asset}" unless @results[asset].respond_to?(:total_entries)
161   - @names[asset] = name
162   - end
163   - end
164   -
165 123 def tags
166 124 @tags_cache_key = "tags_env_#{environment.id.to_s}"
167 125 if is_cache_expired?(@tags_cache_key)
... ... @@ -173,7 +131,7 @@ class SearchController &lt; PublicController
173 131 @tag = params[:tag]
174 132 @tag_cache_key = "tag_#{CGI.escape(@tag.to_s)}_env_#{environment.id.to_s}_page_#{params[:npage]}"
175 133 if is_cache_expired?(@tag_cache_key)
176   - @results[@asset] = environment.articles.find_tagged_with(@tag).paginate(paginate_options)
  134 + @searches[@asset] = {:results => environment.articles.find_tagged_with(@tag).paginate(paginate_options)}
177 135 end
178 136 end
179 137  
... ... @@ -187,11 +145,9 @@ class SearchController &lt; PublicController
187 145 protected
188 146  
189 147 def load_query
190   - @asset = params[:action].to_sym
  148 + @asset = (params[:asset] || params[:action]).to_sym
191 149 @order ||= [@asset]
192   - @results ||= {}
193   - @filter = filter
194   - @filter_title = filter_description(@asset, @filter)
  150 + @searches ||= {}
195 151  
196 152 @query = params[:query] || ''
197 153 @empty_query = @category.nil? && @query.blank?
... ... @@ -211,42 +167,13 @@ class SearchController &lt; PublicController
211 167 end
212 168 end
213 169  
214   - FILTERS = %w(
215   - more_recent
216   - more_active
217   - more_popular
218   - more_comments
219   - )
220   - def filter
221   - if FILTERS.include?(params[:filter])
222   - params[:filter]
223   - else
224   - 'more_recent'
225   - end
226   - end
227   -
228   - def filter_description(asset, filter)
229   - {
230   - 'articles_more_recent' => _('More recent contents from network'),
231   - 'articles_more_popular' => _('More viewed contents from network'),
232   - 'articles_more_comments' => _('Most commented contents from network'),
233   - 'people_more_recent' => _('More recent people from network'),
234   - 'people_more_active' => _('More active people from network'),
235   - 'people_more_popular' => _('More popular people from network'),
236   - 'communities_more_recent' => _('More recent communities from network'),
237   - 'communities_more_active' => _('More active communities from network'),
238   - 'communities_more_popular' => _('More popular communities from network'),
239   - 'products_more_recent' => _('Highlights'),
240   - }[asset.to_s + '_' + filter]
241   - end
242   -
243 170 def load_search_assets
244   - if Searches.keys.include?(params[:action].to_sym) and environment.enabled?("disable_asset_#{params[:action]}")
  171 + if SEARCHES.keys.include?(params[:action].to_sym) && environment.enabled?("disable_asset_#{params[:action]}")
245 172 render_not_found
246 173 return
247 174 end
248 175  
249   - @enabled_searches = Searches.select {|key, name| environment.disabled?("disable_asset_#{params[:action]}") }
  176 + @enabled_searches = SEARCHES.select {|key, name| environment.disabled?("disable_asset_#{key}") }
250 177 @searching = {}
251 178 @titles = {}
252 179 @enabled_searches.each do |key, name|
... ... @@ -256,13 +183,19 @@ class SearchController &lt; PublicController
256 183 @names = @titles if @names.nil?
257 184 end
258 185  
  186 + def load_filter
  187 + @filter = 'more_recent'
  188 + if SEARCHES.keys.include?(@asset.to_sym)
  189 + available_filters = asset_class(@asset)::SEARCH_FILTERS
  190 + @filter = params[:filter] if available_filters.include?(params[:filter])
  191 + end
  192 + end
  193 +
259 194 def limit
260   - if map_search?
  195 + if map_search?(@searches)
261 196 MAP_SEARCH_LIMIT
262 197 elsif !multiple_search?
263   - if [:people, :communities].include? @asset
264   - BLOCKS_SEARCH_LIMIT
265   - elsif @asset == :enterprises and @empty_query
  198 + if [:people, :communities, :enterprises].include? @asset
266 199 BLOCKS_SEARCH_LIMIT
267 200 else
268 201 LIST_SEARCH_LIMIT
... ... @@ -273,41 +206,12 @@ class SearchController &lt; PublicController
273 206 end
274 207  
275 208 def paginate_options(page = params[:page])
276   - page = 1 if multiple_search? or params[:display] == 'map'
  209 + page = 1 if multiple_search?(@searches) || params[:display] == 'map'
277 210 { :per_page => limit, :page => page }
278 211 end
279 212  
280   - def full_text_search(filters = [], options = {})
281   - paginate_options = paginate_options(params[:page])
282   - asset_class = asset_class(@asset)
283   - solr_options = options
284   - pg_options = paginate_options(params[:page])
285   -
286   - if !multiple_search?
287   - if !@results_only and asset_class.respond_to? :facets
288   - solr_options.merge! asset_class.facets_find_options(params[:facet])
289   - solr_options[:all_facets] = true
290   - end
291   - solr_options[:filter_queries] ||= []
292   - solr_options[:filter_queries] += filters
293   - solr_options[:filter_queries] << "environment_id:#{environment.id}"
294   - solr_options[:filter_queries] << asset_class.facet_category_query.call(@category) if @category
295   -
296   - solr_options[:boost_functions] ||= []
297   - params[:order_by] = nil if params[:order_by] == 'none'
298   - if params[:order_by]
299   - order = SortOptions[@asset][params[:order_by].to_sym]
300   - raise "Unknown order by" if order.nil?
301   - order[:solr_opts].each do |opt, value|
302   - solr_options[opt] = value.is_a?(Proc) ? instance_eval(&value) : value
303   - end
304   - end
305   - end
306   -
307   - ret = asset_class.find_by_contents(@query, paginate_options, solr_options)
308   - @results[@asset] = ret[:results]
309   - @facets = ret[:facets]
310   - @all_facets = ret[:all_facets]
  213 + def full_text_search
  214 + @searches[@asset] = find_by_contents(@asset, @scope, @query, paginate_options, {:category => @category, :filter => @filter})
311 215 end
312 216  
313 217 private
... ...
app/helpers/application_helper.rb
... ... @@ -30,6 +30,12 @@ module ApplicationHelper
30 30  
31 31 include AccountHelper
32 32  
  33 + include BlogHelper
  34 +
  35 + include ContentViewerHelper
  36 +
  37 + include LayoutHelper
  38 +
33 39 def locale
34 40 (@page && !@page.language.blank?) ? @page.language : FastGettext.locale
35 41 end
... ... @@ -260,14 +266,17 @@ module ApplicationHelper
260 266 end
261 267  
262 268 def button_bar(options = {}, &block)
263   - concat(content_tag('div', capture(&block) + tag('br', :style => 'clear: left;'), { :class => 'button-bar' }.merge(options)))
  269 + options[:class].nil? ?
  270 + options[:class]='button-bar' :
  271 + options[:class]+=' button-bar'
  272 + concat(content_tag('div', capture(&block) + tag('br', :style => 'clear: left;'), options))
264 273 end
265 274  
266 275 VIEW_EXTENSIONS = %w[.rhtml .html.erb]
267 276  
268   - def partial_for_class_in_view_path(klass, view_path, suffix = nil)
  277 + def partial_for_class_in_view_path(klass, view_path, prefix = nil, suffix = nil)
269 278 return nil if klass.nil?
270   - name = [klass.name.underscore, suffix].compact.map(&:to_s).join('_')
  279 + name = [prefix, klass.name.underscore, suffix].compact.map(&:to_s).join('_')
271 280  
272 281 search_name = String.new(name)
273 282 if search_name.include?("/")
... ... @@ -282,14 +291,14 @@ module ApplicationHelper
282 291 return name if File.exists?(File.join(path))
283 292 end
284 293  
285   - partial_for_class_in_view_path(klass.superclass, view_path, suffix)
  294 + partial_for_class_in_view_path(klass.superclass, view_path, prefix, suffix)
286 295 end
287 296  
288   - def partial_for_class(klass, suffix=nil)
  297 + def partial_for_class(klass, prefix=nil, suffix=nil)
289 298 raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil?
290 299 name = klass.name.underscore
291 300 @controller.view_paths.each do |view_path|
292   - partial = partial_for_class_in_view_path(klass, view_path, suffix)
  301 + partial = partial_for_class_in_view_path(klass, view_path, prefix, suffix)
293 302 return partial if partial
294 303 end
295 304  
... ... @@ -352,10 +361,6 @@ module ApplicationHelper
352 361 end
353 362 end
354 363  
355   - def theme_stylesheet_path
356   - theme_path + '/style.css'
357   - end
358   -
359 364 def current_theme
360 365 @current_theme ||=
361 366 begin
... ... @@ -493,23 +498,24 @@ module ApplicationHelper
493 498  
494 499 def profile_cat_icons( profile )
495 500 if profile.class == Enterprise
496   - icons =
497   - profile.product_categories.map{ |c| c.size > 1 ? c[1] : nil }.
498   - compact.uniq.map{ |c|
499   - cat_name = c.gsub( /[-_\s,.;'"]+/, '_' )
500   - cat_icon = "/images/icons-cat/#{cat_name}.png"
501   - if ! File.exists? RAILS_ROOT.to_s() + '/public/' + cat_icon
502   - cat_icon = '/images/icons-cat/undefined.png'
503   - end
504   - content_tag 'span',
505   - content_tag( 'span', c ),
506   - :title => c,
507   - :class => 'product-cat-icon cat_icon_' + cat_name,
508   - :style => "background-image:url(#{cat_icon})"
509   - }.join "\n"
510   - content_tag 'div',
511   - content_tag( 'span', _('Principal Product Categories'), :class => 'header' ) +"\n"+ icons,
512   - :class => 'product-category-icons'
  501 + icons = profile.product_categories.map{ |c| c.size > 1 ? c[1] : nil }.
  502 + compact.uniq.map do |c|
  503 + cat_name = c.gsub( /[-_\s,.;'"]+/, '_' )
  504 + cat_icon = "/images/icons-cat/#{cat_name}.png"
  505 + if ! File.exists? RAILS_ROOT.to_s() + '/public/' + cat_icon
  506 + cat_icon = '/images/icons-cat/undefined.png'
  507 + end
  508 + content_tag('span',
  509 + content_tag( 'span', c ),
  510 + :title => c,
  511 + :class => 'product-cat-icon cat_icon_' + cat_name,
  512 + :style => "background-image:url(#{cat_icon})"
  513 + )
  514 + end.join("\n").html_safe
  515 + content_tag('div',
  516 + content_tag( 'span', _('Principal Product Categories'), :class => 'header' ) +"\n"+ icons,
  517 + :class => 'product-category-icons'
  518 + )
513 519 else
514 520 ''
515 521 end
... ... @@ -633,10 +639,10 @@ module ApplicationHelper
633 639 # FIXME
634 640 ([toplevel] + toplevel.children_for_menu).each do |cat|
635 641 if cat.top_level?
636   - result << '<div class="categorie_box">'
  642 + result << '<div class="categorie_box">'.html_safe
637 643 result << icon_button( :down, _('open'), '#', :onclick => 'open_close_cat(this); return false' )
638 644 result << content_tag('h5', toplevel.name)
639   - result << '<div style="display:none"><ul class="categories">'
  645 + result << '<div style="display:none"><ul class="categories">'.html_safe
640 646 else
641 647 checkbox_id = "#{object_name}_#{cat.full_name.downcase.gsub(/\s+|\//, '_')}"
642 648 result << content_tag('li', labelled_check_box(
... ... @@ -647,7 +653,7 @@ module ApplicationHelper
647 653 :class => ( object.category_ids.include?(cat.id) ? 'cat_checked' : '' ) ) + "\n"
648 654 end
649 655 end
650   - result << '</ul></div></div>'
  656 + result << '</ul></div></div>'.html_safe
651 657 end
652 658  
653 659 content_tag('div', result)
... ... @@ -787,10 +793,10 @@ module ApplicationHelper
787 793 :class => 'lineitem' + (line_item+=1).to_s() ) +"\n"
788 794 if line_item == line_size
789 795 line_item = 0
790   - html += "<br />\n"
  796 + html += "<br />\n".html_safe
791 797 end
792 798 }
793   - html += "<br />\n" if line_size == 0 || ( values.size % line_size ) > 0
  799 + html += "<br />\n".html_safe if line_size == 0 || ( values.size % line_size ) > 0
794 800 column = object.class.columns_hash[method.to_s]
795 801 text =
796 802 ( column ?
... ... @@ -873,14 +879,6 @@ module ApplicationHelper
873 879 content_tag('div', labelled_check_box(_('Public'), 'profile_data[fields_privacy]['+name+']', 'public', profile.public_fields.include?(name)), :class => 'field-privacy-selector')
874 880 end
875 881  
876   - def template_stylesheet_path
877   - if profile.nil?
878   - "/designs/templates/#{environment.layout_template}/stylesheets/style.css"
879   - else
880   - "/designs/templates/#{profile.layout_template}/stylesheets/style.css"
881   - end
882   - end
883   -
884 882 def login_url
885 883 options = Noosfero.url_options.merge({ :controller => 'account', :action => 'login' })
886 884 url_for(options)
... ... @@ -919,18 +917,6 @@ module ApplicationHelper
919 917 end
920 918 end
921 919  
922   - def icon_theme_stylesheet_path
923   - icon_themes = []
924   - theme_icon_themes = theme_option(:icon_theme) || []
925   - for icon_theme in theme_icon_themes do
926   - theme_path = "/designs/icons/#{icon_theme}/style.css"
927   - if File.exists?(File.join(RAILS_ROOT, 'public', theme_path))
928   - icon_themes << theme_path
929   - end
930   - end
931   - icon_themes
932   - end
933   -
934 920 def page_title
935 921 (@page ? @page.title + ' - ' : '') +
936 922 (profile ? profile.short_name + ' - ' : '') +
... ... @@ -942,42 +928,13 @@ module ApplicationHelper
942 928 (@category ? " - #{@category.full_name}" : '')
943 929 end
944 930  
945   - def noosfero_javascript
946   - render :file => 'layouts/_javascript'
947   - end
948   -
949   - def noosfero_stylesheets
950   - [
951   - 'application',
952   - 'search',
953   - 'thickbox',
954   - 'lightbox',
955   - 'colorpicker',
956   - 'colorbox',
957   - pngfix_stylesheet_path,
958   - ] +
959   - tokeninput_stylesheets
960   - end
961   -
962 931 # DEPRECATED. Do not use this·
963 932 def import_controller_stylesheets(options = {})
964 933 stylesheet_import( "controller_"+ @controller.controller_name(), options )
965 934 end
966 935  
967   - def pngfix_stylesheet_path
968   - 'iepngfix/iepngfix.css'
969   - end
970   -
971   - def tokeninput_stylesheets
972   - ['token-input', 'token-input-facebook', 'token-input-mac', 'token-input-facet']
973   - end
974   -
975   - def noosfero_layout_features
976   - render :file => 'shared/noosfero_layout_features'
977   - end
978   -
979 936 def link_to_email(email)
980   - javascript_tag('var array = ' + email.split('@').to_json + '; document.write("<a href=\'mailto:" + array.join("@") + "\'>" + array.join("@") + "</a>")')
  937 + javascript_tag('var array = ' + email.split('@').to_json + '; document.write("<a href=\'mailto:" + array.join("@") + "\'>" + array.join("@") + "</a>")'.html_safe)
981 938 end
982 939  
983 940 def stylesheet(*args)
... ... @@ -987,13 +944,43 @@ module ApplicationHelper
987 944 def article_to_html(article, options = {})
988 945 options.merge!(:page => params[:npage])
989 946 content = article.to_html(options)
990   - content = content.kind_of?(Proc) ? self.instance_eval(&content) : content
  947 + content = content.kind_of?(Proc) ? self.instance_eval(&content).html_safe : content.html_safe
991 948 @plugins && @plugins.each do |plugin|
992 949 content = plugin.parse_content(content)
993 950 end
994 951 content
995 952 end
996 953  
  954 + # Please, use link_to by default!
  955 + # This method was created to work around to inexplicable
  956 + # chain of problems when display_short_format was called
  957 + # from Article model for an ArticleBlock.
  958 + def reference_to_article(text, article, anchor=nil)
  959 + if article.profile.domains.empty?
  960 + href = "/#{article.url[:profile]}/"
  961 + else
  962 + href = "http://#{article.profile.domains.first.name}/"
  963 + end
  964 + href += article.url[:page].join('/')
  965 + href += '#' + anchor if anchor
  966 + content_tag('a', text, :href => href)
  967 + end
  968 +
  969 + def display_short_format(article, options={})
  970 + options[:comments_link] ||= true
  971 + options[:read_more_link] ||= true
  972 + html = content_tag('div',
  973 + article.lead +
  974 + content_tag('div',
  975 + (options[:comments_link] ? link_to_comments(article) : '') +
  976 + (options[:read_more_link] ? reference_to_article( _('Read more'), article) : ''),
  977 + :class => 'read-more'
  978 + ),
  979 + :class => 'short-post'
  980 + )
  981 + html
  982 + end
  983 +
997 984 def colorpicker_field(object_name, method, options = {})
998 985 text_field(object_name, method, options.merge(:class => 'colorpicker_field'))
999 986 end
... ... @@ -1003,7 +990,7 @@ module ApplicationHelper
1003 990 end
1004 991  
1005 992 def ui_icon(icon_class, extra_class = '')
1006   - "<span class='ui-icon #{icon_class} #{extra_class}' style='float:left; margin-right:7px;'></span>"
  993 + "<span class='ui-icon #{icon_class} #{extra_class}' style='float:left; margin-right:7px;'></span>".html_safe
1007 994 end
1008 995  
1009 996 def ui_button(label, url, html_options = {})
... ... @@ -1018,10 +1005,6 @@ module ApplicationHelper
1018 1005 theme_option(:jquery_theme) || 'smoothness_mod'
1019 1006 end
1020 1007  
1021   - def jquery_ui_theme_stylesheet_path
1022   - 'jquery.ui/' + jquery_theme + '/jquery-ui-1.8.2.custom'
1023   - end
1024   -
1025 1008 def ui_error(message)
1026 1009 content_tag('div', ui_icon('ui-icon-alert') + message, :class => 'alert fg-state-error ui-state-error')
1027 1010 end
... ... @@ -1035,13 +1018,13 @@ module ApplicationHelper
1035 1018 end
1036 1019  
1037 1020 def collapsed_item_icon
1038   - "<span class='ui-icon ui-icon-circlesmall-plus' style='float:left;'></span>"
  1021 + "<span class='ui-icon ui-icon-circlesmall-plus' style='float:left;'></span>".html_safe
1039 1022 end
1040 1023 def expanded_item_icon
1041   - "<span class='ui-icon ui-icon-circlesmall-minus' style='float:left;'></span>"
  1024 + "<span class='ui-icon ui-icon-circlesmall-minus' style='float:left;'></span>".html_safe
1042 1025 end
1043 1026 def leaf_item_icon
1044   - "<span class='ui-icon ui-icon-arrow-1-e' style='float:left;'></span>"
  1027 + "<span class='ui-icon ui-icon-arrow-1-e' style='float:left;'></span>".html_safe
1045 1028 end
1046 1029  
1047 1030 def display_category_menu(block, categories, root = true)
... ... @@ -1300,9 +1283,7 @@ module ApplicationHelper
1300 1283 titles = tabs.inject(''){ |result, tab| result << content_tag(:li, link_to(tab[:title], '#'+tab[:id]), :class => 'tab') }
1301 1284 contents = tabs.inject(''){ |result, tab| result << content_tag(:div, tab[:content], :id => tab[:id]) }
1302 1285  
1303   - content_tag :div, :class => 'ui-tabs' do
1304   - content_tag(:ul, titles) + contents
1305   - end
  1286 + content_tag(:div, content_tag(:ul, titles) + raw(contents), :class => 'ui-tabs')
1306 1287 end
1307 1288  
1308 1289 def jquery_token_input_messages_json(hintText = _('Type in an keyword'), noResultsText = _('No results'), searchingText = _('Searching...'))
... ... @@ -1331,11 +1312,12 @@ module ApplicationHelper
1331 1312 end
1332 1313  
1333 1314 def template_options(klass, field_name)
1334   - return '' if klass.templates.count == 0
1335   - return hidden_field_tag("#{field_name}[template_id]", klass.templates.first.id) if klass.templates.count == 1
  1315 + templates = klass.templates(environment)
  1316 + return '' if templates.count == 0
  1317 + return hidden_field_tag("#{field_name}[template_id]", templates.first.id) if templates.count == 1
1336 1318  
1337 1319 counter = 0
1338   - radios = klass.templates.map do |template|
  1320 + radios = templates.map do |template|
1339 1321 counter += 1
1340 1322 content_tag('li', labelled_radio_button(link_to(template.name, template.url, :target => '_blank'), "#{field_name}[template_id]", template.id, counter==1))
1341 1323 end.join("\n")
... ... @@ -1425,4 +1407,14 @@ module ApplicationHelper
1425 1407 @no_design_blocks = true
1426 1408 end
1427 1409  
  1410 + def default_folder_for_image_upload(profile)
  1411 + default_folder = profile.folders.find_by_type('Gallery')
  1412 + default_folder = profile.folders.find_by_type('Folder') if default_folder.nil?
  1413 + default_folder
  1414 + end
  1415 +
  1416 + def content_id_to_str(content)
  1417 + content.nil? ? '' : content.id.to_s
  1418 + end
  1419 +
1428 1420 end
... ...
app/helpers/block_helper.rb
... ... @@ -3,7 +3,24 @@ module BlockHelper
3 3 def block_title(title)
4 4 tag_class = 'block-title'
5 5 tag_class += ' empty' if title.empty?
6   - content_tag 'h3', content_tag('span', title), :class => tag_class
  6 + content_tag 'h3', content_tag('span', h(title)), :class => tag_class
  7 + end
  8 +
  9 + def highlights_block_config_image_fields(block, image={})
  10 + "
  11 + <tr class=\"image-data-line\">
  12 + <td>
  13 + #{select_tag 'block[images][][image_id]', content_tag(:option) + option_groups_from_collection_for_select(block.folder_choices, :images, :name, :id, :name, image[:image_id].to_i).html_safe}
  14 + </td>
  15 + <td>#{text_field_tag 'block[images][][address]', image[:address], :class => 'highlight-address', :size => 20}</td>
  16 + <td>#{text_field_tag 'block[images][][position]', image[:position], :class => 'highlight-position', :size => 1}</td>
  17 + </tr><tr class=\"image-title\">
  18 + <td colspan=\"3\"><label>#{
  19 + content_tag('span', _('Title')) +
  20 + text_field_tag('block[images][][title]', image[:title], :class => 'highlight-title', :size => 45)
  21 + }</label></td>
  22 + </tr>
  23 + "
7 24 end
8 25  
9 26 end
... ...
app/helpers/blog_helper.rb
... ... @@ -18,8 +18,9 @@ module BlogHelper
18 18 pagination = will_paginate(articles, {
19 19 :param_name => 'npage',
20 20 :previous_label => _('&laquo; Newer posts'),
21   - :next_label => _('Older posts &raquo;')
22   - })
  21 + :next_label => _('Older posts &raquo;'),
  22 + :params => {:action=>"view_page", :page=>articles.first.parent.path.split('/'), :controller=>"content_viewer"}
  23 + }) if articles.present?
23 24 content = []
24 25 artic_len = articles.length
25 26 articles.each_with_index{ |art,i|
... ... @@ -31,7 +32,7 @@ module BlogHelper
31 32 css_add << position + '-inner'
32 33 content << content_tag('div',
33 34 content_tag('div',
34   - display_post(art, format) + '<br style="clear:both"/>',
  35 + display_post(art, format).html_safe + '<br style="clear:both"/>'.html_safe,
35 36 :class => 'blog-post ' + css_add.join(' '),
36 37 :id => "post-#{art.id}"), :class => position
37 38 )
... ... @@ -46,18 +47,6 @@ module BlogHelper
46 47 article_title(article, :no_comments => no_comments) + html
47 48 end
48 49  
49   - def display_short_format(article)
50   - html = content_tag('div',
51   - article.lead +
52   - content_tag('div',
53   - link_to_comments(article) +
54   - link_to( _('Read more'), article.url),
55   - :class => 'read-more'),
56   - :class => 'short-post'
57   - )
58   - html
59   - end
60   -
61 50 def display_full_format(article)
62 51 html = article_to_html(article)
63 52 html = content_tag('p', html) if ! html.include?('</p>')
... ...
app/helpers/catalog_helper.rb
... ... @@ -21,7 +21,7 @@ module CatalogHelper
21 21  
22 22 def category_sub_links(category)
23 23 sub_categories = []
24   - category.children.each do |sub_category|
  24 + category.children.order(:name).each do |sub_category|
25 25 sub_categories << category_link(sub_category, true)
26 26 end
27 27 content_tag('ul', sub_categories) if sub_categories.size > 1
... ...
app/helpers/content_viewer_helper.rb
... ... @@ -39,7 +39,7 @@ module ContentViewerHelper
39 39  
40 40 def link_to_comments(article, args = {})
41 41 return '' unless article.accept_comments?
42   - link_to(number_of_comments(article), article.url.merge(:anchor => 'comments_list') )
  42 + reference_to_article number_of_comments(article), article, 'comments_list'
43 43 end
44 44  
45 45 def article_translations(article)
... ... @@ -48,7 +48,7 @@ module ContentViewerHelper
48 48 { article.environment.locales[translation.language] => { :href => url_for(translation.url) } }
49 49 end
50 50 content_tag(:div, link_to(_('Translations'), '#',
51   - :onclick => "toggleSubmenu(this, '#{_('Translations')}', #{links.to_json}); return false",
  51 + :onmouseover => "toggleSubmenu(this, '#{_('Translations')}', #{links.to_json}); return false",
52 52 :class => 'article-translations-menu simplemenu-trigger up'),
53 53 :class => 'article-translations')
54 54 end
... ...
app/helpers/dates_helper.rb
... ... @@ -23,11 +23,13 @@ module DatesHelper
23 23 end
24 24  
25 25 # formats a date for displaying.
26   - def show_date(date, use_numbers = false)
  26 + def show_date(date, use_numbers = false, year=true)
27 27 if date && use_numbers
28   - _('%{month}/%{day}/%{year}') % { :day => date.day, :month => date.month, :year => date.year }
  28 + date_format = year ? _('%{month}/%{day}/%{year}') : _('%{month}/%{day}')
  29 + date_format % { :day => date.day, :month => date.month, :year => date.year }
29 30 elsif date
30   - _('%{month} %{day}, %{year}') % { :day => date.day, :month => month_name(date.month), :year => date.year }
  31 + date_format = year ? _('%{month_name} %{day}, %{year}') : _('%{month_name} %{day}')
  32 + date_format % { :day => date.day, :month_name => month_name(date.month), :year => date.year }
31 33 else
32 34 ''
33 35 end
... ... @@ -46,7 +48,27 @@ module DatesHelper
46 48 if (date1 == date2) || (date2.nil?)
47 49 show_date(date1, use_numbers)
48 50 else
49   - _('from %{date1} to %{date2}') % {:date1 => show_date(date1, use_numbers), :date2 => show_date(date2, use_numbers)}
  51 + if date1.year == date2.year
  52 + if date1.month == date2.month
  53 + _('from %{month} %{day1} to %{day2}, %{year}') % {
  54 + :day1 => date1.day,
  55 + :day2 => date2.day,
  56 + :month => use_numbers ? date1.month : month_name(date1.month),
  57 + :year => date1.year
  58 + }
  59 + else
  60 + _('from %{date1} to %{date2}, %{year}') % {
  61 + :date1 => show_date(date1, use_numbers, false),
  62 + :date2 => show_date(date2, use_numbers, false),
  63 + :year => date1.year
  64 + }
  65 + end
  66 + else
  67 + _('from %{date1} to %{date2}') % {
  68 + :date1 => show_date(date1, use_numbers),
  69 + :date2 => show_date(date2, use_numbers)
  70 + }
  71 + end
50 72 end
51 73 end
52 74  
... ...
app/helpers/forms_helper.rb
... ... @@ -142,38 +142,6 @@ module FormsHelper
142 142 content_tag('table',rows.join("\n"))
143 143 end
144 144  
145   - def select_folder(label_text, field_id, collection, default_value=nil, html_options = {}, js_options = {})
146   - root = profile ? profile.identifier : _("root")
147   - labelled_form_field(
148   - label_text,
149   - select_tag(
150   - field_id,
151   - options_for_select(
152   - [[root, '']] +
153   - collection.collect {|f| [ root + '/' + f.full_name, f.id ] },
154   - default_value
155   - ),
156   - html_options.merge(js_options)
157   - )
158   - )
159   - end
160   -
161   - def select_profile_folder(label_text, field_id, profile, default_value='', html_options = {}, js_options = {})
162   - result = labelled_form_field(
163   - label_text,
164   - select_tag(
165   - field_id,
166   - options_for_select(
167   - [[profile.identifier, '']] +
168   - profile.folders.collect {|f| [ profile.identifier + '/' + f.full_name, f.id ] },
169   - default_value
170   - ),
171   - html_options.merge(js_options)
172   - )
173   - )
174   - return result
175   - end
176   -
177 145 def date_field(name, value, format = '%Y-%m-%d', datepicker_options = {}, html_options = {})
178 146 datepicker_options[:disabled] ||= false
179 147 datepicker_options[:alt_field] ||= ''
... ... @@ -276,7 +244,7 @@ module FormsHelper
276 244 yearSuffix: #{datepicker_options[:year_suffix].to_json}
277 245 })
278 246 </script>
279   - "
  247 + ".html_safe
280 248 result
281 249 end
282 250  
... ... @@ -295,23 +263,28 @@ module FormsHelper
295 263 field_id,
296 264 options_for_select(
297 265 [[root, '']] +
298   - collection.collect {|f| [ root + '/' + f.full_name, f.id ] },
299   - default_value
  266 + collection.collect {|f| [ root + '/' + f.full_name, f.id.to_s ] },
  267 + default_value.to_s
300 268 ),
301 269 html_options.merge(js_options)
302 270 )
303 271 )
304 272 end
305 273  
306   - def select_profile_folder(label_text, field_id, profile, default_value='', html_options = {}, js_options = {})
  274 + def select_profile_folder(label_text, field_id, profile, default_value='', html_options = {}, js_options = {}, find_options = {})
  275 + if find_options.empty?
  276 + folders = profile.folders
  277 + else
  278 + folders = profile.folders.where(find_options)
  279 + end
307 280 result = labelled_form_field(
308 281 label_text,
309 282 select_tag(
310 283 field_id,
311 284 options_for_select(
312 285 [[profile.identifier, '']] +
313   - profile.folders.collect {|f| [ profile.identifier + '/' + f.full_name, f.id ] },
314   - default_value
  286 + folders.collect {|f| [ profile.identifier + '/' + f.full_name, f.id.to_s ] },
  287 + default_value.to_s
315 288 ),
316 289 html_options.merge(js_options)
317 290 )
... ...
app/helpers/layout_helper.rb 0 → 100644
... ... @@ -0,0 +1,94 @@
  1 +module LayoutHelper
  2 +
  3 + def body_classes
  4 + # Identify the current controller and action for the CSS:
  5 + " controller-#{@controller.controller_name}" +
  6 + " action-#{@controller.controller_name}-#{@controller.action_name}" +
  7 + " template-#{profile.nil? ? "default" : profile.layout_template}" +
  8 + (!profile.nil? && profile.is_on_homepage?(request.path,@page) ? " profile-homepage" : "")
  9 + end
  10 +
  11 + def noosfero_javascript
  12 + plugins_javascripts = @plugins.map { |plugin| plugin.js_files.map { |js| plugin.class.public_path(js) } }.flatten
  13 +
  14 + output = ''
  15 + output += render :file => 'layouts/_javascript'
  16 + output += javascript_tag 'render_all_jquery_ui_widgets()'
  17 + unless plugins_javascripts.empty?
  18 + output += javascript_include_tag plugins_javascripts, :cache => "cache/plugins-#{Digest::MD5.hexdigest plugins_javascripts.to_s}"
  19 + end
  20 + output
  21 + end
  22 +
  23 + def noosfero_stylesheets
  24 + standard_stylesheets = [
  25 + 'application',
  26 + 'search',
  27 + 'thickbox',
  28 + 'lightbox',
  29 + 'colorpicker',
  30 + 'colorbox',
  31 + pngfix_stylesheet_path,
  32 + ] + tokeninput_stylesheets
  33 + plugins_stylesheets = @plugins.select(&:stylesheet?).map { |plugin| plugin.class.public_path('style.css') }
  34 +
  35 + output = ''
  36 + output += stylesheet_link_tag standard_stylesheets, :cache => 'cache'
  37 + output += stylesheet_link_tag template_stylesheet_path
  38 + output += stylesheet_link_tag icon_theme_stylesheet_path
  39 + output += stylesheet_link_tag jquery_ui_theme_stylesheet_path
  40 + unless plugins_stylesheets.empty?
  41 + output += stylesheet_link_tag plugins_stylesheets, :cache => "cache/plugins-#{Digest::MD5.hexdigest plugins_stylesheets.to_s}"
  42 + end
  43 + output += stylesheet_link_tag theme_stylesheet_path
  44 + output
  45 + end
  46 +
  47 + def pngfix_stylesheet_path
  48 + 'iepngfix/iepngfix.css'
  49 + end
  50 +
  51 + def tokeninput_stylesheets
  52 + ['token-input', 'token-input-facebook', 'token-input-mac', 'token-input-facet']
  53 + end
  54 +
  55 + def noosfero_layout_features
  56 + render :file => 'shared/noosfero_layout_features'
  57 + end
  58 +
  59 + def template_stylesheet_path
  60 + if profile.nil?
  61 + "/designs/templates/#{environment.layout_template}/stylesheets/style.css"
  62 + else
  63 + "/designs/templates/#{profile.layout_template}/stylesheets/style.css"
  64 + end
  65 + end
  66 +
  67 + def icon_theme_stylesheet_path
  68 + icon_themes = []
  69 + theme_icon_themes = theme_option(:icon_theme) || []
  70 + for icon_theme in theme_icon_themes do
  71 + theme_path = "/designs/icons/#{icon_theme}/style.css"
  72 + if File.exists?(File.join(RAILS_ROOT, 'public', theme_path))
  73 + icon_themes << theme_path
  74 + end
  75 + end
  76 + icon_themes
  77 + end
  78 +
  79 + def jquery_ui_theme_stylesheet_path
  80 + 'jquery.ui/' + jquery_theme + '/jquery-ui-1.8.2.custom'
  81 + end
  82 +
  83 + def theme_stylesheet_path
  84 + theme_path + '/style.css'
  85 + end
  86 +
  87 + def addthis_javascript
  88 + if NOOSFERO_CONF['addthis_enabled']
  89 + '<script src="http://s7.addthis.com/js/152/addthis_widget.js"></script>'
  90 + end
  91 + end
  92 +
  93 +end
  94 +
... ...
app/helpers/profile_editor_helper.rb
... ... @@ -136,7 +136,7 @@ module ProfileEditorHelper
136 136 concat(
137 137 content_tag(
138 138 'div',
139   - capture(&block) + '<br style="clear:left;"/>&nbsp;',
  139 + capture(&block) + content_tag('br', '', :style => 'clear: left'),
140 140 :class => 'control-panel')
141 141 )
142 142 end
... ...
app/helpers/search_helper.rb
... ... @@ -2,12 +2,10 @@ module SearchHelper
2 2  
3 3 MAP_SEARCH_LIMIT = 2000
4 4 LIST_SEARCH_LIMIT = 20
5   - BLOCKS_SEARCH_LIMIT = 18
  5 + BLOCKS_SEARCH_LIMIT = 24
6 6 MULTIPLE_SEARCH_LIMIT = 8
7   - DistFilt = 200
8   - DistBoost = 50
9 7  
10   - Searches = ActiveSupport::OrderedHash[
  8 + SEARCHES = ActiveSupport::OrderedHash[
11 9 :articles, _('Contents'),
12 10 :enterprises, _('Enterprises'),
13 11 :people, _('People'),
... ... @@ -16,46 +14,31 @@ module SearchHelper
16 14 :events, _('Events'),
17 15 ]
18 16  
19   - SortOptions = {
20   - :products => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')},
21   - :more_recent, {:label => _('More recent'), :solr_opts => {:sort => 'updated_at desc, score desc'}},
22   - :name, {:label => _('Name'), :solr_opts => {:sort => 'name_sortable asc'}},
23   - :closest, {:label => _('Closest to me'), :if => proc{ logged_in? && (profile=current_user.person).lat && profile.lng },
24   - :solr_opts => {:sort => "geodist() asc",
25   - :latitude => proc{ current_user.person.lat }, :longitude => proc{ current_user.person.lng }}},
26   - ],
27   - :events => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')},
28   - :name, {:label => _('Name'), :solr_opts => {:sort => 'name_sortable asc'}},
29   - ],
30   - :articles => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')},
31   - :name, {:label => _('Name'), :solr_opts => {:sort => 'name_sortable asc'}},
32   - :more_recent, {:label => _('More recent'), :solr_opts => {:sort => 'updated_at desc, score desc'}},
33   - ],
34   - :enterprises => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')},
35   - :name, {:label => _('Name'), :solr_opts => {:sort => 'name_sortable asc'}},
36   - ],
37   - :people => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')},
38   - :name, {:label => _('Name'), :solr_opts => {:sort => 'name_sortable asc'}},
39   - ],
40   - :communities => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')},
41   - :name, {:label => _('Name'), :solr_opts => {:sort => 'name_sortable asc'}},
42   - ],
  17 + FILTER_TRANSLATION = {
  18 + 'more_popular' => _('More popular'),
  19 + 'more_active' => _('More active'),
  20 + 'more_recent' => _('More recent'),
  21 + 'more_comments' => _('More comments')
43 22 }
44 23  
45 24 # FIXME remove it after search_controler refactored
46 25 include EventsHelper
47 26  
48   - def multiple_search?
49   - ['index', 'category_index'].include?(params[:action]) or @results.size > 1
  27 + def multiple_search?(searches=nil)
  28 + ['index', 'category_index'].include?(params[:action]) || (searches && searches.size > 1)
50 29 end
51 30  
52   - def map_search?
53   - !@empty_query and !multiple_search? and params[:display] == 'map'
  31 + def map_search?(searches=nil)
  32 + !multiple_search?(searches) && params[:display] == 'map'
  33 + end
  34 +
  35 + def asset_class(asset)
  36 + asset.to_s.singularize.camelize.constantize
54 37 end
55 38  
56 39 def search_page_title(title, category = nil)
57 40 title = "<h1>" + title
58   - title += '<small>' + category.name + '</small>' if category
  41 + title += ' - <small>' + category.name + '</small>' if category
59 42 title + "</h1>"
60 43 end
61 44  
... ... @@ -66,8 +49,12 @@ module SearchHelper
66 49 :align => 'center', :class => 'search-category-context') if category
67 50 end
68 51  
69   - def display_results(map_capable = false)
70   - if map_capable and map_search?
  52 + def display?(asset, mode)
  53 + defined?(asset_class(asset)::SEARCH_DISPLAYS) && asset_class(asset)::SEARCH_DISPLAYS.include?(mode.to_s)
  54 + end
  55 +
  56 + def display_results(searches=nil, asset=nil)
  57 + if display?(asset, :map) && map_search?(searches)
71 58 partial = 'google_maps'
72 59 klass = 'map'
73 60 else
... ... @@ -78,10 +65,13 @@ module SearchHelper
78 65 content_tag('div', render(:partial => partial), :class => "map-or-list-search-results #{klass}")
79 66 end
80 67  
81   - def display_map_list_button
82   - button(:search, params[:display] == 'map' ? _('Display in list') : _('Display in map'),
83   - params.merge(:display => (params[:display] == 'map' ? 'list' : 'map')),
84   - :class => "map-toggle-button" )
  68 + def display_filter(asset, display)
  69 + asset = :articles if asset == :tag
  70 + if display?(asset, display)
  71 + display
  72 + else
  73 + asset_class(asset).default_search_display
  74 + end
85 75 end
86 76  
87 77 def city_with_state(city)
... ... @@ -97,120 +87,50 @@ module SearchHelper
97 87 end
98 88 end
99 89  
100   - def facets_menu(asset, _facets)
101   - @asset_class = asset_class(asset)
102   - @facets = _facets
103   - render(:partial => 'facets_menu')
104   - end
105   -
106   - def facets_unselect_menu(asset)
107   - @asset_class = asset_class(asset)
108   - render(:partial => 'facets_unselect_menu')
109   - end
110   -
111   - def facet_javascript(input_id, facet, array)
112   - array = [] if array.nil?
113   - hintText = _('Type in an option')
114   - text_field_tag('facet['+input_id+']', '', :id => input_id) +
115   - javascript_tag("jQuery.TokenList(jQuery('##{input_id}'), #{array.to_json},
116   - {searchDelay: 0, permanentDropdown: true, theme: 'facet', dontAdd: true, preventDuplicates: true,
117   - #{jquery_token_input_messages_json(hintText)}});")
118   - end
119   -
120   - def facet_link_html(facet, params, value, label, count)
121   - params = params ? params.dup : {}
122   - has_extra = label.kind_of?(Array)
123   - link_label = has_extra ? label[0] : label
124   - id = facet[:solr_field].to_s
125   - params[:facet] ||= {}
126   - params[:facet][id] ||= {}
127   - params[:page] = {} if params[:page]
128   -
129   - selected = facet[:label_id].nil? ? params[:facet][id] == value : params[:facet][id][facet[:label_id]].to_a.include?(value)
130   -
131   - if count > 0
132   - url = params.merge(:facet => params[:facet].merge(
133   - id => facet[:label_id].nil? ? value : params[:facet][id].merge( facet[:label_id] => params[:facet][id][facet[:label_id]].to_a | [value] )
134   - ))
135   - else
136   - # preserve others filters and change this filter
137   - url = params.merge(:facet => params[:facet].merge(
138   - id => facet[:label_id].nil? ? value : { facet[:label_id] => value }
139   - ))
  90 + def display_selector(asset, display, float = 'right')
  91 + display = nil if display.blank?
  92 + display ||= asset_class(asset).default_search_display
  93 + if [display?(asset, :map), display?(asset, :compact), display?(asset, :full)].select {|option| option}.count > 1
  94 + compact_link = display?(asset, :compact) ? (display == 'compact' ? _('Compact') : link_to(_('Compact'), params.merge(:display => 'compact'))) : nil
  95 + map_link = display?(asset, :map) ? (display == 'map' ? _('Map') : link_to(_('Map'), params.merge(:display => 'map'))) : nil
  96 + full_link = display?(asset, :full) ? (display == 'full' ? _('Full') : link_to(_('Full'), params.merge(:display => 'full'))) : nil
  97 + content_tag('div',
  98 + content_tag('strong', _('Display')) + ': ' + [compact_link, map_link, full_link].compact.join(' | ').html_safe,
  99 + :class => 'search-customize-options'
  100 + )
140 101 end
141   -
142   - content_tag 'div', link_to(link_label, url, :class => 'facet-result-link-label') +
143   - content_tag('span', (has_extra ? label[1] : ''), :class => 'facet-result-extra-label') +
144   - (count > 0 ? content_tag('span', " (#{count})", :class => 'facet-result-count') : ''),
145   - :class => 'facet-menu-item' + (selected ? ' facet-result-link-selected' : '')
146 102 end
147 103  
148   - def facet_selecteds_html_for(environment, klass, params)
149   - def name_with_extra(klass, facet, value)
150   - name = klass.facet_result_name(facet, value)
151   - name = name[0] + name[1] if name.kind_of?(Array)
152   - name
153   - end
154   -
155   - ret = []
156   - params = params.dup
157   - params[:facet].each do |id, value|
158   - facet = klass.facet_by_id(id.to_sym)
159   - next unless facet
160   - if value.kind_of?(Hash)
161   - label_hash = facet[:label].call(environment)
162   - value.each do |label_id, value|
163   - facet[:label_id] = label_id
164   - facet[:label] = label_hash[label_id]
165   - value.to_a.each do |value|
166   - ret << [facet[:label], name_with_extra(klass, facet, value),
167   - params.merge(:facet => params[:facet].merge(id => params[:facet][id].merge(label_id => params[:facet][id][label_id].to_a.reject{ |v| v == value })))]
168   - end
169   - end
170   - else
171   - ret << [klass.facet_label(facet), name_with_extra(klass, facet, value),
172   - params.merge(:facet => params[:facet].reject{ |k,v| k == id })]
173   - end
  104 + def filter_selector(asset, filter, float = 'right')
  105 + klass = asset_class(asset)
  106 + if klass::SEARCH_FILTERS.count > 1
  107 + options = options_for_select(klass::SEARCH_FILTERS.map {|f| [FILTER_TRANSLATION[f], f]}, filter)
  108 + url_params = url_for(params.merge(:filter => 'FILTER'))
  109 + onchange = "document.location.href = '#{url_params}'.replace('FILTER', this.value)"
  110 + select_field = select_tag(:filter, options, :onchange => onchange)
  111 + content_tag('div',
  112 + content_tag('strong', _('Filter')) + ': ' + select_field,
  113 + :class => "search-customize-options"
  114 + )
174 115 end
175   -
176   - ret.map do |label, name, url|
177   - content_tag('div', content_tag('span', label, :class => 'facet-selected-label') +
178   - content_tag('span', name, :class => 'facet-selected-name') +
179   - link_to('', url, :class => 'facet-selected-remove', :title => 'remove facet'), :class => 'facet-selected')
180   - end.join
181   - end
182   -
183   - def order_by(asset)
184   - options = SortOptions[asset].map do |name, options|
185   - next if options[:if] and ! instance_eval(&options[:if])
186   - [_(options[:label]), name.to_s]
187   - end.compact
188   -
189   - content_tag('div', _('Sort results by ') +
190   - select_tag(asset.to_s + '[order]', options_for_select(options, params[:order_by] || 'none'),
191   - {:onchange => "window.location = jQuery.param.querystring(window.location.href, { 'order_by' : this.options[this.selectedIndex].value})"}),
192   - :class => "search-ordering")
193   - end
194   -
195   - def label_total_found(asset, total_found)
196   - labels = {
197   - :products => _("%s products offers found"),
198   - :articles => _("%s articles found"),
199   - :events => _("%s events found"),
200   - :people => _("%s people found"),
201   - :enterprises => _("%s enterprises found"),
202   - :communities => _("%s communities found"),
203   - }
204   - content_tag('span', labels[asset] % total_found,
205   - :class => "total-pages-found") if labels[asset]
206   - end
207   -
208   - def asset_class(asset)
209   - asset.to_s.singularize.camelize.constantize
210 116 end
211 117  
212   - def asset_table(asset)
213   - asset_class(asset).table_name
  118 + def filter_title(asset, filter)
  119 + {
  120 + 'articles_more_recent' => _('More recent contents from network'),
  121 + 'articles_more_popular' => _('More viewed contents from network'),
  122 + 'articles_more_comments' => _('Most commented contents from network'),
  123 + 'people_more_recent' => _('More recent people from network'),
  124 + 'people_more_active' => _('More active people from network'),
  125 + 'people_more_popular' => _('More popular people from network'),
  126 + 'communities_more_recent' => _('More recent communities from network'),
  127 + 'communities_more_active' => _('More active communities from network'),
  128 + 'communities_more_popular' => _('More popular communities from network'),
  129 + 'enterprises_more_recent' => _('More recent enterprises from network'),
  130 + 'enterprises_more_active' => _('More active enterprises from network'),
  131 + 'enterprises_more_popular' => _('More popular enterprises from network'),
  132 + 'products_more_recent' => _('Highlights'),
  133 + }[asset.to_s + '_' + filter].to_s
214 134 end
215 135  
216 136 end
... ...
app/helpers/tags_helper.rb
... ... @@ -29,10 +29,8 @@ module TagsHelper
29 29 # (pt_BR only).
30 30 def tag_cloud(tags, tagname_option, url, options = {})
31 31  
32   - return content_tag('em', _('No tags yet.')) +
33   - ' <a href="' + _('http://en.wikipedia.org/wiki/Tag_%28metadata%29') +
34   - '" target="wptags"><span>(' +
35   - _('What are tags?') + ')</span></a>' if tags.empty?
  32 + return content_tag('em', _('No tags yet.') + ' ') +
  33 + link_to(content_tag(:span, _('What are tags?')),_('http://en.wikipedia.org/wiki/Tag_%28metadata%29')) if tags.empty?
36 34  
37 35 max_size = options[:max_size] || Cloud::MAX_SIZE
38 36 min_size = options[:min_size] || Cloud::MIN_SIZE
... ... @@ -68,7 +66,7 @@ module TagsHelper
68 66 :title => n_( 'one item', '%d items', count ) % count
69 67 end
70 68  
71   - end.join("\n")
  69 + end.join("\n").html_safe
72 70 end
73 71  
74 72 end
... ...
app/models/approve_comment.rb
... ... @@ -43,7 +43,7 @@ class ApproveComment &lt; Task
43 43  
44 44 def information
45 45 if article
46   - {:message => _('%{requestor} commented on the the article: %{linked_subject}.') % {:requestor => requestor_name} }
  46 + {:message => _('%{requestor} commented on the the article: %{linked_subject}.') % {:requestor => requestor_name, :linked_subject => linked_subject} }
47 47 else
48 48 {:message => _("The article was removed.")}
49 49 end
... ...
app/models/article.rb
... ... @@ -2,7 +2,28 @@ require &#39;hpricot&#39;
2 2  
3 3 class Article < ActiveRecord::Base
4 4  
5   -include ActionController::UrlWriter
  5 + SEARCHABLE_FIELDS = {
  6 + :name => 10,
  7 + :abstract => 3,
  8 + :body => 2,
  9 + :slug => 1,
  10 + :filename => 1,
  11 + }
  12 +
  13 + SEARCH_FILTERS = %w[
  14 + more_recent
  15 + more_popular
  16 + more_comments
  17 + ]
  18 +
  19 + SEARCH_DISPLAYS = %w[full]
  20 +
  21 + def self.default_search_display
  22 + 'full'
  23 + end
  24 +
  25 + #FIXME This is necessary because html is being generated on the model...
  26 + include ActionView::Helpers::TagHelper
6 27  
7 28 # use for internationalizable human type names in search facets
8 29 # reimplement on subclasses
... ... @@ -147,7 +168,6 @@ include ActionController::UrlWriter
147 168 else
148 169 ArticleCategorization.add_category_to_article(c, self)
149 170 self.categories(reload)
150   - self.solr_save
151 171 end
152 172 end
153 173  
... ... @@ -165,7 +185,6 @@ include ActionController::UrlWriter
165 185 ArticleCategorization.add_category_to_article(item, self)
166 186 end
167 187 self.categories(true)
168   - self.solr_save
169 188 pending_categorizations.clear
170 189 end
171 190  
... ... @@ -201,20 +220,12 @@ include ActionController::UrlWriter
201 220 named_scope :public,
202 221 :conditions => [ "advertise = ? AND published = ? AND profiles.visible = ? AND profiles.public_profile = ?", true, true, true, true ]
203 222  
204   - named_scope :more_recent,
205   - :conditions => [ "advertise = ? AND published = ? AND profiles.visible = ? AND profiles.public_profile = ? AND
206   - ((articles.type != ?) OR articles.type is NULL)",
207   - true, true, true, true, 'RssFeed'
208   - ],
209   - :order => 'articles.published_at desc, articles.id desc'
210   -
211 223 # retrives the most commented articles, sorted by the comment count (largest
212 224 # first)
213 225 def self.most_commented(limit)
214 226 paginate(:order => 'comments_count DESC', :page => 1, :per_page => limit)
215 227 end
216 228  
217   - named_scope :more_popular, :order => 'hits DESC'
218 229 named_scope :relevant_as_recent, :conditions => ["(articles.type != 'UploadedFile' and articles.type != 'RssFeed' and articles.type != 'Blog') OR articles.type is NULL"]
219 230  
220 231 def self.recent(limit = nil, extra_conditions = {}, pagination = true)
... ... @@ -239,8 +250,13 @@ include ActionController::UrlWriter
239 250 # The implementation in this class just provides the +body+ attribute as the
240 251 # HTML. Other article types can override this method to provide customized
241 252 # views of themselves.
  253 + # (To override short format representation, override the lead method)
242 254 def to_html(options = {})
243   - body || ''
  255 + if options[:format] == 'short'
  256 + display_short_format(self)
  257 + else
  258 + body || ''
  259 + end
244 260 end
245 261  
246 262 include ApplicationHelper
... ... @@ -429,8 +445,8 @@ include ActionController::UrlWriter
429 445 named_scope :images, :conditions => { :is_image => true }
430 446 named_scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ]
431 447  
  448 + named_scope :more_popular, :order => 'hits DESC'
432 449 named_scope :more_comments, :order => "comments_count DESC"
433   - named_scope :more_views, :order => "hits DESC"
434 450 named_scope :more_recent, :order => "created_at DESC"
435 451  
436 452 def self.display_filter(user, profile)
... ... @@ -596,7 +612,7 @@ include ActionController::UrlWriter
596 612 end
597 613  
598 614 def lead
599   - abstract.blank? ? first_paragraph : abstract
  615 + abstract.blank? ? first_paragraph.html_safe : abstract.html_safe
600 616 end
601 617  
602 618 def short_lead
... ... @@ -627,7 +643,7 @@ include ActionController::UrlWriter
627 643  
628 644 end
629 645  
630   - def more_views_label
  646 + def more_popular_label
631 647 amount = self.hits
632 648 {
633 649 0 => _('no views'),
... ... @@ -655,98 +671,7 @@ include ActionController::UrlWriter
655 671 img.nil? ? '' : img.attributes['src']
656 672 end
657 673  
658   - private
659   -
660   - # FIXME: workaround for development env.
661   - # Subclasses aren't (re)loaded, and acts_as_solr
662   - # depends on subclasses method to search
663   - # see http://stackoverflow.com/questions/4138957/activerecordsubclassnotfound-error-when-using-sti-in-rails/4139245
664   - UploadedFile
665   - TextArticle
666   - TinyMceArticle
667   - TextileArticle
668   - Folder
669   - EnterpriseHomepage
670   - Gallery
671   - Blog
672   - Forum
673   - Event
674   -
675   - def self.f_type_proc(klass)
676   - klass.constantize.type_name
677   - end
678   -
679   - def self.f_profile_type_proc(klass)
680   - klass.constantize.type_name
681   - end
682   -
683   - def f_type
684   - #join common types
685   - case self.class.name
686   - when 'TinyMceArticle', 'TextileArticle'
687   - TextArticle.name
688   - else
689   - self.class.name
690   - end
691   - end
692   -
693   - def f_profile_type
694   - self.profile.class.name
695   - end
696   -
697   - def f_published_at
698   - self.published_at
699   - end
700   -
701   - def f_category
702   - self.categories.collect(&:name)
703   - end
704   -
705 674 delegate :region, :region_id, :environment, :environment_id, :to => :profile, :allow_nil => true
706   - def name_sortable # give a different name for solr
707   - name
708   - end
709   -
710   - def public
711   - self.public?
712   - end
713   -
714   - def category_filter
715   - categories_including_virtual_ids
716   - end
717   -
718   - public
719   -
720   - acts_as_faceted :fields => {
721   - :f_type => {:label => _('Type'), :proc => proc{|klass| f_type_proc(klass)}},
722   - :f_published_at => {:type => :date, :label => _('Published date'), :queries => {'[* TO NOW-1YEARS/DAY]' => _("Older than one year"),
723   - '[NOW-1YEARS TO NOW/DAY]' => _("In the last year"), '[NOW-1MONTHS TO NOW/DAY]' => _("In the last month"), '[NOW-7DAYS TO NOW/DAY]' => _("In the last week"), '[NOW-1DAYS TO NOW/DAY]' => _("In the last day")},
724   - :queries_order => ['[NOW-1DAYS TO NOW/DAY]', '[NOW-7DAYS TO NOW/DAY]', '[NOW-1MONTHS TO NOW/DAY]', '[NOW-1YEARS TO NOW/DAY]', '[* TO NOW-1YEARS/DAY]']},
725   - :f_profile_type => {:label => _('Profile'), :proc => proc{|klass| f_profile_type_proc(klass)}},
726   - :f_category => {:label => _('Categories')},
727   - }, :category_query => proc { |c| "category_filter:\"#{c.id}\"" },
728   - :order => [:f_type, :f_published_at, :f_profile_type, :f_category]
729   -
730   - acts_as_searchable :fields => facets_fields_for_solr + [
731   - # searched fields
732   - {:name => {:type => :text, :boost => 2.0}},
733   - {:slug => :text}, {:body => :text},
734   - {:abstract => :text}, {:filename => :text},
735   - # filtered fields
736   - {:public => :boolean}, {:environment_id => :integer},
737   - {:profile_id => :integer}, :language,
738   - {:category_filter => :integer},
739   - # ordered/query-boosted fields
740   - {:name_sortable => :string}, :last_changed_by_id, :published_at, :is_image,
741   - :updated_at, :created_at,
742   - ], :include => [
743   - {:profile => {:fields => [:name, :identifier, :address, :nickname, :region_id, :lat, :lng]}},
744   - {:comments => {:fields => [:title, :body, :author_name, :author_email]}},
745   - {:categories => {:fields => [:name, :path, :slug, :lat, :lng, :acronym, :abbreviation]}},
746   - ], :facets => facets_option_for_solr,
747   - :boost => proc { |a| 10 if a.profile && a.profile.enabled },
748   - :if => proc{ |a| ! ['RssFeed'].include?(a.class.name) }
749   - handle_asynchronously :solr_save
750 675  
751 676 private
752 677  
... ...
app/models/article_block.rb
... ... @@ -12,7 +12,11 @@ class ArticleBlock &lt; Block
12 12 block = self
13 13 lambda do
14 14 block_title(block.title) +
15   - (block.article ? article_to_html(block.article, :gallery_view => false) : _('Article not selected yet.'))
  15 + (block.article ? article_to_html(block.article,
  16 + :gallery_view => false,
  17 + :inside_block => block, # For Blogs and folders
  18 + :format => block.visualization_format # For Articles and contents
  19 + ).html_safe : _('Article not selected yet.'))
16 20 end
17 21 end
18 22  
... ... @@ -49,4 +53,14 @@ class ArticleBlock &lt; Block
49 53 self.box.owner.kind_of?(Environment) ? self.box.owner.portal_community.articles : self.box.owner.articles
50 54 end
51 55  
  56 + def posts_per_page
  57 + self.settings[:posts_per_page] or 1
  58 + end
  59 +
  60 + def posts_per_page= value
  61 + value = value.to_i
  62 + self.settings[:posts_per_page] = value if value > 0
  63 + end
  64 +
  65 + settings_items :visualization_format, :type => :string, :default => 'short'
52 66 end
... ...
app/models/blog.rb
... ... @@ -24,8 +24,9 @@ class Blog &lt; Folder
24 24 # FIXME isn't this too much including just to be able to generate some HTML?
25 25 include ActionView::Helpers::TagHelper
26 26 def to_html(options = {})
  27 + me = self
27 28 lambda do
28   - render :file => 'content_viewer/blog_page'
  29 + render :file => 'content_viewer/blog_page', :locals => { :blog=>me, :inside_block=>options[:inside_block] }
29 30 end
30 31 end
31 32  
... ...
app/models/category.rb
1 1 class Category < ActiveRecord::Base
2 2  
  3 + SEARCHABLE_FIELDS = {
  4 + :name => 10,
  5 + :acronym => 5,
  6 + :abbreviation => 5,
  7 + :slug => 1,
  8 + }
  9 +
3 10 validates_exclusion_of :slug, :in => [ 'index' ], :message => N_('%{fn} cannot be like that.').fix_i18n
4 11 validates_presence_of :name, :environment_id
5 12 validates_uniqueness_of :slug,:scope => [ :environment_id, :parent_id ], :message => N_('%{fn} is already being used by another category.').fix_i18n
... ... @@ -100,23 +107,4 @@ class Category &lt; ActiveRecord::Base
100 107 self.children.find(:all, :conditions => {:display_in_menu => true}).empty?
101 108 end
102 109  
103   - private
104   - def name_sortable # give a different name for solr
105   - name
106   - end
107   - public
108   -
109   - acts_as_searchable :fields => [
110   - # searched fields
111   - {:name => {:type => :text, :boost => 2.0}},
112   - {:path => :text}, {:slug => :text},
113   - {:abbreviation => :text}, {:acronym => :text},
114   - # filtered fields
115   - :parent_id,
116   - # ordered/query-boosted fields
117   - {:name_sortable => :string},
118   - ]
119   - after_save_reindex [:articles, :profiles], :with => :delayed_job
120   - handle_asynchronously :solr_save
121   -
122 110 end
... ...
app/models/certifier.rb
1 1 class Certifier < ActiveRecord::Base
2 2  
  3 + SEARCHABLE_FIELDS = {
  4 + :name => 10,
  5 + :description => 3,
  6 + :link => 1,
  7 + }
  8 +
3 9 belongs_to :environment
4 10  
5 11 has_many :qualifier_certifiers, :dependent => :destroy
... ... @@ -24,6 +30,4 @@ class Certifier &lt; ActiveRecord::Base
24 30 self.name.downcase.transliterate <=> b.name.downcase.transliterate
25 31 end
26 32  
27   - after_save_reindex [:products], :with => :delayed_job
28   -
29 33 end
... ...
app/models/comment.rb
1 1 class Comment < ActiveRecord::Base
2 2  
  3 + SEARCHABLE_FIELDS = {
  4 + :title => 10,
  5 + :name => 4,
  6 + :body => 2,
  7 + }
  8 +
3 9 validates_presence_of :body
4 10  
5 11 belongs_to :source, :counter_cache => true, :polymorphic => true
... ... @@ -85,12 +91,6 @@ class Comment &lt; ActiveRecord::Base
85 91 self.article.profile.notification_emails - [self.author_email || self.email]
86 92 end
87 93  
88   - after_save :notify_article
89   - after_destroy :notify_article
90   - def notify_article
91   - article.comments_updated if article.kind_of?(Article)
92   - end
93   -
94 94 after_create :new_follower
95 95 def new_follower
96 96 if source.kind_of?(Article)
... ...
app/models/enterprise.rb
... ... @@ -2,6 +2,8 @@
2 2 # only enterprises can offer products and services.
3 3 class Enterprise < Organization
4 4  
  5 + SEARCH_DISPLAYS += %w[map full]
  6 +
5 7 def self.type_name
6 8 _('Enterprise')
7 9 end
... ... @@ -14,8 +16,6 @@ class Enterprise &lt; Organization
14 16  
15 17 has_and_belongs_to_many :fans, :class_name => 'Person', :join_table => 'favorite_enteprises_people'
16 18  
17   - after_save_reindex [:products], :with => :delayed_job
18   - extra_data_for_index :product_categories
19 19 def product_categories
20 20 products.includes(:product_category).map{|p| p.category_full_name}.compact
21 21 end
... ... @@ -182,7 +182,15 @@ class Enterprise &lt; Organization
182 182 end
183 183  
184 184 def activities
185   - Scrap.find_by_sql("SELECT id, updated_at, 'Scrap' AS klass FROM scraps WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, 'ActionTracker::Record' AS klass FROM action_tracker WHERE action_tracker.target_id = #{self.id} UNION SELECT action_tracker.id, action_tracker.updated_at, 'ActionTracker::Record' AS klass FROM action_tracker INNER JOIN articles ON action_tracker.target_id = articles.id WHERE articles.profile_id = #{self.id} AND action_tracker.target_type = 'Article' ORDER BY action_tracker.updated_at DESC")
  185 + Scrap.find_by_sql("SELECT id, updated_at, 'Scrap' AS klass FROM scraps WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, 'ActionTracker::Record' AS klass FROM action_tracker WHERE action_tracker.target_id = #{self.id} UNION SELECT action_tracker.id, action_tracker.updated_at, 'ActionTracker::Record' AS klass FROM action_tracker INNER JOIN articles ON action_tracker.target_id = articles.id WHERE articles.profile_id = #{self.id} AND action_tracker.target_type = 'Article' ORDER BY updated_at DESC")
  186 + end
  187 +
  188 + def catalog_url
  189 + { :profile => identifier, :controller => 'catalog'}
  190 + end
  191 +
  192 + def more_recent_label
  193 + ''
186 194 end
187 195  
188 196 end
... ...
app/models/environment.rb
... ... @@ -268,8 +268,6 @@ class Environment &lt; ActiveRecord::Base
268 268  
269 269 settings_items :search_hints, :type => Hash, :default => {}
270 270  
271   - settings_items :top_level_category_as_facet_ids, :type => Array, :default => []
272   -
273 271 def news_amount_by_folder=(amount)
274 272 settings[:news_amount_by_folder] = amount.to_i
275 273 end
... ... @@ -618,12 +616,10 @@ class Environment &lt; ActiveRecord::Base
618 616 end
619 617  
620 618 def top_url
621   - protocol = 'http'
622   - result = "#{protocol}://#{default_hostname}"
623   - if Noosfero.url_options.has_key?(:port)
624   - result << ':' << Noosfero.url_options[:port].to_s
625   - end
626   - result
  619 + url = 'http://'
  620 + url << (Noosfero.url_options.key?(:host) ? Noosfero.url_options[:host] : default_hostname)
  621 + url << ':' << Noosfero.url_options[:port].to_s if Noosfero.url_options.key?(:port)
  622 + url
627 623 end
628 624  
629 625 def to_s
... ...
app/models/event.rb
... ... @@ -14,7 +14,6 @@ class Event &lt; Article
14 14 maybe_add_http(self.setting[:link])
15 15 end
16 16  
17   - xss_terminate :only => [ :link ], :on => 'validation'
18 17 xss_terminate :only => [ :body, :link, :address ], :with => 'white_list', :on => 'validation'
19 18  
20 19 def initialize(*args)
... ... @@ -104,18 +103,30 @@ class Event &lt; Article
104 103 }
105 104 }
106 105  
  106 + # TODO: some good soul, please clean this ugly hack:
107 107 if self.body
108 108 html.div('_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____', :class => 'event-description')
109 109 end
110 110 }
111 111  
112 112 if self.body
113   - result.sub!('_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____', self.body)
  113 + if options[:format] == 'short'
  114 + result.sub!('_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____', display_short_format(self))
  115 + else
  116 + result.sub!('_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____', self.body)
  117 + end
114 118 end
115 119  
116 120 result
117 121 end
118 122  
  123 + def lead
  124 + content_tag('div',
  125 + show_period(start_date, end_date),
  126 + :class => 'event-dates'
  127 + ) + super
  128 + end
  129 +
119 130 def event?
120 131 true
121 132 end
... ...
app/models/external_feed.rb
... ... @@ -11,6 +11,15 @@ class ExternalFeed &lt; ActiveRecord::Base
11 11 }
12 12  
13 13 def add_item(title, link, date, content)
  14 + doc = Hpricot(content)
  15 + doc.search('*').each do |p|
  16 + if p.instance_of? Hpricot::Elem
  17 + p.remove_attribute 'style'
  18 + p.remove_attribute 'class'
  19 + end
  20 + end
  21 + content = doc.to_s
  22 +
14 23 article = TinyMceArticle.new(:name => title, :profile => blog.profile, :body => content, :published_at => date, :source => link, :profile => blog.profile, :parent => blog)
15 24 unless blog.children.exists?(:slug => article.slug)
16 25 article.save!
... ...
app/models/feed_reader_block.rb
... ... @@ -47,11 +47,11 @@ class FeedReaderBlock &lt; Block
47 47  
48 48 def formatted_feed_content
49 49 if error_message.blank?
50   - "<ul>\n" +
51   - self.feed_items[0..(limit-1)].map{ |item| "<li><a href='#{item[:link]}'>#{item[:title]}</a></li>" }.join("\n") +
52   - "</ul>"
  50 + "<ul>\n".html_safe +
  51 + self.feed_items[0..(limit-1)].map{ |item| "<li><a href='#{item[:link]}'>#{item[:title]}</a></li>" }.join("\n").html_safe +
  52 + "</ul>".html_safe
53 53 else
54   - '<p>' + error_message + '</p>'
  54 + "<p>#{error_message}</p>".html_safe
55 55 end
56 56 end
57 57  
... ...
app/models/license.rb
1 1 class License < ActiveRecord::Base
  2 +
  3 + SEARCHABLE_FIELDS = {
  4 + :name => 10,
  5 + :url => 5,
  6 + }
  7 +
2 8 belongs_to :environment
3 9 has_many :content, :class_name => 'Article', :foreign_key => 'license_id'
4 10  
... ...
app/models/link_list_block.rb
... ... @@ -80,7 +80,7 @@ class LinkListBlock &lt; Block
80 80  
81 81 def icons_options
82 82 ICONS.map do |i|
83   - "<span title=\"#{i[1]}\" class=\"icon-#{i[0]}\" onclick=\"changeIcon(this, '#{i[0]}')\"></span>"
  83 + "<span title=\"#{i[1]}\" class=\"icon-#{i[0]}\" onclick=\"changeIcon(this, '#{i[0]}')\"></span>".html_safe
84 84 end
85 85 end
86 86  
... ...
app/models/national_region.rb
1 1 class NationalRegion < ActiveRecord::Base
2 2  
  3 + SEARCHABLE_FIELDS = {
  4 + :name => 1,
  5 + :national_region_code => 1,
  6 + }
  7 +
3 8 def self.search_city(city_name, like = false, state = nil)
4 9  
5 10 operator = "="
... ...
app/models/organization.rb
1 1 # Represents any organization of the system
2 2 class Organization < Profile
3 3  
  4 + SEARCH_FILTERS += %w[
  5 + more_popular
  6 + more_active
  7 + ]
  8 +
4 9 settings_items :closed, :type => :boolean, :default => false
5 10 def closed?
6 11 closed
... ...
app/models/organization_mailing.rb
... ... @@ -5,7 +5,7 @@ class OrganizationMailing &lt; Mailing
5 5 end
6 6  
7 7 def recipients(offset=0, limit=100)
8   - source.members.all(:order => self.id, :offset => offset, :limit => limit, :joins => "LEFT OUTER JOIN mailing_sents m ON (m.mailing_id = #{id} AND m.person_id = profiles.id)", :conditions => { "m.person_id" => nil })
  8 + source.members.all(:order => :id, :offset => offset, :limit => limit, :joins => "LEFT OUTER JOIN mailing_sents m ON (m.mailing_id = #{id} AND m.person_id = profiles.id)", :conditions => { "m.person_id" => nil })
9 9 end
10 10  
11 11 def each_recipient
... ...
app/models/person.rb
1 1 # A person is the profile of an user holding all relationships with the rest of the system
2 2 class Person < Profile
3 3  
  4 + SEARCH_FILTERS += %w[
  5 + more_popular
  6 + more_active
  7 + ]
  8 +
4 9 def self.type_name
5 10 _('Person')
6 11 end
... ...
app/models/product.rb
1 1 class Product < ActiveRecord::Base
2 2  
  3 + SEARCHABLE_FIELDS = {
  4 + :name => 10,
  5 + :description => 1,
  6 + }
  7 +
  8 + SEARCH_FILTERS = %w[
  9 + more_recent
  10 + ]
  11 +
  12 + SEARCH_DISPLAYS = %w[map full]
  13 +
  14 + def self.default_search_display
  15 + 'full'
  16 + end
  17 +
3 18 belongs_to :enterprise
4 19 has_one :region, :through => :enterprise
5 20 validates_presence_of :enterprise
... ... @@ -173,7 +188,7 @@ class Product &lt; ActiveRecord::Base
173 188  
174 189 def price_described?
175 190 return false if price.blank? or price == 0
176   - (price - total_production_cost).zero?
  191 + (price - total_production_cost.to_f).zero?
177 192 end
178 193  
179 194 def update_price_details(price_details)
... ... @@ -215,89 +230,6 @@ class Product &lt; ActiveRecord::Base
215 230 end
216 231 end
217 232  
218   - private
219   - def f_category
220   - self.product_category.name
221   - end
222   - def f_region
223   - self.enterprise.region.id if self.enterprise.region
224   - end
225   - def self.f_region_proc(id)
226   - c = Region.find(id)
227   - s = c.parent
228   - if c and c.kind_of?(City) and s and s.kind_of?(State) and s.acronym
229   - [c.name, ', ' + s.acronym]
230   - else
231   - c.name
232   - end
233   - end
234   - def self.f_qualifier_proc(ids)
235   - array = ids.split
236   - qualifier = Qualifier.find_by_id array[0]
237   - certifier = Certifier.find_by_id array[1]
238   - certifier ? [qualifier.name, _(' cert. ') + certifier.name] : qualifier.name
239   - end
240   - def f_qualifier
241   - product_qualifiers.map do |pq|
242   - "#{pq.qualifier_id} #{pq.certifier_id}"
243   - end
244   - end
245   -
246   - alias_method :name_sortable, :name
247 233 delegate :enabled, :region, :region_id, :environment, :environment_id, :to => :enterprise
248   - def name_sortable # give a different name for solr
249   - name
250   - end
251   - def public
252   - self.public?
253   - end
254   - def price_sortable
255   - (price.nil? or price.zero?) ? nil : price
256   - end
257   - def category_filter
258   - enterprise.categories_including_virtual_ids << product_category_id
259   - end
260   - public
261   -
262   - acts_as_faceted :fields => {
263   - :f_category => {:label => _('Related products')},
264   - :f_region => {:label => _('City'), :proc => proc { |id| f_region_proc(id) }},
265   - :f_qualifier => {:label => _('Qualifiers'), :proc => proc { |id| f_qualifier_proc(id) }},
266   - }, :category_query => proc { |c| "category_filter:#{c.id}" },
267   - :order => [:f_category, :f_region, :f_qualifier]
268   -
269   - Boosts = [
270   - [:image, 0.55, proc{ |p| p.image ? 1 : 0}],
271   - [:qualifiers, 0.45, proc{ |p| p.product_qualifiers.count > 0 ? 1 : 0}],
272   - [:open_price, 0.45, proc{ |p| p.price_described? ? 1 : 0}],
273   - [:solidarity, 0.45, proc{ |p| p.percentage_from_solidarity_economy[0].to_f/100 }],
274   - [:available, 0.35, proc{ |p| p.available ? 1 : 0}],
275   - [:price, 0.35, proc{ |p| (!p.price.nil? and p.price > 0) ? 1 : 0}],
276   - [:new_product, 0.35, proc{ |p| (p.updated_at.to_i - p.created_at.to_i) < 24*3600 ? 1 : 0}],
277   - [:description, 0.3, proc{ |p| !p.description.blank? ? 1 : 0}],
278   - [:enabled, 0.2, proc{ |p| p.enterprise.enabled ? 1 : 0}],
279   - ]
280   -
281   - acts_as_searchable :fields => facets_fields_for_solr + [
282   - # searched fields
283   - {:name => {:type => :text, :boost => 2.0}},
284   - {:description => :text}, {:category_full_name => :text},
285   - # filtered fields
286   - {:public => :boolean}, {:environment_id => :integer},
287   - {:enabled => :boolean}, {:category_filter => :integer},
288   - # ordered/query-boosted fields
289   - {:price_sortable => :decimal}, {:name_sortable => :string},
290   - {:lat => :float}, {:lng => :float},
291   - :updated_at, :created_at,
292   - ], :include => [
293   - {:product_category => {:fields => [:name, :path, :slug, :lat, :lng, :acronym, :abbreviation]}},
294   - {:region => {:fields => [:name, :path, :slug, :lat, :lng]}},
295   - {:enterprise => {:fields => [:name, :identifier, :address, :nickname, :lat, :lng]}},
296   - {:qualifiers => {:fields => [:name]}},
297   - {:certifiers => {:fields => [:name]}},
298   - ], :facets => facets_option_for_solr,
299   - :boost => proc{ |p| boost = 1; Boosts.each{ |b| boost = boost * (1 - ((1 - b[2].call(p)) * b[1])) }; boost}
300   - handle_asynchronously :solr_save
301   - after_save_reindex [:enterprise], :with => :delayed_job
302 234  
303 235 end
... ...
app/models/product_category.rb
... ... @@ -11,6 +11,4 @@ class ProductCategory &lt; Category
11 11 top_category ? top_category.children : top_level_for(env).select{|c|c.kind_of?(ProductCategory)}
12 12 end
13 13  
14   - after_save_reindex [:products], :with => :delayed_job
15   -
16 14 end
... ...
app/models/profile.rb
... ... @@ -3,10 +3,20 @@
3 3 # which by default is the one returned by Environment:default.
4 4 class Profile < ActiveRecord::Base
5 5  
6   - # use for internationalizable human type names in search facets
7   - # reimplement on subclasses
8   - def self.type_name
9   - _('Profile')
  6 + SEARCHABLE_FIELDS = {
  7 + :name => 10,
  8 + :identifier => 5,
  9 + :nickname => 2,
  10 + }
  11 +
  12 + SEARCH_FILTERS = %w[
  13 + more_recent
  14 + ]
  15 +
  16 + SEARCH_DISPLAYS = %w[compact]
  17 +
  18 + def self.default_search_display
  19 + 'compact'
10 20 end
11 21  
12 22 module Roles
... ... @@ -68,7 +78,7 @@ class Profile &lt; ActiveRecord::Base
68 78 #FIXME: these will work only if the subclass is already loaded
69 79 named_scope :enterprises, lambda { {:conditions => (Enterprise.send(:subclasses).map(&:name) << 'Enterprise').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} }
70 80 named_scope :communities, lambda { {:conditions => (Community.send(:subclasses).map(&:name) << 'Community').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} }
71   - named_scope :templates, :conditions => {:is_template => true}
  81 + named_scope :templates, lambda { |environment| { :conditions => {:is_template => true, :environment_id => environment.id} } }
72 82  
73 83 def members
74 84 scopes = plugins.dispatch_scopes(:organization_members, self)
... ... @@ -127,18 +137,6 @@ class Profile &lt; ActiveRecord::Base
127 137 scrap.nil? ? Scrap.all_scraps(self) : Scrap.all_scraps(self).find(scrap)
128 138 end
129 139  
130   - class_inheritable_accessor :extra_index_methods
131   - self.extra_index_methods = []
132   -
133   - def extra_data_for_index
134   - self.class.extra_index_methods.map { |meth| meth.to_proc.call(self) }.flatten
135   - end
136   -
137   - def self.extra_data_for_index(sym = nil, &block)
138   - self.extra_index_methods.push(sym) if sym
139   - self.extra_index_methods.push(block) if block_given?
140   - end
141   -
142 140 acts_as_having_settings :field => :data
143 141  
144 142 def settings
... ... @@ -211,7 +209,7 @@ class Profile &lt; ActiveRecord::Base
211 209 has_many :profile_categorizations_including_virtual, :class_name => 'ProfileCategorization'
212 210 has_many :categories_including_virtual, :through => :profile_categorizations_including_virtual, :source => :category
213 211  
214   - has_many :abuse_complaints, :foreign_key => 'requestor_id'
  212 + has_many :abuse_complaints, :foreign_key => 'requestor_id', :dependent => :destroy
215 213  
216 214 def top_level_categorization
217 215 ret = {}
... ... @@ -262,7 +260,6 @@ class Profile &lt; ActiveRecord::Base
262 260 else
263 261 ProfileCategorization.add_category_to_profile(c, self)
264 262 self.categories(true)
265   - self.solr_save
266 263 end
267 264 self.categories(reload)
268 265 end
... ... @@ -894,86 +891,6 @@ private :generate_url, :url_options
894 891 self.active_fields
895 892 end
896 893  
897   - private
898   - def self.f_categories_label_proc(environment)
899   - ids = environment.top_level_category_as_facet_ids
900   - r = Category.find(ids)
901   - map = {}
902   - ids.map{ |id| map[id.to_s] = r.detect{|c| c.id == id}.name }
903   - map
904   - end
905   - def self.f_categories_proc(facet, id)
906   - id = id.to_i
907   - return if id.zero?
908   - c = Category.find(id)
909   - c.name if c.top_ancestor.id == facet[:label_id].to_i or facet[:label_id] == 0
910   - end
911   - def f_categories
912   - category_ids - [region_id]
913   - end
914   -
915   - def f_region
916   - self.region_id
917   - end
918   - def self.f_region_proc(id)
919   - c = Region.find(id)
920   - s = c.parent
921   - if c and c.kind_of?(City) and s and s.kind_of?(State) and s.acronym
922   - [c.name, ', ' + s.acronym]
923   - else
924   - c.name
925   - end
926   - end
927   -
928   - def self.f_enabled_proc(enabled)
929   - enabled = enabled == "true" ? true : false
930   - enabled ? s_('facets|Enabled') : s_('facets|Not enabled')
931   - end
932   - def f_enabled
933   - self.enabled
934   - end
935   -
936   - def name_sortable # give a different name for solr
937   - name
938   - end
939   - def public
940   - self.public?
941   - end
942   - def category_filter
943   - categories_including_virtual_ids
944   - end
945   - public
946   -
947   - acts_as_faceted :fields => {
948   - :f_enabled => {:label => _('Situation'), :type_if => proc { |klass| klass.kind_of?(Enterprise) },
949   - :proc => proc { |id| f_enabled_proc(id) }},
950   - :f_region => {:label => _('City'), :proc => proc { |id| f_region_proc(id) }},
951   - :f_categories => {:multi => true, :proc => proc {|facet, id| f_categories_proc(facet, id)},
952   - :label => proc { |env| f_categories_label_proc(env) }, :label_abbrev => proc{ |env| f_categories_label_abbrev_proc(env) }},
953   - }, :category_query => proc { |c| "category_filter:#{c.id}" },
954   - :order => [:f_region, :f_categories, :f_enabled]
955   -
956   - acts_as_searchable :fields => facets_fields_for_solr + [:extra_data_for_index,
957   - # searched fields
958   - {:name => {:type => :text, :boost => 2.0}},
959   - {:identifier => :text}, {:nickname => :text},
960   - # filtered fields
961   - {:public => :boolean}, {:environment_id => :integer},
962   - {:category_filter => :integer},
963   - # ordered/query-boosted fields
964   - {:name_sortable => :string}, {:user_id => :integer},
965   - :enabled, :active, :validated, :public_profile,
966   - {:lat => :float}, {:lng => :float},
967   - :updated_at, :created_at,
968   - ],
969   - :include => [
970   - {:region => {:fields => [:name, :path, :slug, :lat, :lng]}},
971   - {:categories => {:fields => [:name, :path, :slug, :lat, :lng, :acronym, :abbreviation]}},
972   - ], :facets => facets_option_for_solr,
973   - :boost => proc{ |p| 10 if p.enabled }
974   - after_save_reindex [:articles], :with => :delayed_job
975   - handle_asynchronously :solr_save
976   -
977 894 def control_panel_settings_button
978 895 {:title => _('Profile Info and settings'), :icon => 'edit-profile'}
979 896 end
... ...
app/models/profile_list_block.rb
... ... @@ -49,13 +49,12 @@ class ProfileListBlock &lt; Block
49 49 send(:profile_image_link, item, :minor )
50 50 }.join("\n ")
51 51 if list.empty?
52   - list = '<div class="common-profile-list-block-none">'+ _('None') +'</div>'
  52 + list = content_tag 'div', _('None'), :class => 'common-profile-list-block-none'
53 53 else
54 54 list = content_tag 'ul', nl +' '+ list + nl
55 55 end
56 56 block_title(title) + nl +
57   - '<div class="common-profile-list-block">' +
58   - nl + list + nl + '<br style="clear:both" /></div>'
  57 + content_tag('div', nl + list + nl + content_tag('br', '', :style => 'clear:both'))
59 58 end
60 59 end
61 60  
... ...
app/models/qualifier.rb
1 1 class Qualifier < ActiveRecord::Base
2 2  
  3 + SEARCHABLE_FIELDS = {
  4 + :name => 1,
  5 + }
  6 +
3 7 belongs_to :environment
4 8  
5 9 has_many :qualifier_certifiers, :dependent => :destroy
... ... @@ -15,6 +19,4 @@ class Qualifier &lt; ActiveRecord::Base
15 19 self.name.downcase.transliterate <=> b.name.downcase.transliterate
16 20 end
17 21  
18   - after_save_reindex [:products], :with => :delayed_job
19   -
20 22 end
... ...
app/models/raw_html_block.rb
... ... @@ -7,7 +7,7 @@ class RawHTMLBlock &lt; Block
7 7 settings_items :html, :type => :text
8 8  
9 9 def content(args={})
10   - (title.blank? ? '' : block_title(title)) + html.to_s
  10 + (title.blank? ? '' : block_title(title)).html_safe + html.to_s.html_safe
11 11 end
12 12  
13 13 end
... ...
app/models/region.rb
... ... @@ -4,12 +4,6 @@ class Region &lt; Category
4 4  
5 5 require_dependency 'enterprise' # enterprises can also be validators
6 6  
7   - # searches for organizations that could become validators for this region.
8   - # <tt>search</tt> is passed as is to find_by_contents on Organization.
9   - def search_possible_validators(search)
10   - Organization.find_by_contents(search)[:results].docs.reject {|item| self.validator_ids.include?(item.id) }
11   - end
12   -
13 7 def has_validator?
14 8 validators.count > 0
15 9 end
... ...
app/models/scrap.rb
1 1 class Scrap < ActiveRecord::Base
  2 + SEARCHABLE_FIELDS = {
  3 + :content => 1,
  4 + }
2 5 validates_presence_of :content
3 6 validates_presence_of :sender_id, :receiver_id
4 7  
... ...
app/models/spammer_logger.rb
... ... @@ -5,10 +5,10 @@ class SpammerLogger &lt; Logger
5 5 def self.log(spammer_ip, object=nil)
6 6 if object
7 7 if object.kind_of?(Comment)
8   - @logger << "[#{Time.now.strftime("%F %T %z")}] Comment-id: #{object.id} IP: #{spammer_ip}\n"
  8 + @logger << "[#{Time.now.strftime('%F %T %z')}] Comment-id: #{object.id} IP: #{spammer_ip}\n"
9 9 end
10 10 else
11   - @logger << "[#{Time.now.strftime("%F %T %z")}] IP: #{spammer_ip}\n"
  11 + @logger << "[#{Time.now.strftime('%F %T %z')}] IP: #{spammer_ip}\n"
12 12 end
13 13 end
14 14  
... ...
app/models/tags_block.rb
... ... @@ -20,7 +20,8 @@ class TagsBlock &lt; Block
20 20 end
21 21  
22 22 def content(args={})
23   - tags = owner.article_tags
  23 + is_env = owner.class == Environment
  24 + tags = is_env ? owner.tag_counts : owner.article_tags
24 25 return '' if tags.empty?
25 26  
26 27 if limit
... ... @@ -29,18 +30,28 @@ class TagsBlock &lt; Block
29 30 tags_tmp.map{ |k,v| tags[k] = v }
30 31 end
31 32  
  33 + url = is_env ? {:host=>owner.default_hostname, :controller=>'search', :action => 'tag'} :
  34 + owner.public_profile_url.merge(:controller => 'profile', :action => 'tags')
  35 + tagname_option = is_env ? :tag : :id
  36 +
32 37 block_title(title) +
33   - "\n<div class='tag_cloud'>\n"+
34   - tag_cloud( tags, :id,
35   - owner.public_profile_url.merge(:controller => 'profile', :action => 'tags'),
36   - :max_size => 16, :min_size => 9 ) +
37   - "\n</div><!-- end class='tag_cloud' -->\n";
  38 + "\n<div class='tag_cloud'>\n".html_safe+
  39 + tag_cloud( tags, tagname_option, url, :max_size => 16, :min_size => 9 ) +
  40 + "\n</div><!-- end class='tag_cloud' -->\n".html_safe
38 41 end
39 42  
40 43 def footer
41   - owner_id = owner.identifier
42   - lambda do
43   - link_to s_('tags|View all'), :profile => owner_id, :controller => 'profile', :action => 'tags'
  44 + if owner.class == Environment
  45 + lambda do
  46 + link_to s_('tags|View all'),
  47 + :controller => 'search', :action => 'tags'
  48 + end
  49 + else
  50 + owner_id = owner.identifier
  51 + lambda do
  52 + link_to s_('tags|View all'),
  53 + :profile => owner_id, :controller => 'profile', :action => 'tags'
  54 + end
44 55 end
45 56 end
46 57  
... ...
app/models/uploaded_file.rb
... ... @@ -113,7 +113,7 @@ class UploadedFile &lt; Article
113 113  
114 114 content_tag(
115 115 'div',
116   - link_to_previous + content_tag('span', _('image %d of %d'), :class => 'total-of-images') % [current_index + 1, total_of_images] + link_to_next,
  116 + link_to_previous + (content_tag('span', _('image %d of %d'), :class => 'total-of-images') % [current_index + 1, total_of_images]).html_safe + link_to_next,
117 117 :class => 'gallery-navigation'
118 118 )
119 119 end.to_s +
... ...
app/models/user.rb
... ... @@ -15,7 +15,7 @@ class User &lt; ActiveRecord::Base
15 15 # FIXME ugly workaround
16 16 def self.human_attribute_name(attrib)
17 17 case attrib.to_sym
18   - when :login: return _('Username')
  18 + when :login: return [_('Username'), _('Email')].join(' / ')
19 19 when :email: return _('e-Mail')
20 20 else _(self.superclass.human_attribute_name(attrib))
21 21 end
... ... @@ -116,10 +116,11 @@ class User &lt; ActiveRecord::Base
116 116  
117 117 validates_inclusion_of :terms_accepted, :in => [ '1' ], :if => lambda { |u| ! u.terms_of_use.blank? }, :message => N_('%{fn} must be checked in order to signup.').fix_i18n
118 118  
119   - # Authenticates a user by their login name and unencrypted password. Returns the user or nil.
  119 + # Authenticates a user by their login name or email and unencrypted password. Returns the user or nil.
120 120 def self.authenticate(login, password, environment = nil)
121 121 environment ||= Environment.default
122   - u = first :conditions => ['login = ? AND environment_id = ? AND activated_at IS NOT NULL', login, environment.id] # need to get the salt
  122 + u = self.first :conditions => ['(login = ? OR email = ?) AND environment_id = ? AND activated_at IS NOT NULL',
  123 + login, login, environment.id] # need to get the salt
123 124 u && u.authenticated?(password) ? u : nil
124 125 end
125 126  
... ... @@ -293,7 +294,8 @@ class User &lt; ActiveRecord::Base
293 294 'email_domain' => self.enable_email ? self.email_domain : nil,
294 295 'friends_list' => friends_list,
295 296 'enterprises' => enterprises,
296   - 'amount_of_friends' => friends_list.count
  297 + 'amount_of_friends' => friends_list.count,
  298 + 'chat_enabled' => person.environment.enabled?('xmpp_chat')
297 299 }
298 300 end
299 301  
... ...
app/views/account/_signup_form.rhtml
... ... @@ -32,7 +32,8 @@
32 32 <span id="signup-domain"><%= environment.default_hostname %>/</span>
33 33 <div id='signup-login'>
34 34 <div id='signup-login-field' class='formfield'>
35   - <%= required text_field(:user, :login, :id => 'user_login', :onchange => 'this.value = convToValidLogin(this.value);') %>
  35 + <%= required text_field(:user, :login, :id => 'user_login',
  36 + :onchange => 'this.value = convToValidUsername(this.value);') %>
36 37 <div id='url-check'><p>&nbsp;</p></div>
37 38 </div>
38 39 <%= content_tag(:small, _('Choose your login name carefully! It will be your network access and you will not be able to change it later.'), :id => 'signup-balloon') %>
... ...
app/views/account/forgot_password.rhtml
... ... @@ -5,7 +5,7 @@
5 5 <% labelled_form_for :change_password, @change_password, :url => { :action => 'forgot_password' } do |f| %>
6 6  
7 7 <%= f.text_field :login,
8   - :onchange => 'this.value = convToValidLogin( this.value )' %>
  8 + :onchange => 'this.value = convToValidUsername( this.value )' %>
9 9  
10 10 <%= f.text_field :email %>
11 11  
... ...
app/views/admin_panel/site_info.rhtml
... ... @@ -4,7 +4,7 @@
4 4  
5 5 <%= render :file => 'shared/tiny_mce' %>
6 6  
7   -<% labelled_form_for :environment, @environment, :url => {:host => @environment.default_hostname, :port => request.port} do |f| %>
  7 +<% labelled_form_for :environment, @environment do |f| %>
8 8 <% tabs = [] %>
9 9 <% tabs << {:title => _('Site info'), :id => 'site-info',
10 10 :content => (render :partial => 'site_info', :locals => {:f => f})} %>
... ...
app/views/box_organizer/_article_block.rhtml
1   -<div class='article-block-edition'>
  1 +<div class="article-block-edition">
2 2 <% if @block.box.owner.kind_of?(Environment) and @block.box.owner.portal_community.nil? %>
3   - <p id='no_portal_community'>
  3 + <p id="no_portal_community">
4 4 <%= _("You don't have an community defined as the portal community. Define it before use this block properly.") %>
5 5 </p>
6 6 <% else %>
7   - <% articles = @block.available_articles.select {|article| !article.folder? } %>
8   - <%= select_tag('block[article_id]', options_for_select_with_title(articles.map {|item| [item.path, item.id]}, @block.article ? @block.article.id : nil)) %>
  7 + <%
  8 + articles = @block.available_articles.select {|a| !a.folder? || a.blog? }
  9 + first_text = articles[articles.find_index{|a| a.kind_of? TextArticle}||-1]
  10 + selected = @block.article || first_text
  11 + %>
  12 + <%= select_tag(
  13 + 'block[article_id]',
  14 + options_for_select_with_title(articles.map {|item| [item.path, item.id]}, selected.id),
  15 + :onchange => 'this.changedTo(this.value)'
  16 + )%>
  17 + <div id="block_blog_options" style="display:none">
  18 + <%= labelled_form_field(
  19 + _('Number of posts:'),
  20 + text_field_tag('block[posts_per_page]', @block.posts_per_page)
  21 + )%>
  22 + </div>
  23 + <%= labelled_form_field(
  24 + _('How to display this content:'),
  25 + select_tag(
  26 + 'block[visualization_format]',
  27 + options_for_select([[_('Lead'), 'short'], [_('Full post'), 'full']], @block.visualization_format)
  28 + )
  29 + )%>
  30 + <% blogs = @block.available_articles.select{|a|a.blog?} %>
  31 + <script>
  32 + var select = jQuery("#block_article_id")[0];
  33 + select.blogs = <%= blogs.map{|b| b.id.to_s }.to_json %>;
  34 + select.changedTo = function(articleId) {
  35 + var blogSelected = this.blogs.indexOf(articleId) != -1;
  36 + jQuery("#block_blog_options").toggle(blogSelected);
  37 + }
  38 + select.changedTo('<%= selected.id %>');
  39 + </script>
9 40 <% end %>
10 41 </div>
... ...
app/views/box_organizer/_block_types.rhtml
... ... @@ -1,10 +0,0 @@
1   -<% block_types.in_groups_of(2) do |block1, block2| %>
2   - <div style='float: left; width: 48%; padding-top: 2px;'>
3   - <%= labelled_radio_button(block1.description, :type, block1.name) %>
4   - </div>
5   - <% if block2 %>
6   - <div style='float: left; width: 48%; padding-top: 2px;'>
7   - <%= labelled_radio_button(block2.description, :type, block2.name) %>
8   - </div>
9   - <% end %>
10   -<% end %>
app/views/box_organizer/_highlights_block.rhtml
1 1 <strong><%= _('Highlights') %></strong>
2   -<div id='edit-highlights-block' style='width:450px'>
3   -<table id='highlights' class='noborder'>
4   - <tr><th><%= _('Image') %></th><th><%= _('Address') %></th><th><%= _('Position') %></th><th><%= _('Title') %></th></tr>
  2 +
  3 +<table class="noborder"><tbody id="highlights-data-table">
  4 + <tr><th><%= _('Image') %></th><th><%= _('Address') %></th><th><%= _('Position') %></th></tr>
5 5 <% for image in @block.images do %>
6   - <tr>
7   - <td>
8   - <%= select_tag 'block[images][][image_id]', content_tag(:option) + option_groups_from_collection_for_select(@block.folder_choices, :images, :name, :id, :name, image[:image_id].to_i), :style => "width: 100px" %></p>
9   - </td>
10   - <td><%= text_field_tag 'block[images][][address]', image[:address], :class => 'highlight-address', :size => 10 %></td>
11   - <td><%= text_field_tag 'block[images][][position]', image[:position], :class => 'highlight-position', :size => 3 %></td>
12   - <td><%= text_field_tag 'block[images][][title]', image[:title], :class => 'highlight-title', :size => 10 %></td>
13   - </tr>
  6 + <%= highlights_block_config_image_fields @block, image %>
14 7 <% end %>
15   -</table>
16   -</div>
  8 +</tbody></table>
17 9  
18 10 <%= link_to_function(_('New highlight'), nil, :class => 'button icon-add with-text') do |page|
19   - page.insert_html :bottom, 'highlights', content_tag('tr',
20   - content_tag('td', select_tag('block[images][][image_id]', content_tag(:option) + option_groups_from_collection_for_select(@block.folder_choices, :images, :name, :id, :name), :style => "width: 100px")) +
21   - content_tag('td', text_field_tag('block[images][][address]', nil, :class => 'highlight-address', :size => 10)) +
22   - content_tag('td', text_field_tag('block[images][][position]', nil, :class => 'highlight-position', :size => 3)) +
23   - content_tag('td', text_field_tag('block[images][][title]', nil, :class => 'highlight-position', :size => 10))
24   - ) +
25   - javascript_tag("$('edit-link-list-block').scrollTop = $('edit-link-list-block').scrollHeight")
  11 + page.insert_html :bottom, 'highlights-data-table', highlights_block_config_image_fields(@block)
26 12 end %>
27 13  
28 14 <%= labelled_form_field _('Image transition:'), select('block', 'interval', [[_('No automatic transition'), 0]] + [1, 2, 3, 4, 5, 10, 20, 30, 60].map {|item| [n_('Every 1 second', 'Every %d seconds', item) % item, item]}) %>
... ...
app/views/box_organizer/add_block.rhtml
1   -<div style='height:350px'>
  1 +<div id="add-block-dialog">
2 2 <% form_tag do %>
3 3  
4 4 <p><%= _('In what area do you want to put your new block?') %></p>
5 5  
  6 + <div id="box-position">
6 7 <% @boxes.each do |box| %>
7   - <%= labelled_radio_button(_("Area %d") % box.position, :box_id, box.id, box.central?, { :class => 'box-position', 'data-position' => box.position }) %>
  8 + <% name = box.central? ? _('Main area') : _('Area %d') % box.position %>
  9 + <%= labelled_radio_button(name, :box_id, box.id, box.central?, { 'data-position' => box.position }) %>
8 10 <% end %>
  11 + </div>
9 12  
10 13 <script type="text/javascript">
11   - (function ($) {
12   - $(document).ready(function () {
13   - $(".box-position").live('change', function () {
14   - if ($(this).attr('data-position') == '1') {
15   - $('#center-block-types').show();
16   - $('#side-block-types').hide();
17   - } else {
18   - $('#center-block-types').hide();
19   - $('#side-block-types').show();
20   - };
21   - });
22   - })})(jQuery);
  14 + jQuery('#box-position input').bind('change',
  15 + function () {
  16 + showCenter = jQuery(this).attr('data-position') == '1';
  17 + jQuery('#center-block-types').toggle(showCenter);
  18 + jQuery('#side-block-types').toggle(!showCenter);
  19 + }
  20 + );
23 21 </script>
24 22  
25 23 <p><%= _('Select the type of block you want to add to your page.') %></p>
26 24  
27   - <div id='center-block-types'>
28   - <%= render :partial => 'block_types', :locals => { :block_types => @center_block_types } %>
  25 + <div id="center-block-types" class="block-types">
  26 + <% @center_block_types.each do |block| %>
  27 + <div class='block-type'>
  28 + <%= labelled_radio_button(block.description, :type, block.name) %>
  29 + </div>
  30 + <% end %>
29 31 </div>
30 32  
31   - <div id='side-block-types' style='display:none'>
32   - <%= render :partial => 'block_types', :locals => { :block_types => @side_block_types } %>
  33 + <div id="side-block-types" class="block-types" style="display:none">
  34 + <% @side_block_types.each do |block| %>
  35 + <div class='block-type'>
  36 + <%= labelled_radio_button(block.description, :type, block.name) %>
  37 + </div>
  38 + <% end %>
33 39 </div>
34 40  
35 41 <br style='clear: both'/>
... ...
app/views/box_organizer/edit.rhtml
1   -<div style='width: 500px;'>
2   - <h2><%= _('Editing block') %></h2>
  1 +<div class="block-config-options <%= @block.class.name %>-options">
  2 + <h2 class="title"><%= _('Editing block') %></h2>
3 3  
4 4 <% form_tag(:action => 'save', :id => @block.id) do %>
5 5  
... ...
app/views/box_organizer/index.rhtml
1 1 <h1><%= _('Editing sideboxes')%></h1>
2 2  
3   -<% button_bar do %>
  3 +<% button_bar :class=>'design-menu' do %>
4 4 <%= colorbox_button('add', _('Add a block'), { :action => 'add_block' }) %>
5 5 <%= button(:back, _('Back to control panel'), :controller => (profile.nil? ? 'admin_panel': 'profile_editor')) %>
6 6 <% end %>
... ...
app/views/catalog/index.rhtml
... ... @@ -7,13 +7,17 @@
7 7  
8 8 <div class='l-sidebar-left-bar'>
9 9 <ul>
10   - <% if @categories.size > 0 %>
  10 + <%= content_tag('li', link_to(_('Homepage'), profile.url), :class => 'catalog-categories-link') %>
  11 + <%= content_tag('li', link_to(_('Catalog start'), profile.catalog_url), :class => 'catalog-categories-link') %>
  12 + <% if @categories.present? %>
11 13 <% @categories.each do |category| %>
12 14 <%= category_link(category) %>
13 15 <%= category_sub_links(category) %>
14 16 <% end %>
  17 + <% elsif @category.present? %>
  18 + <%= content_tag('li', _('There are no sub-categories for %s') % @category.name, :id => 'catalog-categories-notice') %>
15 19 <% else %>
16   - <%= content_tag('li', _('There are no sub-categories for %s') % @category.name, :style => 'color: #555753; padding-bottom: 0.5em;') %>
  20 + <%= content_tag('li', _('There are no categories available.'), :id => 'catalog-categories-notice') %>
17 21 <% end %>
18 22 </ul>
19 23 </div>
... ... @@ -64,20 +68,20 @@
64 68  
65 69 <% if product.description %>
66 70 <li class="product-description expand-box">
67   - <span id="product-description-button"><%= _('description') %></span>
68   - <div>
  71 + <span class="product-description-button"><%= _('description') %></span>
  72 + <div class="float-box">
69 73 <div class="arrow"></div>
70   - <div class="content" id="product-description"><%= txt2html(product.description || '') %></div>
  74 + <div class="content"><%= product.description %></div>
71 75 </div>
72 76 </li>
73 77 <% end %>
74 78  
75 79 <% if product.price_described? %>
76 80 <li class="product-price-composition expand-box">
77   - <span id="product-price-composition-button"><%= _('price composition') %></span>
78   - <div>
  81 + <span class="product-price-composition-button"><%= _('price composition') %></span>
  82 + <div class="float-box">
79 83 <div class="arrow"></div>
80   - <div class="content" id="product-price-composition">
  84 + <div class="content">
81 85 <% product.inputs.relevant_to_price.each do |i| %>
82 86 <div class="search-product-input-dots-to-price">
83 87 <div class="search-product-input-name"><%= i.product_category.name %></div>
... ... @@ -98,9 +102,9 @@
98 102 <% if product.inputs.count > 0 %>
99 103 <li class="product-inputs expand-box">
100 104 <span id="inputs-button"><%= _('inputs and raw materials') %></span>
101   - <div>
  105 + <div class="float-box">
102 106 <div class="arrow"></div>
103   - <div class="content" id="inputs-description">
  107 + <div class="content">
104 108 <% product.inputs.each do |i| %>
105 109 <div>
106 110 <%= _('%{amount_used} %{unit} of') % {:amount_used => i.amount_used, :unit => i.unit.singular} + ' ' if i.has_all_price_details? %>
... ...
app/views/cms/_text_editor_sidebar.rhtml
... ... @@ -9,7 +9,12 @@
9 9 <div id='media-upload-form'>
10 10 <% form_tag({ :action => 'media_upload' }, :multipart => true) do %>
11 11 <div class='formfield'>
12   - <%= select_profile_folder(_('Choose folder to upload files:'), :parent_id, profile) %>
  12 + <% default_folder = content_id_to_str default_folder_for_image_upload(profile) %>
  13 + <%= select_profile_folder(
  14 + _('Choose folder to upload files:'),
  15 + :parent_id, profile, default_folder, {}, {},
  16 + "type='Folder' or type='Gallery'"
  17 + ) %>
13 18 </div>
14 19 <p><%= file_field_tag('file1') %></p>
15 20 <p><%= file_field_tag('file2') %></p>
... ...
app/views/cms/select_article_type.rhtml
  1 +<div class="select-article-type">
  2 +
1 3 <h2> <%= _('Choose the type of content:') %> </h2>
2 4  
3   -<ul id="article_types">
  5 +<ul class="article-types">
4 6 <% for type in @article_types %>
5 7 <% action = type[:class].name == 'UploadedFile' ? {:action => 'upload_files'} : {:action => 'new', :type => type[:class].name} %>
6 8 <% content_tag('a', :href => url_for(action.merge(:parent_id => @parent_id, :back_to => @back_to))) do %>
... ... @@ -14,3 +16,5 @@
14 16 <br style="clear:both" />
15 17  
16 18 <%= colorbox_close_button(_('Cancel')) %>
  19 +
  20 +</div>
... ...
app/views/content_viewer/blog_page.rhtml
1   -<% add_rss_feed_to_head(@page.name, @page.feed.url) if @page.blog? && @page.feed %>
  1 +<% add_rss_feed_to_head(blog.name, blog.feed.url) if blog.blog? && blog.feed %>
2 2  
3   -<%= content_tag('em', _('(external feed was not loaded yet)'), :id => 'external-feed-info', :class => 'metadata') if @page.blog? && @page.external_feed && @page.external_feed.enabled && @page.external_feed.fetched_at.nil? %>
  3 +<%= content_tag('em', _('(external feed was not loaded yet)'), :id => 'external-feed-info', :class => 'metadata') if blog.blog? && blog.external_feed && blog.external_feed.enabled && blog.external_feed.fetched_at.nil? %>
4 4  
5 5 <div>
6 6 <div class='blog-description'>
7   - <%= @page.body %>
  7 + <%= blog.body %>
8 8 </div>
9 9 </div>
10 10 <hr class="pre-posts"/>
11 11 <div class="blog-posts">
12   - <%= (@page.empty? ? content_tag('em', _('(no posts)')) : list_posts(@posts, @page.visualization_format)) %>
  12 + <%=
  13 + posts = @posts
  14 + format = blog.visualization_format
  15 + if inside_block
  16 + posts = blog.posts.paginate(:page=>1, :per_page=>inside_block.posts_per_page)
  17 + format = inside_block.visualization_format
  18 + end
  19 + (blog.empty? ? content_tag('em', _('(no posts)')) : list_posts(posts, format))
  20 + %>
13 21 </div>
... ...
app/views/content_viewer/view_page.rhtml
... ... @@ -66,7 +66,6 @@
66 66 addthis_options = '<%= escape_javascript( NOOSFERO_CONF['addthis_options'] ) %>';
67 67 </script>
68 68 <a href="http://www.addthis.com/bookmark.php" id="bt_addThis" target="_blank" onmouseover="return addthis_open(this, '', '[URL]')" onmouseout="addthis_close()" onclick="return addthis_sendto()"><%= addthis_image_tag %></a>
69   -<script type="text/javascript" src="http://s7.addthis.com/js/152/addthis_widget.js"></script>
70 69 </div>
71 70 <% end %>
72 71  
... ... @@ -96,7 +95,7 @@
96 95 <% end %>
97 96  
98 97 <% if @page.accept_comments? && @comments_count > 1 %>
99   - <p class="post-comment-button"><a href="#comment_form" onclick="jQuery('#page-comment-form h4').first().trigger('click')"><%= _('Post a comment') %></a></p>
  98 + <%= link_to(_('Post a comment'), '#', :class => 'display-comment-form', :id => 'top-post-comment-button') %>
100 99 <% end %>
101 100  
102 101 <ul class="article-comments-list">
... ...
app/views/favorite_enterprises/index.rhtml
... ... @@ -5,7 +5,7 @@
5 5 <ul class="profile-list">
6 6 <% @favorite_enterprises.each do |enterprise| %>
7 7 <li>
8   - <%= link_to_profile profile_image(enterprise) + '<br/>' + enterprise.name,
  8 + <%= link_to_profile profile_image(enterprise) + '<br/>'.html_safe + enterprise.name,
9 9 enterprise.identifier, :class => 'profile-link' %>
10 10 <%# profile_image_link enterprise, :portrait, 'div' %>
11 11 <div class="controll">
... ...
app/views/layouts/_user.html.erb 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +<div id="user">
  2 + <span class='logged-in' style='display: none;'>
  3 + <%= usermenu_logged_in %>
  4 + </span>
  5 + <span class='not-logged-in' style='display: none'>
  6 +
  7 + <%= _("<span class='login'>%s</span>") % thickbox_inline_popup_link('<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>', login_url, 'inlineLoginBox', :id => 'link_login') %>
  8 + <%= @plugins.dispatch(:alternative_authentication_link).collect { |content| instance_eval(&content) }.join("") %>
  9 +
  10 + <div id='inlineLoginBox' style='display: none;'>
  11 + <%= render :file => 'account/login', :locals => { :is_thickbox => true } %>
  12 + </div>
  13 +
  14 + <% unless @plugins.dispatch(:allow_user_registration).include?(false) %>
  15 + <%= _("<span class='or'>or</span> <span class='signup'>%s</span>") % link_to('<strong>' + _('Sign up') + '</strong>', :controller => 'account', :action => 'signup')%>
  16 + <% end %>
  17 +
  18 + </span>
  19 + <form action="/search" id="top-search" class="search_form clean" method="get">
  20 + <input name="query" size="15" title="<%=_('Search...')%>" onfocus="this.form.className='focused';" onblur="this.form.className=''" />
  21 + <div><%=_('Press <strong>Enter</strong> to send the search query.')%></div>
  22 + <%= javascript_tag 'jQuery("#user form input").hint();' %>
  23 + </form>
  24 +</div><!-- end id="user" -->
... ...
app/views/layouts/application-ng.rhtml
... ... @@ -8,23 +8,10 @@
8 8 <meta name="description" content="<%= @environment.name %>" />
9 9 <link rel="shortcut icon" href="<%= image_path(theme_favicon) %>" type="image/x-icon" />
10 10 <%= noosfero_javascript %>
11   - <%= stylesheet_link_tag noosfero_stylesheets, :cache => 'cache' %>
12   - <%= stylesheet_link_tag template_stylesheet_path %>
13   - <%= stylesheet_link_tag icon_theme_stylesheet_path %>
14   - <%= stylesheet_link_tag jquery_ui_theme_stylesheet_path %>
15   - <%
16   - plugins_stylesheets = @plugins.select(&:stylesheet?).map { |plugin| plugin.class.public_path('style.css') }
17   - %>
18   - <%= stylesheet_link_tag(plugins_stylesheets, :cache => 'cache/plugins-' + Digest::MD5.hexdigest(plugins_stylesheets.to_s)) unless plugins_stylesheets.empty? %>
19   - <%= stylesheet_link_tag theme_stylesheet_path %>
  11 + <%= noosfero_stylesheets %>
20 12  
21 13 <%# Add custom tags/styles/etc via content_for %>
22 14 <%= yield :head %>
23   - <%= javascript_tag('render_all_jquery_ui_widgets()') %>
24   - <%
25   - plugins_javascripts = @plugins.map { |plugin| plugin.js_files.map { |js| plugin.class.public_path(js) } }.flatten
26   - %>
27   - <%= javascript_include_tag(plugins_javascripts, :cache => 'cache/plugins-' + Digest::MD5.hexdigest(plugins_javascripts.to_s)) unless plugins_javascripts.empty? %>
28 15 <%=
29 16 @plugins.dispatch(:head_ending).collect do |content|
30 17 content.respond_to?(:call) ? content.call : content
... ... @@ -35,15 +22,9 @@
35 22 DEFAULT_LOADING_MESSAGE = <%="'#{ _('loading...') }'" %>;
36 23 </script>
37 24 </head>
38   - <body class="<%=
39   - # Identify the current controller and action for the CSS:
40   - " controller-"+ @controller.controller_name() +
41   - " action-"+ @controller.controller_name() +"-"+ @controller.action_name() +
42   - " template-"+ ( profile.nil? ? "default" : profile.layout_template ) +
43   - (!profile.nil? && profile.is_on_homepage?(request.path,@page) ? " profile-homepage" : "")
44   - %>" >
45   -
  25 + <body class="<%= body_classes %>">
46 26 <a href="#content" id="link-go-content"><span><%= _("Go to the content") %></span></a>
  27 +
47 28 <%=
48 29 @plugins.dispatch(:body_beginning).collect do |content|
49 30 content.respond_to?(:call) ? content.call : content
... ... @@ -55,31 +36,7 @@
55 36 <%= theme_header %>
56 37 </div>
57 38 <div id="wrap-2">
58   - <div id="user">
59   - <span class='logged-in' style='display: none;'>
60   - <%= usermenu_logged_in %>
61   - </span>
62   - <span class='not-logged-in' style='display: none'>
63   -
64   - <%= _("<span class='login'>%s</span>") % thickbox_inline_popup_link('<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>', login_url, 'inlineLoginBox', :id => 'link_login') %>
65   - <%= @plugins.dispatch(:alternative_authentication_link).collect { |content| instance_eval(&content) }.join("") %>
66   -
67   - <div id='inlineLoginBox' style='display: none;'>
68   - <%= render :file => 'account/login', :locals => { :is_thickbox => true } %>
69   - </div>
70   -
71   - <% unless @plugins.dispatch(:allow_user_registration).include?(false) %>
72   - <%= _("<span class='or'>or</span> <span class='signup'>%s</span>") % link_to('<strong>' + _('Sign up') + '</strong>', :controller => 'account', :action => 'signup')%>
73   - <% end %>
74   -
75   - </span>
76   - <form action="/search" class="search_form" method="get" class="clean">
77   - <input name="query" size="15" title="<%=_('Search...')%>" onfocus="this.form.className='focused';" onblur="this.form.className=''" />
78   - <div><%=_('Press <strong>Enter</strong> to send the search query.')%></div>
79   - <%= javascript_tag 'jQuery("#user form input").hint();' %>
80   - </form>
81   - </div><!-- end id="user" -->
82   -
  39 + <%= render :partial => 'layouts/user' %>
83 40 <h1 id="site-title">
84 41 <%= theme_site_title %>
85 42 </h1>
... ... @@ -103,5 +60,6 @@
103 60 </div><!-- end id="theme-footer" -->
104 61 <%= noosfero_layout_features %>
105 62 <%= theme_javascript_ng %>
  63 + <%= addthis_javascript %>
106 64 </body>
107 65 </html>
... ...
app/views/map_balloon/product.rhtml
1 1 <div id="balloon">
2   - <%= render :partial => 'search/product', :locals => {:product => @product} %>
  2 + <%= render :partial => 'search/full_product', :locals => {:product => @product} %>
3 3 </div>
... ...
app/views/profile/_profile_wall.rhtml
1 1 <h3><%= _("%s's wall") % @profile.name %></h3>
2 2 <div id='leave_scrap'>
3 3 <%= flash[:error] %>
4   - <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap', :tab_action => 'wall' }, :update => 'profile_activities', :success => "$('leave_scrap_content').value=''" do %>
  4 + <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap', :tab_action => 'wall' }, :update => 'profile_activities', :success => "$('leave_scrap_content').value=''", :complete => "jQuery('#leave_scrap_form').removeClass('loading').find('*').attr('disabled', false)", :loading => "jQuery('#leave_scrap_form').addClass('loading').find('*').attr('disabled', true)", :html => {:id => 'leave_scrap_form' } do %>
5 5 <%= limited_text_area :scrap, :content, 420, 'leave_scrap_content', :cols => 50, :rows => 2 %>
6 6 <%= submit_button :new, _('Share') %>
7 7 <% end %>
... ...
app/views/profile_members/_manage_roles.html.erb
... ... @@ -13,11 +13,11 @@
13 13  
14 14 <% @roles.each do |role| %>
15 15 <% search_url = url_for(:action => 'search_user', :profile => profile.identifier, :role => role.id) %>
16   - <% @pre_population ||= profile.members_by_role_to_json(role) %>
  16 + <% pre_population = params[:action] == 'last_admin' ? [].to_json : profile.members_by_role_to_json(role) %>
17 17 <script type="text/javascript">
18 18 jQuery(<%= ('#search_' + role.key).to_json %>)
19 19 .tokenInput("<%= search_url %>", {
20   - prePopulate: <%= @pre_population %>,
  20 + prePopulate: <%= pre_population %>,
21 21 hintText: <%= _('Type in a search term for users').to_json %>,
22 22 noResultsText: <%= _('No results').to_json %>,
23 23 searchingText: <%= _('Searching...').to_json %>,
... ...
app/views/search/_article.rhtml
... ... @@ -1,12 +0,0 @@
1   -<li class="search-article-item article-item">
2   - <%= link_to(article.title, article.url, :class => "search-result-title") %>
3   - <div class="search-content-first-column">
4   - <%= render :partial => 'image', :object => article %>
5   - </div>
6   - <table class="noborder search-content-second-column">
7   - <%= render :partial => 'article_common', :object => article %>
8   - </table>
9   - <%= render :partial => 'article_last_change', :object => article %>
10   -
11   - <div style="clear:both"></div>
12   -</li>
app/views/search/_blog.rhtml
... ... @@ -1,24 +0,0 @@
1   -<li class="search-blog article-item">
2   - <%= link_to blog.title, blog.view_url, :class => 'search-result-title' %>
3   - <div class="search-content-first-column">
4   - <%= render :partial => 'image', :object => blog %>
5   - </div>
6   - <table class="noborder search-content-second-column">
7   - <tr class="search-blog-items">
8   - <td class="search-field-label"><%= _("Last posts") %></td>
9   -
10   - <% r = blog.children.find(:all, :order => :updated_at, :conditions => ['type != ?', 'RssFeed']).last(3) %>
11   - <td class="<%= "search-field-none" if r.empty? %>">
12   - <% r.each do |a| %>
13   - <%= link_to a.title, a.view_url, :class => 'search-blog-sample-item '+icon_for_article(a) %>
14   - <% end %>
15   - <%= _('None') if r.empty? %>
16   - </td>
17   - </tr>
18   -
19   - <%= render :partial => 'article_common', :object => blog %>
20   - </table>
21   - <%= render :partial => 'article_last_change', :object => blog %>
22   -
23   - <div style="clear: both;"/></div>
24   -</li>
app/views/search/_compact_profile.html.erb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<% filter_label = profile.send(@filter + '_label') %>
  2 +<% filter_label += show_date(profile.created_at) if @filter == 'more_recent' %>
  3 +<li class="search-profile-item">
  4 + <%= profile_image_link profile, :portrait, 'div', filter_label %>
  5 +</li>
... ...
app/views/search/_content.rhtml
... ... @@ -1 +0,0 @@
1   -_article.rhtml
2 0 \ No newline at end of file
app/views/search/_display_results.rhtml
1 1 <div id="search-results" class="<%= !multiple_search? ? 'only-one-result-box' : 'multiple-results-boxes' %>">
2 2 <% @order.each do |name| %>
3   - <% results = @results[name] %>
4   - <% empty = results.nil? || results.empty? %>
  3 + <% search = @searches[name] %>
5 4  
6   - <div class="search-results-<%= name %> search-results-box <%= "search-results-empty" if empty %>">
7   - <% if not empty %>
8   - <% partial = partial_for_class(results.first.class.class_name.constantize) %>
  5 + <div class="search-results-<%= name %> search-results-box <%= "search-results-empty" if search[:results].blank? %>">
  6 + <% if !search[:results].blank? %>
9 7  
10   - <% if multiple_search? %>
  8 + <% if multiple_search?(@searches) %>
11 9 <h3><%= @names[name] %></h3>
12   - <% if results.total_entries > SearchController::MULTIPLE_SEARCH_LIMIT %>
13   - <%= link_to(_('see all (%d)') % results.total_entries, params.merge(:action => name), :class => 'see-more' ) %>
  10 + <% if search[:results].total_entries > SearchController::MULTIPLE_SEARCH_LIMIT %>
  11 + <%= link_to(_('see all (%d)') % search[:results].total_entries, params.merge(:action => name), :class => 'see-more' ) %>
14 12 <% end %>
15 13 <% end %>
16 14  
17   - <div class="search-results-innerbox search-results-type-<%= partial %> <%= 'common-profile-list-block' if partial == 'profile' %>">
  15 + <% display = display_filter(name, params[:display]) %>
  16 +
  17 + <div class="search-results-innerbox search-results-type-<%= name.to_s.singularize %> <%= 'common-profile-list-block' if [:enterprises, :people, :communities].include?(name) %>">
18 18 <ul>
19   - <% results.each do |hit| %>
20   - <%= render :partial => partial_for_class(hit.class), :object => hit %>
21   - <% end %>
  19 + <% search[:results].each do |hit| %>
  20 + <% partial = partial_for_class(hit.class, display) %>
  21 + <% variable_name = partial.gsub("#{display}_", '').to_sym %>
  22 + <%= render :partial => partial, :locals => {variable_name => hit} %>
  23 + <% end %>
22 24 </ul>
23 25 </div>
24 26 <% else %>
... ...
app/views/search/_event.rhtml
... ... @@ -1,25 +0,0 @@
1   -<li class="search-event-item article-item">
2   -<%= link_to(event.title, event.url, :class => "search-result-title") %>
3   -<div class="search-content-first-column">
4   - <%= render :partial => 'image', :object => event %>
5   -</div>
6   -<table class="noborder search-content-second-column">
7   - <% if event.start_date %>
8   - <tr class="search-article-event-date">
9   - <td class="search-field-label"><%= _('Start date') %></td>
10   - <td class="article-item-date"><%= event.start_date %></td>
11   - </tr>
12   - <% end %>
13   - <% if event.end_date %>
14   - <tr class="search-article-event-date">
15   - <td class="search-field-label"><%= _('End date') %></td>
16   - <td class="article-item-date"><%= event.end_date %></td>
17   - </tr>
18   - <% end %>
19   -
20   - <%= render :partial => 'article_common', :object => event %>
21   -</table>
22   -<%= render :partial => 'article_last_change', :object => event %>
23   -
24   -<div style="clear: both"></div>
25   -</li>
app/views/search/_facets_menu.rhtml
... ... @@ -1,36 +0,0 @@
1   -<% less_options_limit = 8 %>
2   -
3   -<div id="facets-menu">
4   - <% @asset_class.map_facets_for(environment).each do |facet| %>
5   -
6   - <div id="facet-menu-<%= facet[:id].to_s %>" class="facet-menu">
7   - <div class="facet-menu-label">
8   - <%= @asset_class.facet_label(facet) %>
9   - </div>
10   -
11   - <% results = @asset_class.map_facet_results(facet, params[:facet], @facets, @all_facets, :limit => less_options_limit) %>
12   - <% facet_count = results.total_entries %>
13   -
14   - <% if facet_count > 0 %>
15   - <div class="facet-menu-options facet-menu-more-options" style="display: none">
16   - </div>
17   -
18   - <div class="facet-menu-options facet-menu-less-options">
19   - <% results.each do |id, label, count| %>
20   - <%= facet_link_html(facet, params, id, label, count) %><br />
21   - <% end %>
22   - </div> <br />
23   -
24   - <% if facet_count > less_options_limit %>
25   - <%= link_to_function _("Options"),
26   - "facet_options_toggle('#{facet[:id].to_s}', '#{url_for(params.merge(:action => 'facets_browse', :facet_id => facet[:id], :asset => @asset, :escape => false))}'); " +
27   - "jQuery(this).toggleClass('facet-less-options')", :class => "facet-options-toggle" %>
28   - <br />
29   - <% end %>
30   -
31   - <% else %>
32   - <span class="facet-any-result-found"><%= _("No filter available") %></span>
33   - <% end %>
34   - </div>
35   - <% end %>
36   -</div>
app/views/search/_facets_unselect_menu.rhtml
... ... @@ -1,6 +0,0 @@
1   -<div class="facets-applied">
2   - <% if params[:facet] and params[:facet].count > 0 %>
3   - <span class="facets-applied-label"><%= _("Applied filters") %> </span>
4   - <%= facet_selecteds_html_for(environment, asset_class(@asset), params) %>
5   - <% end %>
6   -</div>
app/views/search/_folder.rhtml
... ... @@ -1,24 +0,0 @@
1   -<li class="search-folder-item article-item">
2   - <%= link_to folder.title, folder.view_url, :class => 'search-result-title' %>
3   - <div class="search-content-first-column">
4   - <%= render :partial => 'image', :object => folder %>
5   - </div>
6   - <table class="noborder search-content-second-column">
7   - <tr class="search-folder-items">
8   - <td class="search-field-label"><%= _("Last items") %></td>
9   -
10   - <% r = folder.children.last(3) %>
11   - <td class="<%= "search-field-none" if r.empty? %>">
12   - <% r.each do |a| %>
13   - <%= link_to a.title, a.view_url, :class => 'search-folder-sample-item '+icon_for_article(a) %>
14   - <% end %>
15   - <%= _('None') if r.empty? %>
16   - </td>
17   - </tr>
18   -
19   - <%= render :partial => 'article_common', :object => folder %>
20   - </table>
21   - <%= render :partial => 'article_last_change', :object => folder %>
22   -
23   - <div style="clear:both"></div>
24   -</li>
app/views/search/_forum.rhtml
... ... @@ -1,24 +0,0 @@
1   -<li class="search-forum-item article-item">
2   - <%= link_to forum.title, forum.view_url, :class => 'search-result-title' %>
3   - <div class="search-content-first-column">
4   - <%= render :partial => 'image', :object => forum %>
5   - </div>
6   - <table class="noborder search-content-second-column">
7   - <tr class="search-forum-items">
8   - <td class="search-field-label"><%= _("Last topics") %></td>
9   -
10   - <% r = forum.children.find(:all, :order => :updated_at, :conditions => ['type != ?', 'RssFeed']).last(3) %>
11   - <td class="<%= "search-field-none" if r.empty? %>">
12   - <% r.each do |a| %>
13   - <%= link_to a.title, a.view_url, :class => 'search-forum-sample-item '+icon_for_article(a) %>
14   - <% end %>
15   - <%= _('None') if r.empty? %>
16   - </td>
17   - </tr>
18   -
19   - <%= render :partial => 'article_common', :object => forum %>
20   - </table>
21   - <%= render :partial => 'article_last_change', :object => forum %>
22   -
23   - <div style="clear:both"></div>
24   -</li>
app/views/search/_full_article.html.erb 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +<li class="search-article-item article-item">
  2 + <%= link_to(article.title, article.url, :class => "search-result-title") %>
  3 + <div class="search-content-first-column">
  4 + <%= render :partial => 'image', :object => article %>
  5 + </div>
  6 + <table class="noborder search-content-second-column">
  7 + <%= render :partial => 'article_common', :object => article %>
  8 + </table>
  9 + <%= render :partial => 'article_last_change', :object => article %>
  10 +
  11 + <div style="clear:both"></div>
  12 +</li>
... ...
app/views/search/_full_blog.html.erb 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +<li class="search-blog article-item">
  2 + <%= link_to blog.title, blog.view_url, :class => 'search-result-title' %>
  3 + <div class="search-content-first-column">
  4 + <%= render :partial => 'image', :object => blog %>
  5 + </div>
  6 + <table class="noborder search-content-second-column">
  7 + <tr class="search-blog-items">
  8 + <td class="search-field-label"><%= _("Last posts") %></td>
  9 +
  10 + <% r = blog.children.find(:all, :order => :updated_at, :conditions => ['type != ?', 'RssFeed']).last(3) %>
  11 + <td class="<%= "search-field-none" if r.empty? %>">
  12 + <% r.each do |a| %>
  13 + <%= link_to a.title, a.view_url, :class => 'search-blog-sample-item '+icon_for_article(a) %>
  14 + <% end %>
  15 + <%= _('None') if r.empty? %>
  16 + </td>
  17 + </tr>
  18 +
  19 + <%= render :partial => 'article_common', :object => blog %>
  20 + </table>
  21 + <%= render :partial => 'article_last_change', :object => blog %>
  22 +
  23 + <div style="clear: both;"/></div>
  24 +</li>
... ...
app/views/search/_full_enterprise.html.erb 0 → 100644
... ... @@ -0,0 +1,38 @@
  1 +<li class="search-profile-item">
  2 + <div class="search-enterprise-item">
  3 + <div class="search-enterprise-item-column-left">
  4 + <%= profile_image_link enterprise, :portrait, 'div',
  5 + @filter == 'more_recent' ? enterprise.send(@filter + '_label') + show_date(enterprise.created_at) : enterprise.send(@filter + '_label') %>
  6 + </div>
  7 + <div class="search-enterprise-item-column-right">
  8 + <%= link_to_homepage(enterprise.name, enterprise.identifier, :class => "search-result-title") %>
  9 + <div class="search-enterprise-description">
  10 + <% if enterprise.description %>
  11 + <% body_stripped = strip_tags(enterprise.description) %>
  12 + <% elsif enterprise.home_page and enterprise.home_page.body %>
  13 + <% body_stripped = strip_tags(enterprise.home_page.body) %>
  14 + <% end %>
  15 + <%= excerpt(body_stripped, body_stripped.first(3), 200) if body_stripped %>
  16 + </div>
  17 + <div class="search-enterprise-region">
  18 + <span class="search-enterprise-region-label"><%= _("City") %></span>
  19 + <% if enterprise.region %>
  20 + <span class="search-enterprise-region-name"><%= city_with_state(enterprise.region) %></span>
  21 + <% end %>
  22 + </div>
  23 +
  24 + <div class="search-enterprise-categorization">
  25 + <% enterprise.top_level_categorization.each do |parent, children| %>
  26 + <div class="search-enterprise-category-<%=parent.id%> search-enterprise-category">
  27 + <span class="search-enterprise-categorization-parent"><%= parent.name %></span>
  28 + <span class="search-enterprise-categorization-children">
  29 + <%= children.collect(&:name).join(', ') %>
  30 + </span>
  31 + </div>
  32 + <% end %>
  33 + </div>
  34 + </div>
  35 +
  36 + <hr class="clearfix" />
  37 + </div>
  38 +</li>
... ...
app/views/search/_full_event.html.erb 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +<li class="search-event-item article-item">
  2 +<%= link_to(event.title, event.url, :class => "search-result-title") %>
  3 +<div class="search-content-first-column">
  4 + <%= render :partial => 'image', :object => event %>
  5 +</div>
  6 +<table class="noborder search-content-second-column">
  7 + <% if event.start_date %>
  8 + <tr class="search-article-event-date">
  9 + <td class="search-field-label"><%= _('Start date') %></td>
  10 + <td class="article-item-date"><%= event.start_date %></td>
  11 + </tr>
  12 + <% end %>
  13 + <% if event.end_date %>
  14 + <tr class="search-article-event-date">
  15 + <td class="search-field-label"><%= _('End date') %></td>
  16 + <td class="article-item-date"><%= event.end_date %></td>
  17 + </tr>
  18 + <% end %>
  19 +
  20 + <%= render :partial => 'article_common', :object => event %>
  21 +</table>
  22 +<%= render :partial => 'article_last_change', :object => event %>
  23 +
  24 +<div style="clear: both"></div>
  25 +</li>
... ...
app/views/search/_full_folder.html.erb 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +<li class="search-folder-item article-item">
  2 + <%= link_to folder.title, folder.view_url, :class => 'search-result-title' %>
  3 + <div class="search-content-first-column">
  4 + <%= render :partial => 'image', :object => folder %>
  5 + </div>
  6 + <table class="noborder search-content-second-column">
  7 + <tr class="search-folder-items">
  8 + <td class="search-field-label"><%= _("Last items") %></td>
  9 +
  10 + <% r = folder.children.last(3) %>
  11 + <td class="<%= "search-field-none" if r.empty? %>">
  12 + <% r.each do |a| %>
  13 + <%= link_to a.title, a.view_url, :class => 'search-folder-sample-item '+icon_for_article(a) %>
  14 + <% end %>
  15 + <%= _('None') if r.empty? %>
  16 + </td>
  17 + </tr>
  18 +
  19 + <%= render :partial => 'article_common', :object => folder %>
  20 + </table>
  21 + <%= render :partial => 'article_last_change', :object => folder %>
  22 +
  23 + <div style="clear:both"></div>
  24 +</li>
... ...
app/views/search/_full_forum.html.erb 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +<li class="search-forum-item article-item">
  2 + <%= link_to forum.title, forum.view_url, :class => 'search-result-title' %>
  3 + <div class="search-content-first-column">
  4 + <%= render :partial => 'image', :object => forum %>
  5 + </div>
  6 + <table class="noborder search-content-second-column">
  7 + <tr class="search-forum-items">
  8 + <td class="search-field-label"><%= _("Last topics") %></td>
  9 +
  10 + <% r = forum.children.find(:all, :order => :updated_at, :conditions => ['type != ?', 'RssFeed']).last(3) %>
  11 + <td class="<%= "search-field-none" if r.empty? %>">
  12 + <% r.each do |a| %>
  13 + <%= link_to a.title, a.view_url, :class => 'search-forum-sample-item '+icon_for_article(a) %>
  14 + <% end %>
  15 + <%= _('None') if r.empty? %>
  16 + </td>
  17 + </tr>
  18 +
  19 + <%= render :partial => 'article_common', :object => forum %>
  20 + </table>
  21 + <%= render :partial => 'article_last_change', :object => forum %>
  22 +
  23 + <div style="clear:both"></div>
  24 +</li>
... ...
app/views/search/_full_gallery.html.erb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +<li class="search-gallery article-item">
  2 + <%= link_to gallery.title, gallery.view_url, :class => 'search-result-title' %>
  3 + <div class="search-content-first-column">
  4 + <%= render :partial => 'image', :object => gallery %>
  5 + </div>
  6 + <table class="noborder search-content-second-column">
  7 + <%= render :partial => 'article_common', :object => gallery %>
  8 + </table>
  9 + <%= render :partial => 'article_last_change', :object => gallery %>
  10 +
  11 + <div style="clear: both"></div>
  12 +</li>
  13 +
... ...
app/views/search/_full_product.rhtml 0 → 100644
... ... @@ -0,0 +1,85 @@
  1 +<% extra_content = @plugins.dispatch(:asset_product_extras, product).collect { |content| instance_eval(&content) } %>
  2 +<% extra_properties = @plugins.dispatch(:asset_product_properties, product)%>
  3 +
  4 +<li class="search-product-item <%= 'highlighted' if product.highlighted? %>">
  5 +
  6 + <div class="search-product-item-first-column">
  7 + <%= render :partial => 'search/image', :object => product %>
  8 +
  9 + <% if product.available %>
  10 + <% if product.price && product.price > 0 %>
  11 + <% has_discount = product.discount && product.discount > 0 %>
  12 + <% if product.price %>
  13 + <span class="search-product-price-textid"><%=_("from") if has_discount %></span><%= price_span(product.price, :class => "search-product-price " + (has_discount ? 'with-discount' : '')) %>
  14 + <% if has_discount %>
  15 + <span class="search-product-price-textid"><%=_("by")%></span><%= price_span(product.price_with_discount, :class => "search-product-price") %>
  16 + <% end %>
  17 + <% if product.unit %>
  18 + <span class="search-product-unit">&nbsp;<%= _('/') %>&nbsp;<%= product.unit.name %></span>
  19 + <% end %>
  20 + <% end %>
  21 + <div class="search-product-inputs-info">
  22 + <% if p = product.percentage_from_solidarity_economy %>
  23 + <div class="search-product-percentage-from-solidarity-economy search-product-ecosol-percentage-icon-<%= p[0].to_s %>"
  24 + title="<%=_('Percentage of inputs from solidarity economy')%>">
  25 + <%= p[1] %>
  26 + </div>
  27 + <% end %>
  28 +
  29 + <% if product.price_described? %>
  30 + <% title = (product.inputs.relevant_to_price + product.price_details).map{ |i|
  31 + '<div class="search-product-input-dots-to-price">' +
  32 + '<div class="search-product-input-name">' + i.name + '</div>' +
  33 + price_span(i.price, :class => 'search-product-input-price') +
  34 + '</div>' }.join('') %>
  35 + <%= link_to_function _("Open Price"), '', :title => title, :class => "search-product-price-details" %>
  36 + <% end %>
  37 + </div>
  38 + <% end %>
  39 + <% else %>
  40 + <span class="product-not-available"><%= _('Not available') %></div>
  41 + <% end %>
  42 +
  43 + </div>
  44 + <div class="search-product-item-second-column">
  45 + <%= link_to_product product, :class => 'search-result-title' %>
  46 + <div class="search-product-supplier">
  47 + <span class="search-field-label"><%= _('Supplier') %> </span><%= link_to_homepage(product.enterprise.name, product.enterprise.identifier) %>
  48 + </div>
  49 + <div class="search-product-description">
  50 + <% if product.description %>
  51 + <% desc_stripped = strip_tags(product.description) %>
  52 + <span class="search-field-label"><%= _('Description') %> </span><%= excerpt(desc_stripped, desc_stripped.first(3), 300) %>
  53 + <% end %>
  54 + </div>
  55 + </div>
  56 + <div class="search-product-item-third-column">
  57 + <div class="search-product-region">
  58 + <% if product.enterprise.region %>
  59 + <span class="search-field-label"><%= _('City') %></span>
  60 + <br /><%= city_with_state(product.enterprise.region) %>
  61 + <% end %>
  62 + </div>
  63 + <div class="search-product-qualifiers">
  64 + <% if product.product_qualifiers.count > 0 %>
  65 + <span class="search-field-label"><%= _('Qualifiers') %></span>
  66 + <% product.product_qualifiers.each do |pq| %>
  67 + <% if pq.qualifier %>
  68 + <span class="search-product-qualifier"><%= pq.qualifier.name + (pq.certifier.nil? ? _(";") : '') %></span>
  69 + <% end %>
  70 + <% if pq.certifier %>
  71 + <span class="search-product-certifier">&nbsp;<%= _('cert. ') + pq.certifier.name + _(";") %></span>
  72 + <% end %>
  73 + <% end %>
  74 + <% end %>
  75 + </div>
  76 + </div>
  77 +
  78 + <div style="clear: both"></div>
  79 +
  80 + <%= extra_content.join('\n') %>
  81 + <% extra_properties.each do |property| %>
  82 + <div><%= property[:name] + ': ' + instance_eval(&property[:content]) %></div>
  83 + <% end %>
  84 +
  85 +</li>
... ...
app/views/search/_full_text_article.html.erb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +<li class="search-text-article-item article-item">
  2 + <%= link_to(text_article.title, text_article.url, :class => "search-result-title") %>
  3 +
  4 + <div class="search-content-first-column">
  5 + <%= render :partial => 'image', :object => text_article %>
  6 + </div>
  7 + <table class="noborder search-content-second-column">
  8 + <%= render :partial => 'article_common', :object => text_article %>
  9 + </table>
  10 + <%= render :partial => 'article_last_change', :object => text_article %>
  11 +
  12 + <div style="clear: both"></div>
  13 +</li>
... ...
app/views/search/_full_uploaded_file.html.erb 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +<li class="search-uploaded-file-item article-item">
  2 + <%= link_to uploaded_file.filename, uploaded_file.view_url, :class => 'search-result-title' %>
  3 +
  4 + <div class="search-content-first-column">
  5 + <%= render :partial => 'image', :object => uploaded_file %>
  6 + </div>
  7 +
  8 + <table class="noborder search-content-second-column">
  9 + <%= render :partial => 'article_author', :object => uploaded_file %>
  10 + <%= render :partial => 'article_description', :object => uploaded_file %>
  11 +
  12 + <% if uploaded_file.parent and uploaded_file.parent.published? %>
  13 + <tr class="search-uploaded-file-parent">
  14 + <td class="search-field-label"><%= uploaded_file.parent.gallery? ? _("Gallery") : _("Folder") %></td>
  15 + <td><%= link_to uploaded_file.parent.name, uploaded_file.parent.url %></td>
  16 + </tr>
  17 + <% end %>
  18 +
  19 + <%= render :partial => 'article_tags', :object => uploaded_file.tags %>
  20 + <%= render :partial => 'article_categories', :object => uploaded_file.categories %>
  21 + </table>
  22 + <%= render :partial => 'article_last_change', :object => uploaded_file %>
  23 +
  24 + <div style="clear:both"></div>
  25 +</li>
... ...