zena 1.0.0.rc2 → 1.0.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (274) hide show
  1. data/History.txt +23 -0
  2. data/README.rdoc +1 -1
  3. data/app/controllers/columns_controller.rb +3 -31
  4. data/app/controllers/comments_controller.rb +8 -3
  5. data/app/controllers/data_entries_controller.rb +1 -1
  6. data/app/controllers/documents_controller.rb +2 -2
  7. data/app/controllers/nodes_controller.rb +29 -12
  8. data/app/controllers/relations_controller.rb +2 -2
  9. data/app/controllers/sites_controller.rb +1 -1
  10. data/app/controllers/user_sessions_controller.rb +6 -3
  11. data/app/controllers/users_controller.rb +18 -16
  12. data/app/controllers/versions_controller.rb +20 -18
  13. data/app/controllers/virtual_classes_controller.rb +103 -17
  14. data/app/helpers/users_helper.rb +1 -1
  15. data/app/models/column.rb +19 -50
  16. data/app/models/comment.rb +2 -1
  17. data/app/models/node.rb +45 -22
  18. data/app/models/relation.rb +13 -0
  19. data/app/models/relation_proxy.rb +3 -2
  20. data/app/models/role.rb +213 -4
  21. data/app/models/site.rb +18 -11
  22. data/app/models/template.rb +37 -35
  23. data/app/models/version.rb +1 -1
  24. data/app/models/virtual_class.rb +154 -86
  25. data/app/views/columns/_li.html.erb +1 -1
  26. data/app/views/columns/index.html.erb +1 -9
  27. data/app/views/comments/index.rhtml +10 -8
  28. data/app/views/documents/_crop.rhtml +5 -6
  29. data/app/views/documents/crop_form.rjs +3 -2
  30. data/app/views/groups/index.rhtml +1 -1
  31. data/app/views/iformats/index.rhtml +1 -1
  32. data/app/views/nodes/_import_results.rhtml +1 -1
  33. data/app/views/nodes/_parent.rhtml +1 -2
  34. data/app/views/nodes/update.rjs +3 -4
  35. data/app/views/relations/index.erb +1 -1
  36. data/app/views/sites/index.erb +1 -1
  37. data/app/views/templates/drive_tabs/_drive.rhtml +0 -2
  38. data/app/views/templates/edit_tabs/_image.rhtml +1 -1
  39. data/app/views/templates/edit_tabs/_title.rhtml +0 -6
  40. data/app/views/users/index.rhtml +1 -1
  41. data/app/views/users/preferences.html.erb +2 -2
  42. data/app/views/versions/backup.rjs +1 -1
  43. data/app/views/versions/custom_tab.rhtml +9 -4
  44. data/app/views/versions/destroy.rjs +2 -2
  45. data/app/views/versions/update.rjs +2 -9
  46. data/app/views/virtual_classes/_form.erb +3 -2
  47. data/app/views/virtual_classes/import_prepare.html.erb +13 -0
  48. data/app/views/virtual_classes/index.erb +28 -8
  49. data/app/views/zafu/default/Node-+adminLayout.zafu +1 -13
  50. data/app/views/zafu/default/Node-+login.zafu +1 -0
  51. data/app/views/zafu/default/Node-+notFound.zafu +1 -1
  52. data/app/views/zafu/default/Node-+popupLayout.zafu +1 -2
  53. data/app/views/zafu/default/Node-+search.zafu +1 -1
  54. data/app/views/zafu/default/Node-admin.zafu +205 -0
  55. data/app/views/zafu/default/Node.zafu +11 -11
  56. data/bricks/captcha/lib/bricks/captcha.rb +3 -2
  57. data/bricks/mongrel/zena/init.rb +2 -1
  58. data/bricks/pdf/README +5 -5
  59. data/bricks/pdf/lib/bricks/pdf/engine/prince.rb +2 -2
  60. data/bricks/pdf/lib/bricks/pdf/engine/xhtml2pdf.rb +2 -2
  61. data/bricks/pdf/lib/bricks/pdf/install.rb +5 -5
  62. data/bricks/pdf/lib/bricks/pdf.rb +11 -11
  63. data/bricks/pdf/test/engines/test_prince.rb +4 -4
  64. data/bricks/pdf/test/engines/test_xhtml2pdf.rb +4 -4
  65. data/bricks/pdf/test/shoulda_macros/shoulda_pdf.rb +2 -2
  66. data/bricks/pdf/zena/init.rb +2 -2
  67. data/bricks/pdf/zena/tasks.rb +2 -2
  68. data/bricks/sphinx/lib/bricks/sphinx.rb +6 -2
  69. data/bricks/sphinx/zena/{sphinx.yml → sphinx.yml.erb} +2 -2
  70. data/bricks/sphinx/zena/tasks.rb +28 -2
  71. data/bricks/tags/lib/bricks/tags.rb +16 -1
  72. data/bricks/tags/zena/test/unit/tags_test.rb +15 -0
  73. data/bricks/tags/zena/test/zafu/tags.yml +5 -1
  74. data/bricks/worker/lib/bricks/worker.rb +39 -0
  75. data/bricks/worker/zena/deploy.rb +0 -2
  76. data/bricks/worker/zena/init.rb +1 -0
  77. data/bricks/worker/zena/test/sites/zena/delayed_jobs.yml +16 -0
  78. data/bricks/worker/zena/test/zafu/worker.yml +8 -0
  79. data/bricks/zena/zena/migrate/01_base.rb +36 -60
  80. data/bricks/zena/zena/migrate/02_zerox1_schema.rb +388 -0
  81. data/bricks/zena/zena/migrate/03_zerox1_data.rb +380 -0
  82. data/bricks/zena/zena/migrate/20110315161158_add_reverse_scope_to_roles.rb +9 -0
  83. data/config/database_example.yml +1 -1
  84. data/config/environment.rb +1 -1
  85. data/config/gems.yml +17 -14
  86. data/db/init/base/skins/default/Node-+index.zafu +8 -1
  87. data/db/init/base/skins/default/Node-+login.zafu +1 -0
  88. data/db/init/base/skins/default/Node-+popupLayout.zafu +1 -2
  89. data/db/init/base/skins/default/Node-+search.zafu +2 -2
  90. data/db/init/base/skins/default/Node.zafu +9 -9
  91. data/db/init/base/skins/default/{favicon.png → img/favicon.png} +0 -0
  92. data/db/init/base/skins/default/{style.css → img/style.css} +0 -0
  93. data/db/init/base/skins/default/img/translations.yml +11 -0
  94. data/db/init/base/skins/default/notes.zafu +7 -9
  95. data/doc/zafu_changes.yml +12 -0
  96. data/lib/bricks/loader.rb +38 -15
  97. data/lib/tasks/zena.rake +74 -24
  98. data/lib/zena/acts/enrollable.rb +4 -1
  99. data/lib/zena/acts/secure.rb +2 -48
  100. data/lib/zena/acts/serializable.rb +13 -1
  101. data/lib/zena/app.rb +9 -0
  102. data/lib/zena/code_syntax.rb +154 -151
  103. data/lib/zena/console.rb +141 -0
  104. data/lib/zena/controller/test_case.rb +1 -1
  105. data/lib/zena/db_helper/abstract_db.rb +17 -5
  106. data/lib/zena/db_helper/mysql.rb +14 -12
  107. data/lib/zena/db_helper/postgresql.rb +1 -2
  108. data/lib/zena/db_helper/sqlite3.rb +6 -6
  109. data/lib/zena/deploy/awstats.conf.rhtml +1 -1
  110. data/lib/zena/deploy/httpd.rhtml +6 -1
  111. data/lib/zena/deploy/vhost.rhtml +9 -1
  112. data/lib/zena/deploy.rb +12 -7
  113. data/lib/zena/foxy_parser.rb +3 -1
  114. data/lib/zena/info.rb +1 -1
  115. data/lib/zena/parser/zafu_tags.rb +1 -0
  116. data/lib/zena/parser/zazen_rules.rb +1 -1
  117. data/lib/zena/remote/node.rb +15 -3
  118. data/lib/zena/remote/serializable_array.rb +19 -0
  119. data/lib/zena/remote.rb +1 -0
  120. data/lib/zena/routes.rb +7 -2
  121. data/lib/zena/site_worker.rb +11 -1
  122. data/lib/zena/unit/test_case.rb +68 -0
  123. data/lib/zena/use/action.rb +6 -2
  124. data/lib/zena/use/ajax.rb +127 -53
  125. data/lib/zena/use/ancestry.rb +11 -8
  126. data/lib/zena/use/calendar.rb +265 -129
  127. data/lib/zena/use/conditional.rb +1 -1
  128. data/lib/zena/use/context.rb +5 -5
  129. data/lib/zena/use/dates.rb +172 -60
  130. data/lib/zena/use/display.rb +70 -39
  131. data/lib/zena/use/error_rendering.rb +1 -3
  132. data/lib/zena/use/field_index.rb +4 -1
  133. data/lib/zena/use/forms.rb +94 -72
  134. data/lib/zena/use/fulltext.rb +16 -24
  135. data/lib/zena/use/html_tags.rb +20 -12
  136. data/lib/zena/use/i18n.rb +37 -37
  137. data/lib/zena/use/image_builder.rb +8 -1
  138. data/lib/zena/use/ml_index.rb +16 -16
  139. data/lib/zena/use/prop_eval.rb +10 -5
  140. data/lib/zena/use/query_builder.rb +55 -23
  141. data/lib/zena/use/query_node.rb +51 -25
  142. data/lib/zena/use/refactor.rb +2 -28
  143. data/lib/zena/use/relations.rb +1 -1
  144. data/lib/zena/use/rendering.rb +29 -0
  145. data/lib/zena/use/scope_index.rb +75 -14
  146. data/lib/zena/use/search.rb +5 -10
  147. data/lib/zena/use/test_helper.rb +2 -2
  148. data/lib/zena/use/urls.rb +125 -104
  149. data/lib/zena/use/workflow.rb +2 -1
  150. data/lib/zena/use/zafu_attributes.rb +2 -2
  151. data/lib/zena/use/zafu_safe_definitions.rb +20 -0
  152. data/lib/zena/use/zafu_templates.rb +20 -6
  153. data/lib/zena/use/zazen.rb +31 -20
  154. data/lib/zena/view/test_case.rb +5 -0
  155. data/lib/zena/zafu_compiler.rb +24 -2
  156. data/lib/zena.rb +12 -6
  157. data/locale/de/LC_MESSAGES/zena.mo +0 -0
  158. data/locale/de/zena.po +1345 -1164
  159. data/locale/en/LC_MESSAGES/zena.mo +0 -0
  160. data/locale/en/zena.po +1275 -1129
  161. data/locale/fr/LC_MESSAGES/zena.mo +0 -0
  162. data/locale/fr/zena.mo +0 -0
  163. data/locale/fr/zena.po +1617 -1441
  164. data/locale/log.txt +9 -0
  165. data/locale/zena.pot +957 -748
  166. data/public/javascripts/prototype.js +1 -1
  167. data/public/javascripts/zena.js +99 -44
  168. data/public/stylesheets/admin.css +6 -4
  169. data/public/stylesheets/backend.css +71 -0
  170. data/public/stylesheets/calendar.css +24 -25
  171. data/public/stylesheets/code.css +11 -6
  172. data/public/stylesheets/comment.css +2 -1
  173. data/public/stylesheets/popup.css +7 -8
  174. data/test/custom_queries/complex.host.yml +15 -1
  175. data/test/fixtures/files/Node-test.zafu +29 -28
  176. data/test/fixtures/files/translations_de.yml +12 -1
  177. data/test/fixtures/files/translations_fr.yml +12 -1
  178. data/test/functional/comments_controller_test.rb +9 -0
  179. data/test/functional/iformats_controller_test.rb +1 -1
  180. data/test/functional/nodes_controller_test.rb +124 -35
  181. data/test/functional/users_controller_test.rb +132 -3
  182. data/test/functional/virtual_classes_controller_test.rb +75 -4
  183. data/test/integration/navigation_test.rb +51 -9
  184. data/test/integration/query_node/basic.yml +19 -7
  185. data/test/integration/query_node/complex.yml +1 -1
  186. data/test/integration/query_node/dates.yml +27 -1
  187. data/test/integration/query_node/filters.yml +1 -1
  188. data/test/integration/query_node/relations.yml +13 -4
  189. data/test/integration/query_node_test.rb +4 -0
  190. data/test/integration/xml_api_test.rb +6 -1
  191. data/test/integration/zafu_compiler/action.yml +3 -3
  192. data/test/integration/zafu_compiler/ajax.yml +103 -22
  193. data/test/integration/zafu_compiler/basic.yml +0 -52
  194. data/test/integration/zafu_compiler/calendar.yml +44 -20
  195. data/test/integration/zafu_compiler/comments.yml +53 -0
  196. data/test/integration/zafu_compiler/complex.yml +11 -11
  197. data/test/integration/zafu_compiler/complex_ok.yml +16 -3
  198. data/test/integration/zafu_compiler/conditional.yml +15 -5
  199. data/test/integration/zafu_compiler/context.yml +9 -0
  200. data/test/integration/zafu_compiler/dates.yml +43 -15
  201. data/test/integration/zafu_compiler/display.yml +60 -6
  202. data/test/integration/zafu_compiler/errors.yml +6 -2
  203. data/test/integration/zafu_compiler/forms.yml +45 -6
  204. data/test/integration/zafu_compiler/i18n.yml +8 -1
  205. data/test/integration/zafu_compiler/meta.yml +38 -0
  206. data/test/integration/zafu_compiler/query.yml +43 -4
  207. data/test/integration/zafu_compiler/relations.yml +26 -33
  208. data/test/integration/zafu_compiler/rubyless.yml +10 -0
  209. data/test/integration/zafu_compiler/safe_definitions.yml +21 -1
  210. data/test/integration/zafu_compiler/urls.yml +75 -5
  211. data/test/integration/zafu_compiler/version.yml +2 -2
  212. data/test/integration/zafu_compiler/zafu_attributes.yml +5 -1
  213. data/test/integration/zafu_compiler/zazen.yml +14 -6
  214. data/test/integration/zafu_compiler_test.rb +5 -1
  215. data/test/sites/complex/columns.yml +5 -0
  216. data/test/sites/complex/roles.yml +4 -0
  217. data/test/sites/zena/nodes.yml +13 -2
  218. data/test/sites/zena/roles.yml +13 -5
  219. data/test/sites/zena/versions.yml +27 -9
  220. data/test/unit/column_test.rb +51 -5
  221. data/test/unit/iformat_test.rb +2 -2
  222. data/test/unit/node_test.rb +29 -17
  223. data/test/unit/note_test.rb +1 -1
  224. data/test/unit/relation_proxy_test.rb +4 -5
  225. data/test/unit/relation_test.rb +16 -0
  226. data/test/unit/remote_test.rb +2 -2
  227. data/test/unit/role_test.rb +292 -4
  228. data/test/unit/site_test.rb +12 -0
  229. data/test/unit/template_test.rb +1 -1
  230. data/test/unit/text_document_test.rb +1 -1
  231. data/test/unit/virtual_class_test.rb +200 -83
  232. data/test/unit/zena/acts/enrollable_test.rb +26 -31
  233. data/test/unit/zena/use/calendar_test.rb +90 -37
  234. data/test/unit/zena/use/field_index_test.rb +28 -0
  235. data/test/unit/zena/use/html_tags_test.rb +7 -3
  236. data/test/unit/zena/use/ml_index_test.rb +2 -16
  237. data/test/unit/zena/use/nested_attributes_alias_view_test.rb +2 -2
  238. data/test/unit/zena/use/prop_eval_test.rb +50 -8
  239. data/test/unit/zena/use/query_node_test.rb +11 -0
  240. data/test/unit/zena/use/rendering_test.rb +72 -0
  241. data/test/unit/zena/use/scope_index_test.rb +37 -2
  242. data/test/unit/zena/use/urls_test.rb +10 -0
  243. data/test/unit/zena/use/zazen_test.rb +3 -3
  244. data/vendor/plugins/gettext_i18n_rails/Gemfile +11 -0
  245. data/vendor/plugins/gettext_i18n_rails/Gemfile.lock +92 -0
  246. data/vendor/plugins/gettext_i18n_rails/Rakefile +12 -17
  247. data/vendor/plugins/gettext_i18n_rails/Readme.md +215 -0
  248. data/vendor/plugins/gettext_i18n_rails/VERSION +1 -1
  249. data/vendor/plugins/gettext_i18n_rails/gettext_i18n_rails.gemspec +38 -34
  250. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/active_record.rb +1 -1
  251. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/backend.rb +30 -14
  252. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/haml_parser.rb +1 -1
  253. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/html_safe_translations.rb +29 -0
  254. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/i18n_hacks.rb +29 -1
  255. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/model_attributes_finder.rb +7 -1
  256. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/railtie.rb +10 -0
  257. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/ruby_gettext_extractor.rb +6 -2
  258. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/string_interpolate_fix.rb +20 -0
  259. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/tasks.rb +120 -0
  260. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails.rb +10 -3
  261. data/vendor/plugins/gettext_i18n_rails/lib/tasks/gettext_rails_i18n.rake +1 -74
  262. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/active_record_spec.rb +51 -20
  263. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/backend_spec.rb +12 -7
  264. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/string_interpolate_fix_spec.rb +32 -0
  265. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails_spec.rb +38 -1
  266. data/vendor/plugins/gettext_i18n_rails/spec/rails2/Gemfile +11 -0
  267. data/vendor/plugins/gettext_i18n_rails/spec/spec_helper.rb +1 -8
  268. data/zena.gemspec +2241 -2217
  269. metadata +123 -83
  270. data/.gitignore +0 -36
  271. data/app/views/nodes/_dates.rhtml +0 -13
  272. data/db/init/base/skins/default/Node-+adminLayout.zafu +0 -46
  273. data/db/init/base/skins/default/Node-tree.zafu +0 -19
  274. data/vendor/plugins/gettext_i18n_rails/README.markdown +0 -143
