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 – "готовые к употреблению" проекты, которые можно поставить, запустить и посмотреть, как они работают.