Skip to content

Commit

Permalink
More work on date support in links, started to refactor calendar to s…
Browse files Browse the repository at this point in the history
…upport hours. [#255]
  • Loading branch information
gaspard committed Jul 20, 2009
1 parent 2a8092c commit b51211f
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 37 deletions.
31 changes: 25 additions & 6 deletions app/helpers/application_helper.rb
Expand Up @@ -821,14 +821,33 @@ def cal_class(date, ref)
end

# Yield block for every week between 'start_date' and 'end_date' with a hash of days => events.
def cal_weeks(date_attr, list, start_date, end_date)
def cal_weeks(date_attr, list, start_date, end_date, hours = nil)
# build event hash
cal_hash = {}
(list || []).each do |n|
d = n.send(date_attr)
next unless d
cal_hash[d.strftime("%Y-%m-%d")] ||= []
cal_hash[d.strftime("%Y-%m-%d")] << n
if hours
# hours should contain 0 and should be sorted
# [0,12] ==> 0 => dates from 00:00 to 11:59
# 12 => dates from 12:00 to 23:59

(list || []).each do |n|
d = n.send(date_attr)
next unless d
hours.reverse_each do |h|
if d.hour >= h
h_list = cal_hash[d.strftime("%Y-%m-%d #{h}")] ||= []
h_list << n
break
end
end
end

else
(list || []).each do |n|
d = n.send(date_attr)
next unless d
cal_hash[d.strftime("%Y-%m-%d")] ||= []
cal_hash[d.strftime("%Y-%m-%d")] << n
end
end

start_date.step(end_date,7) do |week|
Expand Down
34 changes: 20 additions & 14 deletions app/models/relation_proxy.rb
Expand Up @@ -122,7 +122,6 @@ def other_icon
end

# set

def other_id=(v)
attributes_to_update[:id] = v.kind_of?(Array) ? v.uniq.compact.map {|v| v.to_i} : (v.blank? ? nil : v.to_i)
end
Expand Down Expand Up @@ -215,13 +214,14 @@ def attributes_to_update_valid?
add_link_ids = @attributes_to_update[:id]

# find all current links
# TODO: this could be optimzed (avoid loading all links...)
other_links.each do |link|
obj_id = link[other_side]
if add_link_ids.include?(obj_id)
# ignore existing links
if add_link_ids.include?(obj_id) && (@attributes_to_update[:date].nil? || @attributes_to_update[:date] == link[:date])
# ignore existing link
add_link_ids.delete(obj_id)
else
# remove unused links
# remove unused links / link to replace
@del_links << link
end
end
Expand All @@ -240,19 +240,25 @@ def attributes_to_update_valid?
else
# ..-to-many
# add/update a link
if other_ids.include?(@attributes_to_update[:id])
# update
if (@attributes_to_update.keys & LINK_ATTRIBUTES) != []
other_links.each do |link|
if link[other_side] == @attributes_to_update[:id]
@update_links << changed_link(link, @attributes_to_update)
break
# TODO: optimize to avoid loading all links...
if @attributes_to_update[:id].blank? && @attributes_to_update[:date]
# delete
@del_links = other_links.select {|l| @attributes_to_update[:date] == l[:date]}
else
links = other_links.select {|l| l[other_side] == @attributes_to_update[:id] && (@attributes_to_update[:date].nil? || @attributes_to_update[:date] == l[:date])}
if links != []
# update
if (@attributes_to_update.keys & LINK_ATTRIBUTES) != []
links.each do |link|
if link[other_side] == @attributes_to_update[:id]
@update_links << changed_link(link, @attributes_to_update)
end
end
end
else
# add
@add_links << @attributes_to_update
end
else
# add
@add_links << @attributes_to_update
end
end
end
Expand Down
72 changes: 56 additions & 16 deletions lib/parser/lib/rules/zena.rb
Expand Up @@ -374,6 +374,7 @@ def r_set
return '' unless @context[:set]
if @params[:value]
out "<% set_#{var_name} = #{@params[:value].inspect} -%>"
# TODO: isn't @context[:vars] = @params[:value].inspect missing here ?
elsif @params[:eval]
return unless eval_string = parse_eval_parameter(@params[:eval])
out "<% set_#{var_name} = #{eval_string} -%>"
Expand Down Expand Up @@ -494,11 +495,31 @@ def r_swap
else
return parser_error("missing 'block' in same parent")
end
states = ((@params[:states] || 'todo, done') + ' ').split(',').map(&:strip)

query_params = "node[#{@params[:attr]}]=\#{#{states.inspect}[ ((#{states.inspect}.index(#{node_attribute(@params[:attr])}.to_s) || 0)+1) % #{states.size}]}#{upd_both}"

if role = @params[:role]
if @context[:in_calendar]
# in calendar context, use date
date_param = "&node[link][#{role}][date]=\#{ defined?(#{current_date}) ? #{current_date}.strftime('%Y-%m-%d+%H') : params['node']['link'][#{role.inspect}]['date']}"
else
date_param = ''
end
# swap on (assign):
# 'link' => {'assigned_note' => {'other_id' => 33, 'date' => '2009-7-17 15:55'}}
# swap off (remove):
# 'link' => {'assigned_note' => {'other_id' => nil, 'date' => '2009-7-17 15:55'}}

# TODO: add support to link to any node, not just 'start' node...
# How to know if the link exists or not ?
# in calendar = known from context
# in reply = known from @node's relation proxy ...
#
# All this is too complicated right now. Implementing "r_assign_calendar" until we find a solution to all this mess.
query_params = "node[link][#{role}][other_id]=\#{params[:s]}#{date_param}"
else
states = ((@params[:states] || 'todo, done') + ' ').split(',').map(&:strip)

query_params = "node[#{@params[:attr]}]=\#{#{states.inspect}[ ((#{states.inspect}.index(#{node_attribute(@params[:attr])}.to_s) || 0)+1) % #{states.size}]}#{upd_both}"
end
out link_to_update(block, :query_params => query_params, :method => :put, :html_params => get_html_params(@params, :link))
end

Expand Down Expand Up @@ -1842,7 +1863,7 @@ def pagination_links
@context[:vars] ||= []
@context[:vars] << "#{pagination_key}_page"
if @blocks == [] || (@blocks.size == 1 && !@blocks.first.kind_of?(String) && @blocks.first.method == 'else')
# add a default blocks
# add a default block
if tag = @params[:tag]
open_tag = "<#{tag}>"
close_tag = "</#{tag}>"
Expand All @@ -1867,8 +1888,7 @@ def pagination_links
out "<% page_numbers(set_#{pagination_key}, set_#{pagination_key}_count, #{(@params[:join] || ' ').inspect}, #{@params[:page_count] ? @params[:page_count].to_i : 'nil'}) do |set_#{pagination_key}_page, #{pagination_key}_page_join| %>"
out "<%= #{pagination_key}_page_join %>"
out "<% if set_#{pagination_key}_page != set_#{pagination_key} -%>"
out expand_with
out expand_with(:in_if => true, :only => ['else', 'elsif'])
out expand_with(:in_if => true)
out "<% end; end -%>"
else
parser_error("unkown 'page' option #{@params[:page].inspect} should be ('previous', 'next' or 'list')")
Expand Down Expand Up @@ -1927,6 +1947,7 @@ def r_calendar
@blocks += [make(:void, :method=>'void', :text=>"<r:else do='[current_date]' format='%d'/>")]
remove_instance_variable(:@all_descendants)
end

@html_tag_done = false
@html_tag_params[:id] = erb_dom_id
@html_tag_params[:class] ||= "#{size}cal"
Expand All @@ -1948,6 +1969,23 @@ def r_calendar
finder, klass = build_finder_for(:all, finder, @params, [@date_scope])
return unless finder
return parser_error("invalid class (#{klass})") unless klass.ancestors.include?(Node)

if hours = @params[:split_hours]
hours = hours.split(',').map{|l| l.to_i}
hours << 0
hours = hours.uniq.sort
# I feel all this would be much better if we could use "each_group" but then how do we access hours ?
week_code = "<% week.step(week+6,1) do |day_#{list_var}| -%>
<td<%= cal_class(day_#{list_var},#{current_date}) %>><% #{hours.inspect}.each do |set_hour|; cal_#{list_var} = Time.utc(day_#{list_var}.year,day_#{list_var}.month,day_#{list_var}.day,set_hour); if #{list_var} = nodes_#{list_var}[cal_#{list_var}.strftime('%Y-%m-%d %H')] -%>#{expand_with(:in_if => true, :list => list_var, :date => "day_#{list_var}", :saved_template => nil, :dom_prefix => nil, :date => "cal_#{list_var}", :in_calendar => true)}<% end; end -%></td>
<% end -%>"
(@context[:vars] ||= []) << "hour"
else
hours = nil
week_code = "<% week.step(week+6,1) do |day_#{list_var}| -%>
<td<%= cal_class(day_#{list_var},#{current_date}) %>><% cal_#{list_var} = Time.utc(day_#{list_var}.year,day_#{list_var}.month,day_#{list_var}.day); if #{list_var} = nodes_#{list_var}[cal_#{list_var}.strftime('%Y-%m-%d')] -%>#{expand_with(:in_if => true, :list => list_var, :date => "cal_#{list_var}", :saved_template => nil, :dom_prefix => nil, :in_calendar => true)}<% end -%></td>
<% end -%>"
end

res = <<-END_TXT
<h3 class='title'>
<span><%= link_to_remote(#{_('img_prev_page').inspect}, :url => #{base_class.to_s.underscore}_path(#{node_id}) + \"/zafu?t_url=#{CGI.escape(template_url)}&dom_id=#{dom_id}&date=#{prev_date}\", :method => :get) %></span>
Expand All @@ -1957,15 +1995,14 @@ def r_calendar
<table cellspacing='0' class='#{size}cal'>
<tr class='head'><%= cal_day_names(#{size.inspect}) %></tr>
<% start_date, end_date = cal_start_end(#{current_date}, #{type.inspect}) -%>
<% cal_weeks(#{ref_date.to_sym.inspect}, #{finder}, start_date, end_date) do |week, cal_#{list_var}| -%>
<% cal_weeks(#{ref_date.to_sym.inspect}, #{finder}, start_date, end_date, #{hours.inspect}) do |week, nodes_#{list_var}| -%>
<tr class='body'>
<% week.step(week+6,1) do |day_#{list_var}|; #{list_var} = cal_#{list_var}[day_#{list_var}.strftime('%Y-%m-%d')] -%>
<td<%= cal_class(day_#{list_var},#{current_date}) %>><% if #{list_var} -%>#{expand_with(:in_if => true, :list => list_var, :date => "day_#{list_var}", :saved_template => nil, :dom_prefix => nil)}<% end -%></td>
<% end -%>
#{week_code}
</tr>
<% end -%>
</table>
END_TXT
@var = node # this is just to trick erb_dom_id until we find a better solution...
render_html_tag(res)
else
fld = @params[:date] || 'event_at'
Expand Down Expand Up @@ -2448,9 +2485,8 @@ def do_list(list_finder, query = nil, opts={})

# INLINE ==========
# 'r_add' needs the form when rendering. Send with :form.
res = expand_with(:list=>list_var, :form=>form_block, :publish_after_save => publish_after_save, :ignore => ['form'], :klass => klass, :in_if => true)
out render_html_tag(res)
# what about 'else' ?
out render_html_tag(expand_with(:list=>list_var, :in_if => false, :form=>form_block, :publish_after_save => publish_after_save, :ignore => ['form'], :klass => klass))
out expand_with(:in_if=>true, :only=>['elsif', 'else'], :html_tag => @html_tag, :html_tag_params => @html_tag_params)
out "<% end -%>"

# SAVED TEMPLATE ========
Expand Down Expand Up @@ -2483,8 +2519,8 @@ def do_list(list_finder, query = nil, opts={})
@context[:vars] << "#{pagination_key}"
end

res = expand_with(:list=>list_var, :in_if => true)
out render_html_tag(res)
out render_html_tag(expand_with(:list=>list_var, :in_if => false))
out expand_with(:in_if=>true, :only=>['elsif', 'else'], :html_tag => @html_tag, :html_tag_params => @html_tag_params)
out "<% end -%>"
end
end
Expand Down Expand Up @@ -2521,6 +2557,8 @@ def dom_id(suffix='')
end
if (method == 'each' || method == 'each_group') && !@context[:make_form]
"#{res}_\#{#{var}.zip}"
elsif @context && @context[:in_calendar]
"#{res}_\#{#{current_date}.to_i}"
elsif method == 'unlink' || method == 'edit'
target = nil
parent = self.parent
Expand Down Expand Up @@ -2548,6 +2586,8 @@ def erb_dom_id(suffix='')
"#{res}_<%= #{var}.zip %>"
elsif method == 'draggable'
"#{res}_<%= #{node}.zip %>"
elsif @context && @context[:in_calendar]
"#{res}_<%= #{current_date}.to_i %>"
elsif method == 'unlink'
target = nil
parent = self.parent
Expand Down Expand Up @@ -2730,7 +2770,7 @@ def get_test_condition(node = self.node, params = @params)
nil
end
when :in
if @context["in_#{value}".to_sym] || ancestors.include?(value)
if @context["in_#{value}".to_sym] # FIXME: || ancestors.include?(value) ==> ancestors is a list of zafu tags, not a list of names !
'true'
else
'false'
Expand Down
20 changes: 20 additions & 0 deletions test/fixtures/files/Node-test.zafu
Expand Up @@ -71,6 +71,26 @@ This filter updates the "distant filter block test"
<h3>tiny calendar</h3>
<div do='calendar' find='notes in site' size='tiny'/>

<h3>assign calendar</h3>
<p>Assigns the main node to 'zena' project with given date</p>
<r:root>
<div do='calendar' select='added_notes' date='l_date'>
<span do='[current_date]' format='%d'/>
initial notes here
<div class='orange' do='block' green_if='link_id'>
<span do='swap' role='added_note' publish='true' />
</div>

<r:else>
<span do='[current_date]' format='%d'/>
no notes yet
<div class='orange' do='block' green_if='link_id'>
<span do='swap' role='added_note' publish='true' />
</div>
</r:else>
</div>
</r:root>

<div id='edit' do='block'>
<h3>edit block test</h3>
<r:text/>
Expand Down
41 changes: 41 additions & 0 deletions test/helpers/application_helper_test.rb
Expand Up @@ -164,6 +164,47 @@ def test_uses_calendar_without_lang
assert_match %r{/calendar/lang/calendar-en-utf8.js}, res
end

def test_cal_weeks
login(:tiger)
weeks = []
event_hash = nil
assert_equal "0", _('week_start_day') # week starts on Sunday
start_date, end_date = cal_start_end(Time.utc(2006,3,18), :month)
assert_equal Date.civil(2006,02,26), start_date
assert_equal Date.civil(2006,04,01), end_date
secure!(Note) { Note.create(:parent_id => nodes_id(:zena), :name => 'foobar', :event_at => Time.utc(2006,03,20))}
nodes = secure!(Note) { Note.find(:all, :conditions => ["nodes.event_at >= ? AND nodes.event_at <= ?", start_date, end_date])}
res = cal_weeks('event_at', nodes, start_date, end_date) do |week, hash|
weeks << week
event_hash = hash
end
assert_equal ["2006-03-18", "2006-03-20"], event_hash.keys
assert_equal ['opening'], event_hash["2006-03-18"].map{|r| r.name}
assert_equal ['foobar'], event_hash["2006-03-20"].map{|r| r.name}
end

def test_cal_weeks_hours
login(:tiger)
weeks = []
event_hash = nil
hours = [0,12]
assert_equal "0", _('week_start_day') # week starts on Sunday
start_date, end_date = cal_start_end(Time.utc(2006,3,18), :month)
assert_equal Date.civil(2006,02,26), start_date
assert_equal Date.civil(2006,04,01), end_date
secure!(Note) { Note.create(:parent_id => nodes_id(:zena), :name => 'morning', :event_at => Time.utc(2006,03,20,9))}
secure!(Note) { Note.create(:parent_id => nodes_id(:zena), :name => 'afternoon', :event_at => Time.utc(2006,03,20,14))}
nodes = secure!(Note) { Note.find(:all, :conditions => ["nodes.event_at >= ? AND nodes.event_at <= ?", start_date, end_date])}
res = cal_weeks('event_at', nodes, start_date, end_date, hours) do |week, hash|
weeks << week
event_hash = hash
end
assert_equal ["2006-03-18 12", "2006-03-20 0", "2006-03-20 12"], event_hash.keys.sort
assert_equal ['opening'], event_hash["2006-03-18 12"].map{|r| r.name}
assert_equal ['morning'], event_hash["2006-03-20 0"].map{|r| r.name}
assert_equal ['afternoon'], event_hash["2006-03-20 12"].map{|r| r.name}
end

def test_select_id
@node = secure!(Node) { nodes(:status) }
select = select_id('node', :parent_id, :class=>'Project')
Expand Down
16 changes: 16 additions & 0 deletions test/helpers/zena_parser/basic.yml
Expand Up @@ -443,6 +443,15 @@ calendar_l_date:
src: "<div do='calendar' select='added_notes' date='l_date' />"
res: "/<td class='ref'><span>17</span><ul><li><a href='/oo/projects/cleanWater/post27.html'>opening</a></li></ul></td>/"

calendar_hours:
context:
ref_date: "2009-7-17"
node: 'zena'
# I do not like the way we do this, the 'else' thing is not helping. Maybe we need some extra zafu tags because it's
# messy: we have 3 lists (days, hours, nodes) ...
src: "<div do='calendar' select='added_notes' date='l_date' split_hours='12'><r:if test='hour eq 0' do='[current_date]' format='%d'/><div do='void' set_class='hour_[hour]' do='each' do='[name]' join=', '/><r:else><r:if test='hour eq 0' do='[current_date]' format='%d'/><div do='void' set_class='hour_[hour]'></div></r:else></div>"
res: "/<td class='ref'>17<div class='hour_0'></div><div class='hour_12'>opening</div></td>/"

flash_messages_both:
src: "<r:flash_messages/>"
tem: "/id.*messages.*notice.*flash.*notice.*error.*flash.*error/"
Expand Down Expand Up @@ -505,6 +514,13 @@ each_alternate_class_ajax:
src: "<ol do='pages'><li do='each' alt_class='blue' do='[name]'/><li do='add'/></ol>"
res: "/<li>status<\/li><li class=\"blue\">track/"

each_else:
context:
node: 'opening'
src: "<div do='pages'>has pages (<r:each do='[name]' join=', '/>)<r:else>no pages</r:else></div>"
tem: "/-%><div>has pages \(<% list1.each do \|var1\| -%><%= var1.name %><% end -%>\)</div><% elsif true -%><div>no pages</div><% end -%>/"
res: "<div>no pages</div>"

case_when:
src: "<r:case><r:when kind_of='Document'>this is a document</r:when><r:when klass='Page'>Page</r:when><r:when status='pub'>Pub</r:when>"
tem: "<% if false -%><% elsif @node.vkind_of?(\"Document\") -%>this is a document<% elsif @node.klass == \"Page\" -%>Page<% elsif @node.version.status == 50 -%>Pub<% end -%>"
Expand Down
2 changes: 1 addition & 1 deletion test/sites/zena/nodes.yml
Expand Up @@ -140,7 +140,7 @@ opening:
parent: cleanWater
ref_lang: fr
log_at: 2006-03-15
event_at: 2006-03-18
event_at: 2006-03-18 15:00

bananas:
zip: 28
Expand Down

0 comments on commit b51211f

Please sign in to comment.