Revision 739:b7ac21913927 vendor/plugins

View differences:

vendor/plugins/redmine_tags/app/views/projects/_filtered_projects.rhtml
1
<% if @featured_projects && @featured_projects.any? %>
2

  
3
  <div class="splitcontentleft">
4
    <%= render_project_hierarchy_with_filtering(@projects, @custom_fields, @question) %>
5
  </div>
6

  
7
  <div class="splitcontentright">
8
    <h3 id="featured-projects-title"><%=l(:project_filtering_featured_projects_label) %></h3>
9
    <div id="featured-projects-box" class="box">
10
      <%= render_project_hierarchy_with_filtering(@featured_projects, @custom_fields, @question) %>
11
    </div>
12
  </div>
13

  
14
<% else %>
15

  
16
  <%= render_project_hierarchy_with_filtering(@projects, @custom_fields, @question) %>
17

  
18
<% end %>
19

  
vendor/plugins/redmine_tags/app/views/projects/index.rhtml
1
<% content_for :header_tags do %>
2
    <%= auto_discovery_link_tag(:atom, {:action => 'index', :format => 'atom', :key => User.current.rss_key}) %>
3
<% end %>
4

  
5
<div class="contextual">
6
    <%= link_to l(:label_overall_activity), { :controller => 'activities', :action => 'index' }%>
7
    <%= '| ' + link_to(l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add') if User.current.allowed_to?(:add_project, nil, :global => true) %>
8
</div>
9

  
10
<% form_tag('/projects', :method => :get, :id => :project_filtering) do %>
11
  <fieldset id="filters" class="collapsible">
12
    <legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
13
    <div>
14
      <p class='q'>
15
        <%= label_tag 'q', l('project_filtering_q_label') %>
16
        <%= text_field_tag 'q', @question, :size => 30, :id => 'search-input' %>
17
      </p>
18
      <%= render :partial => 'custom_field', :collection => @custom_fields_used_for_project_filtering %>
19
      <p class='buttons'><%= submit_tag( l(:button_send), :id => 'filter_button') -%></p>
20
    </div>
21
  </fieldset>
22
<% end %>
23

  
24

  
25
<%= javascript_tag "Field.focus('search-input');" %>
26
<%= javascript_tag "$('filter_button').hide();" %>
27
<%= observe_form( :project_filtering,
28
  :frequency => 0.5,
29
  :url => { :controller => :projects, :action => :index, :format => :js },
30
  :method => :get
31
  )
32
%>
33

  
34
<div id="projects">
35
  <%= render :partial => 'filtered_projects' %>
36
</div>
37

  
38

  
39
<div style="clear:both;"></div>
40

  
41
<% if User.current.logged? %>
42
<p style="text-align:right;">
43
<span class="my-project"><%= l(:label_my_projects) %></span>
44
</p>
45
<% end %>
46

  
47

  
48
END
49

  
50
<% if @user_projects %>  
51
  <%= render_my_project_hierarchy(@user_projects)%>
52
<% end %>
53

  
54
<h2>
55
  <%= l("label_project_all") %>
56
</h2>
57

  
58
<%= render_project_table(@projects) %>
59

  
60
<p class="pagination"><%= pagination_links_full @project_pages, @project_count %></p>
61

  
62

  
63
<% other_formats_links do |f| %>
64
	<%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %>
65
<% end %>
66

  
67
<% html_title(l(:label_project_plural)) -%>
vendor/plugins/redmine_tags/init.rb
41 41
require 'dispatcher'
42 42

  
43 43
Dispatcher.to_prepare :redmine_tags do
44
  
45
  require_dependency 'redmine_project_filtering'
46
  
44 47
  unless Project.included_modules.include?(RedmineTags::Patches::ProjectPatch)
45 48
    Project.send(:include, RedmineTags::Patches::ProjectPatch)
46 49
  end
50
  
51
  unless ProjectsHelper.included_modules.include?(RedmineTags::Patches::ProjectsHelperPatch)
52
    ProjectsHelper.send(:include, RedmineTags::Patches::ProjectsHelperPatch)
53
  end    
47 54

  
48 55
  unless Issue.included_modules.include?(RedmineTags::Patches::IssuePatch)
49 56
    Issue.send(:include, RedmineTags::Patches::IssuePatch)
vendor/plugins/redmine_tags/lib/redmine_project_filtering.rb
1
module RedmineProjectFiltering
2

  
3
  # transforms a question and a list of custom fields into something that Project.search can process
4
  def self.calculate_tokens(question, custom_fields=nil)
5
    list = []
6
    list << custom_fields.values if custom_fields.present?
7
    list << question if question.present?
8

  
9
    tokens = list.join(' ').scan(%r{((\s|^)"[\s\w]+"(\s|$)|\S+)})
10
    tokens = tokens.collect{ |m| m.first.gsub(%r{(^\s*"\s*|\s*"\s*$)}, '') }
11
    
12
    # tokens must be at least 2 characters long
13
    tokens.select {|w| w.length > 1 }
14
  end
15

  
16
end
vendor/plugins/redmine_tags/lib/redmine_tags/patches/project_patch.rb
48 48
      end
49 49

  
50 50
      module ClassMethods
51

  
52

  
53
        def search_by_question(question)
54
          if question.length > 1
55
            search(RedmineProjectFiltering.calculate_tokens(question), nil, :all_words => true).first.sort_by(&:lft)
56
          else
57
            all(:order => 'lft')
58
          end
59
        end
60

  
61

  
51 62
        # Returns available issue tags
52 63
        # === Parameters
53 64
        # * <i>options</i> = (optional) Options hash of
vendor/plugins/redmine_tags/lib/redmine_tags/patches/projects_controller_patch.rb
8 8
        base.class_eval do          
9 9
          unloadable 
10 10
          before_filter :add_tags_to_project, :only => [:save, :update]
11
          before_filter :filter_projects, :only => :index          
11 12
        end
12 13
      end
13 14

  
......
20 21
            unless (old_tags == new_tags)
21 22
              @project.tag_list = new_tags
22 23
            end
23
          end                    
24
          end
24 25
        end
26
  
27
  
28
         def calculate_project_filtering_settings
29
            @project_filtering_settings = Setting[:plugin_redmine_project_filtering]
30
          end
31

  
32
          def filter_projects
33
            
34
            logger.error { "FILTRA PA!" }
35
            
36
            respond_to do |format|
37
              format.any(:html, :xml) { 
38
                calculate_filtered_projects
39
              }
40
              format.js {
41
                calculate_filtered_projects
42
                render :update do |page|
43
                  page.replace_html 'projects', :partial => 'filtered_projects'
44
                end
45
              }
46
              format.atom {
47
                projects = Project.visible.find(:all, :order => 'created_on DESC',
48
                                                      :limit => Setting.feeds_limit.to_i)
49
                render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
50
              }
51
            end
52
          end
53

  
54
          private
55

  
56
          def calculate_filtered_projects
57

  
58
            @question = (params[:q] || "").strip
59
            @custom_fields = params[:custom_fields] || {}
60

  
61
            @projects = Project.visible
62

  
63
            unless @custom_fields.empty?
64
              @projects = @projects.with_custom_values(params[:custom_fields])
65
            end
66

  
67
            @featured_projects = @projects.featured if Project.respond_to? :featured
68

  
69
            @projects = @projects.search_by_question(@question)
70
            debugger                                  
71
            @featured_projects = @featured_projects.search_by_question(@question) if @featured_projects
72

  
73
          end
74
  
75
  
76
  
77
        
25 78
      end
26 79
    end
27 80
  end
vendor/plugins/redmine_tags/lib/redmine_tags/patches/projects_helper_patch.rb
1
module RedmineTags
2
  module Patches
3
    module ProjectsHelperPatch
4

  
5
      def self.included(base) # :nodoc:
6
        base.send(:include, InstanceMethods)
7
        base.class_eval do
8
          unloadable
9
        end
10
      end
11

  
12
      module InstanceMethods
13
        # Renders a tree of projects as a nested set of unordered lists
14
        # The given collection may be a subset of the whole project tree
15
        # (eg. some intermediate nodes are private and can not be seen)
16
        def render_project_hierarchy_with_filtering(projects,custom_fields,question)
17
          s = []
18
          if projects.any?
19
            tokens = RedmineProjectFiltering.calculate_tokens(question, custom_fields)
20
            debugger
21
            
22

  
23
            ancestors = []
24
            original_project = @project
25
            projects.each do |project|
26
              # set the project environment to please macros.
27
              @project = project
28
              if (ancestors.empty? || project.is_descendant_of?(ancestors.last))
29
                s << "<ul class='projects #{ ancestors.empty? ? 'root' : nil}'>"
30
              else
31
                ancestors.pop
32
                s << "</li>"
33
                while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) 
