Compare commits

..

13 Commits

Author SHA1 Message Date
Alex Schroeder
bd2715a35e DoSearch: Add link to actually DO the replacement 2015-12-16 18:19:33 +01:00
Alex Schroeder
986e4fc65f Replace: no pagination
The old code would only call the the function provided
if pagination indicated that it was OK to do so. Thus,
only the first ten pages got replaced. This has been
fixed and tests have been added.
2015-12-16 15:50:35 +01:00
Alex Schroeder
908cecffb9 atom.t: fix warning 2015-12-16 10:04:56 +01:00
IngoBelka
07226ae7a1 typo 2015-11-29 10:25:15 +01:00
IngoBelka
c90258ef4b supplementing the German transltion 2015-11-29 10:10:47 +01:00
Aleks-Daniel Jakimenko-Aleksejev
f500092a6a Alexine IRC bot 2015-11-19 23:25:18 +02:00
Alex Schroeder
d1f1f65c9b green.css: no dashed line between sister sites 2015-11-18 09:58:20 +01:00
Alex Schroeder
aae0cb6379 light.css: no bold summary for recent changes 2015-11-15 21:58:58 +01:00
Alex Schroeder
2b0a0d9a14 word-count.pl: fix regular expression for dates 2015-11-15 21:58:58 +01:00
Aleks-Daniel Jakimenko-Aleksejev
69fcb9646b Fix tests for default stylesheet link
Also, get rid of redundant “www”.
2015-11-03 03:21:27 +02:00
Aleks-Daniel Jakimenko-Aleksejev
a0bf615960 Alexine: some successful commits are major
If previous commit had some failing tests then Alexine will announce that on
the wiki. When the problem is solved we probably don't want to see scary
messages in Recent Changes, so next successful commit should be announced (it
should not be a minor edit).
2015-11-03 03:03:13 +02:00
Aleks-Daniel Jakimenko-Aleksejev
c024f553fd Default css should be retrieved over secure connection
Everything on oddmuse.org now redirects to https, which means that every wiki
that is using default style sheet requires two requests to get the css file.
2015-11-02 20:57:49 +02:00
Aleks-Daniel Jakimenko-Aleksejev
c97d6a576f wiki.css: We are no longer using these fonts
There is no need to define fonts that we do not use anyway.
2015-11-02 20:50:52 +02:00
12 changed files with 264 additions and 102 deletions

View File

@@ -321,7 +321,6 @@ div.sister {
float:left;
margin-right:1ex;
padding-right:1ex;
border-right:1px dashed;
}
div.sister p { padding:1ex; margin:0; }
div.sister hr { display:none; }

View File