@@ -1,6 +1,9 @@
1
+ require 'tzinfo'
2
+
1
3
  module Zena
2
4
  module Use
3
5
  module Dates
6
+ ISO_DATE_FORMAT = '%Y-%m-%dT%H:%M:%S'
4
7
  module Common
5
8
 
6
9
  # This is like strftime but with better support for i18n (translate day names, month abbreviations, etc)
@@ -8,14 +11,18 @@ module Zena
8
11
  return '' if thedate.blank?
9
12
 
10
13
  theformat, tz_name, lang = opts[:format], opts[:tz], opts[:lang]
11
- format = theformat || '%Y-%m-%d %H:%M:%S'
14
+ format = theformat || _('datetime')
12
15
 
13
16
  if tz_name
14
- # display time local to event's timezone
15
- begin
16
- tz = TZInfo::Timezone.get(tz_name)
17
- rescue TZInfo::InvalidTimezoneIdentifier
18
- return "<span class='parser_error'>invalid timezone #{tz_name.inspect}</span>"
17
+ if tz_name.kind_of?(TZInfo::Timezone)
18
+ tz = tz_name
19
+ else
20
+ # display time local to event's timezone
21
+ begin
22
+ tz = TZInfo::Timezone.get(tz_name)
23
+ rescue TZInfo::InvalidTimezoneIdentifier
24
+ return "<span class='parser_error'>invalid timezone #{tz_name.inspect}.</span>"
25
+ end
19
26
  end
