zena 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. data/History.txt +38 -1
  2. data/app/controllers/documents_controller.rb +7 -5
  3. data/app/controllers/nodes_controller.rb +47 -6
  4. data/app/controllers/user_sessions_controller.rb +12 -3
  5. data/app/controllers/virtual_classes_controller.rb +8 -2
  6. data/app/models/acl.rb +5 -2
  7. data/app/models/cached_page.rb +5 -5
  8. data/app/models/column.rb +27 -4
  9. data/app/models/group.rb +1 -1
  10. data/app/models/node.rb +106 -24
  11. data/app/models/note.rb +2 -1
  12. data/app/models/relation.rb +9 -4
  13. data/app/models/relation_proxy.rb +2 -2
  14. data/app/models/role.rb +12 -5
  15. data/app/models/site.rb +10 -9
  16. data/app/models/skin.rb +8 -0
  17. data/app/models/string_hash.rb +65 -0
  18. data/app/models/text_document.rb +1 -1
  19. data/app/models/user.rb +2 -0
  20. data/app/models/virtual_class.rb +43 -10
  21. data/app/views/comments/create.rjs +1 -32
  22. data/app/views/comments/edit.rjs +1 -1
  23. data/app/views/comments/update.rjs +1 -1
  24. data/app/views/documents/show.rhtml +1 -1
  25. data/app/views/groups/_form.rhtml +7 -0
  26. data/app/views/groups/_li.rhtml +1 -1
  27. data/app/views/nodes/500.html +2 -1
  28. data/app/views/nodes/destroy.rjs +2 -0
  29. data/app/views/sites/jobs.erb +2 -3
  30. data/app/views/templates/document_create_tabs/_file.rhtml +1 -1
  31. data/app/views/templates/document_create_tabs/_import.rhtml +4 -1
  32. data/app/views/templates/document_create_tabs/_template.rhtml +3 -0
  33. data/app/views/templates/document_create_tabs/_text_document.rhtml +3 -0
  34. data/app/views/versions/custom_tab.rhtml +1 -1
  35. data/app/views/versions/edit.rhtml +1 -1
  36. data/bricks/acls/lib/bricks/acls.rb +3 -3
  37. data/bricks/acls/zena/test/unit/acl_test.rb +15 -0
  38. data/bricks/fs_skin/lib/bricks/fs_skin.rb +190 -0
  39. data/bricks/fs_skin/zena/init.rb +1 -0
  40. data/bricks/fs_skin/zena/migrate/20110702010330_add_fs_skin_to_idx_templates.rb +12 -0
  41. data/bricks/{static → fs_skin}/zena/skins/blog/Image-edit.zafu +0 -0
  42. data/bricks/{static → fs_skin}/zena/skins/blog/Image.zafu +0 -0
  43. data/bricks/{static → fs_skin}/zena/skins/blog/Node-+index.zafu +0 -0
  44. data/bricks/{static → fs_skin}/zena/skins/blog/Node-+notFound.zafu +0 -0
  45. data/bricks/{static → fs_skin}/zena/skins/blog/Node-+search.zafu +0 -0
  46. data/bricks/{static → fs_skin}/zena/skins/blog/Node.zafu +1 -1
  47. data/bricks/{static → fs_skin}/zena/skins/blog/Post.zafu +0 -0
  48. data/bricks/{static → fs_skin}/zena/skins/blog/Project--kml.zafu +0 -0
  49. data/bricks/{static → fs_skin}/zena/skins/blog/Project.zafu +0 -0
  50. data/bricks/{static → fs_skin}/zena/skins/blog/comments.zafu +0 -0
  51. data/bricks/{static → fs_skin}/zena/skins/blog/dict.yml +0 -0
  52. data/bricks/{static → fs_skin}/zena/skins/blog/img/dateBg.jpg +0 -0
  53. data/bricks/{static → fs_skin}/zena/skins/blog/img/header.png +0 -0
  54. data/bricks/{static → fs_skin}/zena/skins/blog/img/mapPin.png +0 -0
  55. data/bricks/{static → fs_skin}/zena/skins/blog/img/menu.gif +0 -0
  56. data/bricks/{static → fs_skin}/zena/skins/blog/img/menuover.gif +0 -0
  57. data/bricks/{static → fs_skin}/zena/skins/blog/img/style.css +0 -0
  58. data/bricks/fs_skin/zena/tasks.rb +26 -0
  59. data/bricks/{static/zena/test/integration/static_integration_test.rb → fs_skin/zena/test/integration/fs_skin_integration_test.rb} +6 -6
  60. data/bricks/fs_skin/zena/test/unit/fs_skin_test.rb +33 -0
  61. data/bricks/grid/lib/bricks/grid.rb +4 -3
  62. data/bricks/tags/lib/bricks/tags.rb +1 -7
  63. data/bricks/zena/zena/migrate/20120605091558_add_ssl_login_to_site.rb +7 -0
  64. data/bricks/zena/zena/migrate/20120630123551_add_auto_publish_to_group.rb +9 -0
  65. data/config/bricks.yml +3 -3
  66. data/config/gems.yml +2 -3
  67. data/lib/tasks/zena.rake +7 -3
  68. data/lib/zafu.rb +7 -0
  69. data/lib/zafu/all.rb +21 -0
  70. data/lib/zafu/compiler.rb +7 -0
  71. data/lib/zafu/controller_methods.rb +58 -0
  72. data/lib/zafu/handler.rb +57 -0
  73. data/lib/zafu/info.rb +4 -0
  74. data/lib/zafu/markup.rb +309 -0
  75. data/lib/zafu/mock_helper.rb +42 -0
  76. data/lib/zafu/node_context.rb +203 -0
  77. data/lib/zafu/ordered_hash.rb +53 -0
  78. data/lib/zafu/parser.rb +676 -0
  79. data/lib/zafu/parsing_rules.rb +382 -0
  80. data/lib/zafu/process/ajax.rb +530 -0
  81. data/lib/zafu/process/conditional.rb +92 -0
  82. data/lib/zafu/process/context.rb +186 -0
  83. data/lib/zafu/process/forms.rb +143 -0
  84. data/lib/zafu/process/html.rb +186 -0
  85. data/lib/zafu/process/ruby_less_processing.rb +321 -0
  86. data/lib/zafu/security.rb +15 -0
  87. data/lib/zafu/template.rb +25 -0
  88. data/lib/zafu/test_helper.rb +19 -0
  89. data/lib/zafu/view_methods.rb +6 -0
  90. data/lib/zena.rb +1 -1
  91. data/lib/zena/acts/enrollable.rb +1 -1
  92. data/lib/zena/app.rb +4 -17
  93. data/lib/zena/console.rb +18 -1
  94. data/lib/zena/core_ext/file_utils.rb +13 -1
  95. data/lib/zena/core_ext/fixnum.rb +4 -0
  96. data/lib/zena/core_ext/float.rb +7 -0
  97. data/lib/zena/deploy.rb +4 -2
  98. data/lib/zena/deploy/app_init.rhtml +2 -1
  99. data/lib/zena/deploy/database.rhtml +1 -1
  100. data/lib/zena/info.rb +1 -1
  101. data/lib/zena/parser/zazen_rules.rb +4 -4
  102. data/lib/zena/routes.rb +1 -1
  103. data/lib/zena/test_controller.rb +1 -1
  104. data/lib/zena/use.rb +14 -1
  105. data/lib/zena/use/action.rb +4 -2
  106. data/lib/zena/use/ajax.rb +86 -38
  107. data/lib/zena/use/authlogic.rb +16 -1
  108. data/lib/zena/use/calendar.rb +37 -17
  109. data/lib/zena/use/conditional.rb +2 -2
  110. data/lib/zena/use/context.rb +30 -9
  111. data/lib/zena/use/dates.rb +39 -3
  112. data/lib/zena/use/display.rb +6 -19
  113. data/lib/zena/use/forms.rb +100 -79
  114. data/lib/zena/use/i18n.rb +40 -16
  115. data/lib/zena/use/query_builder.rb +0 -6
  116. data/lib/zena/use/query_node.rb +17 -4
  117. data/lib/zena/use/relations.rb +1 -3
  118. data/lib/zena/use/rendering.rb +10 -8
  119. data/lib/zena/use/scope_index.rb +5 -1
  120. data/lib/zena/use/search.rb +2 -1
  121. data/lib/zena/use/urls.rb +82 -77
  122. data/lib/zena/use/workflow.rb +12 -4
  123. data/lib/zena/use/zafu_safe_definitions.rb +37 -9
  124. data/lib/zena/use/zafu_templates.rb +49 -20
  125. data/lib/zena/use/zazen.rb +6 -2
  126. data/locale/it/LC_MESSAGES/zena.mo +0 -0
  127. data/locale/it/zena.mo +0 -0
  128. data/locale/it/zena.po +1982 -0
  129. data/public/images/arrow_back.png +0 -0
  130. data/public/images/remove_tag.png +0 -0
  131. data/public/javascripts/grid.js +800 -199
  132. data/public/javascripts/window.js +1 -1
  133. data/public/javascripts/zena.js +130 -21
  134. data/public/stylesheets/grid.css +11 -2
  135. data/public/stylesheets/zena.css +2 -1
  136. data/test/custom_queries/complex.host.yml +5 -0
  137. data/test/fixtures/files/TestNode.zafu +36 -0
  138. data/test/functional/nodes_controller_test.rb +18 -1
  139. data/test/integration/zafu_compiler/action.yml +2 -2
  140. data/test/integration/zafu_compiler/ajax.yml +44 -26
  141. data/test/integration/zafu_compiler/asset.yml +12 -2
  142. data/test/integration/zafu_compiler/basic.yml +0 -16
  143. data/test/integration/zafu_compiler/calendar.yml +6 -6
  144. data/test/integration/zafu_compiler/complex_ok.yml +23 -1
  145. data/test/integration/zafu_compiler/conditional.yml +5 -5
  146. data/test/integration/zafu_compiler/context.yml +6 -5
  147. data/test/integration/zafu_compiler/dates.yml +23 -2
  148. data/test/integration/zafu_compiler/display.yml +46 -2
  149. data/test/integration/zafu_compiler/errors.yml +2 -2
  150. data/test/integration/zafu_compiler/eval.yml +35 -7
  151. data/test/integration/zafu_compiler/forms.yml +47 -13
  152. data/test/integration/zafu_compiler/i18n.yml +2 -2
  153. data/test/integration/zafu_compiler/meta.yml +35 -1
  154. data/test/integration/zafu_compiler/query.yml +23 -4
  155. data/test/integration/zafu_compiler/relations.yml +10 -6
  156. data/test/integration/zafu_compiler/roles.yml +4 -4
  157. data/test/integration/zafu_compiler/rubyless.yml +11 -1
  158. data/test/integration/zafu_compiler/safe_definitions.yml +23 -5
  159. data/test/integration/zafu_compiler/security.yml +10 -6
  160. data/test/integration/zafu_compiler/urls.yml +23 -6
  161. data/test/integration/zafu_compiler/zafu_attributes.yml +1 -1
  162. data/test/integration/zafu_compiler/zazen.yml +14 -0
  163. data/test/selenium/Add/add3.rsel +8 -8
  164. data/test/selenium/Destroy/0setup.rsel +12 -0
  165. data/test/selenium/Destroy/destroy1.rsel +16 -0
  166. data/test/selenium/Edit/edit2.rsel +9 -9
  167. data/test/selenium/Edit/edit5.rsel +9 -9
  168. data/test/selenium/Edit/edit6.rsel +9 -9
  169. data/test/selenium/Form/form4.rsel +17 -0
  170. data/test/selenium/Toggle/toggle1.rsel +2 -0
  171. data/test/selenium/Toggle/toggle2.rsel +18 -0
  172. data/test/sites/zena/columns.yml +3 -0
  173. data/test/sites/zena/versions.yml +7 -0
  174. data/test/unit/cached_page_test.rb +13 -13
  175. data/test/unit/column_test.rb +26 -0
  176. data/test/unit/node_test.rb +16 -1
  177. data/test/unit/project_test.rb +6 -1
  178. data/test/unit/relation_test.rb +1 -1
  179. data/test/unit/role_test.rb +1 -1
  180. data/test/unit/string_hash_test.rb +30 -0
  181. data/test/unit/virtual_class_test.rb +31 -17
  182. data/test/unit/zafu_markup_test.rb +414 -0
  183. data/test/unit/zafu_node_context_test.rb +375 -0
  184. data/test/unit/zafu_ordered_hash_test.rb +69 -0
  185. data/test/unit/zena/acts/enrollable_test.rb +1 -1
  186. data/test/unit/zena/parser/zafu_asset.yml +0 -10
  187. data/test/unit/zena/parser/zazen.yml +1 -1
  188. data/test/unit/zena/parser_test.rb +1 -72
  189. data/test/unit/zena/use/dates_test.rb +1 -1
  190. data/test/unit/zena/use/rendering_test.rb +24 -7
  191. data/test/unit/zena/use/scope_index_test.rb +17 -0
  192. data/test/unit/zena/use/zazen_test.rb +2 -1
  193. data/zena.gemspec +71 -37
  194. metadata +104 -83
  195. data/app/views/nodes/destroy.erb +0 -0
  196. data/bricks/static/lib/bricks/static.rb +0 -151
  197. data/bricks/static/zena/init.rb +0 -1
  198. data/bricks/static/zena/migrate/20110702010330_add_static_to_idx_templates.rb +0 -12
  199. data/bricks/static/zena/test/unit/static_test.rb +0 -33
  200. data/lib/zena/parser/zafu_rules.rb +0 -244
  201. data/lib/zena/parser/zafu_tags.rb +0 -198
  202. data/lib/zena/parser/zena_rules.rb +0 -23
