Imports initiaux

darcs-hash:20060416092713-72cb0-421d3cbb49699fce4971355f5dbbaa19091945e8.gz
This commit is contained in:
salles 2006-04-16 11:27:13 +02:00
parent 0192d9e074
commit 1e7ce4861e
7 changed files with 1645 additions and 0 deletions

688
wiki/macro/Gallery.py Normal file
View file

@ -0,0 +1,688 @@
# -*- coding: iso-8859-1 -*-
"""
Gallery.py Version 0.86
This macro creates dynamic tabulated displays based on attachment contents
@copyright: 2004,2005 by Simon Ryan <simon<at>smartblackbox.com> http://smartblackbox.com/simon
@license: GPL
Special thanks go to:
My beautiful wife Jenny: For keeping the kids at bay long enough for me to code it :-)
Adam Shand: For his GallerySoftware feature wish list, support, ideas and suggestions.
Usage: [[Gallery(key1=value1,key2=value2....)]]
where the following keys are valid:
thumbnailwidth = no of pixels wide to make the thumbnails
webnailwidth = width in pixels of the web sized images
numberofcolumns = no of columns used in the thumbnail table
Bugs:
Continued rotation will degrade the tmp images (but they can be forced to regen)
Features:
Simple usage, just put [[Gallery]] on any page and upload some pictures as attachments
Rotate buttons
Annotation
Should work with MoinMoin versions 1.2.x and 1.3.x
Support for Python Imaging Library
Works with FastCGI mode
Not yet implemented:
Handling of video formats
Speed up:
# When you get really sick of how slow the moinmoin image system is,
# you can either reconfigure your setup for FastCGI (highly recommended)
# or: set the following variables in your wikiconfig.py
gallerytempdir (the path to a writable directory)
gallerytempurl (the path in your webservers url space where this directory can be read from)
eg:
gallerytempdir='/var/www/html/nails'
gallerytempurl='/nails'
or maybe:
gallerytempurl=url_prefix+'/nails'
# There are other ways of getting speedups for attachments, but these methods are the safest (IMHO)
"""
__author__ = "Simon D. Ryan"
__version__ = "0.86"
from MoinMoin import config, wikiutil
import string, cStringIO, os
import commands, shutil
from random import randint
try:
import Image
except:
pass
class Globs:
# A quick place to plonk those shared variables
thumbnailwidth='200'
webnailwidth='600'
numberofcolumns=4
adminmsg=''
debuglevel=0
originals={}
convertbin=''
annotated={}
attachmentdir=''
gallerytempdirroot=''
gallerytempdir=''
gallerytempurl=''
galleryrotchar=''
pagename=''
admin=''
bcomp=''
baseurl=''
timeout=40
allowedextensions=['jpg','jpeg','png','bmp','tiff','gif']
def message(astring,level=1):
if level<=Globs.debuglevel:
Globs.adminmsg=Globs.adminmsg+'<font color="#FF0000"><strong>Gallery</strong></font>:&nbsp;&nbsp;'+astring+'<br>\n'
def version():
return(' version <b>'+Globs.version+'</b> by Simon D. Ryan.'+\
'<br>Copyright 2004,2005 Simon D. Ryan<br>Gallery is a MoinMoin macro and is released under the '+\
'<a href="http://www.gnu.org/licenses/gpl.txt">GPL</a>\n'+\
'<p>Upload some images as attachments to <a href="'+Globs.baseurl+Globs.pagename+'?action=AttachFile"><b>'+Globs.pagename+'</b></a> and I will generate a gallery for you.')
# Thanks to denny<at>ece.arizona.edu
# This can be replaced with a static translation table to speed things up (later)
def mktrans():
# Allow only letters and digits and a few other valid file characters
alphanumeric=string.letters+string.digits+'.,-_\'!"'
source_string=""
destination_string=""
for i in range(256):
source_string=source_string+chr(i)
if chr(i) in alphanumeric:
destination_string=destination_string+chr(i)
else:
destination_string=destination_string+' '
return string.maketrans(source_string,destination_string)
def qlink(pagename, querystring, query, description=''):
# Returns a hyperlink constructed as a form query on pagename
if not description:
description=query
return '<a href="'+Globs.baseurl+pagename+'?'+querystring+'='+query+Globs.bcomp+'">'+description+'</a>'
def navibar(target,querystring):
# Returns a navigational bar with PREV,THUMBS,NEXT
positions=Globs.originals.keys()
positions.sort()
thumbs='<a href="'+Globs.subname+'">THUMBS</a>'
index=positions.index(target)
back,forward='',''
if not index==0:
# We are not the first so we can provide a back link
back=qlink(Globs.pagename, querystring, positions[index-1], 'PREV')
if not index==len(positions)-1:
# We are not the last so we can provide a forward link
forward=qlink(Globs.pagename, querystring, positions[index+1], 'NEXT')
return '<table><tr><td>'+back+'</td><td>'+thumbs+'</td><td>'+forward+'</td></tr></table>'
def toolbar(target,naillevel):
if Globs.admin:
rotateleft='<input type="submit" name="rotate" value="rotate left">'
rotateright='<input type="submit" name="rotate" value="rotate right">'
htarget='<input type=hidden value="'+target+'" name="'+naillevel+'">'
compat='<input type=hidden value="show" name="action">'
return '<form METHOD=POST><table><tr><td>'+rotateleft+'</td><td>'+rotateright+'</td></tr></table>\n'+htarget+compat+'</form>'
else:
return ''
def buildnails(items):
# For now we use commands.getoutput to do our dirty work
# Later we can build a batch job and fork it off.
# Make sure our temp directory is writable and generate a message if it isn't
try:
if not os.path.isfile(Globs.gallerytempdir+'/tmp.writetest'):
# There is probably a less ugly was to do this using stat (later)
open(Globs.gallerytempdir+'/tmp.writetest','w').close()
except IOError:
message('I had some trouble writing to the temp directory. Is it owned by me and writable?',0)
# Don't go further if there is a lock in place
if os.path.isfile(Globs.attachmentdir+'/tmp.lock'):
message("I'm currently busy generating thumbnails and webnails, please try again later.",0)
return ''
# Find the convert binary in standard locations
if not globals().has_key('Image'):
if not os.path.isfile('/usr/bin/convert'):
if not os.path.isfile('/usr/X11R6/bin/convert'):
message('<b>Please install ImageMagick or PIL so I can build thumbnails and webnails</b><p>',0)
return
else:
Globs.convertbin='/usr/X11R6/bin/convert'
else:
Globs.convertbin='/usr/bin/convert'
else:
# Use Python Imaging Library
Globs.convertbin='Image'
# Create a lock file in the attachments dir so we can always remotely remove it if there is a problem
open(Globs.attachmentdir+'/tmp.lock','w').close()
import time
tstart=time.time()
pid,pid2='',''
# For each original file, check for the existance of a nail
for item in items:
basename,prefix,width=item
# Check to see if we tarry too long on the road
if tstart and (time.time()-tstart) > Globs.timeout:
# This is taking waaay too long let us fork and detach else the browser will time out or worse, the webserver may kill us
pid = os.fork()
if pid != 0:
# We are in the parent so we break out
message('The thumbnail generation process was taking too long so it has been backgrounded. Please try again later to see the full set of thumbnails',0)
break
else:
# Once we are forked we want to ignore the time
tstart=''
# Break away from the controlling terminal, so that the web server cannot kill us by killing our parent
os.setsid()
# Fork again so we can get away without a controlling terminal
pid2 = os.fork()
if (pid2 != 0):
os._exit(0)
else:
# Close all open file descriptors
try:
max_fd = os.sysconf("SC_OPEN_MAX")
except (AttributeError, ValueError):
max_fd = 256
for fd in range(0, max_fd):
try:
os.close(fd)
except OSError:
pass
# Redirect the standard file descriptors to /dev/null
os.open("/dev/null", os.O_RDONLY) # stdin
os.open("/dev/null", os.O_RDWR) # stdout
os.open("/dev/null", os.O_RDWR) # stderr
# Now we are finally free to continue the conversions as a daemon
# If you would like to know more about the above, see:
# Advanced Programming in the Unix Environment: W. Richard Stevens
# It is also explained in:
# Unix Network Programming (Volume 1): W. Richard Stevens
#pathtooriginal='"'+Globs.attachmentdir+'/'+Globs.originals[basename]+'"'
pathtooriginal='"'+os.path.join(Globs.attachmentdir,Globs.originals[basename])+'"'
# Warning:
# Take care if modifying the following line,
# you may inadvertantly overwrite your original images!
if not Globs.convertbin == 'Image':
#print 'building nail for '+pathtooriginal
#convout=commands.getoutput('%s -geometry %s \"%s\" "\"%s/%s.%s.jpg\""' % (Globs.convertbin,width+'x'+width,pathtooriginal,Globs.gallerytempdir,prefix,basename))
convout=commands.getoutput('%s -geometry %s %s "%s/%s.%s.jpg"' % (Globs.convertbin,width+'x'+width,pathtooriginal,Globs.gallerytempdir,prefix,basename))
convout=''
convout=string.strip(convout)
if convout:
message(convout)
else:
# Use PIL (strip off the "")
im = Image.open(pathtooriginal[1:-1])
# Use the integer version for PIL
width=string.atoi(width)
im.thumbnail((width,width), Image.ANTIALIAS)
im.save(os.path.join(Globs.gallerytempdir,prefix)+'.'+basename+'.jpg','JPEG')
if (not pid) and (not pid2):
# Release the lock file when finished
os.unlink(Globs.attachmentdir+'/tmp.lock')
# We have built thumbnails so we can deposit an indicator file to prevent rebuilding next time
if not os.path.isfile(Globs.attachmentdir+'/delete.me.to.regenerate.thumbnails.and.webnails'):
open(Globs.attachmentdir+'/delete.me.to.regenerate.thumbnails.and.webnails','w').close()
def rotate(target,direction):
# Rotate the images
# Don't go further if there is a lock in place
if os.path.isfile(Globs.attachmentdir+'/tmp.lock'):
message("I'm currently busy generating thumbnails and webnails. Please try your rotate request again later.",0)
return ''
# Find the correct binary
if not globals().has_key('Image'):
if not os.path.isfile('/usr/bin/mogrify'):
if not os.path.isfile('/usr/X11R6/bin/mogrify'):
message('<b>Please install ImageMagick so I can build thumbnails and webnails</b><p>',0)
return
else:
Globs.convertbin='/usr/X11R6/bin/mogrify'
else:
Globs.convertbin='/usr/bin/mogrify'
else:
Globs.convertbin = 'Image'
# Do the actual rotations
if direction=='rotate right':
degs='90'
else:
degs='270'
if not Globs.convertbin == 'Image':
convout=commands.getoutput(Globs.convertbin+' -rotate '+degs+' "'+Globs.gallerytempdir+'/tmp.webnail.'+target+'.jpg"')
convout=commands.getoutput(Globs.convertbin+' -rotate '+degs+' "'+Globs.gallerytempdir+'/tmp.thumbnail.'+target+'.jpg"')
if not os.path.isfile(Globs.gallerytempdir+'/tmp.rotated.'+target+'.jpg'):
# Generate from original
pathtooriginal=Globs.attachmentdir+'/'+Globs.originals[target]
shutil.copy(pathtooriginal,Globs.gallerytempdir+'/tmp.rotated.'+target+'.jpg')
convout=commands.getoutput(Globs.convertbin+' -rotate '+degs+' "'+Globs.gallerytempdir+'/tmp.rotated.'+target+'.jpg"')
else:
# Use PIL (strip off the "")
if direction=='rotate right':
degs=270.0
else:
degs=90.0
im = os.path.join(Globs.gallerytempdir,'tmp.webnail.')+target+'.jpg'
imw = Image.open(im)
imw.rotate(degs).save(im,'JPEG')
im = os.path.join(Globs.gallerytempdir,'tmp.thumbnail.')+target+'.jpg'
imw = Image.open(im)
imw.rotate(degs).save(im,'JPEG')
imo = os.path.join(Globs.gallerytempdir,'tmp.rotated.')+target+'.jpg'
if not os.path.isfile(Globs.gallerytempdir+'/tmp.rotated.'+target+'.jpg'):
# Generate from original
im=Globs.attachmentdir+'/'+Globs.originals[target]
else:
im = imo
imw = Image.open(im)
imw.rotate(degs).save(imo,'JPEG')
def getannotation(target):
# Annotations are stored as a file for now (later to be stored in images)
atext=''
if Globs.annotated.has_key(target):
atext=open(Globs.attachmentdir+'/tmp.annotation.'+target+'.txt').readline()
message('was annotated')
else:
message('was not annotated')
# replace double quotes with the html escape so quoted annotations appear
return string.replace(atext,'"','&quot;')
def execute(macro, args):
Globs.version=__version__
# Containers
formvals={}
thumbnails={}
webnails={}
rotated={}
try:
import wikiconfig
except:
wikiconfig=''
# Class variables need to be specifically set
# (except for the case where a value is to be shared with another Gallery macro on the same wiki page)
Globs.originals={}
Globs.annotated={}
Globs.attachmentdir=''
Globs.admin=''
Globs.adminmsg=''
Globs.pagename=''
# process arguments
if args:
# Arguments are comma delimited key=value pairs
sargs=string.split(args,',')
for item in sargs:
sitem=string.split(item,'=')
if len(sitem)==2:
key,value=sitem[0],sitem[1]
if key=='thumbnailwidth':
Globs.thumbnailwidth=value
elif key=='webnailwidth':
Globs.webnailwidth=value
elif key=='numberofcolumns':
try:
Globs.numberofcolumns=string.atoi(value)
except TypeError:
pass
# Experimental, uncomment at own risk
#elif key=='pagename':
# Globs.pagename=value
transtable=mktrans()
# Useful variables
dontregen=''
annotationmessage=''
Globs.baseurl=macro.request.getBaseURL()+'/'
if not Globs.pagename:
#Globs.pagename = string.replace(macro.formatter.page.page_name,'/','_2f')
Globs.pagename = macro.formatter.page.page_name
# This fixes the subpages bug. subname is now used instead of pagename when creating certain urls
Globs.subname = string.split(Globs.pagename,'/')[-1]
# Hmmm. A bug in moinmoin? underscores are getting escaped. These doubly escaped pagenames are even appearing in data/pages
try:
# Try the old MoinMoin-1.2.x way first
textdir=config.text_dir
pagepath = string.replace(wikiutil.getPagePath(Globs.pagename),'_5f','_')
except:
pagepath = macro.formatter.page.getPagePath()
Globs.attachmentdir = pagepath+'/attachments'
Globs.galleryrotchar='?'
if hasattr(macro,'cfg') and hasattr(macro.cfg,'gallerytempdir') and hasattr(macro.cfg,'gallerytempurl'):
Globs.gallerytempdirroot=macro.cfg.gallerytempdir
Globs.gallerytempdir=macro.cfg.gallerytempdir+'/'+Globs.pagename+'/'
Globs.gallerytempurl=macro.cfg.gallerytempurl+'/'+Globs.pagename+'/'
elif hasattr(wikiconfig,'gallerytempdir') and hasattr(wikiconfig,'gallerytempurl'):
message('gallerytempdir and gallerytempurl found')
Globs.gallerytempdirroot=wikiconfig.gallerytempdir
Globs.gallerytempdir=wikiconfig.gallerytempdir+'/'+Globs.pagename+'/'
Globs.gallerytempurl=wikiconfig.gallerytempurl+'/'+Globs.pagename+'/'
elif hasattr(wikiconfig,'attachments'):
Globs.gallerytempdirroot=wikiconfig.attachments['dir']
Globs.gallerytempdir=wikiconfig.attachments['dir']+'/'+Globs.pagename+'/attachments/'
Globs.gallerytempurl=wikiconfig.attachments['url']+'/'+Globs.pagename+'/attachments/'
Globs.attachmentdir = Globs.gallerytempdir
else:
Globs.gallerytempdir=Globs.attachmentdir
Globs.gallerytempurl=Globs.subname+'?action=AttachFile&amp;do=get&amp;target='
# MoinMoin no longer allows us to use a ? to trigger a refetch, so we pass it a &
Globs.galleryrotchar='&'
if args:
args=macro.request.getText(args)
# HTML Constants
tleft='<table><tr><td><center>'
tmidd='</center></td><td><center>'
trigh='</center></td></tr></table>\n'
# Add this to the end of each URL to keep some versions of moinmoin happy
Globs.bcomp='&action=show'
# Process any form items into a dictionary (values become unique)
for item in macro.form.items():
if not formvals.has_key(item[0]):
# Here is where we clean the untrusted web input
# (sometimes we get foreign keys from moinmoin when the page is edited)
try:
formvals[item[0]]=string.translate(item[1][0],transtable)
except AttributeError:
pass
# Figure out if we have delete privs
try:
# If a user can delete the page containing the Gallery, then they are considered a Gallery administrator
# This probably should be configurable via a wikiconfig variable eg: galleryadminreq = <admin|delete|any>
if macro.request.user.may.delete(macro.formatter.page.page_name):
Globs.admin='true'
except AttributeError:
pass
out=cStringIO.StringIO()
# Grab a list of the files in the attachment directory
if os.path.isdir(Globs.attachmentdir):
if Globs.gallerytempdir==Globs.attachmentdir:
afiles=os.listdir(Globs.attachmentdir)
else:
if not os.path.isdir(Globs.gallerytempdirroot):
message('You need to create the temp dir first:'+Globs.gallerytempdirroot,0)
return macro.formatter.rawHTML(
Globs.adminmsg+'<p>')
if not os.path.isdir(Globs.gallerytempdir):
# Try to create it if it is absent
spagename=string.split(Globs.pagename,'/')
compbit=''
for component in spagename:
compbit=compbit+'/'+component
try:
os.mkdir(Globs.gallerytempdirroot+compbit)
except:
message('Please check permissions on temp dir:'+Globs.gallerytempdirroot,0)
return macro.formatter.rawHTML(
Globs.adminmsg+'<p>')
if os.path.isdir(Globs.gallerytempdir):
afiles=os.listdir(Globs.attachmentdir)+os.listdir(Globs.gallerytempdir)
else:
message('You need to create the temp dir first:'+Globs.gallerytempdir,0)
return macro.formatter.rawHTML(
Globs.adminmsg+'<p>')
# Split out the thumbnails and webnails
for item in afiles:
if item.startswith('tmp.thumbnail.'):
origname=item[14:-4]
thumbnails[origname]=''
elif item.startswith('tmp.webnail.'):
origname=item[12:-4]
webnails[origname]=''
elif item.startswith('tmp.rotated.'):
origname=item[12:-4]
rotated[origname]=''
elif item.startswith('tmp.annotation.'):
origname=item[15:-4]
Globs.annotated[origname]=''
elif item == 'delete.me.to.regenerate.thumbnails.and.webnails':
dontregen='true'
elif item == 'tmp.writetest' or item == 'tmp.lock':
pass
else:
# This must be one of the original images
lastdot=string.rfind(item,'.')
origname=item[:lastdot]
ext = item[lastdot+1:]
if string.lower(ext) not in Globs.allowedextensions:
continue
Globs.originals[origname]=item
else:
message(version(),0)
return macro.formatter.rawHTML( Globs.adminmsg )
if not Globs.gallerytempdir==Globs.attachmentdir and os.path.isfile(Globs.attachmentdir+'/tmp.writetest'):
# If we are using the new gallerytempdir and we were using the old system then make sure there are no
# remnant files from the old system in the attachment dir to confuse us
message('You have changed to using a gallerytempdir so I am cleaning old tmp files from your attachment dir.',0)
for item in webnails.keys():
try:
os.unlink(Globs.attachmentdir+'/tmp.webnail.'+item+'.jpg')
except:
pass
# Try deleting any old thumbnails which may be in the attachment directory
for item in thumbnails.keys():
try:
os.unlink(Globs.attachmentdir+'/tmp.thumbnail.'+item+'.jpg')
except:
pass
# Try deleting any old rotated originals which may be in the attachment directory
for item in rotated.keys():
try:
os.unlink(Globs.attachmentdir+'/tmp.rotated.'+item+'.jpg')
except:
pass
os.unlink(Globs.attachmentdir+'/tmp.writetest')
newnails=[]
# Any thumbnails need to be built?
for key in Globs.originals.keys():
if (not thumbnails.has_key(key)) or (not dontregen):
# Create a thumbnail for this original
newnails.append((key,'tmp.thumbnail',Globs.thumbnailwidth))
# Any webnails need to be built?
for key in Globs.originals.keys():
if (not webnails.has_key(key)) or (not dontregen):
# Create a webnail for this original
newnails.append((key,'tmp.webnail',Globs.webnailwidth))
# Ok, lets build them all at once
if not len(newnails)==0:
buildnails(newnails)
# If a regen of thumbnails and webnails has occurred, then we should also delete any tmp.rotated files.
if not dontregen:
for key in rotated.keys():
# Wrapped in a try except since child processes may try to unlink a second time
try:
os.unlink(Globs.gallerytempdir+'/tmp.rotated.'+key+'.jpg')
except:
pass
if formvals.has_key('annotate'):
if Globs.admin and formvals.has_key('target'):
target=formvals['target']
# Write an annotation file
atext=string.replace(formvals['annotate'],'"','&quot;')
target=formvals['target']
ouf=open(Globs.attachmentdir+'/tmp.annotation.'+target+'.txt','w')
ouf.write(atext)
ouf.close()
message('Annotation updated to <i>'+atext+'</i>',0)
# Now update the annotated dictionary
if not Globs.annotated.has_key(target):
Globs.annotated[target]=''
if formvals.has_key('webnail'):
# Does the webnail exist?
message('webnail requested')
target=formvals['webnail']
rotend=''
if Globs.originals.has_key(target):
out.write(navibar(target,'webnail'))
if formvals.has_key('rotate'):
direction=formvals['rotate']
message(direction)
rotate(target,direction)
rotend=Globs.galleryrotchar+'rot='+repr(randint(1,10000))
# Put things in a table
out.write(tleft)
# Lets build up an image tag
out.write('<a href="'+Globs.baseurl+Globs.pagename+'?original='+target+'&action=content"><img src="'+Globs.gallerytempurl+'tmp.webnail.'+target+'.jpg'+rotend+'"></a>\n')
out.write(trigh)
out.write(tleft)
atext=getannotation(target)
# Are we an administrator?
if Globs.admin:
# We always provide an annotation text field
out.write('<form action='+Globs.subname+' name=annotate METHOD=POST>')
out.write('<input maxLength=256 size=55 name=annotate value="'+atext+'">')
out.write('<input type=hidden value="'+target+'" name="target">')
out.write('<input type=hidden value="show" name="action">')
out.write('<input type=hidden value="'+target+'" name="webnail">')
out.write('</form>')
else:
out.write(atext)
out.write(trigh)
out.write(toolbar(target,'webnail'))
else:
message('I do not have file: '+target,0)
elif formvals.has_key('original'):
# Now we just construct a single item rather than a table
# Does the webnail exist?
message('original requested')
target=formvals['original']
rotend=''
if not Globs.originals.has_key(target):
message('I do not have file: '+target,0)
else:
if formvals.has_key('rotate'):
direction=formvals['rotate']
message(direction)
rotate(target,direction)
rotend=Globs.galleryrotchar+'rot='+repr(randint(1,10000))
rotated[target]=''
# Lets build up an image tag
out.write(navibar(target,'original'))
out.write(tleft)
originalfilename=Globs.originals[target]
# If there is a rotated version, show that instead
if rotated.has_key(target):
out.write('<a href="'+Globs.baseurl+Globs.pagename+'?webnail='+target+Globs.bcomp+'"><img src="'+Globs.gallerytempurl+'tmp.rotated.'+target+'.jpg'+rotend+'"></a>\n')
else:
out.write('<a href="'+Globs.baseurl+Globs.pagename+'?webnail='+target+Globs.bcomp+'"><img src="'+Globs.subname+'?action=AttachFile&amp;do=get&amp;target='+originalfilename+'"></a>\n')
out.write(trigh)
out.write(tleft)
atext=getannotation(target)
# Are we an administrator?
if Globs.admin:
# We always provide an annotation text field
out.write('<form action='+Globs.subname+' name=annotate METHOD=POST>')
out.write('<input maxLength=256 size=55 name=annotate value="'+atext+'">')
out.write('<input type=hidden value="'+target+'" name="target">')
out.write('<input type=hidden value="show" name="action">')
out.write('<input type=hidden value="'+target+'" name="original">')
out.write('</form>')
else:
out.write(atext)
out.write(trigh)
out.write(toolbar(target,'original'))
elif formvals.has_key('rotate'):
# We rotate all sizes of this image to the left or right
message('rotate requested')
target=formvals['target']
direction=formvals['rotate']
if not Globs.originals.has_key(target):
message('I do not have file: '+target,0)
else:
# Do the rotation
rotate(target,direction)
# Display the new image in webnail mode
# We may need a way of forcing the browser to reload the newly rotated image here (later)
out.write(tleft)
out.write('<a href="'+Globs.baseurl+Globs.pagename+'?webnail='+target+Globs.bcomp+'"><img src="'+Globs.gallerytempurl+'tmp.webnail.'+target+'.jpg"></a>\n')
out.write(trigh)
else:
# Finally lets build a table of thumbnails
thumbs=Globs.originals.keys()
thumbs.sort()
thumbs.reverse()
# If version number is requested (append a ?version=tellme&action=show to the page request)
# or if there are no original images, just give help message and return
if formvals.has_key('version') or len(thumbs)==0:
message(version(),0)
return macro.formatter.rawHTML( Globs.adminmsg )
out.write('\n<table>')
cease=''
rollover=''
while 1:
out.write('<tr>')
for i in range(Globs.numberofcolumns):
try:
item=thumbs.pop()
except IndexError:
cease='true'
break
# Alt text
atext=getannotation(item)
rollover='alt="'+atext+'" title="'+atext+'"'
# Table entry for thumbnail image
out.write('<td><a href="'+Globs.baseurl+Globs.pagename+'?webnail='+item+Globs.bcomp+'"><center><img src="'+Globs.gallerytempurl+'tmp.thumbnail.'+item+'.jpg" '+rollover+'></a></center></td>')
out.write('</tr>\n')
if cease:
out.write('</table>')
break
out.seek(0)
# Finally output any administrative messages at the top followed by any generated content
return macro.formatter.rawHTML(
Globs.adminmsg+'<p>'
+out.read()
)