20
27
  else
21
28
  tz = visitor.tz
@@ -115,7 +122,12 @@ module Zena
115
122
  defaults = { :id=>"datef#{rnd_id}", :button=>"dateb#{rnd_id}", :display=>"dated#{rnd_id}" }
116
123
  opts = defaults.merge(opts)
117
124
  date = opts[:value] || obj.safe_send(name)
118
- value = tformat_date(date,'datetime')
125
+ showsTime = opts[:time] || 'true'
126
+ # TODO: could we pass the format from the view so that it is
127
+ # translated with the view's dictionary during compilation ?
128
+ dateFormat = showsTime == 'true' ? _('datetime') : _('long_date')
129
+ value = format_date(date, :format => dateFormat)
130
+
119
131
  # TODO: migrate code to Zafu::Markup (needs Zafu 0.7.7)
120
132
  # fld = Zafu::Markup.new('input')
121
133
  # fld.params = (opts[:html] || {}).merge(:name => "node[#{name}]", :id => opts[:id], :type => 'text', :value => value)
@@ -124,17 +136,18 @@ module Zena
124
136
  else
125
137
  fld = "<input id='#{opts[:id]}' name='node[#{name}]' type='text' value='#{value}' class='#{opts[:class]}'/>"
126
138
  end
139
+
140
+ js_data << %Q{Calendar.setup({
141
+ inputField : "#{opts[:id]}", // id of the input field
142
+ button : "#{opts[:button]}", // trigger for the calendar (button ID)
143
+ singleClick : true,
144
+ showsTime : #{showsTime},
145
+ ifFormat : '#{dateFormat}'
146
+ });}
147
+
127
148
  <<-EOL