@@ -50,15 +50,16 @@ module Bricks
50
50
  table, error = get_table_from_json(node.prop[attribute])
51
51
 
52
52
  res = prefix + error.to_s
53
- uuid = UUIDTools::UUID.random_create.to_s.gsub('-','')
53
+ uuid = UUIDTools::UUID.random_create.to_s.gsub('-','')[0..6]
54
54
  msg = opts[:msg] || _('type to edit')
55
- res << "<table id='grid#{uuid}' data-a='node[#{attribute}]' data-msg='#{msg}' class='grid'>\n<tr>"
55
+ res << "<table id='grid#{uuid}' data-a='node[#{attribute}]' data-msg='#{msg}' class='grid'>"
56
56
  if node.can_write? && !opts[:no_edit]
57
- js_data << "Grid.make($('grid#{uuid}'));"
57
+ js_data << "Grid.make('grid#{uuid}');"
58
58
  end
59
59
 
60
60
 
61
61
  if table[1][0]
62
+ res << "\n<tr>"
62
63
  table[1][0].each do |heading|
63
64
  res << "<th>#{ heading }</th>"
64
65
  end
@@ -1,15 +1,9 @@
1
1
  module Bricks
2
2
  module Tags
3
- class StringHash
4
- include RubyLess
5
- safe_context [:[], String] => String
6
- safe_method :keys => [String]
7
- end
8
-
9
3
  def self.included(base)
