#?SuikaWikiConfig/2.0 Plugin: @Name: PropEdit @Description: @@@: WikiPage Property Editor @@lang:en @License: %%Perl%% @Author: @@Name: @@@@: Wakaba @@@lang:ja @@@script:Latn @@Mail[list]: w@suika.fam.cx @Date.RCS: $Date: 2005/02/06 12:24:08 $ @RequiredPlugin[list]: WikiEdit WikiFormCore @Namespace: @@media-type: http://suika.fam.cx/~wakaba/-temp/2004/04/24/mt# @@pe: http://suika.fam.cx/~wakaba/archive/2004/7/20/sw-propedit# @@sw: http://suika.fam.cx/~wakaba/archive/2004/7/20/sw# PluginConst: @NS_XHTML1: http://www.w3.org/1999/xhtml ViewDefinition: @Mode: pe--propedit @Condition: @@http-method[list]: GET HEAD @Description: @@@: Editing WikiPage Properties @@lang: en @template: @@http-status-code: 200 @@media-type: text/html @@use-media-type-charset: 1 @@expires: %%edit%% @@body: %html-document ( title => {%res(name=>{PropEdit:WebPageTitle});}p, link-meta => {%template (name => links); %html-meta(name => ROBOTS, content => NOINDEX);}p, content => { %template ( name => ws--page, -content => { %section ( title => {%res (name => {PropEdit:Title});}p, heading, content => { %pe--propedit (template => { %resource-as-plain-text (name => {PropEdit:Template}); }p); }p, ); }, ); }p, ); ViewDefinition: @Mode: -pe--conflict @Condition: @@http-method[list]: GET @Description: @@@: Editing WikiPage Properties -- Report Confliction @@lang: en @template: @@http-status-code: 409 @@media-type: text/html @@use-media-type-charset: 1 @@expires: %%error%% @@body: %html-document ( title => {%res(name=>{PropEdit:Conflict:WebPageTitle});}p, link-meta => {%template (name => links); %html-meta(name => ROBOTS, content => NOINDEX);}p, content => { %template ( name => ws--page, -content => { %section ( title => {%res (name => {PropEdit:Conflict:Title});}p, heading, content => { %paragraph (content => { %res (name => {PropEdit:Conflict:Description}); }p); %pe--propedit (template => { %resource-as-plain-text (name => {PropEdit:Template}); }p, ); }p);}, ); }p, ); FormattingRule: @Category[list]: view @Name: pe--propedit @Description: @@@: A property editor form @@lang: en @Parameter: @@Name: page @@Type: WikiName @@Default: (auto) @@Description: @@@@: WikiPage to be edited @@@lang:en @Parameter: @@Name: template @@Type: template @@Default: (required) @@Description: @@@@: Template of the content @@@lang: en @Formatting: __ATTRTEXT:%page__;__ATTRTEXT:%template__; my $page = $o->{wiki}->name ($p->{page} || $o->{wiki}->{var}->{page}); my $template = $p->{template}; my $content = __FUNCPACK{WikiEdit}__->get_content ($o, $page); local $o->{var}->{content} = $content->{content}; local $o->{var}->{content_prop} = $content->{content_prop}; local $o->{var}->{source}->{prop} = sub { my %opt = @_; my $key = $opt{p}->{id}; my $uri = $opt{o}->{wiki}->{config}->{}->{$key}->{uri}; my $rv = {}; if ($uri) { if (my $nv = $opt{o}->{wiki}->{input}->parameter ('PE--CTRL--'.$key)) { $rv->{value} = $nv; $rv->{class} = [qw/pe--from-parameter/]; } else { $rv->{value} = $opt{o}->{var}->{content_prop} ->get_attribute_value ($uri, default => $opt{p}->{default}); } } else { $rv->{value} = $opt{p}->{default}; } $rv; }; __FUNCPACK{WikiFormCore}__->make_form_in_html ($p->{-parent}, $template, wiki => $o->{wiki}, o => $o, index => -1, local_id_prefix => 'PE--CTRL--', output => { mode => 'pe--write', page => $page, submit_button => 1, hidden => sub { my ($hidden, $o) = @_; ## Embed hidden sequencial number to detect confliction for ($hidden->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'input')) { $_->set_attribute (type => 'hidden'); $_->set_attribute (name => 'pe--seq'); $_->set_attribute (value => $o->{var}->{content_prop} ->get_attribute_value (, default => 0)); $_->option (use_EmptyElemTag => 1); } }, }); ViewFragment: @Name: links @Description: @@@: Link to property edit mode of the WikiPage @@lang:en @Formatting: %link-wiki(mode => pe--propedit, up-to-date, rel => edit, class => wiki-cmd, description => {%res(name=>{PropEdit:Link:Description});}p); ViewDefinition: @Mode: pe--write @Condition: @@http-method[list]: POST @Description: @@@: Saving modified (new) WikiPage properties @@lang: en @Use: use Message::Util::Error; @method: @@Name: main @@@: my $wiki = $self->{view}->{wiki}; $wiki->{var}->{db}->{read_only}->{'content'} = 1; $wiki->{var}->{db}->{read_only}->{'content_prop'} = 0; $wiki->{var}->{db}->{read_only}->{'lastmodified'} = 1; $wiki->{var}->{db}->{read_only}->{'referer'} = 0; $wiki->init_db; my $page = $wiki->{var}->{page}; my $old_content = $wiki->{db}->get (content => $page); my $prop = $wiki->{db}->get (content_prop => $page); ## Check confliction my $seq = $wiki->{input}->parameter ('pe--seq') || 0; if ($seq != $prop->get_attribute_value (, default => 0)) { $self->{view}->{wiki}->view_in_mode (mode => '-pe--conflict'); throw SuikaWiki::DB::Util::Error -type => 'ERROR_REPORTED'; } my %pprop; ## NOTE: Uniqueness of stringified WikiName assumed. $pprop{my $page_name = $page->stringify (wiki => $wiki)} = {prop => $prop, page => $page}; my $this_page_name = $page_name; MODIFICATION: { my $old_mt; my $new_mt; my %depend; KEY: for my $key (grep s/^PE--CTRL--//, $wiki->{input}->parameter_names) { my $propinfo = $wiki->{config}->{}->{$key}; next KEY unless $propinfo->{uri}; ## Really modified? my $new_value = [$wiki->{input}->parameter ('PE--CTRL--'.$key)]; if (@$new_value == 1) { if ($propinfo->{is_list}) { $new_value = [split /\x0A|\x0D\x0A?/, $new_value->[0]]; } if ($propinfo->{type} eq ) { next KEY if $new_value->[0] eq '#asis'; } } my $old_value = $prop->get_attribute_value ($propinfo->{uri}); if (ref $old_value and @$new_value == @$old_value) { CHK: { for my $i (0..$#$new_value) { last CHK if $old_value->[$i] ne $new_value->[$i]; } next KEY; } } elsif (not ref $old_value and @$new_value == 1) { next KEY if $old_value eq $new_value->[0]; } if ($propinfo->{uri} eq ) { $old_mt = $old_value; $new_mt = $new_value->[0]; } ## Update to new value if (@$new_value) { if ($propinfo->{is_list}) { $prop->set_attribute ($propinfo->{uri} => $new_value); } elsif (length $new_value->[0]) { $prop->set_attribute ($propinfo->{uri} => $new_value->[0]); } else { $prop->remove_attribute ($propinfo->{uri}); } ## Update other page's properties if ($propinfo->{type} eq and defined $propinfo->{}) { PV: for my $wn (@$new_value) { my $wiki_name = $wiki->name ($wn); unless ($pprop{$wn}->{prop}) { $pprop{$wn}->{prop} = $wiki->{db}->get (content_prop => $wiki_name); $pprop{$wn}->{page} = $wiki_name; } my $pv = $pprop{$wn}->{prop}->get_attribute_value ($propinfo->{}, as_array => 1); for (@$pv) { next PV if $_ eq $this_page_name; } push @$pv, $this_page_name; $pprop{$wn}->{prop}->set_attribute ($propinfo->{} => $pv); $pprop{$wn}->{modified} = 1; } } } else { $prop->remove_attribute ($propinfo->{uri}); } $pprop{$page_name}->{modified} = 1; $depend{$key} = $propinfo->{depend} if $propinfo->{depend}; } DEPEND: for my $sub (keys %depend) { for my $main (@{$depend{$sub}}) { unless ($prop->get_attribute ($wiki->{config}->{} ->{$main}->{uri})) { $prop->remove_attribute ($wiki->{config}->{} ->{$sub}->{uri}); next DEPEND; } } } last MODIFICATION unless $pprop{$page_name}->{modified}; ## Update property for my $wn (keys %pprop) { next unless $pprop{$wn}->{modified}; my $prop = $pprop{$wn}->{prop}; my $seq = $prop->get_attribute_value (, default => 0); $prop->set_attribute ( => $seq + 1); try { $self->{view}->{wiki}->{db}->set (content_prop => $pprop{$wn}->{page} => $prop); } catch SuikaWiki::DB::Util::Error with { my $err = shift; if ($err->{-type} eq 'ERROR_REPORTED') { $err->throw; } else { $self->{view}->{wiki}->view_in_mode (mode => '-wdb--fatal-error'); throw SuikaWiki::DB::Util::Error -type => 'ERROR_REPORTED'; } }; } ## Post-write events if ($new_mt) { my $format = __FUNCPACK{WikiFormat}__ ->handler (\$old_content, serialized_media_type => $old_mt, content_prop => $prop, wiki => $wiki); $format->content_type_changed_from (wiki => $wiki, page => $page, old_content => \$old_content, new_content => \$old_content, new_serialized_media_type => $new_mt, content_prop => $prop); } my $format = __FUNCPACK{WikiFormat}__ ->handler (\$old_content, serialized_media_type => $new_mt, content_prop => $prop, wiki => $wiki); $format->content_prop_modified (wiki => $wiki, page => $page, content_prop => $prop); ## ISSUE: Should for other modified WikiPages also fired? } # MODIFICATION ## Redirect appropriate mode my $new_mode = $self->{view}->{wiki}->{input}->parameter ('we--mode-modified'); $new_mode =~ s/[^0-9A-Za-z._-]+//g; my $uri = $self->{view}->{wiki}->uri_reference (page => $page, mode => $new_mode, up_to_date => 1, param => {we__mode_modified => $new_mode}); require SuikaWiki::Output::HTTP; my $output = SuikaWiki::Output::HTTP->new (wiki => $self->{view}->{wiki}); $output->set_redirect (uri => $uri, status_code => 303); $output->output (output => 'http-cgi'); FormattingRule: @Category[list]: form-input @Name: pe--texts @Description: @@@@: Multiple texts input @@@lang:en @Formatting: __ATTRTEXT:%id__;__ATTRNODE:%label__; my $id = __FUNCPACK{WikiFormCore}__ ->control_id ($o, local_id => $p->{id}, require_local_id => 1); my $has_label = 0; if ($p->{label}->count) { $has_label = 1; for ($p->{-parent}->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'label')) { $_->set_attribute (for => $id->{global_id}); $_->append_node ($p->{label}); } $p->{-parent}->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'br') ->option (use_EmptyElemTag => 1); } for ($p->{-parent}->append_new_node (type => '#element', namespace_uri => $NS_XHTML1, local_name => 'textarea')) { $_->set_attribute (name => $id->{local_id}); $_->set_attribute (id => $id->{global_id}) if $has_label; __ATTRTEXT:%size__;__ATTRTEXT:%lines__;__ATTRTEXT:%description__; $_->set_attribute (cols => ($p->{size}||20)*2); ## Length $_->set_attribute (title => $p->{description}) if $p->{description}; $_->set_attribute (disabled => 'disabled') if $o->{form}->{disabled}; __ATTRTEXT:%class__; my @class = split /\s+/, $p->{class}; push @class, 'require' if $o->{form}->{require}->{id}->{$p->{id}}; __ATTRTEXT:%source__; my $items = 5; if ($p->{source}) { if (ref $o->{var}->{source}->{$p->{source}}) { my $d = $o->{var}->{source}->{$p->{source}} ->(p=>$p, o=>$o, type => ); $_->append_text (ref $d->{value} eq 'ARRAY' ? join "\n", @{$d->{value}} : $d->{value}); push @class, @{$d->{class}||[]}; $items = @{$d->{value}} + 1 if ref $d->{value} eq 'ARRAY'; } else { $_->append_text (ref $o->{var}->{$p->{source}} eq 'ARRAY' ? join "\n", @{$o->{var}->{$p->{source}}} : $o->{var}->{$p->{source}}); $items = @{$o->{var}->{$p->{source}}} + 1 if ref $o->{var}->{$p->{source}} eq 'ARRAY'; } } else { __ATTRTEXT:%default__; $_->append_text ($p->{default}); ## Default value } $_->set_attribute (rows => ($p->{lines} || $items)); ## Lines $_->set_attribute (class => join ' ', @class) if @class; } Resource: @Edit:SaveAnd:pe--propedit:Description: @@lang: en @@@: Save modified property values and show this property-editing mode again. @Edit:SaveAnd:pe--propedit:Label: @@lang: en @@@: Editing Properties @PropEdit:Conflict:Description: @@lang: en @@@: Properties for WikiPage %link-to-wikipage (label => {%link-to-it ( label => {%page-name;}p);}); has been modified during you are editing them. Please ensure that third-party's modification does not affect your submitting changes. @PropEdit:Conflict:Title: @@lang: en @@@: Confliction - Editing Content Properties @PropEdit:Conflict:WebPageTitle: @@lang: en @@@: CONFLICTION - %page-name; (Editing Content Properties) @PropEdit:Link:Description: @@lang: en @@@: Edit properties of this WikiPage @PropEdit:Template: ## Should be defined in resource WikiPage @PropEdit:Title: @@lang: en @@@: Editing Content Properties @PropEdit:WebPageTitle: @@lang: en @@@: %page-name; (Editing Content Properties)