Compare commits

...

594 Commits
2.2 ... 2.3.4

Author SHA1 Message Date
Alex Schroeder
b1d39e3195 tables-long.pl: fix tracking of dirty blocks 2015-02-05 09:21:04 +01:00
Alex Schroeder
48a00a6ff6 rss.t: testing multiple feeds on a page 2015-02-05 08:30:12 +01:00
Alex Schroeder
a3ee3c60ce Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2015-02-04 22:30:29 +01:00
Matt Adams
d69063599e logout.pl: link back to the last page after logout
Users who currently use the back button to return to the previous page
after logging in or logging out need to select it more than once and are
often return to a cached version of the page they were previously
viewing instead of one that reflects an updated cookie state. The only
other option currently available to the user is to re-navigate to the
page which they wish to view (likely the previous page).

This change improves the usability of the logout functions by providing
a link to return to the previous pages after logging in or logging out.
Previous pages are returned without cache.
2015-02-04 19:09:44 +01:00
Alex Schroeder
0146225c4f Fix whitespace in message to match up with last commit. 2015-02-04 19:06:29 +01:00
Matt Adams
50fca72f82 Password action (login) has link back to last page. 2015-02-04 19:04:34 +01:00
Alex Schroeder
1a4e6aa527 Submit empty comment no longer wipes comment page. 2015-02-03 10:50:49 +01:00
Alex Schroeder
cdf8b561a6 Fix summary for uploaded files.
The summary for uploaded files had nested p elements; this was
removed. When no summary is provided, we now remove the "#FILE..."
stuff. In this case, no summary is better.
2015-02-01 00:26:43 +01:00
Alex Jakimenko
905d8c930e Fixed recently introduced XSS vulnerability 2015-01-31 20:50:26 +02:00
Matt Adams
f64c6d470b logout.pl: Provide login link if not logged in. 2015-01-31 16:13:01 +01:00
Matt Adams
0657d84769 Show latest summary when displaying uploaded files 2015-01-31 12:57:52 +01:00
Matt Adams
0181d8b944 hiddenpages.pl: stop breaking search & recent changes 2015-01-30 16:42:25 +01:00
Alex Schroeder
fae5f1e345 replacements: fixed recently introduced bug
The recently introduced code to prevent Perl injection broke repeated
replacements with backreferences.
2015-01-25 09:06:22 +01:00
Alex Schroeder
81b179acac search: fixed handling of missing grep
When closing the pipe to grep, check the status returned by the child
process in $? and return all pages if there was an error (which means
that grep did not filter any pages).
2015-01-25 08:40:07 +01:00
Alex Jakimenko
bc810ee0ce Fixed vulnerability (ugly, but works) 2015-01-25 08:09:07 +02:00
Alex Jakimenko
3a4236bc45 div-foo.pl: syntax for setting the "title" attribute; /x in regexes
The syntax is <class1 class2?My title stuff> ... </>
2015-01-25 06:03:20 +02:00
Alex Jakimenko
8642ae63a2 module-updater.pl: unnecessary () in sub declaration 2015-01-25 05:59:52 +02:00
Alex Jakimenko
3c5373f76b image.pl: It is already quoted, no need to quote it again. 2015-01-25 05:53:40 +02:00
Alex Schroeder
58e297b092 long-tables.pl: $rownum replaces $first and $odd
Updated tests, too.
2015-01-19 20:03:46 +01:00
Matt Adams
cd4f6dc64c tables-long.pl: add a class for even and odd rows 2015-01-19 19:45:14 +01:00
Alex Schroeder
5a112b64b3 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2015-01-19 10:06:19 +01:00
Alex Schroeder
a7b0c661c8 big-brother.pl: Remove password parameters.
Make sure admins and editors don't accidentally leave their passwords on
the Recent Visitors page.
2015-01-19 10:02:34 +01:00
Alex Schroeder
b2f9a0044b ParseData: Reverting to the code from 2006.
As explained on my blog
<https://alexschroeder.ch/wiki/2015-01-13_Handwritten_Optimization>,
the current implementation is "suddenly" very slow. This is specially
noticeable when loading large pages. Without quite understanding how
this is possible, I'm reverting to the old implementation.
2015-01-13 15:32:37 +01:00
Alex Schroeder
d0cdd451e4 oddmuse-2014.css: Add Symbola for smileys. 2015-01-13 13:11:26 +01:00
Alex Schroeder
86334d6532 Summary: tags.pl delete unnecessary calls to write hash
When running TagFind and TagCloud, writing the tag file is not
necessary. This is the result of a search and replace operation that
assumed every DB_File untie is equivalent to a write operation. This
is not true.
2015-01-09 17:09:56 +01:00
Alex Schroeder
733752727d tags.pl: Fixed error reporting for reindex action. 2015-01-09 17:00:43 +01:00
Alex Schroeder
6635803807 tags.pl: Use real lists instead of strings
The strings used to be concatenated elements using $FS as the
separator. Now they are references to lists.
2015-01-08 01:04:46 +01:00
Alex Schroeder
7f3488baaa tags.pl: Fixed tests, fixed bugs. 2015-01-08 00:37:37 +01:00
Alex Schroeder
dcc318f34e tags.pl: Switch from DB_File to Storable
The drawback will be that the entire tag database including all the
backlinks will be stored in a hash. On my wiki with 5799 pages the
tag.db file is just 333K so it’s not too bad.
2015-01-08 00:03:29 +01:00
Alex Schroeder
17edc1c523 namespaces.pl: add match to @NamespaceParameters
When using $MatchingPages = 1, the following URL would is a
possiblity:
https://campaignwiki.org/wiki/Adventures?search=&match=dung&dosearch=Go%21

In this situation, "Adventures" needs to be the namespace. The
'search' parameter is ignored and the script needs to react to
'match'.
2015-01-07 15:16:09 +01:00
Alex Schroeder
85912f211b add-link.pl: use https 2015-01-05 15:13:04 +01:00
Alex Schroeder
52d7239400 Merge branch 'master' of ssh://git.sv.gnu.org/srv/git/oddmuse 2015-01-05 14:57:18 +01:00
Alex Schroeder
9c691e5b9b add-link.pl: How to add entries to wikis.
These two wikis work as public bookmarking sites. This script allows
easy addition of links.

https://campaignwiki.org/wiki/LinksToWisdom/
https://campaignwiki.org/wiki/Adventures/
2015-01-05 14:57:05 +01:00
Alex Schroeder
0e45ea2e99 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2015-01-04 11:19:43 +01:00
Alex Schroeder
8773242dba Add support for zh-cn and zh-tw 2015-01-04 11:18:05 +01:00
Alex Schroeder
267cd53adb Update CSS files for emacswiki.org 2014-12-18 14:16:27 +01:00
Alex Schroeder
ce82a328b6 edit-paragraphs: fix $around parameter
In bullet lists, the $around parameter would overshoot. The link would
say around=20, for example, when in fact the correct value would be
around=18. It would add the "* " of the next list item, apparently. The
edit link would still look good because the test we're using is
"$EditParagraphs[0]->[1] <= $pos" -- but if we then don't set "$pos =
$EditParagraphs[0]->[1]" it won't help as we'll get a "Could not
identify the paragraph you were editing" error as soon as we try to edit
with around=20 instead of around=18.
2014-12-10 09:05:14 +01:00
Alex Schroeder
b925805800 edit-paragraphs.t: more tests
Unsuccessfully trying to find a bug by adding more tests.
But then again, more tests is good, so they'll stay.
2014-12-10 08:19:59 +01:00
Alex Schroeder
c8c50b4e81 Merge commit '8ec456e'
Conflicts:
	modules/upgrade.pl
2014-12-09 12:22:22 +01:00
Alex Schroeder
4a976278d5 alex-2014.css: better printing 2014-12-09 12:16:43 +01:00
Alex Schroeder
1255fe8168 Updated tests for ad/spans-and-divs branch. 2014-12-09 09:16:12 +01:00
Alex Schroeder
081e8243d7 Merge branch 'ad/spans-and-divs' 2014-12-09 03:02:34 +01:00
Alex Schroeder
a20fc60617 Merge branch 'as/search-form-rewrites'
Conflicts:
	css/alex-2014.css
2014-12-09 02:59:32 +01:00
Alex Schroeder
770de2986a edit-paragraphs.pl: handle page names containing & 2014-12-09 02:56:23 +01:00
Alex Schroeder
0551018de1 light.css: iPhone changes 2014-12-04 16:19:15 +01:00
Alex Schroeder
aa77f2ce2f Simplify DoSurgeProtection 2014-12-03 08:41:37 +01:00
Alex Schroeder
471994f7b1 Merge branch 'as/search-form-rewrites' of git.sv.gnu.org:/srv/git/oddmuse into as/search-form-rewrites
Conflicts:
	modules/edit-paragraphs.pl
2014-12-03 08:37:39 +01:00
Alex Jakimenko
9d2c0216f6 top gotobar and search form is now wrapped into 'menu' div (might break existing stylesheets) 2014-12-02 21:34:04 +02:00
Alex Jakimenko
82d888f0ea divs instead of <br> tags (might break existing stylesheets) 2014-12-02 21:06:53 +02:00
Alex Schroeder
ccaf283204 edit-paragraphs.pl: handle </p>\s*</form> 2014-11-30 01:22:45 +01:00
Alex Schroeder
3fb5319562 Merge branch 'as/search-form-rewrites' of ssh://git.sv.gnu.org/srv/git/oddmuse into as/search-form-rewrites 2014-11-26 12:24:18 +01:00
Alex Schroeder
76c92f027c edit-paragraphs.pl: handle empty rows 2014-11-26 12:08:38 +01:00
Alex Schroeder
d828454511 Merge branch 'as/search-form-rewrites' of git.sv.gnu.org:/srv/git/oddmuse into as/search-form-rewrites 2014-11-25 23:41:08 +01:00
Alex Schroeder
34c6e93780 Fake action for search and match.
A test for the action in GetRobots makes sure that the robots meta
element gets a NOINDEX if the action is not "browse". Since the
default is "browse", this means we need to set an action for
search=foo and match=foo.
2014-11-25 19:34:38 +01:00
Alex Schroeder
0a6f473098 alex-2014.css: don't hide all the input fields 2014-11-25 17:01:31 +01:00
Alex Schroeder
4d67f9bfd2 oddmuse-2014.css: new CSS file 2014-11-25 09:09:31 +01:00
Alex Schroeder
6e80adc293 alex-2014.css: iPhone adaptation
Depending on the number of visible fields, the form requires a submit button.
Instead of using display:none, use visibility:hidden;position:absolute in order
to "fix" this for the iPhone.

See:
http://stackoverflow.com/questions/5665203/getting-iphone-go-button-to-submit-form
2014-11-25 08:21:49 +01:00
Alex Schroeder
dc3fb65317 light.css: adapting to search form 2014-11-24 22:55:44 +01:00
Alex Schroeder
6a652de193 Put matching pages into the same form as search.
This works if we later handle a stand-alone match parameter like we handle the search parameter.
We just fake an action.
2014-11-24 22:32:11 +01:00
Alex Schroeder
4747235fe7 light.css: Adaptations to the new layout of search. 2014-11-24 18:47:11 +01:00
Alex Schroeder
0ecbeeb2c4 alex-2014.css: Symbola for textareas 2014-11-24 10:16:38 +01:00
Alex Jakimenko
65378d91cb div-foo.pl: more restrictive regexes, added $DivFooPrefix 2014-11-23 23:04:07 +02:00
Alex Schroeder
cb6a6bf4a6 mail.pl: adapt to changes in the footer 2014-11-23 21:43:35 +01:00
Alex Schroeder
db67c34203 Font paths fixed. Search form changes. 2014-11-23 21:23:10 +01:00
Alex Schroeder
ccf8fe2314 Search form: fix HTML issues 2014-11-23 21:22:29 +01:00
Alex Schroeder
e336086cf0 Reorganizing the Search Form
Introducing  (0, 1, 2); supporting  (2);
adding .
2014-11-23 19:37:27 +01:00
Alex Schroeder
5315b3f6ad toc-js.pl: Fix typo 2014-11-19 13:05:11 +01:00
Alex Schroeder
e31abd57bc toc-js.pl: Provide my own endsWith implementation. 2014-11-19 13:03:54 +01:00
Alex Schroeder
5bf60bb5d8 oddmuse-2014.css: new 2014-11-17 14:23:10 +01:00
Alex Schroeder
ad672aff28 alex-2014.css: Font locations, iPhone optimisation. 2014-11-17 10:51:07 +01:00
Alex Schroeder
e49af47d30 alex-2014.css: keep search forms together 2014-11-15 08:55:10 +01:00
Alex Schroeder
ecbe6a859a Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-11-14 22:55:05 +01:00
Alex Schroeder
413228c56c Emacs interface: fixed vc-diff, history is back
The history command was interesting because it limits the display to
those revisions that are actually available for diff and rollback.
Eventually this might form the basis of a better interface.

The vc-diff code also needed to be fixed.
2014-11-14 22:51:46 +01:00
Alex Schroeder
a905de7ab5 alex-2014.css: get rid of line-height everywhere 2014-11-14 12:26:13 +01:00
Alex Schroeder
a09409f375 alex-2014.css: use Noticia Text as font 2014-11-13 13:08:30 +01:00
Alex Schroeder
764c0ffcf1 alex-2014.css: no bold, use local fonts 2014-11-13 11:37:47 +01:00
Alex Schroeder
5962745937 Fixed comment handling.
A simple $comment eq '' resulted in previews if page edits to no
longer work. The correct test is defined $comment and $comment eq ''.
2014-11-11 11:17:29 +01:00
Alex Schroeder
d380062ec6 Merge branch 'master' of ssh://git.sv.gnu.org/srv/git/oddmuse 2014-11-11 11:11:46 +01:00
Alex Schroeder
cd8066233c Unlock Wiki menu lists locks.
If no locks are set, the menu is not shown.
If the menu is shown, the known locks are listed.
2014-11-11 11:04:58 +01:00
Alex Schroeder
6f04d2044f edit-paragraphs: get rid of fuzzy matching
Too many bugs!
2014-11-10 23:17:00 +01:00
Alex Schroeder
f41ded592b Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-11-10 22:11:55 +01:00
Alex Schroeder
8a2c9eca9c edit-paragraphs: fix HTML quoting issues 2014-11-10 22:10:51 +01:00
Alex Schroeder
d712a17f82 toc-js.pl: remove multiple pencils
The existence of multiple pencils appears to be a bug in edit-paragraphs.
2014-11-10 15:39:51 +01:00
Alex Schroeder
504190b752 Merge branch 'master' of ssh://git.sv.gnu.org/srv/git/oddmuse 2014-11-10 15:37:50 +01:00
Alex Schroeder
56e515a791 toc-js.pl: remove pencil icon
This icon is added by edit-paragraphs.pl and it looks ugly.
2014-11-10 15:37:37 +01:00
Alex Schroeder
36feb62052 oddmuse-curl: provide oddmuse-curl
It used to provide oddmuse, and vc-oddmuse used to require oddmuse, but
that doesn't load oddmuse-curl.el.
2014-11-10 13:12:51 +01:00
Alex Schroeder
239f15cdbc Simplified handling of $NewComment
A long time ago, $NewComment was the default text for the comment form,
ie. aftertext. That's why the code still had some comparisons of
aftertext with $NewComment. Now that $NewComment is a label in the
comment form and no longer the content of the text area, these tests can
be removed.
2014-11-10 09:48:12 +01:00
Alex Schroeder
f39cfd3235 edit-paragraphs.pl: handle trailing newlines
This used to generate an extra entry for @EditParagraphs which in turn
prevented the page from ending with an edit link if it ended with
multiple newlines.

Also made $EditParagraphPencil settable in the config file.
2014-11-10 09:45:59 +01:00
Alex Schroeder
329699a6aa Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-11-09 17:56:45 +01:00
Alex Schroeder
28965bdaa6 edit-paragraphs.t: added test cases by Alex Daniel 2014-11-09 17:55:43 +01:00
Alex Schroeder
ed42d2dad5 oddmuse_stats: fixed handling of non-ASCII names 2014-11-09 17:05:02 +01:00
Alex Schroeder
45b21cbdb8 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-11-09 13:11:32 +01:00
Alex Schroeder
b540093c2c edit-paragraphs: handle pre, hr. 2014-11-09 13:09:44 +01:00
Alex Schroeder
d164d47e24 oddmuse-stats: a munin plugin 2014-11-09 12:29:28 +01:00
Alex Schroeder
a56b92ecb3 edit-paragraphs: fix HTML escaping 2014-11-08 21:15:15 +01:00
Alex Schroeder
114d914754 edit-paragraphs: pass around parameter to the form 2014-11-08 18:33:52 +01:00
Alex Schroeder
875051ea84 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse
Conflicts:
	t/edit-paragraphs.t
2014-11-08 18:02:01 +01:00
Alex Schroeder
003357acad edit-paragraphs: handle multiple paragraphs 2014-11-08 18:00:16 +01:00
Alex Schroeder
e1c77c4ba6 edit-paragraphs: handle multiple paragraphs 2014-11-08 17:59:44 +01:00
Alex Schroeder
88475c3e41 edit-paragraphs: fiddled with unit tests
Trying to find a constellation to reproduce missing edit links.
Adding support for editing table rows.
2014-11-08 13:37:26 +01:00
Alex Schroeder
e80f05301d edit-paragraphs: added unit test, fixed table bug
After a table, we'd get a lone link in a separate paragraph, just like
headers.
2014-11-07 23:04:12 +01:00
Alex Schroeder
a624e78975 edit-paragraphs: added unit tests, fixed table bug
Before a table, we'd get a lone link.
2014-11-07 22:47:02 +01:00
Alex Schroeder
8cd869f0f9 alex-2012.css: simplication of a.pencil stuff 2014-11-07 09:56:44 +01:00
Alex Schroeder
b09b3f8f8e light.css: new CSS file used by campaignwiki.org 2014-11-07 09:56:21 +01:00
Alex Schroeder
b9043ffd98 alex-2012.css: new stuff.
* a.pencil things for edit-paragraph.pl
* pre with word wrap
* limiting images to 100% width for the phone
2014-11-07 09:27:11 +01:00
Alex Schroeder
54d3dc400a edit-paragraph.js: new
This hides and shows the pencils at the end of each paragraph.
2014-11-06 21:48:08 +01:00
Alex Schroeder
3962068385 edit-paragraphs.pl: improve caching
Hook into PrintWikiToHTML instead of PrintPageContent in order to
avoid adding an edit link after every page link (as these are the
dirty blocks that get printed from the cache).
2014-11-06 16:01:01 +01:00
Alex Schroeder
a0b74ac3c6 edit-paragraph.pl: fixing stuff that didn't work 2014-11-06 15:38:21 +01:00
Alex Schroeder
870d75ac64 edit-paragraphs.pl: hack $Fragment
In order to get the edit button into the headings, we hack it into
$Fragment -- the current, clean HTML block being assembled by
ApplyRules.
2014-11-06 15:00:46 +01:00
Alex Schroeder
42d8260ce4 edit-paragraphs.pl: remove \r
Multiline paragraphs were not replaced correctly because of extra \r
in line endings.
2014-11-06 14:40:23 +01:00
Alex Schroeder
bfda4abe54 New module. 2014-11-06 13:43:20 +01:00
Alex Schroeder
4b0d411564 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse
Conflicts:
	wiki.pl
2014-11-01 01:03:16 +01:00
Alex Schroeder
6790de2d6a Yet another attempt at fixing encoding issues.
To facilitate future debugging, STDERR now also gets the UTF-8 layer.

Apparently CGI does not decode UTF-8 encoded URL parameters. Handle this
case in GetParam.

PageHtml can be called when STDOUT already has the UTF-8 layer. It needs
to be able to handle both cases. That's why we call binmode without any
layers and then we call binmode with the UTF-8 layer again. Now it will
work for RSS files as well.

Unrelated fix: In order to force a decent Etag header even if no index
file exists (and thus $LastUpdate is undef), we use $Now as an
alternative.
2014-11-01 00:52:55 +01:00
Alex Schroeder
2784628544 PageHtml no longer uses utf8 layer
binmode adding utf8 layer to STDOUT resulted in double encoded pages
included via PageHtml. On my homepage I was appending the comments to
every page using the following code:

    my $target = $CommentsPrefix . $id;
    my $page = '';
    $page = PageHtml($target) if $IndexHash{$target};
    print $q->div({-class=>'comment'},
                  $q->h2(T('Comments')),
                  $page);
2014-10-31 23:50:28 +01:00
Alex Schroeder
dd8c687b2b Caching: Fixed tests.
There is no problem generating an Etag header even if a Last Modified
header is provided.
2014-10-31 23:49:41 +01:00
Alex Jakimenko
9f4ceb2d72 module-updater.pl: No need to return when calling OrError subs 2014-10-31 18:48:48 +02:00
Alex Jakimenko
0f8a4fa1df module-updater.pl: Fixed cache problems 2014-10-31 18:48:06 +02:00
Alex Jakimenko
3b16b58880 module-bisect.pl: Solved cache problems, added 'Back' button from 'Stop' page, all strings are now translatable, some refactoring. 2014-10-31 18:41:08 +02:00
Alex Jakimenko
192a902932 Typos and language 2014-10-31 15:41:00 +02:00
Alex Schroeder
aedf77cff8 wiki.pl: Fix caching.
Previously, if calling GetHeader with 'nocache', this would get passed
on to GetHttpHeader as $ts. The code would then produce an etag header
with a value of 'nocache'. This is now fixed. A long comment now
explains how it is supposed to work to reduce confusion in the future.
2014-10-31 09:27:27 +01:00
Alex Schroeder
728547f309 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-10-31 09:10:08 +01:00
Alex Schroeder
33f5484441 oddmuse-curl.el: oddmuse-search, oddmuse-match
Both may use a prefix argument to search a different wiki.
2014-10-31 09:09:52 +01:00
Alex Schroeder
a225486709 vc-oddmuse.el: vc-oddmuse-diff, vc-oddmuse-checkin
These simply did not work.
2014-10-31 09:08:16 +01:00
Alex Jakimenko
3f7f9ec1eb module-bisect.pl: Indicate progress by using > signs 2014-10-31 04:45:45 +02:00
Alex Jakimenko
174aac5570 module-bisect.pl: Do binary search on your modules by disabling/enabling them 2014-10-31 04:09:33 +02:00
Alex Jakimenko
954232f7c8 module-updater.pl: Do not update modules immediately, just show diffs and ask the user whether he wants to apply those changes. 2014-10-29 23:40:09 +02:00
Alex Jakimenko
067658fd10 comment-div-wrapper.pl: Now using $q-> functions instead of printing html manually 2014-10-26 00:54:45 +03:00
Alex Jakimenko
b2b2b0f6cc comment-div-wrapper.pl: Use 'class' instead of 'id' (otherwise it creates multiple elements with the same id in journals) 2014-10-26 00:29:35 +03:00
Alex Jakimenko
408d169729 comment-div-wrapper.pl: indentation 2014-10-26 00:28:32 +03:00
Alex Schroeder
0eddbd5806 oddmuse-2013.css: white-space and word-wrap 2014-10-24 15:50:42 +02:00
Alex Schroeder
210a28afd4 oddmuse-2013.css: small changes 2014-10-24 15:50:31 +02:00
Alex Schroeder
94a16bd463 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-10-24 09:47:29 +02:00
Alex Schroeder
4005e246f7 oddmuse-curl.el: Emacs 24.4 compatibility
shell-command-on-region apparently no longer returns an error number.

Also, use quotes for oddmuse-get-command.
2014-10-24 09:46:51 +02:00
Alex Jakimenko
6b3cd0437f module-updater.pl: GetRaw() instead of wget, cgi functions instead of printing tags 2014-10-22 03:00:32 +03:00
Alex Jakimenko
c961748b49 image.pl: Commentable images (create divs with text above images) 2014-10-21 17:26:31 +03:00
Alex Jakimenko
7327eb8e0c div-foo.pl: Support for spans, paragraph problem solved 2014-10-21 16:27:14 +03:00
Alex Schroeder
1b0d595945 Oddmuse mode for Emacs: Fix diff support
C-x v = calls diff and it didn't work at all; now it works again but
something about the revisions still isn't right.
2014-10-16 23:29:37 +02:00
Alex Schroeder
b7e2a04bb4 search.t: test fix for encoding error
On my website, I noticed that searching for matching pages with a
string containing a non-ascii character worked, where as doing a
normal search resulted in an encoding error. The difference was this:

  # fix match parameter
  my $match = GetParam('match', '');
  SetParam('match', FreeToNormal($match)) if $match;

This may be necessary to remove underscores, but it should not be
necessary to fix encoding errors.
2014-10-10 18:15:54 +02:00
Alex Schroeder
848eb65ad0 use CGI qw/-utf8/
This option should allow automatic encoding and decoding of
parameters. This saves a few lines and solves an encoding error:
previously, searching for a text containing non-ASCII characters would
result in double-encoded text fields.
2014-10-10 17:15:28 +02:00
Alex Schroeder
7ae98f4ed9 $q->endform to $q->end_form
When updating to CGI 4.06, it turns out that $q->endform
is no longer defined.
2014-10-10 16:43:01 +02:00
Alex Jakimenko
dc792691d4 Fail less dramatically if h1 appears. 2014-10-02 16:29:45 +03:00
Alex Jakimenko
0a57a8e89b toc.pl: Treat h2 as the first header when Creole Extension is active. 2014-10-02 16:23:00 +03:00
Alex Jakimenko
f75d415322 Div Foo Extension 2014-09-29 03:46:02 +03:00
Gauthier Vandemoortele
1654562236 clustermap.pl: fixed regression (subrotine name was changed)
This module used a function called ‘DoRc’ that disappeared from the main oddmuse script since the 1.837 version. It was apparently replaced by ‘PrintRcHtml’.
2014-09-26 23:12:23 +03:00
Alex Schroeder
ba0535f39d Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-09-24 16:51:30 +02:00
Alex Schroeder
e5b069f70b upgrade.t: ensure modules directory exists
When calling clean_pages on OSX, the mac.pl module is installed via
add_module, which in turn calls mkdir. On other systems, however,
installing the old namespace module will not work since the module
directory will not exist. This change ensures that mkdir is called
before symlinking.
2014-09-24 16:49:29 +02:00
Alex Schroeder
d34b9f669b upgrade.t: ensure modules directory exists
When creating a symlink on HFS+, the directory doesn't need to exist,
apparently. On ext4, it needs to exist. Make the test more robust by
calling mkdir.
2014-09-24 16:42:46 +02:00
Alex Schroeder
ae2061fcaf referrer-tracking.t: skip if questionasker is installed 2014-09-24 16:27:21 +02:00
Alex Schroeder
65475cf2e8 git.t: make test more robust
Different git versions use different strings to report issues and the
tests don't use --porcelain. Made them a little more robust.
2014-09-24 16:17:25 +02:00
Alex Schroeder
ce2e63be6b Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-09-23 22:19:51 +02:00
Alex Schroeder
007ce8db86 cookie.t: no longer hardcode the wiki name
Changed the tests to no longer assume the default value for
$CookieName. This is important when running the tests on a system
where Apache starts a number of wikis for various virtual hosts and
one of them will end up as the host to use for http://localhost/. That
wiki might very well have a cookie name set.
2014-09-23 22:17:47 +02:00
IngoBelka
5997c3ea02 creole.pl: title-tag for images
This enables tooltips for images in FireFox and possibly in other browsers too
2014-09-13 14:55:38 +03:00
Alex Schroeder
6895428844 UserCanEditOrDie text preferred
It turns out that one of the tests in lock.t relied on the exact wording
of the error message. I decided to use the same wording for all
instances: "Editing not allowed: %s is read-only" and no longer using
"Editing not allowed for %s".
2014-09-12 15:30:20 +02:00
Alex Schroeder
2bc2d1f927 New convenience function UserCanEditOrDie
Closes bug #41625 "ban-quick-editors.pl can hide the error message".
DoPost now uses the same code as DoEdit and thus it will display the
error message, which solves the issue for ban-quick-editors.pl. Added a
test to demonstrate it.
2014-09-12 15:20:06 +02:00
Alex Schroeder
873ce10ced permanent-anchors.pl: report page deletion status
Make sure the status is returned if page deletion fails.
2014-09-12 11:50:51 +02:00
Alex Schroeder
3855c83a7e maintain.t: Verify that maintenance deletes pages 2014-09-12 11:45:24 +02:00
Alex Schroeder
281736a082 Merge: use [[foo bar]] and [[foo_bar]]
I find that removing " space" and "_underscore" made it easier for me to
visually compare the XPath expressions. I also wanted to keep the
[[foo bar|text]] test (and keep the XPath expression as similar as possible).
2014-09-11 22:08:50 +02:00
Alex Schroeder
63d8e24c2f creole.t: test for new free link rule
Make sure that [[foo bar]] turns to [[foo_bar?]] if foo_bar does not
exist, and [[foo bar|text]] turns to [[foo_bar?|text]].
2014-09-11 21:57:27 +02:00
Alex Jakimenko
c66f1a6f8e We have chosen a wrong way to compare $text with $id. It should be better now.
This also fixes recent test added to creole.t
2014-09-11 16:47:18 +03:00
Alex Jakimenko
6418cab98c creole.t: creole extension has its own link rules, so we have to test spaces in [[links]] 2014-09-11 16:43:52 +03:00
Alex Jakimenko
040d51bc93 default-links.t: test both underscores and spaces in [[links]] 2014-09-11 16:41:22 +03:00
Alex Schroeder
41c3245a51 default-links.t: test for new free link rule
Make sure that [[foo_bar]] turns to [[foo_bar?]] if foo_bar does not
exist.
2014-09-10 23:13:45 +02:00
Alex Schroeder
ffc2a0b12f Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-09-10 22:59:36 +02:00
Alex Schroeder
90c632f4ab Avoid Save button for comments after rollback
If you clicked on the Save button after rolling pack a comment page, the
content of the comment page would be deleted.
2014-09-10 22:56:54 +02:00
Alex Jakimenko
9e8def306a Fixed free links to nonexisting pages (now [[foo bar]] results in [[foo_bar?]] instead of [[foo_bar?|foo bar]]) 2014-09-03 15:25:13 +03:00
Alex Jakimenko
f4e551111a Executable flag is only useful when shebang is specified 2014-09-03 14:23:20 +03:00
Alex Jakimenko
1ead545561 Fix gravatar tests (https links from f7b99d4 commit) 2014-09-03 14:06:38 +03:00
Alex Schroeder
f5fc46821f emoji.pl: use \s+:3 2014-08-27 08:22:04 +02:00
Alex Schroeder
ce9f8d9b74 emoji.pl: require whitespace before :3 2014-08-27 08:19:03 +02:00
Alex Jakimenko
1104ecf72f emoji.pl: :3 smiley fixed
Previously it was matching dates like 12:31
2014-08-27 06:32:55 +03:00
Alex Schroeder
13fc4cc0a4 emoji.pl: fixed rule order 2014-08-26 22:39:39 +02:00
Alex Schroeder
31f7b330c5 emoji.pl: added more 2014-08-26 22:34:30 +02:00
Alex Schroeder
ad3909888b emoji.pl: added more 2014-08-26 22:24:08 +02:00
Alex Schroeder
f7b99d44fd gravatar.pl: use https 2014-08-25 20:29:25 +02:00
Alex Schroeder
2cf943d178 Makefile: more fixing for prepare target
The prepare target didn't handle wiki.pl itself correctly. This has been
fixed. The command to add the git tag was changed from sed to perl, like
for the other targets. As emoji.pl and smiles.pl refer to permanent
anchors, the addition of the anchor parameter to AddModuleDescription
was obviously misguided and I reverted it.
2014-08-24 22:20:50 +02:00
Alex Schroeder
b2b1c16247 markup.pl: link English documentation 2014-08-24 21:31:00 +02:00
Alex Schroeder
f91041b677 Handle AddModuleDescription for translations
The Makefile didn't add tag information for translation files when
running 'make prepare'. This has been fixed. As we cannot have a slash
in the file name, as slashes get escaped in UrlEncode, a new parameter
was added to AddModuleDescription and the Makefile will now set this
parameter for translation files such that the source link will point to
the correct directory ("translations/").
2014-08-24 21:25:38 +02:00
Alex Schroeder
30b0faa70e ban-contributors.t: fixed test
The test no longer refers to hostname but to IP number.
2014-08-24 13:05:03 +02:00
Alex Schroeder
174c4f6642 oddtrans: add fake AddModuleDescription
Add a fake AddModuleDescription such that the new translation files with
the new module description call don't fail on "do".

Also use :encoding(utf8) on opening the file as suggested by Ingo Belka
on the wiki instead of calling utf8::decode on every line.
2014-08-24 12:37:48 +02:00
Alex Schroeder
9ba5b119f8 Fix module description to handle version tag.
This makes sure that "make prepare" works once again by allowing an
optional argument to AddModuleDescription with the tag.
AddModuleDescription now also takes an optional anchor which is used by
emoji.pl and smiles.pl.

This commit also updates all the translation files and makes sure that
they all use AddModuleDescription.
2014-08-24 12:31:15 +02:00
Alex Schroeder
b8ce7f07df diff3 output decoded as UTF-8
Without this decoding, calling diff3 leads to UTF-8 corruption.
2014-08-24 09:01:58 +02:00
Alex Schroeder
c9a9db28a6 german-utf8.pl: updated 2014-08-24 08:46:48 +02:00
Alex Schroeder
b21dc2db01 Get rid of "Updates in the last 1 day"
If it's one day, write "Updates in the last day" instead.
2014-08-24 08:46:03 +02:00
Alex Schroeder
0f61a795ee Modules no longer refer to hostname banning
Hostnames are no longer tracked and therefore log messages such as
"hostname or IP number matched" no longer make sense.
2014-08-24 08:45:14 +02:00
Ingo Belka
ed30eeffb0 oddtrans: Keep translation headers 2014-08-24 08:44:31 +02:00
Alex Jakimenko
9473e08a14 smarttitles.pl allow intermap links in suburl
maybe this feature should have been called "sublink"...
2014-08-24 06:33:50 +03:00
Alex Jakimenko
16796b7fe5 smarttitles.pl: added #SUBURL
SUBURL is another optional feature that allows you to specify some arbitrary link to be displayed in the subtitle.
This might be handy to wikis where some pages are associated with particular URLs
2014-08-23 09:04:12 +03:00
Alex Jakimenko
1e704ece07 smarttitles.pl: do not match in the middle of the string 2014-08-23 06:27:15 +03:00
Alex Jakimenko
1f824d5838 diff.pl: fix corrupted html 2014-08-23 05:28:16 +03:00
Alex Jakimenko
d8bc7bd82f Module Updater Extension 2014-08-23 05:13:27 +03:00
Alex Jakimenko
a2e1a73d10 smarttitles.pl: fixed XSS, fixed wrong behaviour when #TITLE was not specified but #SUBTITLE was, fixed wrong behaviour when title or subtitle was specified in the end of the page, some refactoring 2014-08-22 22:01:50 +03:00
Alex Schroeder
68e71cc535 upgrade.t: fixed old namespaces problem
The problem was that the new namespaces.pl wants to call
AddModuleDescription which doesn't exist in oddmuse-2.2.6.pl -- but
that's the Oddmuse version that is used for the upgrade test.
2014-08-22 16:43:09 +02:00
Alex Schroeder
548bdf7d1c upgrade.pl: add module description 2014-08-22 16:17:18 +02:00
Alex Schroeder
a6314a2c44 Merge branch 'ad/module-description' 2014-08-22 09:09:03 +02:00
Alex Schroeder
85e8800435 offline.pl and webapp.pl: link wiki page 2014-08-22 08:49:40 +02:00
Alex Schroeder
41b5c65e22 national-days: moved to translations folder 2014-08-22 08:33:08 +02:00
Alex Schroeder
3ad0438a78 Revert changes made to translation files.
This reverts part of commit 5aba2ae56f.

Conflicts:
	modules/locked.pl
2014-08-22 00:10:04 +02:00
Alex Schroeder
3ab80d0e3f Merge branch 'ad/module-description' of git.sv.gnu.org:/srv/git/oddmuse into ad/module-description 2014-08-21 23:39:20 +02:00
Alex Schroeder
2312787ec1 simple-rules test moved to Test::More
Moved modules/simple-rules-test.pl to t/simple-rules.t and started using
the standard testing infrastructure.
2014-08-21 23:38:52 +02:00
Alex Schroeder
b8b2035151 simple-rules test moved to Test::More
Moved modules/simple-rules-test.pl to t/simple-rules.t and started using
the standard testing infrastructure.
2014-08-21 23:37:31 +02:00
Alex Schroeder
4aefc9a648 emoji.pl and smiles.pl: Fixed module description
These two modules used to link to a named anchor instead of a simple
page. This was dropped.
2014-08-21 22:32:37 +02:00
Alex Schroeder
c1cb7516a8 locked.pl is effectively a duplicate
listlocked.pl provides the same functionality and is actually installed
on emacswiki.org, so that's the one we'll keep.
2014-08-21 22:24:21 +02:00
Alex Schroeder
5aba2ae56f Fixed typo in AddModuleDescription sub name 2014-08-21 22:23:23 +02:00
Alex Schroeder
f958de8165 AddModuleDescription uses FreeToNormal
This makes sure that links to pages with spaces in their names have
spaces translated to underscores.
2014-08-21 22:22:10 +02:00
Alex Schroeder
f79b188e82 finnish-utf8.pl and swedish-utf8.pl: fix mode
The files specified fundamental-mode for Emacs users. I removed that
line because the defaults seem to work just fine.
2014-08-21 22:01:44 +02:00
Alex Schroeder
dc182fde16 brazilian-portuguese-utf8.pl: Added header back.
This header had somehow gotten lost.
2014-08-21 22:01:11 +02:00
Alex Jakimenko
5fbc444a53 Removed scripts for processing module descriptions 2014-08-21 16:48:49 +03:00
Alex Jakimenko
a7f83b2ba7 Added file descriptions without wiki links 2014-08-21 16:41:32 +03:00
Alex Jakimenko
5bfe0073d9 Fixed some module descriptions 2014-08-21 16:20:43 +03:00
Alex Schroeder
3b3e707d3b Fix Recent Changes pagination
The commit "RcHtml: fix generating More... links" introduced a bug. The
first page after clicking a More... link was the default page again. The
computation of the new FROM parameter wasn't working when neither UPTO
nor DAYS was set (as is the case when you look at the default Recent
Changes). A simple defaulting to $RcDefault did the trick.
2014-08-21 07:53:55 +02:00
Alex Jakimenko
ee932dee37 Automatically reformatted modules 2014-08-21 07:29:46 +03:00
Alex Jakimenko
772bf2745a Scripts to automatically clean module descriptions.
These files do not belong here, but they are commited intentionally (Just in case we need them again)
2014-08-21 07:17:26 +03:00
Alex Jakimenko
8cbd7dabec AddModuleDescription: allow modules without wiki pages 2014-08-21 05:44:00 +03:00
Alex Jakimenko
860d2f0bce AddModuleDescripton() 2014-08-21 04:35:53 +03:00
Alex Jakimenko
ef4aac31b4 Get rid of CRLF line endings 2014-08-21 02:46:47 +03:00
Alex Jakimenko
be1789f996 diff.pl: Fix removal of newline warning 2014-08-21 02:42:14 +03:00
Alex Schroeder
b7c1045783 Help users unlock a wiki.
When a lock is blocking the user, offer them a way to unlock the wiki.

Also, update the German translations.
2014-08-21 01:08:25 +02:00
Alex Schroeder
54913a0131 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-08-20 17:09:46 +02:00
Alex-Daniel Jakimenko
a6036d2455 Fix removal of newline warning 2014-08-20 17:08:12 +02:00
Alex-Daniel Jakimenko
12d362106e Use -- to delimit args from filenames.
This applies to the calls of diff and diff3. -- is required to
indicate the end of command line arguments, so that filenames that
start with dashes will not cause any trouble. Of course, since no one
will ever set his $TempDir to something like that, it is not critical.
2014-08-20 17:07:58 +02:00
Alex Schroeder
b292ab5983 Fix modules using PrintAllPages. 2014-08-20 17:07:54 +02:00
Alex-Daniel Jakimenko
090c708ce9 diff.pl: Diff Action Extension. 2014-08-20 17:07:36 +02:00
Alex-Daniel Jakimenko
67dc63c433 Fix removal of newline warning 2014-08-20 17:02:50 +02:00
Alex Schroeder
2606b846f0 Use -- to delimit args from filenames.
This applies to the calls of diff and diff3. -- is required to
indicate the end of command line arguments, so that filenames that
start with dashes will not cause any trouble. Of course, since no one
will ever set his $TempDir to something like that, it is not critical.
2014-08-20 08:31:32 +02:00
Alex Schroeder
ff66da7c65 Fix modules using PrintAllPages. 2014-08-20 08:28:36 +02:00
Alex Schroeder
76a6b4bfad diff.pl: Diff Action Extension. 2014-08-20 08:22:18 +02:00
Alex Schroeder
ddadb21517 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-08-20 08:21:37 +02:00
Alex Schroeder
e62423ec84 Fix edit link for the homepage.
The universal edit button link in the HTML header did not work when
looking at the home page if the home page did not appear in the URL.
2014-08-15 09:38:32 +02:00
Alex Jakimenko
083fdb3371 Refactor: Some code extracted from GetHeader
The code was moved into the new subroutine GetHeaderTitle.
2014-08-13 15:55:23 +02:00
Alex-Daniel Jakimenko
6cfe1ab29a Links With AccessKeys Extension
Oddmuse provides several shortcuts, like ‘e’ to edit page or ‘c’ to open
comments page and several others. In most browsers it means that
pressing Alt+Shift+e should automatically click (or at least focus) edit
link. However, by default there is no way to provide accesskey for links
on your wiki pages. This module is trying to solve this.
2014-08-13 12:17:24 +02:00
Alex-Daniel Jakimenko
4e43357daa Another Git Extension
Unlike Git Extension, this extension initializes git repository right
inside your Page Directory. This approach simplifies the code because
there is no need to copy files from one location to another.
2014-08-13 12:13:21 +02:00
Alex-Daniel Jakimenko
7a82dd40ff New Window Links Extension
This is a simple extension that provides syntax for creating links that
open in new windows or tabs.
2014-08-13 12:11:54 +02:00
Alex-Daniel Jakimenko
584f23b08a Comment Div Wrapper Extensions
This module will place all comments into <div> tags.
2014-08-13 12:10:08 +02:00
Alex-Daniel Jakimenko
b21f33951f Advanced Uploading
This module adds file upload buttons to comment and edit forms.
2014-08-13 12:06:55 +02:00
Alex Schroeder
acacd5ff01 GetFooterLinks avoids useless link. 2014-08-06 12:25:54 +02:00
Alex Schroeder
a333fbf3b1 creole.pl: Fixed list item issues.
creole.t now runs again.
2014-08-06 11:01:15 +02:00
Alex Jakimenko
eb7de3c722 Allow mixed mode lists.
OpenHtmlEnvironment now accepts fourth parameter that defines similar
tags.

creole.pl now passes 'ol|ul' as fourth parameter to OpenHtmlEnvironment.

In addition to that, the creole.pl code was refactored a little bit to
remove copy-pasted part.
2014-08-05 22:59:17 +02:00
Alex Schroeder
ac7ca05707 oddmuse-curl: make nicer RC buffer
Use shadow face for author.
2014-08-03 01:02:50 +02:00
Alex Schroeder
32ce6cde2d Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-08-03 01:02:22 +02:00
Alex Schroeder
d922b7413c RcHtml: fix generating More... links
When using days for RecentChanges, the More... links after the first
one reverted to $RcDefault instead of keeping the same time period.
This is now fixed.
2014-08-03 01:01:42 +02:00
Alex Schroeder
54b0fbcfaf RcHtml: fix generating More... links
When using days for RecentChanges, the More... links after the first
one reverted to $RcDefault instead of keeping the same time period.
This is now fixed.
2014-08-03 00:59:41 +02:00
Alex Schroeder
d919dd5d94 rc.t: Add test for More... links 2014-08-03 00:50:42 +02:00
Alex Schroeder
48ec41b566 git: added git.t, rewrote git.pl
Tests were added. As I wrote the tests, I realized that GitRun was
printing to STDOUT even though we had created a local *STDOUT and opened
it to write to a memory file (like PageHtml does). Apparently this is
not inherited to the child process. I now use the solution provided for
in the perldoc for open. Unfortunately it requires a temp file. Trying
to use a memory file results in an error. Temporary files are a mess if
I want to access the output: I need to close it and reopen it for
reading. That's why GitRun only does that if $GitDebug is set. This is
what most of the tests will use: set $GitDebug and examine $GitResult.
At the same time I realized that the error message was never being
triggered. The previous code was tricky because it only considered
showing an error message in a non-void context, ie. when called from
maintenance. I wasn't sure this was an actual benefit and decided to
remove it altogether. I we really want to, we can set $GitDebug and
examine $GitResult in GitCleanup.
2014-07-31 13:18:32 +02:00
Alex Schroeder
0d592e12f2 test.pl: extract config file writing
Move the writing of the config file (and the resetting of the important
variables) into a separate file so that tests can reset the config file
without clearing all the pages.
2014-07-31 13:17:02 +02:00
Alex Schroeder
ee8b8db17f oddmuse-curl.el: pwd parameter handling
Two commands used 'password' instead of 'pwd' as parameter for the
password. In addition to that, oddmuse-run will now report errors, if it
thinks there are any.
2014-07-30 14:12:19 +02:00
Alex Jakimenko
252033bff8 git.pl: Some significant changes.
Added: $GitPageFile variable. Set it to true if you want to keep
complete page files in git and not just text.

Fixed: previously git extension was chdir-ing into $GitRepo directory
without ever going back, this could have lead to problems if some other
code needed access to file system.

Fixed: now this extension will work smoothly if $DataDir is set to a
relative path.

Fixed: this extension was probably broken for wiki pages starting with
two dashes (e.g. --SomePage), this is now fixed by using -- to indicate
the end of command-line options.

Changed: GitCleanup is now using GitRun instead of backticks (like
everywhere else). It will also print the exit status of 'git commit'
command.

Changed: some tiny style improvements.
2014-07-30 14:06:07 +02:00
Alex Schroeder
e21333faca Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-07-28 11:36:38 +02:00
Alex Schroeder
ff3d7a9ea2 Search & Replace: use → instead of -> 2014-07-28 11:35:36 +02:00
Alex Schroeder
dd34aff9ef oddmuse-curl.el: Fixed message for new pages.
oddmuse-get-latest-revision doesn't return anything when the page is
new. In this case the previous message was confusing. Now it just says
that the page must be new.
2014-07-28 10:37:21 +02:00
Alex Schroeder
9eee99514b add-link.pl: more improvements 2014-07-27 22:36:38 +02:00
Alex Schroeder
5ead2bdcf2 add-link.pl: added support for /top and /match 2014-07-27 15:48:36 +02:00
Alex Schroeder
8b5267a013 oddmuse-curl.el: Markup for interlinks. 2014-07-26 23:18:22 +02:00
Alex Schroeder
423dad59b1 oddmuse-curl.el: fixing prefix arg handling for previews. 2014-07-26 23:08:47 +02:00
Alex Schroeder
f79aa04c68 oddmuse-curl.el: Support matching page names 2014-07-26 22:46:50 +02:00
Alex Schroeder
7535c859b9 oddmuse-curl.el: Fix Preview. 2014-07-26 16:43:04 +02:00
Alex Schroeder
ac34706853 oddmuse-curl.el, vc-oddmuse.el: Refactor. 2014-07-26 11:38:55 +02:00
Alex Schroeder
b705fcb3f1 oddmuse-curl.el: Reorganize code. 2014-07-25 15:20:59 +02:00
Alex Schroeder
ae13fe5235 oddmuse-curl.el: refactor
Use with-oddmuse-wiki-and-pagename.
2014-07-25 11:12:57 +02:00
Alex Schroeder
5830fbcd71 oddmuse-curl.el, vc-oddmuse.el: Revert support.
Also, a lot of refactoring and preparing to refactor some more.
2014-07-24 23:37:53 +02:00
Alex Schroeder
a2123aeb76 copy.pl: Moved to the campaignwiki subdir 2014-07-23 16:28:08 +02:00
Alex Schroeder
f07bdddb5d oddmuse-curl.el: oddmuse-reload
Added oddmuse-reload as an alias for
oddmuse-compute-pagename-completion-table.
2014-07-23 16:27:59 +02:00
Alex Schroeder
5da39c28a8 copy.pl: major rewrite 2014-07-23 16:24:53 +02:00
Alex Schroeder
28f08d9583 oddmuse-curl.el: Change key-bindings.
Use C-c C-e for editing and C-c C-f for following, freeing C-c C-o.
2014-07-23 09:52:12 +02:00
Alex Jakimenko
0ba55b13d6 Code style and refactoring. 2014-07-21 20:48:47 +02:00
Alex Schroeder
270e1aad9e oddmuse-curl.el: Add wiki searching.
Use C-c C-s to search the wiki. Introduces oddmuse-search-command,
oddmuse-search, etc.

Also: Get rid of %?. Improve documentation for percent format strings.
2014-07-21 09:56:00 +02:00
Alex Schroeder
ec1b7d1a46 Code style.
Simplify A ? A : B to A || B.
2014-07-18 14:11:08 +02:00
Alex Schroeder
718e17f07f recaptcha.t: skip if dependency is not installed
The CPAN module Captcha::reCAPTCHA is required for this test to run.
2014-07-18 14:07:11 +02:00
Alex Jakimenko
48ff67a27c Code style and refactoring 2014-07-18 13:15:29 +02:00
Alex Schroeder
39eabb6cbb Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-07-16 12:45:13 +02:00
Alex Schroeder
28d7d0a897 oddmuse-curl.el: handle ampersand in pagenames 2014-07-16 12:43:21 +02:00
Alex Schroeder
3f295e7a88 RSS 3.0 doesn't need HTML quoted. 2014-07-16 10:44:13 +02:00
Alex Schroeder
d6ef6bb56c alex-2012.css: fix CSS for numbered links 2014-07-12 20:20:00 +02:00
Alex Schroeder
f276ae6469 Don't store host names.
Get rid of the option $UseLookup. Remove GetRemoteHost and rename
GetRemoteAddress to GetRemoteHost. Thus, it now returns IP number only.
2014-07-11 19:09:33 +02:00
Alex Schroeder
f6d4d5f517 gotobar.pl: Use PageMarkedForDeletion 2014-07-11 10:23:46 +02:00
Alex Schroeder
0ee7a23018 all.pl: Add variation parameter to PrintAllPages call. 2014-07-10 17:02:35 +02:00
Alex Schroeder
61dec7317b journal3.t: Add variation=journal to the tests. 2014-07-10 16:56:49 +02:00
Alex Schroeder
7a1b4c38b1 bbcode.t: Fix smiley and frowning face character 2014-07-10 16:53:52 +02:00
Alex Jakimenko
0e97e7bee5 Refactoring 2014-07-10 15:04:47 +02:00
Alex Schroeder
769bc55821 oddmuse-curl.el: Improved pagename handling.
1. Use completion-ignore-case when reading a pagename.
2. Replace _ with spaces when inserting a pagename into the buffer.
3. URL-encode pagename when concatenating with the wiki URL.
2014-07-09 10:42:27 +02:00
Alex Schroeder
bd9cdf56bf oddmuse-curl.el: Only highlight bullet with space.
This avoids conflict with bold words at the beginning of a line.
2014-07-09 10:41:24 +02:00
Alex Schroeder
be97b89b87 journal.t: whitespace 2014-07-09 10:40:34 +02:00
Alex Jakimenko
a9f5fe4374 journal.t: Tests for the new journal syntax 2014-07-05 12:39:47 +02:00
Alex Schroeder
a88878dc08 bbcode.pl: Different Unicode smilies.
The smilies now match emoji.p: use 😊 instead of ☺ and 😟 instead of😊☹.
2014-07-04 16:38:32 +02:00
Alex Schroeder
dcaabca09f emoji.pl: Added module description. 2014-07-04 10:33:33 +02:00
Alex Schroeder
d680d0173b emoji.pl: fix one entity 2014-07-03 15:11:12 +02:00
Alex Schroeder
3e8cb56f37 smiles.pl: Using the data URI schema.
The smilies are from the Emacs 24 distribution.
2014-07-03 15:02:35 +02:00
Alex Schroeder
33ec1b1743 emoji.pl: More.
Also, use 😊 instead of ☺ and 😟 instead of😊☹.
2014-07-03 14:37:16 +02:00
Alex Schroeder
6f4b5451fc emoji.pl: Using Unicode characters.
Instead of using %Smilies (as seen in smiles.pl), this translates
sequences like :) to Unicode characters such as ☺.
2014-07-03 13:44:32 +02:00
Alex Jakimenko
2770defdc4 Additional features for journal syntax.
If you set 0 as the number of entries for More... pages, the More...
button will be disabled completely (e.g. <journal 3,0> to show only 3
entries without giving a link to other pages).

You can specify initial offset by using journal:OFFSET (e.g. <journal:3
5 "News_\d+"> will skip first three news pages).

The :OFFSET syntax might be confusing, but it is quite easy to remember:
in bash ${arr:3:5} will get five elements of array arr starting with the
third index (fourth element, thus the offset is 3). Therefore, to make
it even more confusing, it is now possible to write previous example as
<journal:3:5 "News_\d+">.

Now you can use <titles> to get links without displaying the contents.
It accepts exactly the same arguments as <journal>. For example
<titles:3 5 "News_\d+">.
2014-07-03 12:58:48 +02:00
Alex Jakimenko
1d6f435ca8 askpage.pl: Fixed variable name.
Fixed variable name (this module was not working previously), comments
and minor fixes.
2014-07-03 09:17:49 +02:00
Alex Schroeder
00856c0436 oddmuse-curl.pl: Editable *Preview* buffer.
Switch to fundamental mode (undoing view-mode) before loading a new
preview.
2014-07-03 09:10:22 +02:00
Alex Schroeder
e0ee3bb24d oddmuse-curl.el: Fix line-breaking.
Allow line-breaking when we're right at the start of a link.
2014-07-02 09:46:50 +02:00
Alex Schroeder
8bbbed026d add-link.pl: Handle & in names.
Handle HTML quoting correctly when it comes to site names such that
sites containing an ampersand show up as & and not as &amp;.

Inline the star.png in order to be stand-alone.
2014-07-01 16:07:19 +02:00
Alex Schroeder
c9767ce84b alex-2012.css: Button icon shadow. 2014-07-01 13:36:50 +02:00
Alex Schroeder
b984f3ecad alex-2012.css: Button size. 2014-07-01 13:16:54 +02:00
Alex Schroeder
f58f784009 oddmuse-curl.el: Fix parameters for oddmuse-follow 2014-07-01 10:09:54 +02:00
Alex Schroeder
b6ee8da7c6 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-07-01 10:08:51 +02:00
Alex Schroeder
ae59ab3746 GetParam: only call utf8::decode on defined values
In some recent versions of Perl such as v5.18.0, when $foo is undef,
utf8::decode($foo) modifies $foo to '' (defined null string). This
causes problems. When the Preview button is clicked, for example, a
nomal page is shown instead of the preview, because of this. Thus, we
need to avoid calling utf8::decode on undefined value.
2014-07-01 09:33:17 +02:00
Alex Schroeder
28ab5885a0 contrib: README with an explanation of the files 2014-06-30 14:43:48 +02:00
Alex Schroeder
881dbc7094 copy.pl: add use utf-8. 2014-06-30 14:40:51 +02:00
Alex Schroeder
2537a97900 description: added for gitweb. 2014-06-30 14:29:45 +02:00
Alex Schroeder
20de100781 contrib: Add +x to all .pl files 2014-06-30 14:25:10 +02:00
Alex Schroeder
e1c3445136 add-link.pl: Undid commit to the wrong location. 2014-06-30 14:24:23 +02:00
Alex Schroeder
e8be707079 add-link.pl: Script used to maintain a bookmark wiki. 2014-06-30 14:22:35 +02:00
Alex Schroeder
680c3b96ce oddmuse-curl.el: Remove extra closing parenthesis. 2014-06-30 10:00:41 +02:00
Alex Schroeder
ba4ce729e6 alex-2012.css: Add a download link class 2014-06-30 09:37:14 +02:00
Alex Schroeder
d74da11382 raw.pl: Use new page directory structure.
And added a test for raw.pl.
2014-06-27 11:30:33 +02:00
Alex Schroeder
9d0e6cb3cb upgrade.pl: Fix handling of dot files 2014-06-26 18:52:21 +02:00
Alex Schroeder
027557999d Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-06-26 18:47:15 +02:00
Alex Schroeder
41fb4d0c4b Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-06-26 18:44:45 +02:00
Alex Schroeder
7cf0904b2b oddmuse-curl.el: Infer wiki and pagename
Replace oddmuse-read-wiki-and-pagename by oddmuse-pagename such that
the user will not be asked for a wiki and a pagename if it can be
inferred from the context.
2014-06-26 18:35:20 +02:00
Alex Schroeder
7330f1961b oddmuse-curl.el: C-u shows preview in browser 2014-06-26 18:33:55 +02:00
Alex Schroeder
6e9d50204f oddmuse-curl.el: C-c C-b to browse this page 2014-06-26 18:31:06 +02:00
Alex Schroeder
629157d367 oddmuse-curl.el: more fiddling with markup order 2014-06-25 12:17:32 +02:00
Alex Schroeder
23af89d21e oddmuse-2013.css: smaller font-size for code 2014-06-25 12:16:36 +02:00
Alex Schroeder
a3cf3dbb99 oddmuse-2013.css: black line before comment 2014-06-24 16:18:57 +02:00
Alex Schroeder
a28f380125 journal-rss.pl: monthly parameter
As suggested by Ingo Belka on the wiki: The parameter monthly=1 will
set the match parameter to the current year and the current month.
2014-06-24 16:13:59 +02:00
Alex Schroeder
eb8fd17e01 oddmuse-curl.el: Reorganized, mostly for font-lock
Changed all the oddmuse-*-markup functions to variables. Reorganized
oddmuse-mode.
2014-06-24 11:46:18 +02:00
Alex Schroeder
4784e3bc88 oddmuse-curl.el: oddmuse-revert confirmation
oddmuse-revert will now ask for confirmation before reverting the
current buffer.
2014-06-24 11:44:23 +02:00
Alex Schroeder
cff287ee24 oddmuse-curl.el: Remove Oddmuse Wiki from oddmuse-wikis
There don't seem to be a big overlap between Emacs users and Oddmuse
Wiki editors.
2014-06-24 11:42:32 +02:00
Alex Schroeder
07eeffa3e3 oddmuse-curl.el: add nobreak property
oddmuse-nobreak-p now takes into account the nobreak property. This
property is added to font-lock-extra-managed-props and used by *bold*,
_underline_ and /italic/.
2014-06-23 13:50:07 +02:00
Alex Schroeder
fe7a5e564a admin.pl: Get rid of CreatePageDir. 2014-06-23 12:54:39 +02:00
Alex Schroeder
00aa0761d7 referrer-tracking.t: Clean up after the last test. 2014-06-23 12:24:51 +02:00
Alex Schroeder
f09a81b3b9 referrer-tracking: Get rid of CreatePageDir.
Fix the unit tests, too.
2014-06-23 12:19:07 +02:00
Alex Schroeder
c43b0695c2 oddmuse-curl.t: fix handing of ' in summary
Shell quoting issues, the bane of every programmer.
2014-06-23 11:32:08 +02:00
Alex Schroeder
e9e436c0b8 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-06-23 09:53:17 +02:00
Alex Schroeder
c0194c1178 pageidx file now no longer contains all those ones
Previously, the pageidx file contained the serialized hash. If we had
two pages A and B, it contained A 1 B 1. When you install this version,
your wiki will report extra pages of "1" until you delete your pageidx
file, or until you create a new page (which will delete your pageidx
file).
2014-06-22 23:28:56 +02:00
Alex Schroeder
c6a0cb33ac Raw RSS adds "minor: 1" for minor changes
If you looked at an URL like the following, you wouldn't know which
items referred to minor changes and which didn't. They all looked the
same.
http://localhost/cgi-bin/wiki.pl?action=rc;showedit=1;raw=1

This change adds "minor: 1" to items caused by minor changes, and
oddmuse-curl.el (the Oddmuse Mode for Emacs), handles this.
2014-06-22 23:14:55 +02:00
Alex Schroeder
e9375974cb rollback.t: Get rid of stat
Using stat to get the last edit timestamp can lead to a failing test.
To be absolutely certain, use the timestamp stored in the page file.
As it stands, $Now is used for the timestamp in the page file but if
this is a new file (revision 1), then the index file gets rewritten
and its timestamp changes.
2014-06-22 23:11:35 +02:00
Alex Schroeder
a226902617 oddmuse-curl.el: RecentChanges with Summary
Recent Changes will now show the summary.
2014-06-22 22:20:25 +02:00
Aki Goto
213774d6ff joiner.pl: Support Questionasker and reCaptcha.
These are used in the Register and Login forms.

And, the deprecated CreatePageDir is replaced by CreateDir (fixes a bug
introduced by Oddmuse version 2.3.0).
2014-06-22 12:10:53 +02:00
Aki Goto
98d96fd1d8 gd_security_image.pl: New CAPTCHA module.
This one uses GD::SecurityImage.
2014-06-22 12:06:14 +02:00
Alex Schroeder
ddb8fb06e6 gotobar.pl: Add support for external links 2014-06-22 00:21:46 +02:00
Alex Schroeder
25989f78a5 Merge branch 'as/no-more-page-subdirectories' 2014-06-21 21:30:27 +02:00
Aki Goto
afdb7a9dcb form_timeout.pl: an anti-spam module for Oddmuse
This is an anti-spam module for Oddmuse using form timeout. Edit
permission times out after a specified duration (the default is 30
minutes). When edit content is posted directly by a spam bot without
viewing the edit form, edit will be denied.
2014-06-21 12:18:26 +02:00
Alex Schroeder
2e79a843c8 oddmuse-curl.el: Fix URL 2014-06-21 12:01:08 +02:00
Alex Schroeder
54370da235 oddmuse-curl.el: whitespace 2014-06-21 12:00:26 +02:00
Alex Schroeder
8ec456ed41 Merge branch 'as/no-more-page-subdirectories' of ssh://git.sv.gnu.org/srv/git/oddmuse into as/no-more-page-subdirectories 2014-06-21 05:51:35 -04:00
Alex Schroeder
020df9098d upgrade.pl: Fix globbing.
The globbing expression was broken such that pages starting with a dot
("invisible" files) were not migrated.
2014-06-21 05:49:31 -04:00
Alex Schroeder
43839ac1aa upgrade.t: Testing for the changes to upgrade.pl 2014-06-21 10:45:21 +02:00
Alex Schroeder
3c2f96250b upgrade.pl: Use variables; print utf8.
Instead of fiddling with @MyInitVariables, set the options naming
pages to the empty string.
2014-06-21 04:44:33 -04:00
Alex Schroeder
9def2d2eb2 upgrade.pl: Disable some module initialisations
Some modules read a page file when initializing. As these cannot be
found before the upgrade, we need to disable them.
2014-06-21 04:18:16 -04:00
Alex Schroeder
3ad40b84fb .gitignore: .DS_Store 2014-06-20 22:39:37 +02:00
Alex Schroeder
ecda4c3d98 oddmuse-curl.el: Preview shows just the preview
Don't show the header, footer and textarea; show just the preview div.
2014-06-20 22:36:09 +02:00
Alex Schroeder
74a0576c5d oddmuse-curl.el: Font lock restructuring
All the font-locking functions are now modifying font-lock-defaults
instead of calling font-lock-add-keywords because that's what it says
in the elisp manual.
2014-06-20 21:23:30 +02:00
Alex Schroeder
a6e07a9886 oddmuse-curl.el: Preview command
The preview command uses shr, a built in HTML renderer.
2014-06-20 18:31:33 +02:00
Alex Schroeder
b76b61dc86 .gitignore: .DS_Store 2014-06-19 23:11:04 +02:00
Alex Schroeder
c3cb434973 upgrade.pl: handle name spaces 2014-06-19 23:00:18 +02:00
Alex Schroeder
62f82c2af2 upgrade.pl: New interface.
Don't rely on a separate upgrade action. Any request except for login
and unlock will trigger an upgrade, if you're an admin. Once the upgrade
is complete, the module will rename itself such that it will no longer
load.
2014-06-17 13:14:13 +02:00
Alex Schroeder
d454973294 oddmuse-curl.el: fix order of font-locking
oddmuse-basic-markup must come last (which prepends its rules to the
front) such that links get precedence over other markup.
2014-06-17 12:26:50 +02:00
Alex Schroeder
cba29c8981 oddmuse-curl.el: added oddmuse-new
A function to make it easy to blog by offering the current ISO date as
page name.
2014-06-17 10:39:05 +02:00
Alex Schroeder
4a812931c8 oddmuse-curl.el: do not break links
Added a fill-nobreak-predicate to prevent links from breaking. This uses
the face property and checks for the link face.
2014-06-17 10:37:57 +02:00
Alex-Daniel Jakimenko
093a6da63d askpage.pl: Don't keep old value of $NewComment
Resetting the value was dead code. Instead of fixing this, the old value
is now discarded. There is no point in keeping it around.
2014-06-16 15:40:13 +02:00
Aki Goto
0ab5261bc6 load-lang.pl: add $LoadLanguageDir
The new option $LoadLanguageDir specifies a directory for the language
files.
2014-06-16 15:33:53 +02:00
Alex Schroeder
1d4f3e4a28 Ask Page extension
This is a simple extension to create a page for asking questions. The
process of writing a question is similar to writing a comment, for the
only exception that after pressing the ‘Save’ button the user will be
redirected to the newly created page containing his question.
2014-06-16 11:25:13 +02:00
Alex Jakimenko
6babcffd00 Consistency in file permissions.
Some modules are executable where as others are not. This patch fixes
this.
2014-06-16 11:19:24 +02:00
Alex Jakimenko
977cbba251 Fix two issues with $NewComment.
Display $NewComment above comment textarea.

'c' is now an access key to focus comment textarea.
2014-06-16 11:06:20 +02:00
Alex Schroeder
2fc4f4b054 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse into as/no-more-page-subdirectories 2014-06-16 10:32:31 +02:00
Alex Schroeder
53566c8434 Use a function instead of $ENV{REMOTE_ADDR}
When the webserver is behind a reverse proxy, $ENV{REMOTE_ADDR} is not
the actual remote client's address but the reverse proxy's address. The
actual remote client's address is available from an environment
variable. The name of this variable depends on the proxy, e.g. pound
uses $ENV{HTTP_X_FORWARDED_FOR}.

As suggested by tyatsumi on the wiki, all access $ENV{REMOTE_ADDR} now
happens via a new function which allows users to override it in their
config file.
2014-06-16 09:50:05 +02:00
Alex Schroeder
563e5cd9c6 upgrade.pl: delete empty directories after upgrade 2014-06-07 17:08:18 +02:00
Alex Schroeder
365d33b602 Get rid of one letter sub-directories.
Recent GNU/Linux systems use ext3 or ext4 file systems. These use HTree
to index files. Wikipedia says: "HTree indexing improved the scalability
of Linux ext2 based filesystems from a practical limit of a few thousand
files, into the range of tens of millions of files per directory. [...]
HTree indexes are available in ext3 when the dir_index feature is
enabled. [...] HTree indexes are turned on by default in ext4."

Thus, instead of working on balanced-page-directories.pl, we decided to
get rid of these sub-directories altogether.

Unfortunately, this is backwards incompatible. Users wanting to upgrade
will need to install the upgrade.pl extension in order to upgrade the
file database.
2014-06-06 17:32:44 +02:00
Alex Schroeder
eef56e435d questionasker.t: fixed number of tests 2014-06-05 17:07:15 +02:00
Alex Schroeder
2044564981 Merge branch 'master' of ssh://git.sv.gnu.org/srv/git/oddmuse 2014-06-05 05:34:08 -04:00
Aki Goto
50c9b79858 balanced-page-directories: reset GetPageDirectory
The test for migration sets GetPageDirectory; when the test fails and
we're not migrating, we need to reset GetPageDirectory to its old value.
2014-06-04 16:14:26 +02:00
Alex Schroeder
d99f62ea7e balanced-page-directories: fix page creation
Previously, no new pages could be created because of a deadlock. The
code mistakenly attempted to start migrating when a new page was
created, and since DoPost already held the main lock, migration failed.
The check was now fixed such that migration is not started when a new
page is being created.
2014-06-04 09:58:37 +02:00
Alex Schroeder
c11188fd3e fixed documentation typo 2014-06-03 16:17:07 +02:00
Alex Schroeder
dd22a852eb balanced-page-directories: new module 2014-06-03 16:14:48 +02:00
Alex Schroeder
62b2e22da8 Questionasker: encoding issue with hidden fields
We need to get rid of $q->hidden when using Unicode, as suggested by
tyatsumi on the wiki.
2014-06-03 11:19:50 +02:00
Alex Schroeder
5483bbf386 joiner: fix URL 2014-06-02 09:37:55 +02:00
Alex Schroeder
8608464863 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-06-02 09:22:38 +02:00
Aki Goto
b0d983c817 joiner: user registration module 2014-06-02 09:21:15 +02:00
Alex Schroeder
26a5db86b0 Fix module description. 2014-05-27 14:48:02 +02:00
Aki Goto
5f58256543 Updated Japanese translation. 2014-05-27 14:45:50 +02:00
Alex Jakimenko
c5c088deb1 Do not rehash the password for every entry. 2014-04-23 17:41:44 +02:00
Alex Schroeder
a5b5af9c07 Add $PassHashFunction and $PassSalt
This allows users to have the passwords encrypted in their config
file, as suggested by Alex Jakimenko.
2014-04-23 10:32:36 +02:00
Alex Jakimenko
0dcf49e2cf Add $CommentsPattern to supplement $CommentsPrefix
$CommentsPrefix is used in the code in two contexts:

- as a string added to the original page name to create links (used as
  a plain string)

- and as a way to detect whether the page has comments or not (used as
  a regular expression)

It feels natural to split this functionality into two separate
variables. $CommentsPattern is now the regular expression. No more
CommentsPrefix='.*' hacks!

For example, now you can do some complex stuff like this:

    $CommentsPrefix = 'Comments_on_';
    $CommentsPattern = '^(?|Comments_on_(.*)|Rant_About_(.*)|\d\d\d\d-\d\d-\d\d.*|FAQ)$';

Comments_on_ , Rant_About_ and journal pages will work correctly as
comments pages, but you can also specify some other pages as well, like
FAQ. Basically it can get as complex as one wants. $1 will be used to
create a link to the original page, which means that in this particular
example both Comments_on_Test and Rant_About_Test will have a link to
Test page, while FAQ will have no link to the original page at all.

Of course, by default there will only be "$CommentsPrefix . $id" link in
the footer, so you have to provide links to Rant_About_ pages elsewhere
yourself.

If you don't want to provide a regular expression pattern, you can leave
it undefined. It will be created automatically, keeping functionality
backwards compatible. If you were using $CommentsPrefix='.*' you should
now change it to $CommentsPattern='.*'.
2014-04-21 18:43:40 +02:00
Alex Jakimenko
f3885aa213 OpenPage: Remove useless test. 2014-04-20 00:26:29 +02:00
Alex Schroeder
6136b399a6 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-04-15 07:45:01 +02:00
Alex Schroeder
5cc7d55152 License, dependencies. 2014-04-15 07:39:01 +02:00
Alex Schroeder
4112d2acc4 New URL, trimmed wiki list. 2014-04-15 07:38:01 +02:00
Alex Jakimenko
f270a3ced4 Two small fixes
User input needs to be HTML quoted when printed.
The regular expression matching needs the ignore case flag.
2014-04-15 07:31:50 +02:00
Alex Schroeder
7f74d3c211 Use smaller headers 2014-04-09 08:34:14 -04:00
Alex Jakimenko
375c844e37 Specifying the number of entries for More...
This patch addes a new parameter to PrintJournal
such that a journal can have a certain number of
entries but when the user clicks on the More...
link, pagination happens with a different number.
<Journal 1,5>
2014-04-08 10:43:28 +02:00
Alex Jakimenko
efce35e250 Simplify FreeToNormal and remove if statement 2014-04-06 15:14:59 +02:00
Alex Schroeder
cff4f1fd28 Enabling diff usince C-x v = 2014-04-04 18:12:04 +02:00
Alex Schroeder
6f9ded7e41 vc-oddmuse.el added with support for C-x v l 2014-04-04 15:15:00 +02:00
Alex Jakimenko
40c01683fd Split pageidx file using space
Previously, we split it using whitespace (/\s+/). This caused a problem
if somebody managed to create a page containing non-breaking whitespace.
2014-03-29 09:42:00 +01:00
Alex Schroeder
ab3a7752ba New highlighting to look like Emacs buffers. 2014-03-21 19:18:15 +01:00
Alex Schroeder
08a4861dc3 Get rid of cloud icon. 2014-03-21 07:43:24 +01:00
Alex Schroeder
d7c40d4dbe Fix dead comment links
If the comment page does not exist, the static copy contains an anchor
element with no href attribute. Better avoid this situation.
2014-03-18 13:01:27 +01:00
Alex Schroeder
f8360bebad Produce static.css as well when exporting 2014-03-18 12:47:16 +01:00
Alex Schroeder
45a0558fcc Fixing the UTF-8 encoding issues for static export 2014-03-18 11:49:28 +01:00
Alex Schroeder
f4ff56e69f Fix HTML output for static export 2014-03-18 11:21:08 +01:00
Alex Schroeder
0d7236c047 More tests regarding local links in static exports 2014-03-18 10:32:22 +01:00
Alex Schroeder
686f24251b Fix static export of HTML pages
Apparently the html=1 parameter got lost so that you could not force an
export of all the pages.
2014-03-18 09:26:04 +01:00
Alex Schroeder
0841c834b9 Escape URL of More... links
When computing the More... link at the end of a journal, we need to URL
escape all user input. In this case, that's the regexp and search
parameter.
2014-03-17 09:52:30 +01:00
Alex Schroeder
5225bded01 Revert "Homepage URL fixing works recognizes https."
I must have been hallucinating. Instead of committing the change I
wanted to commit, I added a file that wasn't ready.