10
4
  base.after_save :update_tags
11
5
  base.safe_context :tags => ['Link']
12
- base.safe_method :tag_list => String, :tag => String, :tagged => StringHash, :tag_names => [String]
6
+ base.safe_method :tag_list => String, :tag => String, :tagged => ::StringHash, :tag_names => [String]
13
7
 
14
8
  base.class_eval <<-END
15
9
  include Bricks::Tags::InstanceMethods
@@ -0,0 +1,7 @@
1
+ class AddSslLoginToSite < ActiveRecord::Migration
2
+ def self.up
3
+ end
4
+
5
+ def self.down
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ class AddAutoPublishToGroup < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :groups, :auto_publish, :boolean
4
+ end
5
+
6
+ def self.down
7
+ remove_column :groups, :auto_publish
8
+ end
9
+ end
@@ -5,7 +5,7 @@ test:
5
5
  captcha: ON
6
6
  acls: ON
7
7
  grid: ON
8
- static: OFF
8
+ fs_skin: OFF
9
9
  sphinx: OFF
10
10
  worker: OFF
11
11
  uv: OFF
@@ -37,7 +37,7 @@ development:
37
37
  captcha: ON
38
38
  grid: ON
39
39
  acls: ON
40
- static: OFF
40
+ fs_skin: ON
41
41
  sphinx:
