2007-10-02 12:32:49 +00:00
|
|
|
|
# Copyright (C) 2004, 2005, 2007 Alex Schroeder <alex@emacswiki.org>
|
2004-07-01 17:48:28 +00:00
|
|
|
|
#
|
|
|
|
|
|
# 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
|
2007-10-02 12:32:49 +00:00
|
|
|
|
# the Free Software Foundation; either version 3 of the License, or
|
2004-07-01 17:48:28 +00:00
|
|
|
|
# (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
|
2007-10-02 12:32:49 +00:00
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2004-07-01 17:48:28 +00:00
|
|
|
|
|
2015-03-27 03:01:01 +02:00
|
|
|
|
use strict;
|
2015-08-18 10:48:03 +02:00
|
|
|
|
use v5.10;
|
2015-03-27 03:01:01 +02:00
|
|
|
|
|
2014-08-21 22:23:23 +02:00
|
|
|
|
AddModuleDescription('localnames.pl', 'Local Names Extension');
|
2004-07-01 17:48:28 +00:00
|
|
|
|
|
2015-04-10 13:31:28 +03:00
|
|
|
|
our ($q, $Now, %Page, %Action, $OpenPageName, $ScriptName, $DataDir, $RssDir, @MyRules, @MyMaintenance, @MyInitVariables, $FullUrlPattern, $FreeLinkPattern, $CommentsPrefix, $UseCache, @UserGotoBarPages, %AdminPages, @MyAdminCode, @MyFooters, $UsePathInfo);
|
2015-03-27 03:01:01 +02:00
|
|
|
|
|
2015-07-28 23:02:23 +02:00
|
|
|
|
=encoding utf8
|
|
|
|
|
|
|
2007-10-02 12:32:49 +00:00
|
|
|
|
=head1 Local Names
|
|
|
|
|
|
|
|
|
|
|
|
This module allows you to centrally define redirections. Thus you can
|
|
|
|
|
|
define that whenever somebody links to the page Foo the link will
|
|
|
|
|
|
point to http://example.com/. These redirects are defined on special
|
|
|
|
|
|
page called LocalNames. You can change the name of that page by
|
|
|
|
|
|
setting C<$LocalNamesPage>.
|
|
|
|
|
|
|
|
|
|
|
|
You can also link to external lists of such redirections, as long as
|
|
|
|
|
|
they use the namespace description format developed by Lion Kimbro.
|
|
|
|
|
|
Basically you can "import" redirections. These external lists are
|
|
|
|
|
|
cached in a directory called C<ln> inside the data directory. You can
|
|
|
|
|
|
change the directory by setting C<$LnDir>.
|
|
|
|
|
|
|
|
|
|
|
|
=cut
|
|
|
|
|
|
|
2015-04-10 13:31:28 +03:00
|
|
|
|
our ($LocalNamesPage, %LocalNames, $LocalNamesCollect,
|
|
|
|
|
|
$LocalNamesCollectMaxWords, $LnDir, $LnCacheHours,
|
2011-05-11 12:52:54 +00:00
|
|
|
|
%WantedPages);
|
2004-07-01 17:48:28 +00:00
|
|
|
|
|
|
|
|
|
|
$LocalNamesPage = 'LocalNames';
|
2005-12-20 16:01:43 +00:00
|
|
|
|
$LocalNamesCollect = 0;
|
2005-12-23 13:52:38 +00:00
|
|
|
|
$LocalNamesCollectMaxWords = 2;
|
2006-07-02 11:05:33 +00:00
|
|
|
|
# LN caching is written very similar to the RSS file caching
|
|
|
|
|
|
$LnDir = "$DataDir/ln";
|
|
|
|
|
|
$LnCacheHours = 12;
|
|
|
|
|
|
|
|
|
|
|
|
sub GetLnFile {
|
|
|
|
|
|
return $LnDir . '/' . UrlEncode(shift);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2007-10-02 12:32:49 +00:00
|
|
|
|
=head2 Maintenance
|
|
|
|
|
|
|
|
|
|
|
|
Whenever maintenance runs, all the cached external lists of
|
|
|
|
|
|
redirections are deleted whenever they are older than twelve hours.
|
|
|
|
|
|
You can change this expiry time by setting C<$LnCacheHours>.
|
|
|
|
|
|
|
|
|
|
|
|
=cut
|
|
|
|
|
|
|
2013-08-21 10:19:45 +02:00
|
|
|
|
push (@MyMaintenance, \&LnMaintenance);
|
2006-07-02 11:05:33 +00:00
|
|
|
|
|
|
|
|
|
|
sub LnMaintenance {
|
2016-06-22 15:37:04 +02:00
|
|
|
|
if (opendir(DIR, encode_utf8($RssDir))) { # cleanup if they should expire anyway
|
2016-06-19 15:55:03 +02:00
|
|
|
|
foreach my $file (readdir(DIR)) {
|
2016-06-23 00:34:56 +02:00
|
|
|
|
Unlink("$RssDir/$file") if $Now - Modified($file) > $LnCacheHours * 3600;
|
2006-07-02 11:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
closedir DIR;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2007-10-02 12:32:49 +00:00
|
|
|
|
=head2 Defining Local Names
|
|
|
|
|
|
|
|
|
|
|
|
Local Names are defined on the LocalNames page.
|
|
|
|
|
|
|
|
|
|
|
|
If you create ordinary named external links such as
|
|
|
|
|
|
C<[http://ln.taoriver.net/ Local Names Website]> on the LocalNames
|
|
|
|
|
|
page, you will have defined a new Local Name. If you write C<[[Local
|
|
|
|
|
|
Names Website]]> elsewhere on the site (and the page does not exist),
|
|
|
|
|
|
that link will point to the website you specified.
|
|
|
|
|
|
|
|
|
|
|
|
You can link from the LocalNames page to existing namespace
|
|
|
|
|
|
descriptions. These other namespace descriptions must use the
|
|
|
|
|
|
namespace description format developed by Lion Kimbro. If you write
|
|
|
|
|
|
C<[[ln:URL]]> or C<[[ln:URL text]]>, this will import all the Local
|
|
|
|
|
|
Names defined there into your wiki.
|
|
|
|
|
|
|
|
|
|
|
|
Example: C<[[ln:http://ln.taoriver.net/localnames.txt Lion's Example
|
|
|
|
|
|
Localnames List]]>.
|
|
|
|
|
|
|
|
|
|
|
|
Currently only LN records with absolute URLs are parsed correctly. All
|
|
|
|
|
|
other record types are ignored.
|
|
|
|
|
|
|
|
|
|
|
|
If you want to learn more about local names, see
|
|
|
|
|
|
L<http://ln.taoriver.net/>.
|
|
|
|
|
|
|
|
|
|
|
|
=cut
|
|
|
|
|
|
|
2006-07-02 11:05:33 +00:00
|
|
|
|
# render [[ln:url]] as something clickable
|
|
|
|
|
|
push(@MyRules, \&LocalNamesRule);
|
|
|
|
|
|
|
|
|
|
|
|
sub LocalNamesRule {
|
2015-08-23 21:22:12 +03:00
|
|
|
|
if (m/\G\[\[ln:$FullUrlPattern\s*([^\]]*)\]\]/cg) {
|
2006-07-02 11:05:33 +00:00
|
|
|
|
# [[ln:url text]], [[ln:url]]
|
|
|
|
|
|
return $q->a({-class=>'url outside ln', -href=>$1}, $2||$1);
|
|
|
|
|
|
}
|
2015-02-27 12:10:18 +02:00
|
|
|
|
return;
|
2006-07-02 11:05:33 +00:00
|
|
|
|
}
|
2004-07-01 17:48:28 +00:00
|
|
|
|
|
2007-10-02 12:32:49 +00:00
|
|
|
|
=head2 Initialization
|
2005-01-04 10:15:02 +00:00
|
|
|
|
|
2007-10-02 12:32:49 +00:00
|
|
|
|
The LocalNames page is added to C<%AdminPages> so that the
|
|
|
|
|
|
Administration page will list a link to it. The LocalNames page will
|
|
|
|
|
|
be read and parsed for every request. The result is that the
|
|
|
|
|
|
C<%LocalNames> hash has pagenames as keys and URLs to redirect to as
|
|
|
|
|
|
values.
|
2005-10-28 08:07:39 +00:00
|
|
|
|
|
2007-10-02 12:32:49 +00:00
|
|
|
|
If the LocalNames page refers to external lists of redirections, these
|
|
|
|
|
|
will be read from the cache or fetched anew if older than twelve
|
|
|
|
|
|
hours. If you use the cache=0 parameter in an URL or set C<$UseCache>
|
|
|
|
|
|
to zero or less, Oddmuse will B<fetch the lists of redirections every
|
|
|
|
|
|
single time>. Using the cache=0 parameter is a way to force Oddmuse to
|
|
|
|
|
|
expire the cache. Setting C<$UseCache> to 0 should not be used on a
|
|
|
|
|
|
live site.
|
|
|
|
|
|
|
|
|
|
|
|
Definitions of redirections on the LocalNames take precedence over
|
|
|
|
|
|
redirections defined on remote sites. Earlier lists of redirections
|
|
|
|
|
|
take precedence over later lists.
|
|
|
|
|
|
|
|
|
|
|
|
We ignore the spec at L<http://ln.taoriver.net/spec-1.2.html#Syntax>
|
|
|
|
|
|
when considering what names we allow, since Oddmuse will parse them as
|
|
|
|
|
|
regular links anyway.
|
2005-10-28 08:07:39 +00:00
|
|
|
|
|
2007-10-02 12:32:49 +00:00
|
|
|
|
=cut
|
|
|
|
|
|
|
|
|
|
|
|
push(@MyInitVariables, \&LocalNamesInit);
|
2004-07-01 17:48:28 +00:00
|
|
|
|
|
2005-10-21 22:54:33 +00:00
|
|
|
|
sub LocalNamesInit {
|
2011-05-11 12:52:54 +00:00
|
|
|
|
%WantedPages = (); # list of missing pages used during this request
|
2005-10-21 22:54:33 +00:00
|
|
|
|
%LocalNames = ();
|
|
|
|
|
|
$LocalNamesPage = FreeToNormal($LocalNamesPage); # spaces to underscores
|
2006-07-15 23:13:14 +00:00
|
|
|
|
$AdminPages{$LocalNamesPage} = 1;
|
2004-07-03 01:26:47 +00:00
|
|
|
|
my $data = GetPageContent($LocalNamesPage);
|
2015-08-23 21:22:12 +03:00
|
|
|
|
while ($data =~ m/\[$FullUrlPattern\s+([^\]]+?)\]/g) {
|
2005-12-20 16:01:43 +00:00
|
|
|
|
my ($page, $url) = ($2, $1);
|
|
|
|
|
|
my $id = FreeToNormal($page);
|
|
|
|
|
|
$LocalNames{$id} = $url;
|
2004-07-03 01:26:47 +00:00
|
|
|
|
}
|
2006-07-02 11:05:33 +00:00
|
|
|
|
# Now read data from ln links, checking cache if possible. For all
|
|
|
|
|
|
# URLs not in the cache or with invalid cache, fetch the file again,
|
|
|
|
|
|
# and save it in the cache.
|
2015-08-23 21:22:12 +03:00
|
|
|
|
my @ln = $data =~ m/\[\[ln:$FullUrlPattern[^\]]*?\]\]/g;
|
2006-07-02 11:05:33 +00:00
|
|
|
|
my %todo = map {$_, GetLnFile($_)} @ln;
|
|
|
|
|
|
my %data = ();
|
|
|
|
|
|
if (GetParam('cache', $UseCache) > 0) {
|
|
|
|
|
|
foreach my $uri (keys %todo) { # read cached rss files if possible
|
2016-06-15 23:21:07 +02:00
|
|
|
|
if ($Now - Modified($todo{$uri}) < $LnCacheHours * 3600) {
|
2006-07-02 11:05:33 +00:00
|
|
|
|
$data{$uri} = ReadFile($todo{$uri});
|
|
|
|
|
|
delete($todo{$uri}); # no need to fetch them below
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
my @need_cache = keys %todo;
|
|
|
|
|
|
if (keys %todo > 1) { # try parallel access if available
|
|
|
|
|
|
eval { # see code example in LWP::Parallel, not LWP::Parllel::UserAgent (no callbacks here)
|
|
|
|
|
|
require LWP::Parallel::UserAgent;
|
|
|
|
|
|
my $pua = LWP::Parallel::UserAgent->new();
|
|
|
|
|
|
foreach my $uri (keys %todo) {
|
|
|
|
|
|
if (my $res = $pua->register(HTTP::Request->new('GET', $uri))) {
|
|
|
|
|
|
warn $res->error_as_HTML;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
%todo = (); # because the uris in the response may have changed due to redirects
|
|
|
|
|
|
my $entries = $pua->wait();
|
|
|
|
|
|
foreach (keys %$entries) {
|
|
|
|
|
|
my $uri = $entries->{$_}->request->uri;
|
|
|
|
|
|
$data{$uri} = $entries->{$_}->response->content;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach my $uri (keys %todo) { # default operation: synchronous fetching
|
|
|
|
|
|
$data{$uri} = GetRaw($uri);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (GetParam('cache', $UseCache) > 0) {
|
|
|
|
|
|
CreateDir($LnDir);
|
|
|
|
|
|
foreach my $uri (@need_cache) {
|
|
|
|
|
|
WriteStringToFile(GetLnFile($uri), $data{$uri});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
# go through the urls in the right order, this time
|
|
|
|
|
|
foreach my $ln (@ln) {
|
2006-07-02 12:23:32 +00:00
|
|
|
|
my ($previous_type, $previous_url);
|
2006-07-02 12:11:52 +00:00
|
|
|
|
foreach my $line (split(/[\r\n]+/, $data{$ln})) {
|
2006-07-02 18:49:28 +00:00
|
|
|
|
if ($line =~ /^LN\s+"$FreeLinkPattern"\s+(?:"$FullUrlPattern"|\.)$/
|
2006-07-02 12:32:19 +00:00
|
|
|
|
or $previous_type eq 'LN'
|
2006-07-02 18:49:28 +00:00
|
|
|
|
and $line =~ /^\.\s+"$FreeLinkPattern"\s+(?:"$FullUrlPattern"|\.)$/) {
|
2006-07-02 11:05:33 +00:00
|
|
|
|
my ($name, $url) = ($1, $2);
|
2006-07-02 12:32:19 +00:00
|
|
|
|
$url = $previous_url if not $url and $previous_url;
|
2006-07-02 12:17:12 +00:00
|
|
|
|
$previous_url = $url;
|
2006-07-02 12:23:32 +00:00
|
|
|
|
$previous_type = 'LN';
|
2006-07-02 11:05:33 +00:00
|
|
|
|
my $id = FreeToNormal($name);
|
|
|
|
|
|
# Only store this, if not already stored!
|
|
|
|
|
|
if (not $LocalNames{$id}) {
|
|
|
|
|
|
$LocalNames{$id} = $url;
|
|
|
|
|
|
}
|
2006-07-02 12:23:32 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$previous_type = undef;
|
2006-07-02 11:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
# elsif ($line =~ /^NS "(.*)" "$FullUrlPattern"$/g) {
|
|
|
|
|
|
# }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2004-07-01 17:48:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2007-10-02 12:32:49 +00:00
|
|
|
|
=head2 Name Resolution
|
2004-07-01 17:48:28 +00:00
|
|
|
|
|
2007-10-02 12:32:49 +00:00
|
|
|
|
We want Near Links only to have an effect for pages that do not exist
|
|
|
|
|
|
locally. It should not take precedence! Thus, we hook into
|
|
|
|
|
|
C<ResolveId>; this function returns a list of four elements: CSS
|
|
|
|
|
|
class, resolved id, title (eg. for popups), and a boolean saying
|
|
|
|
|
|
whether the page exists or not. If the second element is empty, then
|
|
|
|
|
|
no page exists and we check C<%LocalNames> for a match. If there is a
|
|
|
|
|
|
match, we return the URL using the CSS class "near" and the title
|
|
|
|
|
|
"LocalNames". The CSS class is the same that is used for Near Links
|
|
|
|
|
|
because the effect is so similar.
|
2004-07-01 17:48:28 +00:00
|
|
|
|
|
2007-10-02 12:36:02 +00:00
|
|
|
|
Note: Existing local pages take precedence over local names, but local
|
|
|
|
|
|
names take precedence over Near Links.
|
|
|
|
|
|
|
2011-05-11 12:52:54 +00:00
|
|
|
|
We also keep track of wanted pages (links to missing pages) so that we
|
|
|
|
|
|
can printe a list of definition links at the bottom using the Define
|
|
|
|
|
|
Action (see below).
|
|
|
|
|
|
|
2007-10-02 12:32:49 +00:00
|
|
|
|
=cut
|
|
|
|
|
|
|
2015-04-11 23:41:33 +03:00
|
|
|
|
*OldLocalNamesResolveId = \&ResolveId;
|
|
|
|
|
|
*ResolveId = \&NewLocalNamesResolveId;
|
2007-10-02 12:32:49 +00:00
|
|
|
|
|
|
|
|
|
|
sub NewLocalNamesResolveId {
|
|
|
|
|
|
my $id = shift;
|
2011-05-11 12:52:54 +00:00
|
|
|
|
my ($class, $resolved, @rest) = OldLocalNamesResolveId($id, @_);
|
|
|
|
|
|
if ((not $resolved or $class eq 'near') and $LocalNames{$id}) {
|
2007-10-02 12:32:49 +00:00
|
|
|
|
return ('near', $LocalNames{$id}, $LocalNamesPage);
|
2004-07-03 01:26:47 +00:00
|
|
|
|
} else {
|
2011-05-11 13:48:08 +00:00
|
|
|
|
$WantedPages{$id} = 1 if not $resolved; # this is provisional!
|
2011-05-11 12:52:54 +00:00
|
|
|
|
return ($class, $resolved, @rest);
|
2004-07-01 17:48:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2005-12-20 16:01:43 +00:00
|
|
|
|
|
2007-10-02 12:32:49 +00:00
|
|
|
|
=head2 Automatically Defining Local Names
|
|
|
|
|
|
|
|
|
|
|
|
It is possible to have Oddmuse automatically define local names as you
|
|
|
|
|
|
edit pages. In order to enable this, set C<$LocalNamesCollect> to 1.
|
|
|
|
|
|
Once you this, every time you save a page with a named external link
|
|
|
|
|
|
such as C<[http://www.emacswiki.org/alex/ Alex]>, this will add or
|
|
|
|
|
|
update the corresponding entry on the LocalNames page.
|
|
|
|
|
|
|
|
|
|
|
|
In order to reduce the number of entries thus collected, only external
|
|
|
|
|
|
links with a name consisting of one or two words are used. You can
|
|
|
|
|
|
change this word limit by setting C<$LocalNamesCollectMaxWords>.
|
|
|
|
|
|
|
|
|
|
|
|
The default limit of two words assumes that you might want to make
|
|
|
|
|
|
C<Alex> a link, or C<Alex Schroeder>, but not C<the example on Alex’s
|
|
|
|
|
|
blog> (five “words”, since the code looks at whitespace only).
|
|
|
|
|
|
|
|
|
|
|
|
=cut
|
|
|
|
|
|
|
2015-04-11 23:41:33 +03:00
|
|
|
|
*LocalNamesOldSave = \&Save;
|
|
|
|
|
|
*Save = \&LocalNamesNewSave;
|
2005-12-20 16:01:43 +00:00
|
|
|
|
|
|
|
|
|
|
sub LocalNamesNewSave {
|
|
|
|
|
|
LocalNamesOldSave(@_);
|
|
|
|
|
|
my ($currentid, $text) = @_;
|
|
|
|
|
|
# avoid recursion
|
|
|
|
|
|
return if $currentid eq $LocalNamesPage or not $LocalNamesCollect;
|
|
|
|
|
|
my $currentname = $currentid;
|
|
|
|
|
|
$currentname =~ s/_/ /g;
|
2009-03-21 23:22:39 +00:00
|
|
|
|
local ($OpenPageName, %Page);
|
2005-12-20 16:01:43 +00:00
|
|
|
|
OpenPage($LocalNamesPage);
|
|
|
|
|
|
my $localnames = $Page{text};
|
2006-03-16 23:36:43 +00:00
|
|
|
|
my %map = ();
|
2005-12-23 13:52:38 +00:00
|
|
|
|
while ($text =~ /\[$FullUrlPattern\s+(([^ \]]+?\s*){1,$LocalNamesCollectMaxWords})\]/g) {
|
2005-12-20 16:01:43 +00:00
|
|
|
|
my ($page, $url) = ($2, $1);
|
|
|
|
|
|
my $id = FreeToNormal($page);
|
2006-03-16 23:36:43 +00:00
|
|
|
|
$map{$id} = () unless defined $map{$id};
|
|
|
|
|
|
$map{$id}{$url} = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
my %collection = ();
|
|
|
|
|
|
foreach my $id (keys %map) {
|
2005-12-20 16:01:43 +00:00
|
|
|
|
# canonical form with trimmed spaces and no underlines
|
2006-03-16 23:36:43 +00:00
|
|
|
|
my $page = $id;
|
2005-12-20 16:01:43 +00:00
|
|
|
|
$page =~ s/_/ /g;
|
2006-03-16 23:36:43 +00:00
|
|
|
|
# skip if the mapping from id to url already defined matches at
|
|
|
|
|
|
# least one of the definitions on the current page.
|
|
|
|
|
|
next if $map{$id}{$LocalNames{$id}};
|
|
|
|
|
|
$collection{$page} = 1;
|
|
|
|
|
|
# pick a random url from the list
|
|
|
|
|
|
my @urls = keys %{$map{$id}};
|
|
|
|
|
|
my $url = $urls[0];
|
2005-12-20 16:01:43 +00:00
|
|
|
|
# if a different mapping exists already; change the old mapping to the new one
|
|
|
|
|
|
# if the change fails (eg. the page name is not in canonical form), don't skip!
|
|
|
|
|
|
next if $LocalNames{$id}
|
|
|
|
|
|
and $localnames =~ s/\[$LocalNames{$id}\s+$page\]/[$url $page]/g;
|
|
|
|
|
|
# add a new entry at the end
|
|
|
|
|
|
$localnames .= "\n\n* [$url $page]"
|
|
|
|
|
|
. Ts(" -- defined on %s", "[[$currentname]]");
|
2006-03-16 23:36:43 +00:00
|
|
|
|
$LocalNames{$id} = $url; # prevent multiple additions
|
2005-12-20 16:01:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
# minor change
|
2006-03-18 19:52:53 +00:00
|
|
|
|
my @collection = sort keys %collection;
|
2005-12-20 16:01:43 +00:00
|
|
|
|
Save($LocalNamesPage, $localnames,
|
2005-12-22 10:52:16 +00:00
|
|
|
|
Tss("Local names defined on %1: %2", $currentname,
|
|
|
|
|
|
length(@collection > 1)
|
|
|
|
|
|
? join(', and ',
|
|
|
|
|
|
join(', ', @collection[0 .. $#collection-1]),
|
2015-04-28 00:03:11 +03:00
|
|
|
|
$collection[-1])
|
2005-12-22 10:52:16 +00:00
|
|
|
|
: @collection), 1)
|
2005-12-20 16:01:43 +00:00
|
|
|
|
unless $localnames eq $Page{text};
|
|
|
|
|
|
}
|
2006-07-02 23:17:40 +00:00
|
|
|
|
|
2007-10-02 12:32:49 +00:00
|
|
|
|
=head2 Local Names Format
|
|
|
|
|
|
|
|
|
|
|
|
The Ln Action lists all the local pages in the local names format
|
|
|
|
|
|
defined in the specification. Example URL:
|
|
|
|
|
|
C<http://localhost/cgi-bin/wiki?action=ln>.
|
|
|
|
|
|
|
|
|
|
|
|
If you want to learn more about local names and the format used, see
|
|
|
|
|
|
L<http://ln.taoriver.net/>.
|
|
|
|
|
|
|
|
|
|
|
|
=cut
|
|
|
|
|
|
|
2006-07-02 23:17:40 +00:00
|
|
|
|
$Action{ln} = \&DoLocalNames;
|
|
|
|
|
|
|
|
|
|
|
|
sub DoLocalNames {
|
|
|
|
|
|
print GetHttpHeader('text/plain');
|
|
|
|
|
|
print "X VERSION 1.2\n";
|
|
|
|
|
|
print "# Local Pages\n";
|
|
|
|
|
|
foreach my $id (AllPagesList()) {
|
|
|
|
|
|
my $title = $id;
|
|
|
|
|
|
$title =~ s/_/ /g;
|
|
|
|
|
|
my $url = $ScriptName . ($UsePathInfo ? '/' : '?') . $id;
|
|
|
|
|
|
print qq{LN "$title" "$url"\n};
|
|
|
|
|
|
}
|
|
|
|
|
|
if (GetParam('expand', 0)) {
|
|
|
|
|
|
print "# Local names defined on $LocalNamesPage:\n";
|
|
|
|
|
|
my $data = GetPageContent($LocalNamesPage);
|
2015-08-23 21:22:12 +03:00
|
|
|
|
while ($data =~ m/\[$FullUrlPattern\s+([^\]]+?)\]/g) {
|
2006-07-02 23:17:40 +00:00
|
|
|
|
my ($title, $url) = ($2, $1);
|
|
|
|
|
|
my $id = FreeToNormal($title);
|
|
|
|
|
|
print qq{LN "$title" "$url"\n};
|
|
|
|
|
|
}
|
|
|
|
|
|
print "# Namespace delegations defined on $LocalNamesPage:\n";
|
2015-08-23 21:22:12 +03:00
|
|
|
|
while ($data =~ m/\[\[ln:$FullUrlPattern([^\]]*)?\]\]/g) {
|
2006-07-02 23:17:40 +00:00
|
|
|
|
my ($title, $url) = ($2, $1);
|
|
|
|
|
|
my $id = FreeToNormal($title);
|
|
|
|
|
|
print qq{NS "$title" "$url"\n};
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
print "# Local names defined on $LocalNamesPage:\n";
|
|
|
|
|
|
foreach my $id (keys %LocalNames) {
|
|
|
|
|
|
my $title = $id;
|
|
|
|
|
|
$title =~ s/_/ /g;
|
|
|
|
|
|
print qq{LN "$title" "$LocalNames{$id}"\n};
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2011-05-11 12:10:11 +00:00
|
|
|
|
|
|
|
|
|
|
=head2 Define Action
|
|
|
|
|
|
|
|
|
|
|
|
The Define Action allows you to interactively add local names using a
|
|
|
|
|
|
form. Example URL: C<http://localhost/cgi-bin/wiki?action=define>.
|
|
|
|
|
|
|
|
|
|
|
|
You can also provide the C<name> and C<link> parameters yourself if
|
|
|
|
|
|
you want to use this action from a script.
|
|
|
|
|
|
|
2011-05-11 12:52:54 +00:00
|
|
|
|
As wanted pages (links to missing pages) come up, you will get links
|
|
|
|
|
|
to appropriate define actions in your footer.
|
|
|
|
|
|
|
2011-05-11 12:10:11 +00:00
|
|
|
|
=cut
|
|
|
|
|
|
|
|
|
|
|
|
$Action{define} = \&DoDefine;
|
|
|
|
|
|
|
|
|
|
|
|
sub DoDefine {
|
|
|
|
|
|
if (GetParam('link', '') and GetParam('name', '')) {
|
|
|
|
|
|
SetParam('title', $LocalNamesPage);
|
|
|
|
|
|
SetParam('text', GetPageContent($LocalNamesPage) . "\n* ["
|
|
|
|
|
|
. GetParam('link', '') . ' ' . GetParam('name', '')
|
|
|
|
|
|
. "]\n");
|
|
|
|
|
|
SetParam('summary', 'Defined ' . GetParam('name'));
|
|
|
|
|
|
return DoPost($LocalNamesPage);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
print GetHeader('', T('Define')),
|
|
|
|
|
|
$q->start_div({-class=>'content define'}),
|
|
|
|
|
|
GetFormStart(undef, 'get', 'def');
|
|
|
|
|
|
my $go = T('Go!');
|
2015-10-15 14:55:54 +02:00
|
|
|
|
print $q->p($q->label({-for=>"defined"}, T('Name:') . ' '),
|
2011-05-11 12:52:54 +00:00
|
|
|
|
$q->textfield(-name=>"name", -id=>"defined",
|
|
|
|
|
|
-tabindex=>"1", -size=>20));
|
2015-10-15 14:55:54 +02:00
|
|
|
|
print $q->p($q->label({-for=>"definition"}, T('URL:') . ' '),
|
2011-05-11 12:52:54 +00:00
|
|
|
|
$q->textfield(-name=>"link", -id=>"definition",
|
|
|
|
|
|
-tabindex=>"2", -size=>20));
|
|
|
|
|
|
print $q->p($q->submit(-label=>$go, -tabindex=>"3"),
|
2011-05-11 12:10:11 +00:00
|
|
|
|
GetHiddenValue('action', 'define'),
|
|
|
|
|
|
GetHiddenValue('recent_edit', 'on'));
|
|
|
|
|
|
print $q->end_form, $q->end_div();
|
|
|
|
|
|
PrintFooter();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
push(@MyAdminCode, sub {
|
|
|
|
|
|
my ($id, $menuref, $restref) = @_;
|
|
|
|
|
|
push(@$menuref, ScriptLink('action=define', T('Define Local Names'),
|
|
|
|
|
|
'define'));
|
|
|
|
|
|
});
|
2011-05-11 12:52:54 +00:00
|
|
|
|
|
|
|
|
|
|
# link to define action for non-existing pages
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
push(@MyFooters, \&GetWantedPages);
|
|
|
|
|
|
|
|
|
|
|
|
sub GetWantedPages {
|
|
|
|
|
|
# skip admin pages
|
|
|
|
|
|
foreach my $id (@UserGotoBarPages, keys %AdminPages) {
|
|
|
|
|
|
delete $WantedPages{$id};
|
|
|
|
|
|
}
|
|
|
|
|
|
# skip comment pages
|
|
|
|
|
|
if ($CommentsPrefix) {
|
|
|
|
|
|
foreach my $id (keys %WantedPages) {
|
2015-08-23 21:22:12 +03:00
|
|
|
|
delete $WantedPages{$id} if $id =~ /^$CommentsPrefix/; # TODO use $CommentsPattern ?
|
2011-05-11 12:52:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2011-05-11 13:48:08 +00:00
|
|
|
|
# now something more complicated: if near-links.pl was loaded, then
|
|
|
|
|
|
# %WantedPages may contain pages that will in fact resolve. That's
|
|
|
|
|
|
# why we try to resolve all the wanted ids again. And since
|
|
|
|
|
|
# resolving ids will do stuff to %WantedPages, we need to make a
|
|
|
|
|
|
# copy of the ids we're looking at.
|
|
|
|
|
|
my @wanted;
|
|
|
|
|
|
foreach my $id (keys %WantedPages) {
|
|
|
|
|
|
my ($class, $resolved) = ResolveId($id);
|
|
|
|
|
|
push(@wanted, $id) unless $resolved;
|
|
|
|
|
|
}
|
2011-05-11 12:52:54 +00:00
|
|
|
|
# if any wanted pages remain, print them
|
2011-05-11 13:48:08 +00:00
|
|
|
|
if (@wanted) {
|
2011-05-11 12:52:54 +00:00
|
|
|
|
return $q->div({-class=>'definition'},
|
2015-10-15 19:10:59 +02:00
|
|
|
|
$q->p(T('Define external redirect:'), ' ',
|
2011-05-11 13:19:47 +00:00
|
|
|
|
map { my $page = NormalToFree($_);
|
|
|
|
|
|
ScriptLink('action=define;name='
|
|
|
|
|
|
. UrlEncode($page),
|
|
|
|
|
|
$page,
|
2011-05-11 12:52:54 +00:00
|
|
|
|
'define');
|
2011-05-11 13:48:08 +00:00
|
|
|
|
} @wanted));
|
2011-05-11 12:52:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
return '';
|
|
|
|
|
|
}
|