Mercurial > hg > soundsoftware-site
changeset 739:b7ac21913927 feature_14
new files for project filtering and search (addresses also Feature #68); projects listing interface changes.
author | luisf <luis.figueira@eecs.qmul.ac.uk> |
---|---|
date | Fri, 04 Nov 2011 17:50:35 +0000 |
parents | 3f87a3b61d9c |
children | 4acfc770e79f |
files | vendor/plugins/redmine_tags/app/views/projects/_filtered_projects.rhtml vendor/plugins/redmine_tags/app/views/projects/index.rhtml vendor/plugins/redmine_tags/init.rb vendor/plugins/redmine_tags/lib/redmine_project_filtering.rb vendor/plugins/redmine_tags/lib/redmine_tags/patches/project_patch.rb vendor/plugins/redmine_tags/lib/redmine_tags/patches/projects_controller_patch.rb vendor/plugins/redmine_tags/lib/redmine_tags/patches/projects_helper_patch.rb |
diffstat | 7 files changed, 267 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/plugins/redmine_tags/app/views/projects/_filtered_projects.rhtml Fri Nov 04 17:50:35 2011 +0000 @@ -0,0 +1,19 @@ +<% if @featured_projects && @featured_projects.any? %> + + <div class="splitcontentleft"> + <%= render_project_hierarchy_with_filtering(@projects, @custom_fields, @question) %> + </div> + + <div class="splitcontentright"> + <h3 id="featured-projects-title"><%=l(:project_filtering_featured_projects_label) %></h3> + <div id="featured-projects-box" class="box"> + <%= render_project_hierarchy_with_filtering(@featured_projects, @custom_fields, @question) %> + </div> + </div> + +<% else %> + + <%= render_project_hierarchy_with_filtering(@projects, @custom_fields, @question) %> + +<% end %> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/plugins/redmine_tags/app/views/projects/index.rhtml Fri Nov 04 17:50:35 2011 +0000 @@ -0,0 +1,67 @@ +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:action => 'index', :format => 'atom', :key => User.current.rss_key}) %> +<% end %> + +<div class="contextual"> + <%= link_to l(:label_overall_activity), { :controller => 'activities', :action => 'index' }%> + <%= '| ' + link_to(l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add') if User.current.allowed_to?(:add_project, nil, :global => true) %> +</div> + +<% form_tag('/projects', :method => :get, :id => :project_filtering) do %> + <fieldset id="filters" class="collapsible"> + <legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend> + <div> + <p class='q'> + <%= label_tag 'q', l('project_filtering_q_label') %> + <%= text_field_tag 'q', @question, :size => 30, :id => 'search-input' %> + </p> + <%= render :partial => 'custom_field', :collection => @custom_fields_used_for_project_filtering %> + <p class='buttons'><%= submit_tag( l(:button_send), :id => 'filter_button') -%></p> + </div> + </fieldset> +<% end %> + + +<%= javascript_tag "Field.focus('search-input');" %> +<%= javascript_tag "$('filter_button').hide();" %> +<%= observe_form( :project_filtering, + :frequency => 0.5, + :url => { :controller => :projects, :action => :index, :format => :js }, + :method => :get + ) +%> + +<div id="projects"> + <%= render :partial => 'filtered_projects' %> +</div> + + +<div style="clear:both;"></div> + +<% if User.current.logged? %> +<p style="text-align:right;"> +<span class="my-project"><%= l(:label_my_projects) %></span> +</p> +<% end %> + + +END + +<% if @user_projects %> + <%= render_my_project_hierarchy(@user_projects)%> +<% end %> + +<h2> + <%= l("label_project_all") %> +</h2> + +<%= render_project_table(@projects) %> + +<p class="pagination"><%= pagination_links_full @project_pages, @project_count %></p> + + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> +<% end %> + +<% html_title(l(:label_project_plural)) -%>
--- a/vendor/plugins/redmine_tags/init.rb Tue Nov 01 15:20:40 2011 +0000 +++ b/vendor/plugins/redmine_tags/init.rb Fri Nov 04 17:50:35 2011 +0000 @@ -41,9 +41,16 @@ require 'dispatcher' Dispatcher.to_prepare :redmine_tags do + + require_dependency 'redmine_project_filtering' + unless Project.included_modules.include?(RedmineTags::Patches::ProjectPatch) Project.send(:include, RedmineTags::Patches::ProjectPatch) end + + unless ProjectsHelper.included_modules.include?(RedmineTags::Patches::ProjectsHelperPatch) + ProjectsHelper.send(:include, RedmineTags::Patches::ProjectsHelperPatch) + end unless Issue.included_modules.include?(RedmineTags::Patches::IssuePatch) Issue.send(:include, RedmineTags::Patches::IssuePatch)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/plugins/redmine_tags/lib/redmine_project_filtering.rb Fri Nov 04 17:50:35 2011 +0000 @@ -0,0 +1,16 @@ +module RedmineProjectFiltering + + # transforms a question and a list of custom fields into something that Project.search can process + def self.calculate_tokens(question, custom_fields=nil) + list = [] + list << custom_fields.values if custom_fields.present? + list << question if question.present? + + tokens = list.join(' ').scan(%r{((\s|^)"[\s\w]+"(\s|$)|\S+)}) + tokens = tokens.collect{ |m| m.first.gsub(%r{(^\s*"\s*|\s*"\s*$)}, '') } + + # tokens must be at least 2 characters long + tokens.select {|w| w.length > 1 } + end + +end
--- a/vendor/plugins/redmine_tags/lib/redmine_tags/patches/project_patch.rb Tue Nov 01 15:20:40 2011 +0000 +++ b/vendor/plugins/redmine_tags/lib/redmine_tags/patches/project_patch.rb Fri Nov 04 17:50:35 2011 +0000 @@ -48,6 +48,17 @@ end module ClassMethods + + + def search_by_question(question) + if question.length > 1 + search(RedmineProjectFiltering.calculate_tokens(question), nil, :all_words => true).first.sort_by(&:lft) + else + all(:order => 'lft') + end + end + + # Returns available issue tags # === Parameters # * <i>options</i> = (optional) Options hash of
--- a/vendor/plugins/redmine_tags/lib/redmine_tags/patches/projects_controller_patch.rb Tue Nov 01 15:20:40 2011 +0000 +++ b/vendor/plugins/redmine_tags/lib/redmine_tags/patches/projects_controller_patch.rb Fri Nov 04 17:50:35 2011 +0000 @@ -8,6 +8,7 @@ base.class_eval do unloadable before_filter :add_tags_to_project, :only => [:save, :update] + before_filter :filter_projects, :only => :index end end @@ -20,8 +21,60 @@ unless (old_tags == new_tags) @project.tag_list = new_tags end - end + end end + + + def calculate_project_filtering_settings + @project_filtering_settings = Setting[:plugin_redmine_project_filtering] + end + + def filter_projects + + logger.error { "FILTRA PA!" } + + respond_to do |format| + format.any(:html, :xml) { + calculate_filtered_projects + } + format.js { + calculate_filtered_projects + render :update do |page| + page.replace_html 'projects', :partial => 'filtered_projects' + end + } + format.atom { + projects = Project.visible.find(:all, :order => 'created_on DESC', + :limit => Setting.feeds_limit.to_i) + render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}") + } + end + end + + private + + def calculate_filtered_projects + + @question = (params[:q] || "").strip + @custom_fields = params[:custom_fields] || {} + + @projects = Project.visible + + unless @custom_fields.empty? + @projects = @projects.with_custom_values(params[:custom_fields]) + end + + @featured_projects = @projects.featured if Project.respond_to? :featured + + @projects = @projects.search_by_question(@question) + debugger + @featured_projects = @featured_projects.search_by_question(@question) if @featured_projects + + end + + + + end end end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vendor/plugins/redmine_tags/lib/redmine_tags/patches/projects_helper_patch.rb Fri Nov 04 17:50:35 2011 +0000 @@ -0,0 +1,93 @@ +module RedmineTags + module Patches + module ProjectsHelperPatch + + def self.included(base) # :nodoc: + base.send(:include, InstanceMethods) + base.class_eval do + unloadable + end + end + + module InstanceMethods + # Renders a tree of projects as a nested set of unordered lists + # The given collection may be a subset of the whole project tree + # (eg. some intermediate nodes are private and can not be seen) + def render_project_hierarchy_with_filtering(projects,custom_fields,question) + s = [] + if projects.any? + tokens = RedmineProjectFiltering.calculate_tokens(question, custom_fields) + debugger + + + ancestors = [] + original_project = @project + projects.each do |project| + # set the project environment to please macros. + @project = project + if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) + s << "<ul class='projects #{ ancestors.empty? ? 'root' : nil}'>" + else + ancestors.pop + s << "</li>" + while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) + ancestors.pop + s << "</ul></li>" + end + end + classes = (ancestors.empty? ? 'root' : 'child') + s << "<li class='#{classes}'><div class='#{classes}'>" + + link_to( highlight_tokens(project.name, tokens), + {:controller => 'projects', :action => 'show', :id => project}, + :class => "project #{User.current.member_of?(project) ? 'my-project' : nil}" + ) + s << "<ul class='filter_fields'>" + + # CustomField.usable_for_project_filtering.each do |field| + # value_model = project.custom_value_for(field.id) + # value = value_model.present? ? value_model.value : nil + # s << "<li><b>#{field.name.humanize}:</b> #{highlight_tokens(value, tokens)}</li>" if value.present? + # end + + s << "</ul>" + s << "<div class='clear'></div>" + unless project.description.blank? + s << "<div class='wiki description'>" + s << "<b>#{ t(:field_description) }:</b>" + s << highlight_tokens(textilizable(project.short_description, :project => project), tokens) + s << "\n</div>" + end + s << "</div>" + ancestors << project + end + ancestors.size.times{ s << "</li></ul>" } + @project = original_project + end + s.join "\n" + end + + private + + # copied from search_helper. This one doesn't escape html or limit the text length + def highlight_tokens(text, tokens) + return text unless text && tokens && !tokens.empty? + re_tokens = tokens.collect {|t| Regexp.escape(t)} + regexp = Regexp.new "(#{re_tokens.join('|')})", Regexp::IGNORECASE + result = '' + text.split(regexp).each_with_index do |words, i| + words = words.mb_chars + if i.even? + result << words + else + t = (tokens.index(words.downcase) || 0) % 4 + result << content_tag('span', words, :class => "highlight token-#{t}") + end + end + result + end + + end + end + end +end +