128
149
  <span class="date_box"><img src="/calendar/iconCalendar.gif" id="#{opts[:button]}" alt='#{_('date selection')}'/>
129
- #{fld}
130
- <script type="text/javascript">
131
- Calendar.setup({
132
- inputField : "#{opts[:id]}", // id of the input field
133
- button : "#{opts[:button]}", // trigger for the calendar (button ID)
134
- singleClick : true,
135
- showsTime : true
136
- });
137
- </script></span>
150
+ #{fld}</span>
138
151
  EOL
139
152
  end
140
153
  end
@@ -144,15 +157,30 @@ module Zena
144
157
  include FormTags
145
158
 
146
159
  # default date used to filter events in templates
147
- def main_date
148
- # TODO: timezone for @date ?
149
- # .to_utc(_('datetime'), visitor.tz)
150
- @main_date ||= params[:date] ? DateTime.parse(params[:date]) : DateTime.now
160
+ def main_date(tz = visitor.tz)
161
+ @main_dates ||= {}
162
+ @main_dates[tz] ||= begin
163
+ if params[:date]
164
+ if date = params[:date].to_utc(ISO_DATE_FORMAT, tz)
165
+ date
166
+ else
167
+ # FIXME: when date parsing fails: show an error, not a 500...
168
+ Node.logger.warn "Could not parse 'date' parameter: #{params[:date].inspect}."
169
+ # malformed url... 404 ?
170
+ Time.now.utc
171
+ end
172
+ else
173
+ # no 'date' parameter
174
+ Time.now.utc
175
+ end
176
+ end
151
177
  end
