Revision 621
Date:
2016/11/10 14:16:02
Author:
ahitrov
Revision Log:
During inline status modifying now all records are reloaded.
'/contenido/ajax/section_browse.html' now can be used as document digging component.
Files:
Legend:
Added
Removed
Modified
utf8/core/comps/contenido/ajax/document_status.html
22
22
$class =~ s/-/:/g;
23
23
my $section = $keeper->get_section_by_id( $s ) if $s;
24
24
my $document = $keeper->get_document_by_id( $id, class => $class );
25
my %filter;
26
map { if ( $_ =~ /(.+?)=(.*)/ ) { $filter{$1} = $2 } } split(/\&/, $params);
27
my $params_unclassed = join ('&', map { $_.'='.$filter{$_} } grep { $_ ne 'class' } keys %filter );
28
my $params_unsection = join ('&', map { $_.'='.$filter{$_} } grep { $_ ne 's' } keys %filter );
29
25
if ( ref $document ) {
30
# набор колонок таблицы документов...
31
my @columns = ref $section && $section->_sorted ? ({attr => '_sort_', name => 'N'}) : ();
32
33
# пытаемся найти колонки, которые документ сам пожелал показать (required_properties -> column)...
34
push @columns,
35
sort {$a->{column} <=> $b->{column}}
36
grep {$_->{column}} $document->structure;
37
38
# стандартная жопка таблицы...
39
push @columns, {attr => '_act_', rusname => 'Действия'};
40
41
26
if ( defined $status ) {
42
27
$document->status( $status );
43
28
$document->store;
…
…
48
33
$document->store;
49
34
}
50
35
}
51
52
my $html = $m->scomp('/contenido/components/section_browse_row.msn', no_tr => 1,
53
document => $document, columns => \@columns, section => $section,
54
lookup_elemets => {}, filter => \%filter, params_unsection => $params_unsection, params_unclassed => $params_unclassed
55
);
56
$result{success} = 1;
57
$result{html} = Encode::decode('utf-8', $html);
36
%result = $m->comp('/contenido/ajax/section_browse.html', return => 'hash', section => $section, params => $params );
37
delete $result{documents};
58
38
} else {
59
39
$result{error} = Encode::decode('utf-8', 'Документ не найден');
60
40
}
utf8/core/comps/contenido/ajax/section_browse.html
1
<% $json %>
2
<%once>
3
4
use JSON::XS;
5
6
</%once>
7
<%args>
8
9
$id => undef
10
$params => undef
11
$return => 'json'
12
$section => undef
13
$build_html => 1
14
15
</%args>
16
<%init>
17
18
my %result;
19
20
if ( ($return eq 'json' && $id && $id =~ /^\d+$/) || ($return eq 'hash' && ref $section) ) {
21
$section = $keeper->get_section_by_id( $id ) unless ref $section;
22
if ( ref $section ) {
23
my %params;
24
if ( ref $params eq 'HASH' ) {
25
%params = %$params;
26
} elsif ( ref $params eq 'ARRAY' ) {
27
map {
28
if ( ref $_ eq 'ARRAY' && scalar @$_ == 2 ) {
29
$params{$_->[0]} = $_->[1];
30
} elsif ( $_ =~ /(.+?)=(.*)/ ) {
31
$params{$1} = $2
32
}
33
} @$params;
34
} elsif ( $params ) {
35
map { if ( $_ =~ /(.+?)=(.*)/ ) { $params{$1} = $2 } } split(/\&/, $params);
36
}
37
my $params_unclassed = join ('&', map { $_.'='.$params{$_} } grep { $_ ne 'class' } keys %params );
38
my $params_unsection = join ('&', map { $_.'='.$params{$_} } grep { $_ ne 's' } keys %params );
39
40
my %filter_params;
41
$filter_params{use_section} = $params{use_section} if exists $params{use_section} && $params{use_section};
42
$filter_params{class} = $params{class} if exists $params{class} && $params{class};
43
$filter_params{alpha} = $params{alpha} if exists $params{alpha} && $params{alpha};
44
$filter_params{alpha_search} = $params{alpha_search} if exists $params{alpha_search} && $params{alpha_search};
45
$filter_params{search_by} = $params{search_by} if exists $params{search_by} && $params{search_by};
46
$filter_params{search} = $params{search} if exists $params{search} && $params{search};
47
$filter_params{p} = $params{p} if exists $params{p} && $params{p} > 1;
48
$filter_params{s} = $params{id} if exists $params{id} && $params{id};
49
my $p = exists $params{p} && $params{p} ? $params{p} : 1;
50
51
# Фильтры работают в любом случае...
52
my $filter = $m->comp('/contenido/components/context.msn', name => 'filter');
53
my $profile = $m->comp('/contenido/components/context.msn', name => 'profile');
54
55
unless (defined $request->{section_accesses}->{$id}) {
56
$request->{section_accesses}->{$id} = $user->get_section_access($id);
57
}
58
my $section_access = $request->{section_accesses}->{$id};
59
60
my (@documents, $total);
61
my $s = $section->id;
62
my $sorted = $section->_sorted();
63
$s .= ",$filter" if ($filter > 0);
64
65
my %filter;
66
my $nothing_found = 0;
67
my %order = (!(exists $params{class} && $params{class}) && $section->order_by) ? (order_by => $section->order_by) : (order => ['date','direct']);
68
if ( exists $params{alpha} and $params{alpha} ne '' ) {
69
$filter{ilike} = 1;
70
$filter{ $params{alpha_search} || 'name' } = $params{alpha}."%";
71
$order{order} = ['name','reverse'];
72
delete $order{order_by};
73
}
74
75
if ( exists $params{class} && $params{class} ) {
76
$filter{class} = $params{class};
77
} elsif ( $section->default_document_class ) {
78
$filter{class} = $section->default_document_class;
79
} elsif ( $section->default_table_class ) {
80
$filter{table} = $section->default_table_class;
81
}
82
$filter{s} = $s unless exists $params{class} && $params{class} && !(exists $params{use_section} && $params{use_section});
83
84
if ( exists $params{search_by} && $params{search_by} && exists $params{search} && defined $params{search} ) {
85
my $doc_class = exists $params{class} && $params{class} ? $params{class} : $section->default_document_class;
86
my $search = $params{search};
87
my $search_by = $params{search_by};
88
if ( $doc_class ) {
89
my @props = $doc_class->new( $keeper )->structure();
90
my ($prop) = grep { $_->{attr} eq $search_by } @props if @props;
91
if ( ref $prop && ($prop->{type} eq 'integer' || $prop->{type} eq 'checkbox' ||
92
(($prop->{type} eq 'pickup' || $prop->{type} eq 'lookup' || $prop->{type} eq 'status') && $search =~ /^\d+$/) ||
93
(exists $prop->{db_type} && $prop->{db_type} =~ /integer\[\]/) )) {
94
$filter{$search_by} = int($search);
95
} elsif ( ref $prop && $prop->{type} eq 'status' && $search =~ /\D/ ) {
96
my $str;
97
foreach my $pair ( @{$prop->{cases}} ) {
98
if ( lc(Encode::decode('utf-8', $pair->[1])) eq lc(Encode::decode('utf-8', $search)) || lc(Encode::decode('utf-8', $pair->[0])) eq lc(Encode::decode('utf-8', $search)) ) {
99
$str = $pair->[0];
100
last;
101
}
102
}
103
if ( $str ) {
104
$filter{$search_by} = $str;
105
}
106
} elsif ( ref $prop && ($prop->{type} eq 'pickup' || $prop->{type} eq 'lookup') && $search =~ /\D/ ) {
107
my $lookup_opts = $prop->{lookup_opts};
108
if ( ref $lookup_opts && (exists $lookup_opts->{class} || exists $lookup_opts->{table}) ) {
109
my $search_field = exists $lookup_opts->{search_by} ? $lookup_opts->{search_by} : 'name';
110
my @ids = $keeper->get_documents (
111
ids => 1,
112
exists $lookup_opts->{class} ? (class => $lookup_opts->{class}) : (table => $lookup_opts->{table}),
113
ilike => 1,
114
$search_field => '%'.$search.'%',
115
);
116
if ( @ids ) {
117
$filter{$search_by} = \@ids;
118
} else {
119
$nothing_found = 1;
120
}
121
}
122
} else {
123
$filter{$search_by}='%'.$search.'%';
124
$filter{ilike} = 1;
125
}
126
} else {
127
$filter{$search_by}='%'.$search.'%';
128
$filter{ilike} = 1;
129
}
130
}
131
132
# Дополнительные фильтры раздела
133
if ($section->filters) {
134
no strict 'vars';
135
my $filters = eval($section->filters);
136
if ($@) {
137
warn "Bad filter: " . $section->filters . " in section " . $section->id;
138
} elsif (ref $filters eq 'HASH') {
139
while ( my ($key, $val) = each %$filters ) {
140
$filter{$key} = $val;
141
}
142
}
143
}
144
145
my $n = ref $section && $section->_page_size ? $section->_page_size : 40;
146
my $first = $n * ($p - 1);
147
($first,$p)=(0,0) if (!$section->no_count && $first>$total);
148
149
$total = $keeper->get_documents( %filter, count => 1 ) unless $section->no_count;
150
unless ( $nothing_found ) {
151
if ( exists $params{class} && $params{class} && !(exists $params{use_section} && $params{use_section}) ) {
152
@documents = $keeper->get_documents( %filter, %order, limit => $n, offset => $first );
153
} elsif ($sorted) {
154
@documents = $keeper->get_sorted_documents( %filter );
155
} else {
156
@documents = $keeper->get_documents( %filter, %order, limit => $n, offset => $first );
157
}
158
}
159
160
# набор колонок таблицы документов...
161
my @columns = $sorted ? ({attr => '_sort_', name => 'N'}) : ();
162
163
# пытаемся найти колонки, которые документ сам пожелал показать (required_properties -> column)...
164
if ($filter{class} or @documents and $documents[0]) {
165
push @columns,
166
sort {$a->{column} <=> $b->{column}}
167
grep {$_->{column}} ($filter{class} ? $filter{class}->new($keeper)->structure : $documents[0]->structure);
168
}
169
170
# стандартная жопка таблицы...
171
@columns = (@columns,
172
{attr => '_act_', rusname => 'Действия'},
173
);
174
175
my $toopi = $project->documents();
176
my $inline_status = 0;
177
my $delete_status = 0;
178
179
my %lookup_elements;
180
my %document_classes;
181
my @inline_pickups = grep {
182
my $type = exists $_->{inline_type} ? $_->{inline_type} : $_->{type};
183
exists $_->{inline} && ($type eq 'pickup' || $type eq 'autocomplete')
184
} @columns;
185
186
map {
187
$_->{document_access} = $user->section_accesses($user, $_->section);
188
if ( $_->{document_access} == 2 ) {
189
$delete_status = 1;
190
}
191
$document_classes{$_->class} = 1;
192
} @documents;
193
map {
194
if ( exists $_->{inline} && $_->{inline} ) {
195
$inline_status = 1;
196
}
197
} @columns;
198
199
$result{success} = 1;
200
$result{total} = $total;
201
$result{page} = $p;
202
$result{nothing_found} = $nothing_found;
203
if ( $build_html ) {
204
my $html = '';
205
foreach my $document ( @documents ) {
206
next unless ref $document;
207
$html .= $m->scomp( '/contenido/components/section_browse_row.msn',
208
document => $document,
209
columns => \@columns,
210
section => $section,
211
toopi => $toopi,
212
inline_status => $inline_status,
213
lookup_elemets => \%lookup_elements,
214
filter => \%filter_params,
215
params_unsection => $params_unsection,
216
params_unclassed => $params_unclassed
217
);
218
}
219
$result{html} = Encode::decode('utf-8', $html);
220
}
221
if ( $return eq 'hash' ) {
222
$result{inline_status} = $inline_status;
223
$result{delete_status} = $delete_status;
224
$result{columns} = \@columns;
225
$result{documents} = \@documents;
226
$result{lookup_elements} = \%lookup_elements;
227
$result{filter} = \%filter_params;
228
$result{toopi} = $toopi;
229
$result{params_unsection} = $params_unsection;
230
$result{params_unclassed} = $params_unclassed;
231
} else {
232
$result{columns} = scalar @columns;
233
}
234
} else {
235
$result{error} = $return eq 'hash' ? 'Секция не найдена' : Encode::decode('utf-8', 'Секция не найдена');
236
}
237
} else {
238
$result{error} = $return eq 'hash' ? 'Переданы неверные параметры' : Encode::decode('utf-8', 'Переданы неверные параметры');
239
}
240
241
my $json;
242
if ( $return eq 'hash' ) {
243
return %result;
244
} else {
245
$json = encode_json \%result;
246
}
247
248
</%init>
utf8/core/comps/contenido/components/section_browse.msn
1
<style>
2
.section-content tr.disabled { background:#f0f0f0; }
3
.section-content tr.disabled td.actions a { display:none; }
4
5
</style>
1
6
<script type="text/javascript">
2
7
<!--
3
8
function checkbox_common_toggle ( sClassSelector ) {
…
…
90
95
91
96
function set_status_toggle( ev, nID, $class_name ) {
92
97
ev.preventDefault();
98
$('#row-' + nID).addClass('disabled');
93
99
$.ajax({
94
100
'url' : '/contenido/ajax/document_status.html',
95
101
'data' : { 'class' : $class_name, 'id' : nID, 'toggle' : 1, 's' : <% ref $section ? $section->id : 0 %>, 'params' : '<% $params %>' },
…
…
99
105
alert( data.error );
100
106
}
101
107
if ( data.success ) {
102
$('#row-' + nID).html(data.html);
103
$('#status-set-'+ nID).on('click', function( ev ) {
108
$('.section-content').html(data.html);
109
$('.context-menu-'+ $class_name).on('click', function( ev ) {
104
110
set_status_toggle(ev, nID, $class_name)
105
111
});
106
112
}
…
…
115
121
trigger: 'left',
116
122
callback: function(key, options) {
117
123
var nID = parseInt($(this).data('id'));
124
$('#row-' + nID).addClass('disabled');
118
125
if ( nID != key ) {
119
126
$.ajax({
120
127
'url' : '/contenido/ajax/document_status.html',
…
…
125
132
alert( data.error );
126
133
}
127
134
if ( data.success ) {
128
$('#row-' + nID).html(data.html);
129
set_status( '#status-set-'+ nID, $class_name);
135
$('.section-content').html(data.html);
136
set_status( '.context-menu-'+ $class_name, $class_name);
130
137
}
131
138
}
132
139
});
…
…
206
213
% }
207
214
%
208
215
</tr>
216
<tbody class="section-content">
209
217
%
210
218
% unless (@$documents) {
211
219
<tr><td align="center" colspan="<% scalar @$columns %>">Документы не найдены</td></tr>
212
220
% }
213
221
% foreach my $document (@$documents) {
214
%
215
222
% next unless ref($document);
216
% my $document_access = $user->section_accesses($user, $document->section);
217
%
218
223
<& /contenido/components/section_browse_row.msn, document => $document, columns => $columns, section => $section,
219
224
toopi => $toopi, inline_status => $inline_status, lookup_elemets => \%lookup_elements,
220
225
filter => $filter, params_unsection => $params_unsection, params_unclassed => $params_unclassed
221
226
&>
222
227
% } #- foreach @documents
228
</tbody>
223
229
</table>
224
230
<input type="hidden" name="id" value="<% $section->id %>">
225
231
% if ( ref $filter eq 'HASH' ) {
utf8/core/comps/contenido/components/section_browse_row.msn
150
150
%
151
151
% } elsif ($attr eq '_act_') {
152
152
%
153
<td nowrap>\
153
<td nowrap class="actions">\
154
154
% if ($document_access == 2) {
155
155
%
156
156
<a href="document.html?id=<% $document->id %>&class=<% $document->class %><% $params_unclassed ? '&'.$params_unclassed : '' %>" title="Редактировать документ"><img
utf8/core/comps/contenido/sections.html
218
218
my $filter = $m->comp('/contenido/components/context.msn', name => 'filter');
219
219
my $profile = $m->comp('/contenido/components/context.msn', name => 'profile');
220
220
221
unless (defined $request->{section_accesses}->{$id})
222
{
223
$request->{section_accesses}->{$id} = $user->get_section_access($id);
224
}
225
my $section_access = $request->{section_accesses}->{$id};
226
227
my (@documents, $total);
228
229
my $s = $owner->id;
230
my $sorted = $owner->_sorted();
231
$s .= ",$filter" if ($filter > 0);
232
233
221
if ($update) {
234
222
my $return_params = join ('&', map { $_.'='.$filter_params{$_} } grep { $_ ne 's' } keys %filter_params );
235
223
my %updated;
…
…
410
398
$m->redirect("sections.html?id=".$id.($return_params ? '&'.$return_params : ''));
411
399
}
412
400
401
unless (defined $request->{section_accesses}->{$id}) {
402
$request->{section_accesses}->{$id} = $user->get_section_access($id);
403
}
404
my $section_access = $request->{section_accesses}->{$id};
405
406
my (@documents, $total);
407
408
my $s = $owner->id;
409
my $sorted = $owner->_sorted();
410
$s .= ",$filter" if ($filter > 0);
411
413
412
my %filter=();
414
413
my $nothing_found = 0;
415
414
my %order = (not $class and $owner->order_by) ? (order_by => $owner->order_by) : (order => ['date','direct']);
Небольшая справка по веткам
cnddist – контейнер, в котором хранятся все дистрибутивы всех библиотек и программных пакетов, которые использовались при построении различных версий Contenido. Если какой-то библиотеки в данном хранилище нет, инсталлятор сделает попытку "подтянуть" ее с веба (например, с CPAN). Если библиотека слишком старая, есть очень большая вероятность, что ее там уже нет. Поэтому мы храним весь хлам от всех сборок. Если какой-то дистрибутив вдруг отсутствует в cnddist - напишите нам, мы положим его туда.
koi8 – отмирающая ветка, чей код, выдача и все внутренние библиотеки заточены на кодировку KOI8-R. Вносятся только те дополнения, которые касаются внешнего вида и функционала админки, баги ядра, обязательные обновления портов и мелочи, которые легко скопипастить. В дальнейшем планируется полная остановка поддержки по данной ветке.
utf8 – актуальная ветка, заточенная под UTF-8.
Внутри каждой ветки: core – исходники ядра; install – скрипт установки инсталляции; plugins – плагины; samples – "готовые к употреблению" проекты, которые можно поставить, запустить и посмотреть, как они работают.