173
wiki/macro/ImageLink.py Normal file
View file

@ -0,0 +1,173 @@
# -*- coding: iso-8859-1 -*-
"""
MoinMoin - ImageLink Macro
PURPOSE:
This macro is used to set a link as WikiName for an attached image. Optional the size of the
image could be adjusted. If no WikiName is given the attachment is linked to the image itselfs.
CALLING SEQUENCE:
[[ImageLink(attachment|URL,[WikiName|URL],[width=width,[height=heigt]])]]
INPUTS:
attachment:image name of attachment or the URL to an image
OPTIONAL INPUTS:
WikiName: the page to set the link to or the URL to link to
KEYWORD PARAMETERS:
width: width of the embedded image
height: height of the embedded image
EXAMPLE:
[[ImageLink(plot.png,FrontPage,width=20,height=20)]]
[[ImageLink(plot.png,FrontPage,height=20)]]
[[ImageLink(plot.png,FrontPage)]]
[[ImageLink(plot.png,width=20,height=20)]]
[[ImageLink(plot.png,width=20)]]
[[ImageLink(plot.png)]]
[[ImageLink(http://localhost/wiki/modern/img/to_slide.png,http://localhost/StartSeite,width=50)]]
[[ImageLink(http://localhost/wiki/modern/img/to_slide.png,FrontPage,width=50)]]
[[ImageLink(plot.png,http://localhost/StartSeite,width=50)]]
[[ImageLink(http://localhost/wiki/modern/img/to_slide.png)]]
[[ImageLink(http://localhost/wiki/modern/img/to_slide.png,alt=whateveryouwant)]]
PROCEDURE:
This routine requires attachment enabled. If the attachment isn't downloaded at all
the attachment line is shown.
If you give only one image size argument e.g. width only the other one is calculated
It must be in "MoinMoin/macro"
Please remove the version number from the file name!
From JeffKunce ImageLink.py I have copied _is_URL to this routine. I have no better idea too.
HISTORY:
The first published version on MoinMoin I know of ImageLink was written by JeffKunce in 2001.
MODIFICATION HISTORY:
@copyright: 2004 by Reimar Bauer (R.Bauer@fz-juelich.de)
@license: GNU GPL, see COPYING for details.
Marcin Zalewski:
Some things that were causing problems on my wiki are changed
(wikiutil.link_tag and macro.formatter.pagelink implemented)
Marcin Zalewski:
Added title attribute to the created link. One could generalize that to
add arbitrary attributes.
One could also add class attributes to <a> and/or
<img> elements. I do not see the need for such modifications. If however this is
to be done in the future one would need to add 'html_class' key to the kw dictionary
with a corresponding value to add class to <img> element. To add class to <a> element
one needs to add 'css_class' key with a corresponding value to the dictionary passed to
pagelink call.
Reimar Bauer:
2004-12-23 Adopted to MoinMoin Version 1.3.1-1
2004-12-23 SYNTAX CHANGE Version 1.3.1-2
width and height and probably other keywords must be called as keywords (e.g. height=20)
2004-12-31 Version 1.3.1-3 code clean up
2005-01-16 Bug fixed in the errorhandler found and patch code from Malte Helmert
2005-03-05 Version 1.3.3-5 Bug fixed found by cypress
''If I put [[ImageLink(moinmoin.png)]] it bombs''
2005-03-28 Version 1.3.3-6 feature request added by CDPark:
''Can we use an external image? And an external target? ''
2005-04-16 Version 1.3.3-7 no default alt tag definition requested by CDPark and AlexanderSchremmer
Chong-Dae Park:
2005-04-17 Version 1.3.3-8 code refactored
IMG with no alt tag is not recommended in the HTML standard.
It keeps user specified alt tag. If it is not, it tries to use WikiName or image name instead.
Reimar Bauer:
2005-04-21 Version 1.3.3-9 bug fixed
When the image does not exist yet, it gives you a "Upload Image" link, this link does not
work. I suspect that this only is a problem on sub-pages, caused by incorrect escaping of
"/". -- CraigJohnson
"""
from MoinMoin.action import AttachFile
from MoinMoin import wikiutil, config
import os,string
def _is_URL(aString):
'''answer true if aString is a URL.
The method used here is pretty dumb. Improvements are welcome.
jjk 03/28/01'''
return string.find(aString, '://')>0
def execute(macro, text):
kw ={} # create a dictionary for the formatter.image call
if text:
args=text.split(',')
else:
args=[]
number_args=len(args)
count=0
for a in args :
if (a.find('=') > -1):
count=count+1
key=a.split('=')
kw[str(key[0])]=wikiutil.escape(string.join(key[1],''), quote=1)
number_args=number_args-count
if (number_args < 1):
msg='Not enough arguments to ImageLink macro! Try [[ImageLink(attachment,[WikiName],[width=width,[height=heigt]])]]'
return macro.formatter.sysmsg(1)+macro.formatter.text(msg)+ macro.formatter.sysmsg(0)
attname=wikiutil.taintfilename(macro.formatter.text(args[0]))
if (number_args >= 2) :
wikiname=args[1]
current_pagename=macro.formatter.page.page_name
if _is_URL(args[0]):
kw['src']=args[0]
else:
kw['src']=AttachFile.getAttachUrl(current_pagename,attname,macro.request)
attachment_path = os.path.join(AttachFile.getAttachDir(macro.request,current_pagename), attname)
if not os.path.exists(attachment_path):
import urllib
linktext = macro.request.getText('Upload new attachment "%(filename)s"'%{
"filename":attname})
return wikiutil.link_tag(macro.request,
"%(pagename)s?action=AttachFile&amp;rename=%(newname)s" % {
"pagename":current_pagename,
"newname": attname},linktext)
if not kw.has_key('alt'):
if (number_args == 1) or _is_URL(args[1]):
if _is_URL(args[0]):
# Get image name http://here.com/dir/image.gif -> image.gif
kw['alt'] = wikiutil.taintfilename(macro.formatter.text(args[0].split('/')[-1]))
kw['alt'] = args[0].split('/')[-1]
else:
kw['alt'] = attname
else:
kw['alt'] = wikiname
if (number_args == 1):
image_link=macro.formatter.image(**kw)
return macro.formatter.url(1,kw['src'] )+image_link +macro.formatter.url(0)
if (number_args == 2 ):
image_link=macro.formatter.image(**kw)
if _is_URL(args[1]):
return macro.formatter.url(1,args[1] )+image_link+macro.formatter.url(0)
else:
return macro.formatter.pagelink(1,wikiname)+image_link+macro.formatter.url(0)