152
178
 
153
- def parse_date(string)
179
+ def parse_date(string, format = nil, tz = nil)
154
180
  return nil unless string
155
- DateTime.parse(string) rescue nil
181
+ format = _('datetime') if format.blank?
182
+ tz = visitor.tz if tz.blank?
183
+ string.to_utc(format, visitor.tz)
156
184
  end
157
185
  end # ViewMethods
158
186
 
@@ -174,21 +202,23 @@ module Zena
174
202
  end
175
203
 
176
204
  module StringMethods
205
+ SPLIT_STRING = /[^0-9]+/
206
+ SPLIT_FORMAT = /[^\w%]*%/
177
207
  # Parse date : return an utc date from a string and an strftime format. With the current implementation, you can only use '.', '-', ' ' or ':' to separate the different parts in the format.
178
208
  def to_utc(format, timezone=nil)
179
- elements = split(/(\.|\-|\/|\s|:)+/)
180
- format = format.split(/(\.|\-|\/|\s|:)+/)
209
+ elements = split(SPLIT_STRING)
210
+ format = format.sub('T', ' ').split(SPLIT_FORMAT)[1..-1]
181
211
  if elements
182
212
  hash = {}
183
213
  elements.each_index do |i|
184
214
  hash[format[i]] = elements[i]
185
215
  end
186
- hash['%Y'] ||= hash['%y'] ? (hash['%y'].to_i + 2000) : Time.now.year
187
- hash['%H'] ||= 0
188
- hash['%M'] ||= 0
189
- hash['%S'] ||= 0
190
- if hash['%Y'] && hash['%m'] && hash['%d']
191
- res = Time.utc(hash['%Y'], hash['%m'], hash['%d'], hash['%H'], hash['%M'], hash['%S'])
216
+ hash['Y'] ||= hash['y'] ? (hash['y'].to_i + 2000) : Time.now.year
217
+ hash['H'] ||= 0
218
+ hash['M'] ||= 0
219
+ hash['S'] ||= 0
220
+ if hash['Y'] && hash['m'] && hash['d']
221
+ res = Time.utc(hash['Y'], hash['m'], hash['d'], hash['H'], hash['M'], hash['S'])
192
222
  begin
193
223
  timezone ? timezone.local_to_utc(res, true) : res
194
224
  rescue TZInfo::AmbiguousTime
@@ -247,21 +277,62 @@ module Zena
247
277
  end
248
278
  end
249
279
 
280
+ module TimeMethods
281
+
282
+ def strftime_tz(format, tz = nil)
283
+ if tz.blank?
284
+ tz = visitor.tz
285
+ elsif tz.kind_of?(String)
286
+ tz = TZInfo::Timezone.get(tz)
287
+ end
288
+ tz.utc_to_local(self).strftime(format.to_s)
289
+ rescue TZInfo::InvalidTimezoneIdentifier
290
+ ''
291
+ rescue TZInfo::AmbiguousTime
292
+ ''
293
+ end
294
+ end
295
+
250
296
  module ZafuMethods
251
297
  include RubyLess
252
298
  safe_method_for Time, :year => {:class => Number, :pre_processor => true}
253
- safe_method_for Time, [:strftime, String] => {:class => String, :pre_processor => true}
254
- safe_method :main_date => :get_date
255
- safe_method [:parse_date, String] => {:class => Time, :nil => true, :accept_nil => true}
299
+ safe_method_for Time, [:strftime, String] => {:class => String, :pre_processor => true, :method => 'strftime_tz'}
300
+ safe_method_for Time, [:strftime, String, String] => {:class => String, :pre_processor => true, :method => 'strftime_tz'}
301
+ safe_method_for Time, [:strftime, String, TZInfo::Timezone] => {:class => String, :pre_processor => true, :method => 'strftime_tz'}
302
+ safe_method_for TZInfo::Timezone, :to_s => {:class => String, :pre_processor => true}
303
+
304
+ safe_method :date => :get_date
305
+ safe_method [:date, TZInfo::Timezone] => :get_date
306
+ safe_method :tz => :get_tz
307
+ safe_method [:parse_date, String] => {:class => Time, :nil => true, :accept_nil => true}
308
+ safe_method [:parse_date, String, String] => {:class => Time, :nil => true, :accept_nil => true}
309
+ safe_method [:parse_date, String, String, TZInfo::Timezone] => {:class => Time, :nil => true, :accept_nil => true}
256
310
 
257
311
  def get_date(signature)