42
42
  switch: OFF
43
43
  activate_if:
@@ -74,7 +74,7 @@ production:
74
74
  captcha: ON
75
75
  grid: ON
76
76
  acls: ON
77
- static: OFF
77
+ fs_skin: ON
78
78
  single: OFF
79
79
  sphinx:
80
80
  switch: OFF
@@ -18,12 +18,11 @@ gem_plugin: # upload progress
18
18
  simple_xlsx_writer: # spreadsheet
19
19
  lib: 'simple_xlsx'
20
20
 
21
- querybuilder: '= 1.1.0'
21
+ querybuilder: '= 1.1.3'
22
22
  yamltest: '= 0.7.0'
23
23
  rubyless: '= 0.8.6'
24
- property: '= 2.2.0'
24
+ property: '= 2.3.2'
25
25
  versions: '= 0.3.1'
26
- zafu: '= 0.8.6'
27
26
 
28
27
  jeweler:
29
28
 
@@ -19,7 +19,7 @@ def symlink_assets(from, to)
19
19
  # we could create a symlink in the sites dir to 'shared' -> /var/zena/current/public
20
20
  # and then symlink with "#{host_path}/public/#{dir}" -> "../shared/public/#{dir}"
21
21
  # OR we could symlink /var/zena/current/...
22
- ['calendar', 'images', 'javascripts', 'stylesheets'].each do |dir|
22
+ ['static', 'calendar', 'images', 'javascripts', 'stylesheets'].each do |dir|
23
23
  File.unlink("#{to}/public/#{dir}") if File.symlink?("#{to}/public/#{dir}")
24
24
  if File.exist?("#{to}/public/#{dir}")
25
25
  if File.directory?("#{to}/public/#{dir}")
@@ -355,23 +355,27 @@ namespace :zena do
355
355
 
356
356
  desc 'Rebuild index for all sites or site defined by HOST param.'
357
357
  task :rebuild_index => :environment do
358
+ # Make sure all bricks are loaded before executing the index rebuild
359
+ Zena::Use.upgrade_class('Site')
360
+
358
361
  include Zena::Acts::Secure
359
362
  if ENV['HOST']
360
363
  sites = [Site.find_by_host(ENV['HOST'])]
361
364
  else
362
365
  sites = Site.all
363
366
  end
367
+
364
368
  sites.each do |site|
369
+ Thread.current[:visitor] = site.any_admin
370
+
365
371
  if ENV['WORKER'] == 'false' || RAILS_ENV == 'test'
366
372
  # We avoid SiteWorker by passing nodes.
367
- Thread.current[:visitor] = site.any_admin
368
373
  nodes = Node.find(:all,
369
374
  :conditions => ['site_id = ?', site.id]
370
375
  )
371
376
  site.rebuild_index(secure_result(nodes))
372
377
  else
373
378
  # We try to use the site worker.
374
- Thread.current[:visitor] = site.any_admin
375
379
  site.rebuild_index
376
380
  end
377
381
  end
