<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>app/views/nodes/_table.rhtml</filename>
    </added>
    <added>
      <filename>public/javascripts/tablekit.js</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -3,6 +3,12 @@ javascript date selection
     Mihai Bazon
     http://dynarch.com
     adapted to Rails by Gaspard Bucher
+
+tablekit table editor
+---------------------
+    Andrew Tetlaw &amp; Millstream Web Software
+    http://www.millstream.com.au/view/code/tablekit/
+    add/remove columns and drag&amp;drop support added by Gaspard Bucher
     
 soft icons
 ----------
@@ -11,8 +17,8 @@ soft icons
     
 xspf mp3 player
 ---------------
-	Fabricio Zuardi
-	http://musicplayer.sourceforge.net/
+    Fabricio Zuardi
+    http://musicplayer.sourceforge.net/
 	
 upload progress bar (sample application demo)
 -------------------</diff>
      <filename>CREDITS</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,6 @@
 require 'digest/sha1'
 require 'tempfile'
+require 'json'
 
 # Methods added to this helper will be available to all templates in the application.
 module ApplicationHelper
@@ -544,6 +545,40 @@ latex_template = %q{
     
     render_to_string( :partial=&gt;'nodes/gallery', :locals=&gt;{:gallery=&gt;images} )
   end
+  
+  # Create a table from an attribute
+  def make_table(opts)
+    style, node, attribute, title, images, table = opts[:style], opts[:node], opts[:attribute], opts[:title], opts[:images], opts[:table]
+    case style.sub('.', '')
+    when &quot;&gt;&quot;
+      prefix = &quot;&lt;div class='img_right'&gt;&quot;
+      suffix = &quot;&lt;/div&gt;&quot;
+    when &quot;&lt;&quot;
+      prefix = &quot;&lt;div class='img_left'&gt;&quot;
+      suffix = &quot;&lt;/div&gt;&quot;
+    when &quot;=&quot;
+      prefix = &quot;&lt;div class='img_center'&gt;&quot;
+      suffix = &quot;&lt;/div&gt;&quot;
+    else
+      prefix = suffix = &quot;&quot;
+    end
+    
+    unless table
+      # get attribute content
+      attribute = &quot;d_#{attribute}&quot; unless ['v_', 'd_'].include?(attribute[0..1])
+      text = Node.zafu_attribute(node, attribute)
+      if text.blank?
+        table = [{&quot;type&quot;=&gt;&quot;table&quot;},[[&quot;title&quot;],[&quot;value&quot;]]]
+      else
+        table = JSON.parse(text)
+      end
+    end  
+    raise JSON::ParserError unless table.kind_of?(Array) &amp;&amp; table.size == 2 &amp;&amp; table[0].kind_of?(Hash) &amp;&amp; table[0]['type'] == 'table' &amp;&amp; table[1].kind_of?(Array)
+    
+    prefix + render_to_string( :partial=&gt;'nodes/table', :locals=&gt;{:table=&gt;table}) + suffix
+  rescue JSON::ParserError
+    &quot;&lt;span class='unknownLink'&gt;could not build table from text&lt;/span&gt;&quot;
+  end
 
   def list_nodes(ids=[], opts={})
     style = opts[:style] || ''</diff>
      <filename>app/helpers/application_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -65,7 +65,7 @@ module Zazen
     
     def scan
       #puts &quot;SCAN:[#{@text}]&quot;
-      if @text =~ /\A([^!&quot;&lt;\n\[]*)/m
+      if @text =~ /\A([^\|!&quot;&lt;\n\[]*)/m
         flush $&amp;
         if @text[0..0] == '!'
           scan_exclam
@@ -73,6 +73,8 @@ module Zazen
           scan_quote
         elsif @text[0..0] == '['
           scan_bracket
+        elsif @text[0..0] == '|'
+          scan_pipe
         elsif @text[0..4] == '&lt;code'
           # FIXME: implement &lt;code..&gt; and @@ instead of &quot;extract&quot;
           flush
@@ -314,6 +316,53 @@ module Zazen
       end
     end
     
+    def scan_pipe
+      #puts &quot;PIPE:[#{@text}]&quot;
+      if @text =~ /\A\|([&lt;=&gt;]\.|)([0-9]+\.|)([a-zA-Z_]+)(\/([^\|]*)|)\|/m
+        # table |&lt;.34.shopping_list/blah blah|
+        # table |shopping_list|
+        #puts &quot;TABLE:#{$~.to_a.inspect}&quot;
+        eat $&amp;
+        style, id, attribute, title_opts, title = $1, $2, $3, $4, $5
+        id = id[0..-2] if id != ''
+        if @translate_ids
+          if @translate_ids != :zip
+            node = @helper.find_node_by_pseudo(id, @context[:node])
+            id = node.pseudo_id(@context[:node], @translate_ids) if node
+          end
+          store &quot;|#{style}#{id}.#{attribute}#{title}|&quot;
+        else
+          node = id == '' ? @context[:node] : @helper.find_node_by_pseudo(id, @context[:node])
+          store @helper.make_table(:style=&gt;style, :node=&gt;node, :attribute=&gt;attribute, :title=&gt;title)
+        end
+      elsif @text =~ /\A\|([&lt;=&gt;]\.|)(#{PSEUDO_ID_REGEXP})\.([a-zA-Z_]+)(\/([^\|]*)|)\|/m
+        # table |&lt;.:art++.shopping_list/blah blah|
+        # table |shopping_list|
+        #puts &quot;TABLE SHORTCUT:#{$~.to_a.inspect}&quot;
+        eat $&amp;
+        text = $&amp;
+        style, id, attribute, title_opts, title = $1, $2, $3, $4, $5
+        if node = @helper.find_node_by_pseudo(id, @context[:node])
+          if @translate_ids
+            # replace shortcut
+            store &quot;|#{style}#{node.pseudo_id(@context[:node], @translate_ids || :zip)}.#{attribute}#{title}|&quot;
+          else
+            # write table
+            store @helper.make_table(:style=&gt;style, :node=&gt;node, :attribute=&gt;attribute, :title=&gt;title)
+          end
+        elsif @translate_ids
+          # node not found, ignore
+          store text
+        else
+          # node not found
+          store &quot;[#{id} not found]&quot;
+        end
+      else
+        #puts &quot;EAT:[#{$&amp;}]&quot;
+        # eat marker and continue scan
+        flush @text[0..0]
+      end
+    end
     
     def extract_code(fulltext)
       @escaped_code = []</diff>
      <filename>lib/parser/lib/rules/zazen.rb</filename>
    </modified>
    <modified>
      <diff>@@ -116,6 +116,26 @@ image_with_http_link:
 image_with_ref:
   src: &quot;!http://www.example.org/images/test.jpg!&quot;
   res: &quot;&lt;p&gt;&lt;img src=\&quot;http://www.example.org/images/test.jpg\&quot; alt=\&quot;\&quot; /&gt;&lt;/p&gt;&quot;
+  
+table:
+  src: &quot;|shopping_list|&quot;
+  res: &quot;&lt;p&gt;[make_table attribute:|shopping_list| style:||]&lt;/p&gt;&quot;
+  
+table_title:
+  src: &quot;|shopping_list/A list of frequent problems|&quot;
+  res: &quot;&lt;p&gt;[make_table attribute:|shopping_list| style:|| title:|A list of frequent problems|]&lt;/p&gt;&quot;
+  
+table_id:
+  src: &quot;|34.shopping_list|&quot;
+  res: &quot;&lt;p&gt;[make_table attribute:|shopping_list| node:|34| style:||]&lt;/p&gt;&quot;
+  
+table_pseudo_id:
+  src: &quot;|:art+.shopping_list|&quot;
+  res: &quot;&lt;p&gt;[make_table attribute:|shopping_list| node:|:art+| style:||]&lt;/p&gt;&quot;
+  
+table_pseudo_path:
+  src: &quot;|(../some/path).shopping_list|&quot;
+  res: &quot;&lt;p&gt;[make_table attribute:|shopping_list| node:|(../some/path)| style:||]&lt;/p&gt;&quot;
 
 link_with_title:
   src: '&quot;this is a title&quot;:23'</diff>
      <filename>lib/parser/test/parser/zazen.yml</filename>
    </modified>
    <modified>
      <diff>@@ -15,7 +15,7 @@ end
 
 class ParserModule::DummyHelper
   def find_node_by_pseudo(*args)
-    nil
+    args[0]
   end
 end
 
@@ -74,6 +74,12 @@ module Zafu
   end
 end
 
+class String
+  def pseudo_id(*args)
+    self
+  end
+end
+
 class ParserTest &lt; Test::Unit::TestCase
   yaml_test :zafu =&gt; {}, :zafu_asset =&gt; {}, :zafu_insight =&gt; {}, :zazen =&gt; {} #, :latex =&gt; {:module =&gt; :zazen, :output =&gt; 'latex'}
   @@test_parsers = {}</diff>
      <filename>lib/parser/test/parser_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -175,5 +175,33 @@ class ZazenHelperTest &lt; ZenaTestHelper
     assert_equal &quot;This \&quot;is\&quot;:33 \&quot;a\&quot;:#{nodes_zip(:wiki)} !#{nodes_zip(:bird_jpg)}! \&quot;link\&quot;:#{nodes_zip(:lion)}.&quot;,
            zazen('This &quot;is&quot;:(collections/art) &quot;a&quot;:(/projects/wiki) !(/projects/wiki/bird)! &quot;link&quot;:(people/lion).', :translate_ids =&gt; :zip, :node =&gt; zena)
   end
+  
+  def test_table_asset
+    login(:tiger)
+    @node = secure!(Node) { nodes(:status) }
+    assert_match %r{&lt;table.*&lt;th.*&lt;td&gt;title&lt;/td&gt;.*&lt;tr.*value}m, zazen(&quot;This is a table test:\n\n|shopping_list|&quot;)
+    assert_match %r{&lt;table&gt;
+  &lt;th&gt;
+    &lt;td&gt;problem&lt;/td&gt;
+    &lt;td&gt;solution&lt;/td&gt;
+    &lt;td&gt;cost&lt;/td&gt;
+  &lt;/th&gt;
+  &lt;tr&gt;
+    &lt;td&gt;dead hard drive&lt;/td&gt;
+    &lt;td&gt;buy a new one&lt;/td&gt;
+    &lt;td&gt;150.0&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;hurting hands&lt;/td&gt;
+    &lt;td&gt;take a rest&lt;/td&gt;
+    &lt;td&gt;0.0&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;buggy display&lt;/td&gt;
+    &lt;td&gt;wait for a bug fix&lt;/td&gt;
+    &lt;td&gt;0.0&lt;/td&gt;
+  &lt;/tr&gt;
+&lt;/table&gt;}m, zazen(&quot;This is a table test:\n\n|problems|&quot;)
+  end
 
 end
\ No newline at end of file</diff>
      <filename>test/helpers/zazen_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -26,7 +26,18 @@ status_fr_assigned:
   key:             assigned
   value:           gaspard
 
-cleanWater_en_d_tz:
+cleanWater_en_tz:
   owner:           cleanWater_en
   key:             tz
-  value:           Asia/Jakarta
\ No newline at end of file
+  value:           Asia/Jakarta
+
+status_en_problems:
+  owner:           status_en
+  key:             problems
+  value: |
+    [{&quot;type&quot;:&quot;table&quot;},
+     [[&quot;problem&quot;,&quot;solution&quot;,&quot;cost&quot;],
+      [&quot;dead hard drive&quot;, &quot;buy a new one&quot;, 150.00],
+      [&quot;hurting hands&quot;, &quot;take a rest&quot;, 0.0],
+      [&quot;buggy display&quot;, &quot;wait for a bug fix&quot;, 0.0]
+     ]]
\ No newline at end of file</diff>
      <filename>test/sites/zena/dyn_attributes.yml</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>b7c65e9b84c1852e107f77d3ad76bc240ab4ad53</id>
    </parent>
  </parents>
  <author>
    <name>Gaspard Bucher</name>
    <email>gaspard@teti.ch</email>
  </author>
  <url>http://github.com/zena/zena/commit/a60e834ec4e4fa906e26309fc3d382ec27be0df6</url>
  <id>a60e834ec4e4fa906e26309fc3d382ec27be0df6</id>
  <committed-date>2008-10-23T04:41:13-07:00</committed-date>
  <authored-date>2008-10-23T04:20:34-07:00</authored-date>
  <message>Started to work on new table helper for zazen. Refs [#228]</message>
  <tree>e08c66fc36a9bd05eb8384b3056728455d64bfd4</tree>
  <committer>
    <name>Gaspard Bucher</name>
    <email>gaspard@teti.ch</email>
  </committer>
</commit>