This reverts commit 670b69c118.
2014-03-17 09:51:11 +01:00
Alex Schroeder
e0d18c31e2 Homepage URL fixing works recognizes https.
When leaving a comment, users are given the option of providing a
homepage to link their name to. A common error is to just provide a
domain like "oddmuse.org" instead of a real URL. The resulting markup
used to be [oddmuse.org YourName] which doesn't do what the user
expected. That's why a piece of code used to check whether the homepage
starts with "http://" and if it doesn't, it prefixes it, resulting in
"[http://oddmuse.org YourName]". If the homepage started with
"https://", however, the code did the wrong thing. That's why we're now
checking whether the homepage starts with any known URL-protocol and a
colon.
2014-03-17 09:50:32 +01:00
Alex Schroeder
670b69c118 Homepage URL fixing works recognizes https.
When leaving a comment, users are given the option of providing a
homepage to link their name to. A common error is to just provide a
domain like "oddmuse.org" instead of a real URL. The resulting markup
used to be [oddmuse.org YourName] which doesn't do what the user
expected. That's why a piece of code used to check whether the homepage
starts with "http://" and if it doesn't, it prefixes it, resulting in
"[http://oddmuse.org YourName]". If the homepage started with
"https://", however, the code did the wrong thing. That's why we're now
checking whether the homepage starts with any known URL-protocol and a
colon.
2014-03-16 08:48:36 +01:00
Alex Schroeder
f4d0f300e6 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse
Conflicts:
	modules/translations/chinese_cn-utf8.pl
2014-03-07 09:02:41 +01:00
Andy Stewart
53a7a9a80c chinese_cn-utf8.pl: Updated translation
Simplified Chinese, fixed.
2014-03-07 08:38:15 +01:00
Alex Schroeder
4f675de687 oddmuse-curl.el: Fix following page links. 2014-03-07 08:31:08 +01:00
Alex Schroeder
dffe5e3053 Updated with new texts. 2014-03-06 17:15:35 +01:00
Alex Schroeder
201970ba0b Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2014-03-06 16:28:27 +01:00
Alex Schroeder
7e9137c6f8 Changing 回復 to 回滾 after feedback from Andy Stewart. 2014-03-06 16:23:04 +01:00
Alex Schroeder
9d81a1e3d2 DoDuckDuckGoSearch uses UrlEncode on the argument.
Drew Adams reported that clicking on the title of a page with a + in
its name had the + replaced by a space. This commit fixes this issue.
2014-03-03 08:30:21 +01:00
Alex Schroeder
2f58de9aa4 $NewText and $NewComment can be translated.
As suggested by Dexasys on the wiki.
2014-02-01 23:49:48 +01:00
Alex Schroeder
5ca2bf3efb Fix tests for fix-encoding. 2014-01-26 11:39:06 +01:00
Alex Schroeder
96bc4e14fa Fix the number of tests. 2014-01-25 18:27:10 +01:00
Alex Schroeder
ad1059dbb2 Revert the last commit.
The output has to be encoded as well.
2014-01-25 18:16:06 +01:00
Alex Schroeder
508396d1d1 New module. 2014-01-24 23:19:58 +01:00
Alex Schroeder
6d457ff87b Fix newline handling. 2014-01-24 23:19:37 +01:00
Alex Schroeder
860cb15324 Lighter RecentChanges. More spacing. 2014-01-22 01:52:43 +01:00
Alex Schroeder
56e76a4883 Get rid of special cases for RecentChanges. 2014-01-22 01:43:44 +01:00
Alex Schroeder
3fa8e0a6b0 New. 2014-01-21 08:06:56 -05:00
Alex Schroeder
4c4ab98d47 Merge branch 'master' of ssh://git.sv.gnu.org/srv/git/oddmuse 2013-12-23 05:18:56 -05:00
Alex Schroeder
ca62cbf446 Add .toc 2013-12-23 05:18:45 -05:00
Alex Schroeder
ef3bde90ac Fix documentation URL 2013-12-21 20:01:58 +01:00
Alex Schroeder
7771c541bb oddmuse-curl.el requires info for the faces.
Fixed the regular expressions for extended markup.
Fixed the regular expression for oddmuse-link-pattern.
Use goto-address when looking at a history page.
Use a list instead of an alist for the list of pagenames.
2013-12-06 11:00:42 +01:00
Alex Schroeder
6adabedefe oddmuse-curl.el merged with the current version on Emacs Wiki. 2013-12-06 09:36:46 +01:00
Alex Schroeder
a776c67cd6 oddmuse-curl.el, an Oddmuse client for Emacs, based on version 1.3
with an improved doc-string for oddmuse-wikis.
2013-12-06 09:31:16 +01:00
Alex Schroeder
0ddc1770a3 Merge branch 'master' of ssh://git.sv.gnu.org/srv/git/oddmuse 2013-11-30 18:59:39 -05:00
Alex Schroeder
44fa8cfb5a Handle empty lines in broken oldrc.log files. 2013-11-30 18:59:31 -05:00
Alex Schroeder
96c21c2240 Removed wikipipi: No idea how this is supposed to work. 2013-12-01 00:21:20 +01:00
Alex Schroeder
1c25325257 Anonymizing older entries in the list of recent changes.
When the maintenance action runs, it copies all the older entries in
rc.log to oldrc.log. Older entries are the entries that will usually
not get used by a typical display of recent changes. Any entry older
than the largest value of @RcDays is moved to oldrc.log (defaults to
90 days).

The idea is that you would only need hostnames or IP numbers to fight
spam and vandalism: Add regular expressions matching either hostname
or IP number of spammers or vandals to $BannedHosts and prevent the
attack from continuing. After a few days, however, this information is
no longer required. In this day and age of privacy invasion, I think
software should take a pro-active stance and therefore the entries
moved to oldrc.log will have their hostname or IP number replaced by
"Anonymous".

The existing entries in oldrc.log are not changed. If you want to do
the right thing, there's a script called anonymize.pl in the contrib
directory.
2013-11-30 23:56:10 +01:00
Alex Schroeder
fd5b4e84b1 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-11-30 22:51:00 +01:00
Alex Schroeder
9beff3748b Set @IndexOptions via @MyInitVariables.
With commit deec99c353 @InitOptions can
no longer be set at load time. Setting it at load time also disables
translations unless they get loaded earlier. Thus, @MyInitVariables.
2013-11-30 22:50:31 +01:00
Alex Schroeder
87dedeab85 Add button. 2013-11-28 01:33:20 -05:00
Alex Schroeder
1e73ae22d3 Show the menu only when a username is provided. 2013-11-21 14:31:24 +01:00
Alex Schroeder
5e9b02b5b1 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
2013-11-17 23:34:43 +01:00
Alex Schroeder
deec99c353 Delaying the setting of @IndexOptions.
This change was suggested by toomas on the wiki because the
%Translations hash was not set at the time that @IndexOptions was set.
It is now set in InitVariables.
2013-11-17 23:32:00 +01:00
Alex Schroeder
d1b0ac4ccb Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-10-25 03:22:47 -04:00
Alex Schroeder
06881768c3 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-10-25 08:50:51 +02:00
Alex Schroeder
8e1f6c92e3 Static action now takes $StaticAlways into account. 2013-10-25 08:49:13 +02:00
Alex Schroeder
1ebc5192ff ReCAPTCHA introduced HTML escaping problems. 2013-10-20 20:27:12 +02:00
Alex Schroeder
7c52b7b4c2 Add facility to fix HTML escaping. 2013-10-20 20:00:30 +02:00
Alex Schroeder
2936ace022 Test for an encoding bug in recaptcha.pl 2013-10-09 23:28:13 +02:00
Alex Schroeder
4504ef43ac Avoid the use of $q->hidden() and use $q->input and GetParam() instead. 2013-10-09 23:09:47 +02:00
Alex Schroeder
50b71adf2d Add a summary when showing a diff in RSS output.
When looking at an URL like action=rss;full=1;page=0;diff=1;days=1 we
expect to see a diff, and with the diff we expect a summary.  RssItem
calls PageHtml if full is set.  PageHtml opens the page and calls
PrintPageDiff.  If diff is set, it calls PrintHtmlDiff.  Since the
page is already open, PrintHtmlDiff will use GetCacheDiff and skip the
calling of GetTextRevision which would have produced a summary. That's
why we use the open page's summary if none has been set.
2013-09-23 16:44:22 +02:00
Alex Schroeder
8bb0475ba2 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-08-31 21:35:16 +02:00
Alex Schroeder
0e66af495b bbCodeRule must come after PortraitSupportRule
If bbCode is interpreted first, it tries to handle [new].
2013-08-31 21:33:42 +02:00
Alex Schroeder
be6752116b Added support for tt distinct from code. 2013-08-25 00:36:41 +02:00
Alex Schroeder
36577490a7 Fix off by one bug recently introduced by changes to rollbacks.
Rollbacks of large sections count down $i to find the right place to
stop. When the for loop continues, however, $i is decremented once
more. Added $i++ in order to compensate.
2013-08-24 16:20:41 +02:00
Alex Schroeder
8e4dcc2240 Rewrote the code that skips over multiple pages.
When we're within a large rollback, $end used to point to the end of
the block that would eventually be stripped. It's a relative pointer.
While we were escanning downwards, we would sometimes strip single
pages even if we were within a larger rollback. Every time this
happened, $end was not shortened.

The current rewrite start skipping lines immediately and does away
with $skip_to and $end.
2013-08-24 15:38:11 +02:00
Alex Schroeder
dc4de8212a Rollback must roll back previously rolled back changes as well. 2013-08-24 13:53:10 +02:00
Alex Schroeder
ba2de753dd Rollback must roll back to minor changes as well. 2013-08-24 13:39:34 +02:00
Alex Schroeder
6dd1b7e125 Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-08-22 08:02:05 -04:00
Alex Schroeder
aec6e9fb30 Add 14pt font-size for comments. 2013-08-22 14:01:38 +02:00
Alex Schroeder
7b7d90f9f9 Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-08-22 06:51:41 -04:00
Alex Schroeder
c937258922 Commented the 'no bleeding' section. 2013-08-22 06:51:36 -04:00
Alex Schroeder
08aa098203 Add whitespace above the "Comments" header. 2013-08-22 12:49:44 +02:00
Alex Schroeder
b0fc1e4cc0 Take minor edits into accounts when proposing list of contributors to ban. 2013-08-21 12:10:18 +02:00
Alex Schroeder
ca9eef8c09 Get rid of undefined behaviour as indicated by Perl 5.18. 2013-08-21 11:55:20 +02:00
Alex Schroeder
b90b6e9651 Used another XPath expression in the test to make it more robust. 2013-08-21 11:49:33 +02:00
Alex Schroeder
f10bbb4f81 Fix test for %Namespaces as suggested by a Perl 5.18 warning. 2013-08-21 10:44:42 +02:00
Alex Schroeder
0116618e36 Fix number of skipped tests if LWP::UserAgent is not available. 2013-08-21 10:42:27 +02:00
Alex Schroeder
d864045815 Use $PERLBREW_PATH if available.
Try to guess which Perl we should be using. Since we loaded wiki.pl,
our $ENV{PATH} is set to /bin:/usr/bin in order to find diff and grep.
Prepending /usr/local/bin is one option, using $PERLBREW_PATH is
another.
2013-08-21 10:41:51 +02:00
Alex Schroeder
294e5745e7 Fixed syntax problem as warned by Perl 5.18 2013-08-21 10:19:45 +02:00
Alex Schroeder
afc4f7ecba Replaced oddmuse.css with default.css. 2013-08-21 09:52:26 +02:00
Alex Schroeder
d249792866 Changed the default CSS to oddmuse.org/default.css
I was often confused as to whether oddmuse.org/oddmuse.css referred to
the CSS used by oddmuse.org or to the CSS used by Oddmuse
installations without CSS setting.
2013-08-19 11:46:11 +02:00
Alex Schroeder
59cad086e7 Removed ban-yourself.pl because that was just an idea without any code. 2013-08-16 00:32:27 +02:00
Alex Schroeder
cfac228f57 Test for ban-quick-editors.pl 2013-08-16 00:31:28 +02:00
Alex Schroeder
a4bd6383a2 Quote the unquoted string "commenthidden". 2013-08-16 00:30:58 +02:00
Alex Schroeder
df0f470998 Don't delete pages that are "lock on creation".
This is meant to protect BannedContent and BannedHost from deletion.
2013-08-16 00:29:32 +02:00
Alex Schroeder
d61bf19b15 New module: don't allow quick editing by an IP or username. 2013-08-15 23:46:31 +02:00
Alex Schroeder
e0659c4d60 Made regular expression test more robust. 2013-08-05 10:02:06 +02:00
Alex Schroeder
70baed8088 Testing: Add tests to verify the process of banning URL fragments. 2013-08-02 17:27:50 +02:00
Alex Schroeder
ab3e187354 Bugfix: Banned URLs are added to BannedContent, not BannedHosts.
Added a separate link to add host or IP number to BannedHosts.
2013-08-02 17:13:44 +02:00
Alex Schroeder
f17a67d817 Convenience: List URLs rolled back and offer entry of regexp.
If you are an admin and rolled back a single page, this will list the
URLs your rollback removed (assuming that those URLs are part of the
spam) and it will allow you to provide a regular expression that will
be added to BannedHosts.
2013-08-02 16:55:49 +02:00
Alex Schroeder
601218c0b1 Added ban-contributors extension and tests. 2013-07-30 17:40:57 +02:00
Alex Schroeder
8af5095ff5 Hide Google+ stuff when printing. 2013-07-24 07:43:56 -04:00
Alex Schroeder
0a6cbfa20d Fix link given by raw history page. 2013-06-05 16:18:10 +02:00
Alex Schroeder
1630b64fa5 Fix critical bug in private-pages.pl.
Private pages were deleted whenever maintenance ran. This has been
fixed.
2013-05-30 16:15:01 +02:00
Alex Schroeder
ff4ad6e151 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-05-23 09:03:13 +02:00
Alex Schroeder
cc07341463 DoRollback prints a footer for a specific page if called for one page only.
The typical workflow when reverting spam:
1. view RecentChanges
2. click History button
3. click Rollback button
4. click Administration
5. click Ban contributors
6. click Ban!

This requires that the Administration link in #4 contains the page
id. This commit ensures it.
2013-05-23 09:02:46 +02:00
Alex Schroeder
9fd20a9e93 A new rollback testing idea. 2013-05-19 16:13:37 +02:00
Alex Schroeder
1a561c3cb1 Fix tagcloud bug in tags.pl.
The hash value wasn't being decoded before being split which resultet
in count being 1 in all cases.
2013-05-19 15:32:54 +02:00
Alex Schroeder
ca3740ca86 Add RuleOrder to prevent conflict with markup.pl. 2013-05-19 14:43:23 +02:00
Alex Schroeder
7a69437443 Italy: removed Festa della Repubblica, added Liberation Day instead. 2013-05-17 10:38:51 +02:00
Alex Schroeder
671f00701b Anniversary of the Unification of Italy 2013-05-17 00:42:48 +02:00
Alex Schroeder
af28957796 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-05-16 23:20:13 +02:00
Alex Schroeder
28c56373f6 DuckDuckGo module.
duckduckgo-search.pl and duckduckgo-search.t based on google-search.pl
and google-search.t to use DuckDuckGo for the search action via a
redirect.
2013-05-16 23:18:23 +02:00
Alex Schroeder
d5fa00f1e2 The admin menu should only list links for actions that are actually
defined. This makes it easier to undefine and hide them.
2013-05-10 00:20:55 +02:00
Alex Schroeder
66fe91efed Expire keep files and delete pages during maintenance without main lock. 2013-05-09 23:46:06 +02:00
Alex Schroeder
3d07062e1f Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-05-08 22:19:12 +02:00
Alex Schroeder
f7b94272bf Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-05-08 22:16:48 +02:00
Alex Schroeder
9e2353aebc Add access keys for articles and comments, if enabled.
If $CommentsPrefix is set, the wiki knows about article pages and
comment pages. The link in GetFooterLinks now uses 'a' and 'c' as
access keys. The access key is passed to GetPageLink and to
ScriptLink.
2013-05-08 22:16:22 +02:00
Alex Schroeder
bf83cc5ca1 Don't use a global $form. 2013-05-07 10:18:12 +02:00
Alex Schroeder
d5e7d58d7e Use EB Garamond hosted by Google if necessary 2013-04-15 03:40:21 -04:00
Alex Schroeder
806a8ba89b DEL no longer uses grey. 2013-04-12 23:09:25 +02:00
Alex Schroeder
8602dfb324 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-04-12 23:03:08 +02:00
Alex Schroeder
6647d52e88 Handle markup singles before handling forced pairs. 2013-04-12 22:59:50 +02:00
Alex Schroeder
3dcf08a850 Fixed %s error in one message reported by Juanma MP. 2013-04-03 11:18:20 +02:00
Alex Schroeder
2a5454a732 New: wikipipe 2013-03-25 14:03:23 +01:00
Alex Schroeder
ee239428d9 Update copyright year. 2013-03-13 18:46:09 +01:00
Alex Schroeder
dd731569d3 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse
Conflicts:
	t/diff.t
2013-03-10 00:52:22 +01:00
Alex Schroeder
d9640c2ef7 Display summary of the change when displaying a diff.
GetTextRevision returns a third parameter (the summary). PrintHtmlDiff
takes a fifth parameter (the summary) and prints it. Test added.
2013-03-10 00:46:49 +01:00
Alex Schroeder
a57d26f520 Whitespace. 2013-03-05 23:13:04 +01:00
Alex Schroeder
98f5b48ceb Add support for -q, -a and -z options.
Rewrote the help message to list the options instead of having
multiple paragraphs of text. Renamed PostRaw to post and added support
for the new options. Pass the new options through copy.
2013-03-05 23:10:35 +01:00
Alex Schroeder
4e790f7847 Fix justification of cells.
The code used to detect whitespace in sibling cells. Thus, if any of
the remaining cells on this line was centered or right justified, this
cell was also getting right justified. If the current cell was both
left and right justified, the result was that it got centered. Added a
test to check for this.
2013-03-05 23:07:23 +01:00
Alex Schroeder
355874edad Add git action to call GitCleanup directly. Add more print statements explaining what git is doing. 2013-02-28 10:44:26 +01:00
Alex Schroeder
91cdb9888a Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-02-14 16:25:47 +01:00
Alex Schroeder
ff28c5f79e no background color for sister site logos 2013-02-14 16:25:28 +01:00
Alex Schroeder
004b0c0831 URL encode keys and values in the tag database.
Depending on your version of the Berkley DB, non-ASCII or non-Latin-1 characters could crash Oddmuse.
2013-02-12 06:00:06 -05:00
Alex Schroeder
01d9cdf4e3 Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-02-12 04:14:08 -05:00
Alex Schroeder
0226a82dca Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-02-01 15:37:44 +01:00
Alex Schroeder
31fcd5dc99 Avoid a javascript error. 2013-02-01 15:30:31 +01:00
Alex Schroeder
2c69716295 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-02-01 15:29:42 +01:00
Alex Schroeder
e772254293 Make sure we don't create an empty TOC element if there aren't enough sections. 2013-02-01 15:26:02 +01:00
Alex Schroeder
f8df77d1a6 Remove the TOC if we don't have enough sections. 2013-02-01 15:17:52 +01:00
Alex Schroeder
de4af94e89 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-02-01 15:16:32 +01:00
Alex Schroeder
cdee73b859 At least two siblings or parent and child nodes required. 2013-02-01 15:12:54 +01:00
Alex Schroeder
70895ed631 Only print outline when there is more than one element. 2013-02-01 15:08:54 +01:00
Alex Schroeder
14a6cc4e2f Find existing TOC from toc.pl using the class attribute. 2013-02-01 15:05:04 +01:00
Alex Schroeder
83eaa45077 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-02-01 14:21:28 +01:00
Alex Schroeder
3a9b92f4a3 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-02-01 14:17:46 +01:00
Alex Schroeder
6e82239616 An extension to generate a table of content. 2013-02-01 14:09:59 +01:00
Alex Schroeder
8e2da8a1a9 Save $1 to prevent it from being overwritten by Tss. 2013-01-31 09:50:11 +01:00
Alex Schroeder
872b914c90 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-01-31 09:43:43 +01:00
Alex Schroeder
1e6f732fa9 Use LogWrite. 2013-01-31 09:43:05 +01:00
Alex Schroeder
925f0788fb Add $1 to the explanation if such a group is part of the regular
expression.
2013-01-31 09:29:25 +01:00
Alex Schroeder
3c0c79a526 logbannedcontent.pl: Logging BannedHosts as well.
Renamed wrappers to make sure all have the Log prefix.

Moved log writing to a separate sub. Provide a little wrapper text for
banned hosts.

Using TimeToW3 to use a standard date and time format.

Use the id if no page has been opened yet (since DoEdit calls
UserIsBanned and DoPost calls UserCanEdit before either calls
OpenPage).
2013-01-31 09:21:54 +01:00
Alex Schroeder
88e66e825e Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-01-30 17:04:24 -05:00
Alex Schroeder
fb7566ae53 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-01-30 16:04:47 +01:00
Alex Schroeder
9b05ea62c5 Protect TZget against crashes if the timestamp is undefined. 2013-01-30 16:03:40 +01:00
Alex Schroeder
4feccd6484 Testing for encoding problems in diff output. 2013-01-25 19:07:11 +01:00
Alex Schroeder
7d166842f0 Make sure banning happens without logging in RegexpNewBannedContent. 2013-01-25 00:03:51 +01:00
Alex Schroeder
c6943cad7b Package Oddmuse. 2013-01-24 23:51:12 +01:00
Alex Schroeder
c29037a9d6 Delete code that doesn't belong. 2013-01-24 23:50:31 +01:00
Alex Schroeder
e1b429c3b7 New 2013-01-24 23:45:24 +01:00
Alex Schroeder
c17c622c97 Intro 2013-01-24 23:31:11 +01:00
Alex Schroeder
9d11d42e5e New 2013-01-24 23:30:32 +01:00
Alex Schroeder
270e0f4932 Invert the loop when scanning for banned content. 2013-01-24 23:04:35 +01:00
Alex Schroeder
d1f6e1bb37 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-01-24 22:46:57 +01:00
Alex Schroeder
47e4ad5e41 New. 2013-01-24 22:46:18 +01:00
Alex Schroeder
78dd013fc0 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-01-23 23:58:06 +01:00
Alex Schroeder
c04403ca66 Download style for a.download. 2013-01-23 23:57:42 +01:00
Alex Schroeder
8c8e23b21a Fix comment. 2013-01-14 23:06:19 +01:00
Alex Schroeder
fd9a715634 Another fix for mail.pl... 2013-01-13 01:04:19 +01:00
Alex Schroeder
957729fd5d Fix subscription migration for mail.pl 2013-01-13 00:57:58 +01:00
Alex Schroeder
23fb0cf18b Added migration of subscriptions to mail.pl and tests. 2013-01-13 00:45:58 +01:00
Alex Schroeder
8e72af0a45 Fix encoding issues with the use of DB_File in mail.pl.
This also fixes the tests. Also get rid of wide character in print by
Test::Builder by adding the fix mentioned in the Test::More manpage.

The DB_File issue was necessary because a page name with an EN DASH
caused the script to crash, thus not printing the footer.
Unfortunately, this is solved by URL-encoding keys and values. This
means that your old mail.db is going to be invalid!
2013-01-12 23:55:08 +01:00
Alex Schroeder
26135820e1 UrlDecode doesn't need utf8::decode. 2013-01-12 23:50:59 +01:00
Alex Schroeder
2c3abffd2e Removed $Id$ from info-ref. 2013-01-12 23:50:11 +01:00
Alex Schroeder
4b46c5385e Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-01-11 04:45:30 -05:00
Alex Schroeder
5b7fdbdea4 Reading files using :utf8 instead of :encoding(utf-8).
This is discouraged because :utf8 does not validate the input. The
problem is that in some cases you can end up with invalid UTF-8 if
your wiki was created with a copy of Oddmuse that allowed raw bytes.
There, we requested users to provide UTF-8 input and printed it back
claiming that it was UTF-8, but in the end it was just a convention.
Spammers and vandals could upload anything they liked. This is why
your rc.log (and all other sorts of files) may contain invalid UTF-8
bytes. This is particularly troublesome in the case of your rc.log
files as these will never go away and they are read very often. The
resulting warnings will fill up your web server logs.
2013-01-11 10:40:35 +01:00
Alex Schroeder
61dae58368 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-01-11 10:34:18 +01:00
Alex Schroeder
6958b66bc5 twitter is a CGI script to process RSS feeds.
It strips the description of an item if it contains the same info as
the title, and it strips the username from the title, if you want.
2013-01-11 10:30:57 +01:00
Alex Schroeder
512cbf4ae9 Get rid of a warning.
Use response->decoded_content.
Add more sources.
Get rid of $Id.
2013-01-11 10:10:19 +01:00
Alex Schroeder
e188665a9b No longer validate the UTF-8 from rc.log files in GetRcLinesFor.
If the rc.log file contained invalid UTF-8, this would fill the server
logs with thousands of warnings. There is nothing we can do about
these (they probably originated from an older copy of the script).
Therefore, <:utf8 is now used instead of <:encoding(UTF-8).
2013-01-10 14:25:56 +01:00
Alex Schroeder
4898f970b0 Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-01-07 07:53:12 -05:00
Alex Schroeder
d9a2db5b8d Added support for sub and sup tags. 2013-01-07 13:51:39 +01:00
Alex Schroeder
7b518f14f0 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2013-01-07 13:41:23 +01:00
Alex Schroeder
ff4b889f1c Merge branch 'master' of ssh://as@git.sv.gnu.org/srv/git/oddmuse 2013-01-06 12:34:17 -05:00
Alex Schroeder
b4b6435826 Fix entities for superscripts and vulgar fractions. 2013-01-06 18:18:16 +01:00
Alex Schroeder
011953370a Print fractions. 2013-01-06 18:13:53 +01:00
Alex Schroeder
40a0b7104a Fixing encoding for RSS feed inclusion using HTTP::Response->decoded_content. 2013-01-01 14:24:44 +01:00
Alex Schroeder
964f8c38c0 Typo in a comment. 2013-01-01 14:13:06 +01:00
Alex Schroeder
e46c89e90f rc2mail now adds some newlines to the HTML mail being sent. 2012-12-21 11:14:09 +01:00
Alex Schroeder
99d8ff2b01 GetRaw uses HTTP::Response's decoded_content to fix encoding issues. 2012-12-11 04:53:51 -05:00
Alex Schroeder
dfbd5ad47e Fix encoding menu disappears if page is missing. 2012-11-28 07:39:14 +01:00
Alex Schroeder
68ea223940 No encoding to fix for non-existing pages
Add more tests to show that fix-encoding does not create a page if it
is missing.
2012-11-28 07:33:20 +01:00
Alex Schroeder
4fc84fa623 Make sure fix encoding doesn't save if nothing has changed 2012-11-21 21:39:13 +01:00
Alex Schroeder
33aa81d9c9 Fix encoding issues with translation links. 2012-11-21 21:29:41 +01:00
Alex Schroeder
58690662df Private pages no longer accessible using revision parameter 2012-11-21 21:11:49 +01:00
Alex Schroeder
b2194ebdac Added some tests for translation links. 2012-11-21 21:01:06 +01:00
Alex Schroeder
d584c4dc68 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2012-11-20 19:46:45 +01:00
Alex Schroeder
105ccdf323 Add header back to bulgarian-utf8.pl and chinese-utf8.pl 2012-11-20 15:47:03 +01:00
Alex Schröder
cb6d1cc17d Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2012-11-20 15:38:51 +01:00
Alex Schroeder
be4bddab30 No longer recreate -utf8 files. 2012-11-16 21:49:56 +01:00
Alex Schroeder
465b278303 Fix a loophole where using <include "..."> allowed you to see hidden pages. 2012-11-16 18:38:27 +01:00
Alex Schroeder
a52bebdcd2 Fix docstring. 2012-11-16 17:56:25 +01:00
Alex Schroeder
1caa4c55c0 Private pages! 2012-11-16 17:12:12 +01:00
Alex Schroeder
9c77e56568 Whitespace. 2012-11-16 15:51:56 +01:00
Alex Schroeder
f5e86f4ddc Prevent double "Showing revision X" by passing QUIET to GetTextRevision. 2012-11-16 15:51:19 +01:00
Alex Schroeder
f10dde33c8 No bullet point before div.refer a elements. 2012-11-14 17:35:52 +01:00
Alex Schröder
ff64a0ed82 Update by Hervé Robin 2012-11-05 13:56:03 +01:00
Alex Schroeder
a046436a50 Deutsche Übersetzung auf Vordermann gebracht. 2012-10-27 13:56:40 +02:00
Alex Schroeder
bcb9721499 New extension. 2012-10-27 13:28:13 +02:00
Alex Schroeder
609f037345 Added link to documentation online. 2012-10-27 12:55:30 +02:00
Alex Schroeder
4ed8c4fb25 Fixed whitespace when setting %Tex.
Made %Tex public so it can be used in a test.
2012-10-26 23:59:54 +02:00
Alex Schroeder
45ebd07cf4 testing encoding of the cookie 2012-10-26 16:46:18 +02:00
Alex Schroeder
51223c6297 Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2012-10-26 16:39:37 +02:00
Alex Schroeder
08b7674ab4 Use decoded_content for HTTP::Response 2012-10-26 16:38:22 +02:00
Alex Schroeder
a8780e75f5 Also handles other parameter per feed, eg. ignore_in_feed = updated 2012-10-26 16:20:30 +02:00
Alex Schröder
dc43759ebd Many additions by Aurélien Desbrières. 2012-10-25 10:21:01 +02:00
Alex Schroeder
e8ba28bffe Merge branch 'master' of git.sv.gnu.org:/srv/git/oddmuse 2012-10-25 08:55:10 +02:00
Alex Schroeder
f3266288e1 Add module description. 2012-10-25 08:54:53 +02:00
Alex Schroeder
8482c47383 user tables without 4em margin 2012-10-23 19:30:30 -04:00
Alex Schroeder
1e4268597d no longer need to encode UTF-8 strings: it's the default 2012-10-22 11:28:26 -04:00
Alex Schroeder
dd05f824a8 Switch tex.pl to rules instead of macros. 2012-10-18 23:36:44 +02:00
Alex Schroeder
6b2d119481 Commented utf8::encode in DoTagsReindex
This was recommended by Erik on the wiki because he found Latin-1
encoded page names in the Tag DB.
2012-09-30 09:39:37 +02:00
Alex Schroeder
37bdb62db8 Added svg to $ImageExtensions.
Apparently this now works; I tested it on an up to date Firefox.
2012-08-18 12:03:29 +02:00
Alex Schroeder
30c5c3798f Use xpath to extract oldtime parameter.
The last change to GetHiddenValue changed the HTML output. Using XPath
will find the right parameter even if the order of the parameters
changed.
2012-08-15 19:32:10 +02:00
350 changed files with 24179 additions and 3622 deletions

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@
/Mac/pkg/
*.dmg
*.pkg
.DS_Store

View File

@@ -17,24 +17,22 @@ build:
mkdir -p build
build/wiki.pl: wiki.pl
sed "s/\\\$$q->a({-href=>'http:\/\/www.oddmuse.org\/'}, 'Oddmuse')/\\\$$q->a({-href=>'http:\/\/git.savannah.gnu.org\/cgit\/oddmuse.git\/tag\/?id=$(VERSION_NO)'}, 'wiki.pl') . ' ($(VERSION_NO)), see ' . &/" < $< > $@
perl -lne "s/(\\\$$q->a\({-href=>'http:\/\/www.oddmuse.org\/'}, 'Oddmuse'\))/\\\$$q->a({-href=>'http:\/\/git.savannah.gnu.org\/cgit\/oddmuse.git\/tag\/?id=$(VERSION_NO)'}, 'wiki.pl') . ' ($(VERSION_NO)), see ' . \$$1/; print" < $< > $@
build/%-utf8.pl: modules/translations/%-utf8.pl
sed "s/<a href=\"http:\/\/git.savannah.gnu.org\/cgit\/oddmuse.git\/tree\/modules\/translations\/\\(.*\\).pl\">\\(.*\\).pl<\/a>/<a href=\"http:\/\/git.savannah.gnu.org\/cgit\/oddmuse.git\/tree\/modules\/translations\/\\1.pl?id=$(VERSION_NO)\">\\1.pl<\/a> (for $(VERSION_NO))/" < $< > $@
# Currently oddtrans introduces encoding errors!
# %-utf8.pl: wiki.pl $(MODULES)
# perl oddtrans -l $@ $^ > $@-new && mv $@-new $@
perl -lne "s/(AddModuleDescription\('[^']+', '[^']+')\)/\$$1, 'translations\/', '$(VERSION_NO)')/; print" < $< > $@
# from: http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/namespaces.pl
# to: http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/namespaces.pl?id=2.1-11-gd4f1e27
build/%.pl: modules/%.pl
sed "s/<a href=\"http:\/\/git.savannah.gnu.org\/cgit\/oddmuse.git\/tree\/modules\/\\(.*\\).pl\">\\(.*\\).pl<\/a>/<a href=\"http:\/\/git.savannah.gnu.org\/cgit\/oddmuse.git\/tree\/modules\/\\1.pl?id=$(VERSION_NO)\">\\1.pl<\/a> (for $(VERSION_NO))/" < $< > $@
perl -lne "s/(AddModuleDescription\('[^']+', '[^']+')\)/\$$1, undef, '$(VERSION_NO)')/; print" < $< > $@
translations: $(TRANSLATIONS)
for f in $^; do \
echo updating $$f...; \
perl oddtrans -l $$f wiki.pl $(MODULES) > $$f-new && mv $$f-new $$f; \
done
# UNTESTED/OBSOLETE: these targets have not been tested in a long time
# and are potentially obsolete.

315
contrib/add-link.pl Normal file
View File