@@ -0,0 +1,7 @@
1
+ require 'zafu/all'
2
+
3
+ if defined?(ActionView)
4
+ require 'zafu/handler'
5
+ ActionView::Template.register_template_handler(:zafu, Zafu::Handler)
6
+ ActionView::Template.register_template_handler(:html, Zafu::Handler)
7
+ end
@@ -0,0 +1,21 @@
1
+ require 'zafu/parsing_rules'
2
+ require 'zafu/process/ajax'
3
+ require 'zafu/process/html'
4
+ require 'zafu/process/ruby_less_processing'
5
+ require 'zafu/process/context'
6
+ require 'zafu/process/conditional'
7
+ require 'zafu/process/forms'
8
+ require 'zafu/security'
9
+
10
+ module Zafu
11
+ All = [
12
+ Zafu::ParsingRules,
13
+ Zafu::Process::HTML,
14
+ Zafu::Process::Context,
15
+ Zafu::Process::Conditional,
16
+ Zafu::Process::RubyLessProcessing,
17
+ Zafu::Process::Ajax,
18
+ Zafu::Process::Forms,
19
+ Zafu::Security,
20
+ ]
21
+ end
@@ -0,0 +1,7 @@
1
+ require 'zafu/parser'
2
+ require 'zafu/node_context'
3
+ require 'zafu/all'
4
+
5
+ module Zafu
6
+ Compiler = Zafu.parser_with_rules(Zafu::All)
7
+ end
@@ -0,0 +1,58 @@
1
+ require 'zafu/node_context'
2
+
3
+ module Zafu
4
+ module ControllerMethods
5
+ def self.included(base)
6
+ base.helper Common
7
+ if RAILS_ENV == 'development'
8
+ base.class_eval do
9
+ def render_for_file_with_rebuild(template_path, status = nil, layout = nil, locals = {}) #:nodoc:
10
+ path = template_path.respond_to?(:path_without_format_and_extension) ? template_path.path_without_format_and_extension : template_path
11
+ logger.info("Rendering #{path}" + (status ? " (#{status})" : '')) if logger
12
+ # if params[:rebuild] == 'true'
13
+ t = self.view_paths.find_template(template_path, 'html')
14
+ t.previously_last_modified = nil
15
+ # end
16
+ render_for_text @template.render(:file => template_path, :locals => locals, :layout => layout), status
17
+ end
18
+ alias_method_chain :render_for_file, :rebuild
19
+ end
20
+ end
21
+ end
22
+
23
+ def zafu_node(name, klass)
24
+ zafu_context[:node] = Zafu::NodeContext.new(name, klass)
25
+ end
26
+
27
+ module Common
28
+ def zafu_context
29
+ @zafu_context ||= {}
30
+ end
31
+
32
+ # Quote for html attributes (field quote). There might be a better rails alternative to this.
33
+ def fquote(text)
34
+ text.to_s.gsub("'",'&apos;')
35
+ end
36
+
37
+ # This method should return the template for a given 'src' and
38
+ # 'base_path'.
39
+ def get_template_text(path, base_path, opts={})
40
+ [path, "#{base_path}/#{path}"].each do |p|
41
+ begin
42
+ t = self.view_paths.find_template(p, 'html') # FIXME: format ?
43
+ rescue ActionView::MissingTemplate
44
+ t = nil
45
+ end
46
+ return [t.source, t.path, t.base_path] if t
47
+ end
48
+ nil
49
+ end
50
+
51
+ def template_url_for_asset(opts)
52
+ opts[:src]
53
+ end
54
+ end # Common
55
+
56
+ include Common
57
+ end
58
+ end
@@ -0,0 +1,57 @@
1
+ require 'zafu/parser'
2
+ require 'zafu/markup'
3
+ require 'zafu/node_context'
4
+ require 'zafu/template'
5
+
6
+ module Zafu
7
+ class Handler < ActionView::TemplateHandler
8
+ include ActionView::TemplateHandlers::Compilable
9
+
10
+ def compile(template)
11
+ @template = template
12
+ helper = Thread.current[:view]
13
+ if !helper.respond_to?(:zafu_context)
14
+ raise Exception.new("Please add \"include Zafu::ControllerMethods\" into your ApplicationController for zafu to work properly.")
15
+ end
16
+ ast = Zafu::Template.new(template, self)
17
+ context = helper.zafu_context.merge(:helper => helper)
18
+ context[:node] ||= get_zafu_node_from_view(helper)
19
+ rb = ast.to_ruby('@output_buffer', context)
20
+ ";@erb = %q{#{ast.to_erb(context)}};#{rb}"
21
+ end
22
+
23
+ def get_template_text(path, base_path)
24
+ if path == @template.path && base_path.nil?
25
+ [@template.source, @template.path, @template.base_path]
26
+ else
27
+ Thread.current[:view].get_template_text(path, base_path)
28
+ end
29
+ end
30
+
31
+ private
32
+ def get_zafu_node_from_view(view)
33
+ controller = view.controller
34
+ if controller.class.to_s =~ /\A([A-Z]\w+?)s?[A-Z]/
35
+ ivar = "@#{$1.downcase}"
36
+ if var = controller.instance_variable_get(ivar.to_sym)
37
+ name = ivar
38
+ klass = var.class
39
+ elsif var = controller.instance_variable_get(ivar + 's')
40
+ name = ivar + 's'
41
+ klass = [var.first.class]
42
+ end
43
+ return Zafu::NodeContext.new(name, klass) if name
44
+ end
45
+ raise Exception.new("Could not guess main instance variable from request parameters, please add something like \"zafu_node('@var_name', Page)\" in your action.")
46
+ end
47
+ end
48
+ end
49
+
50
+ class ActionView::Template
51
+ attr_reader :view
52
+ def render_template_with_zafu(view, local_assigns = {})
53
+ Thread.current[:view] = view
54
+ render_template_without_zafu(view, local_assigns)
55
+ end
56
+ alias_method_chain :render_template, :zafu
57
+ end
@@ -0,0 +1,4 @@
1
+ module Zafu
2
+ VERSION = '0.8.7'
3
+ end
4
+
@@ -0,0 +1,309 @@
1
+ require 'zafu/ordered_hash'
2
+
3
+ module Zafu
4
+ # A Markup object is used to hold information on the tag used (<li>), it's parameters (.. class='xxx') and
5
+ # indentation.
6
+ class Markup
7
+ EMPTY_TAGS = %w{meta input link img}
8
+ STEAL_PARAMS = {
9
+ 'link' => [:href, :charset, :rel, :type, :media, :rev, :target],
10
+ 'a' => [:title, :onclick, :target],
11
+ 'script' => [:type, :charset, :defer],
12
+ :other => [:class, :id, :style],
13
+ }
14
+
15
+ # Tag used ("li" for example). The tag can be nil (no tag).
16
+ attr_accessor :tag
17
+ # Tag parameters (.. class='xxx' id='yyy')
18
+ attr_accessor :params
19
+ # Dynamic tag parameters that should not be escaped. For example: (.. class='<%= @node.klass %>')
20
+ attr_accessor :dyn_params
21
+ # Ensure wrap is not called more then once unless this attribute has been reset in between
22
+ attr_accessor :done
23
+ # Space to insert before tag
24
+ attr_accessor :space_before
25
+ # Space to insert after tag
26
+ attr_accessor :space_after
27
+ # Keys to remove from zafu and use for the tag itself
28
+ attr_writer :steal_keys
29
+
30
+ class << self
31
+
32
+ # Parse parameters into a hash. This parsing supports multiple values for one key by creating additional keys:
33
+ # <tag do='hello' or='goodbye' or='gotohell'> creates the hash {:do=>'hello', :or=>'goodbye', :or1=>'gotohell'}
34
+ def parse_params(text)
35
+ return OrderedHash.new unless text
36
+ return text if text.kind_of?(Hash)
37
+ params = OrderedHash.new
38
+ rest = text.strip
39
+ while (rest != '')
40
+ if rest =~ /(.+?)=/
41
+ key = $1.strip.to_sym
42
+ rest = rest[$&.length..-1].strip
43
+ if rest =~ /('|")(|[^\1]*?[^\\])\1/
44
+ rest = rest[$&.length..-1].strip
45
+ key_counter = 1
46
+ while params[key]
47
+ key = "#{key}#{key_counter}".to_sym
48
+ key_counter += 1
49
+ end
50
+
51
+ if $1 == "'"
52
+ params[key] = $2.gsub("\\'", "'")
53
+ else
54
+ params[key] = $2.gsub('\\"', '"')
55
+ end
56
+ else
57
+ # error, bad format, return found params.
58
+ break
59
+ end
60
+ else
61
+ # error, bad format
62
+ break
63
+ end
64
+ end
65
+ params
66
+ end
67
+ end
68
+
69
+ def initialize(tag, params = nil)
70
+ @done = false
71
+ @tag = tag
72
+ if params
73
+ self.params = params
74
+ else
75
+ @params = OrderedHash.new
76
+ end
77
+ @dyn_params = OrderedHash.new
78
+ end
79
+
80
+ # Set params either using a string (like "alt='time passes' class='zen'")
81
+ def params=(p)
82
+ if p.kind_of?(Hash)
83
+ @params = p
84
+ else
85
+ @params = Markup.parse_params(p)
86
+ end
87
+ end
88
+
89
+ # Another way to set dynamic params (the argument must be a hash).
90
+ def dyn_params=(h)
91
+ set_dyn_params(h)
92
+ end
93
+
94
+ # Steal html parameters from an existing hash (the stolen parameters are removed
95
+ # from the argument)
96
+ def steal_html_params_from(p)
97
+ p.delete_if do |k,v|
98
+ if steal_keys.include?(k) || k =~ /^data-/
99
+ @params[k] = v
100
+ true
101
+ else
102
+ false
103
+ end
104
+ end
105
+ end
106
+
107
+ # Compile dynamic parameters as ERB. A parameter is considered dynamic if it
108
+ # contains the string eval "#{...}"
109
+ def compile_params(helper)
110
+ @params.each do |key, value|
111
+ if value =~ /^(.*)\#\{(.*)\}(.*)$/
112
+ @params.delete(key)
113
+ if $1 == '' && $3 == ''
114
+ code = RubyLess.translate(helper, $2)
115
+ if code.literal
116
+ append_dyn_param(key, helper.form_quote(code.literal.to_s))
117
+ else
118
+ append_dyn_param(key, "<%= #{code} %>")
119
+ end
120
+ else
121
+ code = RubyLess.translate_string(helper, value)
122
+ if code.literal
123
+ append_dyn_param(key, helper.form_quote(code.literal.to_s))
124
+ else
125
+ append_dyn_param(key, "<%= #{code} %>")
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ # Set dynamic html parameters.
133
+ def set_dyn_params(hash)
134
+ hash.each do |k,v|
135
+ set_dyn_param(k, v)
136
+ end
137
+ end
138
+
139
+ # Set dynamic html parameters.
140
+ def set_dyn_param(key, value)
141
+ @params.delete(key)
142
+ @dyn_params[key] = value
143
+ end
144
+
145
+ # Set static html parameters.
146
+ def set_params(hash)
147
+ hash.each do |k,v|
148
+ set_param(k, v)
149
+ end
150
+ end
151
+
152
+ # Set static html parameters.
153
+ def set_param(key, value)
154
+ @dyn_params.delete(key)
155
+ @params[key] = value
156
+ end
157
+
158
+ def prepend_param(key, value)
159
+ if prev_value = @dyn_params[key]
160
+ @dyn_params[key] = "#{value} #{prev_value}"
161
+ elsif prev_value = @params[key]
162
+ @params[key] = "#{value} #{prev_value}"
163
+ else
164
+ @params[key] = value
165
+ end
166
+ end
167
+
168
+ def append_param(key, value)
169
+ if prev_value = @dyn_params[key]
170
+ @dyn_params[key] = "#{prev_value} #{value}"
171
+ elsif prev_value = @params[key]
172
+ @params[key] = "#{prev_value} #{value}"
173
+ else
174
+ @params[key] = value
175
+ end
176
+ end
177
+
178
+ def prepend_dyn_param(key, value, conditional = false)
179
+ spacer = conditional ? '' : ' '
180
+ if prev_value = @params.delete(key)
181
+ @dyn_params[key] = "#{value}#{spacer}#{prev_value}"
182
+ elsif prev_value = @dyn_params[key]
183
+ @dyn_params[key] = "#{value}#{spacer}#{prev_value}"
184
+ else
185
+ @dyn_params[key] = value
186
+ end
187
+ end
188
+
189
+ def append_attribute(text_to_append)
190
+ (@append ||= '') << text_to_append
191
+ end
192
+
193
+ def append_dyn_param(key, value, conditional = false)
194
+ spacer = conditional ? '' : ' '
195
+ if prev_value = @params.delete(key)
196
+ @dyn_params[key] = "#{prev_value}#{spacer}#{value}"
197
+ elsif prev_value = @dyn_params[key]
198
+ @dyn_params[key] = "#{prev_value}#{spacer}#{value}"
199
+ else
200
+ @dyn_params[key] = value
201
+ end
202
+ end
203
+
204
+ # Define the DOM id from a node context
205
+ def set_id(erb_id)
206
+ params[:id] = nil
207
+ dyn_params[:id] = erb_id
208
+ end
209
+
210
+ # Return true if the given key exists in params or dyn_params.
211
+ def has_param?(key)
212
+ params[key] || dyn_params[key]
213
+ end
214
+
215
+ # Duplicate markup and make sure params and dyn_params are duplicated as well.
216
+ def dup
217
+ markup = super
218
+ markup.instance_variable_set(:@params, @params.dup)
219
+ markup.instance_variable_set(:@dyn_params, @dyn_params.dup)
220
+ markup.instance_variable_set(:@pre_wrap, @pre_wrap.dup) if @pre_wrap
221
+ markup
222
+ end
223
+
224
+ # Store some text to insert at the beggining of the tag content on wrap. Inserted
225
+ # elements are indexed in a hash but only values are shown.
226
+ def pre_wrap
227
+ @pre_wrap ||= {}
228
+ end
229
+
230
+ # Wrap the given text with our tag. If 'append' is not empty, append the text
231
+ # after the tag parameters: <li class='foo'[APPEND HERE]>text</li>.
232
+ def wrap(text)
233
+ return text if @done
234
+
235
+ text = "#{@pre_wrap.values}#{text}" if @pre_wrap
236
+
237
+ if dyn_params[:id]
238
+ @tag ||= 'div'
239
+ end
240
+
241
+ if @tag
242
+ if text.blank? && EMPTY_TAGS.include?(@tag)
243
+ res = "#{@pre_wrap}<#{@tag}#{params_to_html}#{@append}/>"
244
+ else
245
+ res = "<#{@tag}#{params_to_html}#{@append}>#{text}</#{@tag}>"
246
+ end
247
+ else
248
+ res = text
249
+ end
250
+ @done = true
251
+
252
+ (@space_before || '') + res + (@space_after || '')
253
+ end
254
+
255
+ def to_s
256
+ wrap(nil)
257
+ end
258
+
259
+ def steal_keys
260
+ @steal_keys || (STEAL_PARAMS[@tag] || []) + STEAL_PARAMS[:other]
261
+ end
262
+
263
+ private
264
+ if RAILS_ENV == 'test'
265
+ def params_to_html
266
+ para = []
267
+ keys = @dyn_params.keys
268
+
269
+ @params.each do |k, v|
270
+ next if keys.include?(k)
271
+
272
+ if !v.to_s.include?("'")
273
+ para << " #{k}='#{v}'"
274
+ else
275
+ para << " #{k}=\"#{v.to_s.gsub('"','\"')}\"" # TODO: do this work in all cases ?
276
+ end
277
+ end
278
+
279
+ keys.each do |k|
280
+ para << " #{k}='#{@dyn_params[k]}'"
281
+ end
282
+
283
+ para
284
+ end
285
+ else
286
+ def params_to_html
287
+ para = []
288
+ keys = @dyn_params.keys
289
+
290
+ @params.each do |k,v|
291
+ next if keys.include?(k)
292
+
293
+ if !v.to_s.include?("'")
294
+ para << " #{k}='#{v}'"
295
+ else
296
+ para << " #{k}=\"#{v.to_s.gsub('"','\"')}\"" # TODO: do this work in all cases ?
297
+ end
298
+ end
299
+
300
+ @dyn_params.each do |k,v|
301
+ para << " #{k}='#{v}'"
302
+ end
303
+
304
+ para
305
+ end
306
+ end
307
+
308
+ end
309
+ end