Revision 630

Date:
2016/12/09 15:54:41
Author:
ahitrov
Revision Log:
Tag editing form

Files:

Legend:

 
Added
 
Removed
 
Modified
  • utf8/plugins/tag/comps/contenido/tag/ajax/tag_edit_form.html

     
    1 1 % if ( ref $tag ) {
    2 % if ( $tag->id ) {
    2 3 <fieldset>
    3 4 <legend><% $tag->id ? 'Редактировать' : 'Создать' %> тег</legend>
    4 5 <& /contenido/tag/components/form_tag_edit.msn, object => $tag &>
    5 6 </fieldset>
    7 % } else {
    8 <fieldset>
    9 <legend><% $tag->id ? 'Редактировать' : 'Создать' %> тег</legend>
    10 <& /contenido/tag/components/form_tag_edit.msn, object => $tag &>
    11 </fieldset>
    12 % }
    6 13 % } else {
    7 14 <div class="error-prompt">Не найден тег с ID=<% $id |h %></div>
    8 15 % }
  • utf8/plugins/tag/comps/contenido/tag/ajax/tag_store.html

     
    1 <% $json %>
    2 <%once>
    3
    4 use JSON::XS;
    5
    6 </%once>
    7 <%args>
    8
    9 $id => undef
    10
    11 </%args>
    12 <%init>
    13
    14 my %result;
    15
    16 warn Dumper \%ARGS;
    17 if ( !$id || $id && $id =~ /^\d+$/ && $id > 0 ) {
    18 my $tag;
    19 if ( $id ) {
    20 $tag = $keeper->get_document_by_id( $id, class => 'tag::Tag' );
    21 } else {
    22 $tag = tag::Tag->new( $keeper );
    23 }
    24 if ( ref $tag ) {
    25 my $dup = $keeper->get_documents(
    26 $tag->id ? ( excludes => $tag->id ) : (),
    27 name => $ARGS{name},
    28 ilike => 1,
    29 class => 'tag::Tag',
    30 count => 1,
    31 );
    32 if ( $dup ) {
    33 $result{error} = Encode::decode('utf-8', 'Найден дубликат тега с таким названием');
    34 } else {
    35 $tag->name( $ARGS{name} );
    36 $tag->alias( $ARGS{alias} );
    37 $tag->status( $ARGS{status} );
    38 $m->comp('/contenido/tag/components/outputs/tag_tree.msn', SETS => \%ARGS, object => $tag);
    39 if ( $tag->store ) {
    40 $result{success} = 1;
    41 $result{id} = $tag->id;
    42 } else {
    43 $result{error} = Encode::decode('utf-8', 'Системная ошибка сохранения. Смотри логи');
    44 }
    45 }
    46 } else {
    47 $result{error} = Encode::decode('utf-8', 'Тег с данным идентификатором не найден');
    48 }
    49 } else {
    50 $result{error} = Encode::decode('utf-8', 'Неверно указан идентификатор');
    51 }
    52
    53 my $json = encode_json \%result;
    54 # $r->content_type('application/json');
    55
    56 </%init>
  • utf8/plugins/tag/comps/contenido/tag/components/block_tag_list.msn

     
    1 1 % if ( @$tags ) {
    2 <script type="text/javascript">
    3 <!--
    4 $(document).ready(function(){
    5 $('.js-edit-tag').on('click', function( ev ){
    6 ev.preventDefault();
    7 OpenContentForm( $(this).data('id') );
    8 });
    9
    10 });
    11 //-->
    12 </script>
    2 13 <table width="100%" border="0" cellpadding="4" cellspacing="0" class="tlistdocs">
    3 14 <tr bgcolor="#efefef">
    4 15 <th>id</th>
     
    9 20 </tr>
    10 21 % foreach my $tag ( @$tags ) {
    11 22 <tr valign="top">
    12 <td><% $tag->id %></td>
    13 <td><% $tag->name %></td>
    23 <td><a href="?id=<% $tag->id %>" class="status-<% $tag->status %> js-edit-tag" data-id="<% $tag->id %>"><% $tag->id %></a></td>
    24 <td><a href="?id=<% $tag->id %>" class="status-<% $tag->status %> js-edit-tag" data-id="<% $tag->id %>"><% $tag->name %></a></td>
    14 25 <td><% $tag->alias %></td>
    15 26 <td></td>
    16 27 <td></td>
  • utf8/plugins/tag/comps/contenido/tag/components/form_tag_edit.msn

     
    1 <script type="text/javascript">
    2 <!--
    3 $(document).ready(function(){
    4 $('#tag-edit-submit').on('click', function(ev){
    5 ev.preventDefault();
    6 var oForm = document.forms['tag-edit-form'];
    7 if ( oForm.elements['name'].value == '' ) {
    8 $('#tag-edit-error-prompt').text('Не указано название тега').show();
    9 oForm.elements['name'].focus();
    10 return false;
    11 }
    12 var nId = oForm.elements['id'].value;
    13 var sName = oForm.elements['name'].value;
    14 var sAlias = oForm.elements['alias'].value;
    15 var nStatus = oForm.elements['status'].value;
    16 var nPid = oForm.elements['pid'].value;
    17 $('#tag-edit-error-prompt').hide();
    18 $.ajax({
    19 'url' : '/contenido/tag/ajax/tag_store.html',
    20 'data' : { 'id' : nId, 'name' : sName, 'alias' : sAlias, 'status' : nStatus, 'pid' : nPid },
    21 'type' : 'POST',
    22 'dataType' : "json",
    23 'success' : function( data ) {
    24 if ( data.error ) {
    25 $('#tag-edit-error-prompt').text(data.error).show();
    26 }
    27 if ( data.success ) {
    28 nTagsFormEditing = 0;
    29 OpenContentForm( data.id );
    30 }
    31 },
    32 'error' : function(XMLHttpRequest, textStatus) {
    33 alert(textStatus);
    34 }
    35 });
    36 });
    37 });
    38 //-->
    39 </script>
    1 40 <form enctype="multipart/form-data" method="POST" name="tag-edit-form">
    2
    41 <input type="hidden" name="id" value="<% $object->id %>">
    42 % if ( $object->id ) {
    43 <div class="form-field">
    44 <div class="prompt">ID: <span class="value"><% $object->id %></span></div>
    45 </div>
    46 % }
    47 % foreach my $name ( qw( name alias status ) ) {
    48 % my $prop = $props{$name};
    49 % my $type = $prop->{type};
    50 % if ( $m->comp_exists( "/contenido/components/inputs/$type.msn" ) ) {
    51 <div class="form-field">
    52 <div class="prompt"><% $prop->{rusname} %><span class="desc">| Attr=<% $prop->{attr} %>; Type=<% $prop->{type} %></span></div>
    53 <& "/contenido/components/inputs/$type.msn", object => $object, prop => $prop, name => $name, check => $object->$name &>
    54 </div>
    55 % }
    56 % }
    57 % if ( $state->{tag}->tag_structure eq 'tree' ) {
    58 % my $name = 'pid';
    59 % my $prop = $props{$name};
    60 <div class="form-field">
    61 <div class="prompt"><% $prop->{rusname} %><span class="desc">| Attr=<% $prop->{attr} %></span></div>
    62 <& /contenido/tag/components/inputs/tag_tree.msn, object => $object, name => 'pid', prop => $prop &>
    63 % }
    64 </div>
    65 <div id="tag-edit-error-prompt" class="error-prompt" style="display:none;"></div>
    66 <div class="form-submit">
    67 <input id="tag-edit-submit" type="button" class="input_btn" value="Сохранить">
    68 </div>
    3 69 </form>
    4 70 <%args>
    5 71
     
    10 76
    11 77 return unless ref $object;
    12 78 my @props = $object->structure;
    79 my %props = map { $_->{attr} => $_ } @props;
    13 80
    14 81 </%init>
  • utf8/plugins/tag/comps/contenido/tag/components/inputs/tag_tree.msn

     
    1 <select name="<% $name %>" style="width:37%" autocomplete="off">
    2 <option value="-1" style="color:red">Тег вне иерархии</option>
    3 <option value="0" style="color:blue"<% $check == 0 && $object->level > 0 ? ' selected' : '' %>>Верхний уровень</option>
    4 % if ( exists $tree->{root} && scalar @{$tree->{root}} ) {
    5 % foreach my $tag ( @{$tree->{root}} ) {
    6 % my $selected = $object->pid && $tag->id == $object->pid ? ' selected' : '';
    7 <option value="<% $tag->id %>" style="padding-left:20px;<% $selected ? 'font-weight:bold;' : '' %>"<% $selected %>><% $tag->name.($tag->alias ? ' ('.$tag->alias.')' : '') %></option>
    8 % }
    9 % }
    10 </select>
    11 <%args>
    12
    13 $object => undef
    14 $name => 'pid'
    15 $prop => undef
    16
    17 </%args>
    18 <%init>
    19
    20 return unless ref $object;
    21 ($prop) = grep { $_->{attr} eq $name } $object->structure unless ref $prop;
    22 my $tree = $keeper->{tag}->get_tree( level => 3 );
    23 my $check = $object->$name;
    24
    25 </%init>
  • utf8/plugins/tag/comps/contenido/tag/components/outputs/tag_tree.msn

     
    1 <%args>
    2
    3 $SETS => {}
    4 $object => undef
    5
    6 </%args>
    7 <%init>
    8
    9 return unless ref $object;
    10 return unless exists $SETS->{pid} && defined $SETS->{pid};
    11
    12 my $pid = $SETS->{pid};
    13 if ( $pid == 0 ) {
    14 $object->pid( 0 );
    15 $object->level( 1 );
    16 } elsif ( $pid < 0 ) {
    17 $object->pid( 0 );
    18 $object->level( 0 );
    19 } elsif ( $pid > 0 ) {
    20 my $tag = $keeper->get_document_by_id( $pid, class => 'tag::Tag' );
    21 if ( ref $tag ) {
    22 $object->pid( $pid );
    23 $object->level( $tag->level + 1 );
    24 } else {
    25 $object->pid( 0 );
    26 $object->level( 0 );
    27 }
    28 }
    29
    30 </%init>
  • utf8/plugins/tag/comps/contenido/tag/i/css/styles.css

     
    2 2 .tag-plugin .block-add-link a { text-decoration:none; }
    3 3 .tag-plugin .block-add-link a:hover { text-decoration:underline; }
    4 4
    5 .tag-plugin a.status-0 { color:gray; }
    6 .tag-plugin a.status-1 { color:#0000ee; }
    7 .tag-plugin a.status-3 { color:red; }
    8 .tag-plugin .error-prompt { border:1px solid red; padding:10px; color:red; font-size:90%; }
    5 9
    6 .tag-plugin .error-prompt { border:1px solid red; padding:10px; color:red; }
  • utf8/plugins/tag/lib/tag/Cloud.pm

     
    72 72 }
    73 73 }
    74 74 } else {
    75 warn "Tag Cloud update error: cloud_element_id=".$self->id.", no source or destination available\n";
    75 warn "Tag Cloud update error: cloud_element_id=".$self->id.", no source (".$self->source_class.", ".$self->source_id.") or destination (".$self->dest_class.", ".$self->dest_id.") available\n";
    76 76 }
    77 return 1;
    77 78 }
    78 79
    79 80 sub post_delete
     
    81 82 my $self = shift;
    82 83 my $object = $keeper->get_document_by_id($self->dest_id, class => $self->dest_class ) if $self->dest_id && $self->dest_class;
    83 84 my $tag = $self->keeper->get_document_by_id($self->source_id, class => $self->source_class ) if $self->source_id && $self->source_class;
    84 if ( ref $object && ref $tag ) {
    85 my ($prop) = grep { $_->{type} eq 'tagset' } $object->structure;
    86 my $class = $object->class;
    87 my $is_extra = grep { ref $_ && $_->{attr} eq $name } $class->extra_properties ? 1 : 0;
    88 if ( ref $prop && !(exists $prop->{virtual} && $prop->{virtual}) ) {
    89 my $name = $prop->{attr};
    90 my $struct;
    91 if ( ref $object->$name ) {
    92 $struct = $object->$name;
    93 } elsif ( $object->$name ) {
    94 $struct = JSON::XS->new->utf8->decode( $object->$name );
    95 }
    96 if ( ref $struct eq 'ARRAY' && @$struct && (grep { $_->{id} == $tag->id } @$struct) ) {
    97 @$struct = grep { $_->{id} != $tag->id } @$struct;
    98 unless ( $is_extra ) {
    99 $struct = Encode::encode('utf-8', JSON::XS->new->encode( $struct ));
    85 if ( ref $object || ref $tag ) {
    86 if ( ref $object ) {
    87 my ($prop) = grep { $_->{type} eq 'tagset' } $object->structure;
    88 my $class = $object->class;
    89 my $is_extra = grep { ref $_ && $_->{attr} eq $name } $class->extra_properties ? 1 : 0;
    90 if ( ref $prop && !(exists $prop->{virtual} && $prop->{virtual}) ) {
    91 my $name = $prop->{attr};
    92 my $struct;
    93 if ( ref $object->$name ) {
    94 $struct = $object->$name;
    95 } elsif ( $object->$name ) {
    96 $struct = JSON::XS->new->utf8->decode( $object->$name );
    100 97 }
    101 $object->$name( $struct );
    102 $object->store;
    98 if ( ref $struct eq 'ARRAY' && @$struct && (grep { $_->{id} == $tag->id } @$struct) ) {
    99 @$struct = grep { $_->{id} != $tag->id } @$struct;
    100 unless ( $is_extra ) {
    101 $struct = Encode::encode('utf-8', JSON::XS->new->encode( $struct ));
    102 }
    103 $object->$name( $struct );
    104 $object->store;
    105 }
    103 106 }
    104 107 }
    105 } else {
    106 warn "Tag Cloud delete error: cloud_element_id=".$self->id.", no source or destination available\n";
    107 108 }
    109 if ( !ref $object || !ref $tag ) {
    110 my $err = '';
    111 $err .= ", no tag (".$self->source_class.", ".$self->source_id.")" unless ref $tag;
    112 $err .= ", no object (".$self->dest_class.", ".$self->dest_id.")" unless ref $object;
    113 warn "Tag Cloud delete warning: cloud_element_id=".$self->id.$err." available\n";
    114 }
    115 return 1;
    108 116 }
    109 117
    110 118 1;
  • utf8/plugins/tag/lib/tag/Keeper.pm

     
    20 20
    21 21 my $tree;
    22 22 my $cache_key = 'plugin_tag_tree_level_'.join('_', @$level);
    23 if ( $cache && $keeper->MEMD ) {
    24 $tree = $keeper->MEMD->get( $key );
    23 if ( $cache > 0 && $keeper->MEMD ) {
    24 $tree = $keeper->MEMD->get( $cache_key );
    25 25 }
    26 26 unless ( defined $tree ) {
    27 27 $tree = { hash => {}, root => [] };
     
    32 32 order_by => 'level, pid, id',
    33 33 return_mode => 'array_ref',
    34 34 );
    35 foreach my $tag ( @$tree ) {
    35 foreach my $tag ( @$tags ) {
    36 36 $tag->{keeper} = undef;
    37 $hash->{$tag->id} = $tag;
    37 $tree->{hash}{$tag->id} = $tag;
    38 38 if ( $tag->pid ) {
    39 39 push @{$tree->{$tag->pid}}, $tag;
    40 40 if ( exists $tree->{hash}{$tag->pid} ) {
     
    44 44 push @{$tree->{root}}, $tag;
    45 45 }
    46 46 if ( $cache && $keeper->MEMD ) {
    47 $keeper->MEMD->set( $key, $tree, 3600 );
    47 $keeper->MEMD->set( $cache_key, $tree, 3600 );
    48 48 }
    49 49 }
    50 50 }
  • utf8/plugins/tag/lib/tag/Tag.pm

     
    7 7 {
    8 8 return (
    9 9 { 'attr' => 'name', 'rusname' => 'Название тега', shortname => 'Тег' },
    10 { 'attr' => 'status',
    11 cases => [
    12 [0, 'Скрытый'],
    13 [1, 'Активный'],
    14 [-1, 'Удален'],
    15
    16 ],
    17 },
    10 18 { 'attr' => 'alt_name', type => 'string', 'rusname' => 'Альтернативная форма названия', shortname => 'Словоформа' },
    11 19 )
    12 20 }
  • utf8/plugins/tag/sql/TOAST/tags-update.630.sql

     
    1 alter table tags alter column level set default 0;
    2 update tags set level = 0 where level is null;
    3
    4 drop index tags_pid;
    5 create index tags_pid on tags (pid) WHERE level > 0;
  • utf8/plugins/tag/sql/TOAST/tags.sql

     
    7 7 status smallint not null default 0,
    8 8 sections integer,
    9 9 pid integer default 0,
    10 level integer default 1,
    10 level integer default 0,
    11 11 name text,
    12 12 alias text,
    13 13 data text
    14 14 );
    15 15 create index tags_name on tags (name);
    16 16 create index tags_alias on tags (alias) WHERE alias IS NOT NULL AND alias != '';
    17 create index tags_pid on tags (pid);
    17 create index tags_pid on tags (pid) WHERE level > 0;

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

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

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

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

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