forked from github/kensanata.oddmuse
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
764c0ffcf1 | ||
|
|
5962745937 | ||
|
|
d380062ec6 | ||
|
|
cd8066233c | ||
|
|
6f04d2044f | ||
|
|
f41ded592b | ||
|
|
8a2c9eca9c | ||
|
|
d712a17f82 | ||
|
|
504190b752 | ||
|
|
56e515a791 | ||
|
|
36feb62052 | ||
|
|
239f15cdbc | ||
|
|
f39cfd3235 | ||
|
|
329699a6aa | ||
|
|
28965bdaa6 | ||
|
|
ed42d2dad5 | ||
|
|
45b21cbdb8 | ||
|
|
b540093c2c | ||
|
|
d164d47e24 | ||
|
|
a56b92ecb3 | ||
|
|
114d914754 | ||
|
|
875051ea84 | ||
|
|
003357acad | ||
|
|
e1c77c4ba6 | ||
|
|
88475c3e41 | ||
|
|
e80f05301d | ||
|
|
a624e78975 | ||
|
|
8cd869f0f9 | ||
|
|
b09b3f8f8e | ||
|
|
b9043ffd98 | ||
|
|
54d3dc400a | ||
|
|
3962068385 | ||
|
|
a0b74ac3c6 | ||
|
|
870d75ac64 | ||
|
|
42d8260ce4 | ||
|
|
bfda4abe54 |
@@ -1031,6 +1031,6 @@ PAGENAME is the pagename of the page you want to browse."
|
||||
(interactive)
|
||||
(kill-new (oddmuse-url oddmuse-wiki oddmuse-page-name)))
|
||||
|
||||
(provide 'oddmuse)
|
||||
(provide 'oddmuse-curl)
|
||||
|
||||
;;; oddmuse-curl.el ends here
|
||||
|
||||
108
contrib/oddmuse_stats
Executable file
108
contrib/oddmuse_stats
Executable file
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/perl -w
|
||||
# -*- perl -*-
|
||||
|
||||
=head1 NAME
|
||||
|
||||
oddmuse-stats - Plugin to monitor Oddmuse edits
|
||||
|
||||
=head1 CONFIGURATION
|
||||
|
||||
Set env.parent_dirs in the config file. The directories in this list
|
||||
are searched for data directories containing rc.log files. No
|
||||
whitespace in the directory names, sorry.
|
||||
|
||||
Example:
|
||||
|
||||
[oddmuse_stats]
|
||||
user www-data
|
||||
env.parent_dirs /home/alex /home/alex/campaignwiki
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Original Author: Alex Schroeder
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
GPLv3
|
||||
|
||||
=head1 MAGIC MARKERS
|
||||
|
||||
#%# family=auto
|
||||
#%# capabilities=autoconf
|
||||
|
||||
=cut
|
||||
|
||||
use Munin::Plugin;
|
||||
use File::Basename;
|
||||
|
||||
# The wiki directories may not contain any spaces.
|
||||
# Use the config file to set the environment variable!
|
||||
my @parent_dirs = ();
|
||||
my %logfiles = ();
|
||||
my %names = ();
|
||||
my $debug = $ENV{MUNIN_DEBUG};
|
||||
|
||||
if ($ENV{'parent_dirs'}) {
|
||||
@parent_dirs = split(/ /, $ENV{'parent_dirs'});
|
||||
} else {
|
||||
die "The parent_dirs environment variable must be set.\n";
|
||||
}
|
||||
|
||||
for my $parent_dir (@parent_dirs) {
|
||||
warn "opening $parent_dir\n" if $debug;
|
||||
if (opendir(my $dh, $parent_dir)) {
|
||||
while(readdir $dh) {
|
||||
next if $_ eq '.' or $_ eq '..';
|
||||
if (-r "$parent_dir/$_/rc.log") {
|
||||
my $basename = basename($_);
|
||||
$names{clean_fieldname($basename)}
|
||||
= $basename;
|
||||
$logfiles{clean_fieldname($basename)}
|
||||
= "$parent_dir/$_/rc.log";
|
||||
} else {
|
||||
warn "discarding $_\n" if $debug;
|
||||
}
|
||||
}
|
||||
closedir $dh;
|
||||
}
|
||||
}
|
||||
|
||||
my $yesterday = time() - 86400;
|
||||
|
||||
if ($ARGV[0]) {
|
||||
if ($ARGV[0] eq 'autoconf') {
|
||||
if (keys %logfiles) {
|
||||
print "yes\n";
|
||||
exit 0;
|
||||
} else {
|
||||
print "no (no logfiles found in " . join(", ", @parent_dirs) . ")\n";
|
||||
exit 0;
|
||||
}
|
||||
} elsif ($ARGV[0] eq 'config') {
|
||||
print "graph_title Oddmuse Wikis\n";
|
||||
print "graph_category wikis\n";
|
||||
print "graph_info This graph shows how many edits the wiki had in the last 24h.\n";
|
||||
print "graph_vlabel edits/day\n";
|
||||
print "graph_order";
|
||||
for my $wiki (sort keys %logfiles) {
|
||||
print " $wiki";
|
||||
};
|
||||
print "\n";
|
||||
for my $wiki (sort keys %logfiles) {
|
||||
my $name = $names{$wiki};
|
||||
print "$wiki.label $name\n";
|
||||
}
|
||||
exit 0;
|
||||
}
|
||||
}
|
||||
|
||||
for my $wiki (sort keys %logfiles) {
|
||||
open (my $fh, '<', $logfiles{$wiki})
|
||||
or die "cannot open " . $logfiles{$wiki} . ": $!";
|
||||
my $value = 0;
|
||||
while (<$fh>) {
|
||||
my ($ts) = split(/\x1e/);
|
||||
$value++ if $ts and $ts >= $yesterday;
|
||||
}
|
||||
print "$wiki.value $value\n";
|
||||
}
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
(add-to-list 'vc-handled-backends 'oddmuse)
|
||||
|
||||
(require 'oddmuse)
|
||||
(require 'oddmuse-curl)
|
||||
(require 'diff)
|
||||
|
||||
(defun vc-oddmuse-revision-granularity () 'file)
|
||||
|
||||
@@ -100,6 +100,25 @@ h1 a:visited, h2 a:visited, h3 a:visited {
|
||||
|
||||
/* links */
|
||||
|
||||
a.pencil {
|
||||
padding-left: 1ex;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
visible: hidden;
|
||||
transition: visibility 0s 1s, opacity 1s linear;
|
||||
opacity: 0;
|
||||
}
|
||||
*:hover > a.pencil {
|
||||
visible: visible;
|
||||
transition: opacity .5s linear;
|
||||
opacity: 1;
|
||||
}
|
||||
@media print {
|
||||
a.pencil {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
a.number {
|
||||
text-decoration: none;
|
||||
}
|
||||
@@ -140,6 +159,15 @@ pre, code, tt {
|
||||
line-height: 110%;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow:hidden;
|
||||
white-space: pre-wrap; /* CSS 3 */
|
||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
}
|
||||
|
||||
/* styling for divs that will be invisible when printing
|
||||
when printing. */
|
||||
|
||||
@@ -366,6 +394,10 @@ div.image span.caption {
|
||||
margin: 0 1em;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.left { float:left; margin-right: 1em; }
|
||||
.right { float:right; margin-left: 1em; }
|
||||
.half a img { height: 50%; width: 50%; }
|
||||
|
||||
592
css/alex-2014.css
Normal file
592
css/alex-2014.css
Normal file
@@ -0,0 +1,592 @@
|
||||
@font-face {
|
||||
font-family: "EB Garamond";
|
||||
font-style: normal;
|
||||
src: local('EB Garamond 12'), url('EBGaramond12-Regular.ttf') format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "EB Garamond";
|
||||
font-style: italic;
|
||||
src: local('EB Garamond 12'), url('EBGaramond12-Italic.ttf') format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'EB Garamond All SC';
|
||||
src: local('EB Garamond 12 All SC'), url('EBGaramond12-AllSC.ttf') format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family:"Symbola";
|
||||
src: local('Symbola'), url("Symbola.woff") format("woff"), url("Symbola.ttf") format("truetype");
|
||||
font-weight:normal;
|
||||
font-style:normal;
|
||||
}
|
||||
|
||||
body, rss {
|
||||
font-family: "EB Garamond", Symbola, serif;
|
||||
font-style: normal;
|
||||
font-size: 18pt;
|
||||
line-height: 22pt;
|
||||
margin:1em 3em;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
/* headings: we can use larger sizes if we use a lighter color.
|
||||
we cannot inherit the font-family because header and footer use a narrow font. */
|
||||
|
||||
h1, h2, h3, title {
|
||||
font-family: "EB Garamond", Symbola, serif;
|
||||
font-weight: normal;
|
||||
line-height: 100%;
|
||||
}
|
||||
h1, channel title {
|
||||
font-size: 32pt;
|
||||
margin: 1em 0 0.5em 0;
|
||||
padding: 0.4em 0;
|
||||
}
|
||||
h2 {
|
||||
font-size: 18pt;
|
||||
margin: 2em 0 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
h3 {
|
||||
font-size: inherit;
|
||||
font-weight: bold;
|
||||
padding: 0;
|
||||
margin: 1em 0 0 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* headers in the journal are smaller */
|
||||
|
||||
div.journal h1, item title {
|
||||
font-size: inherit;
|
||||
padding: 0;
|
||||
clear: both;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
div.journal h2 {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
div.journal h3 {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
font-style: italic;
|
||||
}
|
||||
div.journal hr {
|
||||
display:none;
|
||||
}
|
||||
p.more {
|
||||
margin-top: 3em;
|
||||
}
|
||||
/* Links in headings appear on journal pages. */
|
||||
|
||||
h1 a, h2 a, h3 a {
|
||||
color:inherit;
|
||||
text-decoration:none;
|
||||
font-weight: normal;
|
||||
}
|
||||
h1 a:visited, h2 a:visited, h3 a:visited {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* for download buttons and the like */
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
font-size: 120%;
|
||||
cursor: pointer;
|
||||
padding: 0.4em 0.6em;
|
||||
text-shadow: 0px -1px 0px #ccc;
|
||||
background-color: #cfa;
|
||||
border: 1px solid #9d8;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0px 1px 3px white inset, 0px 1px 3px black;
|
||||
}
|
||||
|
||||
.button .icon {
|
||||
color: #363;
|
||||
text-shadow: 0px -1px 1px white, 0px 1px 3px #666;
|
||||
}
|
||||
|
||||
.button a {
|
||||
text-decoration: none;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* links */
|
||||
|
||||
a.pencil {
|
||||
padding-left: 1ex;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
visibility: hidden;
|
||||
transition: visibility 0s 1s, opacity 1s linear;
|
||||
opacity: 0;
|
||||
}
|
||||
*:hover > a.pencil {
|
||||
visibility: visible;
|
||||
transition: opacity .5s linear;
|
||||
opacity: 1;
|
||||
}
|
||||
@media print {
|
||||
a.pencil {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
a.number {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* stop floating content from flowing over the footer */
|
||||
|
||||
hr {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* the distance between links in the navigation bars */
|
||||
|
||||
span.bar a {
|
||||
margin-right: 1ex;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* search box in the top bar */
|
||||
|
||||
form.tiny, form.tiny p {
|
||||
display: inline;
|
||||
white-space: nowrap;
|
||||
}
|
||||
form.tiny input {
|
||||
padding: 0;
|
||||
width: 10ex;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/* bold = small caps */
|
||||
b, strong {
|
||||
font-family: "EB Garamond All SC";
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* code */
|
||||
|
||||
pre, code, tt {
|
||||
font-family: "Andale Mono", Monaco, "Courier New", Courier, monospace;
|
||||
font-size: 80%;
|
||||
line-height: 110%;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow:hidden;
|
||||
white-space: pre-wrap; /* CSS 3 */
|
||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
}
|
||||
|
||||
/* styling for divs that will be invisible when printing
|
||||
when printing. */
|
||||
|
||||
div.header, div.footer, div.near, div.definition, p.comment, a.tag {
|
||||
|
||||
font-size: 14pt;
|
||||
line-height: 16pt;
|
||||
}
|
||||
div.footer form.search {
|
||||
display: none;
|
||||
}
|
||||
div.rc li {
|
||||
line-height: 110%;
|
||||
}
|
||||
div.rc li + li {
|
||||
margin-top: 1em;
|
||||
}
|
||||
div.rc li strong, table.history strong, strong.description {
|
||||
font-weight: inherit;
|
||||
}
|
||||
div.diff {
|
||||
padding-left: 5%;
|
||||
padding-right: 5%;
|
||||
font-size: 12pt;
|
||||
line-height: 14pt;
|
||||
color: #000;
|
||||
|
||||
}
|
||||
div.old {
|
||||
background-color: #ffffaf;
|
||||
}
|
||||
div.new {
|
||||
background-color: #cfffcf;
|
||||
}
|
||||
|
||||
div.refer {
|
||||
padding-left: 5%;
|
||||
padding-right: 5%;
|
||||
font-size: 12pt;
|
||||
line-height: 13pt;
|
||||
}
|
||||
|
||||
div.message {
|
||||
background-color:#fee;
|
||||
color:#000;
|
||||
}
|
||||
|
||||
img.xml {
|
||||
border:none;
|
||||
padding:1px;
|
||||
}
|
||||
a.small img {
|
||||
max-width:300px;
|
||||
}
|
||||
a.large img {
|
||||
max-width:600px;
|
||||
}
|
||||
div.sister {
|
||||
margin-right:1ex;
|
||||
background-color:inherit;
|
||||
}
|
||||
div.sister p {
|
||||
margin-top:0;
|
||||
}
|
||||
div.sister hr {
|
||||
display:none;
|
||||
}
|
||||
div.sister img {
|
||||
border:none;
|
||||
}
|
||||
|
||||
div.near, div.definition {
|
||||
background-color:#efe;
|
||||
}
|
||||
|
||||
div.sidebar {
|
||||
float:right;
|
||||
border:1px dotted #000;
|
||||
padding:0 1em;
|
||||
}
|
||||
div.sidebar ul {
|
||||
padding-left:1em;
|
||||
}
|
||||
|
||||
/* replacements, features */
|
||||
|
||||
ins {
|
||||
color: #b33;
|
||||
text-decoration: none;
|
||||
}
|
||||
acronym, abbr {
|
||||
letter-spacing:0.1em;
|
||||
font-variant:small-caps;
|
||||
}
|
||||
|
||||
/* Interlink prefix not shown */
|
||||
a .site, a .separator {
|
||||
display: none;
|
||||
}
|
||||
a cite { font:inherit; }
|
||||
/* browser borkage */
|
||||
textarea[name="text"] { width:97%; height:80%; }
|
||||
textarea[name="summary"] { width:97%; height:3em; }
|
||||
/* comments */
|
||||
textarea[name="aftertext"] { width:97%; height:10em; }
|
||||
div.commentshown {
|
||||
background-color:#ffc;
|
||||
padding-bottom:1ex;
|
||||
}
|
||||
div.commenthidden {
|
||||
display:none;
|
||||
}
|
||||
div.commentshown {
|
||||
display:block;
|
||||
}
|
||||
p.comment {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
div.comment {
|
||||
font-size: 14pt;
|
||||
}
|
||||
div.comment h2 {
|
||||
margin-top: 5em;
|
||||
}
|
||||
/* comment pages with username, homepage, and email subscription */
|
||||
.comment form span { display: block; }
|
||||
.comment form span label { display: inline-block; width: 10em; }
|
||||
/* IE sucks */
|
||||
.comment input#username,
|
||||
.comment input#homepage,
|
||||
.comment input#mail { width: 20em; }
|
||||
|
||||
/* cal */
|
||||
div.month { padding:0; margin:0 2ex; }
|
||||
body > div.month {
|
||||
float:right;
|
||||
background-color: inherit;
|
||||
border:solid thin;
|
||||
padding:0 1ex;
|
||||
}
|
||||
div.year > div.month {
|
||||
float:left;
|
||||
}
|
||||
div.footer {
|
||||
clear:both;
|
||||
}
|
||||
div.content div.month a.edit {
|
||||
color:inherit;
|
||||
font-weight:inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* history tables and other tables */
|
||||
table.history {
|
||||
border: none;
|
||||
}
|
||||
td.history {
|
||||
border: none;
|
||||
}
|
||||
|
||||
table.user {
|
||||
border: none;
|
||||
border-top: 1px solid #ccc;
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding: 1em;
|
||||
margin: 1em 2em;
|
||||
}
|
||||
table.user tr td, table.user tr th {
|
||||
border: none;
|
||||
padding: 0.2em 0.5em;
|
||||
vertical-align: top;
|
||||
}
|
||||
table.arab tr th {
|
||||
font-weight:normal;
|
||||
text-align:left;
|
||||
vertical-align:top;
|
||||
}
|
||||
table.arab, table.arab tr th, table.arab tr td {
|
||||
border:none;
|
||||
}
|
||||
th.nobreak {
|
||||
white-space:nowrap;
|
||||
}
|
||||
table.full { width:99%; margin-left:1px; }
|
||||
table.j td, table.j th, table tr td.j, table tr th.j, .j { text-align:justify; }
|
||||
table.l td, table.l th, table tr td.l, table tr th.l, .l { text-align:left; }
|
||||
table.r td, table.r th, table tr td.r, table tr th.r, .r { text-align:right; }
|
||||
table.c td, table.c th, table tr td.c, table tr th.c, .c { text-align:center; }
|
||||
table.t td { vertical-align: top; }
|
||||
td.half { width:50%; }
|
||||
td.third { width:33%; }
|
||||
|
||||
form table td { padding:5px; }
|
||||
|
||||
/* lists */
|
||||
dd { padding-bottom:0.5ex; }
|
||||
dl.inside dt { float:left; }
|
||||
/* search */
|
||||
div.search span.result { font-size:larger; }
|
||||
div.search span.info { font-size:smaller; font-style:italic; }
|
||||
div.search p.result { display:none; }
|
||||
|
||||
img.logo {
|
||||
float: right;
|
||||
margin: 0 0 0 1ex;
|
||||
padding: 0;
|
||||
border: 1px solid #000;
|
||||
opacity: 0.3;
|
||||
background-color:#ffe;
|
||||
}
|
||||
|
||||
/* images */
|
||||
|
||||
div.content a.feed img, div.journal a.feed img,
|
||||
div.content a img.smiley, div.journal a img.smiley, img.smiley,
|
||||
div.content a.inline img, div.journal a.inline img,
|
||||
div.content li a.image img, div.journal li a.image img {
|
||||
margin: 0; padding: 0; border: none;
|
||||
}
|
||||
div.image a img {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
div.image span.caption {
|
||||
margin: 0 1em;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.left { float:left; margin-right: 1em; }
|
||||
.right { float:right; margin-left: 1em; }
|
||||
.half a img { height: 50%; width: 50%; }
|
||||
div.left .left, div.right .right {
|
||||
float:none;
|
||||
}
|
||||
.center { text-align:center; }
|
||||
table.aside {
|
||||
float:right;
|
||||
width:40%;
|
||||
margin-left: 1em;
|
||||
padding: 1ex;
|
||||
border: 1px dotted #666;
|
||||
}
|
||||
table.aside td {
|
||||
text-align:left;
|
||||
}
|
||||
div.sidebar {
|
||||
float:right; width: 250px;
|
||||
text-align: right;
|
||||
border: none;
|
||||
margin: 1ex;
|
||||
}
|
||||
|
||||
.bigsidebar {
|
||||
float:right;
|
||||
width: 500px;
|
||||
border: none;
|
||||
margin-left: 1ex;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
dl.irc dt { width:20ex; float:left; text-align:right; clear:left; }
|
||||
dl.irc dt span.time { float:left; }
|
||||
dl.irc dd { margin-left:22ex; }
|
||||
|
||||
/* portrait */
|
||||
|
||||
div.footer, div.comment, hr { clear: both; }
|
||||
.portrait { float: left; font-size: small; margin-right: 1em; }
|
||||
.portrait { line-height: 1em; }
|
||||
.portrait a { color: #999; }
|
||||
|
||||
div.left { float:left; margin:1em; padding: 0.5em; }
|
||||
div.left p { display:table-cell; }
|
||||
div.left p + p { display:table-caption; caption-side:bottom; }
|
||||
|
||||
p.table a { float:left; width:20ex; }
|
||||
p.table + p { clear:both; }
|
||||
|
||||
/* no bleeding
|
||||
@media screen {
|
||||
div.content, div.rc {
|
||||
overflow:hidden;
|
||||
}
|
||||
} */
|
||||
|
||||
@media print {
|
||||
body {
|
||||
font-size: 12pt;
|
||||
line-height: 13pt;
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/* hide all the crap */
|
||||
div.diff, div.diff+hr, div.refer, div.near, div.definition, div.sister,
|
||||
div.cal, div.footer, span.specialdays, span.gotobar, a.edit, a.number span,
|
||||
div.rc form, form.tiny, p.comment, p#plus1, div.g-plusone {
|
||||
display:none;
|
||||
}
|
||||
a,
|
||||
a:visited,
|
||||
div.content a.near:link,
|
||||
div.content a.near:visited,
|
||||
div.content a.near:active {
|
||||
color:inherit;
|
||||
font-weight: bold;
|
||||
}
|
||||
div.content a.feed {
|
||||
display: none;
|
||||
}
|
||||
div.content a.book,
|
||||
div.content a.movie {
|
||||
text-decoration: none;
|
||||
}
|
||||
a cite {
|
||||
font-style: italic;
|
||||
}
|
||||
/* no difference */
|
||||
pre, code, tt {
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
/* no dotted underlines */
|
||||
acronym, abbr {
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
/* headings */
|
||||
h1 {
|
||||
color: inherit;
|
||||
margin-top: 2em;
|
||||
}
|
||||
h2 {
|
||||
color:inherit;
|
||||
margin: 1em 0;
|
||||
font-variant: small-caps;
|
||||
font-family: "EB Garamond All SC", "EB Garamond", Garamond, serif;
|
||||
}
|
||||
h3 {
|
||||
font-weight:inherit;
|
||||
font-style:italic;
|
||||
color:inherit;
|
||||
margin: 1em 0;
|
||||
}
|
||||
h1 a, h2 a, h3 a {
|
||||
color: inherit;
|
||||
}
|
||||
div.journal h1 a:visited,
|
||||
div.journal h2 a:visited,
|
||||
div.journal h3 a:visited {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
/* rss */
|
||||
channel * { display: block; }
|
||||
|
||||
channel title {
|
||||
margin-top: 30pt;
|
||||
}
|
||||
copyright {
|
||||
font-size: 14pt;
|
||||
line-height: 16pt;
|
||||
margin-top: 1em;
|
||||
}
|
||||
channel > link:before {
|
||||
font-size: 18pt;
|
||||
display: block;
|
||||
margin: 1em;
|
||||
padding: 0.5em;
|
||||
content: "This is an RSS feed, designed to be read in a feed reader.";
|
||||
color: red;
|
||||
border: 1px solid red;
|
||||
}
|
||||
link, license {
|
||||
font-size: 11pt;
|
||||
margin-bottom: 9pt;
|
||||
}
|
||||
username:before { content: "Last edited by "; }
|
||||
username:after { content: "."; }
|
||||
generator:before { content: "Feed generated by "; }
|
||||
generator:after { content: "."; }
|
||||
channel description {
|
||||
font-weight: bold;
|
||||
}
|
||||
item description {
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
docs, language,
|
||||
pubDate, lastBuildDate, ttl, guid, category, comments,
|
||||
docs, image title, image link,
|
||||
status, version, diff, history, importance {
|
||||
display: none;
|
||||
}
|
||||
272
css/light.css
Normal file
272
css/light.css
Normal file
@@ -0,0 +1,272 @@
|
||||
/* This file is in the public domain. */
|
||||
|
||||
/* Esteban is nice, but bold is not so nice, and on Windows it suffers.
|
||||
@import url(http://fonts.googleapis.com/css?family=Esteban&subset=latin,latin-ext);
|
||||
|
||||
For campaignwiki.org, we need to use the same URL in the config file when
|
||||
calling wkhtmltopdf. */
|
||||
|
||||
@import url(https://fonts.googleapis.com/css?family=Noticia+Text:400,400italic,700italic,700&subset=latin,latin-ext);
|
||||
|
||||
body {
|
||||
font-family: "Noticia Text", Times, serif;
|
||||
font-size: 14pt;
|
||||
color: #000;
|
||||
background-color: #eed;
|
||||
margin:1em 2em;
|
||||
}
|
||||
|
||||
@media print {
|
||||
body {
|
||||
background-color: white;
|
||||
font-family: Times, serif;
|
||||
font-size:10pt;
|
||||
}
|
||||
}
|
||||
|
||||
/* iPhone */
|
||||
|
||||
@media only screen and (max-device-width: 480px) {
|
||||
img { max-width: 480px !important; }
|
||||
}
|
||||
|
||||
/* iPad */
|
||||
|
||||
@media only screen and (min-device-width: 481px) and (max-device-width: 900px) {
|
||||
body { font-size: 150%; }
|
||||
textarea,input { font-size: 100%; }
|
||||
img { max-width: 550px !important; }
|
||||
}
|
||||
|
||||
/* general */
|
||||
div.browse {
|
||||
min-height: 3em;
|
||||
}
|
||||
div.footer {
|
||||
clear:both;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
/* comments, footer */
|
||||
div.commentshown {
|
||||
padding-bottom: 1ex;
|
||||
padding-left: 2em;
|
||||
border-left: 2px solid black;
|
||||
font-size: smaller;
|
||||
}
|
||||
div.commenthidden { display:none; }
|
||||
div.commentshown { display:block; }
|
||||
/* comment pages with username, homepage, and email subscription */
|
||||
.comment span { display: block; }
|
||||
.comment span label {
|
||||
display: inline-block; width: 10em;
|
||||
}
|
||||
input#mail, input#homepage, input#username {
|
||||
display: inline-block; width: 20em;
|
||||
}
|
||||
|
||||
/* titles */
|
||||
h1 {
|
||||
font-weight: bold;
|
||||
font-size: 150%;
|
||||
padding: 1em 0;
|
||||
}
|
||||
h1 a:link, h1 a:visited {
|
||||
color: inherit;
|
||||
background-color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
h2 {
|
||||
font-weight: bold;
|
||||
font-size: 130%;
|
||||
padding: 1em 0;
|
||||
clear: both;
|
||||
}
|
||||
@media print {
|
||||
h1 a, h2 a, h3 a, h4 a { font-style: normal; }
|
||||
}
|
||||
|
||||
/* links */
|
||||
a:link {
|
||||
color: #851;
|
||||
background-color: inherit;
|
||||
}
|
||||
a:visited {
|
||||
color: #542;
|
||||
background-color: inherit;
|
||||
}
|
||||
a:active {
|
||||
color:#a41;
|
||||
background-color: inherit;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
font-size: 150%;
|
||||
cursor: pointer;
|
||||
padding: 0.3em 0.5em;
|
||||
text-shadow: 0px -1px 0px #ccc;
|
||||
background-color: #cfa;
|
||||
border: 1px solid #9d8;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0px 1px 3px white inset,
|
||||
0px 1px 3px black;
|
||||
}
|
||||
.button a {
|
||||
text-decoration: none;
|
||||
font-weight: normal;
|
||||
}
|
||||
.bar a { padding-right: 1em; }
|
||||
@media print {
|
||||
a, a:link, a:visited {
|
||||
color:#000;
|
||||
text-decoration:none;
|
||||
font-weight: normal;
|
||||
}
|
||||
a.edit, div.footer, form, span.gotobar, a.number span { display:none; }
|
||||
a[class="url number"]:after, a[class="inter number"]:after {
|
||||
content:"[" attr(href) "]";
|
||||
}
|
||||
a[class="local number"]:after { content:"[" attr(title) "]"; }
|
||||
img[smiley] { line-height: inherit; }
|
||||
}
|
||||
|
||||
/* edit paragraphs */
|
||||
a.pencil {
|
||||
padding-left: 1ex;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
visible: hidden;
|
||||
transition: visibility 0s 1s, opacity 1s linear;
|
||||
opacity: 0;
|
||||
}
|
||||
*:hover > a.pencil {
|
||||
visible: visible;
|
||||
transition: opacity .5s linear;
|
||||
opacity: 1;
|
||||
}
|
||||
@media print {
|
||||
a.pencil {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* table of contents */
|
||||
.toc {
|
||||
font-size: smaller;
|
||||
border-left: 1em solid #886;
|
||||
}
|
||||
.toc ol {
|
||||
list-style-type: none;
|
||||
padding-left: 1em;
|
||||
}
|
||||
.toc a {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* images with links, captions, etc */
|
||||
div.image { display: inline; margin: 1em; font-size: 90%; text-align: center; }
|
||||
.left { float: left; margin-right: 1em; }
|
||||
.right { float: right; margin-left: 1em; }
|
||||
div.right .right { float: none; }
|
||||
div.left .left { float: none; }
|
||||
.caption { padding: 0 1em; }
|
||||
.license { font-size: small; }
|
||||
.aside {
|
||||
font-size: small;
|
||||
width: 30%;
|
||||
float: right;
|
||||
margin-left: 1em;
|
||||
margin-bottom: 1em;
|
||||
padding-left: 1em;
|
||||
}
|
||||
.aside img.smiley { height: 1em; }
|
||||
.narrow {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
a img { border: 1px solid #333; }
|
||||
.fit img { width: 80%; text-align: center; margin: 2em 8%; }
|
||||
.half img { width: 50%; height: 50%; text-align: center; margin: 2em 8%; }
|
||||
.noborder img { border: none; }
|
||||
.twenty img { max-width: 20em; }
|
||||
img.logo {
|
||||
float: right;
|
||||
clear: right;
|
||||
border-style:none;
|
||||
margin-left: 1em;
|
||||
margin-bottom: 1ex;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
/* fancy bold underline */
|
||||
em.underline { font-weight: bold; }
|
||||
|
||||
/* editing, previewing */
|
||||
textarea { width:100%; }
|
||||
div.edit { padding-right: 1em; }
|
||||
div.diff { padding-left:5%; padding-right:5%; }
|
||||
div.old { background-color:#FFFFAF; }
|
||||
div.new { background-color:#CFFFCF; }
|
||||
/* div.message { background-color:#FEE; } */
|
||||
div.message {
|
||||
background-color: inherit;
|
||||
font-size: smaller;
|
||||
}
|
||||
table.history { border-style:none; }
|
||||
td.history { border-style:none; }
|
||||
span.result { font-size:larger; }
|
||||
span.info { font-size:smaller; font-style:italic; }
|
||||
div.rc hr { display: none; }
|
||||
div.rc li { padding-bottom: 0.5em; }
|
||||
|
||||
/* Tables */
|
||||
table.user {
|
||||
margin: 1em 0;
|
||||
padding: 0 1em;
|
||||
border-top: 1px solid black;
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
div.aside table.user {
|
||||
margin: 1em 0;
|
||||
padding: 0;
|
||||
}
|
||||
table.user td, table.user th {
|
||||
border-style: none;
|
||||
padding:5px 10px;
|
||||
vertical-align: top;
|
||||
}
|
||||
table.user th { font-weight:bold; }
|
||||
table.user td.r { text-align:right; }
|
||||
table.user td.l { text-align:left; }
|
||||
table.user td.c { text-align:center; }
|
||||
table.user td.j { text-align:justify; }
|
||||
table.user td.mark { background-color:yellow; }
|
||||
tr:empty { display: block; height: 0.5em; }
|
||||
@media print {
|
||||
table {
|
||||
font-size: 9pt;
|
||||
margin: 0;
|
||||
}
|
||||
table.user td, table.user th {
|
||||
padding: 0 1ex;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calendar */
|
||||
div.month { margin:0; padding:0; font-size:x-small; float:right; }
|
||||
div.content div.month { float:none; }
|
||||
div.year div.month { float:left; font-size:medium; padding:1ex; }
|
||||
div.month pre { margin:0; padding:0 0 0 1ex; }
|
||||
div.month a { text-decoration:none; font: inherit; }
|
||||
div.month span.title a { font: inherit; }
|
||||
/* no difference between a.exact and a.collection */
|
||||
div.month a.local { font-weight: bold; }
|
||||
div.month a.local:link { color: #562; }
|
||||
div.month a.local:visited { color: #542; }
|
||||
div.month a.today { background-color: #faa; }
|
||||
div.month span.title a.local { font-weight: normal; color: #842; }
|
||||
@media print {
|
||||
div.month { display: none; }
|
||||
div.year div.month { display: block; }
|
||||
div.year div.month a { display: inline; }
|
||||
}
|
||||
75
modules/edit-paragraphs.js
Normal file
75
modules/edit-paragraphs.js
Normal file
@@ -0,0 +1,75 @@
|
||||
/* Copyright 2014 Alex Schroeder <alex@gnu.org>
|
||||
based on http://git.savannah.gnu.org/cgit/oddmuse.git/plain/plinks.js
|
||||
for more information see http://oddmuse.org/wiki/Purple_Numbers_Extension
|
||||
based on http://simon.incutio.com/archive/2004/05/30/plinks#p-13
|
||||
Copyright 2004 Simon Willison
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
function add_edit_links() {
|
||||
/* Only show edit links on ordinary pages: They either use
|
||||
* path_info or keywords in the URL, not parameters. */
|
||||
if (/=/.test(document.location.href)) {
|
||||
return;
|
||||
}
|
||||
// find all the pencil links
|
||||
var links = new Array;
|
||||
var elem = document.getElementsByTagName('a');
|
||||
for (var i = 0; i < elem.length; i++) {
|
||||
var atr = elem[i].getAttribute('class');
|
||||
if (atr != null) {
|
||||
var classes = atr.split(" ");
|
||||
for (var j = 0; j < classes.length; j++) {
|
||||
if (classes[j] == 'pencil') {
|
||||
links.push(elem[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// make them invisible
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
var link = links[i];
|
||||
var func = function(thislink) {
|
||||
return function() {
|
||||
if (thislink.style.visibility == "visible") {
|
||||
thislink.style.transition = "visibility 0s 1s, opacity 1s linear";
|
||||
thislink.style.visibility = "hidden";
|
||||
thislink.style.opacity = "0";
|
||||
} else {
|
||||
thislink.style.transition = "opacity 1s linear";
|
||||
thislink.style.visibility = "visible";
|
||||
thislink.style.opacity = "1";
|
||||
};
|
||||
}
|
||||
};
|
||||
link.style.transition = "visibility 0s 1s, opacity 1s linear";
|
||||
link.style.visibility = "hidden";
|
||||
link.style.opacity = "0";
|
||||
link.parentNode.onclick = func(link);
|
||||
}
|
||||
}
|
||||
|
||||
function add_load_event(func) {
|
||||
var oldonload = window.onload;
|
||||
if (typeof window.onload != 'function') {
|
||||
window.onload = func;
|
||||
} else {
|
||||
window.onload = function() {
|
||||
oldonload();
|
||||
func();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_load_event(add_edit_links);
|
||||
198
modules/edit-paragraphs.pl
Normal file
198
modules/edit-paragraphs.pl
Normal file
@@ -0,0 +1,198 @@
|
||||
# Copyright (C) 2014 Alex Schroeder <alex@gnu.org>
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package OddMuse;
|
||||
|
||||
AddModuleDescription('edit-paragraph.pl', 'Edit Paragraphs Extension');
|
||||
|
||||
# edit icon
|
||||
# http://publicdomainvectors.org/en/free-clipart/Pencil-vector-icon/9221.html
|
||||
# q{<img width="30" height="30" title="" alt="edit" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAE2UlEQVRIx53WW0sbaRwG8GcmSsxhdTKT5K60FFqa4CmKh96uq62gtR563butN1KNQSgESqFemBjr2mKjMRpBt1uln2FJe9ObHsyu3d2yyH6EFoTVhr7PXrQTJslMmuwLA0mYvL95/vOebPjSJJMLJZ+t7iu9pw9AHEAQwAGAE4v/Wnasf5dNHsQK/R7A37IsEwAB/ATAY9W/VUpjh9Wi7wHw5s2b4vz588KAKyb9fDMVqniwPgB/AWA0GhX5fF68fftWBAIBHV82wf83bET/AMDJyUnx4cMHwa/t1atXRry07AW0FlhvPwA4dDgclCRJtLe3ixcvXtDYXr9+bcRXjLhcQ+JS9LeGhgbeunVLXL58WQBgIBDg8+fPy/BgMKjjD3VcrrHUOppraGjg3NycWFpaEmfOnKGiKLTC37x5I1paWnT8US2w3voBHDgcDkYiEZFIJITP56PH42E0GmVLSwsB8NKlS8xms0V4JpMRdXV1+lSrWNbS3/sBHLhcLs7OzopEIiH8fj8VReHy8jIjkQhdLhfPnTtXhudyOdHV1UVJkgSAPVQxV4uSulwuhsNhsbi4KPx+P1VV5dLSEsPhMGVZZnNzMxcWFnj27FkCYDAY5P7+vmhra9OT/gLAWe0yOADgwO12c2ZmpoBqmsbFxUWGw2HabDY2Nzdza2uLN27coCzL7Ojo0BPq6C4Ad7Ur0gCAnNvtLkrq9XoZj8cLSVtbW7mxscHx8XEC4NDQEBcWFoSqqjq6DeC7ass7ACBXWl6v18tYLFZA29vbub6+zomJCQLg8PAwt7e3RW9vL7+u22kATWYrlxl6BcDvTqeTkUhExONx4fP5CklnZ2dps9kYCoWYTCYL6PXr15lOp0V3d7eeNGWxUVii7xwOB+fm5spQPWlHR0cROjY2xlQqJXp6enQ0CUD71u5kRP+02+28c+eOiMfj9Hq91DSNiUSCMzMzpuj4+DjX1tZEb2+vjq4C8FZ4pUXoVQDv6+vrGY1GRSwWE5qmUVVVPnjwoICGQiGura0VBtLExASTyaQRfQTAV+U4wlV9E797966IxWJUVZWKonBlZYXT09OUZZltbW1MpVKV0IeSJPnN3qkZPAjgCADv3bsnYrEYPR4PGxsbubq6ytu3b1OSJLa2tjKdTnNsbMyqvCsmqGWprwD4R9/E79+/z6amJrrdbq6vr3NqaqqwImUyGY6OjhIAR0dHSwfSyjeSlrV3dXV1nJ+fFx8/fuSTJ0/Y2NjIjY0NTk1NUZIkBgIB7uzscGRkhAA4MjLCzc1N45R5KEmSr8LZzbRRURTx6dMnkuTx8TGz2SwnJycJgBcvXuTTp0957dq1osWhq6vLOJAqjl6rB6CqqoIkhfhyasnn80yn07xw4QL39/c5PDxMABwcHOTu7q7o7Ow0Thmt2tFbBmuaRiMshODJyQlfvnzJoaEhAuDAwAD39vZEKBQyLg6eGk6h5XB9fT0zmUwRTpKnp6d8/Pgx+/v7+ezZM+PWlrI4sko1lfrre+bm5mYZ/vnzZ2azWREMBnU0XbLLSFVureawjm9tbRUdV3K5nAgEAgQgAGQAuGpALRNLBlgCAKfTib6+PtjtdpyenvLw8FA6OjoSAH4G8COAfyuVzyKYafvVmNrkygPYAWCvMWnFUv8Hwmcq2TCQ4MwAAAAASUVORK5CYII=" />};
|
||||
|
||||
our $EditParagraphPencil = '✎';
|
||||
|
||||
# Allow editing of substrings
|
||||
|
||||
$Action{'edit-paragraph'} = \&DoEditParagraph;
|
||||
|
||||
sub DoEditParagraph {
|
||||
my $id = GetParam('title', '');
|
||||
UserCanEditOrDie($id);
|
||||
|
||||
my $old = UnquoteHtml(GetParam('paragraph', ''));
|
||||
$old =~ s/\r//g;
|
||||
return DoEdit($id) unless $old;
|
||||
|
||||
my $around = GetParam('around', undef);
|
||||
|
||||
# Find text to edit
|
||||
my $new = GetParam('text', '');
|
||||
OpenPage($id);
|
||||
if ($new) {
|
||||
my $myoldtime = GetParam('oldtime', ''); # maybe empty!
|
||||
my $text;
|
||||
if ($myoldtime and $myoldtime != $LastUpdate) {
|
||||
($text) = GetTextAtTime($myoldtime);
|
||||
} else {
|
||||
$text = $Page{text};
|
||||
}
|
||||
|
||||
my $done;
|
||||
if ($around) {
|
||||
# The tricky part is that the numbers refer to the HTML quoted text. What a pain.
|
||||
my $qold = QuoteHtml($old);
|
||||
my $qtext = QuoteHtml($text);
|
||||
|
||||
if (substr($qtext, $around - length($qold), length($qold)) eq $qold) {
|
||||
$text = UnquoteHtml(substr($qtext, 0, $around - length($qold))
|
||||
. QuoteHtml($new) . substr($qtext, $around));
|
||||
$done = 1;
|
||||
}
|
||||
} else {
|
||||
# simple case, just do it
|
||||
my $search_term = quotemeta($old);
|
||||
$done = $text =~ s/$search_term/$new/;
|
||||
}
|
||||
|
||||
if ($done) {
|
||||
SetParam('text', UnquoteHtml($text));
|
||||
return DoPost($id);
|
||||
} else {
|
||||
ReportError(T('Could not identify the paragraph you were editing'),
|
||||
'500 INTERNAL SERVER ERROR',
|
||||
undef,
|
||||
$q->p(T('This is the section you edited:'))
|
||||
. $q->pre(QuoteHtml($old))
|
||||
. $q->p(T('This is the current page:'))
|
||||
. $q->pre($text));
|
||||
}
|
||||
}
|
||||
print GetHeader('', Ts('Editing %s', NormalToFree($id)));
|
||||
print $q->start_div({-class=>'content edit paragraph'});
|
||||
my $form = GetEditForm($id, undef, $old);
|
||||
my $param = GetHiddenValue('paragraph', $old);
|
||||
$param .= GetHiddenValue('action', 'edit-paragraph'); # add action
|
||||
$param .= GetHiddenValue('around', $around); # add around position
|
||||
$form =~ s!</form>!$param</form>!;
|
||||
print $form;
|
||||
print $q->end_div();
|
||||
PrintFooter($id, 'edit');
|
||||
}
|
||||
|
||||
# When PrintWikiToHTML is called for the current revision of a page we
|
||||
# initialize our data structure. The data structure simply divides the
|
||||
# page up into blocks based on what one would like to edit. By
|
||||
# default, that's just paragraph breaks and list items. When using
|
||||
# Creole, ordered list items and table rows are added.
|
||||
|
||||
my @EditParagraphs = ();
|
||||
|
||||
*EditParagraphOldPrintWikiToHTML = *PrintWikiToHTML;
|
||||
*PrintWikiToHTML = *EditParagraphNewPrintWikiToHTML;
|
||||
|
||||
sub EditParagraphNewPrintWikiToHTML {
|
||||
my ($text, $is_saving_cache, $revision, $is_locked) = @_;
|
||||
# We need to use quoted HTML because that's what the rules will applied to!
|
||||
my $quoted_text = QuoteHtml($text);
|
||||
if ($quoted_text and not $revision) {
|
||||
my ($start, $end) = (0, 0);
|
||||
# This grouping with zero-width positive look-ahead assertion makes sure that this chunk of text does not include
|
||||
# markup need for the next chunk of text.
|
||||
if (grep { $_ eq \&CreoleRule } @MyRules) {
|
||||
$regexp = "\n+(\n|(?=[*#-=|]))";
|
||||
} else {
|
||||
$regexp = "\n+(\n|(?=[*]))";
|
||||
}
|
||||
while ($quoted_text =~ /$regexp/g) {
|
||||
$end = pos($quoted_text);
|
||||
push(@EditParagraphs,
|
||||
[$start, $end, substr($quoted_text, $start, $end - $start)]);
|
||||
$start = $end;
|
||||
}
|
||||
# Only do this if we have at least two paragraphs and the end isn't just some empty lines.
|
||||
if (@EditParagraphs and $start and $start < length($quoted_text)) {
|
||||
push(@EditParagraphs, [$start, length($quoted_text), substr($quoted_text, $start)]);
|
||||
}
|
||||
}
|
||||
# warn join('', '', map { $_->[0] . "-" . $_->[1] .": " . $_->[2]; } @EditParagraphs);
|
||||
return EditParagraphOldPrintWikiToHTML(@_);
|
||||
}
|
||||
|
||||
# Whenever an important element is closed, we try to add a link.
|
||||
|
||||
*EditParagraphOldCloseHtmlEnvironments = *CloseHtmlEnvironments;
|
||||
*CloseHtmlEnvironments = *EditParagraphNewCloseHtmlEnvironments;
|
||||
|
||||
sub EditParagraphNewCloseHtmlEnvironments {
|
||||
EditParagraph();
|
||||
return EditParagraphOldCloseHtmlEnvironments(@_);
|
||||
}
|
||||
|
||||
*EditParagraphOldCloseHtmlEnvironmentUntil = *CloseHtmlEnvironmentUntil;
|
||||
*CloseHtmlEnvironmentUntil = *EditParagraphNewCloseHtmlEnvironmentUntil;
|
||||
|
||||
sub EditParagraphNewCloseHtmlEnvironmentUntil {
|
||||
my $tag = $_[0];
|
||||
if ($tag =~ /^(p|li|table|h[1-6])$/i) {
|
||||
EditParagraph();
|
||||
}
|
||||
return EditParagraphOldCloseHtmlEnvironmentUntil(@_);
|
||||
}
|
||||
|
||||
sub EditParagraph {
|
||||
my $text;
|
||||
my $pos = pos; # pos is empty for the last link
|
||||
if (@EditParagraphs) {
|
||||
if ($pos) {
|
||||
while (@EditParagraphs and $EditParagraphs[0]->[1] <= $pos) {
|
||||
$text .= $EditParagraphs[0]->[2];
|
||||
shift(@EditParagraphs);
|
||||
}
|
||||
} else {
|
||||
# the last one
|
||||
$text = $EditParagraphs[-1]->[2];
|
||||
}
|
||||
}
|
||||
if ($text) {
|
||||
|
||||
# Huge Hack Alert: We are appending to $Fragment, which is what Clean appends to. We do this so that we can handle
|
||||
# headers and other block elements. Without this fix we'd see something like this:
|
||||
# <h2>...</h2><p><a ...>✎</a></p>
|
||||
# Usually this would look as follows:
|
||||
# <h2>...</h2><p></p>
|
||||
# This is eliminated in Dirty. But it won't be eliminated if we leave the link in there. What we want is this:
|
||||
# <h2>...<a ...>✎</a></h2><p></p>
|
||||
#
|
||||
# The same issue arises for other block level elements. What happens at the end of a table? Without this fix we'd
|
||||
# see something like this:
|
||||
# <table><tr><td>...</td></tr></table><p><a ...>✎</a></p>
|
||||
# What we want, I guess, is this:
|
||||
# <table><tr><td>...<a ...>✎</a></td></tr></table></p>
|
||||
|
||||
$pos = $pos || length(QuoteHtml($Page{text})); # make sure we have an around value
|
||||
my $link = ScriptLink("action=edit-paragraph;title=$OpenPageName;around=$pos;paragraph="
|
||||
. UrlEncode(UnquoteHtml($text)), $EditParagraphPencil, 'pencil');
|
||||
if ($Fragment =~ s!((:?</h[1-6]>|</t[dh]></tr></table>|</pre>)<p>)$!!) {
|
||||
# $Fragment .= '<!-- 1 -->';
|
||||
$Fragment .= $link . $1;
|
||||
} elsif ($pos and $Fragment =~ /<p>$/) {
|
||||
# Do nothing: this will result in <p></p> and get eliminated.
|
||||
# $Fragment .= '<!-- 2 -->';
|
||||
} else {
|
||||
# This is the default: add the link.
|
||||
# $Fragment .= '<!-- 3 -->';
|
||||
$Fragment .= $link;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,6 +87,14 @@ sub TocScript {
|
||||
if (toc) {
|
||||
var html = outline.asHTML(true);
|
||||
toc.innerHTML = html;
|
||||
|
||||
items = toc.getElementsByTagName('a');
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
while (items[i].textContent.endsWith('✎')) {
|
||||
var text = items[i].childNodes[0].nodeValue;
|
||||
items[i].childNodes[0].nodeValue = text.substring(0, text.length - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
254
t/edit-paragraphs.t
Normal file
254
t/edit-paragraphs.t
Normal file
@@ -0,0 +1,254 @@
|
||||
# Copyright (C) 2014 Alex Schroeder <alex@gnu.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
require 't/test.pl';
|
||||
package OddMuse;
|
||||
use Test::More tests => 48;
|
||||
use utf8;
|
||||
clear_pages();
|
||||
|
||||
AppendStringToFile($ConfigFile, "\$CommentsPrefix = 'Comments on ';\n");
|
||||
|
||||
add_module('edit-paragraphs.pl');
|
||||
|
||||
my $text = q{Give me a torch: I am not for this ambling;
|
||||
Being but heavy, I will bear the light.
|
||||
|
||||
Nay, gentle Romeo, we must have you dance.
|
||||
|
||||
|
||||
Not I, believe me: you have dancing shoes
|
||||
With nimble soles: I have a soul of lead
|
||||
So stakes me to the ground I cannot move.
|
||||
};
|
||||
|
||||
my $page = update_page('Romeo_and_Mercutio', $text);
|
||||
for my $paragraph (split(/\n\n+/, $text)) {
|
||||
test_page($page, 'action=edit-paragraph;title=Romeo_and_Mercutio;around=\d*;paragraph='
|
||||
. UrlEncode($paragraph));
|
||||
}
|
||||
|
||||
# Check whether the form is right.
|
||||
|
||||
ok($page =~ /action=edit-paragraph;title=Romeo_and_Mercutio;around=(\d*);paragraph=([^"]*)/, 'found example link to use');
|
||||
my $around = $1;
|
||||
my $enc = $2;
|
||||
my $par = UrlDecode($enc);
|
||||
xpath_test(get_page("action=edit-paragraph title=Romeo_and_Mercutio around=$around paragraph=$enc"),
|
||||
q'//input[@type="hidden"][@value="Romeo_and_Mercutio"][@name="title"]',
|
||||
q'//input[@type="hidden"][@value="edit-paragraph"][@name="action"]',
|
||||
qq'//textarea[text()="$par"]',
|
||||
qq'//input[\@type="hidden"][\@value="$around"][\@name="around"]');
|
||||
|
||||
# Test for extra links in empty paragraphs before and after tables.
|
||||
|
||||
add_module('creole.pl');
|
||||
|
||||
$text = q{|PARIS |JULIET |
|
||||
|Come you to make confession to this father? |To answer that, I should confess to you. |
|
||||
|Do not deny to him that you love me. |I will confess to you that I love him. |
|
||||
|So will ye, I am sure, that you love me. | |
|
||||
|
||||
-- William Shakespeare, Romeo and Juliet, Act IV, Scene I
|
||||
};
|
||||
|
||||
$page = update_page('Paris_and_Juliet', $text);
|
||||
test_page_negative($page, '\|', '</table><p><a ');
|
||||
|
||||
for my $row (split(/\n/, $text)) {
|
||||
test_page($page, 'action=edit-paragraph;title=Paris_and_Juliet;around=\d*;paragraph='
|
||||
. UrlEncode($row));
|
||||
}
|
||||
|
||||
$text = q{== Romeo and Juliet, Act III, Scene II
|
||||
|
||||
* Tybalt is gone, and Romeo banished;
|
||||
Romeo that kill'd him, he is banished.
|
||||
* O God! did Romeo's hand shed Tybalt's blood?
|
||||
* It did, it did; alas the day, it did!
|
||||
};
|
||||
|
||||
$page = update_page('Nurse_and_Juliet', $text);
|
||||
|
||||
for my $item (split(/\n(?=[*])/, $text)) {
|
||||
my $str = UrlEncode($item);
|
||||
$str =~ s/\*/\\*/g;
|
||||
test_page($page, 'action=edit-paragraph;title=Nurse_and_Juliet;around=\d*;paragraph='
|
||||
. $str);
|
||||
}
|
||||
|
||||
$text = q{Benvolio: Tell me in sadness, who is that you love.
|
||||
|
||||
Romeo: What, shall I groan and tell thee?
|
||||
|
||||
Benvolio: Groan! why, no. But sadly tell me who.
|
||||
|
||||
Romeo: Bid a sick man in sadness make his will: Ah, word ill urged to
|
||||
one that is so ill! In sadness, cousin, I do love a woman.
|
||||
|
||||
Benvolio: I aim'd so near, when I supposed you loved.
|
||||
|
||||
Romeo: A right good mark-man! And she's fair I love.
|
||||
|
||||
Benvolio: A right fair mark, fair coz, is soonest hit.
|
||||
};
|
||||
|
||||
# Replace the first occurence.
|
||||
|
||||
test_page(update_page('Benvolio_and_Romeo', $text),
|
||||
'Benvolio: Tell me in sadness');
|
||||
test_page(get_page('action=edit-paragraph title=Benvolio_and_Romeo '
|
||||
. 'around=0 paragraph=Benvolio text=Ben'),
|
||||
# not using update_page because of the parameters
|
||||
'Status: 302');
|
||||
test_page(get_page('Benvolio_and_Romeo'),
|
||||
'Ben: Tell me in sadness',
|
||||
'Benvolio: Groan!');
|
||||
|
||||
# Reset and try again but replace the occurence around 105.
|
||||
|
||||
update_page('Benvolio_and_Romeo', $text);
|
||||
test_page(get_page('action=edit-paragraph title=Benvolio_and_Romeo '
|
||||
. 'around=105 '
|
||||
. 'paragraph=Benvolio text=Ben'),
|
||||
# not using update_page because of the parameters
|
||||
'Status: 302');
|
||||
test_page(get_page('Benvolio_and_Romeo'),
|
||||
'Benvolio: Tell me in sadness',
|
||||
'Ben: Groan!');
|
||||
|
||||
SKIP: {
|
||||
|
||||
skip "We don't do fuzzy matching anymore.", 3;
|
||||
|
||||
# Try again but now let's simulate a page changed in the background
|
||||
# such that the text is now not exactly at the expected position, but
|
||||
# close by.
|
||||
$text =~ s/tell thee/tell you/;
|
||||
update_page('Benvolio_and_Romeo', $text);
|
||||
test_page(get_page('action=edit-paragraph title=Benvolio_and_Romeo '
|
||||
. 'around=105 '
|
||||
. 'paragraph=Benvolio text=Ben'),
|
||||
# not using update_page because of the parameters
|
||||
'Status: 302');
|
||||
test_page(get_page('Benvolio_and_Romeo'),
|
||||
'Benvolio: Tell me in sadness',
|
||||
'Ben: Groan!');
|
||||
}
|
||||
|
||||
# HTML encoding.
|
||||
|
||||
$text = q{I am hurt.
|
||||
<em>A plague o' both your houses!</em> I am sped.
|
||||
};
|
||||
xpath_test(get_page('action=edit-paragraph title=Mercutio paragraph="' . UrlEncode($text) . '"'),
|
||||
qq'//textarea[text()="$text"]');
|
||||
|
||||
# Make sure the link at the very end is shown.
|
||||
|
||||
$text = q{
|
||||
{{{
|
||||
BENVOLIO Romeo, away, be gone!
|
||||
The citizens are up, and Tybalt slain.
|
||||
Stand not amazed: the prince will doom thee death,
|
||||
If thou art taken: hence, be gone, away!
|
||||
|
||||
ROMEO O, I am fortune's fool!
|
||||
}}}
|
||||
|
||||
----
|
||||
|
||||
William Shakespeare, Romeo and Juliet, Act III, Scene I
|
||||
};
|
||||
|
||||
$page = update_page('Benvolio_and_Romeo', $text);
|
||||
test_page_negative($page, '</pre><p><a ', '<p><a ');
|
||||
test_page($page, 'fool!<a ', '</pre><hr ?/><p>William', 'Scene I<a');
|
||||
|
||||
# Mixed lists.
|
||||
|
||||
$text = q{* One
|
||||
## Two
|
||||
};
|
||||
|
||||
$page = update_page('Alex_Daniel', $text);
|
||||
for my $item (split(/\n(?=[\*\#])/, $text)) {
|
||||
my $str = UrlEncode($item);
|
||||
$str =~ s/\*/\\*/g;
|
||||
test_page($page, 'action=edit-paragraph;title=Alex_Daniel;around=\d*;paragraph='
|
||||
. $str);
|
||||
}
|
||||
|
||||
# Comments, the last element in particular.
|
||||
|
||||
$text = q{Test
|
||||
|
||||
-- Anonymous
|
||||
|
||||
----
|
||||
|
||||
Test
|
||||
|
||||
-- Real Anonymous
|
||||
};
|
||||
|
||||
$page = update_page('Comments_on_Alex_Daniel', $text);
|
||||
test_page($page, 'action=edit-paragraph;title=Comments_on_Alex_Daniel;around=\d*;paragraph=--%20Real%20Anonymous%0a');
|
||||
|
||||
# More than one newline at the end.
|
||||
|
||||
$text = q{one
|
||||
|
||||
two
|
||||
|
||||
};
|
||||
|
||||
$page = update_page('Alex_Daniel', $text);
|
||||
for my $item (split(/\n+/, $text)) {
|
||||
my $str = UrlEncode($item);
|
||||
$str =~ s/\*/\\*/g;
|
||||
test_page($page, 'action=edit-paragraph;title=Alex_Daniel;around=\d*;paragraph='
|
||||
. $str);
|
||||
}
|
||||
|
||||
# More HTML encoding.
|
||||
|
||||
$text = q{Test.
|
||||
|
||||
<test1>
|
||||
|
||||
<test2>
|
||||
|
||||
<test3>
|
||||
};
|
||||
|
||||
$page = update_page('Test', $text);
|
||||
test_page_negative(get_page('action=browse id=Test raw=1'), '<');
|
||||
# HTML encoded text is longer: every < > counts adds 3. Thus 33 + 6x3 = 51.
|
||||
my $action = 'action=edit-paragraph;title=Test;around=51;paragraph=' . UrlEncode("<test3>\n");
|
||||
test_page($page, $action);
|
||||
test_page(get_page(join(' ', split(';', $action))), QuoteHtml("<test3>\n"));
|
||||
# test error
|
||||
test_page(get_page('action=edit-paragraph title=Test'
|
||||
. ' text=' . UrlEncode("<test30>\n") # new
|
||||
. ' paragraph=' . UrlEncode("<test3>\n") # old
|
||||
. ' around=1'),
|
||||
'Could not identify the paragraph you were editing',
|
||||
'<pre>' . QuoteHtml("<test3>\n") . '</pre>');
|
||||
test_page(get_page('action=edit-paragraph title=Test'
|
||||
. ' text=' . UrlEncode("<test30>\n") # new
|
||||
. ' paragraph=' . UrlEncode("<test3>\n") # old
|
||||
. ' around=51'), 'Status: 302');
|
||||
$text =~ s/test3/test30/;
|
||||
test_page(get_page('action=browse id=Test raw=1'), $text);
|
||||
22
wiki.pl
22
wiki.pl
@@ -98,7 +98,7 @@ $LogoUrl = ''; # URL for site logo ('' for no logo)
|
||||
$NotFoundPg = ''; # Page for not-found links ('' for blank pg)
|
||||
|
||||
$NewText = T('This page is empty.') . "\n"; # New page text
|
||||
$NewComment = T('Add your comment here:') . "\n"; # New comment text
|
||||
$NewComment = T('Add your comment here:'); # New comment text
|
||||
|
||||
$EditAllowed = 1; # 0 = no, 1 = yes, 2 = comments pages only, 3 = comments only
|
||||
$AdminPass //= ''; # Whitespace separated passwords.
|
||||
@@ -2091,11 +2091,20 @@ sub DoAdminPage {
|
||||
my @menu = ();
|
||||
push(@menu, ScriptLink('action=index', T('Index of all pages'), 'index')) if $Action{index};
|
||||
push(@menu, ScriptLink('action=version', T('Wiki Version'), 'version')) if $Action{version};
|
||||
push(@menu, ScriptLink('action=unlock', T('Unlock Wiki'), 'unlock')) if $Action{unlock};
|
||||
push(@menu, ScriptLink('action=password', T('Password'), 'password')) if $Action{password};
|
||||
push(@menu, ScriptLink('action=password', T('Password'), 'password')) if $Action{password};
|
||||
push(@menu, ScriptLink('action=maintain', T('Run maintenance'), 'maintain')) if $Action{maintain};
|
||||
my @locks;
|
||||
for my $pattern (@KnownLocks) {
|
||||
for my $name (bsd_glob $pattern) {
|
||||
if (-d $LockDir . $name) {
|
||||
push(@locks, $name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (@locks and $Action{unlock}) {
|
||||
push(@menu, ScriptLink('action=unlock', T('Unlock Wiki'), 'unlock') . ' (' . join(', ', @locks) . ')');
|
||||
};
|
||||
if (UserIsAdmin()) {
|
||||
push(@menu, ScriptLink('action=clear', T('Clear Cache'), 'clear')) if $Action{clear};
|
||||
if ($Action{editlock}) {
|
||||
if (-f "$DataDir/noedit") {
|
||||
push(@menu, ScriptLink('action=editlock;set=0', T('Unlock site'), 'editlock 0'));
|
||||
@@ -2113,6 +2122,7 @@ sub DoAdminPage {
|
||||
Ts('Lock %s', $title), 'pagelock 1'));
|
||||
}
|
||||
}
|
||||
push(@menu, ScriptLink('action=clear', T('Clear Cache'), 'clear')) if $Action{clear};
|
||||
}
|
||||
foreach my $sub (@MyAdminCode) {
|
||||
&$sub($id, \@menu, \@rest);
|
||||
@@ -3516,7 +3526,7 @@ sub DoPost {
|
||||
}
|
||||
my $comment = UnquoteHtml(GetParam('aftertext', undef));
|
||||
$comment =~ s/(\r|$FS)//go;
|
||||
if (defined($comment) and (not $comment or $comment eq $NewComment)) {
|
||||
if (defined $comment and $comment eq '') {
|
||||
ReleaseLock();
|
||||
ReBrowsePage($id);
|
||||
}
|
||||
@@ -3630,7 +3640,7 @@ sub AddComment {
|
||||
my ($string, $comment) = @_;
|
||||
$comment =~ s/\r//g; # Remove "\r"-s (0x0d) from the string
|
||||
$comment =~ s/\s+$//g; # Remove whitespace at the end
|
||||
if ($comment ne '' and $comment ne $NewComment) {
|
||||
if ($comment ne '') {
|
||||
my $author = GetParam('username', T('Anonymous'));
|
||||
my $homepage = GetParam('homepage', '');
|
||||
$homepage = 'http://' . $homepage if $homepage and $homepage !~ /^($UrlProtocols):/;
|
||||
|
||||
Reference in New Issue
Block a user