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
@@ -1227,7 +1227,7 @@ var Windows = {
1227
1227
  modalWindows: [],
1228
1228
  observers: [],
1229
1229
  focusedWindow: null,
1230
- maxZIndex: 0,
1230
+ maxZIndex: 100,
1231
1231
  overlayShowEffectOptions: {duration: 0.5},
1232
1232
  overlayHideEffectOptions: {duration: 0.5},
1233
1233
 
@@ -30,7 +30,7 @@ Zena.open_window = function(url, id, event, pos_x, pos_y) {
30
30
  }
31
31
  // edit window, not in an iframe
32
32
  if (event && (event == true || event.shiftKey || (window == window.parent && window.current_sel))) {
33
- var popup = window.open(url, name, 'location=0,width=300,height=400,resizable=1');
33
+ var popup = window.open(url, id, 'location=0,width=300,height=400,resizable=1');
34
34
  if (pos_x && pos_y) {
35
35
  popup.moveTo(pos_x, pos_y);
36
36
  } else {
@@ -59,13 +59,8 @@ Zena.open_window = function(url, id, event, pos_x, pos_y) {
59
59
  pos_y = 0;
60
60
  }
61
61
  } else {
62
- if (Zena.window_offset) {
63
- Zena.window_offset = Zena.window_offset + 15;
64
- } else {
65
- Zena.window_offset = 15;
66
- }
67
- pos_x = Zena.window_offset;
68
- pos_y = Zena.window_offset;
62
+ pos_x = event.x - 12;
63
+ pos_y = event.y - 12;
69
64
  }
70
65
 
71
66
  var win = new Window({
@@ -93,7 +88,13 @@ Zena.open_window = function(url, id, event, pos_x, pos_y) {
93
88
  Zena.editor_preview = function(url, element, value) {
94
89
  var key = element.name;
95
90
  var full_url = url + '?key=' + key.slice(5, key.length - 1);
96
- new Ajax.Request(full_url, {method:'get', asynchronous:true, evalScripts:true, parameters:{content: value }});
91
+ new Ajax.Request(full_url, {
92
+ // value too large for get.
93
+ method:'post',
94
+ asynchronous:true,
95
+ evalScripts:true,
96
+ parameters:{content: value}
97
+ });
97
98
  }
98
99
 
99
100
  // preview version.
@@ -654,11 +655,7 @@ Zena.popup_keydown = function(evt) {
654
655
  var gallery = Zena.popup_gallery;
655
656
 
656
657
  var code = evt.keyCode;
657
- //if (!e) var e = window.event;
658
- //if (e.keyCode) code = e.keyCode;
659
- //else if (e.which) code = e.which;
660
658
  var character = String.fromCharCode(code);
661
- //alert('Character was ' + character);
662
659
 
663
660
  if (code == Event.KEY_LEFT) {
664
661
  if (gallery.prev) {
@@ -720,7 +717,6 @@ Zena.popup = function(elem) {
720
717
  Event.observe(document.body, 'keydown', function(e) {
721
718
  var evt = e || window.event;
722
719
  $('pg_info').innerHTML = evt.keyCode;
723
- //alert('key :' + evt.keyCode);
724
720
  });
725
721
  }
726
722
  if (!this.popup_gallery || this.popup_gallery.klass != config.klass) {
@@ -875,7 +871,8 @@ Zena.toggle = function(elem, definition, id) {
875
871
  onSuccess: function() {
876
872
  definition['list'] = definition['list'].without(id);
877
873
  Zena.set_toggle(elem.id, definition);
878
- }
874
+ if (definition['js']) definition['js'](elem);
875
+ }
879
876
  });
880
877
  } else {
881
878
  // turn on
@@ -885,8 +882,21 @@ Zena.toggle = function(elem, definition, id) {
885
882
  evalScripts:true,
886
883
  parameters: 'node[' + definition['role'] + '_id]=' + id,
887
884
  onSuccess: function() {
885
+ if (definition['arity'] == 'one') {
886
+ // uncheck all
887
+ definition['list'] = {};
888
+ // search for siblings
889
+ elem.siblings().each(function(s) {
890
+ try {
891
+ s.select('input.cb')[0].checked = false;
892
+ s.removeClassName('on');
893
+ s.addClassName('off');
894
+ } catch (err) {}
895
+ });
896
+ }
888
897
  definition['list'].push(id);
889
898
  Zena.set_toggle(elem.id, definition);
899
+ if (definition['js']) definition['js'](elem);
890
900
  }
891
901
  });
892
902
  }
@@ -904,8 +914,8 @@ Zena.m_toggle = function(id) {
904
914
 
905
915
  var pm_counter = 1;
906
916
  Zena.plus_minus = function(elem, start, plus, minus) {
907
- plus = plus == undefined ? '[+]' : plus;
908
- minus = minus == undefined ? '[-]' : minus;
917
+ var plus = plus == undefined ? '[+]' : plus;
918
+ var minus = minus == undefined ? '[-]' : minus;
909
919
 
910
920
  var tag = elem.tagName;
911
921
  pm_counter = pm_counter + 1;
@@ -913,12 +923,15 @@ Zena.plus_minus = function(elem, start, plus, minus) {
913
923
  var show = start == 'on' ? 'display:none;' : '';
914
924
  var hide = start == 'on' ? '' : 'display:none;';
915
925
  var trigger_tag = " <a id='off_"+id+"' style='"+show+"' onclick='Zena.m_toggle(\"" + id +"\")' class='plus_btn'>"+plus+"</a><a id='on_"+id+"' style='"+hide+"' onclick='Zena.m_toggle(\"" + id +"\")' class='minus_btn'>"+minus+"</a>";
916
- var new_tag = "<"+tag+" style='"+hide+"' id='txt_"+id+"' class='txt" + ' ' + elem.className + "'>" + elem.innerHTML + "</"+tag+">";
917
926
  if (tag.toUpperCase() == 'SPAN' || !elem.previous()) {
918
- Element.replace(elem, trigger_tag + ' ' + new_tag);
927
+ Element.insert(elem, {before:trigger_tag});
919
928
  } else {
920
929
  Element.insert(elem.previous(), {bottom:trigger_tag});
921
- Element.replace(elem, new_tag);
930
+ }
931
+ elem.addClassName('txt')
932
+ elem.id = 'txt_'+id
933
+ if (start != 'on') {
934
+ elem.setStyle({display:'none'})
922
935
  }
923
936
  }
924
937
 
@@ -954,4 +967,100 @@ Zena.insert_inner = function(dom, position, content) {
954
967
  var insertions = {};
955
968
  insertions[position] = d.childElements()[0].innerHTML;
956
969
  Element.insert(dom, insertions);
957
- }
970
+ }
971
+
972
+ Zena.prepare_query = function(data, base, res) {
973
+ var res = res || {}
974
+ // transform {node:{a:'b'}} into {'node[a]':'b'}
975
+ $H(data).each(function(pair) {
976
+ var key = pair.key
977
+ var val = pair.value
978
+ if (base) {
979
+ key = base+'['+key+']'
980
+ }
981
+ if (typeof(val) == 'object') {
982
+ Zena.prepare_query(val, key, res)
983
+ } else {
984
+ res[key] = val
985
+ }
986
+ })
987
+ return res
988
+ }
989
+
990
+ Zena.do = function(method, dom, query) {
991
+ var dom = $(dom)
992
+
993
+ var zip
994
+ if (typeof(query) == 'string') {
995
+ query = {id:query}
996
+ }
997
+ if (query.id) {
998
+ zip = query.id
999
+ delete query.id
1000
+ } else {
1001
+ zip = dom.getAttribute('data-z')
1002
+ }
1003
+
1004
+ var url
1005
+ if (method == 'get') {
1006
+ url = '/nodes/' + zip + '/zafu'
1007
+ } else if (method == 'post') {
1008
+ url = '/nodes'
1009
+ } else {
1010
+ // put
1011
+ url = '/nodes/' + zip
1012
+ }
1013
+
1014
+ if (Object.prototype.toString.apply(query) === '[object Array]') {
1015
+ var list = query
1016
+ var todo = list.length
1017
+ for (var i=0; i < list.length; i++) {
1018
+ new Ajax.Request(url, {
1019
+ method:method,
1020
+ parameters:Zena.prepare_query(list[i]),
1021
+ asynchronous:true,
1022
+ onSuccess: function() {
1023
+ todo--;
1024
+ if (todo == 0) {
1025
+ Zena.reload(dom)
1026
+ }
1027
+ },
1028
+ onFailure: function() {
1029
+ alert("Could not "+method+" "+Object.toJSON(query))
1030
+ }
1031
+ });
1032
+ }
1033
+ } else {
1034
+ query.dom_id = dom.id
1035
+ if (!query.s) query.s = $(document.body).getAttribute('data-z')
1036
+ if (!query.t_url) query.t_url = $(document.body).getAttribute('data-t') + '/' + (dom.getAttribute('data-t') || dom.id)
1037
+ new Ajax.Request(url, {
1038
+ method:method,
1039
+ parameters:Zena.prepare_query(query),
1040
+ asynchronous:true,
1041
+ evalScripts:true,
1042
+ });
1043
+ }
1044
+ }
1045
+
1046
+ Zena.get = function(dom_name, query) {
1047
+ Zena.do('get', dom_name, query || {});
1048
+ return false;
1049
+ }
1050
+ Zena.reload = Zena.get;
1051
+
1052
+ Zena.put = function(dom_name, query) {
1053
+ Zena.do('put', dom_name, query || {});
1054
+ return false;
1055
+ }
1056
+
1057
+ Zena.post = function(dom_name, query) {
1058
+ Zena.do('post', dom_name, query || {});
1059
+ return false;
1060
+ }
1061
+
1062
+ Zena.loading = function(e) {
1063
+ e.addClassName('zloading')
1064
+ }
1065
+
1066
+
@@ -2,9 +2,12 @@
2
2
  .grid tr.action td {border-width:0 0 1px 0; font-size:70%}
3
3
  .grid tr.action td.action {border:0}
4
4
  .grid td.input, .grid th.input { padding:0;}
5
- .grid td.input input, .grid th.input input { margin:0; padding:0;font-size:inherit;}
6
- .grid td.changed {background:#E5DDD7}
5
+ .grid .input input, .grid .input textarea { margin:0; padding:0;font-size:inherit;}
6
+ .grid td.changed, .grid .new td.changed {background:#E5DDD7}
7
+ .grid .new td {background:#B2DFEE}
8
+ .grid .new td.action {background:none}
7
9
  .grid .saved { background:#A3FF4F}
10
+ .grid td.error, .grid tr.error td { background:#FFB6C1; border-color:red}
8
11
  .grid td.undone, .grid td.changed.undone, .grid th.undone, .grid th.changed.undone { background:#F3F07F}
9
12
  .grid .action span {cursor:pointer; visibility:hidden;}
10
13
  .grid:hover .action span {visibility:visible;}
@@ -16,4 +19,10 @@
16
19
  .grid_btn {margin:1em 0}
17
20
  .grid_btn a.save {background:#80B62D}
18
21
  .grid_btn a.undo {background:#AAB76D}
22
+ .grid_msg {border:1px solid #888; background:#eee; border-radius:4px; padding:5px; display:table}
19
23
 
24
+ .tags li {border-radius:2px; background:#ccc url('/images/remove_tag.png') no-repeat; padding:2px 5px 2px 15px; margin:3px; display:inline; background-position:2px 4px}
25
+ .tags li.add {background:#8c8 url('/images/add.png') no-repeat;background-position:1px 2px}
26
+
27
+ .grid .asc {background:#7b7}
28
+ .grid .desc {background:#fa0}
@@ -59,7 +59,7 @@ table.errors td { padding:2px 5px; background:inherit; border:none;}
59
59
 
60
60
  /* dev */
61
61
  .devb, #dev { background:#eee; font-size:10px;
62
- padding:5px; border:2px solid #222; text-align:left; color:#444; z-index:9999; border-width:2px 0 0 2px;}
62
+ padding:5px; border:2px solid #222; text-align:left; color:#444; z-index:100; border-width:2px 0 0 2px;}
63
63
  #dev { position:fixed; bottom:0px; right:0px;}
64
64
  .devb a { color:inherit; }
65
65
  .devb ul, .devb li { margin:0; padding:0; list-style:none; background:none; list-style-image:none;}
@@ -87,3 +87,4 @@ ins.differ, ins.differ * { background:#cfc; text-decoration:none; padding:1px 2p
87
87
  #pg_info a { width:100px; height:40px;}
88
88
  #pg_next {position:absolute; right:0; background:url('/images/popup_next.png?1276089554') no-repeat right top;}
89
89
  #pg_prev {position:absolute; left:0; background:url('/images/popup_prev.png?1276089554') no-repeat left top;}
90
+ .zloading {opacity:0.4}
@@ -63,7 +63,12 @@ Node:
63
63
  - courses.custom_a AS repeat_every
64
64
  - form.last_date AS last_date
65
65
  - form.last_date + INTERVAL courses.custom_a MONTH AS next_date
66
+ # Current hack to properly cast values to Time during read
67
+ - form.last_date + INTERVAL courses.custom_a MONTH AS idx_datetime1
66
68
  - MAX(IF(assigned_pages.custom_a,assigned_pages.custom_a,5)) AS priority
69
+ types:
70
+ next_date: time
71
+ last_date: time
67
72
  tables:
68
73
  - nodes AS courses
69
74
  # assigned to
@@ -63,6 +63,16 @@
63
63
  </table>
64
64
  </div>
65
65
 
66
+ <div class='test' id='destroy1' do='selenium'>
67
+ <h3>destroy1</h3>
68
+ <p>Using "action='destroy'" to remove elements.</p>
69
+ <ul id='destroy_list' do='block' do='projects in site'>
70
+ <li do='add' klass='Project' after='self'/>
71
+ <li do='form'><r:input name='title'/></li>
72
+ <li class='#{title}' do='each'><r:link/> <span id='destroy_#{title}' do='link' action='destroy' update='destroy_list' do='t'>destroy</span></li>
73
+ </ul>
74
+ </div>
75
+
66
76
  <div class='test' id='edit1' do='selenium'>
67
77
  <h3>edit1</h3>
68
78
  <p>Edit in place, form built from block.</p>
@@ -162,6 +172,18 @@
162
172
  </ul>
163
173
  </div>
164
174
 
175
+ //! toggle2
176
+ <div class='test' id='toggle2' do='selenium'>
177
+ <h3>toggle2</h3>
178
+ <p>Toggle with js. <span id='toggle2_count' do='block'>toggle2_count=<r:references find='count'/></span></p>
179
+ <ul class='references' do='references'>
180
+ <li do='each' do='title'/>
181
+ </ul>
182
+ <ul do='projects in site'>
183
+ <li do='each' toggle='reference' for='start' js='Zena.reload("toggle2_count")' do='title'/>
184
+ </ul>
185
+ </div>
186
+
165
187
  <div class='test' id='paginate1' do='selenium'>
166
188
  <h3>paginate1</h3>
167
189
  <p>Ajax pagination.</p>
@@ -240,6 +262,20 @@
240
262
  </r:form>
241
263
  </div>
242
264
 
265
+ //! form4
266
+ <div class='test' id='form4' do='selenium'>
267
+ <h3>form4</h3>
268
+ <p>Form to update hash property.</p>
269
+ <p id='form4_one' do='settings["one"]'/>
270
+ <p id='form4_two' do='settings["two"]'/>
271
+ <r:form node[v_status]='50'>
272
+ <ul>
273
+ <li><r:input label='t' name='settings[two]'/></li>
274
+ <li><r:input type='submit'/></li>
275
+ </ul>
276
+ </r:form>
277
+ </div>
278
+
243
279
  <div class='test' id='drop1' do='selenium'>
244
280
  <h3>drop1</h3>
245
281
  <p>Create a relation by drag and dropping.</p>
@@ -376,7 +376,6 @@ class NodesControllerTest < Zena::Controller::TestCase
376
376
  end
377
377
  end # by changing a link comment
378
378
 
379
-
380
379
  context 'by changing a link date' do
381
380
  subject do
382
381
  {:action => 'update', :controller => 'nodes', :id => nodes_zip(:opening), :node => {:link_id => links_id(:opening_in_art), :l_date => '2011-03-29 17:51'}}
@@ -416,7 +415,25 @@ class NodesControllerTest < Zena::Controller::TestCase
416
415
  end # with a bad value
417
416
 
418
417
  end # by changing skin
418
+
419
+ context 'by changing a hash value' do
420
+ setup do
421
+ Column.create(:role_id => roles_id(:Task), :ptype => 'hash', :name => 'foo')
422
+ end
423
+
424
+ subject do
425
+ {:action => 'update', :controller => 'nodes', :id => nodes_zip(:people), :node => {:foo => {:bar => 'hello'}}}
426
+ end
419
427
 
428
+ should 'change parameter' do
429
+ put_subject
430
+ node = secure(Node) { nodes(:people) }
431
+ foo = node.foo
432
+ assert_equal 'hello', foo['bar']
433
+ # Should not raise cast error
434
+ assert node.update_attributes('title' => 'pep')
435
+ end
436
+ end
420
437
  end # updating a node
421
438
 
422
439
  # ======================================= Template update
@@ -69,7 +69,7 @@ action:
69
69
  swap:
70
70
  src: "<span do='block' do='swap' attr='weight' states='100,-100' do='weight'/>"
71
71
  tem: '/:dom_id => %Q\{list1\}, :t_url => "action/swap/list1"/'
72
- '/action/swap/en/list1.erb': "/<span id='<%= ndom_id\(@node\) %>'>/"
72
+ '/action/swap/en/list1.erb': "/<span .*id='<%= ndom_id\(@node\) %>'/"
73
73
 
74
74
  swap_with_params:
75
75
  src: "<span do='block' do='swap' node[origin]='%{me}' attr='weight' states='100,-100' do='weight'/>"
@@ -86,7 +86,7 @@ swap_in_each:
86
86
 
87
87
  swap_in_each_with_block:
88
88
  src: "<r:pages in='site limit 2'><li do='each'><p do='block'><span do='swap' publish='true' attr='origin' states='todo,done,alert'/></p></li></r:pages>"
89
- res: "/<p id='list2_29'>.*list2_29.*<p id='list2_33'>.*list2_33/"
89
+ res: "/<p .*id='list2_29'.*>.*list2_29.*<p .*id='list2_33'.*>.*list2_33/"
90
90
 
91
91
  hand_made_swap:
92
92
  src: "<r:link update='_page' node[origin]='next_in_list(origin, \"todo,done\")' action='update'/>"
@@ -6,13 +6,13 @@ default:
6
6
 
7
7
  block:
8
8
  src: "<r:parent><r:block name='foobar' do='title'/></r:parent>"
9
- tem: "<% if var1 = @node.parent %><div id='foobar'><%= var1.prop['title'] %></div><% end %>"
10
- 'ajax/block/en/foobar.erb': "<div id='<%= ndom_id(@node) %>'><%= @node.prop['title'] %></div>"
9
+ tem: "<% if var1 = @node.parent %><div id='foobar' data-z='<%= var1.zip %>'><%= var1.prop['title'] %></div><% end %>"
10
+ 'ajax/block/en/foobar.erb': "<div id='<%= ndom_id(@node) %>' data-z='<%= @node.zip %>'><%= @node.prop['title'] %></div>"
11
11
 
12
12
  add:
13
13
  src: "<ul id='children' do='nodes'><li do='each' do='link'/><li do='add'/></ul>"
14
14
  tem: "/\[\"children_add\", \"children_0\"\].each\(Element.toggle\)/"
15
- 'ajax/add/en/children_form.erb': "/class='form' id='<%= ndom_id\(@node\) %>'/"
15
+ 'ajax/add/en/children_form.erb': "/class='form' .*id='<%= ndom_id\(@node\) %>'/"
16
16
  'ajax/add/en/children.erb': "<li id='<%= ndom_id(@node) %>'><a href='<%= zen_path(@node) %>'><%= @node.prop['title'] %></a></li>"
17
17
 
18
18
  edit_not_each:
@@ -24,6 +24,12 @@ edit_in_block:
24
24
  res: "/Ajax.Request\(\"/nodes/22/zafu\?dom_id=list1&"
25
25
  'ajax/edit/in/block/en/list1_form.erb': "/f.text_field :title.*alt='cancel/"
26
26
 
27
+ block_in_block:
28
+ src: "<div do='block' name='a'>A:<r:root do='link' update='a'/><r:filter live='true' update='b'/><div do='block' name='b'>B:</div></div>"
29
+ # Make sure the correct template is built, not a2 or something.
30
+ 'ajax/block/in/block/en/a.erb': "/A:/"
31
+ 'ajax/block/in/block/en/b.erb': "/B:/"
32
+
27
33
  edit_in_block_publish:
28
34
  src: "<li do='block'><r:title/> <r:edit publish='true'/></li>"
29
35
  res: "/Ajax.Request\(\"/nodes/22/zafu\?dom_id=list1/"
@@ -55,7 +61,7 @@ form_update:
55
61
  add_each_no_form:
56
62
  src: "<ul do='children' id='things'><li do='each'>I <p do='title'>blah</p></li><li do='add'/></ul>"
57
63
  tem: "!/</ul><ul></ul>/" # bug in closing group with [add].
58
- res: "/<ul><li.*id='things_add'.*li.*class='form' id='things_0'.*form.*I <p><input id=.things_title. name=.node\[title\]. .*type=.text..*hidden/"
64
+ res: "/<ul><li.*id='things_add'.*li.*class='form' .*id='things_0'.*form.*I <p><input id=.things_title. name=.node\[title\]. .*type=.text..*hidden/"
59
65
 
60
66
  add_each_no_form_date:
61
67
  src: "<ul do='children' id='things'><li do='each'>I <p do='show' attr='event_at' tformat='short_date'>blah</p></li><li do='add'/></ul>"
@@ -74,7 +80,7 @@ each_add_with_form:
74
80
  <li do='add'>add new</li>
75
81
  <li do='form'><input name='title'/> this is the form</li>
76
82
  </ol>
77
- res: "/<li id='list1_30'>bird.*<li id='list1_31'>flower.*<li.*list1_add.*list1_0.*toggle.*<li style.*none.*list1_0.*Ajax.Request.*input type='hidden' name='t_url' value=.ajax/each/add/with/form/list1.*input type='hidden' name='node\[parent_id\]' value=.29./"
83
+ res: "/<li id='list1_30'>bird.*<li id='list1_31'>flower.*<li.*list1_add.*list1_0.*toggle.*<li.*style.*none.*list1_0.*Ajax.Request.*input type='hidden' name='t_url' value=.ajax/each/add/with/form/list1.*input type='hidden' name='node\[parent_id\]' value=.29./"
78
84
 
79
85
  each_add_with_form_in_sub_block:
80
86
  context:
@@ -177,24 +183,24 @@ live_filter:
177
183
  src: "<r:filter live='true'/><r:block><ol do='pages where title like \"#{params[:f]}%\"'><li do='each' do='title'/></ol></r:block>"
178
184
  # Make sure a unique_name is set for the given block
179
185
  tem: "/name='t_url' value='ajax/live/filter/list1'.*<% filter_form\(@node.*ml1.value LIKE \?.*, \"#\{params\[:f\]\}%\"/"
180
- 'ajax/live/filter/en/list1.erb': "/<div id='<%= ndom_id\(@node\).*, \"#\{params\[:f\]\}%\".*var2.prop\['title'\]/"
181
- res: "/<input type='text' name='f'.*<div id='list1'><ol><li>crocodiles</li><li>status title</li></ol></div>/"
186
+ 'ajax/live/filter/en/list1.erb': "/<div .*id='<%= ndom_id\(@node\).*, \"#\{params\[:f\]\}%\".*var2.prop\['title'\]/"
187
+ res: "/<input type='text' name='f'.*<div .*id='list1'.*><ol><li>crocodiles</li><li>status title</li></ol></div>/"
182
188
 
183
189
  live_filter_single_element:
184
190
  context:
185
191
  node: cleanWater
186
192
  src: "<r:filter live='true'/><r:block><r:page where='title like \"#{params[:f]}%\"' find='first'><b do='title'/></r:page></r:block>"
187
193
  tem: "/, \"#\{params\[:f\]\}%\"/"
188
- 'ajax/live/filter/single/element/en/list1.erb': "/<div id=.*params\[:f\].*var1.prop\['title'\]/"
189
- res: "/<input type='text' name='f'.*<div id='list1'><b>crocodiles</b></div>/"
194
+ 'ajax/live/filter/single/element/en/list1.erb': "/<div .*id=.*params\[:f\].*var1.prop\['title'\]/"
195
+ res: "/<input type='text' name='f'.*<div .*id='list1'.*><b>crocodiles</b></div>/"
190
196
 
191
197
  live_filter_select_options:
192
198
  context:
193
199
  node: cleanWater
194
200
  src: "<r:filter live='true' do='select' param='f' tprefix='foo' values='1,2'/><r:block><ol do='pages where title like \"#{params[:f]}%\"'><li do='each' do='title'/></ol></r:block>"
195
201
  tem: "/select name=.f.><%= options_for_select.*.foo_1., .1..*, param_value\(.f.\).to_s/"
196
- 'ajax/live/filter/select/options/en/list1.erb': "/<div id='<%= ndom_id\(@node\) %>'.*params\[:f\]/"
197
- res: "/<select name='f'.*<div id='list1'><ol><li>crocodiles</li><li>status title</li></ol></div>/"
202
+ 'ajax/live/filter/select/options/en/list1.erb': "/<div .*id='<%= ndom_id\(@node\) %>'.*params\[:f\]/"
203
+ res: "/<select name='f'.*<div .*id='list1'.*><ol><li>crocodiles</li><li>status title</li></ol></div>/"
198
204
 
199
205
  draggable_do_syntax:
200
206
  src: "<r:images in='site' do='each' draggable='all' do='img' mode='pv'/>"
@@ -220,7 +226,7 @@ drag_with_form:
220
226
  <td class='edit'> <r:edit class='edit'>éditer</r:edit></td>
221
227
  </tr>
222
228
  </table>"
223
- tem: "/<span class='drag' id='<%= %Q\{list3_#\{var2.zip\}\}.*<% add_drag_id\(%Q\{list3_#\{var2.zip\}\}/"
229
+ tem: "/<span class='drag' id='<%= %Q\{list2_#\{var2.zip\}\}.*<% add_drag_id\(%Q\{list2_#\{var2.zip\}\}/"
224
230
 
225
231
  drag_with_form_not_in_form:
226
232
  src: "<table do='pages in site'>
@@ -255,7 +261,7 @@ draggable_in_block:
255
261
  # should use 'hooba' class
256
262
  src: "<r:block><r:link draggable='hooba'/></r:block>"
257
263
  tem: "/add_drag_id\(%Q\{drag_\#\{@node.zip\}\}, .*hooba/"
258
- res: "<div id='list1'><span class='drag' id='drag_22'><span class='hooba'>&nbsp;</span><a href='/oo/projects-list/Clean-Water-project/page22.html'>status title</a></span></div>"
264
+ res: "<div id='list1' data-z='22'><span class='drag' id='drag_22'><span class='hooba'>&nbsp;</span><a href='/oo/projects-list/Clean-Water-project/page22.html'>status title</a></span></div>"
259
265
  js: "/Zena.draggable\(item, \"hooba\"\)/"
260
266
 
261
267
  draggable_with_id_set:
@@ -290,8 +296,8 @@ edit_link:
290
296
  'ajax/edit/link/fr/list1.erb': "/:link_id => @node.link_id/"
291
297
 
292
298
  start_id:
293
- src: "<r:form><input type='hidden' name='s' value='#{start_id}'/></r:form>"
294
- res: "/<input type='hidden' name='s' value='22'/></"
299
+ src: "<r:form><input name='s' type='hidden' value='#{start_id}'/></r:form>"
300
+ res: "/<input name='s' type='hidden' value='22'/></"
295
301
 
296
302
  drop_add_link:
297
303
  context:
@@ -299,7 +305,7 @@ drop_add_link:
299
305
  src: "<div do='drop' add='favorite'></div>"
300
306
  # without the ugly inspect, this would be '#{id}' or "\#{id}"
301
307
  tem: "/drop_node_path.*\"node\[favorite_id\]\" => \"\\\\#\{id\}\"/"
302
- res: "<div class='drop' id='list1'></div>"
308
+ res: "<div class='drop' id='list1' data-z='22'></div>"
303
309
  js: "/Droppables.add\('list1'.*/nodes/22/drop.*node\[favorite_id\]=%23%7Bid%7D"
304
310
 
305
311
  drop_var_scope:
@@ -312,14 +318,14 @@ drop_done_remove:
312
318
 
313
319
  drop_param:
314
320
  src: "<r:drop change='params' d='%{foo}'>params[:d] = <r:show eval='params[:d]'/></r:drop>"
315
- tem: "/<div class='drop' id='list1'><% add_drop_id\(%Q\{list1\}, :url => drop_node_path\(@node.*:d => \"foo\", :change => \"params\"/"
316
- res: "<div class='drop' id='list1'>params[:d] = </div>"
321
+ tem: "/<div class='drop' id='list1'.*><% add_drop_id\(%Q\{list1\}, :url => drop_node_path\(@node.*:d => \"foo\", :change => \"params\"/"
322
+ res: "<div class='drop' id='list1' data-z='22'>params[:d] = </div>"
317
323
  js: '/Droppables.add\(.list1.*d=foo/'
318
324
 
319
325
  drop_in_each:
320
326
  src: "<ul do='pages'><li do='each'><ul do='drop' set='reference'>...</ul></li></ul>"
321
- tem: "/<ul class='drop' id='<%= %Q\{list2_#\{var2.zip\}\} %>'><% add_drop_id\(%Q\{list2_#\{var2.zip\}\}/"
322
- 'ajax/drop/in/each/en/list2.erb': "/<ul class='drop' id=.*ndom_id.*add_drop_id.*drop_node_path.*ndom_id/"
327
+ tem: "/<ul class='drop' .*id='<%= %Q\{list2_#\{var2.zip\}\} %>'.*><% add_drop_id\(%Q\{list2_#\{var2.zip\}\}/"
328
+ 'ajax/drop/in/each/en/list2.erb': "/<ul class='drop' .*id=.*ndom_id.*add_drop_id.*drop_node_path.*ndom_id/"
323
329
 
324
330
  drop_param_in_each:
325
331
  src: "<r:pages do='each' do='drop' change='params' d='%{foo}'><r:show eval='params[:d]'/></r:pages>"
@@ -341,13 +347,15 @@ drop_in_each_id:
341
347
  # Should use prefix from "drop", not list of favorites.
342
348
  res: "/drop13_39/"
343
349
  # Show drop element
344
- 'ajax/drop/in/each/id/en/drop12.erb': "/^\s*<ul.*<li id='<%= %Q\{drop13_#\{var2.zip\}\} %>"
350
+ 'ajax/drop/in/each/id/en/drop12.erb': "/^\s*<ul.*<li .*id='<%= %Q\{drop13_#\{var2.zip\}\} %>"
345
351
  # Show each element
346
352
  'ajax/drop/in/each/id/en/drop13.erb': '/^\s*<li/'
347
353
 
348
354
  update_target:
349
355
  src: "UT: <div id='foo' do='block'>...</div> <r:link update='foo'/>"
350
- tem: "/UT: <div id='foo'>...</div> .*Ajax.Request.*:dom_id => %Q\{foo\}/"
356
+ tem: "/UT: <div .*id='foo'.*>...</div> .*Ajax.Request.*:dom_id => %Q\{foo\}/"
357
+ # New syntax should be
358
+ # tem: "/UT: <div .*id='foo'>...</div> .*Zena.get('foo', {id:<%= @node.zip %>})/"
351
359
 
352
360
  update_target_encode_params:
353
361
  context:
@@ -358,11 +366,11 @@ update_target_encode_params:
358
366
 
359
367
  include_update_target:
360
368
  src: "IUT: <r:include template='/ajax/update/target'><r:with part='foo'><r:show attr='title'/></r:with></r:include>"
361
- tem: "/IUT: UT: <div id='foo'><%= h @node.prop\['title'\] %></div> <a .*zen_path.*onclick='new Ajax.Request/"
369
+ tem: "/IUT: UT: <div .*id='foo'.*><%= h @node.prop\['title'\] %></div> <a .*zen_path.*onclick='new Ajax.Request/"
362
370
 
363
371
  id_in_each_group_should_be_scoped:
364
372
  src: "<ul do='comments from nodes in site' do='group' by='discussion_id'><li do='each'><r:node do='block' do='title'/></li></ul>"
365
- tem: "/<div id='<%= %Q\{list1_#\{var4.zip\}_list2\} %>'>/"
373
+ tem: "/<div .*id='<%= %Q\{list1_#\{var4.zip\}_list2\} %>'/"
366
374
 
367
375
  link_page_next:
368
376
  context:
@@ -380,7 +388,7 @@ link_page_list:
380
388
  toggle:
381
389
  src: "<span do='toggle' set='favorite' for='visitor.node'/>"
382
390
  res: "<span class='toggle' id='list1_22'></span>"
383
- js: "/var1 = \{\"list\":\[39\], \"url\":\"/nodes/13\", \"role\":\"favorite\".*\"list1_22\"\].each.function.item. \{ Zena.set_toggle/"
391
+ js: "/var1 = \{list:\[39\], url:\"/nodes/13\", role:\"favorite\".*\"list1_22\"\].each.function.item. \{ Zena.set_toggle/"
384
392
 
385
393
  toggle_attribute_in_each:
386
394
  context:
@@ -394,7 +402,7 @@ toggle_dyn_attribute_in_each:
394
402
  node: cleanWater
395
403
  rel: favorite
396
404
  src: "<ul do='pages'><li do='each' toggle='#{params[:rel]}' for='visitor.node' do='title'/></ul>"
397
- tem: "/add_toggle_id\(\"list1_#\{var2.zip\}\", \"var2_tog\", \"#\{params\[:rel\]\}\"\)/"
405
+ tem: "/add_toggle_id\(\"list1_#\{var2.zip\}\", \"var2_tog\", \"#\{params\[:rel\]\}\",\{\}\)/"
398
406
  res: "/<ul><li class='toggle' id='list1_26'>crocodiles</li>/"
399
407
  js: "/list1_26.*each/"
400
408
 
@@ -418,6 +426,16 @@ js_dyn:
418
426
  res: "x y"
419
427
  js: "<script type=\"text/javascript\">\n//<![CDATA[\nalert('ho status title');\n//]]>\n</script>"
420
428
 
429
+ js_less_then:
430
+ src: "x <r:js>if (i < 4) alert('ho <r:title/>');</r:js> y"
431
+ tem: "x <% js_data << capture do %>if (i < 4) alert('ho <%= @node.prop['title'] %>');<% end %> y"
432
+ res: "x y"
433
+ js: "<script type=\"text/javascript\">\n//<![CDATA[\nif (i < 4) alert('ho status title');\n//]]>\n</script>"
434
+
435
+ js_in_attr:
436
+ src: "<a onclick='if (i < 4) alert(\"go\");'>hop</a>"
437
+ tem: "<a onclick='if (i < 4) alert(\"go\");'>hop</a>"
438
+
421
439
  filter_in_list:
422
440
  # Should move to up node and not raise an error.
423
441
  src: "<ul do='pages in site'><r:block></r:block><li do='filter' live='true'/></ul>"