34
                  ancestors.pop
35
                  s << "</ul></li>"
36
                end
37
              end
38
              classes = (ancestors.empty? ? 'root' : 'child')
39
              s << "<li class='#{classes}'><div class='#{classes}'>" +
40
                link_to( highlight_tokens(project.name, tokens), 
41
                  {:controller => 'projects', :action => 'show', :id => project},
42
                  :class => "project #{User.current.member_of?(project) ? 'my-project' : nil}"
43
                )
44
              s << "<ul class='filter_fields'>"
45

  
46
           #  CustomField.usable_for_project_filtering.each do |field|
47
           #    value_model = project.custom_value_for(field.id)
48
           #    value = value_model.present? ? value_model.value : nil
49
           #    s << "<li><b>#{field.name.humanize}:</b> #{highlight_tokens(value, tokens)}</li>" if value.present?
50
           #  end
51
              
52
              s << "</ul>"
53
              s << "<div class='clear'></div>"
54
              unless project.description.blank?
55
                s << "<div class='wiki description'>"
56
                s << "<b>#{ t(:field_description) }:</b>"
57
                s << highlight_tokens(textilizable(project.short_description, :project => project), tokens)
58
                s << "\n</div>"
59
              end
60
              s << "</div>"
61
              ancestors << project
62
            end
63
            ancestors.size.times{ s << "</li></ul>" }
64
            @project = original_project
65
          end
66
          s.join "\n"
67
        end
68
        
69
        private
70
        
71
        # copied from search_helper. This one doesn't escape html or limit the text length
72
        def highlight_tokens(text, tokens)
73
          return text unless text && tokens && !tokens.empty?
74
          re_tokens = tokens.collect {|t| Regexp.escape(t)}
75
          regexp = Regexp.new "(#{re_tokens.join('|')})", Regexp::IGNORECASE    
76
          result = ''
77
          text.split(regexp).each_with_index do |words, i|
78
            words = words.mb_chars
79
            if i.even?
80
              result << words
81
            else
82
              t = (tokens.index(words.downcase) || 0) % 4
83
              result << content_tag('span', words, :class => "highlight token-#{t}")
84
            end
85
          end
86
          result
87
        end
88
      
89
      end
90
    end
91
  end
92
end
93

  

Also available in: Unified diff