220
wiki/macro/ProgressBar.py Normal file
View file

@ -0,0 +1,220 @@
"""
MoinMoin - ProgressBar Macro
Generates a progress bar (in the form of a table)
@copyright: Pascal Bauermeister <pascal DOT bauermeister AT gmail DOT cm>
@license: GPL
Updates:
* [v0.1.1] Sun Dec 18 21:31:17 CET 2005
Changed table cell percentage markup.
* [v0.1.0] Fri Dec 16 22:30:10 CET 2005
Original version
----
The ProgressBar macro generates a table showing a progress indicator.
Usage:
[[ ProgressBar ]]
[[ ProgressBar (TABLEWIDTH TABLEFORMAT PROGRESS%) ]]
[[ ProgressBar (TABLEWIDTH TABLEFORMAT CURRENT/STEPS) ]]
[[ ProgressBar (TABLEWIDTH TABLEFORMAT STARTDATE,ENDDATE) ]]
If no arguments are given, the usage is inserted in the HTML result.
Options:
TABLEWIDTH (optional prefix)
A wiki tablewidth attribute value between []'s
Examples:
[100%]
[80px]
TABLEFORMAT (optional prefix)
A pair of wiki table attribute, to format the inactive and active cells.
Examples:
<bgcolor="black"><bgcolor="white"> # black on white bar
<tablewidth="90%" bgcolor="black"><bgcolor="white"> # same, 90% table
A third format may be given for STARTDATE,ENDDATE usage
By default: <tablewidth="100px"#808080><><#8080ff>
PROGRESS
Will display a table with two cells:
- left: completion, taking PROGRESS % of the table width
- right: remaining
CURRENT/STEPS
Will display a table with STEPS cells, CURRENT of which are active.
STARTDATE,ENDDATE
Will display a table with the number of days, with the cell
representing today in active format and background in inactive format.
If today is before STARTDATE, the left-most cell will be in the
3rd format. If today is after ENDDATE the rightmost cell will be
in the 3rd format.
Dates are in this format: YYYY-MM-DD
Debugging
Please prepend a '?' to the arguments.
Examples:
[[ProgressBar(60%)]]
[[ProgressBar(6/10)]]
[[ProgressBar(2005-11-01,2006-01-06)]]
[[ProgressBar([50%] 60%)]]
[[ProgressBar([50px] 60%)]]
[[ProgressBar([90%]<#8080ff><#808080> 6/10)]]
----
"""
# Imports
import time, re, StringIO
from MoinMoin import version
from MoinMoin.parser import wiki
Dependencies = ["time"] # macro cannot be cached
class _Error (Exception):
pass
def escape (str):
return str.replace ('&','&amp;').replace ('<', '&lt;').replace ('>', '&gt;')
def usage (full = False):
"""Returns the interesting part of the module's doc"""
if full:
return __doc__
else:
rx = re.compile ("--$(.*)^--", re.DOTALL + re.MULTILINE)
return rx.findall (__doc__) [0].strip ()
def s2t (s):
return time.mktime (time.strptime (s, "%Y-%m-%d"))
def execute (macro, text, args_re=None):
try: res = _execute (macro, text)
except Exception, msg:
return """
<p><strong class="error">
Error: macro ProgressBar: %s</strong> </p>
""" % escape ("%s" % msg)
return res
def _execute (macro, text):
fmt = ['#808080','','#8080ff']
width ="100px"
res = ""
text = text.strip ()
# help if empty text
help = len (text) == 0
# debug if starts with '?'
if text.startswith ('?'):
debug = True
text = text [1:]
else:
debug = False
orig_text = text
# Formats
try:
# Table width
if text.startswith ('['):
pos = text.rfind (']')
width = text [1:pos]
text = text [pos+1:].strip ()
# Cells format
if text.startswith ('<'):
pos = text.rfind ('>')
f = text [1:pos].split ('><')
text = text [pos+1:].strip ()
fmt [:len (f)] = f
except:
help = True
# Show help
if help:
return """
<p>
<pre>%s</pre></p>
""" % escape (usage (0))
# Cell formatting utility
def cell (txt, fmt):
if len (txt) == 0:
fmt = 'tablewidth="%s" ' % width + fmt
txt = "||"
if len (fmt): t = "<%s> ||" % fmt
else: t = " ||"
return txt + t
# Progress
if text.endswith ('%'):
for f in fmt [0] + ' %s' % text, fmt [1] :
res = cell (res, f)
# Current/Steps
elif text.find ('/') > 0:
cur, steps = map (int, text.split ('/'))
for i in range (steps):
res = cell (res, fmt [i>=cur])
# Start/end date
else:
starts, ends = map (lambda s:s.strip (), text.split (","))
start, end = s2t (starts), s2t (ends)
now = time.mktime (time.localtime ())
duration = int ( (end-start) / 86400)
progress = int ( (now-start) / 86400) -1
pcent = int (90 / duration)
for i in range (duration):
if i == 0 and progress < 0:
f = fmt [2]
elif i == progress:
f = fmt [0]
else:
f = fmt [1]
res = cell (res, f)
if progress >= duration:
res = cell (res, fmt [2])
else:
res = cell (res, fmt [1])
# Output
if debug:
res = "{{{[[ProgressBar(%s)]]\n%s}}}\n%s" % (orig_text, res, res)
return _format (res, macro.request, macro.formatter)
def _format (src_text, request, formatter):
# parse the text (in wiki source format) and make HTML,
# after diverting sys.stdout to a string
str_out = StringIO.StringIO () # create str to collect output
request.redirect (str_out) # divert output to that string
# parse this line
wiki.Parser (src_text, request).format (formatter)
request.redirect () # restore output
return str_out.getvalue () # return what was generated

