Redmineのカレンダーを流用する

Redmine2.0.3をAptanaに入れてカレンダーを流用することを目的とします。
 

へっだーだけ

ひとまず動くところに持って行きたい。

redmine203/app/controllers/calendar.rbから一部抜粋してapp_root/app/controllers/hoges_controller.rbに貼り付け

  def calendar
    if params[:year] and params[:year].to_i > 1900
      @year = params[:year].to_i
      if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13
        @month = params[:month].to_i
      end
    end
    @year ||= Date.today.year
    @month ||= Date.today.month
  end

redmine203/app/views/calendar/show.html.erbから一部抜粋してapp_root/app/views/hoges/calendar.html.erbに貼り付ける

<div class="calendar_label">
	<%= link_to_previous_month(@year, @month) %> 
	<%= select_year(@year, :prefix => "year", :discard_type => true) %>
	<%= select_month(@month, :prefix => "month", :discard_type => true) %>
	<%= link_to_next_month(@year, @month) %>
</div>

これが動くようになるように改造する。

redmine203/lib/redmine/i18n.rbをコピーしてapp_root/lib/redmine/i18n.rbに貼り付ける。
 
app_root/app/helpers/application_helper.rbに追記

module ApplicationHelper
include Redmine::I18n #追記

redmin203/app/helpers/calendars_helper.rbから一部抜粋して、app_root/app/helpers/application_helper.rbに追記

  def link_to_previous_month(year, month, options={})
    target_year, target_month = if month == 1
                                  [year - 1, 12]
                                else
                                  [year, month - 1]
                                end

    name = if target_month == 12
             "#{month_name(target_month)} #{target_year}"
           else
             "#{month_name(target_month)}"
           end

    # \xc2\xab(utf-8) = &#171;
    link_to_month(("\xc2\xab " + name), target_year, target_month, options)
  end

  def link_to_next_month(year, month, options={})
    target_year, target_month = if month == 12
                                  [year + 1, 1]
                                else
                                  [year, month + 1]
                                end

    name = if target_month == 1
             "#{month_name(target_month)} #{target_year}"
           else
             "#{month_name(target_month)}"
           end

    # \xc2\xbb(utf-8) = &#187;
    link_to_month((name + " \xc2\xbb"), target_year, target_month, options)
  end

  def link_to_month(link_name, year, month, options={})
    link_to_content_update(h(link_name), params.merge(:year => year, :month => month))
  end

redmin203/app/helpers/application_helper.rbから一部抜粋して、app_root/app/helpers/application_helper.rbに追記

  private
  def link_to_content_update(text, url_params = {}, html_options = {})
    link_to(text, url_params, html_options)
  end

これで表示された。

ほんたい

controllerにあったこれがわからん。

@calendar = Redmine::Helpers::Calendar.new(Date.civil(@year, @month, 1), current_language, :month)

やっと見つけた
redmine203/lib/redmine/helpers/calendar.rb を app_root/lib/redmine/helpers/calendar.rbにコピー

current_languageはi18nにあったけど通らないので"ja"で代用

まだエラーがでる。

