/[pub]/suikawiki/script/lib/SuikaWiki/Plugin/WikiEdit.wp2
Suika

Contents of /suikawiki/script/lib/SuikaWiki/Plugin/WikiEdit.wp2

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (hide annotations) (download)
Thu Oct 30 07:45:10 2003 UTC (21 years, 5 months ago) by wakaba
Branch: MAIN
Changes since 1.1: +255 -166 lines
Remove some obsolete rules

1 wakaba 1.1 #?SuikaWikiConfig/2.0
2    
3     Plugin:
4     @Name: WikiEdit
5     @Description:
6     @@@: WikiPage editing components
7     @@lang:en
8     @License: %%GPL%%
9     @Author:
10     @@Name:
11     @@@@: Wakaba
12     @@@lang:ja
13     @@@script:Latn
14     @@Mail[list]: w@suika.fam.cx
15 wakaba 1.2 @Date.RCS: $Date: 2003/10/25 06:37:31 $
16 wakaba 1.1 @RequiredModule[list]:
17 wakaba 1.2 SuikaWiki::Name::Space
18 wakaba 1.1 Digest::SHA1
19 wakaba 1.2 @RequiredPlugin[list]:
20     WikiView
21     WikiStruct
22     WikiLinking
23     WikiFormCore
24     HTML
25 wakaba 1.1
26     PluginConst:
27     @NS_XHTML1:
28     http://www.w3.org/1999/xhtml
29    
30     ViewDefinition:
31     @Mode: edit
32     @Condition:
33     @@http-method[list]:
34     GET
35     HEAD
36     @Description:
37     @@@: Edit WikiPage content as whole, as a plaintext
38     @@lang: en
39     @template:
40     @@http-status-code: 200
41     @@media-type: text/html
42     @@use-media-type-charset: 1
43     @@expires: %%edit%%
44     @@body:
45     %html-document (
46     title => {%res(name=>{Edit:WebPageTitle});}p,
47 wakaba 1.2 link-meta => {%template (name => links);
48     %html-meta(name => ROBOTS, content => NOINDEX);}p,
49 wakaba 1.1 content => {
50     %template (
51     name => ws--page,
52 wakaba 1.2 -content => {%template (name => we--edit-body);},
53 wakaba 1.1 );
54     }p,
55     );
56    
57     ViewDefinition:
58     @Mode: write
59     @Condition:
60     @@http-method[list]:
61     POST
62     @Description:
63     @@@: Saving modified (new) WikiPage content
64     @@lang: en
65     @method:
66     @@@:
67     my $touch = $self->{view}->{wiki}->{input}->parameter ('we--touch');
68    
69     $self->{view}->{wiki}->{var}->{db}->{read_only}->{'content'} = 0;
70     $self->{view}->{wiki}->{var}->{db}->{read_only}->{'lastmodified'} = 0
71     if $touch;
72     $self->{view}->init_db;
73    
74     my $page = $self->{view}->{wiki}->{var}->{page};
75    
76     ## TODO: Implements access control
77     #if (&frozen_reject()) {
78     #}
79    
80 wakaba 1.2 if (not __FUNCPACK__::page_is_editable ($page)) {
81 wakaba 1.1 ## TODO: Implements this
82     # &_do_view_msg (-view => '-error', -page => $main::form{mypage},
83     # error_message => &Resource ('Error:ThisPageIsUneditable'));
84     # return;
85     die "Uneditable!";
86     }
87    
88     ## Check confliction
89     my $current_content = $self->{view}->{wiki}->{db}->get (content => $page);
90     if (length $current_content) {
91 wakaba 1.2 my $current_digest = __FUNCPACK__::digest ($current_content,
92     normalize => 1);
93 wakaba 1.1 my $prev_digest
94     = $self->{view}->{wiki}->{input}->parameter ('we--digest');
95     if ($current_digest ne $prev_digest) {
96     ## TODO: Implements this
97     # _do_view_msg (-view => '-conflict', -page => $page_name);
98 wakaba 1.2 # die "@{[join '//', @$page]}: Conflict : (current) $current_digest [$current_content] vs (prev) $prev_digest";
99     return $self->{view}->{wiki}->view_in_mode
100     (mode => '-conflict');
101 wakaba 1.1 }
102     }
103    
104     my $new_content
105     = $self->{view}->{wiki}->{input}->parameter ('we--content');
106     if (length $new_content) {
107     $self->{view}->{wiki}->{db}->set (content => $page => $new_content);
108     if ($touch) {
109     $self->{view}->{wiki}->{db}->set (lastmodified => $page => time);
110     }
111    
112     ## TODO: Use SuikaWiki 3 interface
113     my $new_mode = $self->{view}->{wiki}->{input}->parameter
114     ('we--mode-modified');
115     $new_mode =~ s/[^0-9A-Za-z._-]+//g;
116     my $uri = SuikaWiki::Plugin->_uri_wiki_page (join ('//', @$page),
117     mode => $new_mode,
118     with_lm => 1,
119     absolute => 1);
120     $uri .= qq<;we--mode-modified=$new_mode>;
121    
122     require SuikaWiki::Output::HTTP;
123     my $output = SuikaWiki::Output::HTTP->new
124     (wiki => $self->{view}->{wiki});
125     $output->set_redirect (uri => $uri, status_code => 303);
126     $output->output (output => 'http-cgi');
127     } else {
128 wakaba 1.2 for (qw/content lastmodified/) {
129     $self->{view}->{wiki}->{db}->delete (content => $page);
130     }
131     $self->{view}->{wiki}->view_in_mode (mode => '-deleted');
132 wakaba 1.1 }
133     @@Name: main
134    
135     ViewDefinition:
136     @Mode: adminedit
137     @Condition:
138     @@http-method[list]:
139     GET
140     HEAD
141     @Description:
142     @@@: Edit WikiPage content as whole, as a plaintext (administrator mode)
143     @@lang: en
144     @template:
145     @@http-status-code: 200
146     @@media-type: application/xhtml+xml
147     @@use-media-type-charset: 1
148     @@expires: %%edit%%
149     @@body:
150 wakaba 1.2 %html-document (
151     title => {%res(name=>{Edit:Admin:WebPageTitle});}p,
152     link-meta => {%predefined-template(name=>links);
153     %html-meta(name=>ROBOTS,content=>NOINDEX);}p,
154     content => {
155     %template (
156     name => ws--page,
157     -content => {%template (name => we--adminedit-body);},
158     );
159     }p,
160     );
161 wakaba 1.1
162 wakaba 1.2 ViewDefinition:
163 wakaba 1.1 @Mode: -conflict
164     @Condition:
165     @@http-method[list]:
166     GET
167     HEAD
168     @Description:
169     @@@: Confliction message
170     @@lang: en
171     @template:
172     @@http-status-code: 409
173     @@media-type: text/html
174     @@use-media-type-charset: 1
175     @@body:
176 wakaba 1.2 %html-document (
177     title => {%res(name=>{Edit:Conflict:WebPageTitle});}p,
178     link-meta => {%template(name=>links);
179     %html-meta(name=>ROBOTS,content=>NOINDEX);}p,
180     content => {
181     %template (
182     name => ws--page,
183     -content => {
184     %section (level=>2,
185     title => {%res(name=>{Edit:Conflict:Title});}p, heading,
186     content => {%template (name => we--conflict-body);}p,
187     );
188     },
189     );
190     }p,
191     );
192    
193     ViewDefinition:
194     @Mode: -deleted
195     @Condition:
196     @@http-method[list]:
197     GET
198     HEAD
199     @Expires:%%view%%
200     @Description:
201     @@@: Confliction message
202     @@lang: en
203     @template:
204     @@http-status-code: 200
205     @@media-type: text/html
206     @@use-media-type-charset: 1
207     @@body:
208     %html-document (
209     title => {%res (name => {Edit:Deleted:WebPageTitle});}p,
210     link-meta => {%template (name => links);
211     %html-meta (name => ROBOTS, content => NOINDEX);}p,
212     content => {
213     %template (
214     name => ws--page,
215     -content => {
216     %section (level=>2,
217     title => {%res(name=>{Edit:Deleted:Title});}p, heading,
218     content => {
219     %paragraph (content => {%res
220     (name => {Edit:Deleted:Description});}p);
221     }p,
222     );
223     },
224     );
225     }p,
226     );
227 wakaba 1.1
228     ViewFragment:
229     @Name: links
230     @Description:
231     @@@: Link to edit mode of the WikiPage
232     @@lang:en
233     @Formatting:
234     %link-wiki(mode=>edit,rel=>edit,class=>wiki-cmd,
235     title=>{%res(name=>{Link:Edit:Description});}p,up-to-date);
236     %link-wiki(mode=>adminedit,rel=>edit,class=>wiki-cmd,
237     title=>{%res(name=>{Link:AdminEdit:Description});}p,up-to-date);
238    
239     ViewFragment:
240     @Name: navbar
241     @Description:
242     @@@: Link to edit mode of the WikiPage
243     @Order: 10
244     @Formatting:
245 wakaba 1.2 %anchor-wiki (mode=>edit,rel=>edit,class=>wiki-cmd,
246     label=>{%res(name=>EditThisPage);}p,
247     title=>{%res(name=>EditThisPageLong);}p,
248     accesskey=>E,add-param=>{#edit});
249    
250     ViewFragment:
251     @Template[list]:
252     we--conflict-body
253     @Order: 30
254     @Description:
255     @@@: Conflict report
256     @@lang:en
257     @Formatting:
258     %paragraph (content=>{%res(name=>{Edit:Conflict:Description});}p);
259     %we--conflict-modified-content;
260     %section (level=>3,
261     id => edit-conflict-diff,
262     title => {%res(name=>{Edit:Conflict:Diff:Title});}p, heading,
263     content => {
264     %paragraph (
265     content => {%res(name=>{Edit:Conflict:Diff:Description});}p);
266     %conflict-diff;
267     }p,
268     );
269    
270     ViewFragment:
271     @Template[list]: we--edit-body
272     @Order:80
273     @Description:
274     @@@: Editing WikiPage form section
275     @@lang:en
276     @Formatting:
277     %section (level=>2,
278     id => edit,
279     title => {%res (name => {Edit:Title});}p, heading,
280     content => {%edit-form;}p,
281     );
282    
283     ViewFragment:
284     @Template[list]: we--adminedit-body
285     @Order:80
286     @Description:
287     @@@: Editing WikiPage form section (Admin edit mode)
288     @@lang:en
289     @Formatting:
290     %section (level=>2,
291     id => edit,
292     title => {%res(name=>{Edit:Title});}p, heading,
293     content => {%edit-form(admin);}p,
294     );
295    
296     ViewFragment:
297     @Template[list]: we--conflict-body
298     @Order: 80
299     @Description:
300     @@@: Editing-WikiPage-form section (conflict mode)
301     @@lang:en
302     @Formatting:
303     %section (level=>2,
304     id => edit,
305     title => {%res(name=>{Edit:Title});}p, heading,
306     content => {
307     %paragraph(name=>{%res(name=>{Edit:Conflict:Edit:Description});}p);
308     %edit-form;
309     }p,
310     );
311 wakaba 1.1
312     ViewFragment:
313     @Name: we--edit
314     @Description:
315     @@@: Edit form --- main textarea
316     @@lang:en
317     @Order: 0
318     @Formatting:
319     %textarea(id=>we--content,size=>{%res(name=>{Edit:Form:Size});}p,
320     lines=>{%res(name=>{Edit:Form:Lines});}p);
321    
322     ViewFragment:
323     @Name: we--edit
324     @Description:
325     @@@: Submit button
326     @@lang:en
327     @Order: 200
328     @Formatting:
329     %submit(label=>{%res(name=>{Edit:Save});}p);
330    
331     FormattingRule:
332     @Category[list]: view
333     @Name: edit-form
334     @Description:
335     @@@: Provides WikiPage editing form
336     @@lang: en
337     @Parameter:
338     @@Name: admin
339     @@Type: boolean
340     @@Default: {0}
341     @@Description:
342     @@@@: Whether administrator's editing mode or not
343     @@@lang:en
344     @Formatting:
345     if (not __FUNCPACK__::page_is_editable ($o->{wiki}->{var}->{page})) {
346     $r = '<p>'.$o->resource('Error:ThisPageIsUneditable',escape=>1).'</p>';
347 wakaba 1.2 # } elsif (!$p->{admin} && &main::is_frozen ($o->{page})) {
348     # $r = '<p>'.$o->resource('Error:ThisPageIsUneditable',escape=>1).'</p>';
349 wakaba 1.1 } else {
350     #$r = '<p>'.$o->resource('Error:PasswordIsNotSpecified',escape=>1).'</p>' if $p->{admin};
351    
352     $r = Message::Markup::XML->new (type => '#element',
353     namespace_uri => $NS_XHTML1,
354     local_name => 'form');
355     $r->set_attribute (method => 'post');
356     ## TODO: Use SuikaWiki 3 interface
357     $r->set_attribute (action => $o->uri ('wiki'));
358 wakaba 1.2 $r->set_attribute ('accept-charset' => 'iso-2022-jp utf-8');
359 wakaba 1.1 for ($r->append_new_node (type => '#element',
360     namespace_uri => $NS_XHTML1,
361     local_name => 'input')) {
362     $_->set_attribute (type => 'hidden');
363     $_->set_attribute (name => 'mypage');
364     ## TODO: Use SuikaWiki 3 interface
365     $_->set_attribute (value => join '//', @{$o->{wiki}->{var}->{page}});
366     $_->option (use_EmptyElemTag => 1);
367     }
368     for ($r->append_new_node (type => '#element',
369     namespace_uri => $NS_XHTML1,
370     local_name => 'input')) {
371     $_->set_attribute (type => 'hidden');
372     $_->set_attribute (name => 'mode');
373     $_->set_attribute (value => 'write');
374     $_->option (use_EmptyElemTag => 1);
375     }
376 wakaba 1.2 ## _charset_ hack
377     for ($r->append_new_node (type => '#element',
378     namespace_uri => $NS_XHTML1,
379     local_name => 'input')) {
380     $_->set_attribute (type => 'hidden');
381     $_->set_attribute (name => '_charset_');
382     $_->option (use_EmptyElemTag => 1);
383     }
384 wakaba 1.1
385     my $ovar_orig = $o->{var};
386     $o->{var} = {
387     #content
388     is_admin_mode => $p->{admin},
389     is_conflict_mode => 0,
390     #is_new_page_template
391     };
392     $o->{var}->{content} = __FUNCPACK__::get_content
393     ($o, $o->{wiki}->{var}->{page});
394     for ($r->append_new_node (type => '#element',
395     namespace_uri => $NS_XHTML1,
396     local_name => 'input')) {
397     $_->set_attribute (type => 'hidden');
398     $_->set_attribute (name => 'we--digest');
399 wakaba 1.2 $_->set_attribute (value => ($o->{var}->{is_new_page_template}?'':
400     __FUNCPACK__::digest ($o->{var}->{content},
401     normalize => 1)));
402 wakaba 1.1 $_->option (use_EmptyElemTag => 1);
403     }
404    
405     my $formatter = $o->formatter ('we__edit');
406     $r->append_node ($formatter->replace
407     ($o->{wiki}->{view}->assemble_template
408     ('we__edit'),
409     $o, {formatter => $formatter}),
410     node_or_text => 1);
411     $o->{var} = $ovar_orig;
412     }
413    
414     FormattingRule:
415     @Category[list]: view
416 wakaba 1.2 @Name: we--conflict-modified-content
417 wakaba 1.1 @Description:
418     @@@:
419 wakaba 1.2 Modified content that is conflicted with current content
420 wakaba 1.1 @@lang:en
421     @Formatting:
422 wakaba 1.2 $r = Message::Markup::XML->new (type => '#element',
423     namespace_uri => $NS_XHTML1,
424     local_name => 'pre');
425     $r->append_text (scalar $o->{wiki}->{input}->parameter ('we--content'));
426 wakaba 1.1
427     FormattingRule:
428     @Category[list]:view
429     @Name: conflict-diff
430     @Description:
431     @@@:
432     Provides marked diff between latest WikiPage content and
433     submitted one
434     @@lang:en
435     @Formatting:
436     require Algorithm::Diff;
437 wakaba 1.2 $r = Message::Markup::XML->new (type => '#element',
438     namespace_uri => $NS_XHTML1,
439     local_name => 'pre');
440     $r->set_attribute (class => 'diff');
441     for (Algorithm::Diff::diff (
442     [split /\x0D?\x0A/,
443     scalar $o->{wiki}->{input}->parameter ('we--content')],
444     [split /\x0D?\x0A/,
445     $o->{wiki}->{db}->get (content
446     => $o->{wiki}->{var}->{page})]
447     )) {
448 wakaba 1.1 for (@{$_}) {
449     my ($sign, $lineno, $text) = @{$_};
450     my $ename = $sign eq '+' ? 'ins' : $sign eq '-' ? 'del' : 'span';
451 wakaba 1.2 my $line = $r->append_new_node (type => '#element',
452     namespace_uri => $NS_XHTML1,
453     local_name => ({qw/+ ins - del/}->{$sign}||'span'));
454    
455     $line->set_attribute (class => 'line');
456     for ($line->append_new_node (type => '#element',
457     namespace_uri => $NS_XHTML1,
458     local_name => 'span')) {
459     $_->set_attribute (class => 'lineno');
460     $_->append_text ($lineno);
461     }
462     $line->append_text (' ');
463     for ($line->append_new_node (type => '#element',
464     namespace_uri => $NS_XHTML1,
465     local_name => 'span')) {
466     $_->set_attribute (class => 'sign');
467     $_->append_text ($sign);
468     }
469     $line->append_text (' ');
470     for ($line->append_new_node (type => '#element',
471     namespace_uri => $NS_XHTML1,
472     local_name => 'span')) {
473     $_->set_attribute (class => 'content');
474     $_->append_text ($text);
475     }
476     $line->append_text ("\n");
477     } # diff lines
478 wakaba 1.1 }
479    
480     FormattingRule:
481     @Name:mode-after-edit-selection
482     @Category[list]:we--edit
483     @Parameter:
484     @@Name: name
485     @@Type: html4:name
486     @@Default:"we--mode-modified"
487     @@Description:
488     @@@@:Form control name for the selection
489     @@@lang:en
490     @Formatting:
491     my $magic = '';
492     $magic = $1 if $o->{var}->{content} =~ m/^([^\x0A\x0D]+)/s;
493    
494     my $name = $p->{name} || 'we--mode-modified';
495     my $selected_mode = $o->{wiki}->{input}->parameter ($name);
496     unless ($selected_mode) {
497     if ($magic =~ /C(?:on(?:fig|st)|SS)/) {
498     $selected_mode = 'edit';
499     } else {
500     $selected_mode = 'default';
501     }
502     }
503    
504     my $SELECT = Message::Markup::XML->new (type => '#element',
505     namespace_uri => $NS_XHTML1,
506     local_name => 'select');
507     $SELECT->set_attribute (name => $name);
508     for (qw/default read edit/) {
509     for my $OPTION ($SELECT->append_new_node (type => '#element',
510     namespace_uri => $NS_XHTML1,
511     local_name => 'option')) {
512     $OPTION->set_attribute (value => $_);
513     my $label = $o->resource ('Edit:SaveAnd:'.$_.':Label');
514     $OPTION->set_attribute (label => $label);
515     $OPTION->append_text ($label);
516     $OPTION->set_attribute
517     (title => $o->resource ('Edit:SaveAnd:'.$_.':Description'));
518     $OPTION->set_attribute (selected => 'selected')
519     if $selected_mode eq $_;
520     }
521     }
522     $SELECT;
523    
524     Resource:
525 wakaba 1.2 @Edit:Conflict:Title:
526     @@@:Confliction detected!
527     @@lang:en
528     @Edit:Conflict:WebPageTitle:
529     @@@:%page-name; (Edit : 409 CONFLICTION)
530     @@lang:en
531     @Edit:Deleted:Description:
532     @@@:Content of WikiPage %page-name; has been removed.
533     @@lang:en
534     @Edit:Deleted:Title:
535     @@@:WikiPage Deleted
536     @@lang:en
537     @Edit:Deleted:WebPageTitle:
538     @@@:%page-name; (Deleted)
539     @@lang:en
540 wakaba 1.1 @Edit:Form:Lines:15
541     @Edit:Form:Size:18
542     @Edit:Save:
543     @@@:Save
544     @@lang:en
545     @Edit:SaveAnd:default:Description:
546     @@@: Save modified content and show content with your default view mode
547     @@lang:en
548     @Edit:SaveAnd:default:Label:
549     @@@: Default view
550     @@lang:en
551     @Edit:SaveAnd:edit:Description:
552     @@@: Save modified content and show content in the edit mode again
553     @@lang:en
554     @Edit:SaveAnd:edit:Label:
555     @@@: Edit again
556     @@lang:en
557     @Edit:SaveAnd:read:Description:
558     @@@: Save modified content and show content in the read mode
559     @@lang:en
560     @Edit:SaveAnd:read:Label:
561     @@@: Show content
562     @@lang:en
563     @EditThisPage:
564     @@@: Edit
565     @@lang:en
566     @EditThisPageLong:
567     @@@: Edit this WikiPage
568     @@lang:en
569     @Edit:WebPageTitle:
570     @@@: %page-name; (Modification)
571     @@lang:en
572     @Edit:Title:
573     @@@: Modification of the WikiPage
574     @@lang:en
575     @Link:AdminEdit:Description:
576     @@@: Edit this WikiPage (administrator's mode)
577     @@lang:en
578     @Link:Edit:Description:
579     @@@: Edit this WikiPage
580     @@lang:en
581    
582     Function:
583 wakaba 1.2 @Name:digest
584     @Description:
585     @@@: Compute digest of given string
586     @@lang:en
587     @Main:
588     my ($s, %opt) = @_;
589     require Digest::SHA1;
590     if ($opt{normalize}) {
591     $s =~ s/\x0D\x0A/\x0A/g;
592     $s =~ tr/\x0D/\x0A/;
593     }
594     Digest::SHA1::sha1_base64 ($s);
595    
596     Function:
597 wakaba 1.1 @Name:get_content
598     @Description:
599     @@@:Get WikiPage content to be modified. For new (currently not exist)
600     WikiPage, new page template content is returned.
601     @@lang:en
602     @Main:
603     my ($o, $page) = @_;
604     my $content;
605     $content = $o->{wiki}->{db}->get (content => $page);
606    
607     unless (length $content) {
608     ## TODO: use namespaced template page
609     $content = $o->{wiki}->{db}->get
610     (content => $o->{wiki}->{config}->{page}->{NewPageTemplate});
611     $o->{var}->{is_new_page_template} = 1;
612     }
613     $content;
614    
615     Function:
616     @Name:page_is_editable
617     @Description:
618     @@@:
619     Returns whether the WikiPage is editable or not.
620     Note that this function is temporary.
621     @@lang:en
622     @Main:
623     my ($page) = @_;
624     $page = join '//', $page;
625     return 0 unless SuikaWiki::Name::Space::validate_name ($page);
626     return 0 if $page =~ /[\x00-\x20\[\]\x7F]/;
627     1;
628    
629     Parameter:
630 wakaba 1.2 @Name: we--content
631     @Type: text
632     @Default: ""
633     @Description:
634     @@@:
635     Content of WikiPage (to be)
636     @@lang:en
637    
638     Parameter:
639 wakaba 1.1 @Name: we--digest
640     @Type: "Base64ed SHA1"
641     @Default: {undef}
642     @Description:
643     @@@:
644     SHA1 digest value of the WikiPage content before the modification.
645     This value is used to detect confliction of modifying.
646     Empty value (undef or length-zero-string) means that
647     there were no WikiPage content.
648 wakaba 1.2 @@lang:en
649    
650     Parameter:
651     @Name: we--mode-modified
652     @Type: mode-name
653     @Default: "default"
654     @Description:
655     @@@:
656     WikiEngine running mode to be specified after modification is completed
657 wakaba 1.1 @@lang:en
658    
659     Parameter:
660     @Name: we--touch
661     @Type: form:checkbox-value
662     @Default: "off"
663     @Description:
664     @@@:
665     Whether last-modified date-time of the WikiPage should be updated or not
666     when the WikiPage is modified.
667     @@lang:en

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24