Line # Revision Author
1 8 ahitrov@rambler.ru <& "/contenido/components/header.msn" &>
2 <& "/contenido/components/naviline.msn", sect_id => $owner->id &>
3
4 17 ahitrov@rambler.ru <script type="text/javascript">
5 <!--
6 function set_create_button( oSelect, sBtnID ) {
7 if ( oSelect.value == '' ) {
8 $('#'+sBtnID).attr('disabled','disabled');
9 } else {
10 $('#'+sBtnID).removeAttr('disabled');
11 }
12 }
13 //-->
14 </script>
15
16 8 ahitrov@rambler.ru <table width="100%" cellspacing="0" cellpadding="0" border="0">
17 <tr valign="top">
18 607 ahitrov <td id="column-side">
19 8 ahitrov@rambler.ru
20 <& "/contenido/components/subsection.msn", section => $owner &>
21 <& "/contenido/components/class_filter.msn", class=> $class, section => $owner &>
22
23 % if (( $owner->id ) && ($owner->id > 0) )
24 % {
25 <& "/contenido/components/section_info.msn", section => $owner &>
26 % }
27
28 % my @LEFT = $m->comp('components/tasks.msn');
29 % my %LEFTh = map { $_->{attr} => $_ } (@LEFT);
30 % if (ref($request->{tab}->{lefts}))
31 % {
32 % for my $left (@{ $request->{tab}->{lefts} })
33 % {
34 % next if (! exists($LEFTh{$left}));
35 <& '/contenido/components/'.$LEFTh{$left}->{component}, %ARGS &>
36 % }
37 % }
38
39 <!-- Примечания -->
40 <fieldset>
41 <legend>Примечания</legend>
42 <table width="100%" cellspacing="5" cellpadding="0" class="tform">
43
44 <tr>
45 <th valign=top>1)</th>
46 <td width="100%">
47 Дата и время документа - поле, которое Вы можете редактировать.<br><br>
48 Кроме этого у каждого документа существует еще две временные отметки - дата создания (ctime) и дата модификации (mtime).
49 Это служебные поля и Вы не можете их изменять (они доступны только для чтения).
50 </td>
51 </tr>
52
53 </table>
54 </fieldset>
55
56 </td>
57 607 ahitrov <td width="2%"><a href="javascript:void()" class="width-toggler"><img src="/contenido/i/icons/left-right.png" width="30"></a></td>
58 <td id="column-content">
59 8 ahitrov@rambler.ru % if($owner->id) {
60
61 <fieldset>
62 <legend>Документы\
63 % if ($class) {
64 класса <% $class %>\
65 % if ($use_section) {
66 c учетом текущей секции\
67 % }
68 % } else {
69 в разделе\
70 % }
71 118 ahitrov % if (!$owner->no_count && $total > 0) {
72 624 ahitrov (всего: <% $total %>, показано с <% $first + 1 %> по <% $sorted ? $total : ($first + $n > $total) ? $total : $first + $n %>)
73 118 ahitrov % } elsif ( $owner->no_count ) {
74 (<span style="color:yellow">без пересчета</span>, показано с <% $first + 1 %> по <% $first + scalar @documents %>)
75 8 ahitrov@rambler.ru % }
76 </legend>
77
78 118 ahitrov % if ($total || scalar @documents || defined($alpha) || defined($search) ) {
79 616 ahitrov <table border="0" cellspacing="0" cellpadding="2" width="100%">
80 <tr>
81 8 ahitrov@rambler.ru % if ($section_access == 2) {
82 616 ahitrov <td width="99%">
83 8 ahitrov@rambler.ru <& "/contenido/components/new_objects_form.msn", proto => 'documents',
84 616 ahitrov sect_id => $owner->id, section => $owner,
85 default => ($owner->default_document_class ? $owner->default_document_class : undef) &>
86 </td>
87 8 ahitrov@rambler.ru % }
88 616 ahitrov <td width="1%">
89 <& "/contenido/components/section_page_size.msn", section => $owner &>
90 </td>
91 </tr>
92 </table>
93 117 ahitrov <div style="font-size:12px; font-family:Arial;">
94 8 ahitrov@rambler.ru <table border="0" cellspacing="0" cellpadding="2" width="100%" style="margin:4px 0 0; border:1px solid gray;">
95 <tr bgcolor="#e0e0e0"><th colspan="4">Поиск по букве:&nbsp;&nbsp;[<a href="?id=<% $id %>" style="font-weight:normal;">сброс фильтра</a>]</th></tr>
96 117 ahitrov <tr><td style="font-size:12px; font-family:Arial; padding:2px 4px;">
97 8 ahitrov@rambler.ru <& /inc/alpha.msn, alpha=>$alpha, params=>\%ARGS, &>
98 </td></tr></table>
99 % ## Форма поиска. Работает при включенном фильтре класса
100 % ## и описанной для класса функции search_fields
101 % ########################################################
102 450 ahitrov % if ( $filter{class} || $filter{table} ) {
103 459 ahitrov % my ($document) = $filter{class} ? ($filter{class}->new( $keeper )) : map { $_->new( $keeper ) } grep { $_->new( $keeper )->class_table eq $owner->default_table_class } @{ $user->get_available_classes };
104 8 ahitrov@rambler.ru % my @fields = $document->search_fields;
105 % if ( @fields ) {
106 % my @props = $document->required_properties;
107 <form action="sections.html">
108 <table border="0" cellspacing="0" cellpadding="2" width="100%" style="margin:4px 0; border:1px solid gray;">
109 <tr bgcolor="#e0e0e0"><th colspan="4">Поиск по полю:&nbsp;&nbsp;[<a href="?id=<% $id %>" style="font-weight:normal;">сброс фильтра</a>]</th></tr><tr>
110 <td width="1%" nowrap style="padding:2px 0 2px 4px;"><select name="search_by">
111 % foreach my $field ( @fields ) {
112 % my ($prop) = grep { $_->{'attr'} eq $field } @props;
113 % my $selected = $field eq $search_by ? ' selected' : '';
114 <option value="<% $field %>"<% $selected %>><% ref $prop ? $prop->{'shortname'} || $prop->{'rusname'} : $field %>
115 % }
116 </td><td width="0">:</td>
117 <td width="98%"><input type="text" name="search" value="<% $search %>" style="width:100%"></td>
118 <td width="1%" style="padding:2px 4px 2px 0;"><input type="submit" value=" &raquo; " style="border:1px solid gray;"></td>
119 </tr></table>
120 % if ( $id ) {
121 <input type="hidden" name="id" value="<% $id %>">
122 % }
123 % if ( $class ) {
124 <input type="hidden" name="class" value="<% $class %>">
125 % }
126 % if ( $use_section ) {
127 <input type="hidden" name="use_section" value="<% $use_section %>">
128 % }
129 </form>
130 % }
131 % }
132
133 <div style="height:5px"><spacer type="block" height="5"></div>
134 118 ahitrov % if ( $owner->no_count ) {
135 <& /inc/pages_nocount.msn, p=>$p, n=>$n, found=> scalar @documents, href=>'sections.html', params=>\%ARGS, size => 15 &>
136 624 ahitrov % } elsif ( $sorted ) {
137 118 ahitrov % } else {
138 8 ahitrov@rambler.ru <& /inc/pages_.msn, p=>$p, n=>$n, total=>$total, href=>'sections.html', params=>\%ARGS, &>
139 118 ahitrov % }
140 8 ahitrov@rambler.ru </div>
141
142 <& /contenido/components/section_browse.msn, documents => \@documents, columns => \@columns, section => $owner, filter => \%filter_params, %ARGS &>
143
144 117 ahitrov <div style="font-size:12px; font-family:Arial;">
145 118 ahitrov % if ( $owner->no_count ) {
146 <& /inc/pages_nocount.msn, p=>$p, n=>$n, found=> scalar @documents, href=>'sections.html', params=>\%ARGS, size => 15 &>
147 624 ahitrov % } elsif ( $sorted ) {
148 118 ahitrov % } else {
149 8 ahitrov@rambler.ru <& /inc/pages_.msn, p=>$p, n=>$n, total=>$total, href=>'sections.html', params=>\%ARGS, &>
150 118 ahitrov % }
151 8 ahitrov@rambler.ru <div style="height:5px"><spacer type="block" height="5"></div>
152 </div>
153
154 % } else {
155 <h4 align="center"><i>---- Нет документов -----</i></h4>
156 % }
157 %
158 % if ($section_access == 2) {
159 <& "/contenido/components/new_objects_form.msn", proto => 'documents',
160 sect_id => $owner->id,
161 default => ($owner->default_document_class ? $owner->default_document_class : undef) &>
162 % }
163
164 </fieldset>
165 </td>
166 </tr>
167 </table>
168
169 % }
170
171 </body>
172 </html>
173 607 ahitrov <%once>
174
175 my $cookie_name = 'content_fullwidth';
176
177 </%once>
178 8 ahitrov@rambler.ru <%args>
179
180 $id => undef
181 $p => 1
182 $class => undef
183 $use_section => undef
184 $alpha => undef
185 $alpha_search => undef
186 $search_by => undef
187 $search => undef
188 $update => undef
189 $delete => undef
190
191 </%args>
192 <%init>
193
194 $id = 0 if $id =~ /\D/;
195 607 ahitrov my $content_fullwidth = $m->comp('/contenido/components/cookies.msn', name => $cookie_name);
196
197 8 ahitrov@rambler.ru my $owner;
198
199 # Операции...
200 if ($id && ($id > 0))
201 {
202 $owner = $keeper->get_section_by_id($id);
203 }
204 if (! ref($owner))
205 {
206 return undef;
207 }
208
209 my %filter_params;
210 $filter_params{use_section} = $use_section if $use_section;
211 $filter_params{class} = $class if $class;
212 $filter_params{alpha} = $alpha if $alpha;
213 $filter_params{alpha_search} = $alpha_search if $alpha_search;
214 $filter_params{search_by} = $search_by if $search_by;
215 $filter_params{search} = $search if $search;
216 $filter_params{p} = $p if $p > 1;
217 $filter_params{s} = $id if $id;
218
219 16 ahitrov@rambler.ru # Фильтры работают в любом случае...
220 8 ahitrov@rambler.ru my $filter = $m->comp('/contenido/components/context.msn', name => 'filter');
221 my $profile = $m->comp('/contenido/components/context.msn', name => 'profile');
222
223 if ($update) {
224 my $return_params = join ('&', map { $_.'='.$filter_params{$_} } grep { $_ ne 's' } keys %filter_params );
225 my %updated;
226 while ( my ($field, $value) = each %ARGS ) {
227 if ( $field =~ /^update_(\d+)_(\w+)$/ ) {
228 my $oid = $1;
229 my $attr = $2;
230 $updated{$oid}{$attr} = $value;
231 }
232 }
233 my %classes = map { $_->{class} => 1 } values %updated;
234 foreach my $update_class ( keys %classes ) {
235 my @ids;
236 while ( my ($oid, $attr) = each %updated) {
237 push @ids, $oid if $attr->{class} eq $update_class;
238 }
239 my @objects = $keeper->get_documents (
240 id => \@ids,
241 class => $update_class
242 ) if @ids;
243 foreach my $object ( @objects ) {
244 my $document_access = $user->section_accesses($user, $object->section);
245 next unless $document_access == 2;
246 my $fields = $updated{$object->id};
247 my @props = grep { exists $_->{inline} && $_->{inline} } $object->structure;
248 if ( ref $fields eq 'HASH' ) {
249 foreach my $prop ( @props ) {
250 my $attr = $prop->{attr};
251 my $value = ref $fields && exists $fields->{$attr} ? $fields->{$attr} : undef;
252 395 ahitrov if ( $prop->{type} eq 'checkbox' ) {
253 $value = $value ? 1 : undef;
254 }
255 386 ahitrov if ( exists $prop->{db_type} ) {
256 if ( $prop->{db_type} eq 'float' ) {
257 for ( $value ) {
258 s/\,/\./;
259 s/^\s+//;
260 s/\s+$//;
261 }
262 if ( $value eq '' ) {
263 $value = undef;
264 }
265 } elsif ( $prop->{db_type} eq 'integer' || $prop->{db_type} eq 'smallint' ) {
266 $value =~ s/\D//sg if $value;
267 if ( $value eq '' ) {
268 $value = undef;
269 }
270 8 ahitrov@rambler.ru }
271 }
272
273 $object->$attr($value);
274 }
275 $object->store;
276 }
277 }
278 }
279 $m->redirect("sections.html?id=".$id.($return_params ? '&'.$return_params : ''));
280 }
281 if ( $delete ) {
282 my $return_params = join ('&', map { $_.'='.$filter_params{$_} } grep { $_ ne 's' } keys %filter_params );
283 my %deleted;
284 while ( my ($field, $value) = each %ARGS ) {
285 if ( $field =~ /^delete_(\d+)_(\w+)$/ ) {
286 my $oid = $1;
287 my $attr = $2;
288 $deleted{$oid}{$attr} = $value;
289 }
290 }
291 my %classes = map { $_->{class} => 1 } values %deleted;
292 foreach my $delete_class ( keys %classes ) {
293 my @ids;
294 while ( my ($oid, $attr) = each %deleted) {
295 push @ids, $oid if exists $attr->{id} && $attr->{id} && ($attr->{class} eq $delete_class);
296 }
297 my @objects = $keeper->get_documents (
298 id => \@ids,
299 class => $delete_class
300 ) if @ids;
301 foreach my $object ( @objects ) {
302 my $document_access = $user->section_accesses($user, $object->section);
303 next unless $document_access == 2;
304 $object->delete;
305 }
306 }
307 $m->redirect("sections.html?id=".$id.($return_params ? '&'.$return_params : ''));
308 }
309 386 ahitrov if ( $ARGS{move} || $ARGS{link} ) {
310 my $return_params = join ('&', map { $_.'='.$filter_params{$_} } grep { $_ ne 's' } keys %filter_params );
311 if ( exists $ARGS{tree} && $ARGS{tree} && $ARGS{tree} != $owner->id ) {
312 my %updated;
313 while ( my ($field, $value) = each %ARGS ) {
314 388 ahitrov if ( $field =~ /^delete_(\d+)_(\w+)$/ ) {
315 386 ahitrov my $oid = $1;
316 my $attr = $2;
317 $updated{$oid}{$attr} = $value;
318 }
319 }
320 522 ahitrov warn Dumper \%updated if $DEBUG;
321 386 ahitrov my %classes = map { $_->{class} => 1 } values %updated;
322 my $parent_new = $keeper->get_section_by_id( $ARGS{tree} );
323 my $document_access = $user->section_accesses($user, $parent_new->id);
324 if ( $document_access == 2 ) {
325 foreach my $update_class ( keys %classes ) {
326 my @ids;
327 while ( my ($oid, $attr) = each %updated) {
328 388 ahitrov push @ids, $oid if exists $attr->{id} && $attr->{id} && ($attr->{class} eq $update_class);
329 386 ahitrov }
330 my @objects = $keeper->get_documents (
331 id => \@ids,
332 class => $update_class
333 ) if @ids;
334 my ($prop) = grep { $_->{attr} eq 'sections' } $update_class->new( $keeper )->structure;
335 if ( ref $prop && exists $prop->{db_type} && exists $prop->{db_field} ) {
336 foreach my $object ( @objects ) {
337 if ( $prop->{db_type} eq 'integer[]' ) {
338 my @sections = grep { $_ != $parent_new->id } $object->sections;
339 if ( @sections && $sections[0] == $owner->id ) {
340 419 ahitrov if ( $ARGS{move} ) {
341 shift @sections;
342 unshift @sections, $parent_new->id;
343 } else {
344 push @sections, $parent_new->id;
345 }
346 } else {
347 if ( $ARGS{move} ) {
348 @sections = grep { $_ != $owner->id } @sections;
349 }
350 521 ahitrov push @sections, $parent_new->id;
351 386 ahitrov }
352 $object->sections( @sections );
353 } else {
354 $object->sections( $parent_new->id );
355 }
356 $object->store;
357 }
358 }
359 }
360 }
361 }
362 $m->redirect("sections.html?id=".$id.($return_params ? '&'.$return_params : ''));
363 522 ahitrov } elsif ( $ARGS{unlink} ) {
364 my $return_params = join ('&', map { $_.'='.$filter_params{$_} } grep { $_ ne 's' } keys %filter_params );
365 my $document_access = $user->section_accesses($user, $owner->id);
366 my %updated;
367 while ( my ($field, $value) = each %ARGS ) {
368 if ( $field =~ /^delete_(\d+)_(\w+)$/ ) {
369 my $oid = $1;
370 my $attr = $2;
371 $updated{$oid}{$attr} = $value;
372 }
373 }
374 warn Dumper \%updated if $DEBUG;
375 my %classes = map { $_->{class} => 1 } values %updated;
376 if ( $document_access == 2 ) {
377 foreach my $update_class ( keys %classes ) {
378 my @ids;
379 while ( my ($oid, $attr) = each %updated) {
380 push @ids, $oid if exists $attr->{id} && $attr->{id} && ($attr->{class} eq $update_class);
381 }
382 my @objects = $keeper->get_documents (
383 id => \@ids,
384 class => $update_class
385 ) if @ids;
386 my ($prop) = grep { $_->{attr} eq 'sections' } $update_class->new( $keeper )->structure;
387 if ( ref $prop && exists $prop->{db_type} && exists $prop->{db_field} ) {
388 foreach my $object ( @objects ) {
389 if ( $prop->{db_type} eq 'integer[]' ) {
390 my @sections = grep { $_ != $owner->id } $object->sections;
391 $object->sections( @sections );
392 } else {
393 $object->sections( undef );
394 }
395 $object->store;
396 }
397 }
398 }
399 }
400 $m->redirect("sections.html?id=".$id.($return_params ? '&'.$return_params : ''));
401 386 ahitrov }
402 8 ahitrov@rambler.ru
403 621 ahitrov unless (defined $request->{section_accesses}->{$id}) {
404 $request->{section_accesses}->{$id} = $user->get_section_access($id);
405 }
406 my $section_access = $request->{section_accesses}->{$id};
407
408 my (@documents, $total);
409
410 my $s = $owner->id;
411 my $sorted = $owner->_sorted();
412 $s .= ",$filter" if ($filter > 0);
413
414 8 ahitrov@rambler.ru my %filter=();
415 131 ahitrov my $nothing_found = 0;
416 8 ahitrov@rambler.ru my %order = (not $class and $owner->order_by) ? (order_by => $owner->order_by) : (order => ['date','direct']);
417 if (defined $alpha and $alpha ne '') {
418 $filter{ilike}=1;
419 $filter{ $alpha_search || 'name' }="$alpha%";
420 $order{order}=['name','reverse'];
421 delete $order{order_by};
422 }
423 if ( $class ) {
424 $filter{class} = $class;
425 } elsif ( $owner->default_document_class ) {
426 $filter{class} = $owner->default_document_class;
427 } elsif ( $owner->default_table_class ) {
428 $filter{table} = $owner->default_table_class;
429 }
430 $filter{s}=$s unless ($class && !$use_section);
431 if ( $search_by && defined $search ) {
432 my $doc_class = $class || $owner->default_document_class;
433 if ( $doc_class ) {
434 my @props = $doc_class->new( $keeper )->structure();
435 my ($prop) = grep { $_->{attr} eq $search_by } @props if @props;
436 131 ahitrov if ( ref $prop && ($prop->{type} eq 'integer' || $prop->{type} eq 'checkbox' ||
437 546 ahitrov (($prop->{type} eq 'pickup' || $prop->{type} eq 'lookup' || $prop->{type} eq 'status') && $search =~ /^\d+$/) ||
438 137 ahitrov (exists $prop->{db_type} && $prop->{db_type} =~ /integer\[\]/) )) {
439 8 ahitrov@rambler.ru $filter{$search_by} = int($search);
440 546 ahitrov } elsif ( ref $prop && $prop->{type} eq 'status' && $search =~ /\D/ ) {
441 my $str;
442 foreach my $pair ( @{$prop->{cases}} ) {
443 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)) ) {
444 $str = $pair->[0];
445 last;
446 }
447 }
448 if ( $str ) {
449 $filter{$search_by} = $str;
450 }
451 131 ahitrov } elsif ( ref $prop && ($prop->{type} eq 'pickup' || $prop->{type} eq 'lookup') && $search =~ /\D/ ) {
452 my $lookup_opts = $prop->{lookup_opts};
453 386 ahitrov if ( ref $lookup_opts && (exists $lookup_opts->{class} || exists $lookup_opts->{table}) ) {
454 131 ahitrov my $search_field = exists $lookup_opts->{search_by} ? $lookup_opts->{search_by} : 'name';
455 my @ids = $keeper->get_documents (
456 ids => 1,
457 386 ahitrov exists $lookup_opts->{class} ? (class => $lookup_opts->{class}) : (table => $lookup_opts->{table}),
458 131 ahitrov ilike => 1,
459 $search_field => '%'.$search.'%',
460 );
461 if ( @ids ) {
462 $filter{$search_by} = \@ids;
463 } else {
464 $nothing_found = 1;
465 }
466 }
467 8 ahitrov@rambler.ru } else {
468 $filter{$search_by}='%'.$search.'%';
469 $filter{ilike} = 1;
470 }
471 } else {
472 $filter{$search_by}='%'.$search.'%';
473 $filter{ilike} = 1;
474 }
475 }
476
477 131 ahitrov # Дополнительные фильтры раздела
478 if ($owner->filters) {
479 no strict 'vars';
480 my $filters = eval($owner->filters);
481 if ($@) {
482 warn "Bad filter: " . $owner->filters . " in section " . $owner->id;
483 } elsif (ref $filters eq 'HASH') {
484 while ( my ($key, $val) = each %$filters ) {
485 $filter{$key} = $val;
486 }
487 }
488 }
489 8 ahitrov@rambler.ru
490 118 ahitrov $total = $keeper->get_documents(%filter, count=>1) unless $owner->no_count;
491 8 ahitrov@rambler.ru
492 616 ahitrov my $n = ref $owner && $owner->_page_size ? $owner->_page_size : 40;
493 8 ahitrov@rambler.ru my $first = $n * ($p - 1);
494 118 ahitrov ($first,$p)=(0,0) if (!$owner->no_count && $first>$total);
495 8 ahitrov@rambler.ru
496 131 ahitrov unless ( $nothing_found ) {
497 if ($class && !$use_section) {
498 @documents = $keeper->get_documents(%filter, %order, limit=>$n, offset=>$first);
499 } elsif ($sorted) {
500 607 ahitrov @documents = $keeper->get_sorted_documents(%filter);
501 131 ahitrov } else {
502 @documents = $keeper->get_documents(%filter, %order, limit=>$n, offset=>$first);
503 }
504 8 ahitrov@rambler.ru }
505 # набор колонок таблицы документов...
506 131 ahitrov my @columns = $sorted ? ({attr => '_sort_', name => 'N'}) : ();
507 8 ahitrov@rambler.ru
508 131 ahitrov # пытаемся найти колонки, которые документ сам пожелал показать (required_properties -> column)...
509 if ($filter{class} or @documents and $documents[0]) {
510 push @columns,
511 sort {$a->{column} <=> $b->{column}}
512 grep {$_->{column}} ($filter{class} ? $filter{class}->new($keeper)->structure : $documents[0]->structure);
513 }
514 8 ahitrov@rambler.ru
515 131 ahitrov # стандартная жопка таблицы...
516 @columns = (@columns,
517 {attr => '_act_', rusname => 'Действия'},
518 );
519
520 8 ahitrov@rambler.ru </%init>

Небольшая справка по веткам

cnddist – контейнер, в котором хранятся все дистрибутивы всех библиотек и программных пакетов, которые использовались при построении различных версий Contenido. Если какой-то библиотеки в данном хранилище нет, инсталлятор сделает попытку "подтянуть" ее с веба (например, с CPAN). Если библиотека слишком старая, есть очень большая вероятность, что ее там уже нет. Поэтому мы храним весь хлам от всех сборок. Если какой-то дистрибутив вдруг отсутствует в cnddist - напишите нам, мы положим его туда.

koi8 – отмирающая ветка, чей код, выдача и все внутренние библиотеки заточены на кодировку KOI8-R. Вносятся только те дополнения, которые касаются внешнего вида и функционала админки, баги ядра, обязательные обновления портов и мелочи, которые легко скопипастить. В дальнейшем планируется полная остановка поддержки по данной ветке.

utf8 – актуальная ветка, заточенная под UTF-8.

Внутри каждой ветки: core – исходники ядра; install – скрипт установки инсталляции; plugins – плагины; samples – "готовые к употреблению" проекты, которые можно поставить, запустить и посмотреть, как они работают.