lib/redmine/helpers/calendar.rb:68:in `first_wday'

case Setting.start_of_week.to_i #げんいん

Settingなんて用意しない。
app_root/lib/redmine/helpers/calendar.rb
週の始まりは「月曜日」にきまっている。(偏見)

      # Return the first day of week
      # 1 = Monday ... 7 = Sunday
      def first_wday
        @first_dow ||= (1 - 1)%7 + 1
=begin
        case Setting.start_of_week.to_i
        when 1
          @first_dow ||= (1 - 1)%7 + 1
        when 6
          @first_dow ||= (6 - 1)%7 + 1
        when 7
          @first_dow ||= (7 - 1)%7 + 1
        else
          @first_dow ||= (l(:general_first_day_of_week).to_i - 1)%7 + 1
        end
=end
      end

retrieve_queryは redmine203/app/helpers/queries_helper.rbにある。
idで絞りこんでいる。ページ遷移したときにsessionのidを見たりしている。謎要素多いけど使わないでおこう。たぶんいらない。

とりあえず表示されるようになったので続く。
 
redmine203/app/views/calendar/show.html.erbの28行目にあった

<%= error_messages_for 'query' %>

application_helper.rbの967行目ぐらいにあった

  def error_messages_for(*objects)
    html = ""
    objects = objects.map {|o| o.is_a?(String) ? instance_variable_get("@#{o}") : o}.compact
    errors = objects.map {|o| o.errors.full_messages}.flatten
    if errors.any?
      html << "<div id='errorExplanation'><ul>\n"
      errors.each do |error|
        html << "<li>#{h error}</li>\n"
      end
      html << "</ul></div>\n"
    end
    html.html_safe
  end  

いらないとおもう。


次の謎はコントローラーの「issues」

events += @query.issues(:include => [:tracker, :assigned_to, :priority],
:conditions => ["((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?))", 
@calendar.startdt, @calendar.enddt, @calendar.startdt, @calendar.enddt]
)

redmine203/app/models/query.rbの584行目あたりにあった

  # Returns the issues
  # Valid options are :order, :offset, :limit, :include, :conditions
  def issues(options={})
    order_option = [group_by_sort_order, options[:order]].reject {|s| s.blank?}.join(',')
    order_option = nil if order_option.blank?
    
    joins = (order_option && order_option.include?('authors')) ? "LEFT OUTER JOIN users authors ON authors.id = #{Issue.table_name}.author_id" : nil

    issues = Issue.visible.scoped(:conditions => options[:conditions]).find :all, :include => ([:status, :project] + (options[:include] || [])).uniq,
                     :conditions => statement,
                     :order => order_option,
                     :joins => joins,
                     :limit  => options[:limit],
                     :offset => options[:offset]

    if has_column?(:spent_hours)
      Issue.load_visible_spent_hours(issues)
    end
    issues
  rescue ::ActiveRecord::StatementInvalid => e
    raise StatementInvalid.new(e.message)
  end

普通のfindやwhereで十分っぽいので使う必要はなさそう。
 
次の謎はコントローラーの「versions」

events += @query.versions(:conditions => ["effective_date BETWEEN ? AND ?", @calendar.startdt, @calendar.enddt])

redmine203/app/models/query.rbの634行目あたりにあった

  # Returns the versions
  # Valid options are :conditions
  def versions(options={})
    Version.visible.scoped(:conditions => options[:conditions]).find :all, :include => :project, :conditions => project_statement
  rescue ::ActiveRecord::StatementInvalid => e
    raise StatementInvalid.new(e.message)
  end

こっちも普通のfindやwhereで十分っぽいので使う必要はなさそう。

コントローラの締めくくり

@calendar.events = events

app_root/lib/redmine/helpers/calendar.rbのコレ

# Sets calendar events
def events=(events)
  @events = events
  @ending_events_by_days = @events.group_by {|event| event.due_date}
  @starting_events_by_days = @events.group_by {|event| event.start_date}
end

これはモデルごとに作りなおしかなー?面倒なのでコントローラーにぶち込む。

@calendar = Redmine::Helpers::Calendar.new(Date.civil(@year, @month, 1), "ja", :month)
events = Iftb.where("dtstart between ? AND ?",@calendar.startdt, @calendar.enddt)
@ending_events_by_days = events.group_by {|event| event.dtend}
@starting_events_by_days = events.group_by {|event| event.dtstart}


viewも追加

<div class="calendar_label">
	<%= link_to_previous_month(@year, @month) %> 
	<%= select_year(@year, :prefix => "year", :discard_type => true) %>
	<%= select_month(@month, :prefix => "month", :discard_type => true) %>
	<%= link_to_next_month(@year, @month) %>
</div>
<% unless @calendar.nil? %>
<%= render :partial => 'calendar', :locals => {:calendar => @calendar} %>
<% end %>

redmine203/app/views/common/_calendar.html.erbをコピーしてapp_root/app/views/hoges/_calendar.html.erbに貼り付ける


とりあえず表示されるようになった。

_calendar.html.erbの

<% calendar.events_on(day).each do |i| %>

これで悩む。
app_root/lib/redmine/helpers/calendar.rbのevents_on(day)を参照してくれるけど中身が表示されない。。。。


app_root/lib/redmine/helpers/calendar.rbを改造する

def events_hoge=(events)
  @events = events
  @ending_events_by_days = events.group_by {|event| event.dtend.to_s(:date)}
  @starting_events_by_days = events.group_by {|event| event.dtstart.to_s(:date)}
end

dtendとdestartはdatetime型なので文字列にしてからconfig/initalizers/datetime_formats.rbの「:date」パワーを使って「%Y-%m-%d"」に変換する。

_calendar.html.erbの

<% calendar.events_on(day.to_s).each do |i| %>

文字列に合わせてあげるとなんとかなった。
 

プルダウンメニューの年月が動いていいない(20121024追記)

いまさら気がついた。
アップデートする仕掛けが入っていない。
redmine203/app/views/calendar/show.html.erb

#3行目
<%= form_tag({:controller => 'calendars', :action => 'show', :project_id => @project},
             :method => :get, :id => 'query_form') do %>
#23行目
<%= link_to_function l(:button_apply), '$("query_form").submit()', :class => 'icon icon-checked' %>

変更してから、ボタンを押すことでフォームの値を送信する・・・あまりやりたくない。


こんなのを見つけた。
Rails select_tag の onchangeイベントによる form_tag action属性の変更

<%= form_tag :controller => "index", :action => "index" do %>
<%= select_tag(:area_id, options_from_collection_for_select(@areas, :id, :area_name, @area_id), \:onchange => "this.form.submit()") %>
<% end %>

このまま仕込むとNGだったので調べる。
http://www.ruby-forum.com/topic/176963

select_year(date, options = {}, html_options = {})

こんな感じに改造

<%= form_tag :action => "calendar" do %>
<div class="calendar_label">
	<%= link_to_previous_month(@year, @month) %> 
	<%= select_year(@year, {:prefix => "year", :discard_type => true}, {:onchange => 'this.form.submit()'}) %>
	<%= select_month(@month, {:prefix => "month", :discard_type => true}, {:onchange => 'this.form.submit()'}) %>
	<%= link_to_next_month(@year, @month) %>
</div>
・・・
<% end %>