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.
- data/History.txt +38 -1
- data/app/controllers/documents_controller.rb +7 -5
- data/app/controllers/nodes_controller.rb +47 -6
- data/app/controllers/user_sessions_controller.rb +12 -3
- data/app/controllers/virtual_classes_controller.rb +8 -2
- data/app/models/acl.rb +5 -2
- data/app/models/cached_page.rb +5 -5
- data/app/models/column.rb +27 -4
- data/app/models/group.rb +1 -1
- data/app/models/node.rb +106 -24
- data/app/models/note.rb +2 -1
- data/app/models/relation.rb +9 -4
- data/app/models/relation_proxy.rb +2 -2
- data/app/models/role.rb +12 -5
- data/app/models/site.rb +10 -9
- data/app/models/skin.rb +8 -0
- data/app/models/string_hash.rb +65 -0
- data/app/models/text_document.rb +1 -1
- data/app/models/user.rb +2 -0
- data/app/models/virtual_class.rb +43 -10
- data/app/views/comments/create.rjs +1 -32
- data/app/views/comments/edit.rjs +1 -1
- data/app/views/comments/update.rjs +1 -1
- data/app/views/documents/show.rhtml +1 -1
- data/app/views/groups/_form.rhtml +7 -0
- data/app/views/groups/_li.rhtml +1 -1
- data/app/views/nodes/500.html +2 -1
- data/app/views/nodes/destroy.rjs +2 -0
- data/app/views/sites/jobs.erb +2 -3
- data/app/views/templates/document_create_tabs/_file.rhtml +1 -1
- data/app/views/templates/document_create_tabs/_import.rhtml +4 -1
- data/app/views/templates/document_create_tabs/_template.rhtml +3 -0
- data/app/views/templates/document_create_tabs/_text_document.rhtml +3 -0
- data/app/views/versions/custom_tab.rhtml +1 -1
- data/app/views/versions/edit.rhtml +1 -1
- data/bricks/acls/lib/bricks/acls.rb +3 -3
- data/bricks/acls/zena/test/unit/acl_test.rb +15 -0
- data/bricks/fs_skin/lib/bricks/fs_skin.rb +190 -0
- data/bricks/fs_skin/zena/init.rb +1 -0
- data/bricks/fs_skin/zena/migrate/20110702010330_add_fs_skin_to_idx_templates.rb +12 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Image-edit.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Image.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Node-+index.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Node-+notFound.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Node-+search.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Node.zafu +1 -1
- data/bricks/{static → fs_skin}/zena/skins/blog/Post.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Project--kml.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/Project.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/comments.zafu +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/dict.yml +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/img/dateBg.jpg +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/img/header.png +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/img/mapPin.png +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/img/menu.gif +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/img/menuover.gif +0 -0
- data/bricks/{static → fs_skin}/zena/skins/blog/img/style.css +0 -0
- data/bricks/fs_skin/zena/tasks.rb +26 -0
- data/bricks/{static/zena/test/integration/static_integration_test.rb → fs_skin/zena/test/integration/fs_skin_integration_test.rb} +6 -6
- data/bricks/fs_skin/zena/test/unit/fs_skin_test.rb +33 -0
- data/bricks/grid/lib/bricks/grid.rb +4 -3
- data/bricks/tags/lib/bricks/tags.rb +1 -7
- data/bricks/zena/zena/migrate/20120605091558_add_ssl_login_to_site.rb +7 -0
- data/bricks/zena/zena/migrate/20120630123551_add_auto_publish_to_group.rb +9 -0
- data/config/bricks.yml +3 -3
- data/config/gems.yml +2 -3
- data/lib/tasks/zena.rake +7 -3
- data/lib/zafu.rb +7 -0
- data/lib/zafu/all.rb +21 -0
- data/lib/zafu/compiler.rb +7 -0
- data/lib/zafu/controller_methods.rb +58 -0
- data/lib/zafu/handler.rb +57 -0
- data/lib/zafu/info.rb +4 -0
- data/lib/zafu/markup.rb +309 -0
- data/lib/zafu/mock_helper.rb +42 -0
- data/lib/zafu/node_context.rb +203 -0
- data/lib/zafu/ordered_hash.rb +53 -0
- data/lib/zafu/parser.rb +676 -0
- data/lib/zafu/parsing_rules.rb +382 -0
- data/lib/zafu/process/ajax.rb +530 -0
- data/lib/zafu/process/conditional.rb +92 -0
- data/lib/zafu/process/context.rb +186 -0
- data/lib/zafu/process/forms.rb +143 -0
- data/lib/zafu/process/html.rb +186 -0
- data/lib/zafu/process/ruby_less_processing.rb +321 -0
- data/lib/zafu/security.rb +15 -0
- data/lib/zafu/template.rb +25 -0
- data/lib/zafu/test_helper.rb +19 -0
- data/lib/zafu/view_methods.rb +6 -0
- data/lib/zena.rb +1 -1
- data/lib/zena/acts/enrollable.rb +1 -1
- data/lib/zena/app.rb +4 -17
- data/lib/zena/console.rb +18 -1
- data/lib/zena/core_ext/file_utils.rb +13 -1
- data/lib/zena/core_ext/fixnum.rb +4 -0
- data/lib/zena/core_ext/float.rb +7 -0
- data/lib/zena/deploy.rb +4 -2
- data/lib/zena/deploy/app_init.rhtml +2 -1
- data/lib/zena/deploy/database.rhtml +1 -1
- data/lib/zena/info.rb +1 -1
- data/lib/zena/parser/zazen_rules.rb +4 -4
- data/lib/zena/routes.rb +1 -1
- data/lib/zena/test_controller.rb +1 -1
- data/lib/zena/use.rb +14 -1
- data/lib/zena/use/action.rb +4 -2
- data/lib/zena/use/ajax.rb +86 -38
- data/lib/zena/use/authlogic.rb +16 -1
- data/lib/zena/use/calendar.rb +37 -17
- data/lib/zena/use/conditional.rb +2 -2
- data/lib/zena/use/context.rb +30 -9
- data/lib/zena/use/dates.rb +39 -3
- data/lib/zena/use/display.rb +6 -19
- data/lib/zena/use/forms.rb +100 -79
- data/lib/zena/use/i18n.rb +40 -16
- data/lib/zena/use/query_builder.rb +0 -6
- data/lib/zena/use/query_node.rb +17 -4
- data/lib/zena/use/relations.rb +1 -3
- data/lib/zena/use/rendering.rb +10 -8
- data/lib/zena/use/scope_index.rb +5 -1
- data/lib/zena/use/search.rb +2 -1
- data/lib/zena/use/urls.rb +82 -77
- data/lib/zena/use/workflow.rb +12 -4
- data/lib/zena/use/zafu_safe_definitions.rb +37 -9
- data/lib/zena/use/zafu_templates.rb +49 -20
- data/lib/zena/use/zazen.rb +6 -2
- data/locale/it/LC_MESSAGES/zena.mo +0 -0
- data/locale/it/zena.mo +0 -0
- data/locale/it/zena.po +1982 -0
- data/public/images/arrow_back.png +0 -0
- data/public/images/remove_tag.png +0 -0
- data/public/javascripts/grid.js +800 -199
- data/public/javascripts/window.js +1 -1
- data/public/javascripts/zena.js +130 -21
- data/public/stylesheets/grid.css +11 -2
- data/public/stylesheets/zena.css +2 -1
- data/test/custom_queries/complex.host.yml +5 -0
- data/test/fixtures/files/TestNode.zafu +36 -0
- data/test/functional/nodes_controller_test.rb +18 -1
- data/test/integration/zafu_compiler/action.yml +2 -2
- data/test/integration/zafu_compiler/ajax.yml +44 -26
- data/test/integration/zafu_compiler/asset.yml +12 -2
- data/test/integration/zafu_compiler/basic.yml +0 -16
- data/test/integration/zafu_compiler/calendar.yml +6 -6
- data/test/integration/zafu_compiler/complex_ok.yml +23 -1
- data/test/integration/zafu_compiler/conditional.yml +5 -5
- data/test/integration/zafu_compiler/context.yml +6 -5
- data/test/integration/zafu_compiler/dates.yml +23 -2
- data/test/integration/zafu_compiler/display.yml +46 -2
- data/test/integration/zafu_compiler/errors.yml +2 -2
- data/test/integration/zafu_compiler/eval.yml +35 -7
- data/test/integration/zafu_compiler/forms.yml +47 -13
- data/test/integration/zafu_compiler/i18n.yml +2 -2
- data/test/integration/zafu_compiler/meta.yml +35 -1
- data/test/integration/zafu_compiler/query.yml +23 -4
- data/test/integration/zafu_compiler/relations.yml +10 -6
- data/test/integration/zafu_compiler/roles.yml +4 -4
- data/test/integration/zafu_compiler/rubyless.yml +11 -1
- data/test/integration/zafu_compiler/safe_definitions.yml +23 -5
- data/test/integration/zafu_compiler/security.yml +10 -6
- data/test/integration/zafu_compiler/urls.yml +23 -6
- data/test/integration/zafu_compiler/zafu_attributes.yml +1 -1
- data/test/integration/zafu_compiler/zazen.yml +14 -0
- data/test/selenium/Add/add3.rsel +8 -8
- data/test/selenium/Destroy/0setup.rsel +12 -0
- data/test/selenium/Destroy/destroy1.rsel +16 -0
- data/test/selenium/Edit/edit2.rsel +9 -9
- data/test/selenium/Edit/edit5.rsel +9 -9
- data/test/selenium/Edit/edit6.rsel +9 -9
- data/test/selenium/Form/form4.rsel +17 -0
- data/test/selenium/Toggle/toggle1.rsel +2 -0
- data/test/selenium/Toggle/toggle2.rsel +18 -0
- data/test/sites/zena/columns.yml +3 -0
- data/test/sites/zena/versions.yml +7 -0
- data/test/unit/cached_page_test.rb +13 -13
- data/test/unit/column_test.rb +26 -0
- data/test/unit/node_test.rb +16 -1
- data/test/unit/project_test.rb +6 -1
- data/test/unit/relation_test.rb +1 -1
- data/test/unit/role_test.rb +1 -1
- data/test/unit/string_hash_test.rb +30 -0
- data/test/unit/virtual_class_test.rb +31 -17
- data/test/unit/zafu_markup_test.rb +414 -0
- data/test/unit/zafu_node_context_test.rb +375 -0
- data/test/unit/zafu_ordered_hash_test.rb +69 -0
- data/test/unit/zena/acts/enrollable_test.rb +1 -1
- data/test/unit/zena/parser/zafu_asset.yml +0 -10
- data/test/unit/zena/parser/zazen.yml +1 -1
- data/test/unit/zena/parser_test.rb +1 -72
- data/test/unit/zena/use/dates_test.rb +1 -1
- data/test/unit/zena/use/rendering_test.rb +24 -7
- data/test/unit/zena/use/scope_index_test.rb +17 -0
- data/test/unit/zena/use/zazen_test.rb +2 -1
- data/zena.gemspec +71 -37
- metadata +104 -83
- data/app/views/nodes/destroy.erb +0 -0
- data/bricks/static/lib/bricks/static.rb +0 -151
- data/bricks/static/zena/init.rb +0 -1
- data/bricks/static/zena/migrate/20110702010330_add_static_to_idx_templates.rb +0 -12
- data/bricks/static/zena/test/unit/static_test.rb +0 -33
- data/lib/zena/parser/zafu_rules.rb +0 -244
- data/lib/zena/parser/zafu_tags.rb +0 -198
- data/lib/zena/parser/zena_rules.rb +0 -23
|
Binary file
|
|
Binary file
|
data/public/javascripts/grid.js
CHANGED
|
@@ -3,50 +3,127 @@ Grid = {
|
|
|
3
3
|
grid_c: 0,
|
|
4
4
|
};
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
if (Prototype.Browser.WebKit) {
|
|
7
|
+
Grid.default_input = "<input type='text' value=''/>"
|
|
8
|
+
Grid.paste_mode = 'redirect'
|
|
9
|
+
} else {
|
|
10
|
+
Grid.default_input = '<textarea></textarea>'
|
|
11
|
+
Grid.paste_mode = 'inline'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
Grid.log = function(what, msg) {
|
|
15
|
+
var log = $('log')
|
|
16
|
+
if (typeof(msg) != 'string') msg = Object.toJSON(msg)
|
|
17
|
+
log.innerHTML = log.innerHTML + '<br/><b>' + what + '</b> ' + msg
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
Grid.changed = function(cell, val, prev, skip_html) {
|
|
21
|
+
if (!skip_html) {
|
|
22
|
+
if (val.value == val.show) {
|
|
23
|
+
cell.innerHTML = val.value
|
|
24
|
+
} else {
|
|
25
|
+
cell.innerHTML = val.show
|
|
26
|
+
cell.setAttribute('data-v', val.value)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
var row = cell.up('tr')
|
|
30
|
+
var table = row.up('table')
|
|
31
|
+
var grid = table.grid
|
|
32
|
+
if (prev.value == val.value) return;
|
|
33
|
+
if (cell.orig_value == val.value) {
|
|
34
|
+
cell.removeClassName('changed')
|
|
13
35
|
if (row.select('.changed').length == 0) {
|
|
14
|
-
row.removeClassName('changed')
|
|
36
|
+
row.removeClassName('changed')
|
|
15
37
|
}
|
|
16
38
|
} else {
|
|
17
|
-
cell.addClassName('changed')
|
|
18
|
-
row.addClassName('changed')
|
|
39
|
+
cell.addClassName('changed')
|
|
40
|
+
row.addClassName('changed')
|
|
19
41
|
}
|
|
20
|
-
var pos = Grid.pos(cell)
|
|
42
|
+
var pos = Grid.pos(cell)
|
|
21
43
|
|
|
22
|
-
var attr, id
|
|
23
|
-
if (
|
|
44
|
+
var attr, id
|
|
45
|
+
if (grid.attr_name) {
|
|
24
46
|
attr = pos;
|
|
25
47
|
id = Grid.pos(row) - 1;
|
|
26
48
|
} else {
|
|
27
|
-
attr =
|
|
49
|
+
attr = grid.attr[pos];
|
|
28
50
|
id = row.id;
|
|
51
|
+
if (!id) {
|
|
52
|
+
// Prepare for create
|
|
53
|
+
id = Grid.buildObj(grid, row)
|
|
54
|
+
}
|
|
29
55
|
}
|
|
30
56
|
|
|
31
57
|
var change = {
|
|
32
|
-
id: id
|
|
58
|
+
id: id,
|
|
59
|
+
_old: prev,
|
|
33
60
|
};
|
|
34
|
-
change[attr] =
|
|
61
|
+
change[attr] = val;
|
|
35
62
|
var table = row.up('table');
|
|
36
|
-
|
|
63
|
+
grid.changes.push(change);
|
|
37
64
|
}
|
|
38
65
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
66
|
+
// Push a row as a new object in changes.
|
|
67
|
+
Grid.buildObj = function(grid, row) {
|
|
68
|
+
// Set a temporary id
|
|
69
|
+
grid.counter++
|
|
70
|
+
var id = 'new_' + grid.id + '_' + grid.counter
|
|
71
|
+
row.id = id
|
|
72
|
+
row.addClassName('new')
|
|
73
|
+
var base = {
|
|
74
|
+
id: id,
|
|
75
|
+
_new: {value:true}
|
|
76
|
+
}
|
|
77
|
+
// Add all default attributes
|
|
78
|
+
grid.defaults.each(function(pair) {
|
|
79
|
+
base[pair.key] = pair.value
|
|
80
|
+
})
|
|
81
|
+
// Add all attributes
|
|
82
|
+
var cells = row.childElements()
|
|
83
|
+
for (var i = 0; i < cells.length - 1; i++) {
|
|
84
|
+
var cell = cells[i]
|
|
85
|
+
var attr = grid.attr[i]
|
|
86
|
+
if (attr) {
|
|
87
|
+
// A readonly cell *MUST* have data-v set or it is ignored.
|
|
88
|
+
if (!cell.getAttribute('data-v') && Grid.isReadOnly(cell)) continue
|
|
89
|
+
var val = Grid.getValue(cell)
|
|
90
|
+
if (val.value.strip() == '') {
|
|
91
|
+
val = base[attr] || val
|
|
92
|
+
} else {
|
|
93
|
+
base[attr] = val
|
|
94
|
+
}
|
|
95
|
+
if (cell.innerHTML.strip() == '') {
|
|
96
|
+
cell.innerHTML = val.show
|
|
97
|
+
}
|
|
49
98
|
}
|
|
99
|
+
}
|
|
100
|
+
grid.changes.push(base)
|
|
101
|
+
return id
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
Grid.closeCell = function(e) {
|
|
105
|
+
if (Grid.in_paste) return
|
|
106
|
+
var cell = e.tagName ? e : e.element().up()
|
|
107
|
+
var table = cell.up('table')
|
|
108
|
+
var prev = cell.prev_value
|
|
109
|
+
var val = Grid.getValue(cell)
|
|
110
|
+
|
|
111
|
+
if (table.grid.list_name) {
|
|
112
|
+
if (val.value == 'on') {
|
|
113
|
+
cell.addClassName('on')
|
|
114
|
+
} else {
|
|
115
|
+
cell.removeClassName('on')
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
cell.removeClassName('input')
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
Grid.changed(cell, val, prev)
|
|
122
|
+
|
|
123
|
+
if (table.grid.input) {
|
|
124
|
+
// single attribute table, serialize in input field
|
|
125
|
+
table.grid.input.value = Grid.serialize(table)
|
|
126
|
+
}
|
|
50
127
|
}
|
|
51
128
|
|
|
52
129
|
Grid.pos = function(elem) {
|
|
@@ -65,15 +142,27 @@ Grid.paste = function(event) {
|
|
|
65
142
|
var tbody = table.childElements()[0];
|
|
66
143
|
var rows = tbody.childElements();
|
|
67
144
|
var cell_offset = Grid.pos(start_cell);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
145
|
+
|
|
146
|
+
var paster
|
|
147
|
+
if (Grid.paste_mode == 'redirect') {
|
|
148
|
+
// Redirect paste inside the paste textarea
|
|
149
|
+
$(document.body).insert({
|
|
150
|
+
bottom: "<textarea style='position:fixed; top:0; left:10100px;' id='grid_p_" + table.grid.id + "'></textarea>"
|
|
151
|
+
});
|
|
152
|
+
paster = $("grid_p_" + table.grid.id);
|
|
153
|
+
Grid.in_paste = true // prevent original input blur
|
|
154
|
+
paster.focus();
|
|
155
|
+
Grid.in_paste = false
|
|
156
|
+
}
|
|
74
157
|
setTimeout(function() {
|
|
75
|
-
var text
|
|
76
|
-
|
|
158
|
+
var text
|
|
159
|
+
if (Grid.paste_mode == 'redirect') {
|
|
160
|
+
text = paster.value
|
|
161
|
+
paster.remove()
|
|
162
|
+
input.focus()
|
|
163
|
+
} else {
|
|
164
|
+
text = input.value
|
|
165
|
+
}
|
|
77
166
|
|
|
78
167
|
var lines = text.strip().split(/\r\n|\r|\n/);
|
|
79
168
|
for (var i = 0; i < lines.length; i++) {
|
|
@@ -84,6 +173,7 @@ Grid.paste = function(event) {
|
|
|
84
173
|
input.value = lines[0][0];
|
|
85
174
|
} else {
|
|
86
175
|
// copy/paste from spreadsheet
|
|
176
|
+
table.grid.changes.push('start')
|
|
87
177
|
var should_create = table.grid.input && true;
|
|
88
178
|
for (var i = 0; i < lines.length; i++) {
|
|
89
179
|
// foreach line
|
|
@@ -92,7 +182,7 @@ Grid.paste = function(event) {
|
|
|
92
182
|
if (!row) {
|
|
93
183
|
if (!should_create) break;
|
|
94
184
|
// create a new row
|
|
95
|
-
Grid.
|
|
185
|
+
Grid.addRow(table, rows[row_offset + i - 1]);
|
|
96
186
|
rows = tbody.select('tr');
|
|
97
187
|
row = rows[row_offset + i];
|
|
98
188
|
}
|
|
@@ -104,24 +194,41 @@ Grid.paste = function(event) {
|
|
|
104
194
|
if (!cell) {
|
|
105
195
|
if (!should_create) break;
|
|
106
196
|
// create a new cell
|
|
107
|
-
Grid.
|
|
197
|
+
Grid.addCol(table, cells[cell_offset + j - 1]);
|
|
108
198
|
cells = row.childElements(); cells.pop();
|
|
109
199
|
cell = cells[cell_offset + j];
|
|
110
200
|
}
|
|
111
|
-
|
|
201
|
+
var val = {value:tabs[j], show:tabs[j]}
|
|
202
|
+
if (i==0 && j==0) {
|
|
203
|
+
input.value = val.value
|
|
204
|
+
Grid.changed(cell, val, cell.prev_value, true)
|
|
205
|
+
cell.prev_value = val
|
|
206
|
+
} else if (!Grid.isReadOnly(cell)) {
|
|
207
|
+
var prev = Grid.getValue(cell)
|
|
208
|
+
Grid.changed(cell, val, prev)
|
|
209
|
+
}
|
|
112
210
|
}
|
|
113
211
|
}
|
|
212
|
+
table.grid.changes.push('end')
|
|
114
213
|
}
|
|
115
|
-
|
|
116
|
-
|
|
214
|
+
if (table.grid.input) {
|
|
215
|
+
// single attribute table, serialize in input field
|
|
216
|
+
table.grid.input.value = Grid.serialize(table)
|
|
217
|
+
}
|
|
218
|
+
}, 0)
|
|
117
219
|
return true;
|
|
118
220
|
}
|
|
119
221
|
|
|
120
222
|
Grid.keydown = function(event) {
|
|
121
|
-
var input = event.element()
|
|
122
|
-
var key = event.keyCode
|
|
123
|
-
var cell = input.up()
|
|
124
|
-
|
|
223
|
+
var input = event.element()
|
|
224
|
+
var key = event.keyCode
|
|
225
|
+
var cell = input.up()
|
|
226
|
+
var grid = cell.up('table').grid
|
|
227
|
+
if (grid.keydown && grid.keydown(event, key)) {
|
|
228
|
+
event.stop()
|
|
229
|
+
return false
|
|
230
|
+
}
|
|
231
|
+
if ((false && key == 39) || (key == 9 && !event.shiftKey)) {
|
|
125
232
|
// tab + key right
|
|
126
233
|
var next = cell.nextSiblings()[0];
|
|
127
234
|
if (!next || next.hasClassName('action')) {
|
|
@@ -132,24 +239,32 @@ Grid.keydown = function(event) {
|
|
|
132
239
|
}
|
|
133
240
|
next = row.childElements()[0];
|
|
134
241
|
}
|
|
135
|
-
Grid.
|
|
242
|
+
Grid.openCell(next);
|
|
136
243
|
event.stop();
|
|
137
|
-
} else if (key == 37 || (key == 9 && event.shiftKey)) {
|
|
244
|
+
} else if ((false && key == 37) || (key == 9 && event.shiftKey)) {
|
|
245
|
+
// shift-tab + left key
|
|
138
246
|
var prev = cell.previousSiblings()[0];
|
|
139
247
|
if (!prev) {
|
|
140
248
|
// wrap back around on shift+tab
|
|
141
|
-
var row = cell.up('tr').previousSiblings()[0]
|
|
142
|
-
if (!row || row.
|
|
249
|
+
var row = cell.up('tr').previousSiblings()[0]
|
|
250
|
+
if (!row || row.hasClassName('action')) {
|
|
143
251
|
row = cell.up('tbody').childElements().last();
|
|
144
252
|
}
|
|
145
253
|
prev = row.childElements().last();
|
|
146
254
|
if (prev.hasClassName('action'))
|
|
147
255
|
prev = prev.previousSiblings()[0];
|
|
148
256
|
}
|
|
149
|
-
Grid.
|
|
257
|
+
Grid.openCell(prev);
|
|
150
258
|
event.stop();
|
|
151
|
-
} else if (key == 40 || key == 13) {
|
|
152
|
-
//
|
|
259
|
+
} else if ((key == 40 && event.altKey) || (key == 13 && !event.shiftKey)) {
|
|
260
|
+
// down
|
|
261
|
+
if (event.altKey) {
|
|
262
|
+
Grid.copy(cell, 'down')
|
|
263
|
+
event.stop()
|
|
264
|
+
return false
|
|
265
|
+
} else if (cell.childElements().first().tagName == 'SELECT' && event.shiftKey) {
|
|
266
|
+
return
|
|
267
|
+
}
|
|
153
268
|
var pos = Grid.pos(cell);
|
|
154
269
|
// go to next row
|
|
155
270
|
var crow = cell.up();
|
|
@@ -157,19 +272,24 @@ Grid.keydown = function(event) {
|
|
|
157
272
|
// find elem
|
|
158
273
|
if (!row) {
|
|
159
274
|
// open new row
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
275
|
+
if (crow.up('table').grid.add) {
|
|
276
|
+
Grid.addRow(crow.up('table'), cell.up());
|
|
277
|
+
row = crow.nextSiblings().first();
|
|
278
|
+
var next = row.childElements()[0];
|
|
279
|
+
setTimeout(function() {
|
|
280
|
+
Grid.openCell(next);
|
|
281
|
+
}, 100);
|
|
282
|
+
}
|
|
166
283
|
} else {
|
|
167
284
|
next = row.childElements()[pos];
|
|
168
|
-
Grid.
|
|
285
|
+
Grid.openCell(next);
|
|
169
286
|
}
|
|
170
287
|
event.stop();
|
|
171
|
-
} else if (key == 38) {
|
|
172
|
-
//
|
|
288
|
+
} else if ((false && key == 38) || (key == 13 && event.shiftKey)) {
|
|
289
|
+
// up
|
|
290
|
+
if (cell.childElements().first().tagName == 'SELECT' && event.shiftKey) {
|
|
291
|
+
return
|
|
292
|
+
}
|
|
173
293
|
var row = cell.up();
|
|
174
294
|
if (Grid.pos(row) == 1) {
|
|
175
295
|
// stop
|
|
@@ -178,65 +298,165 @@ Grid.keydown = function(event) {
|
|
|
178
298
|
// move up
|
|
179
299
|
row = row.previousSiblings().first();
|
|
180
300
|
var next = row.childElements()[pos];
|
|
181
|
-
Grid.
|
|
301
|
+
Grid.openCell(next);
|
|
182
302
|
}
|
|
183
303
|
event.stop();
|
|
184
304
|
}
|
|
185
305
|
return false;
|
|
186
306
|
}
|
|
187
307
|
|
|
188
|
-
Grid.
|
|
189
|
-
|
|
190
|
-
|
|
308
|
+
Grid.isReadOnly = function(cell) {
|
|
309
|
+
return cell.select('a').length > 0 || cell.getAttribute('data-m') == 'r'
|
|
310
|
+
}
|
|
191
311
|
|
|
192
|
-
|
|
193
|
-
cell.
|
|
312
|
+
Grid.openCell = function(cell) {
|
|
313
|
+
if (cell.hasClassName('input') || Grid.isReadOnly(cell)) return;
|
|
314
|
+
var val = Grid.getValue(cell)
|
|
315
|
+
cell.prev_value = val;
|
|
194
316
|
|
|
195
|
-
var
|
|
196
|
-
var
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
317
|
+
var value = val.value
|
|
318
|
+
var table = cell.up('table')
|
|
319
|
+
|
|
320
|
+
if (table.grid.list_name) {
|
|
321
|
+
if (value == 'on') {
|
|
322
|
+
cell.setAttribute('data-v', 'off')
|
|
323
|
+
} else {
|
|
324
|
+
cell.setAttribute('data-v', 'on')
|
|
325
|
+
}
|
|
326
|
+
Grid.closeCell(cell)
|
|
327
|
+
} else {
|
|
328
|
+
var w = cell.getWidth() - 5
|
|
329
|
+
var h = cell.getHeight() - 5
|
|
330
|
+
cell.addClassName('input')
|
|
331
|
+
|
|
332
|
+
// Try to find a form for the cell
|
|
333
|
+
var input
|
|
334
|
+
if (table.grid.helper && cell.tagName != 'TH') {
|
|
335
|
+
var pos = Grid.pos(cell)
|
|
336
|
+
input = table.grid.helper[pos]
|
|
337
|
+
if (input) {
|
|
338
|
+
input = Element.clone(input, true)
|
|
339
|
+
cell.update(input)
|
|
340
|
+
if (input.type == 'checkbox') {
|
|
341
|
+
if (value == input.value) {
|
|
342
|
+
input.checked = true
|
|
343
|
+
}
|
|
344
|
+
} else {
|
|
345
|
+
if (value && value.strip() != '') input.value = value
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (!input) {
|
|
351
|
+
// default input field
|
|
352
|
+
cell.update(Grid.default_input)
|
|
353
|
+
input = cell.childElements()[0]
|
|
354
|
+
input.value = value
|
|
355
|
+
}
|
|
356
|
+
input.setStyle({
|
|
357
|
+
width: w + 'px',
|
|
358
|
+
height: h + 'px'
|
|
359
|
+
})
|
|
360
|
+
input.observe('blur', Grid.closeCell)
|
|
361
|
+
input.observe('keydown', Grid.keydown)
|
|
362
|
+
input.observe('paste', Grid.paste)
|
|
363
|
+
input.focus()
|
|
364
|
+
input.select()
|
|
365
|
+
}
|
|
210
366
|
}
|
|
211
367
|
|
|
212
368
|
Grid.click = function(event) {
|
|
213
|
-
var cell = event.findElement('td, th')
|
|
214
|
-
var row =
|
|
369
|
+
var cell = event.findElement('td, th')
|
|
370
|
+
var row = cell.up('tr')
|
|
371
|
+
var table = cell.up('table')
|
|
215
372
|
if (row.hasClassName('action')) {
|
|
216
|
-
Grid.action(event, cell, row, true)
|
|
373
|
+
Grid.action(event, cell, row, true)
|
|
217
374
|
} else if (cell.hasClassName('action')) {
|
|
218
|
-
Grid.action(event, cell, row, false)
|
|
375
|
+
Grid.action(event, cell, row, false)
|
|
376
|
+
} else if (cell.tagName == 'TH' && !table.grid.attr_name) {
|
|
377
|
+
// sort
|
|
378
|
+
Grid.sort(cell)
|
|
219
379
|
} else {
|
|
220
|
-
Grid.
|
|
380
|
+
Grid.openCell(cell)
|
|
221
381
|
}
|
|
222
382
|
}
|
|
223
383
|
|
|
224
|
-
Grid.
|
|
384
|
+
Grid.valueFromInput = function(input) {
|
|
385
|
+
var val = {}
|
|
386
|
+
if (input.tagName == 'SELECT') {
|
|
387
|
+
val.value = input.value
|
|
388
|
+
val.show = input.select('option[value="'+val.value+'"]').first().innerHTML
|
|
389
|
+
} else {
|
|
390
|
+
if (input.type == 'checkbox') {
|
|
391
|
+
val.value = input.checked ? input.value : (input.getAttribute('data-off') || cell.getAttribute('data-v'))
|
|
392
|
+
} else {
|
|
393
|
+
val.value = input.value
|
|
394
|
+
}
|
|
395
|
+
val.show = val.value
|
|
396
|
+
}
|
|
397
|
+
return val
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
Grid.getValue = function(cell) {
|
|
401
|
+
if (cell.hasClassName('input')) {
|
|
402
|
+
return Grid.valueFromInput(cell.childElements()[0])
|
|
403
|
+
}
|
|
404
|
+
var val = {}
|
|
405
|
+
val.show = cell.innerHTML
|
|
406
|
+
val.value = cell.getAttribute('data-v') || val.show
|
|
407
|
+
if (!cell.orig_value) cell.orig_value = val.value
|
|
408
|
+
return val
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
Grid.copy = function(cell) {
|
|
412
|
+
var table = cell.up('table')
|
|
413
|
+
var row = cell.up()
|
|
414
|
+
var pos = Grid.pos(cell)
|
|
415
|
+
if (cell.tagName == 'TH') {
|
|
416
|
+
row = row.nextSiblings()[0]
|
|
417
|
+
cell = row.childElements()[pos]
|
|
418
|
+
}
|
|
419
|
+
var val = Grid.getValue(cell)
|
|
420
|
+
|
|
421
|
+
table.grid.changes.push('start')
|
|
422
|
+
Grid.changed(cell, val, cell.prev_value, true)
|
|
423
|
+
cell.prev_value = val
|
|
424
|
+
var rows = row.nextSiblings()
|
|
425
|
+
var len = rows.length
|
|
426
|
+
for (var i = 0; i < len; i++) {
|
|
427
|
+
var c = rows[i].childElements()[pos]
|
|
428
|
+
if (!Grid.isReadOnly(c)) {
|
|
429
|
+
var prev = Grid.getValue(c)
|
|
430
|
+
if (prev.value != val.value) Grid.changed(c, val, prev)
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
table.grid.changes.push('end')
|
|
434
|
+
if (table.grid.attr_name) {
|
|
435
|
+
table.grid.input.value = Grid.serialize(table);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
Grid.addRow = function(table, row) {
|
|
225
440
|
// insert row below
|
|
226
|
-
var
|
|
441
|
+
var row_str = '<tr>';
|
|
227
442
|
var cells = row.childElements();
|
|
228
443
|
for (var i = 0; i < cells.length -1; i++) {
|
|
229
|
-
|
|
444
|
+
row_str = row_str + '<td></td>';
|
|
230
445
|
}
|
|
231
|
-
|
|
446
|
+
row_str = row_str + Grid.Buttons(table.grid) + '</tr>';
|
|
232
447
|
row.insert({
|
|
233
|
-
after:
|
|
448
|
+
after: row_str
|
|
234
449
|
});
|
|
235
450
|
var new_row = row.nextSiblings()[0];
|
|
236
|
-
|
|
451
|
+
if (table.grid.attr_name) {
|
|
452
|
+
// FIXME: rewrite history for undo
|
|
453
|
+
} else {
|
|
454
|
+
Grid.buildObj(table.grid, new_row)
|
|
455
|
+
}
|
|
456
|
+
return new_row
|
|
237
457
|
}
|
|
238
458
|
|
|
239
|
-
Grid.
|
|
459
|
+
Grid.addCol = function(table, cell) {
|
|
240
460
|
var rows = table.childElements()[0].select('tr');
|
|
241
461
|
var pos = Grid.pos(cell);
|
|
242
462
|
for (var i = 0; i < rows.length; i++) {
|
|
@@ -259,7 +479,7 @@ Grid.add_col = function(table, cell) {
|
|
|
259
479
|
}
|
|
260
480
|
}
|
|
261
481
|
|
|
262
|
-
Grid.
|
|
482
|
+
Grid.delCol = function(table, cell) {
|
|
263
483
|
var rows = table.childElements()[0].select('tr');
|
|
264
484
|
var pos = Grid.pos(cell);
|
|
265
485
|
for (var i = 0; i < rows.length; i++) {
|
|
@@ -276,30 +496,49 @@ Grid.del_col = function(table, cell) {
|
|
|
276
496
|
}
|
|
277
497
|
}
|
|
278
498
|
|
|
499
|
+
Grid.delRow = function(grid, row) {
|
|
500
|
+
// remove current row
|
|
501
|
+
if (!grid.attr_name) {
|
|
502
|
+
// We must also clear the changes related to the removed row
|
|
503
|
+
Grid.clearChanges(grid.changes, row.id)
|
|
504
|
+
}
|
|
505
|
+
row.remove();
|
|
506
|
+
}
|
|
507
|
+
|
|
279
508
|
Grid.action = function(event, cell, row, is_col) {
|
|
280
|
-
var span = event.findElement('span')
|
|
281
|
-
var table = event.findElement('table')
|
|
509
|
+
var span = event.findElement('span')
|
|
510
|
+
var table = event.findElement('table')
|
|
511
|
+
var grid = table.grid
|
|
282
512
|
if (span.hasClassName('add')) {
|
|
283
513
|
if (is_col) {
|
|
284
|
-
Grid.
|
|
514
|
+
Grid.addCol(table, cell);
|
|
285
515
|
} else {
|
|
286
|
-
Grid.
|
|
287
|
-
Grid.
|
|
516
|
+
var new_row = Grid.addRow(table, row);
|
|
517
|
+
Grid.openCell(new_row.childElements()[0]);
|
|
288
518
|
}
|
|
289
519
|
} else if (span.hasClassName('del')) {
|
|
290
520
|
if (is_col) {
|
|
291
|
-
Grid.
|
|
521
|
+
Grid.delCol(table, cell);
|
|
292
522
|
} else {
|
|
293
|
-
|
|
294
|
-
|
|
523
|
+
if (event.altKey) {
|
|
524
|
+
// remove current row and all unchanged below
|
|
525
|
+
var rows = table.select('tr')
|
|
526
|
+
var row_i = Grid.pos(row)
|
|
527
|
+
for(var i = rows.length - 1; i >= row_i; --i) {
|
|
528
|
+
var arow = rows[i]
|
|
529
|
+
if (!arow.hasClassName('changed')) Grid.delRow(grid, arow)
|
|
530
|
+
}
|
|
531
|
+
} else {
|
|
532
|
+
Grid.delRow(grid, row)
|
|
533
|
+
}
|
|
295
534
|
}
|
|
296
535
|
} else if (span.hasClassName('copy')) {
|
|
297
536
|
var data = Grid.serialize(table, 'tab');
|
|
298
537
|
var td = span.up();
|
|
299
538
|
td.insert({
|
|
300
|
-
top: "<textarea id='grid_copy_" +
|
|
539
|
+
top: "<textarea id='grid_copy_" + grid.id + "'></textarea>"
|
|
301
540
|
});
|
|
302
|
-
var input = $('grid_copy_'+
|
|
541
|
+
var input = $('grid_copy_'+grid.id);
|
|
303
542
|
input.value = data;
|
|
304
543
|
Element.observe($(input), 'blur', function(event) {
|
|
305
544
|
event.element().remove();
|
|
@@ -307,16 +546,25 @@ Grid.action = function(event, cell, row, is_col) {
|
|
|
307
546
|
input.focus();
|
|
308
547
|
input.select();
|
|
309
548
|
}
|
|
310
|
-
|
|
549
|
+
if (grid.attr_name) {
|
|
550
|
+
grid.input.value = Grid.serialize(table);
|
|
551
|
+
}
|
|
311
552
|
}
|
|
312
553
|
|
|
313
554
|
// map grid position to attribute and reverse.
|
|
314
555
|
Grid.makeAttrPos = function(table) {
|
|
315
|
-
var heads = table.
|
|
556
|
+
var heads = table.select('th');
|
|
316
557
|
var attr = {};
|
|
317
558
|
var pos = {};
|
|
318
|
-
|
|
319
|
-
|
|
559
|
+
var helper = {}
|
|
560
|
+
var defaults = {}
|
|
561
|
+
var helpers
|
|
562
|
+
table.grid.attr = attr
|
|
563
|
+
table.grid.pos = pos
|
|
564
|
+
if (table.grid.helper_id) helpers = $(table.grid.helper_id)
|
|
565
|
+
if (helpers) {
|
|
566
|
+
table.grid.helper = helper;
|
|
567
|
+
}
|
|
320
568
|
if (table.grid.attr_name) {
|
|
321
569
|
for (var i = 0; i < heads.length; i++) {
|
|
322
570
|
attr[i] = i;
|
|
@@ -327,8 +575,20 @@ Grid.makeAttrPos = function(table) {
|
|
|
327
575
|
var attr_name = heads[i].getAttribute('data-a');
|
|
328
576
|
attr[i] = attr_name;
|
|
329
577
|
pos[attr_name] = i;
|
|
578
|
+
if (helpers) {
|
|
579
|
+
helper[i] = helpers.select('*[name="'+attr_name+'"]').first()
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
// get default values
|
|
583
|
+
if (helpers) {
|
|
584
|
+
helpers.select('input,textarea,select').each(function(e) {
|
|
585
|
+
if (e.getAttribute('data-d') == 'true') {
|
|
586
|
+
defaults[e.name] = Grid.valueFromInput(e)
|
|
587
|
+
}
|
|
588
|
+
})
|
|
330
589
|
}
|
|
331
590
|
}
|
|
591
|
+
table.grid.defaults = $H(defaults)
|
|
332
592
|
}
|
|
333
593
|
|
|
334
594
|
// only used with single attr table
|
|
@@ -341,9 +601,9 @@ Grid.serialize = function(table, format) {
|
|
|
341
601
|
for (var j = 0; j < cells.length - 1; j++) {
|
|
342
602
|
var cell = cells[j];
|
|
343
603
|
if (cell.hasClassName('input')) {
|
|
344
|
-
row_data.push(cell.
|
|
604
|
+
row_data.push(cell.childElements()[0].value)
|
|
345
605
|
} else {
|
|
346
|
-
row_data.push(
|
|
606
|
+
row_data.push(cell.innerHTML)
|
|
347
607
|
}
|
|
348
608
|
}
|
|
349
609
|
data.push(row_data);
|
|
@@ -368,49 +628,118 @@ Grid.serialize = function(table, format) {
|
|
|
368
628
|
}
|
|
369
629
|
}
|
|
370
630
|
|
|
371
|
-
Grid.Buttons =
|
|
372
|
-
|
|
631
|
+
Grid.Buttons = function(grid) {
|
|
632
|
+
var btns = "<td class='action'>"
|
|
633
|
+
if (grid.add) btns = btns + "<span class='add'> </span>"
|
|
634
|
+
if (grid.remove) btns = btns + "<span class='del'> </span>"
|
|
635
|
+
btns = btns + "</td>"
|
|
636
|
+
return btns
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
Grid.ColButtons = "<td><span class='del'> </span> <span class='add'> </span></td>"
|
|
373
640
|
|
|
374
641
|
// only used with single attr table
|
|
375
642
|
Grid.addButtons = function(table) {
|
|
376
|
-
var
|
|
377
|
-
var
|
|
378
|
-
var
|
|
643
|
+
var grid = table.grid
|
|
644
|
+
var attr_table = grid.attr_name
|
|
645
|
+
var data = []
|
|
646
|
+
var tbody = table.childElements()[0]
|
|
647
|
+
var rows = tbody.select('tr')
|
|
379
648
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
649
|
+
if (attr_table) {
|
|
650
|
+
var col_action = "<tr class='action'><td><span class='add'> </span></td>";
|
|
651
|
+
var cells_length = rows[0].select('th').length;
|
|
652
|
+
for (var i = 1; i < cells_length; i++) {
|
|
653
|
+
col_action = col_action + Grid.ColButtons;
|
|
654
|
+
}
|
|
655
|
+
col_action = col_action + "<td class='action'><span class='copy'> </span></td></tr>";
|
|
384
656
|
}
|
|
385
|
-
col_action = col_action + "<td class='action'><span class='copy'> </span></td></tr>";
|
|
386
657
|
|
|
387
658
|
for (var i = 0; i < rows.length; i++) {
|
|
388
|
-
var buttons
|
|
659
|
+
var buttons
|
|
389
660
|
if (i == 0) {
|
|
390
|
-
|
|
661
|
+
if (grid.add) {
|
|
662
|
+
buttons = "<td class='action'><span class='add'> </span></td>"
|
|
663
|
+
} else {
|
|
664
|
+
buttons = "<td class='action'></td>"
|
|
665
|
+
}
|
|
391
666
|
} else {
|
|
392
|
-
buttons = Grid.Buttons
|
|
667
|
+
buttons = Grid.Buttons(grid)
|
|
393
668
|
}
|
|
394
669
|
rows[i].insert({
|
|
395
670
|
bottom: buttons
|
|
396
|
-
})
|
|
671
|
+
})
|
|
397
672
|
}
|
|
398
673
|
tbody.insert({
|
|
399
674
|
top: col_action
|
|
400
|
-
})
|
|
401
|
-
return data
|
|
675
|
+
})
|
|
676
|
+
return data
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
Grid.onFailure = function(grid, id, errors) {
|
|
680
|
+
var cells = $(id).select('td')
|
|
681
|
+
errors.each(function(pair) {
|
|
682
|
+
var pos = grid.pos[pair.key] || -1
|
|
683
|
+
var cell = cells[pos]
|
|
684
|
+
if (cell) {
|
|
685
|
+
Grid.setError(cell, pair.value)
|
|
686
|
+
} else {
|
|
687
|
+
// generic error
|
|
688
|
+
Grid.setError($(id), pair.key + ': ' + pair.value)
|
|
689
|
+
}
|
|
690
|
+
})
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
Grid.setError = function(e, msg) {
|
|
694
|
+
if (!Grid.msg) {
|
|
695
|
+
Grid.msg = $('grid_msg_')
|
|
696
|
+
if (!Grid.msg) {
|
|
697
|
+
$(document.body).insert({
|
|
698
|
+
bottom: "<div id='grid_msg_' style='display:none' class='grid_msg'></div>"
|
|
699
|
+
})
|
|
700
|
+
Grid.msg = $('grid_msg_')
|
|
701
|
+
}
|
|
702
|
+
Grid.msg.absolutize()
|
|
703
|
+
}
|
|
704
|
+
e.observe('mouseover', function() {
|
|
705
|
+
Grid.msg.innerHTML = msg
|
|
706
|
+
Element.clonePosition(Grid.msg, e, {
|
|
707
|
+
setWidth:false,
|
|
708
|
+
setHeight:false,
|
|
709
|
+
offsetTop:3,
|
|
710
|
+
offsetLeft:e.getWidth() - 3,
|
|
711
|
+
})
|
|
712
|
+
Grid.msg.show()
|
|
713
|
+
})
|
|
714
|
+
e.observe('mouseout', function() {
|
|
715
|
+
Grid.msg.hide()
|
|
716
|
+
})
|
|
717
|
+
e.addClassName('error')
|
|
402
718
|
}
|
|
403
719
|
|
|
404
|
-
Grid.make = function(table) {
|
|
720
|
+
Grid.make = function(table, opts) {
|
|
721
|
+
opts = opts || {}
|
|
722
|
+
table = $(table)
|
|
405
723
|
if (table.grid) return;
|
|
406
724
|
Grid.grid_c++;
|
|
407
725
|
Grid.grids[Grid.grid_c] = table;
|
|
408
726
|
table.grid = {
|
|
409
727
|
changes: [],
|
|
410
728
|
id: Grid.grid_c,
|
|
729
|
+
helper_id: table.getAttribute('data-helper'),
|
|
730
|
+
fdate: table.getAttribute('data-fdate'),
|
|
731
|
+
counter: 0, // Used to create dom_ids for new objects
|
|
732
|
+
onSuccess: opts.onSuccess,
|
|
733
|
+
onFailure: opts.onFailure || Grid.onFailure,
|
|
734
|
+
onStart: opts.onStart || Grid.onStart,
|
|
735
|
+
add: opts.add || opts.add == undefined,
|
|
736
|
+
remove: opts.remove || opts.remove == undefined,
|
|
737
|
+
keydown: opts.keydown,
|
|
411
738
|
};
|
|
739
|
+
|
|
412
740
|
// Detect type.
|
|
413
741
|
table.grid.attr_name = table.getAttribute('data-a');
|
|
742
|
+
table.grid.list_name = table.getAttribute('data-l');
|
|
414
743
|
|
|
415
744
|
var empty = false;
|
|
416
745
|
if (table.grid.attr_name && table.select('th').length == 0) {
|
|
@@ -419,18 +748,25 @@ Grid.make = function(table) {
|
|
|
419
748
|
table.innerHTML = "<tr><th>" + msg + "</th></tr><tr><td></td></tr>";
|
|
420
749
|
}
|
|
421
750
|
|
|
422
|
-
Grid.makeAttrPos(table)
|
|
751
|
+
Grid.makeAttrPos(table)
|
|
752
|
+
Grid.addButtons(table)
|
|
753
|
+
|
|
423
754
|
|
|
424
755
|
if (table.grid.attr_name) {
|
|
425
756
|
// If we have an attr_name, rows and columns are
|
|
426
757
|
// serialized as json in a single field.
|
|
427
|
-
Grid.addButtons(table);
|
|
428
758
|
table.insert({
|
|
429
759
|
after: "<input type='hidden' id='grid_a_" + Grid.grid_c + "' name='" + table.grid.attr_name + "'/>"
|
|
430
760
|
});
|
|
431
761
|
table.grid.input = $("grid_a_" + Grid.grid_c);
|
|
432
762
|
if (!empty) table.grid.input.value = Grid.serialize(table);
|
|
433
763
|
} else {
|
|
764
|
+
var rows = table.select('tr')
|
|
765
|
+
for (var i = 1; i < rows.length; i++) {
|
|
766
|
+
if (!rows[i].id) {
|
|
767
|
+
Grid.buildObj(table.grid, rows[i])
|
|
768
|
+
}
|
|
769
|
+
}
|
|
434
770
|
// Otherwise each row is a new object and each column
|
|
435
771
|
// corresponds to a different attribute (defined in the
|
|
436
772
|
// 'th' of the table).
|
|
@@ -439,58 +775,170 @@ Grid.make = function(table) {
|
|
|
439
775
|
});
|
|
440
776
|
}
|
|
441
777
|
|
|
442
|
-
|
|
443
778
|
table.observe('click', Grid.click);
|
|
444
779
|
}
|
|
445
780
|
|
|
781
|
+
// Default onStart handler
|
|
782
|
+
Grid.onStart = function(operations) {
|
|
783
|
+
if (operations.post) {
|
|
784
|
+
return confirm('Create '+operations.post+' nodes ?')
|
|
785
|
+
}
|
|
786
|
+
return true
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
Grid.clearChanges = function(list, id) {
|
|
790
|
+
for (var i = list.length - 1; i >= 0; i--) {
|
|
791
|
+
while (list[i] && list[i].id == id) {
|
|
792
|
+
list.splice(i, 1)
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
Grid.isChanged = function(elem) {
|
|
798
|
+
var table = $(elem)
|
|
799
|
+
var grid = table.grid
|
|
800
|
+
// buildObj adds a row per new object on load
|
|
801
|
+
return grid.changes.length > (table.attr_name ? 0 : table.select('tr').length - 1)
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
|
|
446
805
|
Grid.save = function(grid_id) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
806
|
+
// do not run on GUI thread
|
|
807
|
+
setTimeout(function() {
|
|
808
|
+
var table = Grid.grids[grid_id]
|
|
809
|
+
var grid = table.grid
|
|
810
|
+
var data = Grid.compact(grid.changes)
|
|
811
|
+
if (grid.list_name) {
|
|
812
|
+
data = Grid.dataForList(grid, data)
|
|
813
|
+
}
|
|
814
|
+
var todo_count = data.keys().length
|
|
815
|
+
var done_count = 0
|
|
816
|
+
if (grid.onStart) {
|
|
817
|
+
var operations = {}
|
|
818
|
+
data.each(function(pair) {
|
|
819
|
+
if (pair.value._new) {
|
|
820
|
+
operations.post = (operations.post || 0) + 1
|
|
821
|
+
} else {
|
|
822
|
+
operations.put = (operations.put || 0) + 1
|
|
823
|
+
}
|
|
824
|
+
})
|
|
825
|
+
if (!grid.onStart(operations)) return
|
|
826
|
+
}
|
|
827
|
+
data.each(function(pair) {
|
|
828
|
+
var id = pair.key
|
|
829
|
+
var changes = pair.value
|
|
830
|
+
var attrs = {zjs:true, "opts[format]":grid.fdate}
|
|
831
|
+
$H(changes).each(function(pair) {
|
|
832
|
+
if (pair.key != '_new') {
|
|
833
|
+
attrs['node['+pair.key+']'] = pair.value
|
|
834
|
+
}
|
|
835
|
+
})
|
|
836
|
+
if (changes._new) {
|
|
837
|
+
new Ajax.Request('/nodes', {
|
|
838
|
+
parameters: attrs,
|
|
839
|
+
onSuccess: function(transport) {
|
|
840
|
+
done_count++
|
|
841
|
+
var reply = transport.responseText.evalJSON()
|
|
842
|
+
// Change row id: it is no longer a new item
|
|
843
|
+
var old_id = id
|
|
844
|
+
$(id).id = 'id_' + reply.id
|
|
845
|
+
id = 'id_' + reply.id
|
|
846
|
+
var attrs = {}
|
|
847
|
+
attrs[id] = reply
|
|
848
|
+
Grid.notify(table, attrs)
|
|
849
|
+
Grid.clearChanges(grid.changes, old_id)
|
|
850
|
+
if (grid.onSuccess) {
|
|
851
|
+
grid.onSuccess(grid, id, 'post', done_count, todo_count)
|
|
852
|
+
}
|
|
853
|
+
},
|
|
854
|
+
|
|
855
|
+
onFailure: function(transport) {
|
|
856
|
+
done_count++
|
|
857
|
+
var errors = {}
|
|
858
|
+
transport.responseText.evalJSON().each(function(e) {
|
|
859
|
+
errors[e[0]] = e[1]
|
|
860
|
+
})
|
|
861
|
+
// Change row id: it is no longer a new item
|
|
862
|
+
grid.onFailure(grid, id, $H(errors))
|
|
863
|
+
},
|
|
864
|
+
method: 'post'
|
|
865
|
+
});
|
|
866
|
+
} else {
|
|
867
|
+
new Ajax.Request('/nodes/' + id.replace('id_',''), {
|
|
868
|
+
parameters: attrs,
|
|
869
|
+
onSuccess: function(transport) {
|
|
870
|
+
done_count++
|
|
871
|
+
var attrs = {}
|
|
872
|
+
attrs[id] = transport.responseText.evalJSON()
|
|
873
|
+
Grid.notify(table, attrs)
|
|
874
|
+
Grid.clearChanges(grid.changes, id)
|
|
875
|
+
if (grid.onSuccess) {
|
|
876
|
+
grid.onSuccess(id, 'put', done_count, todo_count)
|
|
877
|
+
}
|
|
878
|
+
},
|
|
879
|
+
method: 'put'
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
})
|
|
883
|
+
}, 100);
|
|
463
884
|
}
|
|
464
885
|
|
|
465
|
-
Grid.undo = function(grid_id) {
|
|
466
|
-
var table = Grid.grids[grid_id]
|
|
467
|
-
var
|
|
468
|
-
|
|
469
|
-
var
|
|
886
|
+
Grid.undo = function(grid_id, skip_undone) {
|
|
887
|
+
var table = Grid.grids[grid_id]
|
|
888
|
+
var grid = table.grid
|
|
889
|
+
var changes = grid.changes
|
|
890
|
+
var last = changes.last()
|
|
891
|
+
if (!last || last._new) return
|
|
892
|
+
var group = false
|
|
893
|
+
if (last == 'end') {
|
|
894
|
+
group = true
|
|
895
|
+
changes.pop()
|
|
896
|
+
}
|
|
897
|
+
var change = changes.pop()
|
|
898
|
+
var old = change._old
|
|
470
899
|
for (attr in change) {
|
|
471
|
-
if (attr == 'id') continue
|
|
472
|
-
var cell = $(change.id).childElements()[
|
|
473
|
-
var
|
|
474
|
-
|
|
475
|
-
cell.
|
|
900
|
+
if (attr == 'id' || attr == '_old') continue
|
|
901
|
+
var cell = $(change.id).childElements()[grid.pos[attr]]
|
|
902
|
+
var val = old
|
|
903
|
+
var value = old.value
|
|
904
|
+
cell.innerHTML = val.show || ''
|
|
905
|
+
cell.prev_value = val
|
|
476
906
|
if (value == cell.orig_value) {
|
|
477
|
-
cell.removeClassName('changed')
|
|
478
|
-
var row = cell.up()
|
|
479
|
-
if (row.select('.changed').length == 0) row.removeClassName('changed')
|
|
480
|
-
} else {
|
|
907
|
+
cell.removeClassName('changed')
|
|
908
|
+
var row = cell.up()
|
|
909
|
+
if (row.select('.changed').length == 0) row.removeClassName('changed')
|
|
910
|
+
} else {
|
|
911
|
+
[cell, cell.up()].invoke('addClassName', 'changed')
|
|
912
|
+
}
|
|
913
|
+
cell.addClassName('undone')
|
|
914
|
+
if (grid.list_name) {
|
|
915
|
+
cell.setAttribute('data-v', value)
|
|
916
|
+
if (value == 'on') {
|
|
917
|
+
cell.addClassName('on')
|
|
918
|
+
} else {
|
|
919
|
+
cell.removeClassName('on')
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
if (group) {
|
|
924
|
+
while (changes.last() != 'start') {
|
|
925
|
+
Grid.undo(grid_id, true)
|
|
481
926
|
}
|
|
482
|
-
|
|
927
|
+
changes.pop()
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
if (!skip_undone) {
|
|
931
|
+
setTimeout(function() {
|
|
932
|
+
table.select('.undone').invoke('removeClassName', 'undone')
|
|
933
|
+
}, 1000)
|
|
483
934
|
}
|
|
484
|
-
new PeriodicalExecuter(function(pe) {
|
|
485
|
-
table.select('.undone').invoke('removeClassName', 'undone');
|
|
486
|
-
pe.stop();
|
|
487
|
-
}, 1);
|
|
488
935
|
}
|
|
489
936
|
|
|
490
937
|
Grid.compact = function(list) {
|
|
491
938
|
var res = {};
|
|
492
939
|
for (var i = list.length - 1; i >= 0; i--) {
|
|
493
940
|
var changes = list[i];
|
|
941
|
+
if (typeof(changes) == 'string') continue
|
|
494
942
|
var obj = res[changes.id];
|
|
495
943
|
if (!obj) {
|
|
496
944
|
obj = {};
|
|
@@ -498,50 +946,203 @@ Grid.compact = function(list) {
|
|
|
498
946
|
}
|
|
499
947
|
|
|
500
948
|
for (var key in changes) {
|
|
501
|
-
if (key != 'id' && !obj[key]) {
|
|
949
|
+
if (key != 'id' && key != '_old' && !obj[key]) {
|
|
502
950
|
// only take latest change
|
|
503
|
-
obj[key] = changes[key];
|
|
951
|
+
obj[key] = changes[key].value;
|
|
504
952
|
}
|
|
505
953
|
}
|
|
506
954
|
}
|
|
507
|
-
return res;
|
|
955
|
+
return $H(res);
|
|
508
956
|
}
|
|
509
957
|
|
|
510
|
-
Grid.
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
958
|
+
Grid.test = function() {
|
|
959
|
+
var grid = $('grid').grid
|
|
960
|
+
var data = Grid.compact(grid.changes)
|
|
961
|
+
return Grid.dataForList(grid, data)
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// Build the changes array when we have a list. This function
|
|
965
|
+
// detects which rows have changes and builds the full list of
|
|
966
|
+
// ids in the format some_relation_ids:"123,345,888,432". Other fields
|
|
967
|
+
// are kept as is.
|
|
968
|
+
Grid.dataForList = function(grid, data) {
|
|
969
|
+
var res = {}
|
|
970
|
+
var list_name = grid.list_name
|
|
971
|
+
data.each(function(pair) {
|
|
972
|
+
var obj = {}
|
|
973
|
+
var base = pair.value
|
|
974
|
+
res[pair.key] = obj
|
|
975
|
+
for (var key in base) {
|
|
976
|
+
if (parseInt(key) + '' == key) {
|
|
977
|
+
// number key = there is a change in the list
|
|
978
|
+
if (!obj[list_name]) {
|
|
979
|
+
// build full list
|
|
980
|
+
var list = []
|
|
981
|
+
var row = $(pair.key)
|
|
982
|
+
var cells = row.childElements()
|
|
983
|
+
for (var i = 0; i < cells.length - 1; i++) {
|
|
984
|
+
var cell = cells[i]
|
|
985
|
+
var attr = grid.attr[i]
|
|
986
|
+
if (attr && (parseInt(attr) + '' == attr)) {
|
|
987
|
+
// number attr key
|
|
988
|
+
if (cell.getAttribute('data-v') == 'on') list.push(attr)
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
obj[list_name] = list.join(',')
|
|
992
|
+
}
|
|
993
|
+
} else {
|
|
994
|
+
// keep other attributes unchanged
|
|
995
|
+
obj[key] = base[key]
|
|
533
996
|
}
|
|
534
|
-
|
|
997
|
+
}
|
|
998
|
+
})
|
|
999
|
+
return $H(res)
|
|
1000
|
+
}
|
|
535
1001
|
|
|
536
|
-
|
|
1002
|
+
Grid.notify = function(table, changes) {
|
|
1003
|
+
var rows = table.childElements()[0].select('tr')
|
|
1004
|
+
var grid = table.grid
|
|
1005
|
+
var pos = grid.pos
|
|
1006
|
+
for (var obj_id in changes) {
|
|
1007
|
+
var row
|
|
1008
|
+
if (grid.attr_name) {
|
|
1009
|
+
// attr table
|
|
1010
|
+
row = rows[parseInt(obj_id)+1]
|
|
1011
|
+
} else {
|
|
1012
|
+
row = $(obj_id)
|
|
1013
|
+
}
|
|
1014
|
+
var cells = row.childElements()
|
|
1015
|
+
var change = changes[obj_id]
|
|
1016
|
+
for (var attr in change) {
|
|
1017
|
+
if (attr == 'id') continue
|
|
1018
|
+
if (attr == grid.list_name) {
|
|
1019
|
+
var list_on = change[attr].split(/,/)
|
|
1020
|
+
var cells = row.childElements()
|
|
1021
|
+
for (var i = 0; i < cells.length - 1; i++) {
|
|
1022
|
+
var attr = grid.attr[i]
|
|
1023
|
+
var cell = cells[i]
|
|
1024
|
+
if (parseInt(attr) + '' == attr) {
|
|
1025
|
+
if (list_on.indexOf(attr) >= 0) {
|
|
1026
|
+
cell.orig_value = 'on'
|
|
1027
|
+
cell.setAttribute('data-v', 'on')
|
|
1028
|
+
} else {
|
|
1029
|
+
cell.orig_value = 'off'
|
|
1030
|
+
cell.setAttribute('data-v', 'off')
|
|
1031
|
+
}
|
|
1032
|
+
cell.prev_value = undefined
|
|
1033
|
+
cell.removeClassName('error')
|
|
1034
|
+
cell.removeClassName('changed')
|
|
1035
|
+
cell.addClassName('saved')
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
} else {
|
|
1039
|
+
var cell
|
|
1040
|
+
var i = pos[attr]
|
|
1041
|
+
if (i == undefined) continue
|
|
1042
|
+
cell = cells[i]
|
|
1043
|
+
cell.removeClassName('changed')
|
|
1044
|
+
cell.removeClassName('error')
|
|
1045
|
+
if (cell.getAttribute('data-v') != change[attr]) {
|
|
1046
|
+
cell.innerHTML = change[attr]
|
|
1047
|
+
}
|
|
1048
|
+
cell.orig_value = change[attr]
|
|
1049
|
+
cell.prev_value = undefined
|
|
1050
|
+
cell.addClassName('saved')
|
|
537
1051
|
}
|
|
538
1052
|
}
|
|
1053
|
+
row.removeClassName('new')
|
|
1054
|
+
row.removeClassName('error')
|
|
1055
|
+
if (row.select('.changed').length == 0) {
|
|
1056
|
+
row.removeClassName('changed')
|
|
1057
|
+
}
|
|
539
1058
|
}
|
|
540
1059
|
// later
|
|
541
|
-
|
|
542
|
-
table.select('.saved').invoke('removeClassName', 'saved')
|
|
543
|
-
|
|
544
|
-
}, 1);
|
|
545
|
-
// maybe this is not good
|
|
546
|
-
table.grid.changes = []; // clear
|
|
1060
|
+
setTimeout(function() {
|
|
1061
|
+
table.select('.saved').invoke('removeClassName', 'saved')
|
|
1062
|
+
}, 1000)
|
|
547
1063
|
}
|
|
1064
|
+
|
|
1065
|
+
Grid.simulateClick = function(l) {
|
|
1066
|
+
if (document.createEvent) {
|
|
1067
|
+
var e = document.createEvent('MouseEvents')
|
|
1068
|
+
e.initMouseEvent('click', true, true, document.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, l)
|
|
1069
|
+
l.dispatchEvent(e)
|
|
1070
|
+
} else {
|
|
1071
|
+
var e = Object.extend(document.createEventObject())
|
|
1072
|
+
l.fireEvent('onclick', e)
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
Grid.sort = function(cell) {
|
|
1077
|
+
var table = cell.up('table')
|
|
1078
|
+
var desc = false
|
|
1079
|
+
if (cell.hasClassName('asc')) {
|
|
1080
|
+
desc = true
|
|
1081
|
+
cell.removeClassName('asc')
|
|
1082
|
+
cell.addClassName('desc')
|
|
1083
|
+
} else {
|
|
1084
|
+
table.select('.asc, .desc').each(function(e) { e.removeClassName('asc').removeClassName('desc') })
|
|
1085
|
+
cell.addClassName('asc')
|
|
1086
|
+
}
|
|
1087
|
+
var body = table.childElements()[0]
|
|
1088
|
+
var rows = body.select('tr')
|
|
1089
|
+
rows.splice(0,1)
|
|
1090
|
+
var col_i = Grid.pos(cell)
|
|
1091
|
+
|
|
1092
|
+
rows.sort(function(a, b) {
|
|
1093
|
+
var atxt = a.childElements()[col_i].innerHTML.stripTags().toLowerCase()
|
|
1094
|
+
var btxt = b.childElements()[col_i].innerHTML.stripTags().toLowerCase()
|
|
1095
|
+
return atxt.localeCompare(btxt) * (desc ? -1 : 1)
|
|
1096
|
+
}).each(Element.prototype.appendChild, body)
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
/////////// Tags
|
|
1100
|
+
Tags = {}
|
|
1101
|
+
|
|
1102
|
+
Tags.click = function(event) {
|
|
1103
|
+
var e = event.element()
|
|
1104
|
+
var value = e.getAttribute('data-v') || e.innerHTML
|
|
1105
|
+
var tags = e.tags
|
|
1106
|
+
var list = tags.list
|
|
1107
|
+
for (var i = list.length - 1; i >= 0; i--) {
|
|
1108
|
+
while (list[i] && list[i] == value) {
|
|
1109
|
+
list.splice(i, 1)
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
tags.onChange(list, e)
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
Tags.add = function(event) {
|
|
1116
|
+
var e = event.element()
|
|
1117
|
+
var value = e.value
|
|
1118
|
+
var tags = e.tags
|
|
1119
|
+
var list = tags.list
|
|
1120
|
+
for (var i = list.length - 1; i >= 0; i--) {
|
|
1121
|
+
while (list[i] && list[i] == value) {
|
|
1122
|
+
list.splice(i, 1)
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
list.push(value)
|
|
1126
|
+
tags.onChange(list)
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
Tags.make = function(elem, opts) {
|
|
1130
|
+
var tags = {}
|
|
1131
|
+
tags.onChange = opts.onChange
|
|
1132
|
+
elem.tags = tags
|
|
1133
|
+
var list = []
|
|
1134
|
+
tags.list = list
|
|
1135
|
+
elem.childElements().each(function(e) {
|
|
1136
|
+
var input = e.select('input,select').first()
|
|
1137
|
+
if (input) {
|
|
1138
|
+
input.tags = tags
|
|
1139
|
+
input.observe('change', Tags.add)
|
|
1140
|
+
} else {
|
|
1141
|
+
e.tags = tags
|
|
1142
|
+
list.push(e.getAttribute('data-v') || e.innerHTML)
|
|
1143
|
+
e.observe('click', Tags.click)
|
|
1144
|
+
}
|
|
1145
|
+
})
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
|