@@ -47,8 +47,8 @@ textarea, pre, code, tt {
.browse { min-height: 3em; }
.header form, .header p { margin: 0; }
/* hide the buttons but don't use display:none because of
http://stackoverflow.com/questions/5665203/getting-iphone-go-button-to-submit-form */
.header input[type="submit"] { position: absolute; visibility: hidden; }
http://stackoverflow.com/questions/5665203/getting-iphone-go-button-to-submit-form
.header input[type="submit"] { position: absolute; visibility: hidden; } */
.header input { width: 5em; font-size: 80%; }
.footer { clear:both; font-size: 90%; }
.content input { font-size: 80%; line-height: 125%; }
@@ -205,6 +205,7 @@ 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; }
div.rc li strong { font-weight: normal; }
/* Tables */
table.user {

View File

@@ -219,50 +219,3 @@ code {
background: #eee;
white-space: pre-wrap;
}
@font-face {
font-family: 'Gentium Basic';
font-style: normal;
font-weight: 700;
src: local('Gentium Basic Bold'), local('GentiumBasic-Bold'), url(/fonts/GenBasB.woff) format('woff');
}
@font-face {
font-family: 'Gentium Basic';
font-style: italic;
font-weight: 400;
src: local('Gentium Basic Italic'), local('GentiumBasic-Italic'), url(/fonts/GenBasI.woff) format('woff');
}
@font-face {
font-family: 'Gentium Basic';
font-style: italic;
font-weight: 700;
src: local('Gentium Basic Bold Italic'), local('GentiumBasic-BoldItalic'), url(/fonts/GenBasBI.woff) format('woff');
}
@font-face {
font-family: 'Gentium Basic';
font-style: normal;
font-weight: 400;
src: local('Gentium Basic'), local('GentiumBasic'), url(/fonts/GenBasR.woff) format('woff');
}
@font-face {
font-family: 'Gentium Plus';
font-style: normal;
font-weight: 400;
src: local('Gentium Plus'), local('GentiumPlus'), url(/fonts/GentiumPlus-R.woff) format('woff');
}
@font-face {
font-family: 'Gentium Plus';
font-style: italic;
font-weight: 400;
src: local('Gentium Plus Italic'), local('GentiumPlus-Italic'), url(/fonts/GentiumPlus-I.woff) format('woff');
}
@font-face {
font-family: 'Symbola';
src: local('Symbola'), url('/fonts/Symbola.woff') format('woff') url('/fonts/Symbola.ttf') format('truetype');
}

View File

@@ -89,9 +89,9 @@ Ungültige Seite %s (Darf nicht mit .lck enden)
Invalid Page %s
Ungültige Seite %s
There are no comments, yet. Be the first to leave a comment!
Es gibt noch keine Kommentare, sei der Erste der einen hinterlässt!
Welcome!
Willkommen!
This page does not exist, but you can %s.
Diese Seite gibt es nicht, aber du kannst %s.
create it now
@@ -343,9 +343,9 @@ Die Sperre wurde %s gesetzt.
Maybe the user running this script is no longer allowed to remove the lock directory?
Vielleicht darf der user, welcher dieses script ausführt, das Sperr-Verzeichnis nicht löschen?
Sometimes locks are left behind if a job crashes.
Manchmal bleiben Sperren erhalten, wenn ein Prozess abbricht.
After ten minutes, you could try to unlock the wiki.
Nach zehn Minuten kann versucht werden, das Wiki zu entsperren.
This operation may take several seconds...
Das könnte einige Sekunden dauern...
Forced unlock of %s lock.
@@ -435,7 +435,7 @@ Grund unbekannt.
%s pages found.
%s Seiten gefunden.
Preview: %s
Vorschau: %s
Replaced: %s
Ersetzt: %s
Search for: %s
@@ -786,7 +786,7 @@ Kommentar hinzufügen
ordinary changes
normale Änderungen
%s days
%s Tage
################################################################################
# modules/edit-paragraphs.pl
################################################################################
@@ -1398,9 +1398,9 @@ Portrait
# modules/preview.pl
################################################################################
Pages with changed HTML
Seiten mit geändertem HTML
Preview changes in HTML output
Vorschau der Änderungen der HTML-Ausgabe
################################################################################
# modules/private-pages.pl
################################################################################

View File

@@ -691,11 +691,6 @@ Clustermap
Pages without a Cluster
################################################################################
# modules/comment-div-wrapper.pl
################################################################################
Comments:
################################################################################
# modules/commentcount.pl
################################################################################
@@ -703,6 +698,11 @@ Comments on
Comment on
################################################################################
# modules/comment-div-wrapper.pl
################################################################################
Comments:
################################################################################
# modules/compilation.pl
################################################################################
@@ -1239,7 +1239,7 @@ Test / Always enabled / Always disabled
Start
Bisection proccess is already active.
Bisecting proccess is already active.
Stop
@@ -1280,6 +1280,11 @@ You linked more than %s times to the same domain. It would seem that only a spam
Namespaces
################################################################################
# modules/nearlink-create.pl
################################################################################
(create locally)
################################################################################
# modules/near-links.pl
################################################################################
@@ -1299,11 +1304,6 @@ EditNearLinks
The same page on other sites:
################################################################################
# modules/nearlink-create.pl
################################################################################
(create locally)
################################################################################
# modules/no-question-mark.pl
################################################################################
@@ -1662,4 +1662,5 @@ Edit %s.
################################################################################
Tags:
#
END_OF_TRANSLATION

188
scripts/alexine/bot.p6 Executable file
View File

@@ -0,0 +1,188 @@
#!/usr/bin/env perl6
use Net::IRC::Bot;
use Net::IRC::Modules::Autoident;
use Net::IRC::Modules::Tell;
use Net::IRC::CommandHandler;
sub wikiLink($page is copy) {
$page ~~ s:g/\s/_/; # quick and dirty
returnhttps://oddmuse.org/wiki/$page;
}
class Intermap {
has $.intermapLink is rw = https://oddmuse.org/wiki/Local_Intermap?raw=1;
has %!intermap;
method update {
# TODO https breaks HTTP::UserAgent, workaround with curl
my $proc = run(curl, $!intermapLink, :out);
my $text = $proc.out.slurp-rest;
$proc.out.close; # RT #126561
return False unless $proc;
for $text ~~ m:global ^^ \h+ $<name>=\S+ \s+ $<value>=.+? $$ {
%!intermap{~$_<name>} = ~$_<value>; # TODO map!
}
return True;
}
method said ($e) {
self.update if not %!intermap or $e.what ~~ / update intermap /; # lazy init
for $e.what ~~ m:global $<name>=<-[\s :]>+ : $<value>=\S+ { # quick and dirty
next unless %!intermap{.<name>}:exists;
my $link = %!intermap{~.<name>};
my $replacement = $_<value>;
$link ~~ s{ \%s | $ } = $replacement;
$e.msg: $link;
}
}
}
class Pages {
method said ($e) {
for $e.what ~~ m:global [[ $<page>=<-[ \] ]>+ ]] { # quick and dirty
$e.msg: wikiLink ~.<page>;
}
}
}
class Sorry {
has $.answers is rw = « I'm so sorry! Please forgive me!
I should have done better!
I promise that it won't happen again! »;
method said ($e) {
if $e.what ~~ / ^ "{ $e.bot.nick }" [:|,] / {
$e.msg: $!answers.pick;
}
}
}
class RecentChanges {
has $.delay is rw = 30;
has $.url is rw = https://oddmuse.org/wiki?action=rss;all=0;showedit=0;rollback=1;from=;
has $!last = time;
method joined ($e) {
start loop {
sleep $!delay;
self.process: $e;
}
}
method process ($e) {
my $newLast = time;
# TODO https breaks HTTP::UserAgent, workaround with curl
my $proc = run(curl, $!url ~ $!last, :out);
my $xml = $proc.out.slurp-rest;
$proc.out.close; # RT #126561
return False unless $proc;
$!last = $newLast;
use XML;
for from-xml($xml).elements(:TAG<item>, :RECURSE) {
my $title = ~.elements(:TAG<title>, :SINGLE).contents;
my $desc = ~.elements(:TAG<description>, :SINGLE).contents;
my $author = ~.elements(:TAG<dc:contributor>, :SINGLE).contents;
$e.msg:Wiki: [$title] <$author> $desc ({wikiLink $title});
}
return True;
}
}
class RecentCommits {
has $.delay is rw = 30;
has $.url = https://github.com/kensanata/oddmuse.git;
has $.repo = repo;
method joined ($e) {
start {
if $!repo.IO !~~ :e {
fail unless run(git, clone, $!url, $!repo);
}
loop {
sleep $!delay;
self.process: $e;
}
}
}
method process ($e) {
my $proc1 = run(git, --git-dir, $!repo ~ /.git, fetch) ;
return False unless $proc1;
my $proc2 = run(git, --git-dir, $!repo ~ /.git, log,
--pretty=format:Commit: %s (https://github.com/kensanata/oddmuse/commit/%h),
...origin, :out);
$e.msg: $_ for $proc2.out;
$proc2.out.close; # RT #126561
return False unless $proc2;
run(git, --git-dir, $!repo ~ /.git, merge, -q);
return True;
}
}
class Backlog does Net::IRC::CommandHandler {
has $.limit is rw = 60 * 60 * 48;
has $.delay is rw = 30; # seconds before file deletion
has $.path is rw = backlogs/;
has $.link is rw = http://alexine.oddmuse.org/backlogs/; # TODO https
has %.messages = ();
multi method said ($e) {
%!messages{$e.where} = [] unless %!messages{$e.where}:exists;
%!messages{$e.where}.push: { when => time, who => $e.who<nick>, what => $e.what };
self.clean;
}
method clean {
for %!messages.values -> $value { # each channel
for $value.kv -> $index, $elem { # each message
last if time - $elem<when> < $!limit;
LAST { $value.splice(0, $index) } # at least one message will be kept
}
}
}
method backlog ($e, $match) is cmd {
self.clean;
mkdir $!path unless $!path.IO ~~ :d;
my $name = ^2**128 .pick.base(36);
my $fh = open$!path/$name, :w;
$fh.say(<{.<who>}> {.<what>}) for @(%!messages{$e.where});
$fh.close;
$e.msg:$!link$name;
Promise.in($!delay).then: { unlink$!path/$name};
}
method forget ($e, $match) is cmd {
%!messages{$e.where} = [];
$e.msg: OK, we didn't have this conversation.;
}
}
sub MAIN(Str :$nick = alexine, Str :$password is copy = , Str :$channel = #oddmuse) {
$password = prompt Nickserv password: unless $password;
Net::IRC::Bot.new(
nick => $nick,
username => $nick,
realname => $nick,
server => irc.freenode.org,
channels => [ $channel ],
debug => True,
modules => (
Intermap.new(),
Pages.new(),
Sorry.new(),
RecentChanges.new(),
#RecentCommits.new(),
Backlog.new(prefix => .),
Net::IRC::Modules::Tell.new(prefix => .),
Net::IRC::Modules::Autoident.new(password => $password),
),
).run;
}

View File

@@ -21,6 +21,7 @@ TEST_LOG="$WORKING_DIRECTORY/log"
ODDMUSE_TEST_LOCATION="$WORKING_DIRECTORY/oddmuse-for-tests/"
GIT_LOCATION="$WORKING_DIRECTORY/"
LAST_COMMIT_FILE="$WORKING_DIRECTORY/last_commit"
LAST_STATUS_FILE="$WORKING_DIRECTORY/last_status"
FIRST_TESTABLE_COMMIT='1c0801bd6ca23de71c7c360a18a648c2b953f1da'
RESULT_FILE="$WORKING_DIRECTORY/output"
WIKIPUT='../config/oddmuse/scripts/cli/wikiput'
@@ -49,7 +50,9 @@ while :; do
"${git[@]}" reset --hard origin/master # starting our search from the last commit
[[ -f $LAST_COMMIT_FILE ]] || echo "$FIRST_TESTABLE_COMMIT" > "$LAST_COMMIT_FILE"
[[ -f $LAST_STATUS_FILE ]] || echo 0 > "$LAST_STATUS_FILE"
lastCommit=$(< "$LAST_COMMIT_FILE")
lastStatus=$(< "$LAST_STATUS_FILE")
logOutput=$("${git[@]}" log --topo-order --pretty=oneline | grep --before 1 -m 1 "^$lastCommit")
(($(wc -l <<< "$logOutput") < 2)) && exit 0 # No more commits to process, good!
@@ -65,14 +68,16 @@ while :; do
printf "%s\n" "$output" > "$RESULT_FILE"
# echo "Duration: $((duration/60))m$((duration%60))s Status: $status" >> "$RESULT_FILE"
printf "%s\n" "$currentCommit" > "$LAST_COMMIT_FILE"
printf "%s\n" "$status" > "$LAST_STATUS_FILE"
"${gitRepo[@]}" add -- "$(readlink -m -- "$RESULT_FILE")" "$(readlink -m -- "$LAST_COMMIT_FILE")"
"${gitRepo[@]}" add -- "$(readlink -m -- "$RESULT_FILE")" "$(readlink -m -- "$LAST_COMMIT_FILE")" "$(readlink -m -- "$LAST_STATUS_FILE")"
"${gitRepo[@]}" commit -m "Test status at $currentCommit (automated commit)"
"${gitRepo[@]}" push
if (( status == 0 )); then
"$WIKIPUT" -m -u "$USER_NAME" -s 'Tests PASSED' -z 'ham' "$WIKI_LOCATION/$STATUS_PAGE" <<< $'TEST STATUS **OK**\n\n'"Commit:${currentCommit:0:7} see [[$OUT_PAGE|test log]]"
(( lastStatus == 0 )) && minor='-m' || minor='' # we will use unquoted variable on purpose
"$WIKIPUT" $minor -u "$USER_NAME" -s 'Tests PASSED' -z 'ham' "$WIKI_LOCATION/$STATUS_PAGE" <<< $'TEST STATUS **OK**\n\n'"Commit:${currentCommit:0:7} see [[$OUT_PAGE|test log]]"
else
"$WIKIPUT" -u "$USER_NAME" -s 'Tests FAILED' -z 'ham' "$WIKI_LOCATION/$STATUS_PAGE" <<< $'TEST STATUS **FAIL**\n\n'"Commit:${currentCommit:0:7} see [[$OUT_PAGE|test log]]"
fi

View File

@@ -85,7 +85,7 @@ Examples
--------
Journal pages only:
$0 --match '^\d{4}-\d{2}-\d{2}'
$0 --match '^\\d{4}-\\d{2}-\\d{2}'
Skip comment pages:
$0 --match '^(?!Comments_on_)'

View File

@@ -48,7 +48,7 @@ sub random_port {
my $port = random_port();
$ScriptName = "http://localhost:$port";
AppendStringToFile($ConfigFile, "\$ScriptName = $ScriptName;\n");
AppendStringToFile($ConfigFile, "\$ScriptName = '$ScriptName';\n");
add_module('atom.pl');

10
t/css.t
View File

@@ -20,13 +20,13 @@ AppendStringToFile($ConfigFile, "\$StyleSheetPage = 'css';\n");
# Default
xpath_test(get_page('HomePage'),
'//link[@type="text/css"][@rel="stylesheet"][@href="http://www.oddmuse.org/default.css"]');
'//link[@type="text/css"][@rel="stylesheet"][@href="https://oddmuse.org/default.css"]');
# StyleSheetPage
update_page('css', "em { font-weight: bold; }", 'some css', 0, 1);
$page = get_page('HomePage');
negative_xpath_test($page,
'//link[@type="text/css"][@rel="stylesheet"][@href="http://www.oddmuse.org/default.css"]');
'//link[@type="text/css"][@rel="stylesheet"][@href="https://oddmuse.org/default.css"]');
xpath_test($page,
'//link[@type="text/css"][@rel="stylesheet"][@href="http://localhost/wiki.pl?action=browse;id=css;raw=1;mime-type=text/css"]');
@@ -34,7 +34,7 @@ xpath_test($page,
AppendStringToFile($ConfigFile, "\$StyleSheet = 'http://example.org/test.css';\n");
$page = get_page('HomePage');
negative_xpath_test($page,
'//link[@type="text/css"][@rel="stylesheet"][@href="http://www.oddmuse.org/default.css"]',
'//link[@type="text/css"][@rel="stylesheet"][@href="https://oddmuse.org/default.css"]',
'//link[@type="text/css"][@rel="stylesheet"][@href="http://localhost/wiki.pl?action=browse;id=css;raw=1;mime-type=text/css"]');
xpath_test($page,
'//link[@type="text/css"][@rel="stylesheet"][@href="http://example.org/test.css"]');
@@ -43,7 +43,7 @@ xpath_test($page,
AppendStringToFile($ConfigFile, "\$StyleSheet = ['http://example.org/test.css', 'http://example.org/another.css'];\n");
$page = get_page('HomePage');
negative_xpath_test($page,
'//link[@type="text/css"][@rel="stylesheet"][@href="http://www.oddmuse.org/default.css"]',
'//link[@type="text/css"][@rel="stylesheet"][@href="https://oddmuse.org/default.css"]',
'//link[@type="text/css"][@rel="stylesheet"][@href="http://localhost/wiki.pl?action=browse;id=css;raw=1;mime-type=text/css"]');
xpath_test($page,
'//link[@type="text/css"][@rel="stylesheet"][@href="http://example.org/test.css"]');
@@ -53,7 +53,7 @@ xpath_test($page,
# Parameter
$page = get_page('action=browse id=HomePage css=http://example.org/my.css');
negative_xpath_test($page,
'//link[@type="text/css"][@rel="stylesheet"][@href="http://www.oddmuse.org/default.css"]',
'//link[@type="text/css"][@rel="stylesheet"][@href="https://oddmuse.org/default.css"]',
'//link[@type="text/css"][@rel="stylesheet"][@href="http://localhost/wiki.pl?action=browse;id=css;raw=1;mime-type=text/css"]',
'//link[@type="text/css"][@rel="stylesheet"][@href="http://example.org/test.css"]');
xpath_test($page,

View File

@@ -15,7 +15,7 @@
require 't/test.pl';
package OddMuse;
use Test::More tests => 72;
use Test::More tests => 89;
use utf8; # tests contain UTF-8 characters and it matters
add_module('mac.pl');
@@ -116,6 +116,17 @@ xpath_test($page, '//a[@class="more"][@href="http://localhost/wiki.pl?search=Som
$page = get_page('search=Something preview=1 offset=10 num=10 replace=Other pwd=foo');
test_page($page, map { "Page_$_" } ('K' .. 'M'));
# Now do the replacement
$page = get_page('search=Something replace=Other pwd=foo');
test_page($page, 'Replaced: Something &#x2192; Other', '13 pages found',
map { "Page_$_" } ('A' .. 'M'));
# Verify that the change has been made
test_page(get_page('search=Other'), 'Search for: Other', '13 pages found');
# Replace with backreferences, where the replacement pattern is no longer found.
# Take 'fuuz and barz.' and replace ([a-z]+)z with x$1 results in 'xfuu and xbar.'
test_page(get_page('"search=([a-z]%2b)z" replace=x%241 pwd=foo'), '1 pages found');

50
wiki.pl
View File

@@ -101,7 +101,6 @@ our $EditPass //= ''; # Whitespace separated passwords.
our $PassHashFunction //= ''; # Name of the function to create hashes
our $PassSalt //= ''; # Salt will be added to any password before hashing
our $UnicodeIcons = ''; # 1 = Use unicode characters as icons (fallback font is recommended)
our $BannedHosts = 'BannedHosts'; # Page for banned hosts
our $BannedCanRead = 1; # 1 = banned cannot edit, 0 = banned cannot read
our $BannedContent = 'BannedContent'; # Page for banned content (usually for link-ban)
@@ -1171,7 +1170,7 @@ sub GetEditLink { # shortcut
$id = FreeToNormal($id);
my $action = 'action=edit;id=' . UrlEncode($id);
$action .= ';upload=1' if $upload;
return ScriptLink($action, NormalToFree($name), 'edit', undef, ($UnicodeIcons && '✎ ') . T('Click to edit this page'), $accesskey);
return ScriptLink($action, NormalToFree($name), 'edit', undef, T('Click to edit this page'), $accesskey);
}
sub ScriptUrl {
@@ -1675,24 +1674,24 @@ sub RcHeader {
my @menu;
if ($all) {
push(@menu, ScriptLink("$action;days=$days;all=0;showedit=$edits",
($UnicodeIcons && '● ') . T('List latest change per page only')));
T('List latest change per page only')));
} else {
push(@menu, ScriptLink("$action;days=$days;all=1;showedit=$edits",
($UnicodeIcons && '○ ') . T('List all changes')));
T('List all changes')));
if ($rollback) {
push(@menu, ScriptLink("$action;days=$days;all=0;rollback=0;"
. "showedit=$edits", ($UnicodeIcons && '● ') . T('Skip rollbacks')));
. "showedit=$edits", T('Skip rollbacks')));
} else {
push(@menu, ScriptLink("$action;days=$days;all=0;rollback=1;"
. "showedit=$edits", ($UnicodeIcons && '○ ') . T('Include rollbacks')));
. "showedit=$edits", T('Include rollbacks')));
}
}
if ($edits) {
push(@menu, ScriptLink("$action;days=$days;all=$all;showedit=0",
($UnicodeIcons && '● ') . T('List only major changes')));
T('List only major changes')));
} else {
push(@menu, ScriptLink("$action;days=$days;all=$all;showedit=1",
($UnicodeIcons && '○ ') . T('Include minor changes')));
T('Include minor changes')));
}
return $html .
$q->p(join(' | ', (map { ScriptLink("$action;days=$_;all=$all;showedit=$edits", $_); } @RcDays)),
@@ -2120,10 +2119,10 @@ sub DoRollback {
sub DoAdminPage {
my ($id, @rest) = @_;
my @menu = ();
push(@menu, ScriptLink('action=index', ($UnicodeIcons && '🗐 ') . T('Index of all pages'), 'index')) if $Action{index};
push(@menu, ScriptLink('action=version', ($UnicodeIcons && '❓ ') . T('Wiki Version'), 'version')) if $Action{version};
push(@menu, ScriptLink('action=password', ($UnicodeIcons && '🛂 ') . T('Password'), 'password')) if $Action{password};
push(@menu, ScriptLink('action=maintain', ($UnicodeIcons && '♻ ') . T('Run maintenance'), 'maintain')) if $Action{maintain};
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=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) {
@@ -2378,7 +2377,7 @@ sub GetCss { # prevent javascript injection
if ($IndexHash{$StyleSheetPage} and not @css) {
push (@css, "$ScriptName?action=browse;id=" . UrlEncode($StyleSheetPage) . ";raw=1;mime-type=text/css")
}
push (@css, 'http://www.oddmuse.org/default.css') unless @css;
push (@css, 'https://oddmuse.org/default.css') unless @css;
return join('', map { qq(<link type="text/css" rel="stylesheet" href="$_" />) } @css);
}
@@ -2455,20 +2454,20 @@ sub GetFooterLinks {
if ($id =~ /$CommentsPattern/) {
push(@elements, GetPageLink($1, undef, 'original', T('a'))) if $1;
} else {
push(@elements, GetPageLink(($UnicodeIcons && '💬 ') . $CommentsPrefix . $id, undef, 'comment', T('c')));
push(@elements, GetPageLink($CommentsPrefix . $id, undef, 'comment', T('c')));
}
}
if (UserCanEdit($id, 0)) {
if ($rev) { # showing old revision
push(@elements, GetOldPageLink('edit', $id, $rev, ($UnicodeIcons && '⎇ ') . Ts('Edit revision %s of this page', $rev)));
push(@elements, GetOldPageLink('edit', $id, $rev, Ts('Edit revision %s of this page', $rev)));
} else { # showing current revision
push(@elements, GetEditLink($id, ($UnicodeIcons && '✎ ') . T('Edit this page'), undef, T('e')));
push(@elements, GetEditLink($id, T('Edit this page'), undef, T('e')));
}
} else { # no permission or generated page
push(@elements, ScriptLink('action=password', ($UnicodeIcons && '🔒 ') . T('This page is read-only'), 'password'));
push(@elements, ScriptLink('action=password', T('This page is read-only'), 'password'));
}
}
push(@elements, GetHistoryLink($id, ($UnicodeIcons && '⍿ ') . T('View other revisions'))) if $Action{history} and $id and $rev ne 'history';
push(@elements, GetHistoryLink($id, T('View other revisions'))) if $Action{history} and $id and $rev ne 'history';
push(@elements, GetPageLink($id, T('View current revision')),
GetRCLink($id, T('View all changes'))) if $Action{history} and $rev ne '';
if ($Action{contrib} and $id and $rev eq 'history') {
@@ -2477,7 +2476,7 @@ sub GetFooterLinks {
if ($Action{admin} and GetParam('action', '') ne 'admin') {
my $action = 'action=admin';
$action .= ';id=' . UrlEncode($id) if $id;
push(@elements, ScriptLink($action, ($UnicodeIcons && '⚙ ') . T('Administration'), 'admin'));
push(@elements, ScriptLink($action, T('Administration'), 'admin'));
}
return @elements ? $q->div({-class=>'edit bar'}, @elements) : '';
}
@@ -3410,6 +3409,11 @@ sub DoSearch {
if (GetParam('preview', '')) { # Preview button was used
print GetHeader('', Ts('Preview: %s', $string . " &#x2192; " . $replacement));
print $q->start_div({-class=>'content replacement'});
print GetFormStart(undef, 'post', 'replace');
print GetHiddenValue('search', $string);
print GetHiddenValue('replace', $replacement);
print GetHiddenValue('delete', GetParam('delete', 0));
print $q->submit(-value=>T('Go!')) . $q->end_form();
@results = ReplaceAndDiff($re, UnquoteHtml($replacement));
} else {
print GetHeader('', Ts('Replaced: %s', $string . " &#x2192; " . $replacement));
@@ -3581,7 +3585,7 @@ sub SearchExtract {
sub ReplaceAndSave {
my ($from, $to) = @_;
RequestLockOrError(); # fatal
my @result = Replace($from, $to, sub {
my @result = Replace($from, $to, 1, sub {
my ($id, $new) = @_;
Save($id, $new, $from . ' → ' . $to, 1, ($Page{host} ne $q->remote_addr()));
});
@@ -3591,7 +3595,7 @@ sub ReplaceAndSave {
sub ReplaceAndDiff {
my ($from, $to) = @_;
my @found = Replace($from, $to, sub {
my @found = Replace($from, $to, 0, sub {
my ($id, $new) = @_;
print $q->h2(GetPageLink($id)), $q->div({-class=>'diff'}, ImproveDiff(DoDiff($Page{text}, $new)));
});
@@ -3607,7 +3611,7 @@ sub ReplaceAndDiff {
}
sub Replace {
my ($from, $to, $func) = @_; # $func takes $id and $new text
my ($from, $to, $all, $func) = @_; # $func takes $id and $new text
my $lang = GetParam('lang', '');
my $num = GetParam('num', 10);
my $offset = GetParam('offset', 0);
@@ -3627,7 +3631,7 @@ sub Replace {
};
if (s/$from/$replacement->()/egi) { # allows use of backreferences
push (@result, $id);
$func->($id, $_) if @result > $offset and @result <= $offset + $num;
$func->($id, $_) if $all or @result > $offset and @result <= $offset + $num;
}
}
return @result;