From: Gerfried Fuchs
Date: Sun, 31 Oct 2010 13:23:32 +0000 (+0100)
Subject: Initial import of Kalle's Theme
X-Git-Url: https://git.deb.at/w?a=commitdiff_plain;h=f5041d6a290ec7ef657e9e24333ca1c80c08d72e;p=deb%2Fmoinmoin.git
Initial import of Kalle's Theme
---
f5041d6a290ec7ef657e9e24333ca1c80c08d72e
diff --git a/README b/README
new file mode 100644
index 0000000..2d3a2d2
--- /dev/null
+++ b/README
@@ -0,0 +1,9 @@
+This is about Kalle's themeing for moinmoin, which is used on wiki.debian.org.
+
+URL: http://www.kalleswork.net/projects/debian/wiki/
+Testsite: http://wiki.debian.org/ (follow instructions from above)
+
+Expected configuration:
+ debwiki/ goes to /usr/share/moin/htdocs/debwiki
+ wikiconfig.py.debwiki is a configuration template for /etc/moin/
+ theme/ contains the files for the theme directory of your data
diff --git a/debwiki/config.html_head b/debwiki/config.html_head
new file mode 100644
index 0000000..d0119df
--- /dev/null
+++ b/debwiki/config.html_head
@@ -0,0 +1 @@
+
''' % logo
+ return html
+
+ def interwiki(self, d):
+ """ Assemble the interwiki name display, linking to page_front_page
+
+ @param d: parameter dictionary
+ @rtype: string
+ @return: interwiki html
+ """
+ if self.request.cfg.show_interwiki:
+ page = wikiutil.getFrontPage(self.request)
+ text = self.request.cfg.interwikiname or 'Self'
+ link = page.link_to(self.request, text=text, rel='nofollow')
+ html = u'
%s
' % link
+ else:
+ html = u''
+ return html
+
+ def title(self, d):
+ """ Assemble the title (now using breadcrumbs)
+
+ @param d: parameter dictionary
+ @rtype: string
+ @return: title html
+ """
+ _ = self.request.getText
+ content = []
+ if d['title_text'] == d['page'].split_title(): # just showing a page, no action
+ curpage = ''
+ segments = d['page_name'].split('/') # was: title_text
+ for s in segments[:-1]:
+ curpage += s
+ content.append("
%s
" % Page(self.request, curpage).link_to(self.request, s))
+ curpage += '/'
+ link_text = segments[-1]
+ link_title = _('Click to do a full-text search for this title')
+ link_query = {
+ 'action': 'fullsearch',
+ 'value': 'linkto:"%s"' % d['page_name'],
+ 'context': '180',
+ }
+ # we dont use d['title_link'] any more, but make it ourselves:
+ link = d['page'].link_to(self.request, link_text, querystr=link_query, title=link_title, css_class='backlink', rel='nofollow')
+ content.append(('
%s
') % link)
+ else:
+ content.append('
%s
' % wikiutil.escape(d['title_text']))
+
+ html = '''
+
+%s
+
+''' % "".join(content)
+ return html
+
+ def username(self, d):
+ """ Assemble the username / userprefs link
+
+ @param d: parameter dictionary
+ @rtype: unicode
+ @return: username html
+ """
+ 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 and request.user.name:
+ interwiki = wikiutil.getInterwikiHomePage(request)
+ name = request.user.name
+ aliasname = request.user.aliasname
+ if not aliasname:
+ aliasname = name
+ title = "%s @ %s" % (aliasname, interwiki[0])
+ # link to (interwiki) user homepage
+ homelink = (request.formatter.interwikilink(1, title=title, id="userhome", generated=True, *interwiki) +
+ request.formatter.text(name) +
+ request.formatter.interwikilink(0, title=title, id="userhome", *interwiki))
+ userlinks.append(homelink)
+ # link to userprefs action
+ if 'userprefs' not in self.request.cfg.actions_excluded:
+ userlinks.append(d['page'].link_to(request, text=_('Settings'),
+ querystr={'action': 'userprefs'}, id='userprefs', rel='nofollow'))
+
+ if request.user.valid:
+ if request.user.auth_method in request.cfg.auth_can_logout:
+ userlinks.append(d['page'].link_to(request, text=_('Logout'),
+ querystr={'action': 'logout', 'logout': 'logout'}, id='logout', rel='nofollow'))
+ else:
+ query = {'action': 'login'}
+ # special direct-login link if the auth methods want no input
+ if request.cfg.auth_login_inputs == ['special_no_input']:
+ query['login'] = '1'
+ if request.cfg.auth_have_login:
+ userlinks.append(d['page'].link_to(request, text=_("Login"),
+ querystr=query, id='login', rel='nofollow'))
+
+ userlinks = [u'
%s
' % link for link in userlinks]
+ html = u'
%s
' % ''.join(userlinks)
+ return html
+
+ def splitNavilink(self, text, localize=1):
+ """ Split navibar links into pagename, link to page
+
+ Admin or user might want to use shorter navibar items by using
+ the [[page|title]] or [[url|title]] syntax. In this case, we don't
+ use localization, and the links goes to page or to the url, not
+ the localized version of page.
+
+ Supported syntax:
+ * PageName
+ * WikiName:PageName
+ * wiki:WikiName:PageName
+ * url
+ * all targets as seen above with title: [[target|title]]
+
+ @param text: the text used in config or user preferences
+ @rtype: tuple
+ @return: pagename or url, link to page or url
+ """
+ request = self.request
+ fmt = request.formatter
+ title = None
+
+ # Handle [[pagename|title]] or [[url|title]] formats
+ if text.startswith('[[') and text.endswith(']]'):
+ text = text[2:-2]
+ try:
+ pagename, title = text.split('|', 1)
+ pagename = pagename.strip()
+ title = title.strip()
+ localize = 0
+ except (ValueError, TypeError):
+ # Just use the text as is.
+ pagename = text.strip()
+ else:
+ pagename = text
+
+ if wikiutil.is_URL(pagename):
+ if not title:
+ title = pagename
+ link = fmt.url(1, pagename) + fmt.text(title) + fmt.url(0)
+ return pagename, link
+
+ # remove wiki: url prefix
+ if pagename.startswith("wiki:"):
+ pagename = pagename[5:]
+
+ # try handling interwiki links
+ try:
+ interwiki, page = wikiutil.split_interwiki(pagename)
+ thiswiki = request.cfg.interwikiname
+ if interwiki == thiswiki or interwiki == 'Self':
+ pagename = page
+ else:
+ if not title:
+ title = page
+ link = fmt.interwikilink(True, interwiki, page) + fmt.text(title) + fmt.interwikilink(False, interwiki, page)
+ return pagename, link
+ except ValueError:
+ pass
+
+ # Handle regular pagename like "FrontPage"
+ pagename = request.normalizePagename(pagename)
+
+ # Use localized pages for the current user
+ if localize:
+ page = wikiutil.getLocalizedPage(request, pagename)
+ else:
+ page = Page(request, pagename)
+
+ pagename = page.page_name # can be different, due to i18n
+
+ if not title:
+ title = page.split_title()
+ title = self.shortenPagename(title)
+
+ link = page.link_to(request, title)
+
+ return pagename, link
+
+ def shortenPagename(self, name):
+ """ Shorten page names
+
+ Shorten very long page names that tend to break the user
+ interface. The short name is usually fine, unless really stupid
+ long names are used (WYGIWYD).
+
+ If you don't like to do this in your theme, or want to use
+ different algorithm, override this method.
+
+ @param name: page name, unicode
+ @rtype: unicode
+ @return: shortened version.
+ """
+ maxLength = self.maxPagenameLength()
+ # First use only the sub page name, that might be enough
+ if len(name) > maxLength:
+ name = name.split('/')[-1]
+ # If it's not enough, replace the middle with '...'
+ if len(name) > maxLength:
+ half, left = divmod(maxLength - 3, 2)
+ name = u'%s...%s' % (name[:half + left], name[-half:])
+ return name
+
+ def maxPagenameLength(self):
+ """ Return maximum length for shortened page names """
+ return 25
+
+ def navibar(self, d):
+ """ Assemble the navibar
+
+ @param d: parameter dictionary
+ @rtype: unicode
+ @return: navibar html
+ """
+ request = self.request
+ found = {} # pages we found. prevent duplicates
+ items = [] # navibar items
+ item = u'
%s
'
+ 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 == current:
+ cls = 'wikilink current'
+ else:
+ cls = 'wikilink'
+ items.append(item % (cls, link))
+ found[pagename] = 1
+
+ # Add user links to wiki links, eliminating duplicates.
+ userlinks = request.user.getQuickLinks()
+ for text in userlinks:
+ # Split text without localization, user knows what he wants
+ pagename, link = self.splitNavilink(text, localize=0)
+ if not pagename in found:
+ if pagename == current:
+ cls = 'userlink current'
+ else:
+ cls = 'userlink'
+ items.append(item % (cls, link))
+ found[pagename] = 1
+
+ # Add current page at end of local pages
+ if not current in found:
+ title = d['page'].split_title()
+ title = self.shortenPagename(title)
+ link = d['page'].link_to(request, title)
+ cls = 'current'
+ items.append(item % (cls, link))
+
+ # Add sister pages.
+ for sistername, sisterurl in request.cfg.sistersites:
+ if sistername == request.cfg.interwikiname: # it is THIS wiki
+ cls = 'sisterwiki current'
+ items.append(item % (cls, sistername))
+ else:
+ # TODO optimize performance
+ cache = caching.CacheEntry(request, 'sisters', sistername, 'farm', use_pickle=True)
+ if cache.exists():
+ data = cache.content()
+ sisterpages = data['sisterpages']
+ if current in sisterpages:
+ cls = 'sisterwiki'
+ url = sisterpages[current]
+ link = request.formatter.url(1, url) + \
+ request.formatter.text(sistername) +\
+ request.formatter.url(0)
+ items.append(item % (cls, link))
+
+ # Assemble html
+ items = u''.join(items)
+ html = u'''
+
+%s
+
+''' % items
+ return html
+
+ def get_icon(self, icon):
+ """ Return icon data from self.icons
+
+ If called from <> we have a filename, not a
+ key. Using filenames is deprecated, but for now, we simulate old
+ behavior.
+
+ @param icon: icon name or file name (string)
+ @rtype: tuple
+ @return: alt (unicode), href (string), width, height (int)
+ """
+ if icon in self.icons:
+ alt, icon, w, h = self.icons[icon]
+ else:
+ # Create filenames to icon data mapping on first call, then
+ # cache in class for next calls.
+ if not getattr(self.__class__, 'iconsByFile', None):
+ d = {}
+ for data in self.icons.values():
+ d[data[1]] = data
+ self.__class__.iconsByFile = d
+
+ # Try to get icon data by file name
+ if icon in self.iconsByFile:
+ alt, icon, w, h = self.iconsByFile[icon]
+ else:
+ alt, icon, w, h = '', icon, '', ''
+
+ return alt, self.img_url(icon), w, h
+
+ def make_icon(self, icon, vars=None, **kw):
+ """
+ This is the central routine for making tags for icons!
+ All icons stuff except the top left logo and search field icons are
+ handled here.
+
+ @param icon: icon id (dict key)
+ @param vars: ...
+ @rtype: string
+ @return: icon html (img tag)
+ """
+ if vars is None:
+ vars = {}
+ alt, img, w, h = self.get_icon(icon)
+ try:
+ alt = vars['icon-alt-text'] # if it is possible we take the alt-text from 'page_icons_table'
+ except KeyError, err:
+ try:
+ alt = alt % vars # if not we just leave the alt-text from 'icons'
+ except KeyError, err:
+ alt = 'KeyError: %s' % str(err)
+ alt = self.request.getText(alt)
+ tag = self.request.formatter.image(src=img, alt=alt, width=w, height=h, **kw)
+ return tag
+
+ def make_iconlink(self, which, d):
+ """
+ Make a link with an icon
+
+ @param which: icon id (dictionary key)
+ @param d: parameter dictionary
+ @rtype: string
+ @return: html link tag
+ """
+ qs = {}
+ pagekey, querystr, title, icon = self.cfg.page_icons_table[which]
+ qs.update(querystr) # do not modify the querystr dict in the cfg!
+ d['icon-alt-text'] = d['title'] = title % d
+ d['i18ntitle'] = self.request.getText(d['title'])
+ img_src = self.make_icon(icon, d)
+ rev = d['rev']
+ if rev and which in ['raw', 'print', ]:
+ qs['rev'] = str(rev)
+ attrs = {'rel': 'nofollow', 'title': d['i18ntitle'], }
+ page = d[pagekey]
+ if isinstance(page, unicode):
+ # e.g. d['page_parent_page'] is just the unicode pagename
+ # while d['page'] will give a page object
+ page = Page(self.request, page)
+ return page.link_to_raw(self.request, text=img_src, querystr=qs, **attrs)
+
+ def msg(self, d):
+ """ Assemble the msg display
+
+ Display a message with a widget or simple strings with a clear message link.
+
+ @param d: parameter dictionary
+ @rtype: unicode
+ @return: msg display html
+ """
+ _ = self.request.getText
+ msgs = d['msg']
+
+ result = u""
+ close = d['page'].link_to(self.request, text=_('Clear message'), css_class="clear-link")
+ for msg, msg_class in msgs:
+ try:
+ result += u'
%s
' % msg.render()
+ close = ''
+ except AttributeError:
+ if msg and msg_class:
+ result += u'
%s
' % (msg_class, msg)
+ elif msg:
+ result += u'
%s
\n' % msg
+ if result:
+ html = result + close
+ return u'
\n%s\n
\n' % html
+ else:
+ return u''
+
+ return u'
\n%s\n
\n' % html
+
+ def trail(self, d):
+ """ Assemble page trail
+
+ @param d: parameter dictionary
+ @rtype: unicode
+ @return: trail html
+ """
+ request = self.request
+ user = request.user
+ html = ''
+ if not user.valid or user.show_page_trail:
+ trail = user.getTrail()
+ if trail:
+ items = []
+ for pagename in trail:
+ try:
+ interwiki, page = wikiutil.split_interwiki(pagename)
+ if interwiki != request.cfg.interwikiname and interwiki != 'Self':
+ link = (self.request.formatter.interwikilink(True, interwiki, page) +
+ self.shortenPagename(page) +
+ self.request.formatter.interwikilink(False, interwiki, page))
+ items.append('
''' % ''.join(items)
+ return html
+
+ def html_stylesheets(self, d):
+ """ Assemble html head stylesheet links
+
+ @param d: parameter dictionary
+ @rtype: string
+ @return: stylesheets links
+ """
+ link = ''
+
+ # Check mode
+ if d.get('print_mode'):
+ media = d.get('media', 'print')
+ stylesheets = getattr(self, 'stylesheets_' + media)
+ else:
+ stylesheets = self.stylesheets
+ usercss = self.request.user.valid and self.request.user.css_url
+
+ # Create stylesheets links
+ html = []
+ prefix = self.cfg.url_prefix_static
+ csshref = '%s/%s/css' % (prefix, self.name)
+ for media, basename in stylesheets:
+ href = '%s/%s.css' % (csshref, basename)
+ html.append(link % (self.stylesheetsCharset, media, href))
+
+ # Don't add user css url if it matches one of ours
+ if usercss and usercss == href:
+ usercss = None
+
+ # admin configurable additional css (farm or wiki level)
+ for media, csshref in self.request.cfg.stylesheets:
+ html.append(link % (self.stylesheetsCharset, media, csshref))
+
+ csshref = '%s/%s/css/msie.css' % (prefix, self.name)
+ html.append("""
+
+
+""" % link % (self.stylesheetsCharset, 'all', csshref))
+
+ # Add user css url (assuming that user css uses same charset)
+ if usercss and usercss.lower() != "none":
+ html.append(link % (self.stylesheetsCharset, 'all', usercss))
+
+ return '\n'.join(html)
+
+ def shouldShowPageinfo(self, page):
+ """ Should we show page info?
+
+ Should be implemented by actions. For now, we check here by action
+ name and page.
+
+ @param page: current page
+ @rtype: bool
+ @return: true if should show page info
+ """
+ if page.exists() and self.request.user.may.read(page.page_name):
+ # These actions show the page content.
+ # TODO: on new action, page info will not show.
+ # A better solution will be if the action itself answer the question: showPageInfo().
+ contentActions = [u'', u'show', u'refresh', u'preview', u'diff',
+ u'subscribe', u'RenamePage', u'CopyPage', u'DeletePage',
+ u'SpellCheck', u'print']
+ return self.request.action in contentActions
+ return False
+
+ def pageinfo(self, page):
+ """ Return html fragment with page meta data
+
+ Since page information uses translated text, it uses the ui
+ language and direction. It looks strange sometimes, but
+ translated text using page direction looks worse.
+
+ @param page: current page
+ @rtype: unicode
+ @return: page last edit information
+ """
+ _ = self.request.getText
+ html = ''
+ 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
+ pagename = page.page_name
+ if self.request.cfg.show_interwiki:
+ pagename = "%s: %s" % (self.request.cfg.interwikiname, pagename)
+ info = "%s (%s)" % (wikiutil.escape(pagename), info)
+ html = '
%(info)s
\n' % {
+ 'lang': self.ui_lang_attr(),
+ 'info': info
+ }
+ return html
+
+ def searchform(self, d):
+ """
+ assemble HTML code for the search forms
+
+ @param d: parameter dictionary
+ @rtype: unicode
+ @return: search form html
+ """
+ _ = self.request.getText
+ form = self.request.form
+ updates = {
+ 'search_label': _('Search:'),
+ 'search_value': wikiutil.escape(form.get('value', [''])[0], 1),
+ 'search_full_label': _('Text'),
+ 'search_title_label': _('Titles'),
+ 'baseurl': self.request.getScriptname(),
+ 'pagename_quoted': wikiutil.quoteWikinameURL(d['page'].page_name),
+ }
+ d.update(updates)
+
+ html = u'''
+
+
+''' % d
+ return html
+
+ def showversion(self, d, **keywords):
+ """
+ assemble HTML code for copyright and version display
+
+ @param d: parameter dictionary
+ @rtype: string
+ @return: copyright and version display html
+ """
+ html = ''
+ if self.cfg.show_version and not keywords.get('print_mode', 0):
+ html = (u'
MoinMoin Release %s [Revision %s], '
+ 'Copyright by Juergen Hermann et al.
') % (version.release, version.revision, )
+ return html
+
+ def headscript(self, d):
+ """ Return html head script with common functions
+
+ @param d: parameter dictionary
+ @rtype: unicode
+ @return: script for html head
+ """
+ # Don't add script for print view
+ if self.request.action == 'print':
+ return u''
+
+ _ = self.request.getText
+ script = u"""
+
+""" % {
+ 'search_hint': _('Search Wiki'),
+ }
+ return script
+
+ def shouldUseRSS(self, page):
+ """ Return True if RSS feature is available and we are on the
+ RecentChanges page, or False.
+
+ Currently rss is broken on plain Python, and works only when
+ installing PyXML. Return true if PyXML is installed.
+ """
+ if not rss_supported:
+ return False
+ return page.page_name == u'RecentChanges' or \
+ page.page_name == self.request.getText(u'RecentChanges')
+
+ def rsshref(self, page):
+ """ Create rss href, used for rss button and head link
+
+ @rtype: unicode
+ @return: rss href
+ """
+ request = self.request
+ url = page.url(request, querystr={
+ 'action': 'rss_rc', 'ddiffs': '1', 'unique': '1', }, escape=0)
+ return url
+
+ def rsslink(self, d):
+ """ Create rss link in head, used by FireFox
+
+ RSS link for FireFox. This shows an rss link in the bottom of
+ the page and let you subscribe to the wiki rss feed.
+
+ @rtype: unicode
+ @return: html head
+ """
+ link = u''
+ page = d['page']
+ if self.shouldUseRSS(page):
+ link = (u'') % (
+ wikiutil.escape(self.cfg.sitename, True),
+ wikiutil.escape(self.rsshref(page), True) )
+ return link
+
+ def html_head(self, d):
+ """ Assemble html head
+
+ @param d: parameter dictionary
+ @rtype: unicode
+ @return: html head
+ """
+ html = [
+ u'%(title)s - %(sitename)s' % {
+ 'title': wikiutil.escape(d['title']),
+ 'sitename': wikiutil.escape(d['sitename']),
+ },
+ self.externalScript('common'),
+ self.headscript(d), # Should move to separate .js file
+ self.guiEditorScript(d),
+ self.html_stylesheets(d),
+ self.rsslink(d),
+ self.universal_edit_button(d),
+ ]
+ return '\n'.join(html)
+
+ def externalScript(self, name):
+ """ Format external script html """
+ src = '%s/common/js/%s.js' % (self.request.cfg.url_prefix_static, name)
+ return '' % src
+
+ def universal_edit_button(self, d, **keywords):
+ """ Generate HTML for an edit link in the header."""
+ page = d['page']
+ if 'edit' in self.request.cfg.actions_excluded:
+ return ""
+ if not (page.isWritable() and
+ self.request.user.may.write(page.page_name)):
+ return ""
+ _ = self.request.getText
+ querystr = {'action': 'edit'}
+ text = _(u'Edit')
+ url = page.url(self.request, querystr=querystr, escape=0)
+ return (u'' % (text, url))
+
+ def credits(self, d, **keywords):
+ """ Create credits html from credits list """
+ if isinstance(self.cfg.page_credits, (list, tuple)):
+ items = ['
%s
' % i for i in self.cfg.page_credits]
+ html = '
\n%s\n
\n' % ''.join(items)
+ else:
+ # Old config using string, output as is
+ html = self.cfg.page_credits
+ return html
+
+ def actionsMenu(self, page):
+ """ Create actions menu list and items data dict
+
+ The menu will contain the same items always, but items that are
+ not available will be disabled (some broken browsers will let
+ you select disabled options though).
+
+ The menu should give best user experience for javascript
+ enabled browsers, and acceptable behavior for those who prefer
+ not to use Javascript.
+
+ TODO: Move actionsMenuInit() into body onload - requires that the theme will render body,
+ it is currently done in wikiutil/page.
+
+ @param page: current page, Page object
+ @rtype: unicode
+ @return: actions menu html fragment
+ """
+ request = self.request
+ _ = request.getText
+ rev = request.rev
+
+ menu = [
+ 'raw',
+ 'print',
+ 'RenderAsDocbook',
+ 'refresh',
+ '__separator__',
+ 'SpellCheck',
+ 'LikePages',
+ 'LocalSiteMap',
+ '__separator__',
+ 'RenamePage',
+ 'CopyPage',
+ 'DeletePage',
+ '__separator__',
+ 'MyPages',
+ 'SubscribeUser',
+ '__separator__',
+ 'Despam',
+ 'revert',
+ 'PackagePages',
+ 'SyncPages',
+ ]
+
+ titles = {
+ # action: menu title
+ '__title__': _("More Actions:"),
+ # Translation may need longer or shorter separator
+ '__separator__': _('------------------------'),
+ 'raw': _('Raw Text'),
+ 'print': _('Print View'),
+ 'refresh': _('Delete Cache'),
+ 'SpellCheck': _('Check Spelling'), # rename action!
+ 'RenamePage': _('Rename Page'),
+ 'CopyPage': _('Copy Page'),
+ 'DeletePage': _('Delete Page'),
+ 'LikePages': _('Like Pages'),
+ 'LocalSiteMap': _('Local Site Map'),
+ 'MyPages': _('My Pages'),
+ 'SubscribeUser': _('Subscribe User'),
+ 'Despam': _('Remove Spam'),
+ 'revert': _('Revert to this revision'),
+ 'PackagePages': _('Package Pages'),
+ 'RenderAsDocbook': _('Render as Docbook'),
+ 'SyncPages': _('Sync Pages'),
+ }
+
+ options = []
+ option = ''
+ # class="disabled" is a workaround for browsers that ignore
+ # "disabled", e.g IE, Safari
+ # for XHTML: data['disabled'] = ' disabled="disabled"'
+ disabled = ' disabled class="disabled"'
+
+ # Format standard actions
+ available = request.getAvailableActions(page)
+ for action in menu:
+ data = {'action': action, 'disabled': '', 'title': titles[action]}
+ # removes excluded actions from the more actions menu
+ if action in request.cfg.actions_excluded:
+ continue
+
+ # Enable delete cache only if page can use caching
+ if action == 'refresh':
+ if not page.canUseCache():
+ data['action'] = 'show'
+ data['disabled'] = disabled
+
+ # revert action enabled only if user can revert
+ if action == 'revert' and not request.user.may.revert(page.page_name):
+ data['action'] = 'show'
+ data['disabled'] = disabled
+
+ # SubscribeUser action enabled only if user has admin rights
+ if action == 'SubscribeUser' and not request.user.may.admin(page.page_name):
+ data['action'] = 'show'
+ data['disabled'] = disabled
+
+ # PackagePages action only if user has write rights
+ if action == 'PackagePages' and not request.user.may.write(page.page_name):
+ data['action'] = 'show'
+ data['disabled'] = disabled
+
+ # Despam action enabled only for superusers
+ if action == 'Despam' and not request.user.isSuperUser():
+ data['action'] = 'show'
+ data['disabled'] = disabled
+
+ # Special menu items. Without javascript, executing will
+ # just return to the page.
+ if action.startswith('__'):
+ data['action'] = 'show'
+
+ # Actions which are not available for this wiki, user or page
+ if (action == '__separator__' or
+ (action[0].isupper() and not action in available)):
+ data['disabled'] = disabled
+
+ options.append(option % data)
+
+ # Add custom actions not in the standard menu, except for
+ # some actions like AttachFile (we have them on top level)
+ more = [item for item in available if not item in titles and not item in ('AttachFile', )]
+ more.sort()
+ if more:
+ # Add separator
+ separator = option % {'action': 'show', 'disabled': disabled,
+ 'title': titles['__separator__']}
+ options.append(separator)
+ # Add more actions (all enabled)
+ for action in more:
+ data = {'action': action, 'disabled': ''}
+ # Always add spaces: AttachFile -> Attach File
+ # XXX do not create page just for using split_title -
+ # creating pages for non-existent does 2 storage lookups
+ #title = Page(request, action).split_title(force=1)
+ title = action
+ # Use translated version if available
+ data['title'] = _(title)
+ options.append(option % data)
+
+ data = {
+ 'label': titles['__title__'],
+ 'options': '\n'.join(options),
+ 'rev_field': rev and '' % rev or '',
+ 'do_button': _("Do"),
+ 'baseurl': self.request.getScriptname(),
+ 'pagename_quoted': wikiutil.quoteWikinameURL(page.page_name),
+ }
+ html = '''
+
+''' % data
+
+ return html
+
+ def editbar(self, d):
+ """ Assemble the page edit bar.
+
+ Create html on first call, then return cached html.
+
+ @param d: parameter dictionary
+ @rtype: unicode
+ @return: iconbar html
+ """
+ page = d['page']
+ if not self.shouldShowEditbar(page):
+ return ''
+
+ html = self._cache.get('editbar')
+ if html is None:
+ # Remove empty items and format as list
+ items = ''.join(['
%s
' % item
+ for item in self.editbarItems(page) if item])
+ html = u'
%s
\n' % items
+ self._cache['editbar'] = html
+
+ return html
+
+ def shouldShowEditbar(self, page):
+ """ Should we show the editbar?
+
+ Actions should implement this, because only the action knows if
+ the edit bar makes sense. Until it goes into actions, we do the
+ checking here.
+
+ @param page: current page
+ @rtype: bool
+ @return: true if editbar should show
+ """
+ # Show editbar only for existing pages, including deleted pages,
+ # that the user may read. If you may not read, you can't edit,
+ # so you don't need editbar.
+ if (page.exists(includeDeleted=1) and
+ self.request.user.may.read(page.page_name)):
+ form = self.request.form
+ action = self.request.action
+ # Do not show editbar on edit but on save/cancel
+ return not (action == 'edit' and
+ not form.has_key('button_save') and
+ not form.has_key('button_cancel'))
+ return False
+
+ def editbarItems(self, page):
+ """ Return list of items to show on the editbar
+
+ This is separate method to make it easy to customize the
+ edtibar in sub classes.
+ """
+ _ = self.request.getText
+ editbar_actions = []
+ for editbar_item in self.request.cfg.edit_bar:
+ if editbar_item == 'Discussion':
+ if not self.request.cfg.supplementation_page and self.request.getPragma('supplementation-page', 1) in ('on', '1'):
+ editbar_actions.append(self.supplementation_page_nameLink(page))
+ elif self.request.cfg.supplementation_page and not self.request.getPragma('supplementation-page', 1) in ('off', '0'):
+ editbar_actions.append(self.supplementation_page_nameLink(page))
+ elif editbar_item == 'Comments':
+ # we just use to get same style as other links, but we add some dummy
+ # link target to get correct mouseover pointer appearance. return false
+ # keeps the browser away from jumping to the link target::
+ editbar_actions.append('%s' % _('Comments'))
+ elif editbar_item == 'Edit':
+ editbar_actions.append(self.editorLink(page))
+ elif editbar_item == 'Info':
+ editbar_actions.append(self.infoLink(page))
+ elif editbar_item == 'Subscribe':
+ editbar_actions.append(self.subscribeLink(page))
+ elif editbar_item == 'Quicklink':
+ editbar_actions.append(self.quicklinkLink(page))
+ elif editbar_item == 'Attachments':
+ editbar_actions.append(self.attachmentsLink(page))
+ elif editbar_item == 'ActionsMenu':
+ editbar_actions.append(self.actionsMenu(page))
+ return editbar_actions
+
+ def supplementation_page_nameLink(self, page):
+ """Return a link to the discussion page
+
+ If the discussion page doesn't exist and the user
+ has no right to create it, show a disabled link.
+ """
+ _ = self.request.getText
+ suppl_name = self.request.cfg.supplementation_page_name
+ suppl_name_full = "%s/%s" % (page.page_name, suppl_name)
+
+ test = Page(self.request, suppl_name_full)
+ if not test.exists() and not self.request.user.may.write(suppl_name_full):
+ return ('%s' % _(suppl_name))
+ else:
+ return page.link_to(self.request, text=_(suppl_name),
+ querystr={'action': 'supplementation'}, css_class='nbsupplementation', rel='nofollow')
+
+ def guiworks(self, page):
+ """ Return whether the gui editor / converter can work for that page.
+
+ The GUI editor currently only works for wiki format.
+ For simplicity, we also tell it does not work if the admin forces the text editor.
+ """
+ is_wiki = page.pi['format'] == 'wiki'
+ gui_disallowed = self.cfg.editor_force and self.cfg.editor_default == 'text'
+ return is_wiki and not gui_disallowed
+
+
+ def editorLink(self, page):
+ """ Return a link to the editor
+
+ If the user can't edit, return a disabled edit link.
+
+ If the user want to show both editors, it will display "Edit
+ (Text)", otherwise as "Edit".
+ """
+ if 'edit' in self.request.cfg.actions_excluded:
+ return ""
+
+ if not (page.isWritable() and
+ self.request.user.may.write(page.page_name)):
+ return self.disabledEdit()
+
+ _ = self.request.getText
+ querystr = {'action': 'edit'}
+
+ guiworks = self.guiworks(page)
+ if self.showBothEditLinks() and guiworks:
+ text = _('Edit (Text)')
+ querystr['editor'] = 'text'
+ attrs = {'name': 'texteditlink', 'rel': 'nofollow', }
+ else:
+ text = _('Edit')
+ if guiworks:
+ # 'textonly' will be upgraded dynamically to 'guipossible' by JS
+ querystr['editor'] = 'textonly'
+ attrs = {'name': 'editlink', 'rel': 'nofollow', }
+ else:
+ querystr['editor'] = 'text'
+ attrs = {'name': 'texteditlink', 'rel': 'nofollow', }
+
+ return page.link_to(self.request, text=text, querystr=querystr, **attrs)
+
+ def showBothEditLinks(self):
+ """ Return True if both edit links should be displayed """
+ editor = self.request.user.editor_ui
+ if editor == '':
+ editor = self.request.cfg.editor_ui
+ return editor == 'freechoice'
+
+ def guiEditorScript(self, d):
+ """ Return a script that set the gui editor link variables
+
+ The link will be created only when javascript is enabled and
+ the browser is compatible with the editor.
+ """
+ page = d['page']
+ if not (page.isWritable() and
+ self.request.user.may.write(page.page_name) and
+ self.showBothEditLinks() and
+ self.guiworks(page)):
+ return ''
+
+ _ = self.request.getText
+ return """\
+
+""" % {'url': page.url(self.request, querystr={'action': 'edit', 'editor': 'gui', }),
+ 'text': _('Edit (GUI)'),
+ }
+
+ def disabledEdit(self):
+ """ Return a disabled edit link """
+ _ = self.request.getText
+ return ('%s'
+ % _('Immutable Page'))
+
+ def infoLink(self, page):
+ """ Return link to page information """
+ if 'info' in self.request.cfg.actions_excluded:
+ return ""
+
+ _ = self.request.getText
+ return page.link_to(self.request,
+ text=_('Info'),
+ querystr={'action': 'info'}, css_class='nbinfo', rel='nofollow')
+
+ def subscribeLink(self, page):
+ """ Return subscribe/unsubscribe link to valid users
+
+ @rtype: unicode
+ @return: subscribe or unsubscribe link
+ """
+ if not ((self.cfg.mail_enabled or self.cfg.jabber_enabled) and self.request.user.valid):
+ return ''
+
+ _ = self.request.getText
+ if self.request.user.isSubscribedTo([page.page_name]):
+ action, text = 'unsubscribe', _("Unsubscribe")
+ else:
+ action, text = 'subscribe', _("Subscribe")
+ if action in self.request.cfg.actions_excluded:
+ return ""
+ return page.link_to(self.request, text=text, querystr={'action': action}, css_class='nbsubscribe', rel='nofollow')
+
+ def quicklinkLink(self, page):
+ """ Return add/remove quicklink link
+
+ @rtype: unicode
+ @return: link to add or remove a quicklink
+ """
+ if not self.request.user.valid:
+ return ''
+
+ _ = self.request.getText
+ if self.request.user.isQuickLinkedTo([page.page_name]):
+ action, text = 'quickunlink', _("Remove Link")
+ else:
+ action, text = 'quicklink', _("Add Link")
+ if action in self.request.cfg.actions_excluded:
+ return ""
+ return page.link_to(self.request, text=text, querystr={'action': action}, css_class='nbquicklink', rel='nofollow')
+
+ def attachmentsLink(self, page):
+ """ Return link to page attachments """
+ if 'AttachFile' in self.request.cfg.actions_excluded:
+ return ""
+
+ _ = self.request.getText
+ return page.link_to(self.request,
+ text=_('Attachments'),
+ querystr={'action': 'AttachFile'}, css_class='nbattachments', rel='nofollow')
+
+ def startPage(self):
+ """ Start page div with page language and direction
+
+ @rtype: unicode
+ @return: page div with language and direction attribtues
+ """
+ return u'
\n' % self.content_lang_attr()
+
+ def endPage(self):
+ """ End page div
+
+ Add an empty page bottom div to prevent floating elements to
+ float out of the page bottom over the footer.
+ """
+ return '\n
\n'
+
+ # Public functions #####################################################
+
+ def header(self, d, **kw):
+ """ Assemble page header
+
+ Default behavior is to start a page div. Sub class and add
+ footer items.
+
+ @param d: parameter dictionary
+ @rtype: string
+ @return: page header html
+ """
+ return self.startPage()
+
+ editorheader = header
+
+ def footer(self, d, **keywords):
+ """ Assemble page footer
+
+ Default behavior is to end page div. Sub class and add
+ footer items.
+
+ @param d: parameter dictionary
+ @keyword ...:...
+ @rtype: string
+ @return: page footer html
+ """
+ return self.endPage()
+
+ # RecentChanges ######################################################
+
+ def recentchanges_entry(self, d):
+ """
+ Assemble a single recentchanges entry (table row)
+
+ @param d: parameter dictionary
+ @rtype: string
+ @return: recentchanges entry html
+ """
+ _ = self.request.getText
+ html = []
+ html.append('
\n')
+
+ html.append('
%(icon_html)s
\n' % d)
+
+ html.append('
%(pagelink_html)s
\n' % d)
+
+ html.append('
')
+ if d['time_html']:
+ html.append("%(time_html)s" % d)
+ html.append('
\n')
+
+ html.append('
%(info_html)s
\n' % d)
+
+ html.append('
')
+ if d['editors']:
+ html.append(' '.join(d['editors']))
+ html.append('
\n')
+
+ html.append('
')
+ if d['comments']:
+ if d['changecount'] > 1:
+ notfirst = 0
+ for comment in d['comments']:
+ html.append('%s#%02d %s' % (
+ notfirst and ' ' or '', comment[0], comment[1]))
+ notfirst = 1
+ else:
+ comment = d['comments'][0]
+ html.append('%s' % comment[1])
+ html.append('
'
+ # Add day selector
+ if d['rc_days']:
+ days = []
+ for day in d['rc_days']:
+ if day == d['rc_max_days']:
+ days.append('%d' % day)
+ else:
+ days.append(
+ wikiutil.link_tag(self.request,
+ '%s?max_days=%d' % (d['q_page_name'], day),
+ str(day),
+ self.request.formatter, rel='nofollow'))
+ days = ' | '.join(days)
+ html += (_("Show %s days.") % (days, ))
+
+ if d['rc_update_bookmark']:
+ html += " %(rc_update_bookmark)s %(rc_curr_bookmark)s" % d
+
+ html += '
\n
\n'
+
+ html += '
\n'
+ return html
+
+ def recentchanges_footer(self, d):
+ """
+ Assemble the recentchanges footer (close table)
+
+ @param d: parameter dictionary
+ @rtype: string
+ @return: recentchanges footer html
+ """
+ _ = self.request.getText
+ html = ''
+ html += '
\n'
+ if d['rc_msg']:
+ html += " %(rc_msg)s\n" % d
+ html += '
\n'
+ return html
+
+ # Language stuff ####################################################
+
+ def ui_lang_attr(self):
+ """Generate language attributes for user interface elements
+
+ User interface elements use the user language (if any), kept in
+ request.lang.
+
+ @rtype: string
+ @return: lang and dir html attributes
+ """
+ lang = self.request.lang
+ return ' lang="%s" dir="%s"' % (lang, i18n.getDirection(lang))
+
+ def content_lang_attr(self):
+ """Generate language attributes for wiki page content
+
+ Page content uses the page language or the wiki default language.
+
+ @rtype: string
+ @return: lang and dir html attributes
+ """
+ lang = self.request.content_lang
+ return ' lang="%s" dir="%s"' % (lang, i18n.getDirection(lang))
+
+ def add_msg(self, msg, msg_class=None):
+ """ Adds a message to a list which will be used to generate status
+ information.
+
+ @param msg: additional message
+ @param msg_class: html class for the div of the additional message.
+ """
+ if not msg_class:
+ msg_class = 'dialog'
+ if self._send_title_called:
+ raise Exception("You cannot call add_msg() after send_title()")
+ self._status.append((msg, msg_class))
+
+ # stuff from wikiutil.py
+ def send_title(self, text, **keywords):
+ """
+ Output the page header (and title).
+
+ @param text: the title text
+ @keyword page: the page instance that called us - using this is more efficient than using pagename..
+ @keyword pagename: 'PageName'
+ @keyword print_mode: 1 (or 0)
+ @keyword editor_mode: 1 (or 0)
+ @keyword media: css media type, defaults to 'screen'
+ @keyword allow_doubleclick: 1 (or 0)
+ @keyword html_head: additional code
+ @keyword body_attr: additional attributes
+ @keyword body_onload: additional "onload" JavaScript code
+ """
+ request = self.request
+ _ = request.getText
+ rev = request.rev
+
+ if keywords.has_key('page'):
+ page = keywords['page']
+ pagename = page.page_name
+ else:
+ pagename = keywords.get('pagename', '')
+ page = Page(request, pagename)
+ if keywords.get('msg', ''):
+ raise DeprecationWarning("Using send_page(msg=) is deprecated! Use theme.add_msg() instead!")
+ scriptname = request.getScriptname()
+ pagename_quoted = wikiutil.quoteWikinameURL(pagename)
+
+ # get name of system pages
+ page_front_page = wikiutil.getFrontPage(request).page_name
+ page_help_contents = wikiutil.getLocalizedPage(request, 'HelpContents').page_name
+ page_title_index = wikiutil.getLocalizedPage(request, 'TitleIndex').page_name
+ page_site_navigation = wikiutil.getLocalizedPage(request, 'SiteNavigation').page_name
+ page_word_index = wikiutil.getLocalizedPage(request, 'WordIndex').page_name
+ page_help_formatting = wikiutil.getLocalizedPage(request, 'HelpOnFormatting').page_name
+ page_find_page = wikiutil.getLocalizedPage(request, 'FindPage').page_name
+ home_page = wikiutil.getInterwikiHomePage(request) # sorry theme API change!!! Either None or tuple (wikiname,pagename) now.
+ page_parent_page = getattr(page.getParentPage(), 'page_name', None)
+
+ # Prepare the HTML element
+ user_head = [request.cfg.html_head]
+
+ # include charset information - needed for moin_dump or any other case
+ # when reading the html without a web server
+ user_head.append('''\n''' % (page.output_mimetype, page.output_charset))
+
+ meta_keywords = request.getPragma('keywords')
+ meta_desc = request.getPragma('description')
+ if meta_keywords:
+ user_head.append('\n' % wikiutil.escape(meta_keywords, 1))
+ if meta_desc:
+ user_head.append('\n' % wikiutil.escape(meta_desc, 1))
+
+ # search engine precautions / optimization:
+ # if it is an action or edit/search, send query headers (noindex,nofollow):
+ if request.query_string:
+ user_head.append(request.cfg.html_head_queries)
+ elif request.request_method == 'POST':
+ user_head.append(request.cfg.html_head_posts)
+ # we don't want to have BadContent stuff indexed:
+ elif pagename in ['BadContent', 'LocalBadContent', ]:
+ user_head.append(request.cfg.html_head_posts)
+ # if it is a special page, index it and follow the links - we do it
+ # for the original, English pages as well as for (the possibly
+ # modified) frontpage:
+ elif pagename in [page_front_page, request.cfg.page_front_page,
+ page_title_index, 'TitleIndex',
+ page_find_page, 'FindPage',
+ page_site_navigation, 'SiteNavigation',
+ 'RecentChanges', ]:
+ user_head.append(request.cfg.html_head_index)
+ # if it is a normal page, index it, but do not follow the links, because
+ # there are a lot of illegal links (like actions) or duplicates:
+ else:
+ user_head.append(request.cfg.html_head_normal)
+
+ if 'pi_refresh' in keywords and keywords['pi_refresh']:
+ user_head.append('' % keywords['pi_refresh'])
+
+ # output buffering increases latency but increases throughput as well
+ output = []
+ # later:
+ output.append("""\
+
+
+
+%s
+%s
+%s
+""" % (
+ ''.join(user_head),
+ self.html_head({
+ 'page': page,
+ 'title': text,
+ 'sitename': request.cfg.html_pagetitle or request.cfg.sitename,
+ 'print_mode': keywords.get('print_mode', False),
+ 'media': keywords.get('media', 'screen'),
+ }),
+ keywords.get('html_head', ''),
+ ))
+
+ # Links
+ output.append('\n' % (scriptname, wikiutil.quoteWikinameURL(page_front_page)))
+ if pagename:
+ output.append('\n' % (
+ _('Wiki Markup'), scriptname, pagename_quoted, ))
+ output.append('\n' % (
+ _('Print View'), scriptname, pagename_quoted, ))
+
+ # !!! currently disabled due to Mozilla link prefetching, see
+ # http://www.mozilla.org/projects/netlib/Link_Prefetching_FAQ.html
+ #~ all_pages = request.getPageList()
+ #~ if all_pages:
+ #~ try:
+ #~ pos = all_pages.index(pagename)
+ #~ except ValueError:
+ #~ # this shopuld never happend in theory, but let's be sure
+ #~ pass
+ #~ else:
+ #~ request.write('\n' % (request.getScriptname(), quoteWikinameURL(all_pages[0]))
+ #~ if pos > 0:
+ #~ request.write('\n' % (request.getScriptname(), quoteWikinameURL(all_pages[pos-1])))
+ #~ if pos+1 < len(all_pages):
+ #~ request.write('\n' % (request.getScriptname(), quoteWikinameURL(all_pages[pos+1])))
+ #~ request.write('\n' % (request.getScriptname(), quoteWikinameURL(all_pages[-1])))
+
+ if page_parent_page:
+ output.append('\n' % (scriptname, wikiutil.quoteWikinameURL(page_parent_page)))
+
+ # write buffer because we call AttachFile
+ request.write(''.join(output))
+ output = []
+
+ # XXX maybe this should be removed completely. moin emits all attachments as
+ # and it is at least questionable if this fits into the original intent of rel="Appendix".
+ if pagename and request.user.may.read(pagename):
+ from MoinMoin.action import AttachFile
+ AttachFile.send_link_rel(request, pagename)
+
+ output.extend([
+ '\n' % (scriptname, wikiutil.quoteWikinameURL(page_find_page)),
+ '\n' % (scriptname, wikiutil.quoteWikinameURL(page_title_index)),
+ '\n' % (scriptname, wikiutil.quoteWikinameURL(page_word_index)),
+ '\n' % (scriptname, wikiutil.quoteWikinameURL(page_help_formatting)),
+ ])
+
+ output.append("\n")
+ request.write(''.join(output))
+ output = []
+ request.flush()
+
+ # start the
+ bodyattr = []
+ if keywords.has_key('body_attr'):
+ bodyattr.append(' ')
+ bodyattr.append(keywords['body_attr'])
+
+ # Add doubleclick edit action
+ if (pagename and keywords.get('allow_doubleclick', 0) and
+ not keywords.get('print_mode', 0) and
+ request.user.edit_on_doubleclick):
+ if request.user.may.write(pagename): # separating this gains speed
+ url = page.url(request, {'action': 'edit'})
+ bodyattr.append(''' ondblclick="location.href='%s'" ''' % wikiutil.escape(url, True))
+
+ # Set body to the user interface language and direction
+ bodyattr.append(' %s' % self.ui_lang_attr())
+
+ body_onload = keywords.get('body_onload', '')
+ if body_onload:
+ bodyattr.append(''' onload="%s"''' % body_onload)
+ output.append('\n\n' % ''.join(bodyattr))
+
+ # Output -----------------------------------------------------------
+
+ # If in print mode, start page div and emit the title
+ if keywords.get('print_mode', 0):
+ d = {
+ 'title_text': text,
+ 'page': page,
+ 'page_name': pagename or '',
+ 'rev': rev,
+ }
+ request.themedict = d
+ output.append(self.startPage())
+ output.append(self.interwiki(d))
+ output.append(self.title(d))
+
+ # In standard mode, emit theme.header
+ else:
+ exists = pagename and page.exists(includeDeleted=True)
+ # prepare dict for theme code:
+ d = {
+ 'theme': self.name,
+ 'script_name': scriptname,
+ 'title_text': text,
+ 'logo_string': request.cfg.logo_string,
+ 'site_name': request.cfg.sitename,
+ 'page': page,
+ 'rev': rev,
+ 'pagesize': pagename and page.size() or 0,
+ # exists checked to avoid creation of empty edit-log for non-existing pages
+ 'last_edit_info': exists and page.lastEditInfo() or '',
+ 'page_name': pagename or '',
+ 'page_find_page': page_find_page,
+ 'page_front_page': page_front_page,
+ 'home_page': home_page,
+ 'page_help_contents': page_help_contents,
+ 'page_help_formatting': page_help_formatting,
+ 'page_parent_page': page_parent_page,
+ 'page_title_index': page_title_index,
+ 'page_word_index': page_word_index,
+ 'user_name': request.user.name,
+ 'user_valid': request.user.valid,
+ 'msg': self._status,
+ 'trail': keywords.get('trail', None),
+ # Discontinued keys, keep for a while for 3rd party theme developers
+ 'titlesearch': 'use self.searchform(d)',
+ 'textsearch': 'use self.searchform(d)',
+ 'navibar': ['use self.navibar(d)'],
+ 'available_actions': ['use self.request.availableActions(page)'],
+ }
+
+ # add quoted versions of pagenames
+ newdict = {}
+ for key in d:
+ if key.startswith('page_'):
+ if not d[key] is None:
+ newdict['q_'+key] = wikiutil.quoteWikinameURL(d[key])
+ else:
+ newdict['q_'+key] = None
+ d.update(newdict)
+ request.themedict = d
+
+ # now call the theming code to do the rendering
+ if keywords.get('editor_mode', 0):
+ output.append(self.editorheader(d))
+ else:
+ output.append(self.header(d))
+
+ # emit it
+ request.write(''.join(output))
+ output = []
+ request.flush()
+ self._send_title_called = True
+
+ def send_footer(self, pagename, **keywords):
+ """
+ Output the page footer.
+
+ @param pagename: WikiName of the page
+ @keyword print_mode: true, when page is displayed in Print mode
+ """
+ request = self.request
+ d = request.themedict
+
+ # Emit end of page in print mode, or complete footer in standard mode
+ if keywords.get('print_mode', 0):
+ request.write(self.pageinfo(d['page']))
+ request.write(self.endPage())
+ else:
+ request.write(self.footer(d, **keywords))
+
+ # stuff moved from request.py
+ def send_closing_html(self):
+ """ generate timing info html and closing html tag,
+ everyone calling send_title must call this at the end to close
+ the body and html tags.
+ """
+ request = self.request
+
+ # as this is the last chance to emit some html, we stop the clocks:
+ request.clock.stop('run')
+ request.clock.stop('total')
+
+ # Close html code
+ if request.cfg.show_timings and request.action != 'print':
+ request.write('
\n')
+ for t in request.clock.dump():
+ request.write('
',
+
+ # Post header custom html (not recommended)
+ self.emit_custom_html(self.cfg.page_header2),
+
+ # Start of page
+ self.startPage(),
+ ]
+ return u'\n'.join(html)
+
+ def editorheader(self, d, **kw):
+ """ Assemble wiki header for editor
+
+ @param d: parameter dictionary
+ @rtype: unicode
+ @return: page header html
+ """
+ html = [
+ # Pre header custom html
+ self.emit_custom_html(self.cfg.page_header1),
+
+ # Header
+ u'
',
+ u'
',
+ self.title(d),
+ u'
',
+ self.msg(d),
+ u'
',
+
+ # Post header custom html (not recommended)
+ self.emit_custom_html(self.cfg.page_header2),
+
+ # Start of page
+ self.startPage(),
+ ]
+ return u'\n'.join(html)
+
+ def footer(self, d, **keywords):
+ """ Assemble wiki footer
+
+ @param d: parameter dictionary
+ @keyword ...:...
+ @rtype: unicode
+ @return: page footer html
+ """
+ page = d['page']
+ html = [
+ # End of page
+ self.pageinfo(page),
+ self.endPage(),
+
+ # Pre footer custom html (not recommended!)
+ self.emit_custom_html(self.cfg.page_footer1),
+
+ # Footer
+ u'',
+
+ # Post footer custom html
+ self.emit_custom_html(self.cfg.page_footer2),
+ ]
+ return u'\n'.join(html)
+
+ def title(self, d):
+ """ Assemble the title (now using breadcrumbs)
+
+ @param d: parameter dictionary
+ @rtype: string
+ @return: title html
+ """
+ _ = self.request.getText
+ content = []
+ if d['title_text'] == d['page'].split_title(): # just showing a page, no action
+ curpage = ''
+ segments = d['page_name'].split('/') # was: title_text
+ for s in segments[:-1]:
+ curpage += s
+ content.append(Page(self.request, curpage).link_to(self.request, s))
+ curpage += '/'
+ link_text = segments[-1]
+ link_title = _('Click to do a full-text search for this title')
+ link_query = {
+ 'action': 'fullsearch',
+ 'value': 'linkto:"%s"' % d['page_name'],
+ 'context': '180',
+ }
+ # we dont use d['title_link'] any more, but make it ourselves:
+ link = d['page'].link_to(self.request, link_text, querystr=link_query, title=link_title, css_class='backlink', rel='nofollow')
+ content.append(link)
+ else:
+ content.append(wikiutil.escape(d['title_text']))
+
+ location_html = u'/'.join(content)
+ html = u'%s' % location_html
+ return html
+
+ def username(self, d):
+ """ Assemble the username / userprefs link
+
+ @param d: parameter dictionary
+ @rtype: unicode
+ @return: username html
+ """
+ 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 and request.user.name:
+ interwiki = wikiutil.getInterwikiHomePage(request)
+ name = request.user.name
+ aliasname = request.user.aliasname
+ if not aliasname:
+ aliasname = name
+ title = "%s @ %s" % (aliasname, interwiki[0])
+ # link to (interwiki) user homepage
+ homelink = (request.formatter.interwikilink(1, title=title, id="userhome", generated=True, *interwiki) +
+ request.formatter.text(name) +
+ request.formatter.interwikilink(0, title=title, id="userhome", *interwiki))
+ userlinks.append(homelink)
+ # link to userprefs action
+ if 'userprefs' not in self.request.cfg.actions_excluded:
+ userlinks.append(d['page'].link_to(request, text=_('Settings'),
+ querystr={'action': 'userprefs'}, id='userprefs', rel='nofollow'))
+
+ if request.user.valid:
+ if request.user.auth_method in request.cfg.auth_can_logout:
+ userlinks.append(d['page'].link_to(request, text=_('Logout'),
+ querystr={'action': 'logout', 'logout': 'logout'}, id='logout', rel='nofollow'))
+ else:
+ query = {'action': 'login'}
+ # special direct-login link if the auth methods want no input
+ if request.cfg.auth_login_inputs == ['special_no_input']:
+ query['login'] = '1'
+ if request.cfg.auth_have_login:
+ userlinks.append(d['page'].link_to(request, text=_("Login"),
+ querystr=query, id='login', rel='nofollow'))
+
+ userlinks_html = u' | '.join(userlinks)
+ html = u'
%s
' % userlinks_html
+ return html
+
+ def trail(self, d):
+ """ Assemble page trail
+
+ @param d: parameter dictionary
+ @rtype: unicode
+ @return: trail html
+ """
+ request = self.request
+ user = request.user
+ html = ''
+ if not user.valid or user.show_page_trail:
+ trail = user.getTrail()
+ if trail:
+ items = []
+ for pagename in trail:
+ try:
+ interwiki, page = wikiutil.split_interwiki(pagename)
+ if interwiki != request.cfg.interwikiname and interwiki != 'Self':
+ link = (self.request.formatter.interwikilink(True, interwiki, page) +
+ self.shortenPagename(page) +
+ self.request.formatter.interwikilink(False, interwiki, page))
+ items.append(link)
+ continue
+ else:
+ pagename = page
+
+ except ValueError:
+ pass
+ page = Page(request, pagename)
+ title = page.split_title()
+ title = self.shortenPagename(title)
+ link = page.link_to(request, title)
+ items.append(link)
+ html = u'
%s
' % u'/'.join(items)
+ return html
+
+ def interwiki(self, d):
+ """ Assemble the interwiki name display, linking to page_front_page
+
+ @param d: parameter dictionary
+ @rtype: string
+ @return: interwiki html
+ """
+ if self.request.cfg.show_interwiki:
+ page = wikiutil.getFrontPage(self.request)
+ text = self.request.cfg.interwikiname or 'Self'
+ link = page.link_to(self.request, text=text, rel='nofollow')
+ html = u'%s: ' % link
+ else:
+ html = u''
+ return html
+
+def execute(request):
+ """
+ Generate and return a theme object
+
+ @param request: the request object
+ @rtype: MoinTheme
+ @return: Theme object
+ """
+ return Theme(request)
+
diff --git a/wikiconfig.py.debwiki b/wikiconfig.py.debwiki
new file mode 100644
index 0000000..df5b982
--- /dev/null
+++ b/wikiconfig.py.debwiki
@@ -0,0 +1,48 @@
+# -*- coding: iso-8859-1 -*-
+"""MoinMoin Desktop Edition (MMDE) - Configuration
+
+ONLY to be used for MMDE - if you run a personal wiki on your notebook or PC.
+
+This is NOT intended for internet or server or multiuser use due to relaxed security settings!
+"""
+import sys, os
+from MoinMoin.config.multiconfig import DefaultConfig
+
+
+class LocalConfig(DefaultConfig):
+ # vvv DON'T TOUCH THIS EXCEPT IF YOU KNOW WHAT YOU DO vvv
+ moinmoin_dir = os.path.abspath(os.path.normpath(os.path.dirname(sys.argv[0])))
+ data_dir = os.path.join(moinmoin_dir, 'wiki', 'data')
+ data_underlay_dir = os.path.join(moinmoin_dir, 'wiki', 'underlay')
+
+ # DesktopEdition = True # give all local users full powers
+ acl_rights_default = u"All:read,write,delete,revert,admin"
+ surge_action_limits = None # no surge protection
+ sitename = u'Debian Wiki'
+ #logo_string = u''
+ page_front_page = u'FrontPage' # change to some better value
+ # ^^^ DON'T TOUCH THIS EXCEPT IF YOU KNOW WHAT YOU DO ^^^
+
+
+ # Add your configuration items here.
+
+ interwikiname = u'DebianWiki'
+ theme_default = u'debwiki'
+ page_header1 = '
'
+
+# DEVELOPERS! Do not add your configuration items there,
+# you could accidentally commit them! Instead, create a
+# wikiconfig_local.py file containing this:
+#
+# from wikiconfig import LocalConfig
+#
+# class Config(LocalConfig):
+# configuration_item_1 = 'value1'
+#
+
+try:
+ from wikiconfig_local import Config
+except ImportError, err:
+ if not str(err).endswith('wikiconfig_local'):
+ raise
+ Config = LocalConfig