/[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.5 - (hide annotations) (download)
Mon Dec 29 13:03:19 2003 UTC (21 years, 3 months ago) by wakaba
Branch: MAIN
Changes since 1.4: +78 -103 lines
Use WikiForeCore module

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24