@@ -0,0 +1,315 @@
#! /usr/bin/perl
# Copyright (C) 20112015 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;
use LWP::UserAgent;
use HTML::TreeBuilder;
use JSON::PP;
use utf8;
# load Oddmuse core
$RunCGI = 0;
do "wiki.pl";
# globals depending on the name of the script
my ($self, $name, $wiki);
if ($0 eq '/home/alex/campaignwiki.org/add-link.pl') {
$self = "https://campaignwiki.org/add-link";
$name = "OSR Links to Wisdom";
$wiki = 'LinksToWisdom';
} elsif ($0 eq '/home/alex/campaignwiki.org/add-adventure.pl') {
$self = "https://campaignwiki.org/add-adventure";
$name = "OSR Links to Adventures";
$wiki = 'Adventures';
} else {
ReportError('Cannot determine wiki!', '500 INTERNAL SERVER ERROR');
}
# derived variables
my $site = "https://campaignwiki.org/wiki/$wiki";
# my $site = "http://localhost/wiki.pl";
my $home = "$site/$HomePage";
# http://www.emacswiki.org/pics/star.png
my $stardata = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEUAAHkAAACzdRTapx3twwD/9qb////1YCa0AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfXAQYCJAu+WhwbAAAAKnRFWHRDb21tZW50AGJ5IFJhZG9taXIgJ1RoZSBTaGVlcCcgRG9waWVybGFza2kVfTXbAAAAYElEQVQI12NgQAKMMIaYAFTAzRDKCHOEMETCnEFyjIJhYS6OggwMoqGhaS7GRgIMjC6uYc5GikA5YRcXIyWwotBgJUWw7lAXsAyDaIihMlhK1FFA0AjEEAESQgJQu4EYAPAPC2XcokgQAAAAAElFTkSuQmCC';
main();
sub toc {
# start with the homepage
my @values;
my %labels;
for my $id (GetPageContent($HomePage) =~ /\* \[\[(.*?)\]\]/g) {
push @values, $id;
for my $item (GetPageContent(FreeToNormal($id)) =~ /(\*+ [^][\n]*)$/mg) {
my $value = $item;
my $label = $item;
$value =~ s/\* *//g;
push @values, $value;
$label =~ s/\* *//g; # EM SPACE
$labels{$value} = $label;
}
}
return \@values, \%labels;
}
sub top {
# start with the homepage
my %blog;
my $n;
for my $id (GetPageContent($HomePage) =~ /\* \[\[(.*?)\]\]/g) {
for my $item (GetPageContent(FreeToNormal($id)) =~ /^\*+\s+\[(https?:\/\/[^\/\n\t ]+)/mg) {
$n++;
# handle blogspot domain munging
$item =~ s/blogspot(\.[a-z]+)+/blogspot.com/;
$blog{$item}++;
}
}
print $q->p("Total links counted: $n.");
my @list = sort { $blog{$b} <=> $blog{$a} } keys %blog;
# my $max = scalar @list;
# $max = 20 if $max > 20;
# @list = @list[0 .. $max -1];
@list = map {
my $domain = substr($_, index($_, '://') + 3);
my $term = quotemeta($domain);
# handle blogspot domain munging
$term =~ s/blogspot\\\.com/blogspot(\\.[a-z]+)+/;
$term = QuoteHtml($term);
$q->a({-href => $_}, $domain)
. " (" . $q->a({-href => "$self/match/$term"}, $blog{$_}) . ")";
} @list;
return \@list;
}
sub match {
my $term = shift;
# start with the homepage
my @list;
my $title;
for my $id (GetPageContent($HomePage) =~ /\* \[\[(.*?)\]\]/g) {
for my $line (split /\n/, GetPageContent(FreeToNormal($id))) {
if ($line =~ /^\*+\s+([^][\n]*)$/) {
$title = $1;
} elsif ($line =~ /$term/o) {
if ($line =~ /^\*+\s+\[(https?:\S+)\s+([^]]+)\]/) {
push (@list, $q->a({-href => $1}, $2) . " (" . $title . ")");
}
}
}
}
return \@list;
}
sub html_toc {
my ($values, $labels) = toc();
return $q->radio_group(-name =>'toc',
-values => $values,
-labels => $labels,
-linebreak=>'true');
}
sub default {
print $q->p("Add a link to the " . $q->a({-href=>$home}, $name) . ".");
print $q->start_multipart_form(-method=>'get', -class=>'submit');
print $q->p($q->label({-for=>'url'}, T('URL:')) . ' '
. $q->textfield(-name=>'url', -id=>'url', -size=>80));
print $q->p({-style=>'font-size: 10pt'},
"(Drag this bookmarklet to your bookmarks bar for easy access:",
$q->a({-href=>q{javascript:location='}
. $q->url()
. qq{?url='+encodeURIComponent(window.location.href)}},
"Submit $name") . ".)");
print html_toc();
print $q->submit('go', 'Add!');
print $q->end_form();
}
sub confirm {
my ($url, $name, $toc) = @_;
print $q->p("Please confirm that you want to add "
. GetUrl($url, $name)
. " to the section “$toc”.");
print $q->start_form(-method=>'get');
print $q->p($q->label({-for=>'name', -style=>'display: inline-block; width: 15em'},
T('Use a different link name:')) . ' '
. $q->textfield(-style=>'display: inline-block; width:50ex',
-name=>'name', -id=>'name', -size=>50, -default=>$name)
. $q->br()
. $q->label({-for=>'summary', -style=>'display: inline-block; width:15em'},
T('An optional short summary:')) . ' '
. $q->textfield(-style=>'display: inline-block; width:50ex',
-name=>'summary', -id=>'summary', -size=>50)
. $q->br()
. $q->label({-for=>'username', -style=>'display: inline-block; width:15em'},
T('Your name for the log file:')) . ' '
. $q->textfield(-style=>'display: inline-block; width:50ex',
-name=>'username', -id=>'username', -size=>50));
my $star = $q->img({-src=>$stardata, -class=>'smiley', -alt=>'☆'});
print '<p>Optionally: Do you want to rate it?<br />';
my $i = 0;
foreach my $label ($q->span({-style=>'display: inline-block; width:3em'}, $star)
. 'I might use this for my campaign',
$q->span({-style=>'display: inline-block; width:3em'}, $star x 2)
. 'I have used this in a campaign and it worked as intended',
$q->span({-style=>'display: inline-block; width:3em'}, $star x 3)
. 'I have used this in a campaign and it was ' . $q->em('great')) {
$i++;
print qq{<label><input type="radio" name="stars" value="$i" $checked/>$label</label><br />};
}
print '</p>';
print $q->hidden('url', $url);
print $q->hidden('toc', $toc);
print $q->hidden('confirm', 1);
print $q->submit('go', 'Continue');
print $q->end_form();
}
# returns unquoted html
sub get_name {
my $url = shift;
my $tree = HTML::TreeBuilder->new_from_content(GetRaw($url));
my $h = $tree->look_down('_tag', 'title');
$h = $tree->look_down('_tag', 'h1') unless $h;
$h = $h->as_text if $h;
return $h;
}
sub post_addition {
my ($url, $name, $toc, $summary) = @_;
my $id = FreeToNormal($name);
my $display = $name;
utf8::decode($display); # we're dealing with user input
utf8::decode($summary); # we're dealing with user input
print $q->p("Adding ", GetUrl($url, $display), " to “$toc”.");
# start with the homepage
my @pages = GetPageContent($HomePage) =~ /\* \[\[(.*?)\]\]/g;
for my $id (@pages) {
return post($id, undef, $name, $summary, $url, GetParam('stars', '')) if $id eq $toc;
my $data = GetPageContent(FreeToNormal($id));
while ($data =~ /(\*+ ([^][\n]*))$/mg) {
return post($id, $1, $name, $summary, $url, GetParam('stars', '')) if $2 eq $toc;
}
}
print $q->p("Whoops. I was unable to find “$toc” in the wiki. Sorry!");
}
sub post {
my ($id, $toc, $name, $summary, $url, $stars) = @_;
my $data = GetPageContent(FreeToNormal($id));
my $re = quotemeta($url);
if ($data =~ /$re\s+(.*?)\]/) {
my $display = $1;
print $q->p($q->strong("Oops, we seem to have a problem!"));
print $q->p(GetPageLink(NormalToFree($id)),
" already links to the URL you submitted:",
GetUrl($url, $display));
return;
}
$stars = ' ' . (':star:' x $stars) if $stars;
$summary = ': ' . $summary if $summary;
if ($toc) {
$toc =~ /^(\*+)/;
my $depth = "*$1"; # one more!
my $regexp = quotemeta($toc);
$data =~ s/$regexp/$toc\n$depth \[$url $name\]$summary$stars/;
} else {
$data = "* [$url $name]$summary$stars\n" . $data;
}
my $ua = LWP::UserAgent->new;
my %params = (text => $data,
title => $id,
summary => $name,
username => GetParam('username'),
pwd => GetParam('pwd'));
# spam fighting modules
$params{$QuestionaskerSecretKey} = 1 if $QuestionaskerSecretKey;
$params{$HoneyPotOk} = time if $HoneyPotOk;
my $response = $ua->post($site, \%params);
if ($response->is_error) {
print $q->p("The submission failed!");
print $response->content;
} else {
print $q->p("See for yourself: ", GetPageLink($id));
}
}
sub print_end_of_page {
print $q->p('Questions? Send mail to Alex Schroeder <'
. $q->a({-href=>'mailto:kensanata@gmail.com'},
'kensanata@gmail.com') . '>');
print $q->end_div();
PrintFooter();
}
sub main {
$ConfigFile = "$DataDir/config"; # read the global config file
$DataDir = "$DataDir/$wiki"; # but link to the local pages
Init(); # read config file (no modules!)
$ScriptName = $site; # undo setting in the config file
$FullUrl = $site; #
binmode(STDOUT,':utf8');
$q->charset('utf8');
if ($q->path_info eq '/source') {
seek DATA, 0, 0;
print "Content-type: text/plain; charset=UTF-8\r\n\r\n", <DATA>;
} elsif ($q->path_info eq '/structure') {
my ($values, $labels) = toc();
my @indented = map {
($labels->{$_} || $_) =~ /^(*)/;
[$_, length($1)]
} @$values;
print "Content-type: application/json; charset=UTF-8\r\n\r\n";
binmode(STDOUT,':raw'); # because of encode_json
print JSON::PP::encode_json(\@indented);
} elsif ($q->path_info eq '/toc') {
my ($values, $labels) = toc();
print "Content-type: application/json; charset=UTF-8\r\n\r\n";
binmode(STDOUT,':raw'); # because of encode_json
print JSON::PP::encode_json($values);
} elsif ($q->path_info eq '/top') {
print GetHeader('', 'Top Blogs');
print $q->start_div({-class=>'content top'});
print $q->ol($q->li(top()));
print_end_of_page();
} elsif ($q->path_info =~ '^/match/(.*)') {
my $term = $1;
print GetHeader('', "Entries Matching '$term'");
print $q->start_div({-class=>'content match'});
print $q->ol($q->li(match($term)));
print_end_of_page();
} else {
push(@UserGotoBarPages, 'Help');
$UserGotoBar = $q->a({-href=>$q->url . '/source'}, 'Source');
print GetHeader('', 'Submit a new link');
print $q->start_div({-class=>'content index'});
my $url = GetParam('url');
my $name = UnquoteHtml(GetParam('name', get_name($url)));
my $toc = GetParam('toc');
my $confirm = GetParam('confirm');
my $summary = GetParam('summary');
if (not $url or not $toc) {
default();
} elsif (not $confirm) {
confirm($url, $name, $toc);
} else {
post_addition($url, $name, $toc, $summary);
}
print_end_of_page();
}
}
__DATA__

90
contrib/anonymize.pl Normal file
View File

@@ -0,0 +1,90 @@
#! /usr/bin/perl -w
# Copyright (C) 2013 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/>.
=head1 Anonymize oldrc.log Files
This script will read your oldrc.log file and replace the host field
with 'Anonymous'. This is what the main script started doing
2013-11-30.
When you run this script, it sets the main lock to prevent maintenance
from running. You can therefore run it on a live system.
=cut
use strict;
sub verify_setup {
if (not -f 'oldrc.log') {
die "Run this script in your data directory.\n"
. "The oldrc.log file should be in the same directory.\n";
}
if (not -d 'temp') {
die "Run this script in your data directory.\n"
. "The temp directory should be in the same directory.\n";
}
}
sub request_lock {
if (-d 'temp/lockmain') {
die "The wiki is currently locked.\n"
. "Rerun this script later.\n";
}
mkdir('temp/lockmain') or die "Could not create 'temp/lockmain'.\n"
. "You probably don't have the file permissions necessary.\n";
}
sub release_lock {
rmdir('temp/lockmain') or die "Could not remove 'temp/lockmain'.\n"
}
sub anonymize {
open(F, 'oldrc.log') or die "Could not open 'oldrc.log' for reading.\n";
open(B, '>oldrc.log~') or die "Could not open 'oldrc.log~' for writing.\n"
. "I will not continue without having a backup available.\n";
my $FS = "\x1e"; # The FS character is the RECORD SEPARATOR control char
my @lines = ();
while (my $line = <F>) {
next if $line eq "\n"; # some rc.log files are broken and contain empty lines
my ($ts, $id, $minor, $summary, $host, @rest) = split(/$FS/o, $line);
if ($id eq '[[rollback]]') {
# rollback markers are very different
push(@lines, $line);
} else {
# anonymize
push(@lines, join($FS, $ts, $id, $minor, $summary, 'Anonymous', @rest));
}
print B $line;
}
close(F);
open(F, '>', 'oldrc.log') or die "Could not open 'oldrc.log' for writing.\n";
for my $line (@lines) {
print F $line; # @rest ends with a newline
}
close(F);
print "Wrote anonymized 'oldrc.log'.\n";
print "Saved a backup as 'oldrc.log~'\n";
}
sub main {
verify_setup();
request_lock();
anonymize();
release_lock();
}
main();

View File

@@ -0,0 +1,37 @@
The files in this directory are used to run http://campaignwiki.org/
add-link.pl
===========
This is used to add links to the Links To Wisdom wiki. This wiki is a
bookmark site: A few pages make up a big unordered list of links in
wiki format. add-link is a tool to help users contribute new links to
the list.
http://campaignwiki.org/wiki/LinksToWisdom/HomePage
copy.pl
=======
This is used to copy the text from a web page to a wiki page. The idea
was to keep archive copies of cool pages somewhere. The Blog Archive
never got used, though.
http://campaignwiki.org/wiki/BlogArchive/HomePage
monster-tag.pl
==============
This is used to quickly tag many pages in the Monsters wiki. The
Monsters wiki hasn't been used in a long time, though.
http://campaignwiki.org/wiki/Monsters/HomePage
submit.pl
=========
This used to be used to add sites to the Old School RPG Planet. The
aggregator was configured via a wiki page on the Planet wiki. It's now
abandoned.
http://campaignwiki.org/wiki/Planet/HomePage

262
contrib/campaignwiki/add-link.pl Normal file → Executable file
View File

@@ -1,6 +1,6 @@
#! /usr/bin/perl
# Copyright (C) 2011 Alex Schroeder <alex@gnu.org>
# Copyright (C) 20112014 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
@@ -15,8 +15,10 @@
# this program. If not, see <http://www.gnu.org/licenses/>.
package OddMuse;
use LWP::UserAgent;
use HTML::TreeBuilder;
use JSON::PP;
use utf8;
# load Oddmuse core
@@ -24,11 +26,14 @@ $RunCGI = 0;
do "wiki.pl";
# globals
my $self = "http://campaignwiki.org/add-link";
my $name = "OSR Links to Wisdom";
my $wiki = 'LinksToWisdom';
my $site = "http://campaignwiki.org/wiki/$wiki";
# my $site = "http://localhost/wiki.pl";
my $home = "$site/$HomePage";
# http://www.emacswiki.org/pics/star.png
my $stardata = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEUAAHkAAACzdRTapx3twwD/9qb////1YCa0AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfXAQYCJAu+WhwbAAAAKnRFWHRDb21tZW50AGJ5IFJhZG9taXIgJ1RoZSBTaGVlcCcgRG9waWVybGFza2kVfTXbAAAAYElEQVQI12NgQAKMMIaYAFTAzRDKCHOEMETCnEFyjIJhYS6OggwMoqGhaS7GRgIMjC6uYc5GikA5YRcXIyWwotBgJUWw7lAXsAyDaIihMlhK1FFA0AjEEAESQgJQu4EYAPAPC2XcokgQAAAAAElFTkSuQmCC';
main();
@@ -47,9 +52,62 @@ sub toc {
$labels{$value} = $label;
}
}
return \@values, \%labels;
}
sub top {
# start with the homepage
my %blog;
my $n;
for my $id (GetPageContent($HomePage) =~ /\* \[\[(.*?)\]\]/g) {
for my $item (GetPageContent(FreeToNormal($id)) =~ /^\*+\s+\[(https?:\/\/[^\/\n\t ]+)/mg) {
$n++;
# handle blogspot domain munging
$item =~ s/blogspot(\.[a-z]+)+/blogspot.com/;
$blog{$item}++;
}
}
print $q->p("Total links counted: $n.");
my @list = sort { $blog{$b} <=> $blog{$a} } keys %blog;
# my $max = scalar @list;
# $max = 20 if $max > 20;
# @list = @list[0 .. $max -1];
@list = map {
my $domain = substr($_, index($_, '://') + 3);
my $term = quotemeta($domain);
# handle blogspot domain munging
$term =~ s/blogspot\\\.com/blogspot(\\.[a-z]+)+/;
$term = QuoteHtml($term);
$q->a({-href => $_}, $domain)
. " (" . $q->a({-href => "$self/match/$term"}, $blog{$_}) . ")";
} @list;
return \@list;
}
sub match {
my $term = shift;
# start with the homepage
my @list;
my $title;
for my $id (GetPageContent($HomePage) =~ /\* \[\[(.*?)\]\]/g) {
for my $line (split /\n/, GetPageContent(FreeToNormal($id))) {
if ($line =~ /^\*+\s+([^][\n]*)$/) {
$title = $1;
} elsif ($line =~ /$term/o) {
if ($line =~ /^\*+\s+\[(https?:\S+)\s+([^]]+)\]/) {
push (@list, $q->a({-href => $1}, $2) . " (" . $title . ")");
}
}
}
}
return \@list;
}
sub html_toc {
my ($values, $labels) = toc();
return $q->radio_group(-name =>'toc',
-values => \@values,
-labels => \%labels,
-values => $values,
-labels => $labels,
-linebreak=>'true');
}
@@ -57,102 +115,108 @@ sub default {
print $q->p("Add a link to the " . $q->a({-href=>$home}, $name) . ".");
print $q->start_multipart_form(-method=>'get', -class=>'submit');
print $q->p($q->label({-for=>'url'}, T('URL:')) . ' '
. $q->textfield(-name=>'url', -id=>'url', -size=>50));
print toc();
print $q->submit('go', 'Add!');
print $q->end_form();
print $q->p("Drag this bookmarklet to your bookmarks bar for easy access:",
. $q->textfield(-name=>'url', -id=>'url', -size=>80));
print $q->p({-style=>'font-size: 10pt'},
"(Drag this bookmarklet to your bookmarks bar for easy access:",
$q->a({-href=>q{javascript:location='}
. $q->url()
. qq{?url='+encodeURIComponent(window.location.href)}},
"Submit $name") . ".");
"Submit $name") . ".)");
print html_toc();
print $q->submit('go', 'Add!');
print $q->end_form();
}
sub check_url {
my $toc = GetParam('toc');
return default() unless $toc;
my $url = shift;
if (not GetParam('confirm', 0)) {
my $name = get_name($url);
print $q->p("Please confirm that you want to add "
. GetUrl($url, $name)
. " to the section “$toc”.");
print $q->start_form(-method=>'get');
print $q->p($q->label({-for=>'name', -style=>'display: inline-block; width:30ex'},
T('Use a different link name:')) . ' '
. $q->textfield(-style=>'display: inline-block; width:60ex',
-name=>'name', -id=>'name', -size=>50, -default=>$name)
. $q->br()
. $q->label({-for=>'username', -style=>'display: inline-block; width:30ex'},
T('Your name for the log file:')) . ' '
. $q->textfield(-style=>'display: inline-block; width:60ex',
-name=>'username', -id=>'username', -size=>50));
my $star = $q->img({-src=>'http://www.emacswiki.org/pics/star.png', -class=>'smiley',
-alt=>'star'});
print '<p>Optionally: Do you want to rate it?<br />';
my $i = 0;
foreach my $label ($q->span({-style=>'display: inline-block; width:15ex'}, $star)
. 'I might use this for my next campaign',
$q->span({-style=>'display: inline-block; width:15ex'}, $star x 2)
. 'I have used this in a campaign and it worked as intended',
$q->span({-style=>'display: inline-block; width:15ex'}, $star x 3)
. 'I have used it in many of my campaigns',
$q->span({-style=>'display: inline-block; width:15ex'}, $star x 4)
. 'Everybody should give it a try',
$q->span({-style=>'display: inline-block; width:15ex'}, $star x 5)
. 'Everybody should use it, that is how awesome it is!') {
$i++;
print qq{<label><input type="radio" name="stars" value="$i" $checked/>$label</label><br />};
}
print '</p>';
print $q->hidden('url', $url);
print $q->hidden('toc', $toc);
print $q->hidden('confirm', 1);
print $q->submit('go', 'Continue');
print $q->end_form();
} else {
post_addition($q->param('name'), $url, $toc);
sub confirm {
my ($url, $name, $toc) = @_;
print $q->p("Please confirm that you want to add "
. GetUrl($url, $name)
. " to the section “$toc”.");
print $q->start_form(-method=>'get');
print $q->p($q->label({-for=>'name', -style=>'display: inline-block; width: 15em'},
T('Use a different link name:')) . ' '
. $q->textfield(-style=>'display: inline-block; width:50ex',
-name=>'name', -id=>'name', -size=>50, -default=>$name)
. $q->br()
. $q->label({-for=>'summary', -style=>'display: inline-block; width:15em'},
T('An optional short summary:')) . ' '
. $q->textfield(-style=>'display: inline-block; width:50ex',
-name=>'summary', -id=>'summary', -size=>50)
. $q->br()
. $q->label({-for=>'username', -style=>'display: inline-block; width:15em'},
T('Your name for the log file:')) . ' '
. $q->textfield(-style=>'display: inline-block; width:50ex',
-name=>'username', -id=>'username', -size=>50));
my $star = $q->img({-src=>$stardata, -class=>'smiley', -alt=>'☆'});
print '<p>Optionally: Do you want to rate it?<br />';
my $i = 0;
foreach my $label ($q->span({-style=>'display: inline-block; width:3em'}, $star)
. 'I might use this for my campaign',
$q->span({-style=>'display: inline-block; width:3em'}, $star x 2)
. 'I have used this in a campaign and it worked as intended',
$q->span({-style=>'display: inline-block; width:3em'}, $star x 3)
. 'I have used this in a campaign and it was ' . $q->em('great')) {
$i++;
print qq{<label><input type="radio" name="stars" value="$i" $checked/>$label</label><br />};
}
print '</p>';
print $q->hidden('url', $url);
print $q->hidden('toc', $toc);
print $q->hidden('confirm', 1);
print $q->submit('go', 'Continue');
print $q->end_form();
}
# returns unquoted html
sub get_name {
my $url = shift;
my $tree = HTML::TreeBuilder->new_from_content(GetRaw($url));
my $h = $tree->look_down('_tag', 'h1');
$h = $tree->look_down('_tag', 'title') unless $h;
my $h = $tree->look_down('_tag', 'title');
$h = $tree->look_down('_tag', 'h1') unless $h;
$h = $h->as_text if $h;
return $h;
}
sub post_addition {
my ($name, $url, $toc) = @_;
my ($url, $name, $toc, $summary) = @_;
my $id = FreeToNormal($name);
my $display = $name;
utf8::decode($display); # we're dealing with user input
utf8::decode($summary); # we're dealing with user input
print $q->p("Adding ", GetUrl($url, $display), " to “$toc”.");
# start with the homepage
my @pages = GetPageContent($HomePage) =~ /\* \[\[(.*?)\]\]/g;
for my $id (@pages) {
return post($id, undef, $name, $url, GetParam('stars', '')) if $id eq $toc;
return post($id, undef, $name, $summary, $url, GetParam('stars', '')) if $id eq $toc;
my $data = GetPageContent(FreeToNormal($id));
while ($data =~ /(\*+ ([^][\n]*))$/mg) {
return post($id, $1, $name, $url, GetParam('stars', '')) if $2 eq $toc;
return post($id, $1, $name, $summary, $url, GetParam('stars', '')) if $2 eq $toc;
}
}
print $q->p("Whoops. I was unable to find “$toc” in the wiki. Sorry!");
}
sub post {
my ($id, $toc, $name, $url, $stars) = @_;
my ($id, $toc, $name, $summary, $url, $stars) = @_;
my $data = GetPageContent(FreeToNormal($id));
my $re = quotemeta($url);
if ($data =~ /$re\s+(.*?)\]/) {
my $display = $1;
print $q->p($q->strong("Oops, we seem to have a problem!"));
print $q->p(GetPageLink(NormalToFree($id)),
" already links to the URL you submitted:",
GetUrl($url, $display));
return;
}
$stars = ' ' . (':star:' x $stars) if $stars;
$summary = ': ' . $summary if $summary;
if ($toc) {
$toc =~ /^(\*+)/;
my $depth = "*$1"; # one more!
my $regexp = quotemeta($toc);
$data =~ s/$regexp/$toc\n$depth \[$url $name\]$stars/;
$data =~ s/$regexp/$toc\n$depth \[$url $name\]$summary$stars/;
} else {
$data = "* [$url $name]$stars\n" . $data;
$data = "* [$url $name]$summary$stars\n" . $data;
}
my $ua = LWP::UserAgent->new;
my %params = (text => $data,
@@ -173,30 +237,68 @@ sub post {
}
}
sub main {
$ConfigFile = "$DataDir/config"; # read the global config file
$DataDir = "$DataDir/$wiki"; # but link to the local pages
Init(); # read config file (no modules!)
$ScriptName = $site; # undo setting in the config file
binmode(STDOUT,':utf8');
$q->charset('utf8');
if ($q->path_info eq '/source') {
seek DATA, 0, 0;
print "Content-type: text/plain; charset=UTF-8\r\n\r\n", <DATA>;
} else {
$UserGotoBar = $q->a({-href=>$q->url . '/source'}, 'Source');
print GetHeader('', 'Submit a new link');
print $q->start_div({-class=>'content index'});
if (not GetParam('url')) {
default();
} else {
check_url(GetParam('url'));
}
sub print_end_of_page {
print $q->p('Questions? Send mail to Alex Schroeder <'
. $q->a({-href=>'mailto:kensanata@gmail.com'},
'kensanata@gmail.com') . '>');
print $q->end_div();
PrintFooter();
}
sub main {
$ConfigFile = "$DataDir/config"; # read the global config file
$DataDir = "$DataDir/$wiki"; # but link to the local pages
Init(); # read config file (no modules!)
$ScriptName = $site; # undo setting in the config file
$FullUrl = $site; #
binmode(STDOUT,':utf8');
$q->charset('utf8');
if ($q->path_info eq '/source') {
seek DATA, 0, 0;
print "Content-type: text/plain; charset=UTF-8\r\n\r\n", <DATA>;
} elsif ($q->path_info eq '/structure') {
my ($values, $labels) = toc();
my @indented = map {
($labels->{$_} || $_) =~ /^(*)/;
[$_, length($1)]
} @$values;
print "Content-type: application/json; charset=UTF-8\r\n\r\n";
binmode(STDOUT,':raw'); # because of encode_json
print JSON::PP::encode_json(\@indented);
} elsif ($q->path_info eq '/toc') {
my ($values, $labels) = toc();
print "Content-type: application/json; charset=UTF-8\r\n\r\n";
binmode(STDOUT,':raw'); # because of encode_json
print JSON::PP::encode_json($values);
} elsif ($q->path_info eq '/top') {
print GetHeader('', 'Top Blogs');
print $q->start_div({-class=>'content top'});
print $q->ol($q->li(top()));
print_end_of_page();
} elsif ($q->path_info =~ '^/match/(.*)') {
my $term = $1;
print GetHeader('', "Entries Matching '$term'");
print $q->start_div({-class=>'content match'});
print $q->ol($q->li(match($term)));
print_end_of_page();
} else {
push(@UserGotoBarPages, 'Help');
$UserGotoBar = $q->a({-href=>$q->url . '/source'}, 'Source');
print GetHeader('', 'Submit a new link');
print $q->start_div({-class=>'content index'});
my $url = GetParam('url');
my $name = UnquoteHtml(GetParam('name', get_name($url)));
my $toc = GetParam('toc');
my $confirm = GetParam('confirm');
my $summary = GetParam('summary');
if (not $url or not $toc) {
default();
} elsif (not $confirm) {
confirm($url, $name, $toc);
} else {
post_addition($url, $name, $toc, $summary);
}
print_end_of_page();
}
}

View File

@@ -1,6 +1,6 @@
#! /usr/bin/perl
# Copyright (C) 2011 Alex Schroeder <alex@gnu.org>
# Copyright (C) 20112014 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
@@ -17,63 +17,62 @@
package OddMuse;
use LWP::UserAgent;
use HTML::TreeBuilder;
use utf8;
# load Oddmuse core
$RunCGI = 0;
do "wiki.pl";
# globals
my $wiki = 'BlogArchive';
my $site = "http://campaignwiki.org/wiki/$wiki";
# my $site = "http://localhost/wiki.pl";
my $home = "$site/HomePage";
$default_namespace = 'NameOfYourWiki';
main();
sub default {
print $q->p("Copy a blog article to the "
. $q->a({-href=>$home}, $wiki) . ".");
print $q->start_multipart_form(-method=>'get', -class=>'submit');
print $q->p($q->label({-for=>'url'}, T('URL:')) . ' '
. $q->textfield(-name=>'url', -id=>'url', -size=>50));
my ($url, $ns) = @_;
print $q->start_multipart_form(-method=>'get', -class=>'copy');
print $q->p("This script helps you copy of a blog post to your Campaign Wiki.");
print $q->p($q->label({-for=>'url', -style=>'display: inline-block; width: 20ex'}, 'Blog post URL:'),
$q->textfield(-name=>'url', -id=>'url', -size=>50),
$q->br(),
$q->label({-for=>'ns', -style=>'display: inline-block; width: 20ex'}, 'Name of your wiki:'),
$q->textfield(-name=>'ns', -id=>'ns', -size=>50, -default=>$default_namespace));
if ($url and not $ns) {
print $q->p($q->em('Please provide the name of your wiki. It is mandatory. Use “NameOfYourWiki” if you just want to test something.'));
}
print $q->submit('go', 'Go!');
print $q->end_form();
print $q->p("Please make sure youre only submitting your own articles",
"or articles with an appropriate license.");
print $q->p("Drag this bookmarklet to your bookmarks bar for easy access:",
$q->a({-href=>q{javascript:location='http://campaignwiki.org/copy?url='+encodeURIComponent(window.location.href)}}, $wiki) . ".");
$q->a({-href=>q{javascript:location='http://campaignwiki.org/copy?url='+encodeURIComponent(window.location.href)}}, 'Copy Blog Post') . ".");
}
sub check_url {
my $url = shift;
print $q->p("Looking at ", $q->a({-href=>$url}, $url));
my ($name, $data) = get_data($url);
$name = GetParam('name', $name);
if (name_exists($name) and not GetParam('confirm', 0)) {
print $q->p("We already have a page with that name: ",
$q->a({-href=>$duplicate}, $duplicate));
print $q->start_multipart_form(-method=>'get', -class=>'submit');
print $q->p($q->label({-for=>'name'}, T('New name:')) . ' '
. $q->textfield(-name=>'name', -id=>'name', -size=>50,
-default=>$name));
print $q->hidden('url', $url);
print $q->hidden('confirm', 1);
print $q->submit('go', 'Continue');
print $q->end_form();
} elsif (not GetParam('confirm', 0)) {
print $q->p("Please confirm that you want to copy this article to the wiki.");
print $q->start_multipart_form(-method=>'get', -class=>'submit');
print $q->p($q->label({-for=>'name'}, T('Name:')) . ' '
. $q->textfield(-name=>'name', -id=>'name', -size=>50,
-default=>$name));
print $q->hidden('url', $url);
print $q->hidden('confirm', 1);
print $q->submit('go', 'Continue');
print $q->end_form();
} else {
post_addition($name, $data, $url);
}
sub confirm_overwrite {
my ($url, $ns, $name) = @_;
print $q->p("We already have a page with that name: ", GetPageLink($name));
print $q->start_multipart_form(-method=>'get', -class=>'submit');
print $q->p($q->label({-for=>'name'}, T('New name:')) . ' '
. $q->textfield(-name=>'name', -id=>'name', -size=>50, -default=>$name));
print $q->hidden('url', $url);
print $q->hidden('ns', $ns);
print $q->hidden('confirm', 1);
print $q->submit('go', 'Continue');
print $q->end_form();
}
sub confirm_save {
my ($url, $ns, $name) = @_;
my $ns = GetParam('ns', $default_namespace);
print $q->p("Please confirm that you want to copy",
$q->a({-href=>$url}, "this article"), "to", GetPageLink($HomePage, $ns) . ".");
print $q->start_multipart_form(-method=>'get', -class=>'submit');
print $q->p($q->label({-for=>'name'}, T('Name:')) . ' '
. $q->textfield(-name=>'name', -id=>'name', -size=>50, -default=>$name));
print $q->hidden('url', $url);
print $q->hidden('ns', $ns);
print $q->hidden('confirm', 1);
print $q->submit('go', 'Continue');
print $q->end_form();
}
sub get_data {
@@ -82,24 +81,32 @@ sub get_data {
my $h = $tree->look_down('_tag', 'h1');
$h = $tree->look_down('_tag', 'title') unless $h;
$h = $h->as_text if $h;
my $b = $tree->look_down('_tag', 'body');
if ($b = $tree->look_down('_tag', 'div',
'class', qr/post-body/)) {
# blogspot
my $b;
if ($b = $tree->look_down('_tag', 'div', 'class', qr/post-body/)) {
# Blogspot
$b = html($b);
} elsif ($b = $tree->look_down('_tag', 'div', 'class', qr/content/)) {
# Oddmuse
$b = html($b);
} else {
# no idea, just get the text
$b = $b->as_text if $b;
# default: get it all
$b = html($tree->look_down('_tag', 'body'));
}
# common illegal character for page names
$h =~ s/:/,/g;
return ($h, $b);
}
sub html {
my $tree = shift;
my ($tree, $p) = @_;
# $p indicates whether we need an empty line or not
my $str;
for my $element ($tree->content_list()) {
if (not ref $element) {
$str .= $element;
} elsif ($element->tag() eq 'p') {
$str .= ($p == 1 ? "\n\n" : "") . html($element);
$p = 1;
} elsif ($element->tag() eq 'br') {
$str .= "\n\n";
} elsif ($element->tag() eq 'span'
@@ -107,6 +114,20 @@ sub html {
$str .= "[b]" . html($element) . "[/b]";
} elsif ($element->tag() =~ m/^(b|i|h[1-6])$/) {
$str .= "[$1]" . html($element) . "[/$1]";
} elsif ($element->tag() eq 'a'
and $element->attr('href')) {
$str .= "[url=" . $element->attr('href') . "]" . html($element) . "[/url]";
} elsif ($element->tag() eq 'img'
and $element->attr('src')) {
$str .= "[img]" . $element->attr('src') . "[/img]";
} elsif ($element->tag() eq 'pre') {
$str .= "\n\n[code]\n" . $element->as_text() . "\n[/code]";
$p = 1;
} elsif ($element->tag() eq 'div'
and ($element->attr('style') =~ /float: *(left|right)/
or $element->attr('style') =~ /text-align: *(center)/)) {
$str .= "\n[$1]" . html($element) . "[/$1]";
$p = 1;
} else {
$str .= html($element);
}
@@ -123,25 +144,25 @@ sub name_exists {
}
sub post_addition {
my ($name, $data, $url) = @_;
my ($url, $ns, $name, $data) = @_;
my $id = FreeToNormal($name);
print $q->p("Adding ", $q->a({-href=>$url}, $name));
print $q->p("Copying ", $q->a({-href=>$url}, "the blog post") . "…");
my $text = "Based on [$url $name].\n----\n" . $data;
my $ua = LWP::UserAgent->new;
my %params = (text => $text,
title => $id,
summary => $name,
username => GetParam('username'),
ns => $ns,
pwd => GetParam('pwd'));
$params{$QuestionaskerSecretKey} = 1 if $QuestionaskerSecretKey;
my $response = $ua->post($site, \%params);
my $response = $ua->post($FullUrl, \%params);
if ($response->is_error) {
print $q->p("The submission failed!");
print $q->pre($response->status_line . "\n"
. $response->content);
print $q->p("Copying failed!");
print $q->p($q->strong($response->status_line));
print $response->content;
} else {
print $q->p("See for yourself: ",
$q->a({-href=>"$site/$id"}, $name));
print $q->p("Your copy: ", GetPageLink($name) . ".");
}
}
@@ -152,12 +173,22 @@ sub main {
print "Content-type: text/plain; charset=UTF-8\r\n\r\n", <DATA>;
} else {
$UserGotoBar .= $q->a({-href=>$q->url . '/source'}, 'Source');
print GetHeader('', 'Submit a new blog article');
print GetHeader('', 'Copy a blog article');
print $q->start_div({-class=>'content index'});
if (not GetParam('url')) {
default();
my $url = GetParam('url');
my $ns = GetParam('ns');
if (not $url or not $ns) {
default($url, $ns);
} else {
check_url(GetParam('url'));
my ($name, $data) = get_data($url);
$name = GetParam('name', $name);
if (name_exists($name) and not GetParam('confirm', 0)) {
confirm_overwrite($url, $ns, $name);
} elsif (not GetParam('confirm', 0)) {
confirm_save($url, $ns, $name);
} else {
post_addition($url, $ns, $name, $data);
}
}
print $q->p('Questions? Send mail to Alex Schröder <'
. $q->a({-href=>'mailto:kensanata@gmail.com'},

0
contrib/campaignwiki/monster-tag.pl Normal file → Executable file
View File

215
contrib/campaignwiki/submit.pl Normal file → Executable file
View File

@@ -1,6 +1,6 @@
#!/usr/bin/perl
# Copyright (C) 2010 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2010, 2012 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
@@ -17,6 +17,7 @@
package OddMuse;
use URI;
use LWP::UserAgent;
use utf8;
# load Oddmuse core
$RunCGI = 0;
@@ -61,16 +62,16 @@ sub parse_blogs {
return %cached_blogs if %cached_blogs;
my @data = split(/\n/, GetRaw($src));
my $url;
my $name;
my $paramref;
foreach $_ (@data) {
if (/^\[(.+)\]/) {
$url = $1;
$name = undef;
} elsif (/^name *= *(.+)/) {
$name = $1;
$paramref = {};
} elsif (/^([a-z_]+) *= *(.+)/) {
$paramref->{$1} = $2;
}
if ($url && $name) {
$cached_blogs{$url} = $name;
if ($url && $paramref->{name}) {
$cached_blogs{$url} = $paramref;
}
}
return %cached_blogs;
@@ -84,8 +85,16 @@ sub host_exists {
}
}
sub debug_url {
my $url = $q->url(-path_info=>1) . "?debug=1;";
$url .= join(";", map { $_ . "=" . GetParam($_) }
qw(username confirmed candidate url));
return $url;
}
sub check_url {
my $url = shift;
print $q->p("Debug: url=$url") if GetParam("debug");
my $frown = $q->img({-src=>"http://emacswiki.org/pics/smiles/sad.png",
-alt=>":("});
my $smile = $q->img({-src=>"http://emacswiki.org/pics/smiles/smile.png",
@@ -97,26 +106,24 @@ sub check_url {
$u = URI->new($url);
eval {$u->host };
}
# - not an url
# - it's campaign wiki site
# - no username
# or read Feeds page and
# - it's a duplicate
# - it's a partial match: continue with confirmed=1
# or read the list of alternatives from the url
# - one of the feeds listed is known: continue with confirmed=2
# - no feeds were listed: url is a feed or report it
# - one feed was listed: try it
# - some feeds were listed: pick one
if ($@) {
# the prefixing of http:// above should make it really hard to reach this code
print $q->p($q->a({-href=>$url}, $url) . qq{
seems to be <strong>invalid</strong>. $frown Make sure you use something
like the following: <tt>http://grognardia.blogspot.com/</tt>});
} elsif (not GetParam('username', '')) {
print $q->p(qq{As an anti-spam measure I'd really like you to <strong>provide a name</strong> for the log file. Sorry about that. $frown});
} else {
my %blogs = parse_blogs();
my $duplicate = host_exists($u->host, %blogs);
if ($duplicate
&& !$blogs{$url}
&& !GetParam('confirmed')) {
print $q->p("We have a partial match: ",
$q->a({-href=>$duplicate}, $duplicate));
print GetFormStart();
print $q->hidden('confirmed', 1);
print $q->hidden('url', $url);
print $q->submit('go', 'Proceed anyway!');
print $q->end_form();
} elsif ($url =~ /campaignwiki\.org/i) {
print $q->p(qq{
This looks <strong>familiar</strong>!
@@ -124,17 +131,35 @@ I do not think that adding any of the wikis on this site is the right
thing to do, though.});
print $q->p(qq{Thanks for testing it. }
. $q->img({-src=>"http://www.emacswiki.org/pics/grin.png"}));
} elsif (not GetParam('username', '')) {
print $q->p(qq{As an anti-spam measure I'd really like you to
<strong>provide a name</strong> for the log file. Sorry about that. $frown});
} else {
my %blogs = parse_blogs();
my $duplicate = host_exists($u->host, %blogs);
if ($blogs{$url}) {
print $q->p("We already list ",
$q->a({-href=>$duplicate}, $duplicate));
} elsif ($duplicate && !GetParam('confirmed')) {
print $q->p("We have a partial match: ",
$q->a({-href=>$duplicate}, $duplicate));
print GetFormStart();
print $q->hidden('confirmed', 1);
print $q->hidden('url', $url);
print $q->submit('go', 'Proceed anyway!');
print $q->end_form();
} else {
my @alternatives = get_feeds($url, keys %blogs);
if ($#alternatives > 0 && !GetParam('candidate')) {
my ($status, @alternatives) = get_feeds($url, %blogs);
if ($status eq 'known' && GetParam('confirmed') < 2) {
print $q->p($q->a({-href=>$url},
"The page you submitted")
. " lists "
. $q->a({-href=>$alternatives[0]},
"a known feed") . ".");
print GetFormStart();
print $q->hidden('confirmed', 1);
print $q->hidden('confirmed', 2);
print $q->hidden('url', $url);
print $q->p("You need to pick one of the candidates:");
print $q->p(join($q->br(), map {
$q->input({-type=>"radio", -name=>"candidate", -value=>$_},
$q->a({-href=>$_}, QuoteHtml($_))) } @alternatives));
print $q->submit('go', 'Submit');
print $q->submit('go', 'Proceed anyway!');
print $q->end_form();
} elsif ($#alternatives < 0) {
if (is_feed($url)) {
@@ -143,20 +168,31 @@ thing to do, though.});
print $q->p("Apparently " . $q->a({-href=>$url}, QuoteHtml($url))
. " is not a feed and doesn't link to any feed. "
. "There is nothing for me to add. " . $frown);
print $q->p("If you feel like it, you could try to "
. $q->a({-href=>debug_url()}, "debug")
. " this.");
}
} elsif ($#alternatives == 0) {
print $q->p($q->a({-href=>$url}, "The page you submitted")
. " lists "
. $q->a({-href=>$alternatives[0]},
"one new feed")
. ".");
print GetFormStart();
print $q->hidden('url', $alternatives[0]);
print $q->submit('go', 'Take it!');
print $q->end_form();
print $q->p("If you feel like it, you could try to "
. $q->a({-href=>debug_url()}, "debug")
. " this.");
} else {
my $candidate = GetParam('candidate');
$candidate = $alternatives[0] unless $candidate;
if (is_feed($candidate)) {
post_addition($candidate);
} else {
print $q->p($q->a({-href=>$candidate}, "The page you submitted")
. " listed "
. $q->a({-href=>$candidate}, QuoteHtml($candidate))
. " as one of its feeds. "
. "But it turns out that this is not a valid feed! "
. "I can't add an invalid feed. " . $frown);
}
print GetFormStart();
print $q->p("You need to pick one of the candidates:");
print $q->p(join($q->br(), map {
$q->input({-type=>"radio", -name=>"url", -value=>$_},
$q->a({-href=>$_}, QuoteHtml($_))) } @alternatives));
print $q->submit('go', 'Submit');
print $q->end_form();
}
}
}
@@ -172,23 +208,73 @@ sub is_feed {
sub get_feeds {
my $url = shift;
my %others = map { $_ => 1 } @_;
my @links = GetRaw($url) =~ /<link\b *(.*?)>/g;
my %others = @_;
my $html = GetRaw($url);
my @links = $html =~ /<link\b *(.*?)>/g;
print $q->p("Debug: " . scalar(@links) . " links found") if GetParam("debug");
print $q->pre($html) unless scalar(@links);
print $q->p("Debug: no content returned") if GetParam("debug") and not $html;
my @feeds;
foreach my $link (@links) {
my %link;
foreach (split(/ /, lc($link))) {
my ($attr, $val) = split(/=/, $_, 2);
# strip quotes and garbage: "foo"/ -> foo
my $to = index($val, substr($val, 0, 1), 1);
$val = substr($val, 1, $to -1) if $to >= 0;
$link{$attr} = $val;
print $q->p("Debug: $link")
if GetParam("debug");
if ($link !~ /\brel=(['"])alternate\1/i) {
print $q->p("Debug: missing rel='alternate'")
if GetParam("debug");
next;
}
next unless $link{rel} eq 'alternate';
next unless $valid_content_type{$link{type}};
push(@feeds, $link{href}) unless $others{$link{href}};
$link =~ /\btype=(['"])(.*?)\1/i;
my $type = $2;
if (not $valid_content_type{$type}) {
print $q->p("Debug: type parameter is invalid ($type)")
if GetParam("debug");
next;
}
$link =~ /\bhref=(['"])(.*?)\1/i;
my $href = $2;
# clean up blogspot urls and prefer atom format
$href =~ s/\?alt=rss$//i if $href =~ /blogspot/i;
if (not $href) {
print $q->p("Debug: href missing")
if GetParam("debug");
next;
}
if ($others{$href}) {
print $q->p("Debug: feed already known ($href)")
if GetParam("debug");
if ($q->param('confirmed') >= 2) {
next;
} else {
# don't look for other alternatives!
return 'known', $href;
}
}
push(@feeds, $href);
}
return @feeds;
print $q->p("Debug: returning " . scalar(@feeds) . " links found")
if GetParam("debug");
return 'ok', @feeds;
}
sub config {
my %blogs = @_;
my $result = qq{#! config file for the RPG Planet
# format:
# Feed URL in square brackets, followed by name = and the name of the feed
};
foreach my $url (sort {lc($blogs{$a}->{name}) cmp lc($blogs{$b}->{name})} keys %blogs) {
$result .= "[$url]\n";
$paramref = $blogs{$url};
foreach my $key (sort keys %{$paramref}) {
$result .= $key . " = " . $paramref->{$key} . "\n";
}
}
return $result;
}
sub post_addition {
@@ -206,14 +292,9 @@ sub post_addition {
$title = $final_url unless $title;
print $q->p("Adding ",
$q->a({-href=>$final_url}, $title));
$blogs{$url} = $title;
my $result = qq{#! config file for the RPG Planet
# format:
# Feed URL in square brackets, followed by name = and the name of the feed
};
foreach $url (sort {lc($blogs{$a}) cmp lc($blogs{$b})} keys %blogs) {
$result .= "[$url]\nname = " . $blogs{$url} . "\n";
}
my %param = (name => $title);
$blogs{$url} = \%param;
my $result = config(%blogs);
my $ua = LWP::UserAgent->new;
my %params = (text => $result,
title => $page,
@@ -250,16 +331,18 @@ sub main {
if ($q->path_info eq '/source') {
seek DATA, 0, 0;
print "Content-type: text/plain; charset=UTF-8\r\n\r\n", <DATA>;
} elsif ($q->path_info eq '/test') {
print "Content-type: text/plain; charset=UTF-8\r\n\r\n";
print config(parse_blogs());
} else {
$UserGotoBar .= $q->a({-href=>$q->url . '/source'}, 'Source');
print GetHeader('', 'Submit a new blog');
print $q->start_div({-class=>'content index'});
if (not GetParam('url')
or not GetParam($HoneyPotOk)) {
if (not GetParam('url')) {
print $q->p("Debug: no url parameter provided.") if GetParam("debug");
default();
} else {
SetParam('title', 'Feeds'); # required to trigger HoneyPotInspection()
HoneyPotInspection();
check_url(GetParam('url'));
}
print $q->p('Questions? Send mail to Alex Schröder <'

View File

@@ -1,21 +1,17 @@
#!/usr/bin/perl
# Copyright (C) 2005, 2006, 2007 Alex Schroeder <alex@emacswiki.org>
# Copyright (C) 2005, 2006, 2007, 2012 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 2 of the License, or
# (at your option) any later version.
# 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.
# 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, write to the
# Free Software Foundation, Inc.
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
use strict;
use warnings;
@@ -38,6 +34,42 @@ my %indexes = (
=> 'GNU Emacs Lisp reference manual, Index',
'http://www.gnu.org/software/emacs/manual/html_node/elisp/index.html'
=> 'GNU Emacs Lisp reference manual, Top Menu',
'http://www.gnu.org/software/emacs/manual/html_node/message/Index.html'
=> 'Message Manual, Index',
'http://www.gnu.org/software/emacs/manual/html_node/gnus/Index.html'
=> 'The Gnus Newsreader, Index',
'http://www.gnu.org/software/emacs/manual/html_node/cl/Function-Index.html'
=> 'Common Lisp Extensions, Function Index',
'http://www.gnu.org/software/emacs/manual/html_node/ccmode/Variable-Index.html'
=> 'CC Mode Manual, Variable Index',
'http://www.gnu.org/software/emacs/manual/html_node/ccmode/Concept-and-Key-Index.html'
=> 'CC Mode Manual, Command and Function Index',
'http://www.gnu.org/software/emacs/manual/html_node/org/Index.html'
=> 'Org Mode Manual, Index',
'http://www.gnu.org/software/auctex/manual/auctex/Function-Index.html'
=> 'AUCTeX Manual, Function Index',
'http://www.gnu.org/software/auctex/manual/auctex/Variable-Index.html'
=> 'AUCTeX Manual, Variable Index',
'http://www.gnu.org/software/auctex/manual/auctex/Concept-Index.html'
=> 'AUCTeX Manual, Concept Index',
'http://www.gnu.org/software/texinfo/manual/texinfo/html_node/index.html'
=> 'Texinfo, Command and Variable Index',
'http://www.gnu.org/software/texinfo/manual/texinfo/html_node/General-Index.html'
=> 'Texinfo, General Index',
'http://www.gnu.org/software/texinfo/manual/info/html_node/Index.html'
=> 'Info, Index',
'http://www.gnu.org/software/emacs/manual/html_node/dired-x/Command-Index.html'
=> 'Dired Extra, Function Index',
'http://www.gnu.org/software/emacs/manual/html_node/dired-x/Variable-Index.html'
=> 'Dired Extra, Variable Index',
'http://www.gnu.org/software/coreutils/manual/html_node/Concept-index.html'
=> 'Coreutils, Index',
'http://www.gnu.org/software/diffutils/manual/html_node/Index.html'
=> 'Diffutils, Index',
'http://www.gnu.org/software/findutils/manual/html_node/find_html/Primary-Index.html'
=> 'Findutils, Primary Index',
'http://www.gnu.org/software/emacs/manual/html_node/ediff/Index.html'
=> 'Edfiff, Index',
);
my $db = '/org/org.emacswiki/htdocs/emacs/info-ref.dat';
@@ -63,7 +95,9 @@ sub ProcessRequest {
sub ShowForm {
print $q->header, $q->start_html,
$q->start_form, "Index entry: ", $q->textfield('find'), $q->submit, $q->end_form,
$q->p('$Id: info-ref,v 1.1 2007/07/13 23:20:57 as Exp $'),
$q->p($q->a({-href=>"http://www.emacswiki.org/scripts/info-ref"}, "Source"), $q->br(),
'Last DB update: ', TimeToText((stat($db))[9]),
' (' . $q->a({-href=>$q->url . '?init=1'}, "update") . ')'),
$q->end_html;
}
@@ -74,9 +108,11 @@ sub Find {
foreach my $line (split(/$nl/, $data)) {
my ($key, $rest) = split(/$fs/, $line);
$map{$key} = ();
foreach my $a (split(/$gs/, $rest)) {
my ($link, $label) = split(/$rs/, $a);
$map{$key}{$link} = $label;
if ($rest) {
foreach my $a (split(/$gs/, $rest)) {
my ($link, $label) = split(/$rs/, $a);
$map{$key}{$link} = $label;
}
}
}
my @links = keys %{$map{$str}};
@@ -150,7 +186,7 @@ sub GetRaw {
return unless eval { require LWP::UserAgent; };
my $ua = LWP::UserAgent->new;
my $response = $ua->get($uri);
return $response->content;
return $response->decoded_content;
}
sub ReadFile {
@@ -189,3 +225,18 @@ sub ReportError { # fatal!
print $q->start_html, $q->h2($errmsg), $q->end_html;
exit (1);
}
sub CalcDay {
my ($sec, $min, $hour, $mday, $mon, $year) = gmtime(shift);
return sprintf('%4d-%02d-%02d', $year+1900, $mon+1, $mday);
}
sub CalcTime {
my ($sec, $min, $hour, $mday, $mon, $year) = gmtime(shift);
return sprintf('%02d:%02d UTC', $hour, $min);
}
sub TimeToText {
my $t = shift;
return CalcDay($t) . ' ' . CalcTime($t);
}

1054
contrib/oddmuse-curl.el Normal file

File diff suppressed because it is too large Load Diff

108
contrib/oddmuse_stats Executable file
View 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";
}

51
contrib/twitter Normal file
View File

@@ -0,0 +1,51 @@
#!/usr/bin/perl
# Copyright (C) 2009, 2012 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/>.
use CGI qw/:standard/;
use CGI::Carp qw(fatalsToBrowser);
use LWP::UserAgent;
use XML::RSS;
if (not param('feed')) {
print header(),
start_html('Description Stripping'),
h1('Description Stripping'),
p('Removes the description of an article if it matches the title. This is most useful for Twitter and other microblogging services.'),
p('Example input:', code('http://api.twitter.com/1/statuses/user_timeline.rss?screen_name=kensanata')),
start_form(-method=>'GET'),
p('Feed: ', textfield('feed', '', 40), checkbox('Strip username'),
submit()),
end_form(),
end_html();
exit;
}
$ua = LWP::UserAgent->new;
$request = HTTP::Request->new('GET', param('feed'));
$response = $ua->request($request);
$data = $response->content;
exit unless $data;
print header(-type=>$response->content_type);
$rss = new XML::RSS;
$rss->parse($data);
foreach my $i (@{$rss->{items}}) {
$i->{description} = undef if $i->{description} eq $i->{title};
$i->{title} =~ s/^.*?: // if param('Strip username');
}
print $rss->as_string;

168
contrib/vc-oddmuse.el Normal file
View File

@@ -0,0 +1,168 @@
;;; vc-oddmuse.el -- add VC support to oddmuse-curl
;;
;; Copyright (C) 2014 Alex Schroeder <alex@gnu.org>
;;
;; Latest version:
;; http://git.savannah.gnu.org/cgit/oddmuse.git/plain/contrib/vc-oddmuse.el
;; Discussion, feedback:
;; http://www.emacswiki.org/cgi-bin/wiki/OddmuseCurl
;;
;; 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; Add the following to your init file:
;;
;; (add-to-list 'vc-handled-backends 'oddmuse)
(add-to-list 'vc-handled-backends 'oddmuse)
(require 'oddmuse-curl)
(require 'diff)
(defun vc-oddmuse-revision-granularity () 'file)
(defun vc-oddmuse-registered (file)
"Handle files in `oddmuse-directory'."
(string-match (concat "^" (expand-file-name oddmuse-directory))
(file-name-directory file)))
(defun vc-oddmuse-state (file)
"Return the current version control state of FILE.
For a list of possible values, see `vc-state'."
;; Avoid downloading the current version from the wiki and comparing
;; the text: Too much traffic!
'edited)
(defun vc-oddmuse-working-revision (file)
"The current revision based on `oddmuse-revisions'."
(oddmuse-revision-get oddmuse-wiki oddmuse-page-name))
(defun vc-oddmuse-checkout-model (files)
"No locking."
'implicit)
(defun vc-oddmuse-create-repo (file)
(error "You cannot create Oddmuse wikis using Emacs."))
(defun vc-oddmuse-register (files &optional rev comment)
"This always works.")
(defun vc-oddmuse-revert (file &optional contents-done)
"No idea"
nil)
(defvar vc-oddmuse-log-command
(concat "curl --silent %w"
" --form action=rc"
" --form showedit=1"
" --form all=1"
" --form from=1"
" --form raw=1"
" --form match='%r'")
"Command to use for publishing index pages.
It must print the page to stdout.
See `oddmuse-format-command' for the formatting options.")
(defun vc-oddmuse-print-log (files buffer &optional shortlog start-revision limit)
"Load complete recent changes for the files."
;; Derive `oddmuse-wiki' from the first file
(with-oddmuse-file (car files)
;; The wiki expects a Perl regular expression!
(let ((regexp (concat "^(" (mapconcat 'file-name-nondirectory files "|") ")$")))
(oddmuse-run "Getting recent changes" vc-oddmuse-log-command nil nil buffer)))
(with-current-buffer buffer
(oddmuse-render-rss3))
'limit-unsupported)
(defun vc-oddmuse-log-outgoing ()
(error "This is not supported."))
(defun vc-oddmuse-log-incoming ()
(error "This is not supported."))
(defvar vc-oddmuse-get-revision-command
(concat "curl --silent"
" --form action=browse"
" --form id=%t"
" --form revision=%v"
" --form raw=1"
" '%w'")
"Command to use to get older revisions of a page.
It must print the page to stdout.
%? '?' character
%w URL of the wiki as provided by `oddmuse-wikis'
%t Page title as provided by `oddmuse-page-name'
%v Revision to retrieve as provided by `oddmuse-revision'")
(defun oddmuse-revision-filename (rev)
"Return filename for revision REV.
This uses `oddmuse-directory', `wiki' and `pagename' as bound by
`with-oddmuse-file'."
(concat oddmuse-directory
"/" wiki
"/" pagename
".~" rev "~"))
(defun vc-oddmuse-diff (files &optional rev1 rev2 buffer)
"Report the differences for FILES."
(setq buffer (or buffer (get-buffer-create "*vc-diff*")))
(dolist (file files)
(with-oddmuse-file file
(setq rev1 (or rev1 (oddmuse-get-latest-revision wiki pagename)))
(dolist (rev (list rev1 rev2))
(when (and rev (not (file-readable-p (oddmuse-revision-filename rev))))
(let* ((oddmuse-revision rev)
(command vc-oddmuse-get-revision-command)
(filename (oddmuse-revision-filename rev)))
(with-temp-buffer
(oddmuse-run
(concat "Downloading revision " rev)
command wiki pagename)
(write-file filename)))))
(diff-no-select
(if rev1 (oddmuse-revision-filename rev1) file)
(if rev2 (oddmuse-revision-filename rev2) file)
nil
(vc-switches 'oddmuse 'diff)
buffer))))
(defun vc-oddmuse-revert (file &optional contents-done)
"Revert FILE back to the wiki revision.
If optional arg CONTENTS-DONE is non-nil, then nothing needs to
be done, as the contents of FILE have already been reverted from
a version backup."
(unless contents-done
(with-oddmuse-file file
(let ((command (oddmuse-format-command vc-oddmuse-get-revision-command)))
(with-temp-buffer
(oddmuse-run "Loading" command)
(write-file file))))))
(defun vc-oddmuse-checkin (files rev comment)
"Commit changes in FILES to this backend.
REV is a historical artifact and should be ignored. COMMENT is
used as a check-in comment."
(dolist (file files)
(with-oddmuse-file file
(let* ((summary comment)
(command (oddmuse-format-command oddmuse-post-command))
(buf (get-buffer-create " *oddmuse-response*")))
(with-temp-buffer
(insert-file-contents file)
(oddmuse-run "Posting" command wiki pagename buf t 302))))))
(provide 'vc-oddmuse)

View File

@@ -1,15 +1,18 @@
@font-face {
font-family: 'Garamond';
font-style: normal;
font-weight: 400;
src: local('Garamond'), local('GaramondNo8'), local('EB Garamond'), local('EBGaramond'), url(https://themes.googleusercontent.com/static/fonts/ebgaramond/v4/kYZt1bJ8UsGAPRGnkXPeFdIh4imgI8P11RFo6YPCPC0.woff) format('woff');
}
body, rss {
font-family: Garamond, GaramondNo8, "Bookman Old Style", Cochin, Baskerville, serif;
font-family: Garamond, serif;
font-size: 16pt;
line-height: 20pt;
margin:1em 3em;
padding:0;
}
body.sans {
font-family: Franklin Gothic Book, Corbel, Arial, sans-serif;
}
/* 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. */
@@ -71,6 +74,55 @@ 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;
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;
}
/* stop floating content from flowing over the footer */
hr {
@@ -107,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. */
@@ -149,9 +210,6 @@ div.refer {
line-height: 13pt;
}
div.refer a:first-child:before { content: "" }
div.refer a:before { content: "• " }
div.message {
background-color:#fee;
color:#000;
@@ -179,7 +237,6 @@ div.sister hr {
}
div.sister img {
border:none;
background-color:#ffe;
}
div.near, div.definition {
@@ -197,9 +254,6 @@ div.sidebar ul {
/* replacements, features */
del {
color: #666;
}
ins {
color: #b33;
text-decoration: none;
@@ -232,9 +286,15 @@ div.commentshown {
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 span { display: block; }
.comment span label { display: inline-block; width: 10em; }
.comment form span { display: block; }
.comment form span label { display: inline-block; width: 10em; }
/* IE sucks */
.comment input#username,
.comment input#homepage,
@@ -334,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%; }
@@ -384,78 +448,78 @@ 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 {
/* no bleeding */
div.content, div.rc {
overflow:hidden;
}
}
} */
@media print {
body {
font-size: 12pt;
line-height: 13pt;
color: #000;
background-color: #fff;
}
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 {
display:none;
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;
color:inherit;
font-weight: bold;
}
div.content a.feed {
display: none;
display: none;
}
div.content a.book,
div.content a.movie {
text-decoration: none;
text-decoration: none;
}
a cite {
font-style: italic;
font-style: italic;
}
/* no difference */
pre, code, tt {
font-size: inherit;
line-height: inherit;
font-size: inherit;
line-height: inherit;
}
/* no dotted underlines */
acronym, abbr {
border: none;
text-decoration: none;
border: none;
text-decoration: none;
}
/* headings */
h1 {
color: inherit;
margin-top: 2em;
}
h2 {
color:inherit;
margin: 1em 0;
font-variant: small-caps;
}
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;
color: inherit;
margin-top: 2em;
}
h2 {
color:inherit;
margin: 1em 0;
font-variant: small-caps;
}
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;
}
}

632
css/alex-2014.css Normal file
View File

@@ -0,0 +1,632 @@
/* font-face includes TTF for PDF generation */
/* vietnamese */
@font-face {
font-family: 'Noticia Text';
font-style: normal;
font-weight: 400;
src: local('Noticia Text'), local('NoticiaText-Regular)'), url('/fonts/NoticiaText-Regular.woff') format('woff') url('/fonts/NoticiaText-Regular.ttf') format('truetype');
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Noticia Text';
font-style: normal;
font-weight: 400;
src: local('Noticia Text'), local('NoticiaText-Regular)'), url('/fonts/NoticiaText-Regular.woff') format('woff') url('/fonts/NoticiaText-Regular.ttf') format('truetype');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Noticia Text';
font-style: normal;
font-weight: 400;
src: local('Noticia Text'), local('NoticiaText-Regular)'), url('/fonts/NoticiaText-Regular.woff') format('woff') url('/fonts/NoticiaText-Regular.ttf') format('truetype');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
/* vietnamese */
@font-face {
font-family: 'Noticia Text';
font-style: normal;
font-weight: 700;
src: local('Noticia Text Bold'), local('NoticiaText-Bold)'), url('/fonts/NoticiaText-Bold.woff') format('woff') url('/fonts/NoticiaText-Bold.ttf') format('truetype');
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Noticia Text';
font-style: normal;
font-weight: 700;
src: local('Noticia Text Bold'), local('NoticiaText-Bold)'), url('/fonts/NoticiaText-Bold.woff') format('woff') url('/fonts/NoticiaText-Bold.ttf') format('truetype');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Noticia Text';
font-style: normal;
font-weight: 700;
src: local('Noticia Text Bold'), local('NoticiaText-Bold)'), url('/fonts/NoticiaText-Bold.woff') format('woff') url('/fonts/NoticiaText-Bold.ttf') format('truetype');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
/* vietnamese */
@font-face {
font-family: 'Noticia Text';
font-style: italic;
font-weight: 400;
src: local('Noticia Text Italic'), local('NoticiaText-Italic)'), url('/fonts/NoticiaText-Italic.woff') format('woff') url('/fonts/NoticiaText-Italic.ttf') format('truetype');
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Noticia Text';
font-style: italic;
font-weight: 400;
src: local('Noticia Text Italic'), local('NoticiaText-Italic)'), url('/fonts/NoticiaText-Italic.woff') format('woff') url('/fonts/NoticiaText-Italic.ttf') format('truetype');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Noticia Text';
font-style: italic;
font-weight: 400;
src: local('Noticia Text Italic'), local('NoticiaText-Italic)'), url('/fonts/NoticiaText-Italic.woff') format('woff') url('/fonts/NoticiaText-Italic.ttf') format('truetype');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
/* vietnamese */
@font-face {
font-family: 'Noticia Text';
font-style: italic;
font-weight: 700;
src: local('Noticia Text Bold Italic'), local('NoticiaText-BoldItalic)'), url('/fonts/NoticiaText-BoldItalic.woff') format('woff') url('/fonts/NoticiaText-BoldItalic.ttf') format('truetype');
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Noticia Text';
font-style: italic;
font-weight: 700;
src: local('Noticia Text Bold Italic'), local('NoticiaText-BoldItalic)'), url('/fonts/NoticiaText-BoldItalic.woff') format('woff') url('/fonts/NoticiaText-BoldItalic.ttf') format('truetype');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Noticia Text';
font-style: italic;
font-weight: 700;
src: local('Noticia Text Bold Italic'), local('NoticiaText-BoldItalic)'), url('/fonts/NoticiaText-BoldItalic.woff') format('woff') url('/fonts/NoticiaText-BoldItalic.ttf') format('truetype');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
@font-face {
font-family: 'Symbola';
src: local('Symbola'), url('/fonts/Symbola.woff') format('woff') url('/fonts/Symbola.ttf') format('truetype');
}
body, rss {
font-family: "Noticia Text", Symbola, serif;
font-style: normal;
font-size: 14pt;
margin: 1em 3em;
padding:0;
}
@media print {
body {
font-size: 12pt;
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, div.content a.feed {
display:none;
}
div.content a.book,
div.content a.movie {
text-decoration: none;
}
a cite {
font-style: italic;
}
img[alt="RSS"] { display: none }
a.rss { font-size: 8pt }
}
/* 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: inherit;
font-weight: normal;
}
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 {
visibility: hidden;
}
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 */
.header form, .header p {
display: inline;
white-space: nowrap;
}
label[for="searchlang"], #searchlang, .header input[type="submit"] {
/* don't use display: none! http://stackoverflow.com/questions/5665203/getting-iphone-go-button-to-submit-form */
visibility: hidden; position: absolute;
}
/* wrap on the iphone */
@media media only screen and (max-device-width: 480px) {
}
.header input {
width: 10ex;
}
/* other form fields */
input[type="text"] {
padding: 0;
font-size: 80%;
line-height: 125%;
}
/* code */
textarea, pre, code, tt {
font-family: "Andale Mono", Monaco, "Courier New", Courier, monospace, "Symbola";
font-size: 80%;
}
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;
}
@media print {
div.header, div.footer, div.near, div.definition, p.comment, a.tag {
font-size: 8pt;
}
}
div.footer form.search {
display: none;
}
div.rc li + li {
margin-top: 1em;
}
div.rc li strong, table.history strong, strong.description {
font-family: inherit;
font-weight: inherit;
}
div.diff {
padding-left: 5%;
padding-right: 5%;
font-size: 12pt;
color: #000;
}
div.old {
background-color: #ffffaf;
}
div.new {
background-color: #cfffcf;
}
div.refer {
padding-left: 5%;
padding-right: 5%;
font-size: 12pt;
}
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 {
font-size: 12pt;
padding: 2em 0;
}
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 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;
}
} */
/* rss */
channel * { display: block; }
channel title {
margin-top: 30pt;
}
copyright {
font-size: 14pt;
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;
}

View File

@@ -108,6 +108,35 @@ 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;
}
/* 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; }
@@ -179,7 +208,7 @@ div.rc hr { display: none; }
/* Tables */
table.user {
margin: 1em 4em;
margin: 1em 0;
padding: 0 1em;
border-top: 1px solid black;
border-bottom: 1px solid black;

347
css/bootstrap.css vendored Normal file
View File

@@ -0,0 +1,347 @@
/* Public Domain
Written by Alex Schroeder and Evgkeni Sampelnikof */
textarea { width:100%; }
h1 a { color: inherit }
div.journal h1 { font-size:large; }
table { margin-bottom: 1em; }
div.diff { padding-left:5%; padding-right:5%; }
div.old { background-color:#FFFFAF; }
div.new { background-color:#CFFFCF; }
img.portrait { float: left; clear: left; margin: 1ex; border:#999 1px solid; }
div.footer, div.comment, hr { clear: both; }
div.portrait { float: left; clear: left; font-size: xx-small; margin-right: 1em; }
div.portrait img.portrait { float: none; margin: 0; }
div.portrait a { text-decoration: none; color: #999; }
div.color {
clear: both;
padding: 1ex 2em;
margin: 0 -1em;
box-shadow: inset 40px 0px 20px -20px #EEEEEE,
inset -40px 0px 20px -20px #EEEEEE;
}
.left { float:left; margin-right:1em; }
.right { float:right; margin-left:1em; }
div.two, div.one {
color: #444;
background-color: #f8f8f8;
margin: 7px -1em;
box-shadow: inset 40px 0px 20px -20px #EEEEEE,
inset -40px 0px 20px -20px #EEEEEE,
0px 8px 4px -8px #ccc,
0px -6px 4px -8px #ccc;
}
.irc .time { display: none; }
dl.irc dt { float: left; text-align: right; width: 13ex; }
dl.irc dd { margin-left: 15ex; display: block; }
div.toc {
background-color: #FAFAFA;
border: 1px solid #dddddd;
font-family: sans-serif;
font-size: 80%;
line-height: 90%;
margin: 3em 0 1em;
padding: 1em 0px 0px 1em;
border-radius: 3px;
}
div.toc li {
font-size: 12px;
line-height: 20px;
}
.ell .toc li {
display: inline;
padding-right: 1em;
}
div.letter { column-count: 3; -webkit-column-count: 3; -moz-column-count: 3 }
.footer .edit.bar {
display: block;
text-align: center;
}
.specialdays {
line-height: 1em; /* has no effect: set for div.header instead? */
font-size: 0.9em;
}
.footer .time {
display: block;
text-align: center;
color: #666;
font-size: 10px;
font-weight: bold;
line-height: 12px;
}
.footer {
color: #888;
line-height: 20px;
}
.footer .legal {
text-align: justify;
-moz-text-align-last: center;
text-align-last: center;
font-size: 0.9em;
line-height: 1.4em;
margin: 0 120px 0;
padding: 1em 0 0;
}
.footer .legal a {
color: #888;
text-decoration: underline;
}
.translation.bar {
display: block;
text-align: center;
font-size: 0.8em;
padding-top: 5px;
}
/* .include.WikiLanguageMenu could share those styles,
(altough it might be better to leave it left-aligned) */
.translation.bar a:nth-child(n+2) {
border-left: 1px solid #999;
}
.translation.bar a {
padding: 6px;
display: inline-block;
}
.navbar .nav > li > a.brand {
color: #C76A0D;
padding: 5px 8px 0;
}
a {
color: #C76A0D;
}
a:hover {
color: #8F3E0F;
}
body {
word-wrap: break-word;
padding-left: 20px;
padding-right: 20px;
background-color: #EEEEEE;
color: #000;
font-size: 0.8em;
}
pre {
font-size: 1em;
line-height: 1.5em;
}
hr {
border-top: #ccc 1px solid;
border-bottom: #fff 1px solid;
}
.footer_wrapper {
background: #EEEEEE;
background: linear-gradient(to bottom, #EEEEEE, #CCCCCC);
padding-bottom: 20px;
margin-left: -20px;
margin-right: -20px;
padding-left: 20px;
padding-right: 20px;
}
.footer.container hr:first-child {
display: none;
}
.footer hr {
margin: 10px 100px 0;
}
.footer.container {
padding-top: 10px;
margin-top: 10px;
background: radial-gradient(
50% 8px at top,
rgba(0, 0, 0, 0.3) 0%,
rgba(0, 0, 0, 0) 100%
);
box-shadow: 0 -1px 2px -2px white;
/* border-top: 1px #ccc solid; */
}
body, li {
line-height: 2em;
}
h1, h2, h3 {
text-shadow: 1px 1px white;
}
.navbar-inner {
border-radius: 0 0 4px 4px;
border-width: 0 1px 1px;
}
.navbar .nav > li > a {
padding: 10px;
}
label[for="searchlang"], input#searchlang {
display: none;
}
@media (max-width:480px){
h1 { font-size: 1.8em; }
.navbar .nav > li > a {
padding: 0px 2px;
line-height: 10px;
}
/* hide CC logo */
.footer .licence {
display: none;
}
/* make legal foo*/
.footer .legal {
margin: 5px 5px 5px;
}
.footer .bar a {
margin: 2px 0;
}
}
/* Right-alignment. Will make it harder to achieve responsive behaviour:
twitter.github.com/bootstrap/components.html#navbar
Look for "Responsive navbar" heading.
If this is undesirable, remove the lines with the "RA" comment;
*/
.navbar .nav {
text-align: right; /* RA */
*text-align: left; /* RA */
width: 100%; /* RA */
}
.navbar .nav > li:first-child {
float: left; /* RA */
}
.navbar .nav > li {
display: inline-block; /* RA */
float: none; /* RA */
*float: left;
*display: inline;
line-height: 20px;
}
textarea:focus,
input[type="text"]:focus,
input[type="password"]:focus,
input[type="datetime"]:focus,
input[type="datetime-local"]:focus,
input[type="date"]:focus,
input[type="month"]:focus,
input[type="time"]:focus,
input[type="week"]:focus,
input[type="number"]:focus,
input[type="email"]:focus,
input[type="url"]:focus,
input[type="search"]:focus,
input[type="tel"]:focus,
input[type="color"]:focus,
.uneditable-input:focus {
border-color: rgba(236,160,73,.8);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075),
0 0 8px rgba(236,160,73,.6);
}
/* IE7/8 Flexibility */
.container,
.navbar-static-top .container,
.navbar-fixed-top .container,
.navbar-fixed-bottom .container {
width: auto;
max-width: 940px;
}
/* Don't widen the layout past 940 */
@media (min-width: 1200px) {
.container,
.navbar-static-top .container,
.navbar-fixed-top .container,
.navbar-fixed-bottom .container {
width: 940px;
}
}
div.comment {
background: radial-gradient(
50% 8px at top,
rgba(0, 0, 0, 0.3) 0%,
rgba(0, 0, 0, 0) 100%
);
background-repeat: no-repeat;
box-shadow: 0 -1px 2px -2px white;
padding-top: 20px;
}
div.comment p:nth-child(2) {
color: #666;
/* line-height: 15px; */
font-size: 0.9em;
line-height: 1.4em;
}
div.comment p:nth-child(1) {
margin-bottom: 0px;
}
.comment textarea {
width: 100%;
*width: auto;
resize: vertical;
*resize: both;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/* highlighting source code */
span.builtin { color: #483d8b; } /* DarkSlateBlue */
span.comment { color: #b22222; } /* Firebrick */
span.constant { color: #008b8b; } /* DarkCyan */
span.function { color: #0000ff; } /* Blue1 */
span.keyword { color: #7f007f; } /* Purple */
span.string { color: #8b475d; } /* VioletRed4 */
span.type { color: #228b22; } /* ForestGreen */
span.warning { color: #ff0000; font-weight: bold; } /* Red1 */
span.comment span,
span.string span { color: inherit; }
span.comment span.important.constant,
span.string span.important.constant { color: #008b8b; }
/* old: Equivalent to Output::HTML */
span.linecomment { color: #b22222; } /* firebrick */
span.blockcomment { color: #b22222; } /* firebrick */
span.prepro { color: purple; }
span.select { font-weight: bold; }
span.quote { color: #8b475d; } /* VioletRed4 */
span.category_1 { color: teal; }
span.category_2 { color: blue; }
span.category_3 { color: blue; }
code {
white-space: pre-wrap;
}
/* Local Variables: */
/* css-indent-offset: 4 */
/* End: */

View File

@@ -115,6 +115,7 @@ div.toc h2 {
/* get rid of useless "10 results found" when using indexed search. */
div.search p.result { display:none; }
label[for="searchlang"], input#searchlang { display: none; }
form.tiny, form.tiny p {
display:inline;
@@ -237,9 +238,6 @@ a.near:link {
a.near:visited {
color:#550;
}
a.tag:before {
content:"\2601\ ";
}
ol, ul, dl {
padding-top:0.5em;
}
@@ -249,7 +247,7 @@ dd, li {
/* elisp files and other scripts for download */
p.download a {
p.download a, a.download {
padding: 0.5em;
color: black;
text-decoration: none;
@@ -338,7 +336,22 @@ div.month a.local {
/* highlighting */
/* Equivalent to Output::HTML */
/* highlighting source code */
span.builtin { color: #483d8b; } /* DarkSlateBlue */
span.comment { color: #b22222; } /* Firebrick */
span.constant { color: #008b8b; } /* DarkCyan */
span.function { color: #0000ff; } /* Blue1 */
span.keyword { color: #7f007f; } /* Purple */
span.string { color: #8b475d; } /* VioletRed4 */
span.type { color: #228b22; } /* ForestGreen */
span.warning { color: #ff0000; font-weight: bold; } /* Red1 */
span.comment span,
span.string span { color: inherit; }
span.comment span.important.constant,
span.string span.important.constant { color: #008b8b; }
/* old: Equivalent to Output::HTML */
span.linecomment { color: green; }
span.blockcomment { color: green; }

384
css/light.css Normal file
View File

@@ -0,0 +1,384 @@
/* 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); */
/* vietnamese */
@font-face {
font-family: 'Noticia Text';
font-style: normal;
font-weight: 400;
src: local('Noticia Text'), local('NoticiaText-Regular)'), url('/fonts/NoticiaText-Regular.woff') format('woff');
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Noticia Text';
font-style: normal;
font-weight: 400;
src: local('Noticia Text'), local('NoticiaText-Regular)'), url('/fonts/NoticiaText-Regular.woff') format('woff');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Noticia Text';
font-style: normal;
font-weight: 400;
src: local('Noticia Text'), local('NoticiaText-Regular)'), url('/fonts/NoticiaText-Regular.woff') format('woff');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
/* vietnamese */
@font-face {
font-family: 'Noticia Text';
font-style: normal;
font-weight: 700;
src: local('Noticia Text Bold'), local('NoticiaText-Bold)'), url('/fonts/NoticiaText-Bold.woff') format('woff');
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Noticia Text';
font-style: normal;
font-weight: 700;
src: local('Noticia Text Bold'), local('NoticiaText-Bold)'), url('/fonts/NoticiaText-Bold.woff') format('woff');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Noticia Text';
font-style: normal;
font-weight: 700;
src: local('Noticia Text Bold'), local('NoticiaText-Bold)'), url('/fonts/NoticiaText-Bold.woff') format('woff');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
/* vietnamese */
@font-face {
font-family: 'Noticia Text';
font-style: italic;
font-weight: 400;
src: local('Noticia Text Italic'), local('NoticiaText-Italic)'), url('/fonts/NoticiaText-Italic.woff') format('woff');
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Noticia Text';
font-style: italic;
font-weight: 400;
src: local('Noticia Text Italic'), local('NoticiaText-Italic)'), url('/fonts/NoticiaText-Italic.woff') format('woff');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Noticia Text';
font-style: italic;
font-weight: 400;
src: local('Noticia Text Italic'), local('NoticiaText-Italic)'), url('/fonts/NoticiaText-Italic.woff') format('woff');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
/* vietnamese */
@font-face {
font-family: 'Noticia Text';
font-style: italic;
font-weight: 700;
src: local('Noticia Text Bold Italic'), local('NoticiaText-BoldItalic)'), url('/fonts/NoticiaText-BoldItalic.woff') format('woff');
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Noticia Text';
font-style: italic;
font-weight: 700;
src: local('Noticia Text Bold Italic'), local('NoticiaText-BoldItalic)'), url('/fonts/NoticiaText-BoldItalic.woff') format('woff');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Noticia Text';
font-style: italic;
font-weight: 700;
src: local('Noticia Text Bold Italic'), local('NoticiaText-BoldItalic)'), url('/fonts/NoticiaText-BoldItalic.woff') format('woff');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}
@font-face {
font-family: 'Symbola';
src: local('Symbola'), url('/fonts/Symbola.woff') format('woff');
}
body {
font-family: "Noticia Text", Symbola, serif;
font-size: 14pt;
color: #000;
background-color: #eed;
margin:1em 2em;
}
textarea, pre, code, tt {
font-family: "Andale Mono", Monaco, "Courier New", Courier, monospace, Symbola;
font-size: 80%;
}
@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 */
.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; }
.header input { width: 5em; font-size: 80%; }
.footer { clear:both; font-size: 90%; }
.content input { font-size: 80%; line-height: 125%; }
/* 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 a.pencil {
position: absolute;
right: inherit;
}
/* 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; }
}

230
css/oddmuse-2013.css Normal file
View File

@@ -0,0 +1,230 @@
@font-face {
font-family: 'Gentium Basic';
font-style: normal;
font-weight: 400;
src: local('Gentium Basic'), local('GentiumBasic'), url(http://themes.googleusercontent.com/static/fonts/gentiumbasic/v5/KCktj43blvLkhOTolFn-MVhr3SzZVY8L1R-AhaesIwA.woff) format('woff');
}
@font-face {
font-family: 'Gentium Basic';
font-style: normal;
font-weight: 700;
src: local('Gentium Basic Bold'), local('GentiumBasic-Bold'), url(http://themes.googleusercontent.com/static/fonts/gentiumbasic/v5/2qL6yulgGf0wwgOp-UqGyKuvVGpDTHxx0YlM6XbRIFE.woff) format('woff');
}
@font-face {
font-family: 'Gentium Basic';
font-style: italic;
font-weight: 400;
src: local('Gentium Basic Italic'), local('GentiumBasic-Italic'), url(http://themes.googleusercontent.com/static/fonts/gentiumbasic/v5/qoFz4NSMaYC2UmsMAG3lyajIwExuvJl80GezUi4i-sM.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(http://themes.googleusercontent.com/static/fonts/gentiumbasic/v5/8N9-c_aQDJ8LbI1NGVMrwjBWbH-5CKom31QWlI8zOIM.woff) format('woff');
}
body {
background:#fff;
padding:2% 5%;
margin:0;
font-family: "Gentium Basic", "Bookman Old Style", "Times New Roman", serif;
font-size: 16pt;
}
div.header h1 {
margin-top:2ex;
}
a {
text-decoration: none;
color: #a00;
}
a:visited {
color: #d88;
}
div.header h1 a:hover, h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover,
a:hover, span.caption a.image:hover {
background:#fee;
}
img.logo {
float: right;
clear: right;
border-style:none;
background-color:#fff;
}
img {
padding: 0.5em;
margin: 0 1em;
}
a.image:hover {
background:inherit;
}
a.image:hover img {
background:#fee;
}
/* a.definition soll aussehen wie h2 */
h2, p a.definition {
display:block;
clear:both;
}
/* Such Link im h1 soll nicht auffallen. */
h1, h2, h3, h4, h1 a, h1 a:visited, p a.definition {
color:#666;
font-size: 30pt;
font-weight: normal;
margin: 4ex 0 1ex 0;
padding: 0;
border-bottom: 1px solid #000;
}
h3, h4 {
font-size: inherit;
}
div.diff {
padding: 1em 3em;
}
div.old {
background-color:#FFFFAF;
}
div.new {
background-color:#CFFFCF;
}
div.old p, div.new p {
padding: 0.5em 0;
}
div.refer { padding-left:5%; padding-right:5%; font-size:smaller; }
div[class="content refer"] p { margin-top:2em; }
div.content div.refer hr { display:none; }
div.content div.refer { padding:0; font-size:medium; }
div.content div.refer p { margin:0; }
div.refer a { display:block; }
table.history { border-style:none; }
td.history { border-style:none; }
table.user {
border-style: none;
margin-left: 3em;
}
table.user tr td {
border-style: none;
padding:0.5ex 1ex;
}
dt {
font-weight:bold;
}
dd {
margin-bottom:1ex;
}
textarea {
width:100%;
height:80%;
font-size: 12pt;
}
textarea#summary { height: 3em; }
input {
font-size: 12pt;
}
div.image span.caption {
margin: 0 1em;
}
li img, img.smiley, .noborder img {
border:none;
padding:0;
margin:0;
background:#fff;
color:#000;
}
/* Google +1 */
a#plus1 img {
background-color: #fff;
padding: 0;
margin: 0;
border: none;
}
div.header img, div.footer img { border:0; padding:0; margin:0; }
.left { float:left; }
.right { float:right; }
div.left .left, div.right .right {
float:none;
}
.center { text-align:center; }
span.author {
color: #501;
}
span.bar a {
padding-right:1ex;
}
.rc .author {
color: #655;
}
.rc strong {
font-weight: normal;
color: inherit;
}
.rc li {
position:relative;
padding: 1ex 0;
}
hr {
border:none;
color:black;
background-color:#000;
height:2px;
margin-top:2ex;
}
div.footer hr {
height:4px;
margin: 2em 0 1ex 0;
clear:both;
}
div.content > div.comment {
border-top: none;
padding-top: none;
border-left: 1ex solid #bbb;
padding-left: 1ex;
}
div.wrapper > div.comment {
border-top: 2px solid #000;
padding-top: 2em;
}
pre {
padding: 0.5em;
margin-left: 1em;
margin-right: 2em;
white-space: 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+ */
}
tt, pre, code {
font-size: 80%;
};

250
css/oddmuse-2014.css Normal file
View File

@@ -0,0 +1,250 @@
@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 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 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');
}
body {
background:#fff;
padding:2% 5%;
margin:0;
font-family: "Gentium Basic", "Gentium Plus", "Symbola", serif;
font-size: 16pt;
}
div.header h1 {
margin-top:2ex;
}
a {
text-decoration: none;
color: #a00;
}
a:visited {
color: #d88;
}
div.header h1 a:hover, h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover,
a:hover, span.caption a.image:hover {
background:#fee;
}
img.logo {
float: right;
clear: right;
border-style:none;
background-color:#fff;
}
img {
padding: 0.5em;
margin: 0 1em;
}
a.image:hover {
background:inherit;
}
a.image:hover img {
background:#fee;
}
/* a.definition soll aussehen wie h2 */
h2, p a.definition {
display:block;
clear:both;
}
/* Such Link im h1 soll nicht auffallen. */
h1, h2, h3, h4, h1 a, h1 a:visited, p a.definition {
color:#666;
font-size: 30pt;
font-weight: normal;
margin: 4ex 0 1ex 0;
padding: 0;
border-bottom: 1px solid #000;
}
h3, h4 {
font-size: inherit;
}
div.diff {
padding: 1em 3em;
}
div.old {
background-color:#FFFFAF;
}
div.new {
background-color:#CFFFCF;
}
div.old p, div.new p {
padding: 0.5em 0;
}
div.refer { padding-left:5%; padding-right:5%; font-size:smaller; }
div[class="content refer"] p { margin-top:2em; }
div.content div.refer hr { display:none; }
div.content div.refer { padding:0; font-size:medium; }
div.content div.refer p { margin:0; }
div.refer a { display:block; }
table.history { border-style:none; }
td.history { border-style:none; }
table.user {
border-style: none;
margin-left: 3em;
}
table.user tr td {
border-style: none;
padding:0.5ex 1ex;
}
dt {
font-weight:bold;
}
dd {
margin-bottom:1ex;
}
textarea {
width:100%;
height:80%;
font-size: 12pt;
}
textarea#summary { height: 3em; }
input {
font-size: 12pt;
}
div.image span.caption {
margin: 0 1em;
}
li img, img.smiley, .noborder img {
border:none;
padding:0;
margin:0;
background:#fff;
color:#000;
}
/* Google +1 */
a#plus1 img {
background-color: #fff;
padding: 0;
margin: 0;
border: none;
}
div.header img, div.footer img { border:0; padding:0; margin:0; }
/* No goto bar at the bottom. */
.footer .gotobar, .footer .edit br { display: none; }
.left { float:left; }
.right { float:right; }
div.left .left, div.right .right {
float:none;
}
.center { text-align:center; }
span.author {
color: #501;
}
span.bar a {
padding-right:1ex;
}
.rc .author {
color: #655;
}
.rc strong {
font-weight: normal;
color: inherit;
}
.rc li {
position:relative;
padding: 1ex 0;
}
hr {
border:none;
color:black;
background-color:#000;
height:2px;
margin-top:2ex;
}
div.footer hr {
height:4px;
margin: 2em 0 1ex 0;
clear:both;
}
div.content > div.comment {
border-top: none;
padding-top: none;
border-left: 1ex solid #bbb;
padding-left: 1ex;
}
div.wrapper > div.comment {
border-top: 2px solid #000;
padding-top: 2em;
}
pre {
padding: 0.5em;
margin-left: 1em;
margin-right: 2em;
white-space: 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+ */
}
tt, pre, code {
font-size: 80%;
};

1
description Normal file
View File

@@ -0,0 +1 @@
Oddmuse

2
modules/aawrapperdiv.pl Executable file → Normal file
View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/aawrapperdiv.pl">aawrapperdiv.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/WrapperDiv_Module">WrapperDiv Module</a></p>';
AddModuleDescription('aawrapperdiv.pl', 'WrapperDiv Module');
*OldGetHeader = *GetHeader;

36
modules/accesskeys.pl Normal file
View File

@@ -0,0 +1,36 @@
# Copyright (C) 2014 Alex-Daniel Jakimenko <alex.jakimenko@gmail.com>
# 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('accesskeys.pl', 'Links With AccessKeys Extension');
push(@MyRules, \&LinksWithAccessKeys);
sub LinksWithAccessKeys {
if (m/\G(\[\[$FreeLinkPattern\{(.)\}\]\])/cog) {
my ($id, $key) = ($2, $3);
Dirty($1);
$id = FreeToNormal($id);
my ($class, $resolved, $title, $exists) = ResolveId($id);
my $text = NormalToFree($id);
if ($resolved) { # anchors don't exist as pages, therefore do not use $exists
print ScriptLink(UrlEncode($resolved), $text, $class, undef, $title, $key);
} else {
print "[[" . QuoteHtml($text) . GetEditLink($id, '?') . "]]";
}
return ''; # this is a dirty rule that depends the definition of other pages
}
return undef; # the rule didn't match
}

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/admin.pl">admin.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Admin_Power_Extension">Admin Power Extension</a></p>';
AddModuleDescription('admin.pl', 'Admin Power Extension');
$Action{delete} = \&AdminPowerDelete;
$Action{rename} = \&AdminPowerRename;
@@ -62,13 +62,13 @@ sub AdminPowerRename {
# Regenerate index on next request -- remove this before errors can occur!
unlink($IndexFile);
# page file
CreatePageDir($PageDir, $new); # It might not exist yet
CreateDir($PageDir); # It might not exist yet
rename($fname, $newfname)
or ReportError(Tss('Cannot rename %1 to %2', $fname, $newfname) . ": $!", '500 INTERNAL SERVER ERROR');
# keep directory
my $kdir = GetKeepDir($id);
my $newkdir = GetKeepDir($new);
CreatePageDir($KeepDir, $new); # It might not exist yet (only the parent directory!)
CreateDir($KeepDir); # It might not exist yet (only the parent directory!)
rename($kdir, $newkdir)
or ReportError(Tss('Cannot rename %1 to %2', $kdir, $newkdir) . ": $!", '500 INTERNAL SERVER ERROR')
if -d $kdir;
@@ -76,7 +76,7 @@ sub AdminPowerRename {
if (defined(&GetRefererFile)) {
my $rdir = GetRefererFile($id);
my $newrdir = GetRefererFile($new);
CreatePageDir($RefererDir, $new); # It might not exist yet
CreateDir($RefererDir); # It might not exist yet
rename($rdir, $newrdir)
or ReportError(Tss('Cannot rename %1 to %2', $rdir, $newrdir) . ": $!", '500 INTERNAL SERVER ERROR')
if -d $rdir;

View File

@@ -14,7 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/adsense.pl">adsense.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/AdSense_Module">AdSense Module</a></p>';
AddModuleDescription('adsense.pl', 'AdSense Module');
use vars qw($AdSensePageName $AdSensePlace);

View File

@@ -0,0 +1,35 @@
# Copyright (C) 2014 Alex-Daniel Jakimenko <alex.jakimenko@gmail.com>
# 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('advanced-uploads.pl', 'Advanced File Upload Extension');
$HtmlHeaders .= '<script type="text/javascript" src="/js/uploader.js"></script>';
*AdvancedUploadsOldGetTextArea = *GetTextArea;
*GetTextArea = *AdvancedUploadsNewGetTextArea;
sub AdvancedUploadsNewGetTextArea {
my ($name, $text, $rows) = @_;
return AdvancedUploadsOldGetTextArea(@_) . $q->br() . ($name =~ 'text|aftertext' ? GetUploadForm() : '');
}
sub GetUploadForm {
return $q->span({-class=>'upload'}, $q->label({-for=>'fileToUpload'}, T('Attach file:')),
$q->filefield(-name=>'fileToUpload', -id=>'fileToUpload', -multiple=>'multiple', -onChange=>'fileSelected()', -size=>20),
$q->span({-id=>'fileSize'}, ''),
$q->button(-name=>'uploadButton', -value=>T('Upload'), -onClick=>'uploadFile()'),
$q->span({-id=>'progressNumber'}));
}

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/age.pl">age.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Age_Indication_Extension">Age Indication Extension</a></p>';
AddModuleDescription('age.pl', 'Age Indication Extension');
use vars qw(%AgeEffect $AgeParameter);

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/aggregate.pl">aggregate.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Front_Page_Extension">Front Page Extension</a></p>';
AddModuleDescription('aggregate.pl', 'Front Page Extension');
push(@MyRules, \&AggregateRule);

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/all.pl">all.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/All_Action">All Action</a></p>';
AddModuleDescription('all.pl', 'All Action');
$Action{all} = \&DoPrintAllPages;
@@ -28,7 +28,7 @@ sub DoPrintAllPages {
print GetHeader('', T('Complete Content'))
. $q->p(Ts('The main page is %s.', $q->a({-href=>'#' . $HomePage}, $HomePage)));
print $q->p($q->b(Ts('(for %s)', GetParam('lang', 0)))) if GetParam('lang', 0);
PrintAllPages(0, 0, undef, AllPagesList());
PrintAllPages(0, 0, undef, undef, AllPagesList());
PrintFooter();
}

View File

@@ -12,7 +12,7 @@
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/anchors.pl">anchors.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Comments_on_Local_Anchor_Extension">Comments on Local Anchor Extension</a></p>';
AddModuleDescription('anchors.pl', 'Local Anchor Extension');
push(@MyRules, \&AnchorsRule);

2
modules/antispam.pl Executable file → Normal file
View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/antispam.pl">antispam.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Antispam_Module">Antispam Module</a></p>';
AddModuleDescription('antispam.pl', 'Antispam Module');
use vars qw($DoMaskEmail $CreateMailtoLinks);

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/archive.pl">archive.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Archive_Extension">Archive Extension</a></p>';
AddModuleDescription('archive.pl', 'Archive Extension');
*OldArchiveGetHeader = *GetHeader;
*GetHeader = *NewArchiveGetHeader;

63
modules/askpage.pl Normal file
View File

@@ -0,0 +1,63 @@
# Copyright (C) 2014 Alex-Daniel Jakimenko <alex.jakimenko@gmail.com>
#
# 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/>.
AddModuleDescription('askpage.pl', 'Ask Page Extension');
use Fcntl qw(:DEFAULT :flock);
use vars qw($AskPage $QuestionPage $NewQuestion);
# Don't forget to set your $CommentsPattern to include both $AskPage and $QuestionPage
$AskPage = 'Ask';
$QuestionPage = 'Question_';
$NewQuestion = 'Write your question here:';
sub IncrementInFile {
my $filename = shift;
sysopen my $fh, $filename, O_RDWR|O_CREAT or die "can't open $filename: $!";
flock $fh, LOCK_EX or die "can't flock $filename: $!";
my $num = <$fh> || 1;
seek $fh, 0, 0 or die "can't rewind $filename: $!";
truncate $fh, 0 or die "can't truncate $filename: $!";
(print $fh $num+1, "\n") or die "can't write $filename: $!";
close $fh or die "can't close $filename: $!";
return $num;
}
*OldAskPageDoPost=*DoPost;
*DoPost=*NewAskPageDoPost;
sub NewAskPageDoPost {
my $id = FreeToNormal(shift);
if ($id eq $AskPage and not GetParam('text', undef)) { # comment, not a regular edit
my $currentQuestion = IncrementInFile("$DataDir/curquestion");
$currentQuestion =~ s/[\s\n]//g;
return OldAskPageDoPost($QuestionPage . $currentQuestion, @_); # hack page name
}
OldAskPageDoPost($id, @_); # keep original functionality for regular edits
}
*OldAskPageGetCommentForm=*GetCommentForm;
*GetCommentForm=*NewAskPageGetCommentForm;
sub NewAskPageGetCommentForm {
my ($id, $rev, $comment) = @_;
$NewComment = $NewQuestion if $id eq $AskPage;
OldAskPageGetCommentForm(@_);
}
*OldAskPageJournalSort=*JournalSort;
*JournalSort=NewAskPageJournalSort;
sub NewAskPageJournalSort {
return OldAskPageJournalSort() unless $a =~ m/^$QuestionPage\d+$/ and $b =~ m/^$QuestionPage\d+$/;
($b =~ m/$QuestionPage(\d+)/)[0] <=> ($a =~ m/$QuestionPage(\d+)/)[0];
}

View File

@@ -1,4 +1,4 @@
# Copyright (C) 2004, 2006, 2008 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2004, 2006, 2008, 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
@@ -17,7 +17,7 @@ use XML::Atom::Entry;
use XML::Atom::Link;
use XML::Atom::Person;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/atom.pl">atom.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Atom_Extension">Atom Extension</a></p>';
AddModuleDescription('atom.pl', 'Atom Extension');
push(@MyInitVariables, \&AtomInit);
@@ -140,11 +140,11 @@ sub DoAtomSave {
my $title = $entry->title();
my $author = $entry->author();
SetParam('username', $author->name) if $author; # Used in Save()
my $id = FreeToNormal($title) if ValidIdOrDie($title);
my $id = FreeToNormal($title);
UserCanEditOrDie($id);
$oldid = $id unless $oldid;
ValidIdOrDie($oldid);
my $summary = $entry->summary();
ReportError(Ts('Editing not allowed for %s.', $id), '403 FORBIDDEN') unless UserCanEdit($id, 1);
# Lock before getting old page to prevent races
RequestLockOrError(); # fatal
OpenPage($oldid);

View File

@@ -25,7 +25,7 @@ directory of your Oddmuse Wiki.
=cut
package OddMuse;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/autolock.pl">autolock.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Autolock_Extension">Autolock Extension</a></p>';
AddModuleDescription('autolock.pl', 'Autolock Extension');
# ....................{ CONFIGURATION }....................

View File

@@ -20,7 +20,7 @@
# ie: http://search.cpan.org/CPAN/authors/id/C/CH/CHAMAS/MLDBM-2.01.tar.gz
use MLDBM qw( DB_File Storable );
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/backlinkage.pl">backlinkage.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Inline_Backlinks">Inline Backlinks</a></p>';
AddModuleDescription('backlinkage.pl', 'Inline Backlinks');
my $debug=1; # Set Text Output Verbosity when compiling
my $backfile = $DataDir . '/backlinks.db'; # Where data lives

2
modules/backlinks.pl Executable file → Normal file
View File

@@ -10,7 +10,7 @@
# For user doc, see:
# http://www.oddmuse.org/cgi-bin/oddmuse/Backlinks_Extension
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/backlinks.pl">backlinks.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Backlinks_Extension">Backlinks Extension</a></p>';
AddModuleDescription('backlinks.pl', 'Backlinks Extension');
*OldGetSearchLink = *GetSearchLink;
*GetSearchLink = *NewGetSearchLink;

View File

@@ -0,0 +1,175 @@
# Copyright (C) 2014 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2014 Aki Goto <tyatsumi@gmail.com>
#
# 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/>.
=head1 Balanced Page Directories
B<WARNING: This module is deprecated.> Oddmuse no longer disperses
page data files into 27 directories based on the first character of
the page name. The directories used to be "A" to "Z", and "other". If
you uses your wiki as a blog, all the pages starting with a date ended
up in "other". If your page names started with letters other than "A"
to "Z", all the pages ended up in "other". If you were using comment
pages, all your comment pages ended in "C". This module was intended
to create more subdirectories and spread them more evenly. This is no
longer necessary, as the typical filesystem's performance no longer
degrades with tens of thousands of files in a directory. I'm assuming
most Oddmuse hosts to use some form of GNU/Linux with ext3 or ext4
with dir_index option.
The remaining info for this module is all deprecated.
=over
The ext2 inode specification allows for over 100 trillion files to
reside in a single directory, however because of the current
linked-list directory implementation, only about 10-15 thousand files
can realistically be stored in a single directory. L<haversian-ga on
09 Dec 2002 22:56
PST|http://answers.google.com/answers/threadview?id=122241>
=back
CAUTION: When this extension is installed, your data structure I<must>
change. Make sure you have a backup of your data directory somewhere.
=head2 Finding the right directory
On the command line, finding the right subdirectory can be a problem.
Here's how to use md5sum. Note that the -n option to echo prevents the
trailing newline. Its inclusion would change the checksum.
echo -n HomePage | md5sum | cut -c 1-2
c1
echo -n ホームページ | md5sum | cut -c 1-2
10
=head2 $BalancedPageDirectoriesSize
If you have more than 2560000 pages (w00t!) you might want to set
$BalancedPageDirectoriesSize to 3. This will give you 16× more
directories, which should let you have 40960000 pages. Also, please
let us know about your wiki. :)
=head2 Migration
Once you install the code, reload any page. This should trigger
migration. No output is produced during migration. Migration is
triggered whenever a page file isn't found but a page is found at the
default old location. If, for example, $PageDir/c1/HomePage.pg doesn't
exist but $PageDir/h/HomePage.pg does, and the wiki can be locked, the
wiki is locked and migration is started.
=cut
AddModuleDescription('balanced-page-directories.pl', 'Balanced Page Directories Extension');
use Digest::MD5 qw(md5_hex);
use File::Find qw(finddepth);
use vars qw($BalancedPageDirectoriesSize);
$BalancedPageDirectoriesSize = 2;
*OldBalancedPageDirectoriesGetPageDirectory = *GetPageDirectory;
*GetPageDirectory = *NewBalancedPageDirectoriesGetPageDirectory;
sub NewBalancedPageDirectoriesGetPageDirectory {
my $id = shift;
utf8::encode($id);
return substr(md5_hex($id), 0, $BalancedPageDirectoriesSize);
}
*OldBalancedPageDirectoriesOpenPage = *OpenPage;
*OpenPage = *NewBalancedPageDirectoriesOpenPage;
sub NewBalancedPageDirectoriesOpenPage {
my $id = shift;
if (! -f GetPageFile($id)) {
BalancedPageDirectoriesMigrate($id);
}
return OldBalancedPageDirectoriesOpenPage($id, @_);
}
sub BalancedPageDirectoriesMigrate {
my $id = shift;
# This code is called if the page file does not exist. Perhaps we
# need to migrate? Check if the old page file exists. If it does
# not, there is no point in migration.
*GetPageDirectory = *OldBalancedPageDirectoriesGetPageDirectory;
if (not -f GetPageFile($id)) {
*GetPageDirectory = *NewBalancedPageDirectoriesGetPageDirectory;
return;
}
# Make sure we can change the data structure now.
RequestLockOrError();
# Now we know that we need to migrate. The list of pages is scanned
# using globbing.
SetParam('refresh', 1);
for $id (AllPagesList()) {
*GetPageDirectory = *OldBalancedPageDirectoriesGetPageDirectory;
my $page_from = GetPageFile($id);
my $keep_from = GetKeepDir($id);
my $lock_from = GetLockedPageFile($id);
my $joiner_from = $JoinerDir . '/' . GetPageDirectory($username) if $JoinerDir;
my $joiner_email_from = $JoinerEmailDir . '/' . GetPageDirectory($username) if $JoinerEmailDir;
my $referrer_from = $RefererDir . '/' . GetPageDirectory($id) if $RefererDir;
*GetPageDirectory = *NewBalancedPageDirectoriesGetPageDirectory;
my $page_to = GetPageFile($id);
my $keep_to = GetKeepDir($id);
my $lock_to = GetLockedPageFile($id);
my $joiner_to = $JoinerDir . '/' . GetPageDirectory($username) if $JoinerDir;
my $joiner_email_to = $JoinerEmailDir . '/' . GetPageDirectory($username) if $JoinerEmailDir;
my $referrer_to = $RefererDir . '/' . GetPageDirectory($id) if $RefererDir;
# no clobbering
if (! -f $page_to) {
CreatePageDir($PageDir, $id);
rename $page_from, $page_to || ReportError("Cannot rename $page_from");
}
if (-f $lock_from and ! -f $lock_to) {
rename $lock_from, $lock_to || ReportError("Cannot rename $lock_from");
}
if (-d $keep_from and ! -d $keep_to) {
CreateKeepDir($KeepDir, $id);
rename $keep_from, $keep_to || ReportError("Cannot rename $keep_from");
}
if ($joiner_from and -d $joiner_from and ! -d $joiner_to) {
CreatePageDir($JoinerDir, $id);
rename $joiner_from, $joiner_to || ReportError("Cannot rename $joiner_from");
}
if ($joiner_email_from and -d $joiner_email_from and ! -d $joiner_email_to) {
CreatePageDir($JoinerEmailDir, $id);
rename $joiner_email_from, $joiner_email_to || ReportError("Cannot rename $joiner_email_from");
}
if ($referrer_from and -d $referrer_from and ! -d $referrer_to) {
CreateRefererDir($RefererDir, $id);
rename $referrer_from, $referrer_to || ReportError("Cannot rename $referrer_from");
}
}
# Delete empty subdirectories. Actually, attempt to delete all the
# directories, depth first. It will simply fail for the non-empty
# directories. http://www.perlmonks.org/?node_id=520791
for my $parent ($PageDir, $KeepDir, $JoinerDir, $JoinerEmailDir, $RefererDir) {
next unless $parent;
finddepth(sub { rmdir $_ if -d }, $parent);
}
ReleaseLock();
}

157
modules/ban-contributors.pl Normal file
View File

@@ -0,0 +1,157 @@
# Copyright (C) 2013 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/>.
=head1 Ban Contributors Extension
This module adds "Ban contributors" to the administration page. If you
click on it, it will list all the recent contributors to the page
you've been looking at. Each contributor (IP or hostname) will be
compared to the list of regular expressions on the C<BannedHosts> page
(see C<$BannedHosts>). If the contributor is already banned, this is
mentioned. If the contributor is not banned, you'll see a button
allowing you to ban him or her immediately. If you click the button,
the IP or hostname will be added to the C<BannedHosts> page for you.
=cut
AddModuleDescription('ban-contributors.pl', 'Ban Contributors Extension');
push(@MyAdminCode, \&BanMenu);
sub BanMenu {
my ($id, $menuref, $restref) = @_;
if ($id and UserIsAdmin()) {
push(@$menuref, ScriptLink('action=ban;id=' . UrlEncode($id),
T('Ban contributors')));
}
}
$Action{ban} = \&DoBanHosts;
sub IsItBanned {
my ($it, $regexps) = @_;
my $re = undef;
foreach my $regexp (@$regexps) {
eval { $re = qr/$regexp/i; };
if (defined($re) && $it =~ $re) {
return $it;
}
}
}
sub DoBanHosts {
my $id = shift;
my $content = GetParam('content', '');
my $host = GetParam('host', '');
if ($content) {
SetParam('text', GetPageContent($BannedContent)
. $content . " # " . CalcDay($Now) . " "
. NormalToFree($id) . "\n");
SetParam('summary', NormalToFree($id));
DoPost($BannedContent);
} elsif ($host) {
$host =~ s/\./\\./g;
SetParam('text', GetPageContent($BannedHosts)
. "^" . $host . " # " . CalcDay($Now) . " "
. NormalToFree($id) . "\n");
SetParam('summary', NormalToFree($id));
DoPost($BannedHosts);
} else {
ValidIdOrDie($id);
print GetHeader('', Ts('Ban Contributors to %s', NormalToFree($id)));
SetParam('rcidonly', $id);
SetParam('all', 1);
SetParam('showedit', 1);
my %contrib = ();
for my $line (GetRcLines()) {
$contrib{$line->[4]}->{$line->[5]} = 1 if $line->[4];
}
my @regexps = ();
foreach (split(/\n/, GetPageContent($BannedHosts))) {
if (/^\s*([^#]\S+)/) { # all lines except empty lines and comments, trim whitespace
push(@regexps, $1);
}
}
print '<div class="content ban">';
foreach (sort(keys %contrib)) {
my $name = $_;
delete $contrib{$_}{''};
$name .= " (" . join(", ", sort(keys(%{$contrib{$_}}))) . ")";
if (IsItBanned($_, \@regexps)) {
print $q->p(Ts("%s is banned", $name));
} else {
print GetFormStart(undef, 'get', 'ban'),
GetHiddenValue('action', 'ban'),
GetHiddenValue('id', $id),
GetHiddenValue('host', $_),
GetHiddenValue('recent_edit', 'on'),
$q->p($name, $q->submit(T('Ban!'))), $q->end_form();
}
}
}
PrintFooter();
}
=head2 Rollback
If you are an admin and rolled back a single page, this extension will
list the URLs your rollback removed (assuming that those URLs are part
of the spam) and it will allow you to provide a regular expression
that will be added to BannedHosts.
=cut
*OldBanContributorsWriteRcLog = *WriteRcLog;
*WriteRcLog = *NewBanContributorsWriteRcLog;
sub NewBanContributorsWriteRcLog {
my ($tag, $id, $to) = @_;
if ($tag eq '[[rollback]]' and $id and $to > 0
and $OpenPageName eq $id and UserIsAdmin()) {
# we currently have the clean page loaded, so we need to reload
# the spammed revision (there is a possible race condition here)
my ($old) = GetTextRevision($Page{revision}-1, 1);
my %urls = map {$_ => 1 } $old =~ /$UrlPattern/og;
# we open the file again to force a load of the despammed page
foreach my $url ($Page{text} =~ /$UrlPattern/og) {
delete($urls{$url});
}
# we also remove any candidates that are already banned
my @regexps = ();
foreach (split(/\n/, GetPageContent($BannedContent))) {
if (/^\s*([^#]\S+)/) { # all lines except empty lines and comments, trim whitespace
push(@regexps, $1);
}
}
foreach my $url (keys %urls) {
delete($urls{$url}) if IsItBanned($url, \@regexps);
}
if (keys %urls) {
print $q->p(Ts("These URLs were rolled back. Perhaps you want to add a regular expression to %s?",
GetPageLink($BannedContent)));
print $q->pre(join("\n", sort keys %urls));
print GetFormStart(undef, 'get', 'ban'),
GetHiddenValue('action', 'ban'),
GetHiddenValue('id', $id),
GetHiddenValue('recent_edit', 'on'),
$q->p($q->label({-for=>'content'}, T('Regular expression:')), " ",
$q->textfield(-name=>'content', -size=>30), " ",
$q->submit(T('Ban!'))),
$q->end_form();
};
print $q->p(T("Consider banning the IP number as well: "),
ScriptLink('action=ban;id=' . UrlEncode($id), T('Ban contributors')));
};
return OldBanContributorsWriteRcLog(@_);
}

View File

@@ -0,0 +1,37 @@
# Copyright (C) 2013 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/>.
#
# This file must load before logbannedcontent.pl such that quick
# editors will be logged.
AddModuleDescription('ban-quick-editors.pl', 'Banning Quick Editors');
*BanQuickOldUserIsBanned = *UserIsBanned;
*UserIsBanned = *BanQuickNewUserIsBanned;
sub BanQuickNewUserIsBanned {
my $rule = BanQuickOldUserIsBanned(@_);
if (not $rule
and $SurgeProtection # need surge protection
and GetParam('title')) {
my $name = GetParam('username', GetRemoteHost());
my @entries = @{$RecentVisitors{$name}};
# $entry[0] is $Now after AddRecentVisitor
my $ts = $entries[1];
if ($Now - $ts < 5) {
return "fast editing spam bot";
}
}
return $rule;
}

84
modules/banned-regexps.pl Normal file
View File

@@ -0,0 +1,84 @@
# Copyright (C) 2012 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('banned-regexps.pl', 'Banning Regular Expressions');
=h1 Compatibility
This extension works with logbannedcontent.pl.
=h1 Example content for the BannedRegexps page:
# This page lists regular expressions that prevent the saving of a page.
# The regexps are matched against any page or comment submitted.
# The format is simple: # comments to the end of the line. Empty lines are ignored.
# Everything else is a regular expression. If the regular expression is followed by
# a comment, this is used as the explanation when a user is denied editing. If the
# comment starts with a date, this date is not included in the explanation.
# The date could help us decide which regular expressions to delete in the future.
# In other words:
# ^\s*([^#]+?)\s*(#\s*(\d\d\d\d-\d\d-\d\d\s*)?(.*))?$
# Group 1 is the regular expression to use.
# Group 4 is the explanation to use.
порно # 2012-12-31 Russian porn
<a\s+href=["']?http # 2012-12-31 HTML anchor tags usually mean spam
\[url= # 2012-12-31 bbCode links usually mean spam
\s+https?:\S+[ .\r\n]*$ # 2012-12-31 ending with a link usually means spam
(?s)\s+https?:\S+.*\s+https?:\S+.*\s+https?:\S+.* # 2012-12-31 three naked links usually mean spam
=cut
use vars qw($BannedRegexps);
$BannedRegexps = 'BannedRegexps';
push(@MyInitVariables, sub {
$AdminPages{$BannedRegexps} = 1;
$LockOnCreation{$BannedRegexps} = 1;
$PlainTextPages{$BannedRegexps} = 1;
});
*RegexpOldBannedContent = *BannedContent;
*BannedContent = *RegexpNewBannedContent;
# the above also changes the mapping for the variable!
$BannedContent = $RegexpOldBannedContent;
sub RegexpNewBannedContent {
my $str = shift;
my $rule = RegexpOldBannedContent($str, @_);
if (not $rule) {
foreach (split(/\n/, GetPageContent($BannedRegexps))) {
next unless m/^\s*([^#]+?)\s*(#\s*(\d\d\d\d-\d\d-\d\d\s*)?(.*))?$/;
my ($regexp, $comment, $re) = ($1, $4, undef);
eval { $re = qr/$regexp/i; };
if (defined($re) && $str =~ $re) {
my $group1 = $1;
my $explanation = ($group1
? Tss('Regular expression "%1" matched "%2" on this page.', QuoteHtml($regexp), $group1)
: Ts('Regular expression "%s" matched on this page.', QuoteHtml($regexp)));
$rule = $explanation . ' '
. ($comment ? Ts('Reason: %s.', $comment) : T('Reason unknown.')) . ' '
. Ts('See %s for more information.', GetPageLink($BannedRegexps));
last;
}
}
}
LogWrite($rule) if $rule and $BannedFile;
return $rule if $rule;
return 0;
}

View File

@@ -1,22 +1,23 @@
# Copyright (C) 2007, 2008 Alex Schroeder <alex@gnu.org>
# Copyright (C) 2007, 2008, 2013 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 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.
# 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/>.
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/bbcode.pl">bbcode.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/bbCode_Extension">bbCode Extension</a></p>';
AddModuleDescription('bbcode.pl', 'bbCode Extension');
push(@MyRules, \&bbCodeRule);
$RuleOrder{\&bbCodeRule} = 100; # must come after PortraitSupportRule
use vars qw($bbBlock);
my %bbTitle = qw(h1 1 h2 1 h3 1 h4 1 h5 1 h6 1);
@@ -37,6 +38,12 @@ sub bbCodeRule {
. qq{font-style: normal;"}); }
elsif ($tag eq 's' or $tag eq 'strike') {
return AddHtmlEnvironment('del'); }
elsif ($tag eq 'tt') {
return AddHtmlEnvironment('tt'); }
elsif ($tag eq 'sub') {
return AddHtmlEnvironment('sub'); }
elsif ($tag eq 'sup') {
return AddHtmlEnvironment('sup'); }
elsif ($tag eq 'color') {
return AddHtmlEnvironment('em', qq{style="color: $option; }
. qq{font-style: normal;"}); }
@@ -96,7 +103,8 @@ sub bbCodeRule {
%translate = qw{b b i i u em color em size em font span url a
quote blockquote h1 h1 h2 h2 h3 h3 h4 h4 h5 h5
h6 h6 center div left div right div list ul
s del strike del highlight strong};
s del strike del sub sub sup sup highlight strong
tt tt};
# closing a block level element closes all elements
if ($bbBlock eq $translate{$tag}) {
/\G([ \t]*\n)*/cg; # eat whitespace after closing block level element
@@ -114,15 +122,15 @@ sub bbCodeRule {
# smiley
elsif (/\G(:-?[()])/cg) {
if (substr($1,-1) eq ')') {
# '☺' 0009786 00263a WHITE SMILING FACE, So, 0, ON, N,
return '&#x263a;'; }
# 😊 1F60A SMILING FACE WITH SMILING EYES
return '&#x1F60A;'; }
else {
# '☹' 0009785 002639 WHITE FROWNING FACE, So, 0, ON, N,
return '&#x2639;'; }}
# 😟 1F61F WORRIED FACE
return '&#x1F61F;'; }}
elsif (/\G:(?:smile|happy):/cg) {
return '&#x263a;'; }
return '&#x1F60A;'; }
elsif (/\G:(?:sad|frown):/cg) {
return '&#x2639;'; }
return '&#x1F61F;'; }
# no match
return undef;
}

View File

@@ -17,7 +17,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/beautify.pl">beautify.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Source_Code_Beautification_Extension">Source Code Beautification Extension</a></p>';
AddModuleDescription('beautify.pl', 'Source Code Beautification Extension');
use Beautifier::Core;
use Output::HTML;

View File

@@ -15,14 +15,18 @@
package OddMuse;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/big-brother.pl">big-brother.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Big_Brother_Extension">Big Brother Extension</a></p>';
AddModuleDescription('big-brother.pl', 'Big Brother Extension');
use vars qw($VisitorTime);
use vars qw($VisitorTime @BigBrotherSecretParameters);
my $US = "\x1f";
$VisitorTime = 7200; # keep visitor data arround for 2 hours.
# normal password parameter from wiki.pl
# password parameters from login.pl
@BigBrotherSecretParameters = qw(pwd pwd1 pwd2 oldpwd);
push(@MyAdminCode, \&BigBrotherVisitors);
sub BigBrotherVisitors {
@@ -47,6 +51,13 @@ sub AddRecentVisitor {
$ts++ while $entries{$ts};
my $action = GetParam('action', 'browse');
my $id = GetId(); # script/p/q -> q
my %params = map { $_ => 1 } $q->param;
for $bad (@BigBrotherSecretParameters) {
delete $params{$bad};
}
my $url = ScriptUrl(join(';', "action=$action;id=" . UrlEncode($id),
map { $_ . '=' . UrlEncode(GetParam($_)) }
keys %params));
my $url = $q->url(-path_info=>1,-query=>1);
my $download = GetParam('action', 'browse') eq 'download'
|| GetParam('download', 0)

2
modules/blockquote.pl Executable file → Normal file
View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/blockquote.pl">blockquote.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Comments_on_Text_Formatting_Rules">Comments on Text Formatting Rules</a></p>';
AddModuleDescription('blockquote.pl', 'Comments on Text Formatting Rules');
push(@MyRules, \&BlockQuoteRule);

View File

@@ -22,7 +22,7 @@
# is useless. This extension will not work under Windows/IIS unless cal
# is installed.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/cal3.pl">cal3.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Cal3_Extension">Cal3 Extension</a></p>';
AddModuleDescription('cal3.pl', 'Cal3 Extension');
*OldCalendarGetHeader = *GetHeader;
*GetHeader = *NewCalendarGetHeader;

View File

@@ -17,7 +17,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/calendar.pl">calendar.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Calendar_Extension">Calendar Extension</a></p>';
AddModuleDescription('calendar.pl', 'Calendar Extension');
use vars qw($CalendarOnEveryPage $CalAsTable $CalStartMonday);
@@ -104,7 +104,7 @@ sub DoCollect {
# Now save information required for saving the cache of the current page.
local (%Page, $OpenPageName);
print $q->start_div({-class=>'content journal collection'});
PrintAllPages(1, 1, undef, @pages);
PrintAllPages(1, 1, undef, undef, @pages);
print $q->end_div();
}
$CollectingJournal = 0;

View File

@@ -16,7 +16,9 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/canonical.pl">canonical.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Canonical_Names">Canonical Names</a></p>';
AddModuleDescription('canonical.pl', 'Canonical Names');
use utf8;
*OldCanonicalResolveId = *ResolveId;
*ResolveId = *NewCanonicalResolveId;
@@ -39,14 +41,9 @@ sub NewCanonicalResolveId {
# If the page AlexSchröder exists, [[alexschroder]] will link to it.
use utf8;
use Encode;
sub CanonicalName {
my $str = shift;
$DebugInfo .= ' ' . $str;
$str = decode('utf-8', $str);
$str =~ tr/äáàâëéèêïíìîöóòôüúùû/aaaaeeeeiiiioooouuuu/;
$str = lc($str);
$DebugInfo .= '->' . $str;
return $str;
}

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/checkbox.pl">checkbox.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Checklist_Extension">Checklist Extension</a></p>';
AddModuleDescription('checkbox.pl', 'Checklist Extension');
# [[ : To do]]
# [[X: Done]]

10
modules/clustermap.pl Executable file → Normal file
View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/clustermap.pl">clustermap.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/ClusterMap_Module">ClusterMap Module</a></p>';
AddModuleDescription('clustermap.pl', 'ClusterMap Module');
use vars qw($ClusterMapPage $ClusterMapTOC $FilterUnclusteredRegExp @ClusterMapAdminPages);
@@ -40,8 +40,8 @@ $PrintTOCAnchor = 0;
%ClusterMap = ();
*OldDoRc = *DoRc;
*DoRc = *ClusterMapDoRc;
*OldPrintRcHtml = *PrintRcHtml;
*PrintRcHtml = *ClusterMapPrintRcHtml;
push(@MyAdminCode, \&ClusterMapAdminRule);
@@ -178,7 +178,7 @@ sub CreateClusterMap {
}
}
sub ClusterMapDoRc {
sub ClusterMapPrintRcHtml {
my ( @options ) = @_;
my $page = "";
my $cluster = GetParam(rcclusteronly);
@@ -195,7 +195,7 @@ sub ClusterMapDoRc {
print "</ul>";
}
OldDoRc(@options);
OldPrintRcHtml(@options);
}
sub PrintUnclusteredMap {

View File

@@ -0,0 +1,55 @@
# Copyright (C) 2014 Alex-Daniel Jakimenko <alex.jakimenko@gmail.com>
# 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('comment-div-wrapper.pl', 'Comment Div Wrapper Extension');
my $CommentDiv = 0;
push(@MyRules, \&CommentDivWrapper);
$RuleOrder{\&CommentDivWrapper} = -50;
sub CommentDivWrapper {
if (substr($OpenPageName, 0, length($CommentsPrefix)) eq $CommentsPrefix) {
if (pos == 0 and not $CommentDiv) {
$CommentDiv = 1;
return $q->start_div({-class=>'userComment'});
}
}
if ($OpenPageName =~ /$CommentsPattern/o) {
if ($bol and m/\G(\s*\n)*----+[ \t]*\n?/cg) {
my $html = CloseHtmlEnvironments()
. ($CommentDiv++ > 0 ? $q->end_div() : $q->h2({-class=>'commentsHeading'}, T('Comments:'))) . $q->start_div({-class=>'userComment'})
. AddHtmlEnvironment('p');
return $html;
}
}
return undef;
}
# close final div
*OldCommentDivApplyRules = *ApplyRules;
*ApplyRules = *NewCommentDivApplyRules;
sub NewCommentDivApplyRules {
my ($blocks, $flags) = OldCommentDivApplyRules(@_);
if ($CommentDiv) {
print $q->end_div();
$blocks .= $FS . $q->end_div();
$flags .= $FS . 0;
$CommentDiv = 0;
}
return ($blocks, $flags);
}

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/commentcount.pl">commentcount.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Comment_Count_Extension">Comment Count Extension</a></p>';
AddModuleDescription('commentcount.pl', 'Comment Count Extension');
*OldCommentcountAddComment = *AddComment;
*AddComment = *NewCommentcountAddComment;

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/compilation.pl">compilation.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Compilation_Extension">Compilation Extension</a></p>';
AddModuleDescription('compilation.pl', 'Compilation Extension');
$Action{compilation} = \&DoCompilation;
@@ -49,7 +49,7 @@ sub PrintCompilation {
local %Page;
local $OpenPageName='';
print '<div class="compilation">';
PrintAllPages(1, 1, undef, @pages);
PrintAllPages(1, 1, undef, undef, @pages);
print '</div>';
}
return @pages;

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/config.pl">config.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Plans">Plans</a></p>';
AddModuleDescription('config.pl', 'Plans');
$Action{config} = \&DoConfig;
$Action{clone} = \&DoClone;
@@ -37,7 +37,7 @@ sub DoConfig {
$SurgeProtection $SurgeProtectionTime $SurgeProtectionViews
$DeletedPage $RCName @RcDays $RcDefault $KeepDays
$KeepMajor $SummaryHours $SummaryDefaultLength $ShowEdits
$UseLookup $RecentTop $RecentLink $PageCluster
$RecentTop $RecentLink $PageCluster
$InterWikiMoniker $SiteDescription $RssImageUrl $RssRights
$RssExclude $RssCacheHours $RssStyleSheet $UploadAllowed
@UploadTypes $EmbedWiki $FooterNote $EditNote $TopLinkBar

View File

@@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/context.pl">context.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Calendar_Extension">Calendar Extension</a></p>';
AddModuleDescription('context.pl', 'Calendar Extension');
push (@MyInitVariables, \&ContextMenuItem);

View File

@@ -23,7 +23,7 @@
#
# Of course, you can customize this to store more information
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/creationdate.pl">creationdate.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/CreationDate_Module">CreationDate Module</a></p>';
AddModuleDescription('creationdate.pl', 'CreationDate Module');
*CreationDateOldOpenPage = *OpenPage;
*OpenPage = CreationDateOpenPage;

View File

@@ -14,7 +14,7 @@ directory for your Oddmuse Wiki.
=cut
package OddMuse;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/creole.pl">creole.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Creole_Markup_Extension">Creole Markup Extension</a></p>';
AddModuleDescription('creole.pl', 'Creole Markup Extension');
# ....................{ CONFIGURATION }....................
@@ -242,6 +242,7 @@ sub CreoleRule {
-class=> 'image outside'},
$q->img({-src=> UnquoteHtml($1),
-alt=> UnquoteHtml($3),
-title=> UnquoteHtml($3),
-class=> 'url outside'})));
}
# image link: [[link|{{pic}}]] and [[link|{{pic|text}}]]
@@ -252,6 +253,7 @@ sub CreoleRule {
ScriptLink(UrlEncode(FreeToNormal($2)),
$q->img({-src=> GetDownloadLink(FreeToNormal($3), 2),
-alt=> UnquoteHtml($text),
-title=> UnquoteHtml($text),
-class=> 'upload'}), 'image')), $text);
}
# image link: [[link|{{url}}]] and [[link|{{url|text}}]]
@@ -262,6 +264,7 @@ sub CreoleRule {
ScriptLink(UrlEncode(FreeToNormal($2)),
$q->img({-src=> UnquoteHtml($3),
-alt=> UnquoteHtml($text),
-title=> UnquoteHtml($text),
-class=> 'url outside'}), 'image')), $text);
}
# image link: [[url|{{pic}}]] and [[url|{{pic|text}}]]
@@ -272,6 +275,7 @@ sub CreoleRule {
$q->a({-href=> UnquoteHtml($2), -class=> 'image outside'},
$q->img({-src=> GetDownloadLink(FreeToNormal($3), 2),
-alt=> UnquoteHtml($text),
-title=> UnquoteHtml($text),
-class=> 'upload'}))), $text);
}
# image link: [[url|{{url}}]] and [[url|{{url|text}}]]
@@ -281,6 +285,7 @@ sub CreoleRule {
$q->a({-href=> UnquoteHtml($1), -class=> 'image outside'},
$q->img({-src=> UnquoteHtml($2),
-alt=> UnquoteHtml($4),
-title=> UnquoteHtml($4),
-class=> 'url outside'})));
}
# link: [[url]] and [[url|text]]
@@ -391,7 +396,7 @@ sub CreoleRule {
my $is_right_justified = $3;
# Now that we've retrieved all numbered matches, match another lookahead.
my $is_left_justified = m/\G(?=.*?[ \t]+\|)/;
my $is_left_justified = m/\G(?=[^\n|]*?[ \t]+\|)/;
my $attributes = $column_span == 1 ? '' : qq{colspan="$column_span"};
if ($is_left_justified and
@@ -456,21 +461,16 @@ sub CreoleListAndNewLineRule {
my $is_in_list_item = InElement('li');
# # numbered list
if (($bol and m/\G[ \t]*(#)[ \t]*/cg) or
($is_in_list_item and m/\G[ \t]*\n+[ \t]*(#+)[ \t]*/cg)) {
# * bullet list (nestable; needs space when nested to disambiguate from bold)
if (($bol and m/\G[ \t]*([#*])[ \t]*/cg) or
($is_in_list_item and m/\G[ \t]*\n+[ \t]*(#+)[ \t]*/cg) or
($is_in_list_item and m/\G[ \t]*\n+[ \t]*(\*+)[ \t]+/cg)) {
# Note: the first line of this return statement is --not-- equivalent to:
# "return CloseHtmlEnvironmentUntil('li')", as that line does not permit
# modules overriding the CloseHtmlEnvironments() function to "have a say."
return ($is_in_list_item ? CloseHtmlEnvironmentUntil('li') : CloseHtmlEnvironments())
.OpenHtmlEnvironment('ol', length($1))
.AddHtmlEnvironment ('li');
}
# * bullet list (nestable; needs space when nested to disambiguate from bold)
elsif (($bol and m/\G[ \t]*(\*)[ \t]*/cg) or
($is_in_list_item and m/\G[ \t]*\n+[ \t]*(\*+)[ \t]+/cg)) {
return ($is_in_list_item ? CloseHtmlEnvironmentUntil('li') : CloseHtmlEnvironments())
.OpenHtmlEnvironment('ul', length($1))
.AddHtmlEnvironment ('li');
.OpenHtmlEnvironment(substr($1, 0, 1) eq '#' ? 'ol' : 'ul', length($1), '', 'ol|ul')
.AddHtmlEnvironment('li');
}
# - bullet list (not nestable; always needs space)
elsif ($CreoleDashStyleUnorderedLists and (

View File

@@ -22,7 +22,7 @@ creoleaddition is simply installable; simply:
=cut
package OddMuse;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/creoleaddition.pl">creoleaddition.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Creole_Addition_Markup_Extension">Creole Addition Markup Extension</a></p>';
AddModuleDescription('creoleaddition.pl', 'Creole Addition Markup Extension');
# ....................{ CONFIGURATION }....................

2
modules/crossbar.pl Executable file → Normal file
View File

@@ -33,7 +33,7 @@ crossbar is easily installable; move this file into the B<wiki/modules/>
directory for your Oddmuse Wiki.
=cut
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/crossbar.pl">crossbar.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Crossbar_Extension">Crossbar Extension</a></p>';
AddModuleDescription('crossbar.pl', 'Crossbar Extension');
# ....................{ CONFIGURATION }....................
use vars qw($CrossbarPageName

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/crumbs.pl">crumbs.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/List_Parent_Pages_Extension">List Parent Pages Extension</a></p>';
AddModuleDescription('crumbs.pl', 'List Parent Pages Extension');
push(@MyRules, \&CrumbsRule);
$RuleOrder{\&CrumbsRule} = -10; # run before default rules!

View File

@@ -15,7 +15,7 @@ automatically.
=cut
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/css-install.pl">css-install.pl</a></p>';
AddModuleDescription('css-install.pl');
=head1 CONFIGURATION

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/csv.pl">csv.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Comments_on_Long_Table_Markup_Extension">Comments on Long Table Markup Extension</a></p>';
AddModuleDescription('csv.pl', 'Comments on Long Table Markup Extension');
push(@MyRules, \&CsvRule);

View File

@@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/dates.pl">dates.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Dates_Extension">Dates Extension</a></p>';
AddModuleDescription('dates.pl', 'Dates Extension');
push(@MyAdminCode, \&DatesMenu);

View File

@@ -15,6 +15,8 @@
package OddMuse;
AddModuleDescription('debug.pl');
@Debugging = (\&DebugInterLinks);
sub DebugInterLinks {

View File

@@ -1,22 +1,18 @@
# Copyright (C) 2006 Alex Schroeder <alex@emacswiki.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 2 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, write to the
# Free Software Foundation, Inc.
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
# Copyright (C) 2006-2013 Alex Schroeder <alex@gnu.org>
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/delete-all.pl">delete-all.pl</a></p>';
# 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/>.
AddModuleDescription('delete-all.pl');
use vars qw($DeletedAge);
@@ -27,6 +23,7 @@ $DeleteAge = 172800; # 2*24*60*60
# All pages will be deleted after two days of inactivity!
sub NewDelPageDeletable {
return 1 if $Now - $Page{ts} > $DeleteAge;
return 1 if $Now - $Page{ts} > $DeleteAge
and not $LockOnCreation{$OpenPageName};
return OldDelPageDeletable(@_);
}

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/despam.pl">despam.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Despam_Extension">Despam Extension</a></p>';
AddModuleDescription('despam.pl', 'Despam Extension');
push(@MyAdminCode, \&DespamMenu);
@@ -91,14 +91,14 @@ sub DespamBannedContent {
foreach my $url (@urls) {
if ($url =~ /($regexp)/i) {
return Tss('Rule "%1" matched "%2" on this page.',
QuoteHtml($regexp), $url);
QuoteHtml($regexp), QuoteHtml($url));
}
}
}
# depends on strange-spam.pl!
foreach (@DespamStrangeRules) {
my $regexp = $_;
if ($str =~ /($regexp)/) {
if ($str =~ /($regexp)/i) {
my $match = $1;
$match =~ s/\n/ /g;
return Tss('Rule "%1" matched "%2" on this page.',

84
modules/diff.pl Normal file
View File

@@ -0,0 +1,84 @@
# Copyright (C) 2014 Alex-Daniel Jakimenko <alex.jakimenko@gmail.com>
# 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('diff.pl', 'Diff Action Extension');
push(@MyRules, \&DiffActionRule);
$Action{pagediff} = \&DoDiffAction;
sub DiffActionRule {
return PrintDiffActionChooser($3) if (m/\G(&lt;diff( (.*))&gt;)/cgi);
return undef; # the rule didn't match
}
sub DoDiffAction {
print GetHeader('', T('Page diff'), '');
my $page1 = GetParam('page1');
my $page2 = GetParam('page2');
my $pattern = GetParam('pattern');
$pattern ||= '.*';
print PrintDiffActionChooser($pattern);
ValidIdOrDie($page1);
ValidIdOrDie($page2);
my $diff = DoUnifiedDiff("1\n \n" . GetPageContent($page1), "2\n \n" . GetPageContent($page2)); # add extra lines, otherwise diff between identical files will print nothing # TODO fix this, otherwise one day this will fail...
$diff = QuoteHtml($diff);
$diff =~ tr/\r//d; # TODO is this required? # probably not
for (split /\n/, $diff) {
s/(^.)//;
my $type = $1;
if ($type eq '+') {
print '<span class="diffactionnew">' . $type;
} elsif ($type eq '-') {
print '<span class="diffactionold">' . $type;
}
ApplyRules($_);
print '</span>' if $type =~ /[+-]/;
print '<br/>';
}
PrintFooter();
}
sub PrintDiffActionChooser {
my $pattern = shift;
$pattern ||= '.*';
my @chosenPages = ();
for (@IndexList) {
push @chosenPages, $_ if m/$pattern/;
}
return GetFormStart(undef, 'get', 'pagediff')
. GetHiddenValue('action', 'pagediff')
. GetHiddenValue('pattern', $pattern)
. $q->popup_menu(-name=>'page1', -values=>\@chosenPages) . ' '
. $q->popup_menu(-name=>'page2', -values=>\@chosenPages) . ' '
. $q->submit(-name=>'', -value=>T('Diff'))
. $q->end_form();
}
sub DoUnifiedDiff { # copied from DoDiff
CreateDir($TempDir);
my $oldName = "$TempDir/old";
my $newName = "$TempDir/new";
RequestLockDir('diff') or return '';
WriteStringToFile($oldName, $_[0]);
WriteStringToFile($newName, $_[1]);
my $diff_out = `diff -U 99999 -- \Q$oldName\E \Q$newName\E | tail -n +7`; # should be +4, but we always add extra line # TODO that workaround is ugly, fix it!
utf8::decode($diff_out); # needs decoding
$diff_out =~ s/\n\K\\ No newline.*\n//g; # Get rid of common complaint.
ReleaseLockDir('diff');
# No need to unlink temp files--next diff will just overwrite.
return $diff_out;
}

39
modules/div-foo.pl Normal file
View File

@@ -0,0 +1,39 @@
# Copyright (C) 2014 Alex-Daniel Jakimenko <alex.jakimenko@gmail.com>
#
# 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('div-foo.pl', 'Div Foo Extension');
use vars qw($DivFooPrefix);
$DivFooPrefix = 'foo_';
push(@MyRules, \&DivFooRule);
sub DivFooRule {
if (m/\G \&lt; ([a-z-_][a-z-_ ]+[a-z-_]) \&gt; \s*\n /cgx) {
return CloseHtmlEnvironment('p') . AddHtmlEnvironment('div', 'class="' . join(' ', map {"$DivFooPrefix$_"} split /\s+/, $1) . '"');
}
if (m/\G \&lt; ([a-z-_][a-z-_ ]+[a-z-_]) (\?(.*?(?=\&gt;)))? \&gt; /cgx) {
my $title = $3 ? ' title="' . QuoteHtml($3) . '"' : '';
return AddHtmlEnvironment('span', 'class="' . join(' ', map {"$DivFooPrefix$_"} split /\s+/, $1) . '"' . $title);
}
if (m/\G \&lt; \/ \/ \&gt; /cgx) {
return CloseHtmlEnvironment('div') . (InElement('div') ? '' : AddHtmlEnvironment('p'));
}
if (m/\G \&lt; \/ \&gt; /cgx) {
return CloseHtmlEnvironment('span');
}
return undef;
}

View File

@@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/dojo.pl">dojo.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Using_Dojo_Instead_Of_Wiki_Markup">Using Dojo Instead Of Wiki Markup</a></p>';
AddModuleDescription('dojo.pl', 'Using Dojo Instead Of Wiki Markup');
use vars qw(@DojoPlugins $DojoTheme);

View File

@@ -21,7 +21,7 @@
# edit a page by double-clicking on it. The user must have
# JavaScript enabled for this to work.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/doubleclick.pl">doubleclick.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Doubleclick_Extension">Doubleclick Extension</a></p>';
AddModuleDescription('doubleclick.pl', 'Doubleclick Extension');
*OldDoubleclickGetHeader = *GetHeader;
*GetHeader = NewDoubleclickGetHeader;

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/download.pl">download.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Download_Extension">Download Extension</a></p>';
AddModuleDescription('download.pl', 'Download Extension');
push( @MyRules, \&DownloadSupportRule );

View File

@@ -15,6 +15,8 @@
use File::Glob ':glob';
use vars qw($DraftDir);
AddModuleDescription('drafts.pl');
$DraftDir = $DataDir."/draft"; # directory for drafts
push(@MyInitVariables, \&DraftInit);

View File

@@ -0,0 +1,49 @@
# Copyright (C) 20072013 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/>.
AddModuleDescription('duckduckgo-search.pl', 'Use DuckDuckGo For Searches');
use vars qw($DuckDuckGoSearchDomain);
$DuckDuckGoSearchDomain = undef;
$Action{search} = \&DoDuckDuckGoSearch;
push(@MyInitVariables, \&DuckDuckGoSearchInit);
sub DuckDuckGoSearchInit {
# If $ScriptName does not contain a hostname, this extension will
# have no effect. Domain regexp based on RFC 2396 section 3.2.2.
if (!$DuckDuckGoSearchDomain) {
my $alpha = '[a-zA-Z]';
my $alphanum = '[a-zA-Z0-9]';
my $alphanumdash = '[-a-zA-Z0-9]';
my $domainlabel = "$alphanum($alphanumdash*$alphanum)?";
my $toplabel = "$alpha($alphanumdash*$alphanum)?";
if ($ScriptName =~ m!^(https?://)?([^/]+\.)?($domainlabel\.$toplabel)\.?(:|/|\z)!) {
$DuckDuckGoSearchDomain = $3;
}
}
if ($DuckDuckGoSearchDomain
and GetParam('search', undef)
and not GetParam('action', undef)
and not GetParam('old', 0)) {
SetParam('action', 'search');
}
}
sub DoDuckDuckGoSearch {
my $search = UrlEncode(GetParam('search', undef));
print $q->redirect({-uri=>"https://www.duckduckgo.com/?q=$search+site%3A$DuckDuckGoSearchDomain"});
}

View File

@@ -1,22 +1,18 @@
# Copyright (C) 2005 Alex Schroeder <alex@emacswiki.org>
# Copyright (C) 2005-2013 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 2 of the License, or
# (at your option) any later version.
# 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.
# 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, write to the
# Free Software Foundation, Inc.
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/dynamic-comments.pl">dynamic-comments.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Dynamic_Comments_Extension">Dynamic Comments Extension</a></p>';
AddModuleDescription('dynamic-comments.pl', 'Dynamic Comments Extension');
push(@MyInitVariables, \&DynamicCommentsAddScript);
@@ -51,7 +47,7 @@ sub DynamicCommentsNewGetPageLink {
my $anchor = "id" . $num++;
return qq{<a href="javascript:togglecomments('$anchor')">$title</a>}
. '</p>' # close p before opening div
. $q->div({-class=>commenthidden, -id=>$anchor},
. $q->div({-class=>'commenthidden', -id=>$anchor},
$page,
$q->p(DynamicCommentsOldGetPageLink($id, T('Add Comment'))))
. '<p>'; # open an empty p that will be closed in PrintAllPages

View File

@@ -27,7 +27,7 @@
# $LogoUrl = GetDynLogoUrl();
#
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/dynlogo.pl">dynlogo.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Dynamic_Logo">Dynamic Logo</a></p>';
AddModuleDescription('dynlogo.pl', 'Dynamic Logo');
use vars qw($DynLogoDirectory $DynLogoDefault %DynLogoMap);

View File

@@ -15,7 +15,7 @@
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/edit-assist.pl">edit-assist.pl</a></p>';
AddModuleDescription('edit-assist.pl');
push (@MyInitVariables,
sub {

View File

@@ -1,3 +1,5 @@
AddModuleDescription('edit-cluster.pl');
$EditCluster = 'EditCluster';
sub GetRc {
@@ -88,7 +90,7 @@ sub EditClusterNewRcHeader {
} else {
print $q->h2((GetParam('days', $RcDefault) != 1)
? Ts('Updates in the last %s days', GetParam('days', $RcDefault))
: Ts('Updates in the last %s day', GetParam('days', $RcDefault)))
: Ts('Updates in the last day'))
}
my $action;
my ($idOnly, $userOnly, $hostOnly, $clusterOnly, $filterOnly, $match, $lang) =

View 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);

213
modules/edit-paragraphs.pl Normal file
View File

@@ -0,0 +1,213 @@
# 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 = '&#x270E;';
# Allow editing of substrings
$Action{'edit-paragraph'} = \&DoEditParagraph;
sub DoEditParagraph {
my $id = UnquoteHtml(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 {
$text = substr($text, 0, $around)
. "\n### around here ###\n"
. substr($text, $around)
if $around;
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) {
$pos = $EditParagraphs[0]->[1]; # just in case we're overshooting
$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 ...>&#x270E;</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 ...>&#x270E;</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 ...>&#x270E;</a></p>
# What we want, I guess, is this:
# <table><tr><td>...<a ...>&#x270E;</a></td></tr></table></p>
$pos = $pos || length(QuoteHtml($Page{text})); # make sure we have an around value
my $title = UrlEncode($OpenPageName);
my $paragraph = UrlEncode(UnquoteHtml($text));
my $link = ScriptLink("action=edit-paragraph;title=$title;around=$pos;paragraph=$paragraph",
$EditParagraphPencil, 'pencil');
if ($Fragment =~ s!((:?</h[1-6]>|</t[dh]></tr></table>|</pre>)<p>)$!!) {
# $Fragment .= '<!-- moved inside -->';
$Fragment .= $link . $1;
} elsif ($Fragment =~ s!(</p>\s*</form>)$!!) {
# $Fragment .= '<!-- HTML fixes for <html> -->';
# Since anything can appear in raw HTML tags, there is no one-size fits all rule.
# I usually use the <html> tags to embed forms, and forms need to contain a <p>.
# so that's what I'm handling.
$Fragment .= $link . $1;
} elsif ($pos and $Fragment =~ /<(p|tr)>$/) {
# Do nothing: this is either an empty paragraph and will be
# eliminated, or an empty row which will not be shown.
# $Fragment .= '<!-- empty -->';
} else {
# This is the default: add the link.
# $Fragment .= '<!-- default -->';
$Fragment .= $link;
}
}
}

View File

@@ -10,7 +10,7 @@
# For user doc, see:
# http://www.oddmuse.org/cgi-bin/oddmuse/Email_Quote_Extension
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/emailquote.pl">emailquote.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Email_Quote_Extension">Email Quote Extension</a></p>';
AddModuleDescription('emailquote.pl', 'Email Quote Extension');
push(@MyRules, \&EmailQuoteRule);

66
modules/emoji.pl Normal file
View File

@@ -0,0 +1,66 @@
# 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/>.
AddModuleDescription('emoji.pl', 'Smilies');
push(@MyRules, \&EmojiRule);
# this must come before tex.pl because of \o/ turning into ø/
$RuleOrder{\&EmojiRule} = 150;
# Some relevant links
# https://en.wikipedia.org/wiki/List_of_emoticons
sub EmojiRule {
if (m/\G:-?D/cg) {
# 😀 1F600 GRINNING FACE
return '&#x1F600;';
} elsif (/\G:[-o]?\)/cg) {
# 😊 1F60A SMILING FACE WITH SMILING EYES
return '&#x1F60A;';
} elsif (/\G\s+:3/cg) {
# 😸 1F638 GRINNING CAT FACE WITH SMILING EYES
return ' &#x1f638;';
} elsif (/\G:-?\(/cg) {
# 😟 1F61F WORRIED FACE
return '&#x1F61F;';
} elsif (/\G;-?\)/cg) {
# 😉 1F609 WINKING FACE
return '&#x1F609;';
} elsif (/\G:'\(/cg) {
# 😢 1F622 CRYING FACE
return '&#x1F622;';
} elsif (/\G&gt;:-?\(/cg) {
# 😠 1F620 ANGRY FACE
return '&#x1F620;';
} elsif (/\G:-?[Ppb]/cg) {
# 😝 1F61D FACE WITH STUCK-OUT TONGUE AND TIGHTLY-CLOSED EYES
return '&#x1F61D;';
} elsif (/\G&lt;3/cg) {
# ❤ 2764 HEAVY BLACK HEART
return '&#x2764;';
} elsif (/\G\^_*\^/cg) {
# 😄 1F604 SMILING FACE WITH OPEN MOUTH AND SMILING EYES
return '&#x1F604;';
} elsif (/\G\b[Oo]_[Oo]\b/cg) {
# 😲 1F632 ASTONISHED FACE
return '&#x1F632;';
} elsif (/\G\\o\//cg) {
# 🙌 1F64C PERSON RAISING BOTH HANDS IN CELEBRATION
return '&#x1F64C;';
} elsif (/\G\\m\//cg) {
# ✊ 270A RAISED FIST
return '&#x270A;';
}
return undef;
}

View File

@@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/enclosure.pl">enclosure.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Podcasting">Podcasting</a></p>';
AddModuleDescription('enclosure.pl', 'Podcasting');
use vars qw(@Enclosures);

View File

@@ -23,7 +23,7 @@
# Additionally, lines starting with Q: and A: are rendered using
# the css classes div.question and div.answer.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/faq.pl">faq.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/FAQ_Extension">FAQ Extension</a></p>';
AddModuleDescription('faq.pl', 'FAQ Extension');
$FaqHeaderText = "Questions on this page:" unless $FaqHeaderText;
$FaqQuestionText = "Question: " unless $FaqQuestionText;

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA,
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/fckeditor.pl">fckeditor.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Using_FCKeditor_In_Addition_To_Wiki_Markup">Using FCKeditor In Addition To Wiki Markup</a></p>';
AddModuleDescription('fckeditor.pl', 'Using FCKeditor In Addition To Wiki Markup');
use vars qw($FCKeditorHeight);

View File

@@ -10,7 +10,7 @@
# For user doc, see:
# http://www.oddmuse.org/cgi-bin/oddmuse/Field_List_Extension
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/fieldlist.pl">fieldlist.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Field_List_Extension">Field List Extension</a></p>';
AddModuleDescription('fieldlist.pl', 'Field List Extension');
push(@MyRules, \&FieldListRules);

View File

@@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/find.pl">find.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Find_Extension">Find Extension</a></p>';
AddModuleDescription('find.pl', 'Find Extension');
$Action{find} = \&DoFind;

57
modules/fix-encoding.pl Normal file
View File

@@ -0,0 +1,57 @@
# Copyright (C) 2012 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/>.
AddModuleDescription('fix-encoding.pl', 'Fix Encoding');
$Action{'fix-encoding'} = \&FixEncoding;
sub FixEncoding {
my $id = shift;
ValidIdOrDie($id);
RequestLockOrError();
OpenPage($id);
my $text = $Page{text};
utf8::decode($text);
Save($id, $text, T('Fix character encoding'), 1) if $text ne $Page{text};
ReleaseLock();
ReBrowsePage($id);
}
$Action{'fix-escaping'} = \&FixEscaping;
sub FixEscaping {
my $id = shift;
ValidIdOrDie($id);
RequestLockOrError();
OpenPage($id);
my $text = UnquoteHtml($Page{text});
Save($id, $text, T('Fix HTML escapes'), 1) if $text ne $Page{text};
ReleaseLock();
ReBrowsePage($id);
}
push(@MyAdminCode, \&FixEncodingMenu);
sub FixEncodingMenu {
my ($id, $menuref, $restref) = @_;
if ($id && GetParam('username')) {
push(@$menuref,
ScriptLink('action=fix-encoding;id=' . UrlEncode($id),
T('Fix character encoding')));
push(@$menuref,
ScriptLink('action=fix-escaping;id=' . UrlEncode($id),
T('Fix HTML escapes')));
}
}

View File

@@ -15,7 +15,7 @@ directory of your Oddmuse Wiki.
=cut
package OddMuse;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/flashbox.pl">flashbox.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Flashbox_Extension">Flashbox Extension</a></p>';
AddModuleDescription('flashbox.pl', 'Flashbox Extension');
# ....................{ CONFIGURATION }....................

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/flickrgallery.pl">flickrgallery.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/FlickrGallery_Module">FlickrGallery Module</a></p>';
AddModuleDescription('flickrgallery.pl', 'FlickrGallery Module');
# NOTE: This API key for Flickr is NOT to be used in any other products
# INCLUDING derivative works. The rest of the code can be used as licensed

View File

@@ -13,7 +13,7 @@ directory for your Oddmuse Wiki.
=cut
package OddMuse;
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/footnotes.pl">footnotes.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Footnotes_Extension">Footnotes Extension</a></p>';
AddModuleDescription('footnotes.pl', 'Footnotes Extension');
# ....................{ CONFIGURATION }....................

106
modules/form_timeout.pl Normal file
View File

@@ -0,0 +1,106 @@
# form_timeout.pl - a form timeout based anti-spam module for Oddmuse
#
# Copyright (C) 2014 Aki Goto <tyatsumi@gmail.com>
#
# Original code is in PHP from http://textcaptcha.com/really
# by Rob Tuley <hello@rob.cx>. Used with permission.
#
# 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/>.
AddModuleDescription('form_timeout.pl');
=head1 DESCRIPTION
This is an anti-spam module for Oddmuse using form timeout method.
Edit permission is timed out in specified duration (default is 30 minutes)
after viewing the edit form. When edit content is posted directly by a spam bot
without viewing the edit form, edit will be denied.
=head1 CONFIGURATION
$FormTimeoutSalt
Mandatory. Token hash salt. Specify arbitrary string.
Default = undef.
$FormTimeoutTimeout
The form timeout in seconds.
Default = 60 * 30 (30 minutes).
=cut
use vars qw($FormTimeoutSalt $FormTimeoutTimeout);
use Digest::MD5 qw(md5_hex);
$FormTimeoutSalt = undef;
$FormTimeoutTimeout = 60 * 30; # 30 minutes
push(@MyInitVariables, \&FormTimeoutInitVariables);
sub FormTimeoutInitVariables {
if (!defined($FormTimeoutSalt)) {
ReportError(T('Set $FormTimeoutSalt.'), '500 INTERNAL SERVER ERROR');
}
}
sub FormTimeoutGetHash {
my ($when) = @_;
return md5_hex($FormTimeoutSalt . $when);
}
sub FormTimeoutGetToken {
return $Now . '#' . FormTimeoutGetHash($Now);
}
sub FormTimeoutGetTime {
my ($token) = @_;
my ($when, $hash) = split /#/, $token;
my $valid_hash = FormTimeoutGetHash($when);
if ($hash ne $valid_hash) {
return '';
}
return $when;
}
sub FormTimeoutCheck {
my $token = GetParam('form_timeout_token', '');
my $when = FormTimeoutGetTime($token);
if ($when eq '' || $when < $Now - $FormTimeoutTimeout) {
return 0;
}
return 1;
}
*OldFormTimeoutGetFormStart = *GetFormStart;
*GetFormStart = *NewFormTimeoutGetFormStart;
sub NewFormTimeoutGetFormStart {
my ($ignore, $method, $class) = @_;
my $form = OldFormTimeoutGetFormStart($ignore, $method, $class);
my $token = FormTimeoutGetToken();
$form .= $q->input({-type=>'hidden', -name=>'form_timeout_token',
-value=>$token});
return $form;
}
*OldFormTimeoutDoEdit = *DoEdit;
*DoEdit = *NewFormTimeoutDoEdit;
sub NewFormTimeoutDoEdit {
my ($id, $newText, $preview) = @_;
if (!FormTimeoutCheck()) {
ReportError(T('Form Timeout'), '403 FORBIDDEN', undef,
$q->p(Ts('Editing not allowed: %s is read-only.', NormalToFree($id))));
}
OldFormTimeoutDoEdit($id, $newText, $preview);
}

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env perl
# ====================[ forms.pl ]====================
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/forms.pl">forms.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Form_Extension">Form Extension</a></p>';
AddModuleDescription('forms.pl', 'Form Extension');
# ....................{ MARKUP }....................
push(@MyRules, \&FormsRule);

60
modules/fractions.pl Normal file
View File

@@ -0,0 +1,60 @@
# Copyright (C) 2013 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/>.
AddModuleDescription('fractions.pl', 'Fractions');
push(@MyRules, \&FractionsRule);
# usage: ^1/32
sub FractionsRule {
if (/\G\^([0-9]+)\/([0-9]+)/cg) {
if ($1 == 1 and $2 == 4) { return "\&#x00bc;"; }
elsif ($1 == 1 and $2 == 2) { return "\&#x00bd;"; }
elsif ($1 == 3 and $2 == 4) { return "\&#x00be;"; }
elsif ($1 == 1 and $2 == 7) { return "\&#x2150;"; }
elsif ($1 == 1 and $2 == 9) { return "\&#x2151;"; }
elsif ($1 == 1 and $2 == 10) { return "\&#x2152;"; }
elsif ($1 == 1 and $2 == 3) { return "\&#x2153;"; }
elsif ($1 == 2 and $2 == 3) { return "\&#x2154;"; }
elsif ($1 == 1 and $2 == 5) { return "\&#x2155;"; }
elsif ($1 == 2 and $2 == 5) { return "\&#x2156;"; }
elsif ($1 == 3 and $2 == 5) { return "\&#x2157;"; }
elsif ($1 == 4 and $2 == 5) { return "\&#x2158;"; }
elsif ($1 == 1 and $2 == 6) { return "\&#x2159;"; }
elsif ($1 == 5 and $2 == 6) { return "\&#x215a;"; }
elsif ($1 == 1 and $2 == 8) { return "\&#x215b;"; }
elsif ($1 == 3 and $2 == 8) { return "\&#x215c;"; }
elsif ($1 == 5 and $2 == 8) { return "\&#x215d;"; }
elsif ($1 == 7 and $2 == 8) { return "\&#x215e;"; }
else {
my $html;
# superscripts
for my $char (split(//, $1)) {
if ($char eq '1') { $html .= "\&#x00b9;"; }
elsif ($char eq '2') { $html .= "\&#x00b2;"; }
elsif ($char eq '3') { $html .= "\&#x00b3;"; }
else { $html .= "\&#x207$char;"; }
}
# fraction slash
$html .= '&#x2044;';
# subscripts
for my $char (split(//, $2)) {
$html .= "\&#x208$char;";
}
return $html;
}
}
return undef;
}

View File

@@ -0,0 +1,398 @@
# GdSecurityImage - a CAPTCHA module for Oddmuse using GD::SecurityImage module
#
# Copyright (C) 2014 Aki Goto <tyatsumi@gmail.com>
#
# Codes reused from MwfCaptcha.pm in mwForum - Web-based discussion forum
# Copyright (c) 1999-2014 Markus Wichitill
#
# Codes reused from questionasker.pl for Oddmuse
# Copyright (C) 2004 Brock Wilcox <awwaiid@thelackthereof.org>
# Copyright (C) 2006, 2007 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/>.
AddModuleDescription('gd_security_image.pl');
=head1 DESCRIPTION
This is a CAPTCHA module for Oddmuse using GD::SecurityImage module.
=head1 CONFIGURATION
$GdSecurityImageFont
Mandatory.
Set a TTF font file used for generating CAPTCHA images.
Example: '/usr/share/fonts/truetype/ttf-bitstream-vera/VeraBd.ttf'.
$GdSecurityImageRememberAnswer
If 1, once CAPTCHA is answered, the result is cached on cookies
and you need not to re-answer CAPTCHAs for some duration specified
by $GdSecurityImageDuration.
If 0, CAPTCHA is requested everytime you try to submit forms.
Default = 1.
$GdSecurityImageDuration
The duration a CAPTCHA ticket is valid in seconds.
Default = 60 * 10 (10 minutes).
$GdSecurityImageRequiredList
The page name for exceptions, if defined. Every page linked to via
WikiWord or [[free link]] is considered to be a page which needs
questions asked. All other pages do not require questions asked. If
not set, then all pages need questions asked.
%GdSecurityImageProtectedForms
Forms using one of the specified classes are protected.
Default: ('comment' => 1, 'edit upload' => 1, 'edit text' => 1,).
$GdSecurityImageDataDir
When using with Namespaces Extension, specify original root data directory
to concentrate GdSecurityImage data files in it.
Default: $DataDir.
$GdSecurityImageWidth
Default: 250.
$GdSecurityImageHeight
Default: 60.
$GdSecurityImagePtsize
Default: 16.
$GdSecurityImageScramble
Default: 1.
$GdSecurityImageChars
Default: [qw(A B C D E F G H I J K L M O P R S T U V W X Y)].
=head1 API
You can use this module in other modules by using following APIs.
GdSecurityImageGetHtml
returns CAPTCHA HTML form element for embedding in HTML form clause.
GdSecurityImageCheck
returns whether CAPTCHA is answered correctly or not.
=head1 DATA STRUCTURE
Image data and ticket data are stored in $DataDir/gd_security_image directory.
Old data are deleted partially whenever CAPTCHA form is accessed.
You can delete this directory totally harmlessly, although it forces users to
re-answer CAPTCHA.
=cut
use vars qw($GdSecurityImageFont $GdSecurityImageRememberAnswer
$GdSecurityImageDuration $GdSecurityImageRequiredList
%GdSecurityImageProtectedForms $GdSecurityImageDataDir
$GdSecurityImageWidth $GdSecurityImageHeight
$GdSecurityImagePtsize $GdSecurityImageScramble $GdSecurityImageChars
$GdSecurityImageAA);
use vars qw($GdSecurityImageDir $GdSecurityImageId $GdSecurityImagePngToAA);
use Digest::MD5;
use File::Glob ':glob';
$GdSecurityImageRequiredList = '';
$Action{gd_security_image} = \&GdSecurityImageDoImage;
push(@MyInitVariables, \&GdSecurityImageInitVariables);
sub GdSecurityImageGetImageFile {
my ($id) = @_;
return "$GdSecurityImageDir/$id.png";
}
sub GdSecurityImageGetTicketFile {
my ($id) = @_;
return "$GdSecurityImageDir/$id.ticket";
}
sub GdSecurityImageGenerate {
# Load modules
my $gd = eval { require GD };
eval { require Image::Magick }
or ReportError(T('GD or Image::Magick modules not available.'), '500 INTERNAL SERVER ERROR') if !$gd;
eval { require GD::SecurityImage }
or ReportError(T('GD::SecurityImage module not available.'));
# Generate captcha image
GD::SecurityImage->import($gd ? () : (use_magick => 1));
my $img = GD::SecurityImage->new(
width => $GdSecurityImageWidth,
height => $GdSecurityImageHeight,
font => $GdSecurityImageFont,
ptsize => $GdSecurityImagePtsize,
scramble => $GdSecurityImageScramble,
rnd_data => $GdSecurityImageChars,
bgcolor => '#000000',
);
$img->random();
my $newCaptchaStr = $img->random_str();
$img->create('ttf', int(rand(2)) ? 'default' : 'ec', '#ffffff', '#ffffff');
$img->particle(3000);
### experimental ###
#my $raw = $img->raw;
#my $w2 = $GdSecurityImageWidth * 2 / 3;
#my $h2 = $GdSecurityImageHeight * 2 / 3;
#my $raw2 = GD::Image->new($w2, $h2);
#$raw2->copyResampled($raw, 0, 0, 0, 0, $w2, $h2, $raw->getBounds);
#my $png = $raw2->png;
# Store captcha image
my ($imgData) = $img->out(force => 'png');
my $ticketId = Digest::MD5::md5_hex(rand());
CreateDir($GdSecurityImageDir);
my $file = GdSecurityImageGetImageFile($ticketId);
open my $fh, ">:raw", $file
or ReportError(Ts('Image storing failed. (%s)', $!), '500 INTERNAL SERVER ERROR');
print $fh $imgData;
#print $fh $png; ### experimental ###
close $fh;
# Insert captcha ticket
my %page = ();
$page{id} = $ticketId;
$page{generation_time} = $Now;
$page{string} = $newCaptchaStr;
CreateDir($GdSecurityImageDir);
WriteStringToFile(GdSecurityImageGetTicketFile($ticketId), EncodePage(%page));
return $ticketId;
}
sub GdSecurityImageIsValidId {
my ($id) = @_;
return $id =~ /^[0-9a-f]+$/;
}
sub GdSecurityImageReadImageFile {
my $file = shift;
utf8::encode($file); # filenames are bytes!
if (open(IN, '<:raw', $file)) {
local $/ = undef; # Read complete files
my $data=<IN>;
close IN;
return (1, $data);
}
return (0, '');
}
sub GdSecurityImageDoImage {
my $id = GetParam('gd_security_image_id', '');
if (!GdSecurityImageIsValidId($id)) {
ReportError(T('Bad gd_security_image_id.'), '400 BAD REQUEST');
}
my ($status, $data) = GdSecurityImageReadImageFile(GdSecurityImageGetImageFile($id));
binmode(STDOUT, ":raw");
print $q->header(-type=>'image/png');
print $data;
unlink(GdSecurityImageGetImageFile($id));
}
sub GdSecurityImageCleanup {
my ($id) = @_;
if (!GdSecurityImageIsValidId($id)) {
return;
}
my @files = (bsd_glob("$GdSecurityImageDir/*.png"), bsd_glob("$GdSecurityImageDir/*.ticket"));
foreach my $file (@files) {
if ($Now - (stat $file)[9] > $GdSecurityImageDuration) {
unlink($file);
}
}
}
sub GdSecurityImageCheck {
if (defined($GdSecurityImageId)) {
return $GdSecurityImageId eq '';
}
my $id = GetParam('gd_security_image_id', '');
my $answer = GetParam('gd_security_image_answer', '');
GdSecurityImageCleanup($id);
if ($answer ne '' && GdSecurityImageIsValidId($id)) {
my ($status, $data) = ReadFile(GdSecurityImageGetTicketFile($id));
if ($status) {
my %page = ParseData($data);
if ($page{generation_time} + $GdSecurityImageDuration > $Now) {
if ($answer eq $page{string}) {
$GdSecurityImageId = '';
if (!$GdSecurityImageRememberAnswer) {
SetParam('gd_security_image_id', '');
SetParam('gd_security_image_answer', '');
}
return 1;
}
}
}
}
if (GdSecurityImageIsValidId($id)) {
unlink(GdSecurityImageGetTicketFile($id));
}
$GdSecurityImageId = GdSecurityImageGenerate();
return 0;
}
sub GdSecurityImageGetHtml {
if (GdSecurityImageCheck()) {
return '';
}
my $form = '';
SetParam('gd_security_image_answer', '');
$form .= $q->start_div({-class=>'gd_security_image'});
$form .= $q->start_div();
$form .= T('Please type the six characters from the anti-spam image');
$form .= $q->end_div();
$form .= $q->start_div();
$form .= $q->input({-type=>'hidden', -name=>'gd_security_image_id', -value=>$GdSecurityImageId});
$form .= $q->textfield(-name=>'gd_security_image_answer', -id=>'gd_security_image_answer');
$form .= $q->submit(-name=>'Submit', -value=>T('Submit'));
$form .= $q->end_div();
$form .= $q->start_div();
$form .= $q->img({-src=>"$FullUrl?action=gd_security_image&gd_security_image_id=$GdSecurityImageId", -alt=>T('CAPTCHA'), -width=>$GdSecurityImageWidth, -height=>$GdSecurityImageHeight});
$form .= $q->end_div();
if ($GdSecurityImageAA) {
$form .= $q->start_div({class=>'aa_captcha'});
$form .= $q->start_pre();
my $png_file = GdSecurityImageGetImageFile($GdSecurityImageId);
$form .= `$GdSecurityImagePngToAA $png_file`;
$form .= $q->end_pre();
$form .= $q->end_div();
}
$form .= $q->end_div();
return $form;
}
*OldGdSecurityImageDoPost = *DoPost;
*DoPost = *NewGdSecurityImageDoPost;
sub NewGdSecurityImageDoPost {
my(@params) = @_;
my $id = FreeToNormal(GetParam('title', undef));
my $preview = GetParam('Preview', undef); # case matters!
unless (UserIsEditor()
or $preview
or GdSecurityImageCheck()
or GdSecurityImageException($id)) {
print GetHeader('', T('Edit Denied'), undef, undef, '403 FORBIDDEN');
print $q->p(T('You did not answer correctly.'));
print GetFormStart(), GdSecurityImageGetHtml(),
(map { $q->input({-type=>'hidden', -name=>$_, -value=>UnquoteHtml(GetParam($_))}) }
qw(title text oldtime summary recent_edit aftertext)), $q->end_form;
PrintFooter();
# logging to the error log file of the server
# warn "Q: '$QuestionaskerQuestions[$question_num][0]', A: '$answer'\n";
return;
}
return (OldGdSecurityImageDoPost(@params));
}
*OldGdSecurityImageGetEditForm = *GetEditForm;
*GetEditForm = *NewGdSecurityImageGetEditForm;
sub NewGdSecurityImageGetEditForm {
return GdSecurityImageAddTo(OldGdSecurityImageGetEditForm(@_));
}
*OldGdSecurityImageGetCommentForm = *GetCommentForm;
*GetCommentForm = *NewGdSecurityImageGetCommentForm;
sub NewGdSecurityImageGetCommentForm {
return GdSecurityImageAddTo(OldGdSecurityImageGetCommentForm(@_));
}
sub GdSecurityImageAddTo {
my $form = shift;
if (not $upload
and not GdSecurityImageException(GetId())
and not UserIsEditor()) {
my $question = GdSecurityImageGetHtml();
$form =~ s/(.*)<p>(.*?)<label for="username">/$1$question<p>$2<label for="username">/;
}
return $form;
}
sub GdSecurityImageException {
my $id = shift;
return 0 unless $GdSecurityImageRequiredList and $id;
my $data = GetPageContent($GdSecurityImageRequiredList);
if ($WikiLinks) {
while ($data =~ /$LinkPattern/g) {
return 0 if FreeToNormal($1) eq $id;
}
}
if ($FreeLinks) {
while ($data =~ /\[\[$FreeLinkPattern\]\]/g) {
return 0 if FreeToNormal($1) eq $id;
}
}
return 1;
}
sub GdSecurityImageInitVariables {
ReportError(T('$GdSecurityImageFont is not set.'), '500 INTERNAL SERVER ERROR') unless defined $GdSecurityImageFont;
$GdSecurityImageRememberAnswer = 1 unless defined $GdSecurityImageRememberAnswer;
$GdSecurityImageDuration = 60 * 10 unless defined $GdSecurityImageDuration;
$GdSecurityImageRequiredList = FreeToNormal($GdSecurityImageRequiredList);
# Forms using one of the following classes are protected.
%GdSecurityImageProtectedForms = ('comment' => 1,
'edit upload' => 1,
'edit text' => 1,)
unless defined %GdSecurityImageProtectedForms;
$GdSecurityImageDataDir = $DataDir unless defined $GdSecurityImageDataDir;
$GdSecurityImageWidth = 240 unless defined $GdSecurityImageWidth;
$GdSecurityImageHeight = 75 unless defined $GdSecurityImageHeight;
$GdSecurityImagePtsize = 16.75 unless defined $GdSecurityImagePtsize;
$GdSecurityImageScramble = 1 unless defined $GdSecurityImageScramble;
$GdSecurityImageChars = [qw(A B C D E F G H I J K L M O P R S T U V W X Y)] unless defined $GdSecurityImageChars;
$GdSecurityImageAA = 0 unless defined $GdSecurityImageAA;
$GdSecurityImageDir = "$GdSecurityImageDataDir/gd_security_image";
$GdSecurityImageId = undef;
$GdSecurityImagePngToAA = "$ModuleDir/pngtoaa";
$CookieParameters{'gd_security_image_id'} = '';
$InvisibleCookieParameters{'gd_security_image_id'} = 1;
$CookieParameters{'gd_security_image_answer'} = '';
$InvisibleCookieParameters{'gd_security_image_answer'} = 1;
}

72
modules/git-another.pl Normal file
View File

@@ -0,0 +1,72 @@
# Copyright (C) 2014 Alex-Daniel Jakimenko <alex.jakimenko@gmail.com>
# Copyright (C) 2011 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('git-another.pl', 'Another Git Extension');
use Cwd;
use Capture::Tiny ':all';
use vars qw($GitBinary $GitMail);
$GitBinary = 'git';
$GitMail = 'unknown@oddmuse.org';
sub GitCommit {
my ($message, $author) = @_;
my $oldDir = cwd;
chdir("$DataDir/page");
capture {
system($GitBinary, qw(add -A));
system($GitBinary, qw(commit -q -m), $message, "--author=$author <$GitMail>");
};
chdir($oldDir);
}
sub GitInitRepository {
return if -d "$DataDir/page/.git";
capture {
system($GitBinary, qw(init -q --), "$DataDir/page");
};
GitCommit('Initial import', 'Oddmuse');
}
sub RenderHtmlCacheWithoutPrinting { # requires an open page
$FootnoteNumber = 0;
my $blocks, $flags;
capture {
($blocks, $flags) = ApplyRules(QuoteHtml($Page{text}), 1, 1, $Page{revision}, 'p');
};
if ($Page{blocks} ne $blocks and $Page{flags} ne $flags) {
$Page{blocks} = $blocks;
$Page{flags} = $flags;
SavePage();
}
}
*GitOldSave = *Save;
*Save = *GitNewSave;
sub GitNewSave {
GitInitRepository();
GitCommit('No description available', 'Oddmuse'); # commit any changes before this edit
GitOldSave(@_);
RenderHtmlCacheWithoutPrinting();
my $message = $Page{summary};
$message =~ s/^\s+$//;
$message ||= T('No summary provided');
my $author = $Page{username} || T('Anonymous');
GitCommit($message, $author); # commit this edit
}

View File

@@ -31,7 +31,7 @@ Set these variables in the B<config> file within your data directory.
=head2 $GitBinary
Default: C</usr/bin/git>
Default: C<git>
The fully qualified name for the binary to run. Your PATH will not be searched.
@@ -48,31 +48,56 @@ Default: C<unknown@oddmuse.org>
The email address used to identify users in git.
=head2 $GitDebug
Default: 0
If set, we capture the output of the git command and store it in
$GitResult. This is useful when writing tests.
=head2 $GitResult
If $GitDebug is set, this variable holds STDOUT of the git command.
=cut
use vars qw($GitBinary $GitRepo $GitMail);
use Cwd;
use File::Temp ();
use vars qw($GitBinary $GitRepo $GitMail $GitPageFile $GitDebug $GitResult);
$GitBinary = '/usr/bin/git';
AddModuleDescription('git.pl', 'Git Extension');
$GitBinary = 'git';
$GitMail = 'unknown@oddmuse.org';
$GitPageFile = 0;
push(@MyInitVariables, \&GitInitVariables);
sub GitRun {
my $result = '';
local *STDOUT;
open(STDOUT, '>', \$result) or die "Can't open memory file: $!";
system($GitBinary, @_) == 0
or ReportError("git failed: $!",
"500 INTERNAL SERVER ERROR",
undef,
$q->p($q->tt(join(' ', $GitBinary, map {
if (index($_, ' ') == -1) {
$_;
} else {
"'$_'";
}
} @_))),
$q->pre($result));
my $oldDir = cwd;
my $exitStatus;
# warn join(' ', $GitBinary, @_) . "\n";
chdir($GitRepo);
if ($GitDebug) {
# capture the output of the git comand in a temporary file
my $fh = File::Temp->new();
open(my $oldout, ">&STDOUT") or die "Can't dup STDOUT: $!";
open(STDOUT, '>', $fh) or die "Can't redirect STDOUT: $!";
# run git in the work directory
$exitStatus = system($GitBinary, @_);
# read the temporary file with the output
close($fh);
open(STDOUT, ">&", $oldout) or die "Can't dup \$oldout: $!";
open(F, '<', $fh) or die "Can't open temp file for reading: $!";
local $/ = undef; # Read complete files
$GitResult = <F>;
close(F);
} else {
$exitStatus = system($GitBinary, @_);
}
chdir($oldDir);
return $exitStatus;
}
sub GitInitVariables {
@@ -80,39 +105,50 @@ sub GitInitVariables {
}
sub GitInitRepository {
if (not -d "$GitRepo/.git") {
CreateDir($GitRepo);
chdir($GitRepo); # important for all the git commands that follow!
GitRun('init', '--quiet');
foreach my $id (AllPagesList()) {
OpenPage($id);
WriteStringToFile("$GitRepo/$id", $Page{text});
GitRun('add', $id);
}
GitRun('commit', '--quiet', '-m', 'initial import',
"--author=Oddmuse <$GitMail>");
} else {
chdir($GitRepo); # important for all the git commands that follow!
return if -d "$GitRepo/.git";
my $exception = shift;
CreateDir($GitRepo);
GitRun(qw(init --quiet));
# Add legacy pages: If you installed this extension for an older
# wiki, all the existing pages need to be added. We do this for all
# the pages except for the one we just saved. That page will get a
# better author and log message.
foreach my $id (AllPagesList()) {
next if $id eq $exception;
OpenPage($id);
WriteStringToFile("$GitRepo/$id", $GitPageFile ? EncodePage(%Page) : $Page{text});
GitRun(qw(add --), $id);
}
GitRun(qw(commit --quiet -m), 'initial import', "--author=Oddmuse <$GitMail>");
}
*GitOldSave = *Save;
*Save = *GitNewSave;
sub GitNewSave {
# Save is called within lock, with opened page. That's why we cannot
# call GitInitRepository right away, because it opens all the legacy
# pages to save them, too. We need to save first.
GitOldSave(@_);
GitInitRepository();
my ($id) = @_;
WriteStringToFile("$GitRepo/$id", $Page{text});
if ($Page{revision} == 1) {
GitRun('add', $id);
}
# We also need to save all the data from the open page.
my $message = $Page{summary};
$message =~ s/^\s+$//;
$message ||= T('no summary available');
my $author = $Page{username} || T('Anonymous');
GitRun('commit', '--quiet', '-m', $message,
"--author=$author <$GitMail>", $id);
my $data = $GitPageFile ? EncodePage(%Page) : $Page{text};
my $id = shift;
# GitInitRepository will try to add and commit all the pages already
# in the wiki. These are assumed to be legacy pages. The page we
# just saved, however, should not be committed as a legacy page
# because legacy pages are committed with a default author and log
# message!
GitInitRepository($id);
WriteStringToFile("$GitRepo/$id", $data);
GitRun(qw(add --), $id);
GitRun(qw(commit --quiet -m), $message,
"--author=$author <$GitMail>", '--', $id);
}
*GitOldDeletePage = *DeletePage;
@@ -123,36 +159,59 @@ sub GitNewDeletePage {
return $error if $error;
GitInitRepository();
my ($id) = @_;
GitRun('rm', '--quiet', '--ignore-unmatch', $id);
GitRun(qw(rm --quiet --ignore-unmatch --), $id);
my $message = T('page was marked for deletion');
my $author = T('Oddmuse');
GitRun('commit', '--quiet', '-m', $message,
"--author=$author <$GitMail>", $id);
GitRun(qw(commit --quiet -m), $message,
"--author=$author <$GitMail>", '--', $id);
return ''; # no error
}
push(@MyMaintenance, \&GitCleanup);
$Action{git} = \&DoGitCleanup;
sub DoGitCleanup {
UserIsAdminOrError();
print GetHeader('', 'Git', '');
print $q->start_div({-class=>'content git'});
RequestLockOrError();
print $q->p(T('Main lock obtained.')), '<p>', T('Cleaning up git repository');
GitCleanup();
ReleaseLock();
print $q->p(T('Main lock released.')), $q->end_div();
PrintFooter();
}
sub GitCleanup {
if (-d $GitRepo) {
print $q->p('Git cleanup starting');
AllPagesList();
# delete all the files including all the files starting with a dot
opendir(DIR, $GitRepo) or ReportError("cannot open directory $GitRepo: $!");
foreach my $file (readdir(DIR)) {
next if $file eq '.git' or $file eq '.' or $file eq '..';
unlink "$GitRepo/$file" or ReportError("cannot delete $GitRepo/$file: $!");
my $name = $file;
utf8::decode($name); # filenames are bytes
next if $file eq '.git' or $file eq '.' or $file eq '..' or $IndexHash{$name};
print $q->p("Deleting left over file $name");
unlink "$GitRepo/$file" or ReportError("cannot delete $GitRepo/$name: $!");
}
closedir DIR;
# write all the files again
foreach my $id (AllPagesList()) {
# write all the files again, just to be sure
print $q->p('Rewriting all the files, just to be sure');
foreach my $id (@IndexList) {
OpenPage($id);
WriteStringToFile("$GitRepo/$id", $Page{text});
WriteStringToFile("$GitRepo/$id", $GitPageFile ? EncodePage(%Page) : $Page{text});
}
# run git!
chdir($GitRepo); # important for all the git commands that follow!
# add any new files
GitRun('add', '.');
print $q->p('Adding new files, if any');
GitRun(qw(add -A));
# commit the new state
GitRun('commit', '--quiet', '-a', '-m', 'maintenance job',
"--author=Oddmuse <$GitMail>");
print $q->p('Committing changes, if any');
my $exitStatus = GitRun(qw(commit --quiet -m), 'maintenance job',
"--author=Oddmuse <$GitMail>");
print $q->p('git commit finished with ' . $exitStatus . ' exit status.');
print $q->p('Git done');
}
}

View File

@@ -20,7 +20,7 @@ use vars qw($GoogleCustomSearchEngine);
$GoogleCustomSearchEngine = 'http://www.google.com/cse?cx=004774160799092323420:6-ff2s0o6yi&q=';
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/google-custom-search.pl">google-custom-search.pl</a></p>';
AddModuleDescription('google-custom-search.pl');
# disable search form
sub GetSearchForm {}
@@ -50,7 +50,7 @@ sub NewGoogleCustomGetSearchLink {
sub NewGoogleCustomGetHeader {
my $html = OldGoogleCustomGetHeader(@_);
$form .= qq {
my $form = qq {
<!-- Google CSE Search Box Begins -->
<form class="tiny" action="http://www.google.com/cse" id="searchbox_004774160799092323420:6-ff2s0o6yi"><p>
<input type="hidden" name="cx" value="004774160799092323420:6-ff2s0o6yi" />

View File

@@ -16,7 +16,7 @@
# 59 Temple Place, Suite 330
# Boston, MA 02111-1307 USA
$ModulesDescription .= '<p><a href="http://git.savannah.gnu.org/cgit/oddmuse.git/tree/modules/google-search.pl">google-search.pl</a>, see <a href="http://www.oddmuse.org/cgi-bin/oddmuse/Use_Google_For_Searches">Use Google For Searches</a></p>';
AddModuleDescription('google-search.pl', 'Use Google For Searches');
use vars qw($GoogleSearchDomain $GoogleSearchExclusive);

Some files were not shown because too many files have changed in this diff Show More