View file

@ -0,0 +1,244 @@
# -*- coding: iso-8859-1 -*-
"""
MoinMoin - RandomIncludeQuote macro
This macro includes the formatted content of the given page(s). See
http://purl.net/wiki/moinmaster/HelpOnMacros/Include
for detailed docs.
@copyright: 2000-2004 by Jürgen Hermann <jh@web.de>
@copyright: 2000-2001 by Richard Jones <richard@bizarsoftware.com.au>
@license: GNU GPL, see COPYING for details.
"""
#Dependencies = ["pages"] # included page
Dependencies = ["time"] # works around MoinMoinBugs/TableOfContentsLacksLinks
import re, StringIO
from MoinMoin import wikiutil
from MoinMoin.Page import Page
from MoinMoin.util import web
_sysmsg = '<p><strong class="%s">%s</strong></p>'
## keep in sync with TableOfContents macro!
_arg_heading = r'(?P<heading>,)\s*(|(?P<hquote>[\'"])(?P<htext>.+?)(?P=hquote))'
_arg_level = r',\s*(?P<level>\d*)'
_arg_from = r'(,\s*from=(?P<fquote>[\'"])(?P<from>.+?)(?P=fquote))?'
_arg_to = r'(,\s*to=(?P<tquote>[\'"])(?P<to>.+?)(?P=tquote))?'
_arg_sort = r'(,\s*sort=(?P<sort>(ascending|descending)))?'
_arg_items = r'(,\s*items=(?P<items>\d+))?'
_arg_skipitems = r'(,\s*skipitems=(?P<skipitems>\d+))?'
_arg_titlesonly = r'(,\s*(?P<titlesonly>titlesonly))?'
_arg_editlink = r'(,\s*(?P<editlink>editlink))?'
_args_re_pattern = r'^(?P<name>[^,]+)(%s(%s)?%s%s%s%s%s%s%s)?$' % (
_arg_heading, _arg_level, _arg_from, _arg_to, _arg_sort, _arg_items,
_arg_skipitems, _arg_titlesonly, _arg_editlink)
_title_re = r"^(?P<heading>\s*(?P<hmarker>=+)\s.*\s(?P=hmarker))$"
def extract_titles(body, title_re):
titles = []
for title, _ in title_re.findall(body):
h = title.strip()
level = 1
while h[level:level+1] == '=': level = level+1
depth = min(5,level)
title_text = h[level:-level].strip()
titles.append((title_text, level))
return titles
def execute(macro, text, args_re=re.compile(_args_re_pattern), title_re=re.compile(_title_re, re.M), called_by_toc=0):
request = macro.request
_ = request.getText
# return immediately if getting links for the current page
if request.mode_getpagelinks:
return ''
# parse and check arguments
args = args_re.match(text)
if not args:
return (_sysmsg % ('error', _('Invalid include arguments "%s"!')) % (text,))
# prepare including page
result = []
print_mode = macro.form.has_key('action') and macro.form['action'][0] == "print"
this_page = macro.formatter.page
if not hasattr(this_page, '_macroInclude_pagelist'):
this_page._macroInclude_pagelist = {}
# get list of pages to include
inc_name = wikiutil.AbsPageName(request, this_page.page_name, args.group('name'))
pagelist = [inc_name]
if inc_name.startswith("^"):
try:
inc_match = re.compile(inc_name)
except re.error:
pass # treat as plain page name
else:
# Get user filtered readable page list
pagelist = request.rootpage.getPageList(filter=inc_match.match)
# sort and limit page list
pagelist.sort()
sort_dir = args.group('sort')
if sort_dir == 'descending':
pagelist.reverse()
max_items = args.group('items')
if max_items:
pagelist = pagelist[:int(max_items)]
skipitems = 0
if args.group("skipitems"):
skipitems = int(args.group("skipitems"))
titlesonly = args.group('titlesonly')
editlink = args.group('editlink')
# iterate over pages
for inc_name in pagelist:
if not request.user.may.read(inc_name):
continue
if this_page._macroInclude_pagelist.has_key(inc_name):
result.append(u'<p><strong class="error">Recursive include of "%s" forbidden</strong></p>' % (inc_name,))
continue
if skipitems:
skipitems -= 1
continue
fmt = macro.formatter.__class__(request, is_included=True)
fmt._base_depth = macro.formatter._base_depth
inc_page = Page(request, inc_name, formatter=fmt)
inc_page._macroInclude_pagelist = this_page._macroInclude_pagelist
# check for "from" and "to" arguments (allowing partial includes)
body = inc_page.get_raw_body() + '\n'
from_pos = 0
to_pos = -1
from_re = args.group('from')
if from_re:
try:
from_match = re.compile(from_re, re.M).search(body)
except re.error, e:
##result.append("*** fe=%s ***" % e)
from_match = re.compile(re.escape(from_re), re.M).search(body)
if from_match:
from_pos = from_match.end()
else:
result.append(_sysmsg % ('warning', 'Include: ' + _('Nothing found for "%s"!')) % from_re)
to_re = args.group('to')
if to_re:
try:
to_match = re.compile(to_re, re.M).search(body, from_pos)
except re.error:
to_match = re.compile(re.escape(to_re), re.M).search(body, from_pos)
if to_match:
to_pos = to_match.start()
else:
result.append(_sysmsg % ('warning', 'Include: ' + _('Nothing found for "%s"!')) % to_re)
if titlesonly:
newbody = []
levelstack = []
for title, level in extract_titles(body[from_pos:to_pos], title_re):
if levelstack:
if level > levelstack[-1]:
result.append(macro.formatter.bullet_list(1))
levelstack.append(level)
else:
while levelstack and level < levelstack[-1]:
result.append(macro.formatter.bullet_list(0))
levelstack.pop()
if not levelstack or level != levelstack[-1]:
result.append(macro.formatter.bullet_list(1))
levelstack.append(level)
else:
result.append(macro.formatter.bullet_list(1))
levelstack.append(level)
result.append(macro.formatter.listitem(1))
result.append(inc_page.link_to(request, title))
result.append(macro.formatter.listitem(0))
while levelstack:
result.append(macro.formatter.bullet_list(0))
levelstack.pop()
continue
if from_pos or to_pos != -1:
inc_page.set_raw_body(body[from_pos:to_pos], modified=True)
##result.append("*** f=%s t=%s ***" % (from_re, to_re))
##result.append("*** f=%d t=%d ***" % (from_pos, to_pos))
if called_by_toc:
result.append(inc_page.get_raw_body())
continue
if not hasattr(request, "_Include_backto"):
request._Include_backto = this_page.page_name
# do headings
level = None
if args.group('heading') and args.group('hquote'):
heading = args.group('htext') or inc_page.split_title(request)
level = 1
if args.group('level'):
level = int(args.group('level'))
if print_mode:
result.append(macro.formatter.heading(1, level) +
macro.formatter.text(heading) +
macro.formatter.heading(0, level))
else:
import sha
from MoinMoin import config
# this heading id might produce duplicate ids,
# if the same page is included multiple times
# Encode stuf we feed into sha module.
pntt = (inc_name + heading).encode(config.charset)
hid = "head-" + sha.new(pntt).hexdigest()
request._page_headings.setdefault(pntt, 0)
request._page_headings[pntt] += 1
if request._page_headings[pntt] > 1:
hid += '-%d'%(request._page_headings[pntt],)
result.append(
#macro.formatter.heading(1, level, hid,
# icons=edit_icon.replace('<img ', '<img align="right" ')) +
macro.formatter.heading(1, level, hid) +
inc_page.link_to(request, heading, css_class="include-heading-link") +
macro.formatter.heading(0, level)
)
# set or increment include marker
this_page._macroInclude_pagelist[inc_name] = \
this_page._macroInclude_pagelist.get(inc_name, 0) + 1
# output the included page
strfile = StringIO.StringIO()
request.redirect(strfile)
try:
cid = request.makeUniqueID("Include_%s" % wikiutil.quoteWikinameFS(inc_page.page_name))
inc_page.send_page(request, content_only=1, content_id=cid)
result.append(strfile.getvalue())
finally:
request.redirect()
# decrement or remove include marker
if this_page._macroInclude_pagelist[inc_name] > 1:
this_page._macroInclude_pagelist[inc_name] = \
this_page._macroInclude_pagelist[inc_name] - 1
else:
del this_page._macroInclude_pagelist[inc_name]
# if no heading and not in print mode, then output a helper link
if editlink and not (level or print_mode):
result.extend([
'<div class="include-link">',
inc_page.link_to(request, '[%s]' % (inc_name,), css_class="include-page-link"),
inc_page.link_to(request, '[%s]' % (_('edit'),), css_class="include-edit-link", querystr={'action': 'edit', 'backto': request._Include_backto}),
'</div>',
])
# XXX page.link_to is wrong now, it escapes the edit_icon html as it escapes normal text
# return include text
return ''.join(result)
# vim:ts=4:sw=4:et

View file

@ -0,0 +1,219 @@
# -*- coding: iso-8859-1 -*-
#Dependencies = ["pages"] # included page
Dependencies = ["time"] # works around MoinMoinBugs/TableOfContentsLacksLinks
import re, StringIO
from MoinMoin import wikiutil, search
from MoinMoin.Page import Page
from MoinMoin.util import web
from random import choice
_sysmsg = '<p><strong class="%s">%s</strong></p>'
## keep in sync with TableOfContents macro!
_arg_heading = r'(?P<heading>,)\s*(|(?P<hquote>[\'"])(?P<htext>.+?)(?P=hquote))'
_arg_level = r',\s*(?P<level>\d*)'
_arg_from = r'(,\s*from=(?P<fquote>[\'"])(?P<from>.+?)(?P=fquote))?'
_arg_to = r'(,\s*to=(?P<tquote>[\'"])(?P<to>.+?)(?P=tquote))?'
_arg_sort = r'(,\s*sort=(?P<sort>(ascending|descending)))?'
_arg_items = r'(,\s*items=(?P<items>\d+))?'
_arg_skipitems = r'(,\s*skipitems=(?P<skipitems>\d+))?'
_arg_titlesonly = r'(,\s*(?P<titlesonly>titlesonly))?'
_arg_editlink = r'(,\s*(?P<editlink>editlink))?'
_args_re_pattern = r'^(?P<name>[^,]+)(%s(%s)?%s%s%s%s%s%s%s)?$' % (
_arg_heading, _arg_level, _arg_from, _arg_to, _arg_sort, _arg_items,
_arg_skipitems, _arg_titlesonly, _arg_editlink)
_title_re = r"^(?P<heading>\s*(?P<hmarker>=+)\s.*\s(?P=hmarker))$"
def extract_titles(body, title_re):
titles = []
for title, _ in title_re.findall(body):
h = title.strip()
level = 1
while h[level:level+1] == '=': level = level+1
depth = min(5,level)
title_text = h[level:-level].strip()
titles.append((title_text, level))
return titles
def execute(macro, text, args_re=re.compile(_args_re_pattern), title_re=re.compile(_title_re, re.M), called_by_toc=0):
request = macro.request
_ = request.getText
qnumber = choice(range(1, 10, 1))
text = u'QuestionnaireCrans/Question\d+[a-z]?$,, from="^= Question =$", to="^----$"'
# return immediately if getting links for the current page
if request.mode_getpagelinks:
return ''
# parse and check arguments
args = args_re.match(text)
if not args:
return (_sysmsg % ('error', _('Invalid include arguments "%s"!')) % (text,))
# Search the pages and return the results
query = search.QueryParser(regex=1).parse_query(args.group('name'))
results = search.searchPages(request, query)
results.sortByPagename()
pagelist = [results.hits[qnumber].page_name]
# prepare including page
result = []
print_mode = macro.form.has_key('action') and macro.form['action'][0] == "print"
this_page = macro.formatter.page
if not hasattr(this_page, '_macroInclude_pagelist'):
this_page._macroInclude_pagelist = {}
skipitems = 0
if args.group("skipitems"):
skipitems = int(args.group("skipitems"))
titlesonly = args.group('titlesonly')
editlink = args.group('editlink')
# iterate over pages
for inc_name in pagelist:
if not request.user.may.read(inc_name):
continue
if this_page._macroInclude_pagelist.has_key(inc_name):
result.append(u'<p><strong class="error">Recursive include of "%s" forbidden</strong></p>' % (inc_name,))
continue
if skipitems:
skipitems -= 1
continue
fmt = macro.formatter.__class__(request, is_included=True)
fmt._base_depth = macro.formatter._base_depth
inc_page = Page(request, inc_name, formatter=fmt)
inc_page._macroInclude_pagelist = this_page._macroInclude_pagelist
# check for "from" and "to" arguments (allowing partial includes)
body = inc_page.get_raw_body() + '\n'
from_pos = 0
to_pos = -1
from_re = args.group('from')
if from_re:
try:
from_match = re.compile(from_re, re.M).search(body)
except re.error, e:
##result.append("*** fe=%s ***" % e)
from_match = re.compile(re.escape(from_re), re.M).search(body)
if from_match:
from_pos = from_match.end()
else:
result.append(_sysmsg % ('warning', 'Include: ' + _('Nothing found for "%s"!')) % from_re)
to_re = args.group('to')
if to_re:
try:
to_match = re.compile(to_re, re.M).search(body, from_pos)
except re.error:
to_match = re.compile(re.escape(to_re), re.M).search(body, from_pos)
if to_match:
to_pos = to_match.start()
else:
result.append(_sysmsg % ('warning', 'Include: ' + _('Nothing found for "%s"!')) % to_re)
if titlesonly:
newbody = []
levelstack = []
for title, level in extract_titles(body[from_pos:to_pos], title_re):
if levelstack:
if level > levelstack[-1]:
result.append(macro.formatter.bullet_list(1))
levelstack.append(level)
else:
while levelstack and level < levelstack[-1]:
result.append(macro.formatter.bullet_list(0))
levelstack.pop()
if not levelstack or level != levelstack[-1]:
result.append(macro.formatter.bullet_list(1))
levelstack.append(level)
else:
result.append(macro.formatter.bullet_list(1))
levelstack.append(level)
result.append(macro.formatter.listitem(1))
result.append(inc_page.link_to(request, title))
result.append(macro.formatter.listitem(0))
while levelstack:
result.append(macro.formatter.bullet_list(0))
levelstack.pop()
continue
if from_pos or to_pos != -1:
inc_page.set_raw_body(body[from_pos:to_pos], modified=True)
##result.append("*** f=%s t=%s ***" % (from_re, to_re))
##result.append("*** f=%d t=%d ***" % (from_pos, to_pos))
if called_by_toc:
result.append(inc_page.get_raw_body())
continue
if not hasattr(request, "_Include_backto"):
request._Include_backto = this_page.page_name
# do headings
level = None
if args.group('heading') and args.group('hquote'):
heading = args.group('htext') or inc_page.split_title(request)
level = 1
if args.group('level'):
level = int(args.group('level'))
if print_mode:
result.append(macro.formatter.heading(1, level) +
macro.formatter.text(heading) +
macro.formatter.heading(0, level))
else:
import sha
from MoinMoin import config
# this heading id might produce duplicate ids,
# if the same page is included multiple times
# Encode stuf we feed into sha module.
pntt = (inc_name + heading).encode(config.charset)
hid = "head-" + sha.new(pntt).hexdigest()
request._page_headings.setdefault(pntt, 0)
request._page_headings[pntt] += 1
if request._page_headings[pntt] > 1:
hid += '-%d'%(request._page_headings[pntt],)
result.append(
#macro.formatter.heading(1, level, hid,
# icons=edit_icon.replace('<img ', '<img align="right" ')) +
macro.formatter.heading(1, level, hid) +
inc_page.link_to(request, heading, css_class="include-heading-link") +
macro.formatter.heading(0, level)
)
# set or increment include marker
this_page._macroInclude_pagelist[inc_name] = \
this_page._macroInclude_pagelist.get(inc_name, 0) + 1
# output the included page
strfile = StringIO.StringIO()
request.redirect(strfile)
try:
cid = request.makeUniqueID("Include_%s" % wikiutil.quoteWikinameFS(inc_page.page_name))
inc_page.send_page(request, content_only=1, content_id=cid)
result.append(strfile.getvalue())
finally:
request.redirect()
# decrement or remove include marker
if this_page._macroInclude_pagelist[inc_name] > 1:
this_page._macroInclude_pagelist[inc_name] = \
this_page._macroInclude_pagelist[inc_name] - 1
else:
del this_page._macroInclude_pagelist[inc_name]
# if no heading and not in print mode, then output a helper link
if editlink and not (level or print_mode):
result.extend([
'<div class="include-link">',
inc_page.link_to(request, '[%s]' % (inc_name,), css_class="include-page-link"),
inc_page.link_to(request, '[%s]' % (_('edit'),), css_class="include-edit-link", querystr={'action': 'edit', 'backto': request._Include_backto}),
'</div>',
])
# XXX page.link_to is wrong now, it escapes the edit_icon html as it escapes normal text
# return include text
return ''.join(result)
# vim:ts=4:sw=4:et

View file

@ -0,0 +1,57 @@
# -*- coding: iso-8859-1 -*-
"""
MoinMoin - RandomQuote Macro
Selects a random quote from FortuneCookies or a given page.
Usage:
[[RandomQuote()]]
[[RandomQuote(WikiTips)]]
Comments:
It will look for list delimiters on the page in question.
It will ignore anything that is not in an "*" list.
@copyright: 2002-2004 by Jürgen Hermann <jh@web.de>
@license: GNU GPL, see COPYING for details.
Originally written by Thomas Waldmann.
Gustavo Niemeyer added wiki markup parsing of the quotes.
"""
import random, StringIO
from MoinMoin.Page import Page, wikiutil
Dependencies = ["time"]
def execute(macro, args):
_ = macro.request.getText
pagename = args or 'FortuneCookies'
if macro.request.user.may.read(pagename):
page = Page(macro.request, pagename)
raw = page.get_raw_body()
else:
raw = ""
# this selects lines looking like a list item
# !!! TODO: make multi-line quotes possible (optionally split by "----" or something)
quotes = raw.splitlines()
quotes = [quote.strip() for quote in quotes]
quotes = [quote[2:] for quote in quotes if quote.startswith('1. ')]
if not quotes:
return (macro.formatter.highlight(1) +
_('No quotes on %(pagename)s.') % {'pagename': pagename} +
macro.formatter.highlight(0))
quote = random.choice(quotes)
page.set_raw_body(quote, 1)
out = StringIO.StringIO()
macro.request.redirect(out)
page.send_page(macro.request, content_only=1, content_id="RandomQuote_%s" % wikiutil.quoteWikinameFS(page.page_name) )
quote = out.getvalue()
macro.request.redirect()
return quote

44
wiki/macro/latex.py Normal file
View file

@ -0,0 +1,44 @@
#FORMAT python
"""
See the latex parser, this is just a thin wrapper around it.
"""
# Imports
from MoinMoin import wikiutil
import re
Dependencies = []
splitre = re.compile(r'([^\\])%')
class latex:
def __init__(self, macro, args):
self.macro = macro
self.formatter = macro.formatter
self.text = args
def renderInPage(self):
# return immediately if getting links for the current page
if self.macro.request.mode_getpagelinks:
return ''
if self.text is None: # macro call without parameters
return ''
# get an exception? for moin before 1.3.2 use the following line instead:
# L = wikiutil.importPlugin('parser', 'latex', 'Parser', self.macro.cfg.data_dir)
L = wikiutil.importPlugin(self.macro.cfg, 'parser', 'latex', 'Parser')
if L is None:
return self.formatter.text("<<please install the latex parser>>")
l = L('', self.macro.request)
tmp = splitre.split(self.text, 1)
if len(tmp) == 3:
prologue,p2,tex=tmp
prologue += p2
else:
prologue = ''
tex = tmp[0]
return l.get(self.formatter, tex, prologue)
def execute(macro, args):
return latex(macro, args).renderInPage()