258
- if var = get_context_var('set_var', 'main_date')
312
+ if var = get_context_var('set_var', 'date')
259
313
  {:class => var.klass, :method => var, :nil => var.could_be_nil?}
260
314
  else
261
315
  {:class => Time, :method => 'main_date'}
262
316
  end
263
317
  end
264
318
 
319
+ def get_tz(signature)
320
+ if var = get_context_var('set_var', 'tz')
321
+ {:class => var.klass, :method => var, :nil => var.could_be_nil?}
322
+ else
323
+ {:class => TZInfo::Timezone, :method => 'visitor.tz'}
324
+ end
325
+ end
326
+
327
+ def r_default
328
+ if tz_name = @params.delete(:tz)
329
+ set_tz_code, tz_var = set_tz_var(tz_name)
330
+ out set_tz_code
331
+ end
332
+ super
333
+ end
334
+
335
+
265
336
  # date_box seizure setup
266
337
  def r_uses_datebox
267
338
  if ZENA_CALENDAR_LANGS.include?(visitor.lang)
@@ -270,47 +341,88 @@ module Zena
270
341
  l = visitor.site[:default_lang]
271
342
  end
272
343
  <<-EOL
273
- <script src="/calendar/calendar.js" type="text/javascript"></script>
274
- <script src="/calendar/calendar-setup.js" type="text/javascript"></script>
275
- <script src="/calendar/lang/calendar-#{l}-utf8.js" type="text/javascript"></script>
276
- <link href="/calendar/calendar-brown.css" media="screen" rel="Stylesheet" type="text/css" />
344
+ <script src="#{helper.send(:compute_public_path, 'calendar', 'calendar', 'js')}" type="text/javascript"></script>
345
+ <script src="#{helper.send(:compute_public_path, 'calendar-setup', 'calendar', 'js')}" type="text/javascript"></script>
346
+ <script src="#{helper.send(:compute_public_path, "calendar-#{l}-utf8", 'calendar/lang', 'js')}" type="text/javascript"></script>
347
+ <link href="#{helper.send(:compute_public_path, "calendar-brown", 'calendar', 'css')}" media="screen" rel="Stylesheet" type="text/css" />
277
348
  <% js_data << %Q{Calendar._TT["DEF_DATE_FORMAT"] = "#{_('datetime')}";} -%>
278
349
  <% js_data << %Q{Calendar._TT["FIRST_DAY"] = #{_('week_start_day')};} -%>
279
350
  EOL
280
351
  end
281
352
 
282
353
  # Select a date for the current context
283
- def r_main_date
284
- return nil unless code = get_attribute_or_eval
354
+ # FIXME: Remove ? Is this used ?
355
+ # def r_set_main_date
356
+ # return nil unless code = get_attribute_or_eval
357
+ #
358
+ # if format = @params[:format]
359
+ # format = RubyLess.translate_string(self, format)
360
+ # else
361
+ # format = "'%Y-%m-%d %H:%M:%S'"
362
+ # end
363
+ #
364
+ # if code.klass <= String
365
+ # if code.could_be_nil?
366
+ # code = "(#{code} || '').to_utc(#{format})"
367
+ # else
368
+ # code = "#{code}.to_utc(#{format})"
369
+ # end
370
+ # could_be_nil = true
371
+ # elsif code.klass <= Time
372
+ # could_be_nil = code.could_be_nil?
373
+ # else
374
+ # return parser_error("should evaluate to a String or Time (found #{code.klass})")
375
+ # end
376
+ # v = get_var_name('set_var', 'date')
377
+ # out "<% #{v} = #{code} %>"
378
+ # set_context_var('set_var', 'date', RubyLess::TypedString.new(v, :class => Time, :nil => could_be_nil))
379
+ # out expand_with
380
+ # end
285
381
 
286
- if format = @params[:format]
287
- format = RubyLess.translate_string(self, format)
288
- else
289
- format = "'%Y-%m-%d %H:%M:%S'"
382
+ protected
383
+
384
+ def set_tz_var(tz_name)
385
+ tz = TZInfo::Timezone.get(tz_name)
386
+ tz_var = get_var_name('dates', 'tz')
387
+
388
+ set_context_var('set_var', 'tz', RubyLess::TypedString.new(
389
+ tz_var,
390
+ :class => TZInfo::Timezone
391
+ ))
392
+ return "<% #{tz_var} = TZInfo::Timezone.get(#{tz.name.inspect}) %>", tz_var
393
+ rescue TZInfo::InvalidTimezoneIdentifier
394
+ parser_error("Invalid timezone #{tz_name.inspect}.")
290
395
  end
291
396
 
292
- if code.klass <= String
293
- if code.could_be_nil?
294
- code = "(#{code} || '').to_utc(#{format})"
397
+ def show_time(method)
398
+ if tformat = param(:tformat)
399
+ tformat = RubyLess.translate(self, "t(%Q{#{tformat}})")
400
+ method = "#{method}, :format => #{tformat}"
401
+ end
402
+
403
+ if hash_arguments = extract_from_params(:tz, :lang, :format)
404
+ unless @params[:tz]
405
+ # We might have set_tz_var
406
+ if tz = get_context_var('set_var', 'tz')
407
+ if tz.klass <= TZInfo::Timezone || tz.klass <= String
408
+ hash_arguments << ":tz => #{tz}"
409
+ end
410
+ end
411
+ end
412
+ "<%= format_date(#{method}, #{hash_arguments.join(', ')}) %>"
413
+ elsif tformat
414
+ "<%= format_date(#{method}) %>"
295
415
  else
296
- code = "#{code}.to_utc(#{format})"
416
+ "<%= #{method} %>"
297
417
  end
298
- could_be_nil = true
299
- elsif code.klass <= Time
300
- could_be_nil = code.could_be_nil?
301
- else
302
- return parser_error("should evaluate to a String or Time (found #{code.klass})")
303
418
  end
304
- v = get_var_name('set_var', 'main_date')
305
- out "<% #{v} = #{code} %>"
306
- set_context_var('set_var', 'main_date', RubyLess::TypedString.new(v, :class => Time, :nil => could_be_nil))
307
- out expand_with
308
- end
309
-
310
- end
419
+ end # ZafuMethods
311
420
  end # Dates
312
421
  end # Use
313
422
  end # Zena
314
423
 
315
424
  # FIXME: where should we put this ?
316
425
  String.send(:include, Zena::Use::Dates::StringMethods)
426
+
427
+ # FIXME: where should we put this ?
428
+ Time.send(:include, Zena::Use::Dates::TimeMethods)
@@ -255,28 +255,28 @@ module Zena
255
255
  link_to_with_state(_('preferences'), preferences_user_path(visitor[:id]))
256
256
  when 'comments'
257
257
  return nil unless visitor.is_admin?
258
- link_to_with_state(_('manage comments'), comments_path)
258
+ link_to_with_state(_('comments'), comments_path)
259
259
  when 'users'
260
260
  return nil unless visitor.is_admin?
261
- link_to_with_state(_('manage users'), users_path)
261
+ link_to_with_state(_('users'), users_path)
262
262
  when 'groups'
263
263
  return nil unless visitor.is_admin?
264
- link_to_with_state(_('manage groups'), groups_path)
264
+ link_to_with_state(_('groups'), groups_path)
265
265
  when 'relations'
266
266
  return nil unless visitor.is_admin?
267
- link_to_with_state(_('manage relations'), relations_path)
267
+ link_to_with_state(_('relations'), relations_path)
268
268
  when 'virtual_classes'
269
269
  return nil unless visitor.is_admin?
270
- link_to_with_state(_('manage classes'), virtual_classes_path)
270
+ link_to_with_state(_('classes'), virtual_classes_path)
271
271
  when 'properties'
272
272
  return nil unless visitor.is_admin?
273
- link_to_with_state(_('manage properties'), columns_path)
273
+ link_to_with_state(_('properties'), columns_path)
274
274
  when 'iformats'
275
275
  return nil unless visitor.is_admin?
276
276
  link_to_with_state(_('image formats'), iformats_path)
277
277
  when 'sites'
278
278
  return nil unless visitor.is_admin?
279
- link_to_with_state(_('manage sites'), sites_path)
279
+ link_to_with_state(_('sites'), sites_path)
280
280
  when 'dev'
281
281
  return nil unless visitor.is_admin?
282
282
  if visitor.dev_skin_id
@@ -394,7 +394,7 @@ module Zena
394
394
 
395
395
  safe_method [:zazen, String] => :r_zazen
396
396
 
397
- # As a last resort, if the method cannot be compilated, use <r:show eval='...'/>
397
+ # As a last resort, if the method does not compile try to use <r:show eval='...'/>
398
398
  def self.included(base)
399
399
  base.process_unknown :show_eval
400
400
  end
@@ -429,28 +429,31 @@ module Zena
429
429
  else
430
430
  nil
431
431
  end
432
- elsif node = node(Node)
432
+ else
433
+ node = node(Node) || '@node'
433
434
  return nil unless attribute = get_attribute_or_eval
434
435
  hash_arguments = extract_from_params(:code) || []
435
436
 
436
437
  hash_arguments.insert(0, ":node => #{node}")
437
438
 
438
439
  "<%= zazen(#{attribute}, #{hash_arguments.join(', ')}) %>"
439
- else
440
- parser_error("Cannot access 'Node' context")
441
440
  end
442
441
  end
443
442
 
444
443
  # Display an attribute or RubyLess code
445
444
  def r_show(code = nil)
446
- if node.list_context?
445
+ if code.nil? && node.list_context?
447
446
  @context[:node] = node.move_to("#{node}.first", node.klass.first, :query => node.opts[:query])
448
447
  return r_show
449
- elsif node.will_be?(String)
450
- return "<%= #{node} %>"
451
448
  end
452
449
 
453
- return nil unless method = code || get_attribute_or_eval
450
+ if method = code || get_attribute_or_eval(false)
451
+ # ok
452
+ elsif node.will_be?(String) || node.will_be?(Time)
453
+ method = RubyLess.translate(self, 'this')
454
+ else
455
+ return nil
456
+ end
454
457
 
455
458
  klass = method.klass
456
459
 
@@ -466,24 +469,24 @@ module Zena
466
469
  res = show_string(method)
467
470
  end
468
471
 
469
- res = extract_label(res, @params, @params[:attr])
472
+ res = extract_label(res, @params[:attr])
470
473
 
471
- if @params[:blank] == 'hide'
474
+ if param(:blank) == 'hide'
472
475
  "<% if !#{method}.blank? %>#{@markup.wrap(res)}<% end %>"
473
476
  else
474
477
  res
475
478
  end
476
479
  end
477
480
 
478
- def extract_label(res, params, attribute)
479
- if (label = params[:label] || params[:tlabel]) && attribute
481
+ def extract_label(res, attribute)
482
+ if (label = param(:label) || param(:tlabel)) && attribute
480
483
  case label
481
484
  when 'true'
482
485
  "<label>#{attribute}</label> <span>#{res}</span>"
483
486
  when 't'
484
487
  "<label>#{trans(attribute)}</label> <span>#{res}</span>"
485
488
  else
486
- if params[:tlabel]
489
+ if @params[:tlabel]
487
490
  code = ::RubyLess.translate(self, "t(%Q{#{label}})")
488
491
  else
489
492
  code = ::RubyLess.translate_string(self, label)
@@ -511,7 +514,44 @@ module Zena
511
514
  else
512
515
  list = @params[:list].split(',').map{|e| e.strip}
513
516
  end
514
- helper.javascript_include_tag(*list)
517
+
518
+ out helper.javascript_include_tag(*list)
519
+ return
520
+ # Experimental: move all scripts at end of file
521
+ if list.include?('prototype')
522
+ list -= ['prototype']
523
+ out helper.javascript_include_tag('prototype')
524
+ end
525
+ return if list.empty?
526
+
527
+ list = list.map do |e|
528
+ "Script.load('#{helper.javascript_path(e)}');"
529
+ end
530
+ code = %Q{ var Script = {
531
+ _loadedScripts: [],
532
+ load: function(script){
533
+ if (this._loadedScripts.include(script)){
534
+ return false;
535
+ }
536
+ var code = new Ajax.Request(script, {
537
+ asynchronous: false, method: "GET",
538
+ evalJS: false, evalJSON: false
539
+ }).transport.responseText;
540
+ if (Prototype.Browser.IE) {
541
+ window.execScript(code);
542
+ } else if (Prototype.Browser.WebKit){
543
+ $$("head").first().insert(Object.extend(
544
+ new Element("script", {type: "text/javascript"}), {text: code}
545
+ ));
546
+ } else {
547
+ window.eval(code);
548
+ }
549
+ this._loadedScripts.push(script);
550
+ }
551
+ };
552
+ #{list.join("\n ")}
553
+ }
554
+ out "<% js_data.unshift #{code.inspect} -%>"
515
555
  end
516
556
 
517
557
  # Insert stylesheet asset tags
@@ -613,17 +653,17 @@ module Zena
613
653
  return parser_error("not in a list context") unless node.list_context?
614
654
  return parser_error("not a Node list") unless node.single_class <= Node
615
655
  klass = "#{node.single_class.name}"
616
- @blocks = [make(:void, :method => 'void', :text => %Q{<table class='grid'>
656
+ add_block %Q{<table class='grid'>
617
657
  <tr do='#{klass}' do='roles'><th class='role' colspan='\#{columns.size}' do='each' do='name'/></tr>
618
658
  <tr do='#{klass}' do='roles' do='each' do='columns'><th do='each' do='name'/></tr>
619
659
  <tr do='each'><r:#{klass} do='roles' do='each' do='columns'><td do='each' do='@node.send(name)'/></r:#{klass}></tr>
620
- </table>})]
660
+ </table>}
621
661
  expand_with
622
662
  end
623
663
 
624
664
  private
625
665
  def show_number(method)
626
- if fmt = @params[:format]
666
+ if fmt = param(:format)
627
667
  begin
628
668
  # test argument
629
669
  sprintf(fmt, 123.45)
@@ -639,7 +679,7 @@ module Zena
639
679
  modifier = ''
640
680
  end
641
681
 
642
- if @params[:zero] == 'hide'
682
+ if param(:zero) == 'hide'
643
683
  "<%= sprintf_unless_zero(#{fmt.inspect}, #{method}#{modifier}) %>"
644
684
  else
645
685
  "<%= sprintf(#{fmt.inspect}, #{method}#{modifier}) %>"
@@ -650,23 +690,14 @@ module Zena
650
690
  end
651
691
 
652
692
  def show_string(method)
653
- "<%= #{method} %>"
654
- end
655
-
656
- def show_time(method)
657
- if tformat = @params.delete(:tformat)
658
- tformat = RubyLess.translate(self, "t(%Q{#{tformat}})")
659
- method = "#{method}, :format => #{tformat}"
660
- end
661
-
662
- if hash_arguments = extract_from_params(:tz, :lang, :format)
663
- "<%= format_date(#{method}, #{hash_arguments.join(', ')}) %>"
664
- elsif tformat
665
- "<%= format_date(#{method}) %>"
666
- else
693
+ if param(:h) == 'false'
667
694
  "<%= #{method} %>"
695
+ else
696
+ "<%= h #{method} %>"
668
697
  end
669
698
  end
699
+
700
+ # show_time is in Dates
670
701
  end
671
702
  end # Display
672
703
  end # Use
@@ -5,10 +5,8 @@ module Zena
5
5
 
6
6
  #TODO: test
7
7
  def error_messages_for(type, opts={})
8
- super unless type == 'node'
9
-
10
8
  obj = opts[:object]
11
- return '' if obj.errors.empty?
9
+ return '' if !obj || obj.errors.empty?
12
10
  res = ["<table class='#{opts[:class] || 'errors'}'>"]
13
11
  obj.errors.each_error do |er,msg|
14
12
  res << "<tr><td><b>#{er}</b></td><td>#{_(msg)}</td></tr>"
@@ -10,7 +10,10 @@ module Zena
10
10
  end
11
11
 
12
12
  def property_field_index
13
- if version.status == Zena::Status[:pub]
13
+ # Better rule
14
+ if new_record? ||
15
+ version.status == Zena::Status[:pub] ||
16
+ versions.count == 1
14
17
  super
15
18
  end
16
19
  end