Imports initiaux
darcs-hash:20060414194001-d1718-ceecbd9d441a17318a957ec7b4686f85a4aa47b5.gz
This commit is contained in:
parent
1c6255c1d7
commit
8f2f2247d7
18 changed files with 5116 additions and 0 deletions
110
wiki/parser/Box.py
Normal file
110
wiki/parser/Box.py
Normal file
|
@ -0,0 +1,110 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin - Portail parser
|
||||
|
||||
PURPOSE:
|
||||
une boite jolie
|
||||
|
||||
CALLING SEQUENCE:
|
||||
{{{
|
||||
#!Box titre
|
||||
blablabla
|
||||
|
||||
tables, images....
|
||||
}}}
|
||||
|
||||
"""
|
||||
from MoinMoin.parser import wiki
|
||||
import os,string,re,StringIO
|
||||
from MoinMoin.action import AttachFile
|
||||
|
||||
#####################################################################
|
||||
# Fonctions #
|
||||
#####################################################################
|
||||
# to_wikiname : transfome la chaine text avec le parser wiki
|
||||
# classique et le formateur formatter
|
||||
# (je sais pas a quoi sert request, mais faut pas
|
||||
# l'enlever !)
|
||||
#######
|
||||
|
||||
def to_wikiname(request,formatter,text):
|
||||
##taken from MiniPage
|
||||
out=StringIO.StringIO()
|
||||
request.redirect(out)
|
||||
wikiizer = wiki.Parser(text,request)
|
||||
wikiizer.format(formatter)
|
||||
result=out.getvalue()
|
||||
request.redirect()
|
||||
del out
|
||||
|
||||
return result.strip()
|
||||
|
||||
#####################################################################
|
||||
# BoxFormatter : creer le code html
|
||||
#######
|
||||
class BoxFormatter:
|
||||
|
||||
def __init__(self, request, formatter):
|
||||
self.formatter = formatter
|
||||
self.request = request
|
||||
self.counter = 0
|
||||
|
||||
def make(self, title, body_html, color=None):
|
||||
if color==None:
|
||||
css_color_class=u""
|
||||
else:
|
||||
css_color_class = u" %s_box" % color
|
||||
html = [
|
||||
self.formatter.rawHTML(u'<div class="sidebox%s">' % css_color_class),
|
||||
self.formatter.rawHTML(u'<div class="boxhead">'),
|
||||
self.formatter.heading(1,3),
|
||||
title,
|
||||
self.formatter.heading(0,3),
|
||||
self.formatter.rawHTML(u'</div>'),
|
||||
self.formatter.rawHTML(u'<div class="boxbody1">'),
|
||||
self.formatter.rawHTML(u'<div class="boxbody2">'),
|
||||
body_html,
|
||||
self.formatter.rawHTML(u'</div>'),
|
||||
self.formatter.rawHTML(u'</div>'),
|
||||
self.formatter.rawHTML(u'</div>'),
|
||||
]
|
||||
self.request.write(u'\n'.join(html))
|
||||
|
||||
#####################################################################
|
||||
# Parser : classe principale, c'est elle qui parse
|
||||
#######
|
||||
class Parser:
|
||||
|
||||
def __init__(self, raw, request, **kw):
|
||||
self.request = request
|
||||
self.raw = raw
|
||||
self.settings={'title': u'|'.join([u" ".join(kw.keys()), u" ".join(kw.values())])}
|
||||
self.settings = self.parseArgs(kw["format_args"])
|
||||
|
||||
|
||||
def parseArgs(self, argsString):
|
||||
argList = argsString.split(u',')
|
||||
settings = {}
|
||||
for anArg in argList:
|
||||
anArg = anArg.strip(u' ')
|
||||
if anArg.find(u'color=')!=-1:
|
||||
settings['color'] = anArg.split(u'=')[1]
|
||||
else:
|
||||
settings['title'] = anArg
|
||||
return settings
|
||||
|
||||
def format(self, formatter):
|
||||
quotes = self.raw
|
||||
|
||||
# on utilise la classe qui va fabriquer le code html
|
||||
boite = BoxFormatter(self.request, formatter)
|
||||
title = self.settings['title']
|
||||
content = to_wikiname(self.request, formatter, quotes)
|
||||
try:
|
||||
color = self.settings['color']
|
||||
except:
|
||||
color=None
|
||||
boite.make( title,content, color)
|
||||
return
|
||||
|
||||
|
1193
wiki/parser/EXIF.py
Normal file
1193
wiki/parser/EXIF.py
Normal file
File diff suppressed because it is too large
Load diff
890
wiki/parser/Gallery2.py
Normal file
890
wiki/parser/Gallery2.py
Normal file
|
@ -0,0 +1,890 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin - Gallery2 parser
|
||||
|
||||
PURPOSE:
|
||||
This parser is used to visualize a couple of images as a thumbnail gallery.
|
||||
Optional a description of an image could be added including WikiName.
|
||||
On default the image name and it's creation date is shown.
|
||||
If you click on a thumbnail you get the webnails shown. By a menue you are able to toggle between the slides.
|
||||
|
||||
CALLING SEQUENCE:
|
||||
{{{
|
||||
#!Gallery2 [columns=columns],[filter=filter],[mode=mode],
|
||||
[show_text=show_text],[show_date=show_date], [show_tools=show_tools],
|
||||
[sort_by_name=sort_by_name],[sort_by_date=sort_by_date], [sort_by_alias=sort_by_alias],
|
||||
[reverse_sort=reverse_sort],
|
||||
[only_items=only_items],[template_itemlist=template_itemlist],
|
||||
[album=album],[album_name=album_name],[front_image=front_image],
|
||||
[thumbnail_width=thumbnail_width],[webnail_width=webnail_width],[text_width=text_width],
|
||||
[image_for_webnail=image_for_webnail],
|
||||
[border_thick=border_thick],[renew=renew],[help=help]
|
||||
* [image1.jpg alias]
|
||||
* [image2.jpg alias]
|
||||
}}}
|
||||
|
||||
KEYWORD PARAMETERS:
|
||||
columns: number of columns for thumbnails
|
||||
filter: regex to select images
|
||||
show_text: default is 1 description is shown
|
||||
any other means no description
|
||||
show_date: default is 1 date info from exif header if available is shown
|
||||
show_tools: default is 1 icon toolbar is show any other disables this
|
||||
sort_by_name: default is 1, the images are sorted by name, but not if only_items is 1
|
||||
sort_by_date: default is 0, if set to 1 the images are sorted to the modification time
|
||||
sort_by_alias default is 0, if set to 1 and only_items set to 1 it is used to order the images by the alias name
|
||||
reverse_sort: default is 0, if set to 1 the file list is reversed
|
||||
any other means no description
|
||||
mode: default is 1 this means description below the image
|
||||
any other number means description right of image
|
||||
only_items: default is 0 if it is set to 1 only images which are described in listitem are shown
|
||||
dependend on the order of the items
|
||||
template_itemlist: default is 0, if set to 1 an item list is shown which could be copied into the script.
|
||||
album: default is 0 if set to 1 only the first image of a series is shown but slideshow over all images
|
||||
album_name: useful for album. default is 'album' use it as short name for the album.
|
||||
front_image: Useful for album. default is ''. The first image is shown in front of the album and slideshow.
|
||||
If set to an existing image name this is shown in front of album and slideshow.
|
||||
The slide show could start by this somewhere.
|
||||
border_thick: default is 1 this is the thickness in pixeln of the outer frame
|
||||
renew: default is 0 if set to 1 then all selected thumbnails_* and webnails_* removed.
|
||||
Afterwards they are new created.
|
||||
thumbnail_width: default is 128
|
||||
webnail_width: default is 640
|
||||
text_width: default is 140
|
||||
image_for_webnail default is 0 if set to 1 then the image is shown as preview and not the webnail
|
||||
help: default is 0 if set a copy of the CALLING SEQUENCE is shown,
|
||||
(there are some new ideas around to show help to an user so this will be later replaced)
|
||||
|
||||
OPTIONAL INPUTS:
|
||||
itemlist : if it is used and only_items is 1 then only the images in this list are ahown.
|
||||
The alias text is used as description of the image instead of the file name
|
||||
|
||||
|
||||
EXAMPLE:
|
||||
= GalleryTest =
|
||||
|
||||
== all images shown, one is decribed ==
|
||||
{{{
|
||||
{ { {
|
||||
#!Gallery2
|
||||
* [100_1185.JPG Bremen, SpaceCenter]
|
||||
} } }
|
||||
}}}
|
||||
|
||||
Result: [[BR]]
|
||||
{{{
|
||||
#!Gallery2
|
||||
* [100_1185.JPG Bremen, SpaceCenter]
|
||||
}}}
|
||||
|
||||
== only thumbnails and only_items ==
|
||||
{{{
|
||||
{ { {
|
||||
#!Gallery2 show_text=0,show_tools=0,show_date=0,columns=2,only_items=1
|
||||
* [100_1185.JPG Bremen, SpaceCenter]
|
||||
* [100_1194.JPG Bremen]
|
||||
} } }
|
||||
}}}
|
||||
|
||||
Result: [[BR]]
|
||||
{{{
|
||||
#!Gallery2 show_text=0,show_tools=0,show_date=0,columns=2,only_items=1
|
||||
* [100_1185.JPG Bremen, SpaceCenter]
|
||||
* [100_1194.JPG Bremen]
|
||||
}}}
|
||||
|
||||
== only_items by two columns and text right ==
|
||||
|
||||
{{{
|
||||
{ { {
|
||||
#!Gallery2 mode=2,columns=2,only_items=1
|
||||
* [100_1185.JPG Bremen, SpaceCenter]
|
||||
* [100_1194.JPG Bremen]
|
||||
} } }
|
||||
}}}
|
||||
|
||||
Result: [[BR]]
|
||||
{{{
|
||||
#!Gallery2 mode=2,columns=2,only_items=1
|
||||
* [100_1185.JPG Bremen, SpaceCenter]
|
||||
* [100_1194.JPG Bremen, behind SpaceCenter]
|
||||
}}}
|
||||
|
||||
----
|
||||
|
||||
== only_items by two columns, date supressed ==
|
||||
|
||||
{{{
|
||||
{ { {
|
||||
#!Gallery2 columns=2,only_items=1,show_date=0
|
||||
* [100_1185.JPG Bremen, SpaceCenter]
|
||||
* [100_1194.JPG Bremen, behind SpaceCenter]
|
||||
} } }
|
||||
}}}
|
||||
|
||||
Result: [[BR]]
|
||||
{{{
|
||||
#!Gallery2 columns=2,only_items=1,show_date=0
|
||||
* [100_1185.JPG Bremen, SpaceCenter]
|
||||
* [100_1194.JPG Bremen, behind SpaceCenter]
|
||||
}}}
|
||||
|
||||
|
||||
== filter regex used, mode 2, icons and date supressed, one column and border_thick=5 ==
|
||||
{{{
|
||||
{ { {
|
||||
#!Gallery2 columns=1,filter=100_118[0-5],mode=2,show_date=0,show_tools=0,border_thick=5
|
||||
} } }
|
||||
}}}
|
||||
|
||||
Result: [[BR]]
|
||||
{{{
|
||||
#!Gallery2 columns=1,filter=100_118[0-7],mode=2,show_date=0,show_tools=0,border_thick=5
|
||||
}}}
|
||||
|
||||
== other macro calls ==
|
||||
{{{
|
||||
{ { {
|
||||
#!Gallery2 only_items=1,show_date=0
|
||||
* [100_1189.JPG [[MiniPage(||Bremen||SpaceCenter||\n|| ||SpaceJump||)]]]
|
||||
} } }
|
||||
}}}
|
||||
|
||||
Result: [[BR]]
|
||||
{{{
|
||||
#!Gallery2 only_items=1,show_date=0
|
||||
* [100_1189.JPG [[MiniPage(||Bremen||SpaceCenter||\n|| ||SpaceJump||)]]]
|
||||
}}}
|
||||
|
||||
== renew means always new thumbnails and webnails of selection ==
|
||||
{{{
|
||||
{ { {
|
||||
#!Gallery2 only_items=1,show_date=0,show_tools=0,renew=1
|
||||
* [100_1189.JPG [[MiniPage(||["Bremen"]||SpaceCenter||\n|| ||SpaceJump||)]]]
|
||||
} } }
|
||||
}}}
|
||||
|
||||
Result: [[BR]]
|
||||
{{{
|
||||
#!Gallery2 only_items=1,show_date=0,renew=1
|
||||
* [100_1189.JPG [[MiniPage(||["Bremen"]||SpaceCenter||\n|| ||SpaceJump||)]]]
|
||||
}}}
|
||||
|
||||
== template_itemlist ==
|
||||
{{{
|
||||
{ { {
|
||||
#!Gallery2 template_itemlist=1
|
||||
* [100_1185.JPG Bremen, SpaceCenter]
|
||||
} } }
|
||||
}}}
|
||||
|
||||
Result: [[BR]]
|
||||
{{{
|
||||
#!Gallery2 template_itemlist=1
|
||||
* [100_1185.JPG Bremen, SpaceCenter]
|
||||
}}}
|
||||
|
||||
== help to show Calling Sequence ==
|
||||
{{{
|
||||
{ { {
|
||||
#!Gallery2 help=1
|
||||
} } }
|
||||
}}}
|
||||
|
||||
Result: [[BR]]
|
||||
{{{
|
||||
#!Gallery2 help=1
|
||||
}}}
|
||||
|
||||
|
||||
PROCEDURE:
|
||||
Download some images to a page and start with the examples.
|
||||
Aliasing of the filenames are done by adding an itemlist, see example.
|
||||
|
||||
This routine requires the PIL (Python Imaging Library).
|
||||
And the EXIF routine from http://home.cfl.rr.com/genecash/digital_camera.html
|
||||
|
||||
|
||||
At the moment I have added the EXIF routine to the parsers dir.
|
||||
It's not the best place but during developing it is nice to have it there
|
||||
If you put it to another place you have to change the line
|
||||
from MoinMoin.parser import EXIF too.
|
||||
|
||||
This routine requires the Action macro gallery2Image which is used to rotate or delete a selected image.
|
||||
Only users which have the rights to delete are able to execute this action macro.
|
||||
The icons of these are only shown if you have enough rights.
|
||||
|
||||
The gallery2image macro does not take care on the EXIF header. This is lost by rotating.
|
||||
If a file is deleted by this macro it is moved to a bak file.
|
||||
|
||||
Please remove the Version number from the code!
|
||||
|
||||
RESTRICTIONS:
|
||||
The movie mode is not implemented at the moment. The implementation will be done in the action macro.
|
||||
|
||||
|
||||
If you rotate an image at the moment the exif is destroyed. PIL ignores the exif header.
|
||||
This is not a quite big problem normally files with an EXIF header are right rotated.
|
||||
|
||||
Required Images:
|
||||
I have put them to wiki/modern/img/ dir. The icons were created by me. License: GPL
|
||||
|
||||
attachment:to_bak.png
|
||||
attachment:to_left.png
|
||||
attachment:to_right.png
|
||||
attachment:to_slide.png
|
||||
attachment:to_full.png
|
||||
|
||||
HISTORY:
|
||||
While recognizing how to write MiniPage I got the idea to write a Gallery Parser.
|
||||
We have used in our wikis in the past the Gallery macro of SimonRyan.
|
||||
I have tried to modify it a bit to change it for 1.3 but my python skills weren't enough
|
||||
or it was easier to write it completly new.
|
||||
So this one shows now a way how a Gallery could be used by the parser and an action Macro.
|
||||
Probably it is a good example for others who like to know how to do this
|
||||
|
||||
MODIFICATION HISTORY:
|
||||
Version 1.3.3.-1
|
||||
@copyright: 2005 by Reimar Bauer (R.Bauer@fz-juelich.de)
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
2005-03-26: Version 1.3.3-2 keyword renew added
|
||||
creation of thumbnails and webnails in two calls splitted
|
||||
Version 1.3.3-3 bug fixed if itemlist is given to describe only some of the images
|
||||
but only_items is not set to 1
|
||||
Example code changed
|
||||
2005-03-27: Version 1.3.3-4 Action macro added and the form to call it. User which have rights to delete
|
||||
could use the functions of gallery2Image.
|
||||
2005-08-03: Version 1.3.3-5 theme path for icons corrected and a platform independent path joining
|
||||
os.unlink removed as suggested by CraigJohnson
|
||||
sort_by_name is default if not only_items is 1
|
||||
optional sort_by_date could be used
|
||||
keyword template_itemlist added
|
||||
keyword help added
|
||||
extra frame by mode=2 removed
|
||||
2005-08-06: Version 1.3.5-6 slideshow mode added
|
||||
keyword image_for_webnail added
|
||||
2005-08-13: Version 1.3.5-7 syntax changed from GET to POST
|
||||
forms instead of links
|
||||
filenames from images submitted to gallery2image too
|
||||
new keyword sort_by_alias
|
||||
internal code clean up
|
||||
this version needs: gallery2image-1.3.5-5.py
|
||||
2005-08-14: Version 1.3.5-8 (TW) cleanup
|
||||
2005-08-14: Version 1.3.5-9 html code for tables changed
|
||||
because of the ugly extra space of form elements
|
||||
</div> tag removed so now we use the page style
|
||||
slide show action goes to right webnail now
|
||||
this version needs: gallery2image-1.3.5-5.py
|
||||
2005-08-17: Version 1.3.5-10 html code separated in functions
|
||||
structure of code changed, now you see the thumbnails after creation
|
||||
bug removed if quote is given but file does not exist
|
||||
2005-09-02: Version 1.3.5-11 keyword album, album_name and front_image added
|
||||
image urls changed to complete server url
|
||||
|
||||
|
||||
"""
|
||||
Dependencies = []
|
||||
from MoinMoin.action import AttachFile
|
||||
from MoinMoin import wikiutil, config
|
||||
from MoinMoin.Page import Page
|
||||
|
||||
import os,string,re,Image,StringIO
|
||||
|
||||
#from MoinMoin.parser import EXIF
|
||||
import EXIF
|
||||
|
||||
from MoinMoin.parser import wiki
|
||||
|
||||
def show_tools_restricted(pagename,this_target,thumbnail_width,full,alias,target,exif_date,request):
|
||||
if request.user.may.delete(pagename):
|
||||
return tools_restricted_html(pagename,this_target,thumbnail_width,full,alias,target,exif_date,request)
|
||||
else:
|
||||
return ''
|
||||
|
||||
def tools_restricted_html(pagename,this_target,thumbnail_width,full,alias,target,exif_date,request):
|
||||
text='''
|
||||
<form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
|
||||
<td>
|
||||
<input type="hidden" name="action" value="gallery2image">
|
||||
<input type="hidden" name="do" value="RL">
|
||||
<input type="hidden" name="target" value="%(this_target)s">
|
||||
<input type="image" value="submit" src="%(server)s/wiki/modern/img/to_left.png" title="rotate to left">
|
||||
</td>
|
||||
</form>
|
||||
<form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
|
||||
<td>
|
||||
<input type="hidden" name="action" value="gallery2image">
|
||||
<input type="hidden" name="do" value="RR">
|
||||
<input type="hidden" name="target" value="%(this_target)s">
|
||||
<input type="image" value="submit" src="%(server)s/wiki/modern/img/to_right.png" title="rotate to right" >
|
||||
</td>
|
||||
</form>
|
||||
<form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
|
||||
<td>
|
||||
<input type="hidden" name="action" value="gallery2image">
|
||||
<input type="hidden" name="do" value="RM">
|
||||
<input type="hidden" name="target" value="%(this_target)s">
|
||||
<input type="image" value="submit" src="%(server)s/wiki/modern/img/to_bak.png" title="move to bak" >
|
||||
</td>
|
||||
</form>''' % {
|
||||
"server" : 'https://'+request.server_name,
|
||||
'baseurl': request.getScriptname(),
|
||||
"pagename":pagename,
|
||||
"this_target":this_target}
|
||||
return text
|
||||
|
||||
def tools_html(pagename,this_image,thumbnail_width,full,alias,target,exif_date,request):
|
||||
text='''
|
||||
<TABLE align="center" width="%(thumbnail_width)s">
|
||||
<TR>
|
||||
<form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
|
||||
<td>
|
||||
<input type="hidden" name="action" value="AttachFile">
|
||||
<input type="hidden" name="do" value="get">
|
||||
<input type="hidden" name="target" value="%(this_target)s">
|
||||
<input type="image" value="submit" src="%(server)s/wiki/modern/img/to_full.png" title="load image">
|
||||
</td>
|
||||
</form>
|
||||
<form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
|
||||
<td>
|
||||
<input type="hidden" name="action" value="gallery2image">
|
||||
<input type="hidden" name="do" value="VS">
|
||||
<input type="hidden" name="full" value="%(full)s">
|
||||
<input type="hidden" name="alias" value="%(alias)s">
|
||||
<input type="hidden" name="target" value="%(target)s">
|
||||
<input type="hidden" name="exif_date" value="%(exif_date)s">
|
||||
<input type="image" value="submit" src="%(server)s/wiki/modern/img/to_slide.png" title="slide_show" >
|
||||
</td>
|
||||
</form>
|
||||
%(show_tools_restricted)s
|
||||
</TR>
|
||||
</TABLE>''' % {
|
||||
"server" : 'https://'+request.server_name,
|
||||
'baseurl': request.getScriptname(),
|
||||
"pagename":pagename,
|
||||
"thumbnail_width":thumbnail_width,
|
||||
"full":full,
|
||||
"alias":alias,
|
||||
"exif_date":exif_date,
|
||||
"target":target,
|
||||
"this_target":this_image,
|
||||
"show_tools_restricted":show_tools_restricted(pagename,this_image,thumbnail_width,full,alias,target,exif_date,request)
|
||||
}
|
||||
|
||||
return text
|
||||
|
||||
def show_alias_mode2(show_alias,thumbnail_width,this_alias,text_width):
|
||||
if show_alias == '1':
|
||||
return '''
|
||||
<td valign="top" width="%(text_width)s">
|
||||
%(this_alias)s
|
||||
</td>''' % {
|
||||
"this_alias":this_alias,
|
||||
"text_width":text_width}
|
||||
else:
|
||||
return ''
|
||||
|
||||
def show_date_mode2(show_date,this_exif_date):
|
||||
if show_date == '1':
|
||||
return '''
|
||||
<td>
|
||||
<p>%(this_exif_date)s</p>
|
||||
</td>''' % {
|
||||
"this_exif_date":this_exif_date }
|
||||
else:
|
||||
return '';
|
||||
|
||||
def show_tools_mode2(show_tools,pagename,this_target,thumbnail_width,full,alias,target,exif_date,request):
|
||||
if show_tools == '1' :
|
||||
return "<td align=""center""> %s </td>" % tools_html(pagename,this_target,thumbnail_width,full,alias,target,exif_date,request)
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
|
||||
def mode2_html(pagename,border_thick,width,thumbnail_width,text_width,full,this_image,alias,this_alias,exif_date,this_exif_date,target,this_target,submit,show_tools,show_date,show_alias,request):
|
||||
text='''
|
||||
<tr valign="center">
|
||||
<form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
|
||||
<td align="center" valign="center" width="%(thumbnail_width)s">
|
||||
<input type="hidden" name="action" value="gallery2image">
|
||||
<input type="hidden" name="do" value="VS">
|
||||
<input type="hidden" name="full" value="%(full)s">
|
||||
<input type="hidden" name="alias" value="%(alias)s">
|
||||
<input type="hidden" name="exif_date" value="%(exif_date)s">
|
||||
<input type="hidden" name="target" value="%(target)s">
|
||||
<input type="image" value="submit" src="%(server)s%(submit)s">
|
||||
</td>
|
||||
</form>
|
||||
%(alias_html)s
|
||||
</tr>
|
||||
<tr>%(tools_html)s%(date_html)s</tr>'''% {
|
||||
"server" : 'https://'+request.server_name,
|
||||
"baseurl": request.getScriptname(),
|
||||
"pagename":pagename,
|
||||
"thumbnail_width":thumbnail_width,
|
||||
"full":full,
|
||||
"alias":alias,
|
||||
"exif_date":exif_date,
|
||||
"target":target,
|
||||
"submit":submit,
|
||||
"tools_html":show_tools_mode2(show_tools,pagename,this_image,thumbnail_width,full,alias,target,exif_date,request),
|
||||
"date_html": show_date_mode2(show_date,this_exif_date),
|
||||
"alias_html": show_alias_mode2(show_alias,thumbnail_width,this_alias,text_width)
|
||||
}
|
||||
|
||||
return text
|
||||
|
||||
def show_tools_mode1(show_tools,pagename,this_image,thumbnail_width,full,alias,target,exif_date,request):
|
||||
if show_tools == '1' :
|
||||
text="<tr><td align=""center"">%s </td></tr>" % tools_html(pagename,this_image,thumbnail_width,full,alias,target,exif_date,request)
|
||||
else:
|
||||
text=''
|
||||
return text
|
||||
|
||||
def show_date_mode1(show_date,this_exif_date):
|
||||
if show_date == '1':
|
||||
return '''
|
||||
<TR>
|
||||
<td>%(this_exif_date)s</td>
|
||||
</TR>''' % {
|
||||
"this_exif_date":this_exif_date}
|
||||
else:
|
||||
return ''
|
||||
|
||||
def show_alias_mode1(show_alias,thumbnail_width,this_alias,text_width):
|
||||
if show_alias == '1':
|
||||
return '''
|
||||
<TR>
|
||||
<td align="left" width="%(thumbnail_width)s"> %(this_alias)s</td>
|
||||
</TR>''' % {
|
||||
"thumbnail_width": thumbnail_width,
|
||||
"this_alias":this_alias}
|
||||
else:
|
||||
return ''
|
||||
|
||||
def mode1_html(pagename,border_thick,width,thumbnail_width,text_width,full,this_image,alias,this_alias,exif_date,this_exif_date,target,this_target,submit,
|
||||
show_tools,show_date,show_alias,request):
|
||||
text='''
|
||||
<table width="%(thumbnail_width)s" align="center" valign="center">
|
||||
<TR align="center" valign="center">
|
||||
<form action="%(baseurl)s/%(pagename)s" method="POST" enctype="multipart/form-data">
|
||||
<td align="center" valign="middle" width="%(thumbnail_width)s">
|
||||
<input type="hidden" name="action" value="gallery2image">
|
||||
<input type="hidden" name="do" value="VS">
|
||||
<input type="hidden" name="full" value="%(full)s">
|
||||
<input type="hidden" name="alias" value="%(alias)s">
|
||||
<input type="hidden" name="exif_date" value="%(exif_date)s">
|
||||
<input type="hidden" name="target" value="%(target)s">
|
||||
<input type="image" value="submit" src="%(server)s%(submit)s" >
|
||||
</td>
|
||||
</form>
|
||||
</TR>
|
||||
%(alias_html)s
|
||||
%(date_html)s
|
||||
%(tools_html)s
|
||||
</table>'''% {
|
||||
"server" : 'https://'+request.server_name,
|
||||
"baseurl": request.getScriptname() ,
|
||||
"pagename":pagename,
|
||||
"full":full,
|
||||
"alias":alias,
|
||||
"exif_date":exif_date,
|
||||
"target":target,
|
||||
"submit":submit,
|
||||
"thumbnail_width":thumbnail_width,
|
||||
"tools_html": show_tools_mode1(show_tools,pagename,this_image,thumbnail_width,full,alias,target,exif_date,request),
|
||||
"date_html":show_date_mode1(show_date,this_exif_date),
|
||||
"alias_html": show_alias_mode1(show_alias,thumbnail_width,this_alias,text_width)
|
||||
}
|
||||
|
||||
return text
|
||||
|
||||
def get_files(kw,path,files,quotes,request):
|
||||
web=[]
|
||||
full=[]
|
||||
thumb=[]
|
||||
exif_date=[]
|
||||
img_type=[]
|
||||
description=[]
|
||||
|
||||
|
||||
ddict={}
|
||||
n=len(quotes['image'])
|
||||
if n > 0 :
|
||||
i = 0
|
||||
for txt in quotes['image']:
|
||||
ddict[txt]=quotes['alias'][i]
|
||||
i += 1
|
||||
|
||||
for attfile in files:
|
||||
# only files not thumb or webnails
|
||||
if attfile.find('thumbnail_') == -1 and attfile.find('webnail_') == -1:
|
||||
# only images
|
||||
if wikiutil.isPicture(attfile):
|
||||
description.append(ddict.get(attfile, attfile))
|
||||
full.append(attfile)
|
||||
|
||||
if kw['image_for_webnail'] == '1':
|
||||
webnail = attfile
|
||||
else:
|
||||
fname, ext = os.path.splitext(attfile)
|
||||
if ext in ('.gif', '.png'):
|
||||
img_type.append('PNG')
|
||||
webnail = 'webnail_%s.png' % fname
|
||||
thumbfile = 'thumbnail_%s.png' % fname
|
||||
else:
|
||||
img_type.append("JPEG")
|
||||
webnail = 'webnail_%s.jpg' % fname
|
||||
thumbfile = 'thumbnail_%s.jpg' % fname
|
||||
|
||||
infile = os.path.join(path, attfile)
|
||||
if os.path.exists(infile):
|
||||
web.append(webnail)
|
||||
thumb.append(thumbfile)
|
||||
|
||||
f = open(infile, 'rb')
|
||||
tags = EXIF.process_file(f)
|
||||
if tags.has_key('EXIF DateTimeOriginal'):
|
||||
date = str(tags['EXIF DateTimeOriginal'])
|
||||
date = date.replace(':', '-', 2)
|
||||
else:
|
||||
date = '--'
|
||||
exif_date.append(date)
|
||||
f.close()
|
||||
|
||||
return thumb,web,full,exif_date,img_type,description
|
||||
|
||||
def to_htmltext(text):
|
||||
text = text.split(' ')
|
||||
text = ' '.join(text)
|
||||
return text
|
||||
|
||||
def to_wikiname(request,formatter,text):
|
||||
##taken from MiniPage
|
||||
out=StringIO.StringIO()
|
||||
request.redirect(out)
|
||||
wikiizer = wiki.Parser(text.strip(),request)
|
||||
wikiizer.format(formatter)
|
||||
result=out.getvalue()
|
||||
request.redirect()
|
||||
del out
|
||||
|
||||
return result.strip()
|
||||
|
||||
|
||||
def get_quotes(self,formatter):
|
||||
quotes = self.raw.split('\n')
|
||||
quotes = [quote.strip() for quote in quotes]
|
||||
quotes = [quote[2:] for quote in quotes if quote.startswith('* ')]
|
||||
|
||||
|
||||
image=[]
|
||||
text=[]
|
||||
|
||||
for line in quotes:
|
||||
im, na=line[1:-1].split(' ',1)
|
||||
text.append(na.strip())
|
||||
image.append(im.strip())
|
||||
|
||||
return {
|
||||
'alias': text,
|
||||
'image': image,
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Parser:
|
||||
|
||||
def __init__(self, raw, request, **kw):
|
||||
self.raw = raw
|
||||
self.request = request
|
||||
self.form = request.form
|
||||
self._ = request.getText
|
||||
self.kw = {
|
||||
'sort_by_date': '0',
|
||||
'sort_by_name': '1',
|
||||
'sort_by_alias': '0',
|
||||
'album': '0',
|
||||
'album_name': 'album',
|
||||
'front_image':'',
|
||||
'template_itemlist': '0',
|
||||
'reverse_sort': '0',
|
||||
'border_thick': '1',
|
||||
'columns': '4',
|
||||
'filter': '.',
|
||||
'mode': '1',
|
||||
'help': '0',
|
||||
'show_text': '1',
|
||||
'show_date': '1',
|
||||
'show_tools': '1',
|
||||
'only_items': '0',
|
||||
'image_for_webnail': '0',
|
||||
'renew': '0',
|
||||
'thumbnail_width': '128',
|
||||
'webnail_width': '640',
|
||||
'text_width': '140',
|
||||
}
|
||||
|
||||
|
||||
for arg in kw.get('format_args','').split(','):
|
||||
|
||||
if arg.find('=') > -1:
|
||||
key, value=arg.split('=')
|
||||
self.kw[key]=wikiutil.escape(value, quote=1)
|
||||
|
||||
|
||||
self.kw['width']=str((int(self.kw['thumbnail_width'])+int(self.kw['text_width'])))
|
||||
|
||||
|
||||
def format(self, formatter):
|
||||
kw=self.kw
|
||||
Dict = {}
|
||||
quotes=get_quotes(self,formatter)
|
||||
current_pagename=formatter.page.page_name
|
||||
attachment_path = AttachFile.getAttachDir(self.request, current_pagename, create=1)
|
||||
|
||||
if kw['help'] == '1':
|
||||
self.request.write('''
|
||||
<br>
|
||||
{{{<br>
|
||||
#!Gallery2 [columns=columns],[filter=filter],[mode=mode],<br>
|
||||
[show_text=show_text],[show_date=show_date], [show_tools=show_tools],<br>
|
||||
[sort_by_name=sort_by_name],[sort_by_date=sort_by_date],[sort_by_alias=sort_by_alias]<br>
|
||||
[reverse_sort=reverse_sort],<br>
|
||||
[only_items=only_items],[template_itemlist=template_itemlist],<br>
|
||||
[album=album],[album_name=album_name],[front_image=front_image],<br>
|
||||
[thumbnail_width=thumbnail_width],[webnail_width=webnail_width],[text_width=text_width],<br>
|
||||
[image_for_webnail=image_for_webnail],<br>
|
||||
[border_thick=border_thick],[renew=renew],[help=help]<br>
|
||||
* [image1.jpg alias]<br>
|
||||
* [image2.jpg alias]<br>
|
||||
}}}<br>''')
|
||||
return
|
||||
|
||||
|
||||
if kw['only_items'] == '1':
|
||||
all_files=quotes['image']
|
||||
result=[]
|
||||
for attfile in all_files:
|
||||
infile=os.path.join(attachment_path,attfile)
|
||||
if os.path.exists(infile):
|
||||
result.append(attfile)
|
||||
all_files = result
|
||||
|
||||
if kw['sort_by_alias'] == '1':
|
||||
new_ordered_files=[]
|
||||
alias_text=quotes['alias']
|
||||
|
||||
i=0
|
||||
for attfile in all_files:
|
||||
infile=os.path.join(attachment_path,attfile)
|
||||
ft_file=str(os.path.getmtime(infile))+os.tmpnam()
|
||||
Dict[alias_text[i]]=attfile
|
||||
i += 1
|
||||
|
||||
keys = Dict.keys()
|
||||
keys.sort()
|
||||
for txt in keys:
|
||||
new_ordered_files.append(Dict[txt])
|
||||
|
||||
|
||||
all_files=new_ordered_files
|
||||
Dict.clear()
|
||||
|
||||
else:
|
||||
all_files=os.listdir(attachment_path)
|
||||
|
||||
result = []
|
||||
|
||||
for test in all_files:
|
||||
if re.match(kw['filter'], test):
|
||||
result.append(test)
|
||||
all_files=result
|
||||
|
||||
if not all_files:
|
||||
self.request.write("<br><br><h1>No matching image file found!</h1>")
|
||||
return
|
||||
|
||||
|
||||
|
||||
if kw['sort_by_name'] == '1' and kw['only_items'] == '0':
|
||||
all_files.sort()
|
||||
|
||||
if kw['sort_by_date']=='1':
|
||||
for attfile in all_files:
|
||||
infile=os.path.join(attachment_path,attfile)
|
||||
ft_file=str(os.path.getmtime(infile))+os.tmpnam()
|
||||
Dict[ft_file]=attfile
|
||||
|
||||
keys = Dict.keys()
|
||||
keys.sort()
|
||||
file_mdate=[]
|
||||
for txt in keys:
|
||||
file_mdate.append(Dict[txt])
|
||||
all_files=file_mdate
|
||||
Dict.clear()
|
||||
|
||||
if kw['reverse_sort']=='1':
|
||||
all_files.reverse()
|
||||
|
||||
|
||||
cells=[]
|
||||
cell_name=[]
|
||||
img=[]
|
||||
|
||||
thumb, web, full, exif_date, imgtype, description = get_files(kw, attachment_path, all_files, quotes, self.request)
|
||||
|
||||
if kw['template_itemlist'] == '1':
|
||||
self.request.write('Copy the following listitems into the script. Replace alias with the label you want. Afterwards disable template_itemlist by setting it to 0:<BR>')
|
||||
for attfile in full :
|
||||
self.request.write(' * [%(attfile)s %(date)s]<br>' % {
|
||||
'attfile' : attfile,
|
||||
'date' : 'alias'
|
||||
})
|
||||
|
||||
|
||||
i = 0
|
||||
z = 1
|
||||
cols = int(kw['columns'])
|
||||
|
||||
|
||||
n = len(full)
|
||||
if kw['album'] == '0' :
|
||||
self.request.write("<table align='center' border='%s' >" % self.kw['border_thick'])
|
||||
if kw['mode'] == '1' or cols > 1 :
|
||||
self.request.write('<TR valign="bottom">')
|
||||
self.request.write('<TD>')
|
||||
|
||||
|
||||
if kw['album'] == '1' :
|
||||
if kw['front_image'] == '' :
|
||||
front_image = full[0]
|
||||
else:
|
||||
front_image = kw['front_image']
|
||||
ii = 0
|
||||
for tst in full :
|
||||
if tst == front_image :
|
||||
break
|
||||
ii += 1
|
||||
|
||||
|
||||
for attfile in full :
|
||||
if kw['album'] == '1' :
|
||||
if tst == front_image :
|
||||
i = ii
|
||||
|
||||
|
||||
this_description=description[i]
|
||||
this_exif_date=exif_date[i]
|
||||
this_webnail=web[i]
|
||||
this_imgtype=imgtype[i]
|
||||
this_thumbfile=thumb[i]
|
||||
|
||||
|
||||
thumbf=os.path.join(attachment_path,this_thumbfile)
|
||||
webf=os.path.join(attachment_path,this_webnail)
|
||||
|
||||
|
||||
if kw['renew'] == '1':
|
||||
if os.path.exists(thumbf):
|
||||
os.unlink(thumbf)
|
||||
if os.path.exists(webf):
|
||||
os.unlink(webf)
|
||||
|
||||
if not os.path.exists(webf) or not os.path.exists(thumbf):
|
||||
infile=os.path.join(attachment_path,attfile)
|
||||
im = Image.open(infile)
|
||||
if not os.path.exists(webf):
|
||||
im.thumbnail(((int(kw['webnail_width'])),((int(kw['webnail_width'])))), Image.ANTIALIAS)
|
||||
im.save(webf, this_imgtype)
|
||||
if not os.path.exists(thumbf):
|
||||
im.thumbnail(((int(kw['thumbnail_width'])),((int(kw['thumbnail_width'])))),
|
||||
Image.ANTIALIAS)
|
||||
im.save(thumbf, this_imgtype)
|
||||
|
||||
|
||||
if kw['mode'] == '1':
|
||||
text=mode1_html(current_pagename,
|
||||
kw['border_thick'],
|
||||
kw['width'],
|
||||
kw['thumbnail_width'],
|
||||
kw['text_width'],
|
||||
attfile + "," + ','.join(full),
|
||||
attfile,
|
||||
to_htmltext(this_description + "!,!" + '!,!'.join(description)),
|
||||
to_wikiname(self.request,formatter,this_description),
|
||||
to_htmltext(this_exif_date + "," + ','.join(exif_date)),
|
||||
this_exif_date,
|
||||
this_webnail + "," + ','.join(web),
|
||||
this_webnail,
|
||||
AttachFile.getAttachUrl(current_pagename, this_thumbfile, self.request),
|
||||
kw['show_tools'],
|
||||
kw['show_date'],
|
||||
kw['show_text'],
|
||||
self.request
|
||||
)
|
||||
self.request.write(''.join(text))
|
||||
|
||||
if kw['mode'] == '2':
|
||||
text=mode2_html(current_pagename,
|
||||
kw['border_thick'],
|
||||
kw['width'],
|
||||
kw['thumbnail_width'],
|
||||
kw['text_width'],
|
||||
attfile + "," + ','.join(full),
|
||||
attfile,
|
||||
to_htmltext(this_description + "!,!" + '!,!'.join(description)),
|
||||
to_wikiname(self.request,formatter,this_description),
|
||||
to_htmltext(this_exif_date + "," + ','.join(exif_date)),
|
||||
this_exif_date,
|
||||
this_webnail + "," + ','.join(web),
|
||||
this_webnail,
|
||||
AttachFile.getAttachUrl(current_pagename, this_thumbfile, self.request),
|
||||
kw['show_tools'],
|
||||
kw['show_date'],
|
||||
kw['show_text'],
|
||||
self.request
|
||||
)
|
||||
|
||||
if cols > 1 : self.request.write('<table valign="bottom">')
|
||||
self.request.write(''.join(text))
|
||||
if cols > 1 : self.request.write('</table>')
|
||||
|
||||
if kw['mode'] == '1' or cols > 1:
|
||||
if kw['album'] == '0' :
|
||||
if z < cols:
|
||||
self.request.write('</TD>')
|
||||
if z < n :
|
||||
self.request.write('<TD>')
|
||||
else:
|
||||
self.request.write('</TD>')
|
||||
self.request.write('</TR>')
|
||||
if i < n-1 :
|
||||
self.request.write('<TR valign="bottom">')
|
||||
self.request.write('<TD>')
|
||||
|
||||
i += 1
|
||||
z += 1
|
||||
if z > cols :
|
||||
z = 1
|
||||
|
||||
if kw['album'] == '1' :
|
||||
self.request.write("%(n)s images (%(album_name)s)" % {"n": str(n), "album_name":kw['album_name']})
|
||||
break
|
||||
if kw['album'] == '0' :
|
||||
if i < n :
|
||||
self.request.write('</TD>')
|
||||
self.request.write('</TR>')
|
||||
|
||||
|
||||
self.request.write('</table>')
|
||||
|
||||
############################################
|
||||
##TODO: syntax change to formatter - later #
|
||||
############################################
|
||||
|
||||
|
||||
|
||||
|
||||
|
117
wiki/parser/Portail.py
Normal file
117
wiki/parser/Portail.py
Normal file
|
@ -0,0 +1,117 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin - Portail parser
|
||||
|
||||
PURPOSE:
|
||||
Pour afficher un portail a la wikipedia.
|
||||
|
||||
CALLING SEQUENCE:
|
||||
{{{
|
||||
#!Portail
|
||||
image1.png | title1 | description 1
|
||||
image2.png | title2 | description 2
|
||||
image3.png | title3 | description 3
|
||||
}}}
|
||||
|
||||
CREDIT
|
||||
Le code est derive de celui de Gallery2.
|
||||
|
||||
"""
|
||||
from MoinMoin.parser import wiki
|
||||
import os,string,re,StringIO
|
||||
from MoinMoin.action import AttachFile
|
||||
|
||||
#####################################################################
|
||||
# Fonctions #
|
||||
#####################################################################
|
||||
# to_wikiname : transfome la chaine text avec le parser wiki
|
||||
# classique et le formateur formatter
|
||||
# (je sais pas a quoi sert request, mais faut pas
|
||||
# l'enlever !)
|
||||
#######
|
||||
|
||||
def to_wikiname(request,formatter,text):
|
||||
##taken from MiniPage
|
||||
out=StringIO.StringIO()
|
||||
request.redirect(out)
|
||||
wikiizer = wiki.Parser(text.strip(),request)
|
||||
wikiizer.format(formatter)
|
||||
result=out.getvalue()
|
||||
request.redirect()
|
||||
del out
|
||||
|
||||
return result.strip()
|
||||
|
||||
#####################################################################
|
||||
# PortailFormatter : creer le code html du portail a l'aide de
|
||||
# de formatter et l'envoie a request
|
||||
#######
|
||||
class PortailFormatter:
|
||||
|
||||
def __init__(self, request, formatter):
|
||||
self.formatter = formatter
|
||||
self.request = request
|
||||
self.counter = 0
|
||||
|
||||
def open(self):
|
||||
self.request.write(self.formatter.table(1,{'style':'width:100%;padding:10px;'}))
|
||||
|
||||
def cell(self, title, description, image):
|
||||
if self.counter==0:
|
||||
self.request.write(self.formatter.table_row(1))
|
||||
self.request.write(self.formatter.table_cell(1,{'style':'width:50%;border:none;padding:20px 20px 20px 50px;background:transparent url(\'' + image.replace("\'","\\\'") + '\') center left no-repeat; vertical-align:center;'}))
|
||||
self.request.write(title)
|
||||
self.request.write(description)
|
||||
self.request.write(self.formatter.table_cell(0))
|
||||
if self.counter==1:
|
||||
self.request.write(self.formatter.table_row(0))
|
||||
self.counter = (self.counter + 1)%2
|
||||
|
||||
def close(self):
|
||||
if self.counter==1:
|
||||
self.request.write(self.formatter.table_cell(1,{'style':'width:50%;border:none;padding:20px 20px 20px 50px;'}))
|
||||
self.request.write(self.formatter.table_cell(0))
|
||||
self.request.write(self.formatter.table_row(0))
|
||||
self.request.write(self.formatter.table(0))
|
||||
|
||||
#####################################################################
|
||||
# Parser : classe principale, c'est elle qui parse
|
||||
#######
|
||||
class Parser:
|
||||
|
||||
def __init__(self, raw, request, **kw):
|
||||
self.request = request
|
||||
self.raw = raw
|
||||
return
|
||||
|
||||
|
||||
def format(self, formatter):
|
||||
|
||||
# on divise le textes en lignes (1 ligne = une entree dans le portail)
|
||||
quotes = self.raw.split('\n')
|
||||
|
||||
# on récupere le chemin des fichiers attaches pour les images
|
||||
current_pagename=formatter.page.page_name
|
||||
attachment_path = AttachFile.getAttachDir(self.request, current_pagename, create=1)
|
||||
|
||||
# on initialise la classe qui va fabriquer le code html
|
||||
portail = PortailFormatter(self.request, formatter)
|
||||
portail.open()
|
||||
|
||||
# on traite les ligne une à une
|
||||
for line in quotes:
|
||||
line=line.strip()
|
||||
items=line.split('|',2)
|
||||
if items.__len__()<3:
|
||||
self.request.write('<!-- error, wrong number of parameters -->')
|
||||
else:
|
||||
description=items.pop().strip()
|
||||
link=items.pop().strip()
|
||||
image = AttachFile.getAttachUrl(current_pagename, items.pop().strip(), self.request)
|
||||
|
||||
link = to_wikiname(self.request, formatter, link)
|
||||
description = to_wikiname(self.request, formatter, description)
|
||||
portail.cell(link, description, image)
|
||||
portail.close()
|
||||
|
||||
return
|
5
wiki/parser/__init__.py
Normal file
5
wiki/parser/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
|
||||
from MoinMoin.util import pysupport
|
||||
|
||||
modules = pysupport.getPackageModules(__file__)
|
214
wiki/parser/latex.py
Normal file
214
wiki/parser/latex.py
Normal file
|
@ -0,0 +1,214 @@
|
|||
#FORMAT python
|
||||
#!/usr/bin/python
|
||||
# -*- coding: iso-8859-15 -*-
|
||||
|
||||
"""
|
||||
New latex formatter using dvipng and tempfile
|
||||
|
||||
Author: JohannesBerg <johannes@sipsolutions.net>
|
||||
|
||||
This parser (and the corresponding macro) was tested with Python 2.3.4 and
|
||||
* Debian Linux with out-of-the-box tetex-bin and dvipng packages installed
|
||||
* Windows XP (not by me)
|
||||
|
||||
In the parser, you can add stuff to the prologue by writing
|
||||
%%end-prologue%%
|
||||
somewhere in the document, before that write stuff like \\usepackage and after it put
|
||||
the actual latex display code.
|
||||
"""
|
||||
|
||||
Dependencies = []
|
||||
|
||||
import sha, os, tempfile, shutil, re
|
||||
from MoinMoin.action import AttachFile
|
||||
from MoinMoin.Page import Page
|
||||
|
||||
latex_template = r'''
|
||||
\documentclass[12pt]{article}
|
||||
\pagestyle{empty}
|
||||
%(prologue)s
|
||||
\begin{document}
|
||||
%(raw)s
|
||||
\end{document}
|
||||
'''
|
||||
|
||||
max_pages = 10
|
||||
MAX_RUN_TIME = 5 # seconds
|
||||
|
||||
latex = "latex" # edit full path here, e.g. reslimit = "C:\\path\\to\\latex.exe"
|
||||
dvipng = "dvipng" # edit full path here (or reslimit = r'C:\path\to\latex.exe')
|
||||
|
||||
# last arg must have %s in it!
|
||||
latex_args = ("--interaction=nonstopmode", "%s.tex")
|
||||
|
||||
# last arg must have %s in it!
|
||||
dvipng_args = ("-bgTransparent", "-Ttight", "--noghostscript", "-l%s" % max_pages, "%s.dvi")
|
||||
|
||||
# this is formatted with hexdigest(texcode),
|
||||
# page number and extension are appended by
|
||||
# the tools
|
||||
latex_name_template = "latex_%s_p"
|
||||
|
||||
# keep this up-to-date, also with max_pages!!
|
||||
latex_attachment = re.compile((latex_name_template+'%s%s') % (r'[0-9a-fA-F]{40}', r'[0-9]{1,2}', r'\.png'))
|
||||
|
||||
anchor = re.compile(r'^%%anchor:[ ]*([a-zA-Z0-9_-]+)$', re.MULTILINE | re.IGNORECASE)
|
||||
# the anchor re must start with a % sign to be ignored by latex as a comment!
|
||||
end_prologue = '%%end-prologue%%'
|
||||
|
||||
def call_command_in_dir_NT(app, args, targetdir):
|
||||
reslimit = "runlimit.exe" # edit full path here
|
||||
os.environ['openin_any'] = 'p'
|
||||
os.environ['openout_any'] = 'p'
|
||||
os.environ['shell_escape'] = 'f'
|
||||
stdouterr = os.popen('%s %d "%s" %s %s < NUL' % (reslimit, MAX_RUN_TIME, targetdir, app, ' '.join(args)), 'r')
|
||||
output = ''.join(stdouterr.readlines())
|
||||
err = stdouterr.close()
|
||||
if not err is None:
|
||||
return ' error! exitcode was %d, transscript follows:\n\n%s' % (err,output)
|
||||
return None
|
||||
|
||||
def call_command_in_dir_unix(app, args, targetdir):
|
||||
# this is the unix implementation
|
||||
(r,w) = os.pipe()
|
||||
pid = os.fork()
|
||||
if pid == -1:
|
||||
return 'could not fork'
|
||||
if pid == 0:
|
||||
# child
|
||||
os.close(r)
|
||||
os.dup2(os.open("/dev/null", os.O_WRONLY), 0)
|
||||
os.dup2(w, 1)
|
||||
os.dup2(w, 2)
|
||||
os.chdir(targetdir)
|
||||
os.environ['openin_any'] = 'p'
|
||||
os.environ['openout_any'] = 'p'
|
||||
os.environ['shell_escape'] = 'f'
|
||||
import resource
|
||||
resource.setrlimit(resource.RLIMIT_CPU,
|
||||
(MAX_RUN_TIME * 1000, MAX_RUN_TIME * 1000)) # docs say this is seconds, but it is msecs on my system.
|
||||
os.execvp(app, [app] + list(args))
|
||||
print "failed to exec()",app
|
||||
os._exit(2)
|
||||
else:
|
||||
# parent
|
||||
os.close(w)
|
||||
r = os.fdopen(r,"r")
|
||||
output = ''.join(r.readlines())
|
||||
(npid, exi) = os.waitpid(pid, 0)
|
||||
r.close()
|
||||
sig = exi & 0xFF
|
||||
stat = exi >> 8
|
||||
if stat != 0 or sig != 0:
|
||||
return ' error! exitcode was %d (signal %d), transscript follows:\n\n%s' % (stat,sig,output)
|
||||
return None
|
||||
# notreached
|
||||
|
||||
if os.name == 'nt':
|
||||
call_command_in_dir = call_command_in_dir_NT
|
||||
else:
|
||||
call_command_in_dir = call_command_in_dir_unix
|
||||
|
||||
|
||||
class Parser:
|
||||
extensions = ['.tex']
|
||||
def __init__ (self, raw, request, **kw):
|
||||
self.raw = raw
|
||||
if len(self.raw)>0 and self.raw[0] == '#':
|
||||
self.raw[0] = '%'
|
||||
self.request = request
|
||||
self.exclude = []
|
||||
if not hasattr(request, "latex_cleanup_done"):
|
||||
request.latex_cleanup_done = {}
|
||||
|
||||
def cleanup(self, pagename):
|
||||
attachdir = AttachFile.getAttachDir(self.request, pagename, create=1)
|
||||
for f in os.listdir(attachdir):
|
||||
if not latex_attachment.match(f) is None:
|
||||
os.remove("%s/%s" % (attachdir, f))
|
||||
|
||||
def _internal_format(self, formatter, text):
|
||||
tmp = text.split(end_prologue, 1)
|
||||
if len(tmp) == 2:
|
||||
prologue,tex=tmp
|
||||
else:
|
||||
prologue = ''
|
||||
tex = tmp[0]
|
||||
if callable(getattr(formatter, 'johill_sidecall_emit_latex', None)):
|
||||
return formatter.johill_sidecall_emit_latex(tex)
|
||||
return self.get(formatter, tex, prologue, True)
|
||||
|
||||
def format(self, formatter):
|
||||
self.request.write(self._internal_format(formatter, self.raw))
|
||||
|
||||
def get(self, formatter, inputtex, prologue, para=False):
|
||||
if not self.request.latex_cleanup_done.has_key(formatter.page.page_name):
|
||||
self.request.latex_cleanup_done[formatter.page.page_name] = True
|
||||
self.cleanup(formatter.page.page_name)
|
||||
|
||||
if len(inputtex) == 0: return ''
|
||||
|
||||
if callable(getattr(formatter, 'johill_sidecall_emit_latex', None)):
|
||||
return formatter.johill_sidecall_emit_latex(inputtex)
|
||||
|
||||
extra_preamble = ''
|
||||
preamble_page = self.request.pragma.get('latex_preamble', None)
|
||||
if preamble_page is not None:
|
||||
extra_preamble = Page(self.request, preamble_page).get_raw_body()
|
||||
extra_preamble = re.sub(re.compile('^#'), '%', extra_preamble)
|
||||
|
||||
tex = latex_template % { 'raw': inputtex, 'prologue': extra_preamble + prologue }
|
||||
enctex = tex.encode('utf-8')
|
||||
fn = latex_name_template % sha.new(enctex).hexdigest()
|
||||
|
||||
attachdir = AttachFile.getAttachDir(self.request, formatter.page.page_name, create=1)
|
||||
dst = "%s/%s%%d.png" % (attachdir, fn)
|
||||
if not os.access(dst % 1, os.R_OK):
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
try:
|
||||
data = open("%s/%s.tex" % (tmpdir, fn), "w")
|
||||
data.write(enctex)
|
||||
data.close()
|
||||
args = list(latex_args)
|
||||
args[-1] = args[-1] % fn
|
||||
res = call_command_in_dir(latex, args, tmpdir)
|
||||
if not res is None:
|
||||
return formatter.preformatted(1)+formatter.text('latex'+res)+formatter.preformatted(0)
|
||||
args = list(dvipng_args)
|
||||
args[-1] = args[-1] % fn
|
||||
res = call_command_in_dir(dvipng, args, tmpdir)
|
||||
if not res is None:
|
||||
return formatter.preformatted(1)+formatter.text('dvipng'+res)+formatter.preformatted(0)
|
||||
|
||||
page = 1
|
||||
while os.access("%s/%s%d.png" % (tmpdir, fn, page), os.R_OK):
|
||||
shutil.copyfile ("%s/%s%d.png" % (tmpdir, fn, page), dst % page)
|
||||
page += 1
|
||||
|
||||
finally:
|
||||
for root,dirs,files in os.walk(tmpdir, topdown=False):
|
||||
for name in files:
|
||||
os.remove(os.path.join(root,name))
|
||||
for name in dirs:
|
||||
os.rmdir(os.path.join(root,name))
|
||||
os.rmdir(tmpdir)
|
||||
|
||||
result = ""
|
||||
page = 1
|
||||
loop = False
|
||||
for match in anchor.finditer(inputtex):
|
||||
result += formatter.anchordef(match.group(1))
|
||||
for match in anchor.finditer(prologue):
|
||||
result += formatter.anchordef(match.group(1))
|
||||
while os.access(dst % page, os.R_OK):
|
||||
url = AttachFile.getAttachUrl(formatter.page.page_name, fn+"%d.png" % page, self.request)
|
||||
if loop:
|
||||
result += formatter.linebreak(0)+formatter.linebreak(0)
|
||||
if para:
|
||||
result += formatter.paragraph(1)
|
||||
result += formatter.image(src="%s" % url, alt=inputtex, title=inputtex, align="absmiddle")
|
||||
if para:
|
||||
result += formatter.paragraph(0)
|
||||
page += 1
|
||||
loop = True
|
||||
return result
|
5
wiki/theme/__init__.py
Normal file
5
wiki/theme/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
|
||||
from MoinMoin.util import pysupport
|
||||
|
||||
modules = pysupport.getPackageModules(__file__)
|
35
wiki/theme/bde.py
Normal file
35
wiki/theme/bde.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin monobook theme. Uses the css sheet from
|
||||
http://wikipedia.org, adapting the moin output to fit it.
|
||||
|
||||
Adapted by Jim Clark <jim AT clarkster DOT co DOT uk>
|
||||
Adapted for CR@NS by Nicolas Salles <salles AT crans DOT org>
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
|
||||
from crans import ThemeCrans
|
||||
|
||||
class Theme(ThemeCrans):
|
||||
|
||||
|
||||
# Standard set of style sheets
|
||||
stylesheets = (
|
||||
# media basename
|
||||
('all', 'common'),
|
||||
('screen', 'crans'),
|
||||
('screen', 'bde'),
|
||||
('print', 'print'),
|
||||
('projection', 'projection'),
|
||||
)
|
||||
|
||||
def execute(request):
|
||||
"""
|
||||
Generate and return a theme object
|
||||
|
||||
@param request: the request object
|
||||
@rtype: MoinTheme
|
||||
@return: Theme object
|
||||
"""
|
||||
return Theme(request)
|
||||
|
467
wiki/theme/blackliste.py
Normal file
467
wiki/theme/blackliste.py
Normal file
|
@ -0,0 +1,467 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin monobook theme. Uses the css sheet from
|
||||
http://wikipedia.org, adapting the moin output to fit it.
|
||||
|
||||
Adapted by Jim Clark <jim AT clarkster DOT co DOT uk>
|
||||
Adapted for CR@NS by Nicolas Salles <salles AT crans DOT org>
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
|
||||
from MoinMoin.theme import ThemeBase
|
||||
from MoinMoin import wikiutil, i18n
|
||||
from MoinMoin.Page import Page
|
||||
|
||||
class Theme(ThemeBase):
|
||||
|
||||
name = "blackliste"
|
||||
|
||||
# fake _ function to get gettext recognize those texts:
|
||||
_ = lambda x: x
|
||||
|
||||
icons = {
|
||||
# key alt icon filename w h
|
||||
# ------------------------------------------------------------------
|
||||
# navibar
|
||||
'help': ("%(page_help_contents)s", "moin-help.png", 12, 11),
|
||||
'find': ("%(page_find_page)s", "moin-search.png", 12, 12),
|
||||
'diff': (_("Diffs"), "moin-diff.png", 22, 22),
|
||||
'info': (_("Info"), "moin-info.png", 22, 22),
|
||||
'edit': (_("Edit"), "moin-edit.png", 22, 22),
|
||||
'unsubscribe':(_("Unsubscribe"), "moin-unsubscribe.png", 22, 22),
|
||||
'subscribe': (_("Subscribe"), "moin-subscribe.png",22, 22),
|
||||
'raw': (_("Raw"), "moin-raw.png", 12, 13),
|
||||
'xml': (_("XML"), "moin-xml.png", 20, 13),
|
||||
'print': (_("Print"), "moin-print.png", 16, 14),
|
||||
'view': (_("View"), "moin-show.png", 22, 22),
|
||||
'home': (_("Home"), "moin-home.png", 13, 12),
|
||||
'up': (_("Up"), "moin-parent.png", 15, 13),
|
||||
# FileAttach
|
||||
'attach': ("%(attach_count)s", "moin-attach.png", 7, 15),
|
||||
# RecentChanges
|
||||
'rss': (_("[RSS]"), "moin-rss.png", 36, 14),
|
||||
'deleted': (_("[DELETED]"), "moin-deleted.png",60, 12),
|
||||
'updated': (_("[UPDATED]"), "moin-updated.png",60, 12),
|
||||
'new': (_("[NEW]"), "moin-new.png", 31, 12),
|
||||
'diffrc': (_("[DIFF]"), "moin-diff.png", 22, 22),
|
||||
# General
|
||||
'bottom': (_("[BOTTOM]"), "moin-bottom.png", 14, 10),
|
||||
'top': (_("[TOP]"), "moin-top.png", 14, 10),
|
||||
'www': ("[WWW]", "moin-www.png", 11, 11),
|
||||
'mailto': ("[MAILTO]", "moin-email.png", 14, 10),
|
||||
'news': ("[NEWS]", "moin-news.png", 10, 11),
|
||||
'telnet': ("[TELNET]", "moin-telnet.png", 10, 11),
|
||||
'ftp': ("[FTP]", "moin-ftp.png", 11, 11),
|
||||
'file': ("[FILE]", "moin-ftp.png", 11, 11),
|
||||
# search forms
|
||||
'searchbutton': ("[?]", "moin-search.png", 12, 12),
|
||||
'interwiki': ("[%(wikitag)s]", "moin-inter.png", 16, 16),
|
||||
}
|
||||
del _
|
||||
|
||||
# Standard set of style sheets
|
||||
stylesheets = (
|
||||
# media basename
|
||||
('all', 'common'),
|
||||
('screen', 'blackliste'),
|
||||
('print', 'print'),
|
||||
('projection', 'projection'),
|
||||
)
|
||||
|
||||
|
||||
# Public functions #####################################################
|
||||
|
||||
def header(self, d, **kw):
|
||||
""" Assemble wiki header
|
||||
Here we don't add any menu bars, search bars, etc - instead wait
|
||||
until the footer. This keeps the HTML cleaner and more accessible,
|
||||
making sure the main content arrives first.
|
||||
"""
|
||||
html = [
|
||||
u'<div id="globalWrapper">',
|
||||
u'<div id="column-content">',
|
||||
self.startPage(),
|
||||
self.msg(d),
|
||||
self.title(d),
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def footer(self, d, **keywords):
|
||||
""" Assemble wiki footer
|
||||
"""
|
||||
html = [
|
||||
# End of page
|
||||
u'<div class="visualClear"></div>',
|
||||
self.endPage(),
|
||||
u'</div>',
|
||||
self.columnone(d),
|
||||
u'</div>'
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def columnone(self, d):
|
||||
""" assemble all the navigation aids for the page
|
||||
"""
|
||||
page = d['page']
|
||||
html = [
|
||||
u'<div id="column-one">',
|
||||
self.editbar(d),
|
||||
self.username(d),
|
||||
u'<div class="portlet" id="p-logo">',
|
||||
self.logo(),
|
||||
u'</div>',
|
||||
self.navibar(d),
|
||||
self.searchform(d),
|
||||
self.actionmenu(d),
|
||||
u'<div class="visualClear"></div>',
|
||||
u'<div id="footer">',
|
||||
self.pageinfo(page),
|
||||
self.credits(d),
|
||||
u'</div>',
|
||||
u'</div>'
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def headscript(self, d):
|
||||
""" Override to not output search/action menu javascript.
|
||||
(perhaps not a good idea)
|
||||
"""
|
||||
return ''
|
||||
|
||||
def extendedAttrs(self, title, accesskey):
|
||||
""" Helper function for assembling titled access key links
|
||||
"""
|
||||
return 'title="%(title)s [alt-%(accesskey)s]" accesskey=%(accesskey)s' % \
|
||||
{'accesskey' : accesskey,
|
||||
'title' : title}
|
||||
|
||||
def editbar(self, d):
|
||||
""" Display a list of actions for the page. This list will be turned
|
||||
into a set of tabbed views on the page by the css.
|
||||
"""
|
||||
page = d['page']
|
||||
if not self.shouldShowEditbar(page):
|
||||
return ''
|
||||
|
||||
# Use cached editbar if possible.
|
||||
cacheKey = 'editbar'
|
||||
cached = self._cache.get(cacheKey)
|
||||
if cached:
|
||||
return cached
|
||||
|
||||
request = self.request
|
||||
_ = self.request.getText
|
||||
link = wikiutil.link_tag
|
||||
quotedname = wikiutil.quoteWikinameURL(page.page_name)
|
||||
# action, title, description, accesskey
|
||||
tabs = [('view', 'Article', 'View the page content', 'c'),
|
||||
('edit', 'Edit', 'Edit this page', 'e'),
|
||||
('diff', 'Show Changes', 'Last page modification', 'd'),
|
||||
('info', 'Get Info', 'Page history and information', 'h'),
|
||||
('subscribe', 'Subscribe', 'Subscribe to updates to this page', 'w')]
|
||||
|
||||
items = []
|
||||
current = self.request.form.get('action', ['view'])[0]
|
||||
for action, title, description, accesskey in tabs:
|
||||
if action == current:
|
||||
cls = 'selected'
|
||||
else:
|
||||
cls = 'none'
|
||||
|
||||
if action == "subscribe":
|
||||
items.append(u'<li class="%s" id="edit-%s">%s</li>\n' % (cls, action, self.make_iconlink(
|
||||
["subscribe", "unsubscribe"][self.request.user.isSubscribedTo([d['page_name']])], d)))
|
||||
else:
|
||||
items.append(u'<li class="%s" id="edit-%s">%s</li>\n' % (cls, action, self.make_iconlink(action, d)))
|
||||
|
||||
html = [
|
||||
u'<div id="p-cactions" class="portlet">',
|
||||
u'<ul class="editbar">',
|
||||
''.join(items),
|
||||
u'</ul>',
|
||||
u'</div>'
|
||||
]
|
||||
html = ''.join(html)
|
||||
# cache for next call
|
||||
self._cache[cacheKey] = html
|
||||
|
||||
return html
|
||||
|
||||
|
||||
def actionmenu(self, d):
|
||||
""" different implementation of the actionmenu (aka toolbox)
|
||||
"""
|
||||
|
||||
page = d['page']
|
||||
|
||||
# Use cached actionmenu if possible.
|
||||
cacheKey = 'actionmenu'
|
||||
cached = self._cache.get(cacheKey)
|
||||
if cached:
|
||||
return cached
|
||||
|
||||
request = self.request
|
||||
_ = request.getText
|
||||
quotedname = wikiutil.quoteWikinameURL(page.page_name)
|
||||
|
||||
menu = [
|
||||
'raw',
|
||||
'print',
|
||||
'refresh',
|
||||
'AttachFile',
|
||||
'SpellCheck',
|
||||
'LikePages',
|
||||
'LocalSiteMap',
|
||||
'RenamePage',
|
||||
'DeletePage',
|
||||
]
|
||||
|
||||
titles = {
|
||||
'raw': _('Show Raw Text', formatted=False),
|
||||
'print': _('Show Print View', formatted=False),
|
||||
'refresh': _('Delete Cache', formatted=False),
|
||||
'AttachFile': _('Attach File', formatted=False),
|
||||
'SpellCheck': _('Check Spelling', formatted=False), # rename action!
|
||||
'RenamePage': _('Rename Page', formatted=False),
|
||||
'DeletePage': _('Delete Page', formatted=False),
|
||||
'LikePages': _('Show Like Pages', formatted=False),
|
||||
'LocalSiteMap': _('Show Local Site Map', formatted=False),
|
||||
}
|
||||
|
||||
links = []
|
||||
|
||||
# Format standard actions
|
||||
available = request.getAvailableActions(page)
|
||||
for action in menu:
|
||||
# Enable delete cache only if page can use caching
|
||||
if action == 'refresh':
|
||||
if not page.canUseCache():
|
||||
break
|
||||
# Actions which are not available for this wiki, user or page
|
||||
if action[0].isupper() and not action in available:
|
||||
break;
|
||||
|
||||
link = wikiutil.link_tag(self.request, \
|
||||
quotedname + '?action=' + action, titles[action])
|
||||
links.append(link)
|
||||
|
||||
# Add custom actions not in the standard menu
|
||||
more = [item for item in available if not item in titles]
|
||||
more.sort()
|
||||
if more:
|
||||
# Add more actions (all enabled)
|
||||
for action in more:
|
||||
data = {'action': action, 'disabled': ''}
|
||||
title = Page(request, action).split_title(request, force=1)
|
||||
# Use translated version if available
|
||||
title = _(title, formatted=False)
|
||||
link = wikiutil.link_tag(self.request, \
|
||||
quotedname + '?action=' + action, title)
|
||||
links.append(link)
|
||||
|
||||
html = [
|
||||
u'<div class="portlet" id="p-tb">',
|
||||
u'<h5>Toolbox</h5>',
|
||||
u'<div class="pBody">',
|
||||
u'<ul>',
|
||||
u'<li>%s</li></ul>' % '</li>\n<li>'.join(links),
|
||||
u'</ul>',
|
||||
u'</div>',
|
||||
u'</div>',
|
||||
]
|
||||
html = ''.join(html)
|
||||
# cache for next call
|
||||
self._cache[cacheKey] = html
|
||||
return html
|
||||
|
||||
|
||||
def username(self, d):
|
||||
""" Assemble the username / userprefs link
|
||||
Copied from the base class, modified to include hotkeys and link titles
|
||||
"""
|
||||
from MoinMoin.Page import Page
|
||||
request = self.request
|
||||
_ = request.getText
|
||||
|
||||
userlinks = []
|
||||
# Add username/homepage link for registered users. We don't care
|
||||
# if it exists, the user can create it.
|
||||
if request.user.valid:
|
||||
homepage = Page(request, request.user.name)
|
||||
title = homepage.split_title(request)
|
||||
attrs = self.extendedAttrs(_('User Page'), '.')
|
||||
homelink = homepage.link_to(request, text=title, attrs=attrs)
|
||||
userlinks.append(homelink)
|
||||
|
||||
# Set pref page to localized Preferences page
|
||||
attrs = self.extendedAttrs(_('My Preferences'), 'u')
|
||||
prefpage = wikiutil.getSysPage(request, 'UserPreferences')
|
||||
title = prefpage.split_title(request)
|
||||
userlinks.append(prefpage.link_to(request, text=title, attrs=attrs))
|
||||
|
||||
# Add a logout link (not sure this is really necessary
|
||||
attrs = self.extendedAttrs(_('log out'), 'o')
|
||||
page = d['page']
|
||||
url = wikiutil.quoteWikinameURL(page.page_name) + \
|
||||
'?action=userform&logout=1'
|
||||
link = wikiutil.link_tag(self.request, url, 'log out', attrs=attrs)
|
||||
userlinks.append(link)
|
||||
|
||||
else:
|
||||
# Add prefpage links with title: Login
|
||||
prefpage = wikiutil.getSysPage(request, 'UserPreferences')
|
||||
attrs = self.extendedAttrs('Logging in is not required, but brings benefits', 'o')
|
||||
userlinks.append(prefpage.link_to(request, text=_("Login"), attrs=attrs))
|
||||
|
||||
html = [
|
||||
u'<div class="portlet" id="p-personal">',
|
||||
u'<ul id="username">',
|
||||
u'<li class="pt-userpage">%s</li></ul>' % '</li>\n<li>'.join(userlinks),
|
||||
u'</ul>',
|
||||
u'</div>'
|
||||
]
|
||||
return ''.join(html)
|
||||
|
||||
def searchform(self, d):
|
||||
""" assemble HTML code for the search form
|
||||
Tweaks from the bass class to wrap in a 'portlet' class, move the
|
||||
description to a header tag, add an access key of 'f' and
|
||||
add SearchButton class for the buttons
|
||||
"""
|
||||
_ = self.request.getText
|
||||
form = self.request.form
|
||||
updates = {
|
||||
'search_label' : _('Search:'),
|
||||
'search_value': wikiutil.escape(form.get('value', [''])[0], 1),
|
||||
'search_full_label' : _('Text', formatted=False),
|
||||
'search_title_label' : _('Titles', formatted=False),
|
||||
}
|
||||
d.update(updates)
|
||||
|
||||
html = u'''
|
||||
<div class="portlet" id="p-search">
|
||||
<h5><label for="searchInput">%(search_label)s</label></h5>
|
||||
<div class="pBody">
|
||||
<form id="searchform" method="get" action="">
|
||||
<div>
|
||||
<input type="hidden" name="action" value="fullsearch">
|
||||
<input type="hidden" name="context" value="180">
|
||||
<input id="searchInput" name="value" type="text" accesskey="f"
|
||||
value="%(search_value)s">
|
||||
<input id="titlesearch" name="titlesearch" type="submit" class="searchButton"
|
||||
value="%(search_title_label)s" alt="Search Titles">
|
||||
<input id="fullsearch" name="fullsearch" type="submit" class="searchButton"
|
||||
value="%(search_full_label)s" alt="Search Full Text">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
''' % d
|
||||
return html
|
||||
|
||||
def shouldShowEditbar(self, page):
|
||||
""" Override to include the editbar on edit/preview pages.
|
||||
(at the risk that the user may accidentally cancel an edit)
|
||||
"""
|
||||
if (page.exists(includeDeleted=1) and
|
||||
self.request.user.may.read(page.page_name)):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def navibar(self, d):
|
||||
""" Alterations from the base class to include access keys and
|
||||
descriptions for FrontPage/RecentChanges
|
||||
"""
|
||||
request = self.request
|
||||
found = {} # pages we found. prevent duplicates
|
||||
links = [] # navibar items
|
||||
current = d['page_name']
|
||||
|
||||
# Process config navi_bar
|
||||
if request.cfg.navi_bar:
|
||||
for text in request.cfg.navi_bar:
|
||||
pagename, link = self.splitNavilink(text)
|
||||
if pagename == d['page_front_page']:
|
||||
attrs = self.extendedAttrs('Visit the main page', 'z')
|
||||
elif pagename == 'RecentChanges':
|
||||
attrs = self.extendedAttrs('List of recent changes in this wiki', 'r')
|
||||
else:
|
||||
attrs = ''
|
||||
|
||||
a = wikiutil.link_tag(request, pagename, attrs=attrs)
|
||||
links.append(a)
|
||||
found[pagename] = 1
|
||||
|
||||
# Add user links to wiki links, eliminating duplicates.
|
||||
userlinks = request.user.getQuickLinks()
|
||||
for text in userlinks:
|
||||
# Split text without localization, user know what she wants
|
||||
pagename, link = self.splitNavilink(text, localize=0)
|
||||
if not pagename in found:
|
||||
a = wikiutil.link_tag(request, pagename, attrs=attrs)
|
||||
links.append(a)
|
||||
found[pagename] = 1
|
||||
|
||||
html = [
|
||||
u'<div class="portlet" id="p-nav">',
|
||||
u'<div class="pBody">',
|
||||
u'<ul id="navibar">',
|
||||
u'<li>%s</li></ul>' % '</li>\n<li>'.join(links),
|
||||
u'</ul>',
|
||||
u'</div>',
|
||||
u'</div>',
|
||||
]
|
||||
return ''.join(html)
|
||||
|
||||
def pageinfo(self, page):
|
||||
""" Simple override from base class.
|
||||
Remove <p> so footer isn't too big
|
||||
"""
|
||||
_ = self.request.getText
|
||||
|
||||
if self.shouldShowPageinfo(page):
|
||||
info = page.lastEditInfo()
|
||||
if info:
|
||||
if info['editor']:
|
||||
info = _("last edited %(time)s by %(editor)s") % info
|
||||
else:
|
||||
info = _("last modified %(time)s") % info
|
||||
return info
|
||||
return ''
|
||||
|
||||
def rtl_stylesheet(self, d):
|
||||
""" monobook uses a separate css page for rtl alterations.
|
||||
Add the rtl stylesheet if the user needs it
|
||||
"""
|
||||
link = ('<link rel="stylesheet" type="text/css" charset="%s"'
|
||||
' media="%s" href="%s">')
|
||||
html = []
|
||||
if i18n.getDirection(self.request.lang) == 'rtl':
|
||||
prefix = self.cfg.url_prefix
|
||||
href = '%s/%s/css/%s.css' % (prefix, self.name, 'rtl')
|
||||
html.append(link % (self.stylesheetsCharset, 'all', href))
|
||||
return '\n'.join(html)
|
||||
|
||||
def html_head(self, d):
|
||||
""" Tweak the sending of the head, to include right-to-left
|
||||
alterations if necessary
|
||||
"""
|
||||
html = [
|
||||
u'<title>%(title)s - %(sitename)s</title>' % d,
|
||||
self.headscript(d), # Should move to separate .js file
|
||||
self.html_stylesheets(d),
|
||||
self.rtl_stylesheet(d),
|
||||
self.rsslink(),
|
||||
]
|
||||
return '\n'.join(html)
|
||||
|
||||
def execute(request):
|
||||
"""
|
||||
Generate and return a theme object
|
||||
|
||||
@param request: the request object
|
||||
@rtype: MoinTheme
|
||||
@return: Theme object
|
||||
"""
|
||||
return Theme(request)
|
496
wiki/theme/crans-test.py
Normal file
496
wiki/theme/crans-test.py
Normal file
|
@ -0,0 +1,496 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin monobook theme. Uses the css sheet from
|
||||
http://wikipedia.org, adapting the moin output to fit it.
|
||||
|
||||
Adapted by Jim Clark <jim AT clarkster DOT co DOT uk>
|
||||
Adapted for CR@NS by Nicolas Salles <salles AT crans DOT org>
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
|
||||
from MoinMoin.theme import ThemeBase
|
||||
from MoinMoin import wikiutil, i18n
|
||||
from MoinMoin.Page import Page
|
||||
|
||||
class ThemeCrans(ThemeBase):
|
||||
|
||||
name = "crans"
|
||||
|
||||
# fake _ function to get gettext recognize those texts:
|
||||
_ = lambda x: x
|
||||
|
||||
icons = {
|
||||
# key alt icon filename w h
|
||||
# ------------------------------------------------------------------
|
||||
# navibar
|
||||
'help': ("%(page_help_contents)s", "moin-help.png", 12, 11),
|
||||
'find': ("%(page_find_page)s", "moin-search.png", 12, 12),
|
||||
'diff': (_("Diffs"), "moin-diff.png", 22, 22),
|
||||
'info': (_("Info"), "moin-info.png", 22, 22),
|
||||
'edit': (_("Edit"), "moin-edit.png", 22, 22),
|
||||
'unsubscribe':(_("Unsubscribe"), "moin-unsubscribe.png", 22, 22),
|
||||
'subscribe': (_("Subscribe"), "moin-subscribe.png",22, 22),
|
||||
'raw': (_("Raw"), "moin-raw.png", 12, 13),
|
||||
'xml': (_("XML"), "moin-xml.png", 20, 13),
|
||||
'print': (_("Print"), "moin-print.png", 16, 14),
|
||||
'view': (_("View"), "moin-show.png", 22, 22),
|
||||
'home': (_("Home"), "moin-home.png", 13, 12),
|
||||
'up': (_("Up"), "moin-parent.png", 15, 13),
|
||||
# FileAttach
|
||||
'attach': ("%(attach_count)s", "moin-attach.png", 7, 15),
|
||||
# RecentChanges
|
||||
'rss': (_("[RSS]"), "moin-rss.png", 36, 14),
|
||||
'deleted': (_("[DELETED]"), "moin-deleted.png",60, 12),
|
||||
'updated': (_("[UPDATED]"), "moin-updated.png",60, 12),
|
||||
'new': (_("[NEW]"), "moin-new.png", 31, 12),
|
||||
'diffrc': (_("[DIFF]"), "moin-diff.png", 22, 22),
|
||||
# General
|
||||
'bottom': (_("[BOTTOM]"), "moin-bottom.png", 14, 10),
|
||||
'top': (_("[TOP]"), "moin-top.png", 14, 10),
|
||||
'www': ("[WWW]", "moin-www.png", 11, 11),
|
||||
'mailto': ("[MAILTO]", "moin-email.png", 14, 10),
|
||||
'news': ("[NEWS]", "moin-news.png", 10, 11),
|
||||
'telnet': ("[TELNET]", "moin-telnet.png", 10, 11),
|
||||
'ftp': ("[FTP]", "moin-ftp.png", 11, 11),
|
||||
'file': ("[FILE]", "moin-ftp.png", 11, 11),
|
||||
# search forms
|
||||
'searchbutton': ("[?]", "moin-search.png", 12, 12),
|
||||
'interwiki': ("[%(wikitag)s]", "moin-inter.png", 16, 16),
|
||||
}
|
||||
del _
|
||||
|
||||
# Standard set of style sheets
|
||||
stylesheets = (
|
||||
# media basename
|
||||
('all', 'common'),
|
||||
('screen', 'crans'),
|
||||
('print', 'print'),
|
||||
('projection', 'projection'),
|
||||
)
|
||||
|
||||
|
||||
# Public functions #####################################################
|
||||
|
||||
def header(self, d, **kw):
|
||||
""" Assemble wiki header
|
||||
Here we don't add any menu bars, search bars, etc - instead wait
|
||||
until the footer. This keeps the HTML cleaner and more accessible,
|
||||
making sure the main content arrives first.
|
||||
"""
|
||||
html = [
|
||||
u'<div id="globalWrapper">',
|
||||
u'<div id="column-content">',
|
||||
self.startPage(),
|
||||
self.msg(d),
|
||||
self.title(d),
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def footer(self, d, **keywords):
|
||||
""" Assemble wiki footer
|
||||
"""
|
||||
html = [
|
||||
# End of page
|
||||
u'<div class="visualClear"></div>',
|
||||
self.endPage(),
|
||||
u'</div>',
|
||||
self.columnone(d),
|
||||
u'</div>'
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def columnone(self, d):
|
||||
""" assemble all the navigation aids for the page
|
||||
"""
|
||||
page = d['page']
|
||||
html = [
|
||||
u'<div id="column-one">',
|
||||
self.editbar(d),
|
||||
self.username(d),
|
||||
u'<div class="portlet" id="p-logo">',
|
||||
self.logo(),
|
||||
u'</div>',
|
||||
self.navibar(d),
|
||||
self.searchform(d),
|
||||
self.actionmenu(d),
|
||||
u'<div class="visualClear"></div>',
|
||||
u'<div id="footer">',
|
||||
self.pageinfo(page),
|
||||
self.credits(d),
|
||||
u'</div>',
|
||||
u'</div>'
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def headscript(self, d):
|
||||
""" Override to not output search/action menu javascript.
|
||||
(perhaps not a good idea)
|
||||
"""
|
||||
return ''
|
||||
|
||||
def extendedAttrs(self, title, accesskey):
|
||||
""" Helper function for assembling titled access key links
|
||||
"""
|
||||
return 'title="%(title)s [alt-%(accesskey)s]" accesskey=%(accesskey)s' % \
|
||||
{'accesskey' : accesskey,
|
||||
'title' : title}
|
||||
|
||||
def editbar(self, d):
|
||||
""" Display a list of actions for the page. This list will be turned
|
||||
into a set of tabbed views on the page by the css.
|
||||
"""
|
||||
page = d['page']
|
||||
if not self.shouldShowEditbar(page):
|
||||
return ''
|
||||
|
||||
# Use cached editbar if possible.
|
||||
cacheKey = 'editbar'
|
||||
cached = self._cache.get(cacheKey)
|
||||
if cached:
|
||||
return cached
|
||||
|
||||
request = self.request
|
||||
_ = self.request.getText
|
||||
link = wikiutil.link_tag
|
||||
quotedname = wikiutil.quoteWikinameURL(page.page_name)
|
||||
# action, title, description, accesskey
|
||||
tabs = [('view', 'Article', 'View the page content', 'c'),
|
||||
('edit', 'Edit', 'Edit this page', 'e'),
|
||||
('diff', 'Show Changes', 'Last page modification', 'd'),
|
||||
('info', 'Get Info', 'Page history and information', 'h'),
|
||||
('subscribe', 'Subscribe', 'Subscribe to updates to this page', 'w')]
|
||||
|
||||
items = []
|
||||
current = self.request.form.get('action', ['view'])[0]
|
||||
for action, title, description, accesskey in tabs:
|
||||
if action == current:
|
||||
cls = 'selected'
|
||||
else:
|
||||
cls = 'none'
|
||||
|
||||
if action == "subscribe":
|
||||
items.append(u'<li class="%s" id="edit-%s">%s</li>\n' % (cls, action, self.make_iconlink(
|
||||
["subscribe", "unsubscribe"][self.request.user.isSubscribedTo([d['page_name']])], d)))
|
||||
else:
|
||||
items.append(u'<li class="%s" id="edit-%s">%s</li>\n' % (cls, action, self.make_iconlink(action, d)))
|
||||
|
||||
html = [
|
||||
u'<div id="p-cactions" class="portlet">',
|
||||
u'<ul class="editbar">',
|
||||
''.join(items),
|
||||
u'</ul>',
|
||||
u'</div>'
|
||||
]
|
||||
html = ''.join(html)
|
||||
# cache for next call
|
||||
self._cache[cacheKey] = html
|
||||
|
||||
return html
|
||||
|
||||
|
||||
def actionmenu(self, d):
|
||||
""" different implementation of the actionmenu (aka toolbox)
|
||||
"""
|
||||
|
||||
page = d['page']
|
||||
|
||||
# Use cached actionmenu if possible.
|
||||
cacheKey = 'actionmenu'
|
||||
cached = self._cache.get(cacheKey)
|
||||
if cached:
|
||||
return cached
|
||||
|
||||
request = self.request
|
||||
_ = request.getText
|
||||
quotedname = wikiutil.quoteWikinameURL(page.page_name)
|
||||
|
||||
menu = [
|
||||
'raw',
|
||||
'print',
|
||||
'refresh',
|
||||
'AttachFile',
|
||||
'SpellCheck',
|
||||
'LikePages',
|
||||
'LocalSiteMap',
|
||||
'RenamePage',
|
||||
'DeletePage',
|
||||
]
|
||||
|
||||
titles = {
|
||||
'raw': _('Show Raw Text', formatted=False),
|
||||
'print': _('Show Print View', formatted=False),
|
||||
'refresh': _('Delete Cache', formatted=False),
|
||||
'AttachFile': _('Attach File', formatted=False),
|
||||
'SpellCheck': _('Check Spelling', formatted=False), # rename action!
|
||||
'RenamePage': _('Rename Page', formatted=False),
|
||||
'DeletePage': _('Delete Page', formatted=False),
|
||||
'LikePages': _('Show Like Pages', formatted=False),
|
||||
'LocalSiteMap': _('Show Local Site Map', formatted=False),
|
||||
}
|
||||
|
||||
links = []
|
||||
|
||||
# Format standard actions
|
||||
available = request.getAvailableActions(page)
|
||||
for action in menu:
|
||||
# Enable delete cache only if page can use caching
|
||||
if action == 'refresh':
|
||||
if not page.canUseCache():
|
||||
break
|
||||
# Actions which are not available for this wiki, user or page
|
||||
if action[0].isupper() and not action in available:
|
||||
break;
|
||||
|
||||
link = wikiutil.link_tag(self.request, \
|
||||
quotedname + '?action=' + action, titles[action])
|
||||
links.append(link)
|
||||
|
||||
# Add custom actions not in the standard menu
|
||||
more = [item for item in available if not item in titles]
|
||||
more.sort()
|
||||
if more:
|
||||
# Add more actions (all enabled)
|
||||
for action in more:
|
||||
data = {'action': action, 'disabled': ''}
|
||||
title = Page(request, action).split_title(request, force=1)
|
||||
# Use translated version if available
|
||||
title = _(title, formatted=False)
|
||||
link = wikiutil.link_tag(self.request, \
|
||||
quotedname + '?action=' + action, title)
|
||||
links.append(link)
|
||||
|
||||
html = [
|
||||
u'<div class="portlet" id="p-tb">',
|
||||
u'<h5>Toolbox</h5>',
|
||||
u'<div class="pBody">',
|
||||
u'<ul>',
|
||||
u'<li>%s</li></ul>' % '</li>\n<li>'.join(links),
|
||||
u'</ul>',
|
||||
u'</div>',
|
||||
u'</div>',
|
||||
]
|
||||
html = ''.join(html)
|
||||
# cache for next call
|
||||
self._cache[cacheKey] = html
|
||||
return html
|
||||
|
||||
|
||||
def username(self, d):
|
||||
""" Assemble the username / userprefs link
|
||||
Copied from the base class, modified to include hotkeys and link titles
|
||||
"""
|
||||
from MoinMoin.Page import Page
|
||||
request = self.request
|
||||
_ = request.getText
|
||||
|
||||
userlinks = []
|
||||
# Add username/homepage link for registered users. We don't care
|
||||
# if it exists, the user can create it.
|
||||
if request.user.valid:
|
||||
homepage = Page(request, request.user.name)
|
||||
title = homepage.split_title(request)
|
||||
attrs = self.extendedAttrs(_('User Page'), '.')
|
||||
homelink = homepage.link_to(request, text=title, attrs=attrs)
|
||||
userlinks.append(homelink)
|
||||
|
||||
# Set pref page to localized Preferences page
|
||||
attrs = self.extendedAttrs(_('My Preferences'), 'u')
|
||||
prefpage = wikiutil.getSysPage(request, 'UserPreferences')
|
||||
title = prefpage.split_title(request)
|
||||
userlinks.append(prefpage.link_to(request, text=title, attrs=attrs))
|
||||
|
||||
# Add a logout link (not sure this is really necessary
|
||||
attrs = self.extendedAttrs(_('log out'), 'o')
|
||||
page = d['page']
|
||||
url = wikiutil.quoteWikinameURL(page.page_name) + \
|
||||
'?action=userform&logout=1'
|
||||
link = wikiutil.link_tag(self.request, url, 'log out', attrs=attrs)
|
||||
userlinks.append(link)
|
||||
|
||||
else:
|
||||
# Add prefpage links with title: Login
|
||||
prefpage = wikiutil.getSysPage(request, 'UserPreferences')
|
||||
attrs = self.extendedAttrs('Logging in is not required, but brings benefits', 'o')
|
||||
userlinks.append(prefpage.link_to(request, text=_("Login"), attrs=attrs))
|
||||
|
||||
html = [
|
||||
u'<div class="portlet" id="p-personal">',
|
||||
u'<ul id="username">',
|
||||
u'<li class="pt-userpage">%s</li></ul>' % '</li>\n<li>'.join(userlinks),
|
||||
u'</ul>',
|
||||
u'</div>'
|
||||
]
|
||||
return ''.join(html)
|
||||
|
||||
def searchform(self, d):
|
||||
""" assemble HTML code for the search form
|
||||
Tweaks from the bass class to wrap in a 'portlet' class, move the
|
||||
description to a header tag, add an access key of 'f' and
|
||||
add SearchButton class for the buttons
|
||||
"""
|
||||
_ = self.request.getText
|
||||
form = self.request.form
|
||||
updates = {
|
||||
'search_label' : _('Search:'),
|
||||
'search_value': wikiutil.escape(form.get('value', [''])[0], 1),
|
||||
'search_full_label' : _('Text', formatted=False),
|
||||
'search_title_label' : _('Titles', formatted=False),
|
||||
}
|
||||
d.update(updates)
|
||||
|
||||
html = u'''
|
||||
<div class="portlet" id="p-search">
|
||||
<h5><label for="searchInput">%(search_label)s</label></h5>
|
||||
<div class="pBody">
|
||||
<form id="searchform" method="get" action="">
|
||||
<div>
|
||||
<input type="hidden" name="action" value="fullsearch">
|
||||
<input type="hidden" name="context" value="180">
|
||||
<input id="searchInput" name="value" type="text" accesskey="f"
|
||||
value="%(search_value)s">
|
||||
<input id="titlesearch" name="titlesearch" type="submit" class="searchButton"
|
||||
value="%(search_title_label)s" alt="Search Titles">
|
||||
<input id="fullsearch" name="fullsearch" type="submit" class="searchButton"
|
||||
value="%(search_full_label)s" alt="Search Full Text">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
''' % d
|
||||
return html
|
||||
|
||||
def shouldShowEditbar(self, page):
|
||||
""" Override to include the editbar on edit/preview pages.
|
||||
(at the risk that the user may accidentally cancel an edit)
|
||||
"""
|
||||
if (page.exists(includeDeleted=1) and
|
||||
self.request.user.may.read(page.page_name)):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def navibar(self, d):
|
||||
""" Alterations from the base class to include access keys and
|
||||
descriptions for FrontPage/RecentChanges
|
||||
"""
|
||||
request = self.request
|
||||
found = {} # pages we found. prevent duplicates
|
||||
links = [] # navibar items
|
||||
current = d['page_name']
|
||||
|
||||
# Process config navi_bar
|
||||
if request.cfg.navi_bar:
|
||||
for text in request.cfg.navi_bar:
|
||||
pagename, link = self.splitNavilink(text)
|
||||
if pagename == d['page_front_page']:
|
||||
attrs = self.extendedAttrs('Visit the main page', 'z')
|
||||
elif pagename == 'RecentChanges':
|
||||
attrs = self.extendedAttrs('List of recent changes in this wiki', 'r')
|
||||
else:
|
||||
attrs = ''
|
||||
|
||||
a = wikiutil.link_tag(request, pagename, attrs=attrs)
|
||||
links.append(a)
|
||||
found[pagename] = 1
|
||||
|
||||
# Add user links to wiki links, eliminating duplicates.
|
||||
userlinks = request.user.getQuickLinks()
|
||||
for text in userlinks:
|
||||
# Split text without localization, user know what she wants
|
||||
pagename, link = self.splitNavilink(text, localize=0)
|
||||
if not pagename in found:
|
||||
a = wikiutil.link_tag(request, pagename, attrs=attrs)
|
||||
links.append(a)
|
||||
found[pagename] = 1
|
||||
|
||||
html = [
|
||||
u'<div class="portlet" id="p-nav">',
|
||||
u'<div class="pBody">',
|
||||
u'<ul id="navibar">',
|
||||
u'<li>%s</li></ul>' % '</li>\n<li>'.join(links),
|
||||
u'</ul>',
|
||||
u'</div>',
|
||||
u'</div>',
|
||||
]
|
||||
return ''.join(html)
|
||||
|
||||
def pageinfo(self, page):
|
||||
""" Simple override from base class.
|
||||
Remove <p> so footer isn't too big
|
||||
"""
|
||||
_ = self.request.getText
|
||||
|
||||
if self.shouldShowPageinfo(page):
|
||||
info = page.lastEditInfo()
|
||||
if info:
|
||||
if info['editor']:
|
||||
info = _("last edited %(time)s by %(editor)s") % info
|
||||
else:
|
||||
info = _("last modified %(time)s") % info
|
||||
return info
|
||||
return ''
|
||||
|
||||
def rtl_stylesheet(self, d):
|
||||
""" monobook uses a separate css page for rtl alterations.
|
||||
Add the rtl stylesheet if the user needs it
|
||||
"""
|
||||
link = ('<link rel="stylesheet" type="text/css" charset="%s"'
|
||||
' media="%s" href="%s">')
|
||||
html = []
|
||||
if i18n.getDirection(self.request.lang) == 'rtl':
|
||||
prefix = self.cfg.url_prefix
|
||||
href = '%s/%s/css/%s.css' % (prefix, self.name, 'rtl')
|
||||
html.append(link % (self.stylesheetsCharset, 'all', href))
|
||||
return '\n'.join(html)
|
||||
|
||||
def html_head(self, d):
|
||||
""" Tweak the sending of the head, to include right-to-left
|
||||
alterations if necessary
|
||||
"""
|
||||
html = [
|
||||
u'<title>%(title)s - %(sitename)s</title>' % d,
|
||||
self.headscript(d), # Should move to separate .js file
|
||||
self.html_stylesheets(d),
|
||||
self.rtl_stylesheet(d),
|
||||
self.rsslink(),
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def html_stylesheets(self, d):
|
||||
"""
|
||||
On fixe le chemin d'acces vers les feuilles de style
|
||||
"""
|
||||
html = []
|
||||
for media, nom in self.stylesheets:
|
||||
html.append(u'<link rel="stylesheet" type="text/css" media="%s" href="/wiki/crans/css/%s.css" />' % (media, nom))
|
||||
|
||||
|
||||
|
||||
class Theme(ThemeCrans):
|
||||
|
||||
name = "crans"
|
||||
|
||||
# Standard set of style sheets
|
||||
stylesheets = (
|
||||
# media basename
|
||||
('all', 'common'),
|
||||
('screen', 'crans'),
|
||||
('print', 'print'),
|
||||
('projection', 'projection'),
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def execute(request):
|
||||
"""
|
||||
Generate and return a theme object
|
||||
|
||||
@param request: the request object
|
||||
@rtype: MoinTheme
|
||||
@return: Theme object
|
||||
"""
|
||||
return Theme(request)
|
502
wiki/theme/crans.py
Normal file
502
wiki/theme/crans.py
Normal file
|
@ -0,0 +1,502 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin monobook theme. Uses the css sheet from
|
||||
http://wikipedia.org, adapting the moin output to fit it.
|
||||
|
||||
Adapted by Jim Clark <jim AT clarkster DOT co DOT uk>
|
||||
Adapted for CR@NS by Nicolas Salles <salles AT crans DOT org>
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
|
||||
from MoinMoin.theme import ThemeBase
|
||||
from MoinMoin import wikiutil, i18n
|
||||
from MoinMoin.Page import Page
|
||||
|
||||
class ThemeCrans(ThemeBase):
|
||||
|
||||
name = "crans"
|
||||
|
||||
# fake _ function to get gettext recognize those texts:
|
||||
_ = lambda x: x
|
||||
|
||||
icons = {
|
||||
# key alt icon filename w h
|
||||
# ------------------------------------------------------------------
|
||||
# navibar
|
||||
'help': ("%(page_help_contents)s", "moin-help.png", 12, 11),
|
||||
'find': ("%(page_find_page)s", "moin-search.png", 12, 12),
|
||||
'diff': (_("Diffs"), "moin-diff.png", 22, 22),
|
||||
'info': (_("Info"), "moin-info.png", 22, 22),
|
||||
'edit': (_("Edit"), "moin-edit.png", 22, 22),
|
||||
'unsubscribe':(_("Unsubscribe"), "moin-unsubscribe.png", 22, 22),
|
||||
'subscribe': (_("Subscribe"), "moin-subscribe.png",22, 22),
|
||||
'raw': (_("Raw"), "moin-raw.png", 12, 13),
|
||||
'xml': (_("XML"), "moin-xml.png", 20, 13),
|
||||
'print': (_("Print"), "moin-print.png", 16, 14),
|
||||
'view': (_("View"), "moin-show.png", 22, 22),
|
||||
'home': (_("Home"), "moin-home.png", 13, 12),
|
||||
'up': (_("Up"), "moin-parent.png", 15, 13),
|
||||
# format
|
||||
'format': (_("[TEX]"), "moin-tex.png", 20, 22),
|
||||
# FileAttach
|
||||
'attach': ("%(attach_count)s", "moin-attach.png", 7, 15),
|
||||
# RecentChanges
|
||||
'rss': (_("[RSS]"), "moin-rss.png", 36, 14),
|
||||
'deleted': (_("[DELETED]"), "moin-deleted.png",60, 12),
|
||||
'updated': (_("[UPDATED]"), "moin-updated.png",60, 12),
|
||||
'new': (_("[NEW]"), "moin-new.png", 31, 12),
|
||||
'diffrc': (_("[DIFF]"), "moin-diff.png", 22, 22),
|
||||
# General
|
||||
'bottom': (_("[BOTTOM]"), "moin-bottom.png", 14, 10),
|
||||
'top': (_("[TOP]"), "moin-top.png", 14, 10),
|
||||
'www': ("[WWW]", "moin-www.png", 11, 11),
|
||||
'mailto': ("[MAILTO]", "moin-email.png", 14, 10),
|
||||
'news': ("[NEWS]", "moin-news.png", 10, 11),
|
||||
'telnet': ("[TELNET]", "moin-telnet.png", 10, 11),
|
||||
'ftp': ("[FTP]", "moin-ftp.png", 11, 11),
|
||||
'file': ("[FILE]", "moin-ftp.png", 11, 11),
|
||||
# search forms
|
||||
'searchbutton': ("[?]", "moin-search.png", 12, 12),
|
||||
'interwiki': ("[%(wikitag)s]", "moin-inter.png", 16, 16),
|
||||
}
|
||||
del _
|
||||
|
||||
# Standard set of style sheets
|
||||
stylesheets = (
|
||||
# media basename
|
||||
('all', 'common'),
|
||||
('screen', 'crans'),
|
||||
('print', 'print'),
|
||||
('projection', 'projection'),
|
||||
)
|
||||
|
||||
|
||||
# Public functions #####################################################
|
||||
|
||||
def header(self, d, **kw):
|
||||
""" Assemble wiki header
|
||||
Here we don't add any menu bars, search bars, etc - instead wait
|
||||
until the footer. This keeps the HTML cleaner and more accessible,
|
||||
making sure the main content arrives first.
|
||||
"""
|
||||
html = [
|
||||
u'<div id="globalWrapper">',
|
||||
u'<div id="column-content">',
|
||||
self.startPage(),
|
||||
self.msg(d),
|
||||
self.title(d),
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def footer(self, d, **keywords):
|
||||
""" Assemble wiki footer
|
||||
"""
|
||||
html = [
|
||||
# End of page
|
||||
u'<div class="visualClear"></div>',
|
||||
self.endPage(),
|
||||
u'<div class="visualclear"></div>',
|
||||
u'</div>',
|
||||
self.columnone(d),
|
||||
u'</div>'
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def columnone(self, d):
|
||||
""" assemble all the navigation aids for the page
|
||||
"""
|
||||
page = d['page']
|
||||
html = [
|
||||
u'<div id="column-one">',
|
||||
self.editbar(d),
|
||||
self.username(d),
|
||||
u'<div class="portlet" id="p-logo">',
|
||||
self.logo(),
|
||||
u'</div>',
|
||||
self.navibar(d),
|
||||
self.searchform(d),
|
||||
self.actionmenu(d),
|
||||
u'<div class="visualClear"></div>',
|
||||
u'<div id="footer">',
|
||||
self.pageinfo(page),
|
||||
self.credits(d),
|
||||
u'</div>',
|
||||
u'</div>'
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def headscript(self, d):
|
||||
""" Override to not output search/action menu javascript.
|
||||
(perhaps not a good idea)
|
||||
"""
|
||||
return ''
|
||||
|
||||
def extendedAttrs(self, title, accesskey):
|
||||
""" Helper function for assembling titled access key links
|
||||
"""
|
||||
return 'title="%(title)s [alt-%(accesskey)s]" accesskey=%(accesskey)s' % \
|
||||
{'accesskey' : accesskey,
|
||||
'title' : title}
|
||||
|
||||
def editbar(self, d):
|
||||
""" Display a list of actions for the page. This list will be turned
|
||||
into a set of tabbed views on the page by the css.
|
||||
"""
|
||||
page = d['page']
|
||||
if not self.shouldShowEditbar(page):
|
||||
return ''
|
||||
|
||||
# Use cached editbar if possible.
|
||||
cacheKey = 'editbar'
|
||||
cached = self._cache.get(cacheKey)
|
||||
if cached:
|
||||
return cached
|
||||
|
||||
request = self.request
|
||||
_ = self.request.getText
|
||||
link = wikiutil.link_tag
|
||||
quotedname = wikiutil.quoteWikinameURL(page.page_name)
|
||||
# action, title, description, accesskey
|
||||
tabs = [('view', 'Article', 'View the page content', 'c'),
|
||||
('edit', 'Edit', 'Edit this page', 'e'),
|
||||
('diff', 'Show Changes', 'Last page modification', 'd'),
|
||||
('info', 'Get Info', 'Page history and information', 'h'),
|
||||
#('format', 'Latex', 'Source Latex', 'l'),
|
||||
('subscribe', 'Subscribe', 'Subscribe to updates to this page', 'w')]
|
||||
|
||||
items = []
|
||||
current = self.request.form.get('action', ['view'])[0]
|
||||
for action, title, description, accesskey in tabs:
|
||||
if action == current:
|
||||
cls = 'selected'
|
||||
else:
|
||||
cls = 'none'
|
||||
|
||||
if action == "subscribe":
|
||||
items.append(u'<li class="%s" id="edit-%s">%s</li>\n' % (cls, action, self.make_iconlink(
|
||||
["subscribe", "unsubscribe"][self.request.user.isSubscribedTo([d['page_name']])], d)))
|
||||
else:
|
||||
items.append(u'<li class="%s" id="edit-%s">%s</li>\n' % (cls, action, self.make_iconlink(action, d)))
|
||||
|
||||
html = [
|
||||
u'<div id="p-cactions" class="portlet">',
|
||||
u'<ul class="editbar">',
|
||||
''.join(items),
|
||||
u'</ul>',
|
||||
u'</div>'
|
||||
]
|
||||
html = ''.join(html)
|
||||
# cache for next call
|
||||
self._cache[cacheKey] = html
|
||||
|
||||
return html
|
||||
|
||||
|
||||
def actionmenu(self, d):
|
||||
""" different implementation of the actionmenu (aka toolbox)
|
||||
"""
|
||||
|
||||
page = d['page']
|
||||
|
||||
# Use cached actionmenu if possible.
|
||||
cacheKey = 'actionmenu'
|
||||
cached = self._cache.get(cacheKey)
|
||||
if cached:
|
||||
return cached
|
||||
|
||||
request = self.request
|
||||
_ = request.getText
|
||||
quotedname = wikiutil.quoteWikinameURL(page.page_name)
|
||||
|
||||
menu = [
|
||||
'raw',
|
||||
'print',
|
||||
u'format&mimetype=text/latex',
|
||||
'refresh',
|
||||
'AttachFile',
|
||||
'SpellCheck',
|
||||
'LikePages',
|
||||
'LocalSiteMap',
|
||||
'RenamePage',
|
||||
'DeletePage',
|
||||
]
|
||||
|
||||
titles = {
|
||||
'raw': _('Show Raw Text', formatted=False),
|
||||
'print': _('Show Print View', formatted=False),
|
||||
u'format&mimetype=text/latex': _('Obtenir le code latex', formatted=False),
|
||||
'refresh': _('Delete Cache', formatted=False),
|
||||
'AttachFile': _('Attach File', formatted=False),
|
||||
'SpellCheck': _('Check Spelling', formatted=False), # rename action!
|
||||
'RenamePage': _('Rename Page', formatted=False),
|
||||
'DeletePage': _('Delete Page', formatted=False),
|
||||
'LikePages': _('Show Like Pages', formatted=False),
|
||||
'LocalSiteMap': _('Show Local Site Map', formatted=False),
|
||||
}
|
||||
|
||||
links = []
|
||||
|
||||
# Format standard actions
|
||||
available = request.getAvailableActions(page)
|
||||
for action in menu:
|
||||
# Enable delete cache only if page can use caching
|
||||
if action == 'refresh':
|
||||
if not page.canUseCache():
|
||||
break
|
||||
# Actions which are not available for this wiki, user or page
|
||||
if action[0].isupper() and not action in available:
|
||||
break;
|
||||
|
||||
link = wikiutil.link_tag(self.request, \
|
||||
quotedname + '?action=' + action, titles[action])
|
||||
links.append(link)
|
||||
|
||||
# Add custom actions not in the standard menu
|
||||
more = [item for item in available if not item in titles]
|
||||
more.sort()
|
||||
if more:
|
||||
# Add more actions (all enabled)
|
||||
for action in more:
|
||||
data = {'action': action, 'disabled': ''}
|
||||
title = Page(request, action).split_title(request, force=1)
|
||||
# Use translated version if available
|
||||
title = _(title, formatted=False)
|
||||
link = wikiutil.link_tag(self.request, \
|
||||
quotedname + '?action=' + action, title)
|
||||
links.append(link)
|
||||
|
||||
html = [
|
||||
u'<div class="portlet" id="p-tb">',
|
||||
u'<h5>Toolbox</h5>',
|
||||
u'<div class="pBody">',
|
||||
u'<ul>',
|
||||
u'<li>%s</li></ul>' % '</li>\n<li>'.join(links),
|
||||
u'</ul>',
|
||||
u'</div>',
|
||||
u'</div>',
|
||||
]
|
||||
html = ''.join(html)
|
||||
# cache for next call
|
||||
self._cache[cacheKey] = html
|
||||
return html
|
||||
|
||||
|
||||
def username(self, d):
|
||||
""" Assemble the username / userprefs link
|
||||
Copied from the base class, modified to include hotkeys and link titles
|
||||
"""
|
||||
from MoinMoin.Page import Page
|
||||
request = self.request
|
||||
_ = request.getText
|
||||
|
||||
userlinks = []
|
||||
# Add username/homepage link for registered users. We don't care
|
||||
# if it exists, the user can create it.
|
||||
if request.user.valid:
|
||||
homepage = Page(request, request.user.name)
|
||||
title = homepage.split_title(request)
|
||||
attrs = self.extendedAttrs(_('User Page'), '.')
|
||||
homelink = homepage.link_to(request, text=title, attrs=attrs)
|
||||
userlinks.append(homelink)
|
||||
|
||||
# Set pref page to localized Preferences page
|
||||
attrs = self.extendedAttrs(_('My Preferences'), 'u')
|
||||
prefpage = wikiutil.getSysPage(request, 'UserPreferences')
|
||||
title = prefpage.split_title(request)
|
||||
userlinks.append(prefpage.link_to(request, text=title, attrs=attrs))
|
||||
|
||||
# Add a logout link (not sure this is really necessary
|
||||
attrs = self.extendedAttrs(_('log out'), 'o')
|
||||
page = d['page']
|
||||
url = wikiutil.quoteWikinameURL(page.page_name) + \
|
||||
'?action=userform&logout=1'
|
||||
link = wikiutil.link_tag(self.request, url, 'log out', attrs=attrs)
|
||||
userlinks.append(link)
|
||||
|
||||
else:
|
||||
# Add prefpage links with title: Login
|
||||
prefpage = wikiutil.getSysPage(request, 'UserPreferences')
|
||||
attrs = self.extendedAttrs('Logging in is not required, but brings benefits', 'o')
|
||||
userlinks.append(prefpage.link_to(request, text=_("Login"), attrs=attrs))
|
||||
|
||||
html = [
|
||||
u'<div class="portlet" id="p-personal">',
|
||||
u'<ul id="username">',
|
||||
u'<li class="pt-userpage">%s</li></ul>' % '</li>\n<li>'.join(userlinks),
|
||||
u'</ul>',
|
||||
u'</div>'
|
||||
]
|
||||
return ''.join(html)
|
||||
|
||||
def searchform(self, d):
|
||||
""" assemble HTML code for the search form
|
||||
Tweaks from the bass class to wrap in a 'portlet' class, move the
|
||||
description to a header tag, add an access key of 'f' and
|
||||
add SearchButton class for the buttons
|
||||
"""
|
||||
_ = self.request.getText
|
||||
form = self.request.form
|
||||
updates = {
|
||||
'search_label' : _('Search:'),
|
||||
'search_value': wikiutil.escape(form.get('value', [''])[0], 1),
|
||||
'search_full_label' : _('Text', formatted=False),
|
||||
'search_title_label' : _('Titles', formatted=False),
|
||||
}
|
||||
d.update(updates)
|
||||
|
||||
html = u'''
|
||||
<div class="portlet" id="p-search">
|
||||
<h5><label for="searchInput">%(search_label)s</label></h5>
|
||||
<div class="pBody">
|
||||
<form id="searchform" method="get" action="">
|
||||
<div>
|
||||
<input type="hidden" name="action" value="fullsearch">
|
||||
<input type="hidden" name="context" value="180">
|
||||
<input id="searchInput" name="value" type="text" accesskey="f"
|
||||
value="%(search_value)s">
|
||||
<input id="titlesearch" name="titlesearch" type="submit" class="searchButton"
|
||||
value="%(search_title_label)s" alt="Search Titles">
|
||||
<input id="fullsearch" name="fullsearch" type="submit" class="searchButton"
|
||||
value="%(search_full_label)s" alt="Search Full Text">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
''' % d
|
||||
return html
|
||||
|
||||
def shouldShowEditbar(self, page):
|
||||
""" Override to include the editbar on edit/preview pages.
|
||||
(at the risk that the user may accidentally cancel an edit)
|
||||
"""
|
||||
if (page.exists(includeDeleted=1) and
|
||||
self.request.user.may.read(page.page_name)):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def navibar(self, d):
|
||||
""" Alterations from the base class to include access keys and
|
||||
descriptions for FrontPage/RecentChanges
|
||||
"""
|
||||
request = self.request
|
||||
found = {} # pages we found. prevent duplicates
|
||||
links = [] # navibar items
|
||||
current = d['page_name']
|
||||
|
||||
# Process config navi_bar
|
||||
if request.cfg.navi_bar:
|
||||
for text in request.cfg.navi_bar:
|
||||
pagename, link = self.splitNavilink(text)
|
||||
if pagename == d['page_front_page']:
|
||||
attrs = self.extendedAttrs('Visit the main page', 'z')
|
||||
elif pagename == 'RecentChanges':
|
||||
attrs = self.extendedAttrs('List of recent changes in this wiki', 'r')
|
||||
else:
|
||||
attrs = ''
|
||||
|
||||
a = wikiutil.link_tag(request, pagename, attrs=attrs)
|
||||
links.append(a)
|
||||
found[pagename] = 1
|
||||
|
||||
# Add user links to wiki links, eliminating duplicates.
|
||||
userlinks = request.user.getQuickLinks()
|
||||
for text in userlinks:
|
||||
# Split text without localization, user know what she wants
|
||||
pagename, link = self.splitNavilink(text, localize=0)
|
||||
if not pagename in found:
|
||||
a = wikiutil.link_tag(request, pagename, attrs=attrs)
|
||||
links.append(a)
|
||||
found[pagename] = 1
|
||||
|
||||
html = [
|
||||
u'<div class="portlet" id="p-nav">',
|
||||
u'<div class="pBody">',
|
||||
u'<ul id="navibar">',
|
||||
u'<li>%s</li></ul>' % '</li>\n<li>'.join(links),
|
||||
u'</ul>',
|
||||
u'</div>',
|
||||
u'</div>',
|
||||
]
|
||||
return ''.join(html)
|
||||
|
||||
def pageinfo(self, page):
|
||||
""" Simple override from base class.
|
||||
Remove <p> so footer isn't too big
|
||||
"""
|
||||
_ = self.request.getText
|
||||
|
||||
if self.shouldShowPageinfo(page):
|
||||
info = page.lastEditInfo()
|
||||
if info:
|
||||
if info['editor']:
|
||||
info = _("last edited %(time)s by %(editor)s") % info
|
||||
else:
|
||||
info = _("last modified %(time)s") % info
|
||||
return info
|
||||
return ''
|
||||
|
||||
def rtl_stylesheet(self, d):
|
||||
""" monobook uses a separate css page for rtl alterations.
|
||||
Add the rtl stylesheet if the user needs it
|
||||
"""
|
||||
link = ('<link rel="stylesheet" type="text/css" charset="%s"'
|
||||
' media="%s" href="%s">')
|
||||
html = []
|
||||
if i18n.getDirection(self.request.lang) == 'rtl':
|
||||
prefix = self.cfg.url_prefix
|
||||
href = '%s/%s/css/%s.css' % (prefix, self.name, 'rtl')
|
||||
html.append(link % (self.stylesheetsCharset, 'all', href))
|
||||
return '\n'.join(html)
|
||||
|
||||
def html_head(self, d):
|
||||
""" Tweak the sending of the head, to include right-to-left
|
||||
alterations if necessary
|
||||
"""
|
||||
html = [
|
||||
u'<title>%(title)s - %(sitename)s</title>' % d,
|
||||
self.headscript(d), # Should move to separate .js file
|
||||
self.html_stylesheets(d),
|
||||
self.rtl_stylesheet(d),
|
||||
self.rsslink(),
|
||||
]
|
||||
return u' \n'.join(html)
|
||||
|
||||
def html_stylesheets(self, d):
|
||||
"""
|
||||
On fixe le chemin d'acces vers les feuilles de style
|
||||
"""
|
||||
html = []
|
||||
for media, nom in self.stylesheets:
|
||||
html.append(u'<link rel="stylesheet" type="text/css" media="%s" href="/wiki/crans/css/%s.css" />' % (media, nom))
|
||||
return u'\n'.join(html)
|
||||
|
||||
|
||||
class Theme(ThemeCrans):
|
||||
|
||||
name = "crans"
|
||||
|
||||
# Standard set of style sheets
|
||||
stylesheets = (
|
||||
# media basename
|
||||
('all', 'common'),
|
||||
('screen', 'crans'),
|
||||
('print', 'print'),
|
||||
('projection', 'projection'),
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def execute(request):
|
||||
"""
|
||||
Generate and return a theme object
|
||||
|
||||
@param request: the request object
|
||||
@rtype: MoinTheme
|
||||
@return: Theme object
|
||||
"""
|
||||
return Theme(request)
|
24
wiki/theme/ensanime.py
Normal file
24
wiki/theme/ensanime.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
from crans import ThemeCrans
|
||||
|
||||
class Theme(ThemeCrans):
|
||||
|
||||
# Standard set of style sheets
|
||||
stylesheets = (
|
||||
# media basename
|
||||
('all', 'common'),
|
||||
('all', 'common-reverse'),
|
||||
('screen', 'crans'),
|
||||
('screen', 'ensanime'),
|
||||
('print', 'print'),
|
||||
('projection', 'projection'),
|
||||
)
|
||||
|
||||
def execute(request):
|
||||
"""
|
||||
Generate and return a theme object
|
||||
|
||||
@param request: the request object
|
||||
@rtype: MoinTheme
|
||||
@return: Theme object
|
||||
"""
|
||||
return Theme(request)
|
25
wiki/theme/matrix.py
Normal file
25
wiki/theme/matrix.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
MoinMoin technical theme
|
||||
|
||||
@copyright: (c) 2003-2004 by Nir Soffer
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
|
||||
from MoinMoin.theme import modern
|
||||
|
||||
|
||||
class Theme(modern.Theme):
|
||||
|
||||
name = "matrix"
|
||||
|
||||
|
||||
def execute(request):
|
||||
""" Generate and return a theme object
|
||||
|
||||
@param request: the request object
|
||||
@rtype: Theme instance
|
||||
@return: Theme object
|
||||
"""
|
||||
return Theme(request)
|
||||
|
195
wiki/theme/mentalhealth.py
Normal file
195
wiki/theme/mentalhealth.py
Normal file
|
@ -0,0 +1,195 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
Top Matter:
|
||||
MentalHealth is a MoinMoin theme
|
||||
by robin.escalation@ACM.org
|
||||
dated this 20th of April 2005
|
||||
|
||||
let's call it version 0.9
|
||||
and by golly this is GPLed
|
||||
|
||||
Description:
|
||||
It may look something like the standard "rightsidebar" theme.
|
||||
But in reality it is so much better. ;-)
|
||||
|
||||
For example:
|
||||
* smaller type so more fits
|
||||
* very nice colours to soothe the soul
|
||||
* but main page still white background so no clashes
|
||||
* nice alignment, sizes etc.
|
||||
* search form integrated with right panel look
|
||||
* got rid of damn ugly action pulldown menu
|
||||
* no loss of functionality
|
||||
|
||||
Seems to look good but if you have an issue on a browser then
|
||||
let me know.
|
||||
|
||||
Accompanying files:
|
||||
No files changed in folder "img".
|
||||
Only file changed in folder "css" is "screen.css".
|
||||
(Though see next.)
|
||||
|
||||
Skinning the theme:
|
||||
This theme uses four compatible colours, as mentioned in the
|
||||
header "screen.css". If you like you can search'n'replace for
|
||||
those more to your liking. I have a couple of alternate versions
|
||||
of the stylesheet, named screen01.css, screen02.css, etc., just
|
||||
to show how this works. Rename each in tun to screen.css and
|
||||
check it out.
|
||||
|
||||
Installation:
|
||||
* move mentalhealth.py to $python/Lib/site-packages/MoinMoin/theme/
|
||||
* move the mentalhealth folder under $python/share/moin/htdocs/
|
||||
|
||||
And Finally:
|
||||
"Oh we're in love with beauty,
|
||||
We're in love with wealth,
|
||||
We're in love with mental health."
|
||||
-- Julian Cope
|
||||
|
||||
"""
|
||||
|
||||
from MoinMoin.theme import ThemeBase
|
||||
from MoinMoin.wikiutil import link_tag as link
|
||||
from MoinMoin.wikiutil import quoteWikinameURL as quoteURL
|
||||
|
||||
class Theme(ThemeBase):
|
||||
name = "mentalhealth"
|
||||
|
||||
def editbar(self, d):
|
||||
"""
|
||||
Assemble the page edit bar.
|
||||
|
||||
This is rewritten here to get rid of fugly drop-down menu.
|
||||
(Obviating the need for the actionsMenu() method).
|
||||
|
||||
Also I tried to reduce the number of aliases 'cause I find
|
||||
that hard to follow.
|
||||
|
||||
@param d: parameter dictionary
|
||||
@rtype: unicode
|
||||
@return: iconbar html
|
||||
"""
|
||||
# short circuit
|
||||
if not self.shouldShowEditbar(d['page']):
|
||||
return ''
|
||||
|
||||
# initialisations & optimisation
|
||||
_ = self.request.getText
|
||||
page = d['page']
|
||||
cacheKey = 'editbar'
|
||||
quotedname = quoteURL(page.page_name)
|
||||
|
||||
# use cached copy if possible
|
||||
cached = self._cache.get(cacheKey)
|
||||
if cached:
|
||||
return cached
|
||||
|
||||
# each action in this list is a line on the editbar panel
|
||||
links = []
|
||||
|
||||
# parent page
|
||||
parent = page.getParentPage()
|
||||
if parent:
|
||||
links += [parent.link_to(self.request, _("Show Parent", formatted=False))]
|
||||
|
||||
# the rest we will do cleverly :-)
|
||||
# these are the possible actions and their text labels
|
||||
choices = [ ['edit', 'edit'],
|
||||
['diff', 'show changes'],
|
||||
['info', 'get info'],
|
||||
['raw', 'show raw text'],
|
||||
['print', 'show print view'],
|
||||
['refresh', 'delete cache'],
|
||||
['AttachFile', 'attach file'],
|
||||
['SpellCheck', 'check spelling'],
|
||||
['LikePages', 'show like pages'],
|
||||
['LocalSiteMap', 'show local site map'],
|
||||
['RenamePage', 'rename page'],
|
||||
['DeletePage', 'delete page']
|
||||
]
|
||||
|
||||
# determine which actions we can use
|
||||
available = self.request.getAvailableActions(page)
|
||||
for action, label in choices:
|
||||
if action == 'refresh' and not page.canUseCache():
|
||||
continue
|
||||
if action == 'edit' and not (page.isWritable() and self.request.user.may.write(page.page_name)):
|
||||
continue
|
||||
|
||||
if action[0].isupper() and not action in available:
|
||||
continue
|
||||
|
||||
links += [link(self.request, '%s?action=%s' % (quotedname, action),
|
||||
_(label, formatted=False))]
|
||||
|
||||
# we will still delegate this next so I can stop rewriting code
|
||||
links += [self.subscribeLink(page)]
|
||||
|
||||
# wrap it all up nicely
|
||||
html = u'<ul class="editbar">\n%s\n</ul>\n' %\
|
||||
'\n'.join(['<li>%s</li>' % item for item in links if item != ''])
|
||||
|
||||
# cache for next call
|
||||
self._cache[cacheKey] = html
|
||||
return html
|
||||
|
||||
def header(self, d, **kw):
|
||||
"""
|
||||
Assemble page header, which is to say our right-hand panel.
|
||||
|
||||
@param d: parameter dictionary
|
||||
@rtype: string
|
||||
@return: page header html
|
||||
"""
|
||||
_ = self.request.getText
|
||||
|
||||
# there are 5 main panels: each one follows this markup
|
||||
html = u'<div class="sidepanel"><h1>%s</h1>%s</div>'
|
||||
|
||||
# "search" panel hack so I don't have to rewrite searchform()
|
||||
searchpanel = self.searchform(d).replace('<input id="titlesearch"',
|
||||
'<br><input id="titlesearch"')
|
||||
|
||||
# bundle up all our parts
|
||||
parts = [ self.emit_custom_html(self.cfg.page_header1),
|
||||
'<div id="header"></div>',
|
||||
self.emit_custom_html(self.cfg.page_header2),
|
||||
|
||||
u'<div id="sidebar">',
|
||||
html % (_('Search'), searchpanel),
|
||||
html % (_('Navigation'), self.navibar(d)),
|
||||
html % (_('Recent'), self.trail(d)),
|
||||
html % (_('This Page'), self.editbar(d)),
|
||||
html % (_('User'), self.username(d)),
|
||||
self.credits(d),
|
||||
u'</div>',
|
||||
|
||||
self.msg(d),
|
||||
self.startPage(),
|
||||
self.title(d)
|
||||
]
|
||||
return u'\n'.join(parts)
|
||||
|
||||
def footer(self, d, **kw):
|
||||
"""
|
||||
Assemble page footer
|
||||
|
||||
@param d: parameter dictionary
|
||||
@keyword ...:...
|
||||
@rtype: string
|
||||
@return: page footer html
|
||||
"""
|
||||
parts = [ u'<div id="pagebottom"></div>',
|
||||
self.pageinfo(d['page']),
|
||||
self.endPage(),
|
||||
self.emit_custom_html(self.cfg.page_footer1),
|
||||
self.emit_custom_html(self.cfg.page_footer2),
|
||||
]
|
||||
return u'\n'.join(parts)
|
||||
|
||||
def execute(request):
|
||||
"""
|
||||
Generate and return a theme object.
|
||||
"""
|
||||
return Theme(request)
|
444
wiki/theme/monobook.py
Normal file
444
wiki/theme/monobook.py
Normal file
|
@ -0,0 +1,444 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin monobook theme. Uses the css sheet from
|
||||
http://wikipedia.org, adapting the moin output to fit it.
|
||||
|
||||
Adapted by Jim Clark <jim AT clarkster DOT co DOT uk>
|
||||
@license: GNU GPL, see COPYING for details.
|
||||
"""
|
||||
|
||||
from MoinMoin.theme import ThemeBase
|
||||
from MoinMoin import wikiutil, i18n
|
||||
from MoinMoin.Page import Page
|
||||
|
||||
class Theme(ThemeBase):
|
||||
|
||||
name = "monobook"
|
||||
|
||||
# Standard set of style sheets
|
||||
stylesheets = (
|
||||
# media basename
|
||||
('all', 'common'),
|
||||
('screen', 'monobook'),
|
||||
('screen', 'screen'),
|
||||
('print', 'print'),
|
||||
('projection', 'projection'),
|
||||
)
|
||||
|
||||
|
||||
# Public functions #####################################################
|
||||
|
||||
def header(self, d, **kw):
|
||||
""" Assemble wiki header
|
||||
Here we don't add any menu bars, search bars, etc - instead wait
|
||||
until the footer. This keeps the HTML cleaner and more accessible,
|
||||
making sure the main content arrives first.
|
||||
"""
|
||||
html = [
|
||||
u'<div id="globalWrapper">',
|
||||
u'<div id="column-content">',
|
||||
self.startPage(),
|
||||
self.msg(d),
|
||||
self.title(d),
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def footer(self, d, **keywords):
|
||||
""" Assemble wiki footer
|
||||
"""
|
||||
html = [
|
||||
# End of page
|
||||
u'<div class="visualClear"></div>',
|
||||
self.endPage(),
|
||||
u'</div>',
|
||||
self.columnone(d),
|
||||
u'</div>'
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def columnone(self, d):
|
||||
""" assemble all the navigation aids for the page
|
||||
"""
|
||||
page = d['page']
|
||||
html = [
|
||||
u'<div id="column-one">',
|
||||
self.editbar(d),
|
||||
self.username(d),
|
||||
u'<div class="portlet" id="p-logo">',
|
||||
self.logo(),
|
||||
u'</div>',
|
||||
self.navibar(d),
|
||||
self.searchform(d),
|
||||
self.actionmenu(d),
|
||||
u'<div class="visualClear"></div>',
|
||||
u'<div id="footer">',
|
||||
self.pageinfo(page),
|
||||
self.credits(d),
|
||||
u'</div>',
|
||||
u'</div>'
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def headscript(self, d):
|
||||
""" Override to not output search/action menu javascript.
|
||||
(perhaps not a good idea)
|
||||
"""
|
||||
return ''
|
||||
|
||||
def extendedAttrs(self, title, accesskey):
|
||||
""" Helper function for assembling titled access key links
|
||||
"""
|
||||
return 'title="%(title)s [alt-%(accesskey)s]" accesskey=%(accesskey)s' % \
|
||||
{'accesskey' : accesskey,
|
||||
'title' : title}
|
||||
|
||||
def editbar(self, d):
|
||||
""" Display a list of actions for the page. This list will be turned
|
||||
into a set of tabbed views on the page by the css.
|
||||
"""
|
||||
page = d['page']
|
||||
if not self.shouldShowEditbar(page):
|
||||
return ''
|
||||
|
||||
# Use cached editbar if possible.
|
||||
cacheKey = 'editbar'
|
||||
cached = self._cache.get(cacheKey)
|
||||
if cached:
|
||||
return cached
|
||||
|
||||
request = self.request
|
||||
_ = self.request.getText
|
||||
link = wikiutil.link_tag
|
||||
quotedname = wikiutil.quoteWikinameURL(page.page_name)
|
||||
# action, title, description, accesskey
|
||||
tabs = [('show', 'Article', 'View the page content', 'c'),
|
||||
('edit', 'Edit', 'Edit this page', 'e'),
|
||||
('diff', 'Show Changes', 'Last page modification', 'd'),
|
||||
('info', 'Get Info', 'Page history and information', 'h'),
|
||||
('subscribe', 'Subscribe', 'Subscribe to updates to this page', 'w')]
|
||||
|
||||
items = []
|
||||
current = self.request.form.get('action', ['show'])[0]
|
||||
for action, title, description, accesskey in tabs:
|
||||
if action == current:
|
||||
cls = 'selected'
|
||||
else:
|
||||
cls = 'none'
|
||||
|
||||
if action == 'edit':
|
||||
if page.isWritable() and request.user.may.write(page.page_name):
|
||||
pass
|
||||
else:
|
||||
action = 'raw'
|
||||
title = 'View Source'
|
||||
description = 'This page is protected. You can view its source'
|
||||
|
||||
if action == 'subscribe':
|
||||
user = self.request.user
|
||||
if not self.cfg.mail_smarthost or not user.valid:
|
||||
break
|
||||
# Email enabled and user valid, get current page status
|
||||
if user.isSubscribedTo([page.page_name]):
|
||||
title = 'Unsubscribe'
|
||||
description = 'Unsubscribe from updates to this page'
|
||||
|
||||
if action == 'show':
|
||||
url = quotedname
|
||||
else:
|
||||
url = quotedname + '?action=' + action
|
||||
|
||||
attrs = self.extendedAttrs(_(description), accesskey)
|
||||
link = wikiutil.link_tag(self.request, url, _(title), attrs=attrs)
|
||||
items.append(u'<li class="%s">%s</li>' % (cls, link))
|
||||
|
||||
html = [
|
||||
u'<div id="p-cactions" class="portlet">',
|
||||
u'<ul class="editbar">',
|
||||
''.join(items),
|
||||
u'</ul>',
|
||||
u'</div>'
|
||||
]
|
||||
html = ''.join(html)
|
||||
# cache for next call
|
||||
self._cache[cacheKey] = html
|
||||
|
||||
return html
|
||||
|
||||
|
||||
def actionmenu(self, d):
|
||||
""" different implementation of the actionmenu (aka toolbox)
|
||||
"""
|
||||
|
||||
page = d['page']
|
||||
|
||||
# Use cached actionmenu if possible.
|
||||
cacheKey = 'actionmenu'
|
||||
cached = self._cache.get(cacheKey)
|
||||
if cached:
|
||||
return cached
|
||||
|
||||
request = self.request
|
||||
_ = request.getText
|
||||
quotedname = wikiutil.quoteWikinameURL(page.page_name)
|
||||
|
||||
menu = [
|
||||
'raw',
|
||||
'print',
|
||||
'refresh',
|
||||
'AttachFile',
|
||||
'SpellCheck',
|
||||
'LikePages',
|
||||
'LocalSiteMap',
|
||||
'RenamePage',
|
||||
'DeletePage',
|
||||
]
|
||||
|
||||
titles = {
|
||||
'raw': _('Show Raw Text', formatted=False),
|
||||
'print': _('Show Print View', formatted=False),
|
||||
'refresh': _('Delete Cache', formatted=False),
|
||||
'AttachFile': _('Attach File', formatted=False),
|
||||
'SpellCheck': _('Check Spelling', formatted=False), # rename action!
|
||||
'RenamePage': _('Rename Page', formatted=False),
|
||||
'DeletePage': _('Delete Page', formatted=False),
|
||||
'LikePages': _('Show Like Pages', formatted=False),
|
||||
'LocalSiteMap': _('Show Local Site Map', formatted=False),
|
||||
}
|
||||
|
||||
links = []
|
||||
|
||||
# Format standard actions
|
||||
available = request.getAvailableActions(page)
|
||||
for action in menu:
|
||||
# Enable delete cache only if page can use caching
|
||||
if action == 'refresh':
|
||||
if not page.canUseCache():
|
||||
break
|
||||
# Actions which are not available for this wiki, user or page
|
||||
if action[0].isupper() and not action in available:
|
||||
break;
|
||||
|
||||
link = wikiutil.link_tag(self.request, \
|
||||
quotedname + '?action=' + action, titles[action])
|
||||
links.append(link)
|
||||
|
||||
# Add custom actions not in the standard menu
|
||||
more = [item for item in available if not item in titles]
|
||||
more.sort()
|
||||
if more:
|
||||
# Add more actions (all enabled)
|
||||
for action in more:
|
||||
data = {'action': action, 'disabled': ''}
|
||||
title = Page(request, action).split_title(request, force=1)
|
||||
# Use translated version if available
|
||||
title = _(title, formatted=False)
|
||||
link = wikiutil.link_tag(self.request, \
|
||||
quotedname + '?action=' + action, title)
|
||||
links.append(link)
|
||||
|
||||
html = [
|
||||
u'<div class="portlet" id="p-tb">',
|
||||
u'<h5>Toolbox</h5>',
|
||||
u'<div class="pBody">',
|
||||
u'<ul>',
|
||||
u'<li>%s</li></ul>' % '</li>\n<li>'.join(links),
|
||||
u'</ul>',
|
||||
u'</div>',
|
||||
u'</div>',
|
||||
]
|
||||
html = ''.join(html)
|
||||
# cache for next call
|
||||
self._cache[cacheKey] = html
|
||||
return html
|
||||
|
||||
|
||||
def username(self, d):
|
||||
""" Assemble the username / userprefs link
|
||||
Copied from the base class, modified to include hotkeys and link titles
|
||||
"""
|
||||
from MoinMoin.Page import Page
|
||||
request = self.request
|
||||
_ = request.getText
|
||||
|
||||
userlinks = []
|
||||
# Add username/homepage link for registered users. We don't care
|
||||
# if it exists, the user can create it.
|
||||
if request.user.valid:
|
||||
homepage = Page(request, request.user.name)
|
||||
title = homepage.split_title(request)
|
||||
attrs = self.extendedAttrs(_('User Page'), '.')
|
||||
homelink = homepage.link_to(request, text=title, attrs=attrs)
|
||||
userlinks.append(homelink)
|
||||
|
||||
# Set pref page to localized Preferences page
|
||||
attrs = self.extendedAttrs(_('My Preferences'), 'u')
|
||||
prefpage = wikiutil.getSysPage(request, 'UserPreferences')
|
||||
title = prefpage.split_title(request)
|
||||
userlinks.append(prefpage.link_to(request, text=title, attrs=attrs))
|
||||
|
||||
# Add a logout link (not sure this is really necessary
|
||||
attrs = self.extendedAttrs(_('log out'), 'o')
|
||||
page = d['page']
|
||||
url = wikiutil.quoteWikinameURL(page.page_name) + \
|
||||
'?action=userform&logout=1'
|
||||
link = wikiutil.link_tag(self.request, url, 'log out', attrs=attrs)
|
||||
userlinks.append(link)
|
||||
|
||||
else:
|
||||
# Add prefpage links with title: Login
|
||||
prefpage = wikiutil.getSysPage(request, 'UserPreferences')
|
||||
attrs = self.extendedAttrs('Logging in is not required, but brings benefits', 'o')
|
||||
userlinks.append(prefpage.link_to(request, text=_("Login"), attrs=attrs))
|
||||
|
||||
html = [
|
||||
u'<div class="portlet" id="p-personal">',
|
||||
u'<ul id="username">',
|
||||
u'<li class="pt-userpage">%s</li></ul>' % '</li>\n<li>'.join(userlinks),
|
||||
u'</ul>',
|
||||
u'</div>'
|
||||
]
|
||||
return ''.join(html)
|
||||
|
||||
def searchform(self, d):
|
||||
""" assemble HTML code for the search form
|
||||
Tweaks from the bass class to wrap in a 'portlet' class, move the
|
||||
description to a header tag, add an access key of 'f' and
|
||||
add SearchButton class for the buttons
|
||||
"""
|
||||
_ = self.request.getText
|
||||
form = self.request.form
|
||||
updates = {
|
||||
'search_label' : _('Search:'),
|
||||
'search_value': wikiutil.escape(form.get('value', [''])[0], 1),
|
||||
'search_full_label' : _('Text', formatted=False),
|
||||
'search_title_label' : _('Titles', formatted=False),
|
||||
}
|
||||
d.update(updates)
|
||||
|
||||
html = u'''
|
||||
<div class="portlet" id="p-search">
|
||||
<h5><label for="searchInput">%(search_label)s</label></h5>
|
||||
<div class="pBody">
|
||||
<form id="searchform" method="get" action="">
|
||||
<div>
|
||||
<input type="hidden" name="action" value="fullsearch">
|
||||
<input type="hidden" name="context" value="180">
|
||||
<input id="searchInput" name="value" type="text" accesskey="f"
|
||||
value="%(search_value)s">
|
||||
<input id="titlesearch" name="titlesearch" type="submit" class="searchButton"
|
||||
value="%(search_title_label)s" alt="Search Titles">
|
||||
<input id="fullsearch" name="fullsearch" type="submit" class="searchButton"
|
||||
value="%(search_full_label)s" alt="Search Full Text">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
''' % d
|
||||
return html
|
||||
|
||||
def shouldShowEditbar(self, page):
|
||||
""" Override to include the editbar on edit/preview pages.
|
||||
(at the risk that the user may accidentally cancel an edit)
|
||||
"""
|
||||
if (page.exists(includeDeleted=1) and
|
||||
self.request.user.may.read(page.page_name)):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def navibar(self, d):
|
||||
""" Alterations from the base class to include access keys and
|
||||
descriptions for FrontPage/RecentChanges
|
||||
"""
|
||||
request = self.request
|
||||
found = {} # pages we found. prevent duplicates
|
||||
links = [] # navibar items
|
||||
current = d['page_name']
|
||||
|
||||
# Process config navi_bar
|
||||
if request.cfg.navi_bar:
|
||||
for text in request.cfg.navi_bar:
|
||||
pagename, link = self.splitNavilink(text)
|
||||
if pagename == d['page_front_page']:
|
||||
attrs = self.extendedAttrs('Visit the main page', 'z')
|
||||
elif pagename == 'RecentChanges':
|
||||
attrs = self.extendedAttrs('List of recent changes in this wiki', 'r')
|
||||
else:
|
||||
attrs = ''
|
||||
|
||||
a = wikiutil.link_tag(request, pagename, attrs=attrs)
|
||||
links.append(a)
|
||||
found[pagename] = 1
|
||||
|
||||
# Add user links to wiki links, eliminating duplicates.
|
||||
userlinks = request.user.getQuickLinks()
|
||||
for text in userlinks:
|
||||
# Split text without localization, user know what she wants
|
||||
pagename, link = self.splitNavilink(text, localize=0)
|
||||
if not pagename in found:
|
||||
a = wikiutil.link_tag(request, pagename, attrs=attrs)
|
||||
links.append(a)
|
||||
found[pagename] = 1
|
||||
|
||||
html = [
|
||||
u'<div class="portlet" id="p-nav">',
|
||||
u'<div class="pBody">',
|
||||
u'<ul id="navibar">',
|
||||
u'<li>%s</li></ul>' % '</li>\n<li>'.join(links),
|
||||
u'</ul>',
|
||||
u'</div>',
|
||||
u'</div>',
|
||||
]
|
||||
return ''.join(html)
|
||||
|
||||
def pageinfo(self, page):
|
||||
""" Simple override from base class.
|
||||
Remove <p> so footer isn't too big
|
||||
"""
|
||||
_ = self.request.getText
|
||||
|
||||
if self.shouldShowPageinfo(page):
|
||||
info = page.lastEditInfo()
|
||||
if info:
|
||||
if info['editor']:
|
||||
info = _("last edited %(time)s by %(editor)s") % info
|
||||
else:
|
||||
info = _("last modified %(time)s") % info
|
||||
return info
|
||||
return ''
|
||||
|
||||
def rtl_stylesheet(self, d):
|
||||
""" monobook uses a separate css page for rtl alterations.
|
||||
Add the rtl stylesheet if the user needs it
|
||||
"""
|
||||
link = ('<link rel="stylesheet" type="text/css" charset="%s"'
|
||||
' media="%s" href="%s">')
|
||||
html = []
|
||||
if i18n.getDirection(self.request.lang) == 'rtl':
|
||||
prefix = self.cfg.url_prefix
|
||||
href = '%s/%s/css/%s.css' % (prefix, self.name, 'rtl')
|
||||
html.append(link % (self.stylesheetsCharset, 'all', href))
|
||||
return '\n'.join(html)
|
||||
|
||||
def html_head(self, d):
|
||||
""" Tweak the sending of the head, to include right-to-left
|
||||
alterations if necessary
|
||||
"""
|
||||
html = [
|
||||
u'<title>%(title)s - %(sitename)s</title>' % d,
|
||||
self.headscript(d), # Should move to separate .js file
|
||||
self.html_stylesheets(d),
|
||||
self.rtl_stylesheet(d),
|
||||
self.rsslink(),
|
||||
]
|
||||
return '\n'.join(html)
|
||||
|
||||
def execute(request):
|
||||
"""
|
||||
Generate and return a theme object
|
||||
|
||||
@param request: the request object
|
||||
@rtype: MoinTheme
|
||||
@return: Theme object
|
||||
"""
|
||||
return Theme(request)
|
33
wiki/theme/movieclub.py
Normal file
33
wiki/theme/movieclub.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
Theme Movieclub, sous classe de Crans.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
from crans import ThemeCrans
|
||||
|
||||
class Theme(ThemeCrans):
|
||||
|
||||
|
||||
# Standard set of style sheets
|
||||
stylesheets = (
|
||||
# media basename
|
||||
('all', 'common'),
|
||||
('all', 'common-reverse'),
|
||||
('all', 'common-movieclub'),
|
||||
('screen', 'crans'),
|
||||
('screen', 'movieclub'),
|
||||
('print', 'print'),
|
||||
('projection', 'projection'),
|
||||
)
|
||||
|
||||
def execute(request):
|
||||
"""
|
||||
Generate and return a theme object
|
||||
|
||||
@param request: the request object
|
||||
@rtype: MoinTheme
|
||||
@return: Theme object
|
||||
"""
|
||||
return Theme(request)
|
131
wiki/theme/rightsidebarsmaller.py
Normal file
131
wiki/theme/rightsidebarsmaller.py
Normal file
|
@ -0,0 +1,131 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
MoinMoin theme by and for crw.
|
||||
"""
|
||||
|
||||
from MoinMoin import wikiutil
|
||||
from MoinMoin.Page import Page
|
||||
from MoinMoin.theme import ThemeBase
|
||||
|
||||
class Theme(ThemeBase):
|
||||
""" here are the functions generating the html responsible for
|
||||
the look and feel of your wiki site
|
||||
"""
|
||||
|
||||
name = "rightsidebarsmaller"
|
||||
|
||||
def wikipanel(self, d):
|
||||
""" Create wiki panel """
|
||||
_ = self.request.getText
|
||||
html = [
|
||||
u'<div class="sidepanel">',
|
||||
u'<h1>%s</h1>' % _("Navigation"),
|
||||
self.navibar(d),
|
||||
u'</div>',
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def pagepanel(self, d):
|
||||
""" Create page panel """
|
||||
_ = self.request.getText
|
||||
if self.shouldShowEditbar(d['page']):
|
||||
html = [
|
||||
u'<div class="sidepanel">',
|
||||
u'<h1>%s</h1>' % _("Page"),
|
||||
self.editbar(d),
|
||||
u'</div>',
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
return ''
|
||||
|
||||
def userpanel(self, d):
|
||||
""" Create user panel """
|
||||
_ = self.request.getText
|
||||
|
||||
trail = self.trail(d)
|
||||
if trail:
|
||||
trail = u'<h2>%s</h2>\n' % _("Recently viewed pages") + trail
|
||||
|
||||
html = [
|
||||
u'<div class="sidepanel">',
|
||||
u'<h1>%s</h1>' % _("User"),
|
||||
self.username(d),
|
||||
trail,
|
||||
u'</div>'
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def header(self, d):
|
||||
"""
|
||||
Assemble page header
|
||||
|
||||
@param d: parameter dictionary
|
||||
@rtype: string
|
||||
@return: page header html
|
||||
"""
|
||||
_ = self.request.getText
|
||||
|
||||
html = [
|
||||
# Custom html above header
|
||||
self.emit_custom_html(self.cfg.page_header1),
|
||||
|
||||
# Hedar
|
||||
u'<div id="header">',
|
||||
self.searchform(d),
|
||||
self.logo(),
|
||||
u'</div>',
|
||||
|
||||
# Custom html below header (not recomended!)
|
||||
self.emit_custom_html(self.cfg.page_header2),
|
||||
|
||||
# Sidebar
|
||||
u'<div id="sidebar">',
|
||||
self.wikipanel(d),
|
||||
self.pagepanel(d),
|
||||
self.userpanel(d),
|
||||
self.credits(d),
|
||||
u'</div>',
|
||||
|
||||
self.msg(d),
|
||||
|
||||
# Page
|
||||
self.startPage(),
|
||||
self.title(d),
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def footer(self, d, **keywords):
|
||||
""" Assemble page footer
|
||||
|
||||
@param d: parameter dictionary
|
||||
@keyword ...:...
|
||||
@rtype: string
|
||||
@return: page footer html
|
||||
"""
|
||||
page = d['page']
|
||||
html = [
|
||||
# Page end
|
||||
# Used to extend the page to the bottom of the sidebar
|
||||
u'<div id="pagebottom"></div>',
|
||||
self.pageinfo(page),
|
||||
self.endPage(),
|
||||
|
||||
# Custom html above footer
|
||||
self.emit_custom_html(self.cfg.page_footer1),
|
||||
|
||||
# And bellow
|
||||
self.emit_custom_html(self.cfg.page_footer2),
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
|
||||
def execute(request):
|
||||
"""
|
||||
Generate and return a theme object
|
||||
|
||||
@param request: the request object
|
||||
@rtype: MoinTheme
|
||||
@return: Theme object
|
||||
"""
|
||||
return Theme(request)
|
||||
|
230
wiki/theme/sinorca4moin.py
Normal file
230
wiki/theme/sinorca4moin.py
Normal file
|
@ -0,0 +1,230 @@
|
|||
# -*- coding: iso-8859-1 -*-
|
||||
"""MoinMoin theme "sinorca4moin" by David Linke.
|
||||
|
||||
Credits to "Haran" who published his sinorca-design at www.oswd.org
|
||||
"""
|
||||
|
||||
from MoinMoin import wikiutil
|
||||
from MoinMoin.Page import Page
|
||||
from MoinMoin.theme import ThemeBase
|
||||
|
||||
class Theme(ThemeBase):
|
||||
""" here are the functions generating the html responsible for
|
||||
the look and feel of your wiki site
|
||||
"""
|
||||
|
||||
name = "sinorca4moin"
|
||||
|
||||
def iconbar(self, d):
|
||||
"""
|
||||
Assemble the iconbar
|
||||
|
||||
@param d: parameter dictionary
|
||||
@rtype: string
|
||||
@return: iconbar html
|
||||
"""
|
||||
iconbar = []
|
||||
if self.cfg.page_iconbar and self.request.user.show_toolbar and d['page_name']:
|
||||
iconbar.append('<ul id="iconbar">\n')
|
||||
icons = self.cfg.page_iconbar[:]
|
||||
for icon in icons:
|
||||
if icon == "up":
|
||||
if d['page_parent_page']:
|
||||
iconbar.append('<li>%s</li>\n' % self.make_iconlink(icon, d))
|
||||
elif icon == "subscribe":
|
||||
iconbar.append('<li>%s</li>\n' % self.make_iconlink(
|
||||
["subscribe", "unsubscribe"][self.request.user.isSubscribedTo([d['page_name']])], d))
|
||||
elif icon == "home":
|
||||
if d['page_home_page']:
|
||||
iconbar.append('<li>%s</li>\n' % self.make_iconlink(icon, d))
|
||||
else:
|
||||
iconbar.append('<li>%s</li>\n' % self.make_iconlink(icon, d))
|
||||
iconbar.append('</ul>\n')
|
||||
return ''.join(iconbar)
|
||||
|
||||
def editbar(self, d):
|
||||
""" Assemble the page edit bar.
|
||||
|
||||
Display on existing page. Replace iconbar, showtext, edit text,
|
||||
refresh cache and available actions.
|
||||
|
||||
@param d: parameter dictionary
|
||||
@rtype: unicode
|
||||
@return: iconbar html
|
||||
"""
|
||||
page = d['page']
|
||||
if not self.shouldShowEditbar(page):
|
||||
return ''
|
||||
|
||||
# Use cached editbar if possible.
|
||||
cacheKey = 'editbar'
|
||||
cached = self._cache.get(cacheKey)
|
||||
if cached:
|
||||
return cached
|
||||
|
||||
# Make new edit bar
|
||||
request = self.request
|
||||
_ = self.request.getText
|
||||
link = wikiutil.link_tag
|
||||
quotedname = wikiutil.quoteWikinameURL(page.page_name)
|
||||
links = []
|
||||
add = links.append
|
||||
|
||||
# Parent page
|
||||
#parent = page.getParentPage()
|
||||
#if parent:
|
||||
# add(parent.link_to(request, _("Show Parent", formatted=False)))
|
||||
|
||||
# Page actions
|
||||
if page.isWritable() and request.user.may.write(page.page_name):
|
||||
add(link(request, quotedname + '?action=edit', _('Edit')))
|
||||
else:
|
||||
add(_('Immutable Page', formatted=False))
|
||||
|
||||
add(link(request, quotedname + '?action=info',
|
||||
_('Get Info', formatted=False)))
|
||||
add(self.actionsMenu(page))
|
||||
|
||||
# Format
|
||||
items = '\n'.join(['<li>%s</li>' % item for item in links if item != ''])
|
||||
html = u'<ul class="editbar">\n%s\n</ul>\n' % items
|
||||
|
||||
# cache for next call
|
||||
self._cache[cacheKey] = html
|
||||
return html
|
||||
|
||||
def wikipanel(self, d):
|
||||
""" Create wiki panel """
|
||||
_ = self.request.getText
|
||||
html = [
|
||||
u'<div class="sidepanel">',
|
||||
u' <p class="sideBarTitle">%s</p>' % _("Wiki"),
|
||||
self.navibar(d),
|
||||
u'</div>',
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def pagepanel(self, d):
|
||||
""" Create page panel """
|
||||
_ = self.request.getText
|
||||
if self.shouldShowEditbar(d['page']):
|
||||
html = [
|
||||
u'<div class="sidepanel">',
|
||||
u' <p class="sideBarTitle">%s</p>' % _("Page"),
|
||||
self.editbar(d),
|
||||
u'</div>',
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
return ''
|
||||
|
||||
def userpanel(self, d):
|
||||
""" Create user panel """
|
||||
_ = self.request.getText
|
||||
|
||||
html = [
|
||||
u'<div class="sidepanel">',
|
||||
u' <p class="sideBarTitle">%s</p>' % _("User"),
|
||||
self.username(d),
|
||||
u'</div>'
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def logo(self):
|
||||
""" Assemble logo with link to front page
|
||||
|
||||
adds h1-tags for sinorca
|
||||
"""
|
||||
if self.cfg.logo_string:
|
||||
pagename = wikiutil.getFrontPage(self.request).page_name
|
||||
pagename = wikiutil.quoteWikinameURL(pagename)
|
||||
logo = wikiutil.link_tag(self.request, pagename, self.cfg.logo_string)
|
||||
html = u'''<div id="logo"> <h1 class="headerTitle">%s</h1></div>''' % logo
|
||||
return html
|
||||
return u''
|
||||
|
||||
def header(self, d):
|
||||
"""
|
||||
Assemble page header
|
||||
|
||||
@param d: parameter dictionary
|
||||
@rtype: string
|
||||
@return: page header html
|
||||
"""
|
||||
_ = self.request.getText
|
||||
|
||||
trail = self.trail(d)
|
||||
|
||||
html = [
|
||||
# Header
|
||||
u'<div id="header">',
|
||||
# Custom html super-header
|
||||
self.emit_custom_html(self.cfg.page_header1),
|
||||
u' <div class="midHeader">',
|
||||
self.logo(),
|
||||
u' </div>',
|
||||
# Custom html below header (not recomended!)
|
||||
self.emit_custom_html(self.cfg.page_header2),
|
||||
trail,
|
||||
u'</div>',
|
||||
|
||||
# Iconbar
|
||||
self.iconbar(d),
|
||||
|
||||
# Sidebar
|
||||
u'<!-- ##### Side Bar ##### -->',
|
||||
u'<div id="sidebar">',
|
||||
|
||||
u'<div class="sidepanel">',
|
||||
u' <p class="sideBarTitle">Search in %s</p>' % _(self.cfg.sitename),
|
||||
self.searchform(d),
|
||||
u'</div>',
|
||||
|
||||
self.wikipanel(d),
|
||||
self.pagepanel(d),
|
||||
self.userpanel(d),
|
||||
self.credits(d),
|
||||
u'</div>',
|
||||
|
||||
self.msg(d),
|
||||
|
||||
# Page
|
||||
self.startPage(),
|
||||
self.title(d),
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
def footer(self, d, **keywords):
|
||||
""" Assemble page footer
|
||||
|
||||
@param d: parameter dictionary
|
||||
@keyword ...:...
|
||||
@rtype: string
|
||||
@return: page footer html
|
||||
"""
|
||||
page = d['page']
|
||||
html = [
|
||||
# Page end
|
||||
# Used to extend the page to the bottom of the sidebar
|
||||
u'<div id="pagebottom"></div>',
|
||||
self.pageinfo(page),
|
||||
self.endPage(),
|
||||
|
||||
# Custom html above footer
|
||||
self.emit_custom_html(self.cfg.page_footer1),
|
||||
|
||||
# And bellow
|
||||
self.emit_custom_html(self.cfg.page_footer2),
|
||||
]
|
||||
return u'\n'.join(html)
|
||||
|
||||
|
||||
def execute(request):
|
||||
"""
|
||||
Generate and return a theme object
|
||||
|
||||
@param request: the request object
|
||||
@rtype: MoinTheme
|
||||
@return: Theme object
|
||||
"""
|
||||
return Theme(request)
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue