Commit 5613834a authored by Valentin Samir's avatar Valentin Samir

[wiki] Remets le thème memodump

parent e968b4bc
# -*- coding: iso-8859-1 -*-
"""
MoinMoin - memodump theme
Based on modernized theme in MoinMoin
Config variables:
Following variables and methods in wikiconfig.py will change something in the theme.
memodump_menuoverride
Overrides menu elements.
memodump_menu_def(request)
Additional data dictionary of menu items.
memodump_hidelocation
Overrides list of page names that should have no location area.
e.g. [page_front_page, u'SideBar', ]
References:
How to edit menu items:
https://github.com/dossist/moinmoin-memodump/wiki/EditMenu
Tips:
https://github.com/dossist/moinmoin-memodump/wiki/Tips
@copyright: 2014 dossist.
@license: GNU GPL, see http://www.gnu.org/licenses/gpl for details.
"""
from MoinMoin.theme import ThemeBase
import StringIO, re
from MoinMoin import wikiutil
from MoinMoin.action import get_available_actions
from MoinMoin.Page import Page
class Theme(ThemeBase):
name = "memodump"
_ = lambda x: x # We don't have gettext at this moment, so we fake it
icons = {
# key alt icon filename w h
# FileAttach
'attach': ("%(attach_count)s", "moin-attach.png", 16, 16),
'info': ("[INFO]", "moin-info.png", 16, 16),
'attachimg': (_("[ATTACH]"), "attach.png", 32, 32),
# RecentChanges
'rss': (_("[RSS]"), "moin-rss.png", 16, 16),
'deleted': (_("[DELETED]"), "moin-deleted.png", 16, 16),
'updated': (_("[UPDATED]"), "moin-updated.png", 16, 16),
'renamed': (_("[RENAMED]"), "moin-renamed.png", 16, 16),
'conflict': (_("[CONFLICT]"), "moin-conflict.png", 16, 16),
'new': (_("[NEW]"), "moin-new.png", 16, 16),
'diffrc': (_("[DIFF]"), "moin-diff.png", 16, 16),
# General
'bottom': (_("[BOTTOM]"), "moin-bottom.png", 16, 16),
'top': (_("[TOP]"), "moin-top.png", 16, 16),
'www': ("[WWW]", "moin-www.png", 16, 16),
'mailto': ("[MAILTO]", "moin-email.png", 16, 16),
'news': ("[NEWS]", "moin-news.png", 16, 16),
'telnet': ("[TELNET]", "moin-telnet.png", 16, 16),
'ftp': ("[FTP]", "moin-ftp.png", 16, 16),
'file': ("[FILE]", "moin-ftp.png", 16, 16),
# search forms
'searchbutton': ("[?]", "moin-search.png", 16, 16),
'interwiki': ("[%(wikitag)s]", "moin-inter.png", 16, 16),
# smileys (this is CONTENT, but good looking smileys depend on looking
# adapted to the theme background color and theme style in general)
#vvv == vvv this must be the same for GUI editor converter
'X-(': ("X-(", 'angry.png', 16, 16),
':D': (":D", 'biggrin.png', 16, 16),
'<:(': ("<:(", 'frown.png', 16, 16),
':o': (":o", 'redface.png', 16, 16),
':(': (":(", 'sad.png', 16, 16),
':)': (":)", 'smile.png', 16, 16),
'B)': ("B)", 'smile2.png', 16, 16),
':))': (":))", 'smile3.png', 16, 16),
';)': (";)", 'smile4.png', 16, 16),
'/!\\': ("/!\\", 'alert.png', 16, 16),
'<!>': ("<!>", 'attention.png', 16, 16),
'(!)': ("(!)", 'idea.png', 16, 16),
':-?': (":-?", 'tongue.png', 16, 16),
':\\': (":\\", 'ohwell.png', 16, 16),
'>:>': (">:>", 'devil.png', 16, 16),
'|)': ("|)", 'tired.png', 16, 16),
':-(': (":-(", 'sad.png', 16, 16),
':-)': (":-)", 'smile.png', 16, 16),
'B-)': ("B-)", 'smile2.png', 16, 16),
':-))': (":-))", 'smile3.png', 16, 16),
';-)': (";-)", 'smile4.png', 16, 16),
'|-)': ("|-)", 'tired.png', 16, 16),
'(./)': ("(./)", 'checkmark.png', 16, 16),
'{OK}': ("{OK}", 'thumbs-up.png', 16, 16),
'{X}': ("{X}", 'icon-error.png', 16, 16),
'{i}': ("{i}", 'icon-info.png', 16, 16),
'{1}': ("{1}", 'prio1.png', 15, 13),
'{2}': ("{2}", 'prio2.png', 15, 13),
'{3}': ("{3}", 'prio3.png', 15, 13),
'{*}': ("{*}", 'star_on.png', 16, 16),
'{o}': ("{o}", 'star_off.png', 16, 16),
}
del _
stylesheets = (
# media basename
('all', 'bootstrap.min'),
('all', 'bootstrap-theme.min'),
('all', 'memodump'),
('all', 'moinizer'),
)
stylesheets_print = (
('all', 'bootstrap.min'),
('all', 'bootstrap-theme.min'),
('all', 'memodump'),
('all', 'moinizer'),
('all', 'memoprint'),
)
stylesheets_projection = (
('all', 'bootstrap.min'),
('all', 'bootstrap-theme.min'),
('all', 'memodump'),
('all', 'moinizer'),
('all', 'memoslide'),
)
def header(self, d, **kw):
""" Assemble wiki header
header1: supported.
header2: supported.
@param d: parameter dictionary
@rtype: unicode
@return: page header html
"""
html = u"""
<div id="outbox" class="sidebar-toggle">
<!-- Bootstrap navbar -->
<div class="navbar navbar-inverse navbar-fixed-top navbar-mobile-toggle" role="navigation">
<div class="container">
<!-- Navbar header -->
<div class="navbar-header">
<!-- Sidebar toggler -->
<button type="button" class="btn navbar-btn sidebar-toggler" data-toggle="toggle" data-target=".sidebar-toggle">
<span class="sr-only">Toggle sidebar</span>
<span class="menu-btn-sidebar-toggler sidebar-toggle"></span>
</button>
<!-- Button to show navbar controls when collapsed -->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<!-- Sitename -->
%(sitename)s
</div> <!-- /.navbar-header -->
<!-- Body of navbar -->
<div class="collapse navbar-collapse">
<!-- Navbar elements -->
<ul class="nav navbar-nav navbar-right">
<!-- Comment toggle button -->
%(commentbutton)s
<!-- Edit button -->
%(edit)s
<!-- Search form -->
%(search)s
<!-- Menu -->
%(menu)s
<!-- Login user -->
%(usermenu)s
</ul> <!-- /.navbar-right -->
</div> <!-- /.collapse -->
</div> <!-- /.container -->
</div> <!-- /.navbar -->
<!-- End of navbar -->
<div class="container no-padding" id="pagebox">
%(custom_pre)s
<!-- Sidebar -->
<div class="sidebar-toggle" id="sidebar-curtain">
<div class="sidebar-toggle" id="sidebar-mover">
<div class="sidebar-toggle" id="sidebar" role="navigation">
<!-- SideBar contents -->
%(sidebar)s
<!-- End of SideBar contents -->
%(navilinks)s
%(trail)s
</div> <!-- /#sidebar -->
</div> <!-- /#sidebar-mover -->
</div><div id="contentbox"> <!-- End of Sidebar and Beginning of content -->
%(custom_post)s
%(msg)s
%(location)s
<!-- Page contents -->
""" % {'sitename': self.logo(),
'location': self.location(d),
'menu': self.menu(d),
'usermenu': self.username(d),
'search': self.searchform(d),
'edit': self.editbutton(d),
'commentbutton': self.commentbutton(),
'sidebar': self.sidebar(d),
'trail': self.trail(d),
#'quicklinks': self.quicklinks(d),
'navilinks': self.navibar(d),
'msg': self.msg(d),
'custom_pre': self.emit_custom_html(self.cfg.page_header1), # custom html just below the navbar, not recommended!
'custom_post': self.emit_custom_html(self.cfg.page_header2), # custom html just before the contents, not recommended!
}
return html
def editorheader(self, d, **kw):
"""
header() for edit mode. Just set edit mode flag and call self.header().
"""
d['edit_mode'] = 1
return self.header(d, **kw)
def footer(self, d, **keywords):
""" Assemble wiki footer
footer1: supported.
footer2: supported.
@param d: parameter dictionary
@keyword ...:...
@rtype: unicode
@return: page footer html
"""
page = d['page']
html = u"""
<!-- End of page contents -->
<div class="clearfix"></div>
</div> <!-- /#contentbox -->
<!-- End of content body -->
</div> <!-- /.container, #pagebox -->
</div> <!-- /#outbox -->
<!-- pageinfo -->
<div id="pageinfo-container">
<div class="container">
%(pageinfo)s
</div>
</div>
<!-- End of pageinfo -->
%(custom_pre)s
<!-- Footer -->
<div id="footer">
<div class="container text-right text-muted">
%(credits)s
%(version)s
%(custom_post)s
</div> <!-- /.container -->
</div> <!-- /#footer -->
<!-- End of footer -->
<!-- Bootstrap core JavaScript -->
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="%(prefix)s/%(theme)s/js/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="%(prefix)s/%(theme)s/js/bootstrap.min.js"></script>
<!-- toggle.js by dossist -->
<script src="%(prefix)s/%(theme)s/js/toggle.js"></script>
<!-- Custom script -->
%(script)s
<!-- End of JavaScript -->
""" % {'pageinfo': self.pageinfo(page),
'custom_pre': self.emit_custom_html(self.cfg.page_footer1), # Pre footer custom html (not recommended!)
'credits': self.credits(d),
'version': self.showversion(d, **keywords),
'custom_post': self.emit_custom_html(self.cfg.page_footer2), # In-footer custom html (not recommended!)
'prefix': self.cfg.url_prefix_static,
'theme': self.name,
'script': self.script(),
}
return html
def script(self):
"""
Append in-html script at the bottom of the page body.
"""
return ur"""
<script>
+function ($) {
// Toggle minified navbar under mobile landscape view
$('.navbar-collapse').on('show.bs.collapse', function () {
$('.navbar-mobile-toggle').togglejs('show');
});
$('.navbar-collapse').on('hidden.bs.collapse', function () {
$('.navbar-mobile-toggle').togglejs('hide');
});
//Scroll position fix for hash anchors
var mdAnchorFix = {
escapeRe: /[ !"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~]/g,
escape: function (str) {
return str.replace(mdAnchorFix.escapeRe, '\\$&');
},
rgbRe: /^rgba\(([ \t]*\d{1,3},){3}([ \t]*\d{1,3})\)$/i,
isTransparent: function (rgbstr) {
if (rgbstr === 'transparent') {
return true;
}
rgbMatch = rgbstr.match(mdAnchorFix.rgbRe);
if (rgbMatch) {
return (Number(rgbMatch[2]) ? false : true);
}
return false;
},
navbarHeight: function () {
var height = 0;
var $navbar = $('.navbar');
if ( !mdAnchorFix.isTransparent($navbar.css('background-color'))
&& ($navbar.css('display') !== 'none')
&& ($navbar.css('visibility') !== 'hidden') ) {
height = $navbar.height();
}
return height;
},
jump: function () {
origin = $('#' + mdAnchorFix.escape(location.hash.substr(1))).offset().top;
offset = mdAnchorFix.navbarHeight() + 15;
setTimeout(function () { window.scrollTo(0, origin - offset); }, 1);
},
clickWrapper: function () {
if ( ($(this).attr('href') === location.hash)
|| !('onhashchange' in window.document.body) ) {
setTimeout(function () { $(window).trigger("hashchange"); }, 1);
}
},
};
$('#pagebox a[href^="#"]:not([href="#"])').on("click", mdAnchorFix.clickWrapper);
$(window).on("hashchange", mdAnchorFix.jump);
if (location.hash) setTimeout(function () { mdAnchorFix.jump(); }, 100);
}(jQuery);
</script>
"""
def logo(self):
""" Assemble logo with link to front page
Using <a> tag only instead of wrapping with div
The logo may contain an image and or text or any html markup.
Just note that everything is enclosed in <a> tag.
@rtype: unicode
@return: logo html
"""
html = u''
if self.cfg.logo_string:
page = wikiutil.getFrontPage(self.request)
html = page.link_to_raw(self.request, "Crans", css_class="navbar-brand")
html = u'''
<div class="navbar-brand-wrapper">
%s
</div>
''' % html
return html
def location(self, d):
""" Assemble location area on top of the page content.
Certain pages shouldn't have location area as it feels redundant.
Location area is excluded in FrontPage by default.
Config variable memodump_hidelocation will override the list of pages to have no location area.
"""
html = u''
page = d['page']
pages_hide = [self.request.cfg.page_front_page, ]
try:
pages_hide = self.request.cfg.memodump_hidelocation
except AttributeError:
pass
if not page.page_name in pages_hide:
html = u'''
<div id="location">
%(interwiki)s
%(pagename)s
%(lastupdate)s
</div>
''' % {'interwiki': self.interwiki(d), 'pagename': self.title(d), 'lastupdate': self.lastupdate(d), }
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'<span id="interwiki">%s<span class="sep">:</span></span>' % link
else:
html = u''
return html
def lastupdate(self, d):
""" Return html for last update in location area, if conditions are met. """
_ = self.request.getText
page = d['page']
html = u''
if self.shouldShowPageinfo(page):
info = page.lastEditInfo()
if info:
html = u'<span class="lastupdate">%s %s</span>' % (_('Last updated at'), info['time'])
return html
def searchform(self, d):
"""
assemble HTML code for the search form
@param d: parameter dictionary
@rtype: unicode
@return: search form html
"""
_ = self.request.getText
form = self.request.values
updates = {
'search_label': _('Search:'),
'search_hint': _('Search'),
'search_value': wikiutil.escape(form.get('value', ''), 1),
'search_full_label': _('Text'),
'search_title_label': _('Titles'),
'url': self.request.href(d['page'].page_name)
}
d.update(updates)
html = u'''
<li>
<div class="navbar-form">
<form class="form-search" role="search" id="searchform" method="get" action="%(url)s">
<input type="hidden" name="action" value="fullsearch">
<input type="hidden" name="context" value="180">
<div class="form-group">
<label class="sr-only" for="searchinput">%(search_label)s</label>
<input id="searchinput" type="text" class="form-control form-search" placeholder="%(search_hint)s" name="value" value="%(search_value)s">
</div>
</form>
</div>
</li>
''' % d
return html
def editbutton(self, d):
""" Return an edit button html fragment.
If the user can't edit, return a disabled edit button.
"""
page = d['page']
edit_mode = d.get('edit_mode', 0)
if 'edit' in self.request.cfg.actions_excluded:
return u""
button = u''
li_attr = u''
if not (page.isWritable() and
self.request.user.may.write(page.page_name)):
button = self.disabledEdit()
li_attr = u' class="disabled"'
else:
_ = self.request.getText
querystr = {'action': 'edit'}
text = u'<span class="hidden-sm">%s</span>' % _('Edit')
attrs = {'name': 'editlink', 'rel': 'nofollow', 'css_class': 'menu-nav-edit'}
button = page.link_to_raw(self.request, text=text, querystr=querystr, **attrs)
if edit_mode:
li_attr = u' class="active"'
html = u'''
<li%s>
%s
</li>
''' % (li_attr, button)
return html
def disabledEdit(self):
""" Return a disabled edit link """
_ = self.request.getText
html = u'%s<span class="hidden-sm">%s</span>%s' % (
self.request.formatter.url(1, css="menu-nav-edit"),
_('Immutable Page'),
self.request.formatter.url(0)
)
return html
def commentbutton(self):
"""
Return a comment toggle button html.
Don't check if 'Comment' is present in self.request.cfg.edit_bar
The button is display:none; (i.e. disappeared) by default, but will automatically appear
when default javascript notices there is a comment in the source.
"""
_ = self.request.getText
html = u'''
<li class="toggleCommentsButton navbar-comment-toggle" style="display:none;">
<a href="#" class="menu-nav-comment nbcomment navbar-comment-toggle" rel="nofollow" onClick="toggleComments();return false;" data-toggle="toggle" data-target=".navbar-comment-toggle">
<span class="hidden-sm">%s</span>
</a>
</li>
''' % _('Comments')
return html
def username(self, d):
""" Assemble the username / userprefs link as dropdown menu
Assemble a login link instead in case of no login user.
@param d: parameter dictionary
@rtype: unicode
@return: username html
"""
request = self.request
_ = request.getText
userlinks = []
userbutton = u''
loginbutton = u''
# 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])
# make user button
userbutton = u'%s<span class="nav-maxwidth-100">%s</span><span class="padding"></span><span class="caret"></span>%s' % (
request.formatter.url(1, url="#", css="menu-nav-user dropdown-toggle", **{"data-toggle": "dropdown", "rel": "nofollow"}),
request.formatter.text(name),
request.formatter.url(0),
)
# link to (interwiki) user homepage
wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_interwiki(self.request, *interwiki)
wikiurl = wikiutil.mapURL(self.request, wikiurl)
href = wikiutil.join_wiki(wikiurl, wikitail)
homelink = (request.formatter.url(1, href, title=title, css='menu-dd-userhome', rel="nofollow") +
request.formatter.text(name) +
request.formatter.url(0))
userlinks.append(homelink)
# link to userprefs action
if 'userprefs' not in self.request.cfg.actions_excluded:
userlinks.append(d['page'].link_to_raw(request, text=_('Settings'), css_class='menu-dd-userprefs',
querystr={'action': 'userprefs'}, rel='nofollow'))
# logout link
if request.user.auth_method in request.cfg.auth_can_logout:
userlinks.append(d['page'].link_to_raw(request, text=_('Logout'), css_class='menu-dd-logout',
querystr={'action': 'logout', 'logout': '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:
loginbutton = (d['page'].link_to_raw(request, text=_("Login"),
querystr=query, css_class='menu-nav-login', rel='nofollow'))
if userbutton:
userlinks_html = u'</li>\n <li>'.join(userlinks)
html = u'''
<li class="dropdown">
%s
<ul class="dropdown-menu">
<li>%s</li>
</ul>
</li> <!-- /dropdown -->
''' % (userbutton, userlinks_html)
elif loginbutton:
html = u'''
<li>
%s
</li>
''' % loginbutton
else:
html = u''
return html
def menu(self, d):
"""
Build dropdown menu html. Incompatible with original actionsMenu() method.
Menu can be customized by adding a config variable 'memodump_menuoverride'.
The variable will override the default menu set.
Additional menu definitions are given via config method 'memodump_menu_def(request)'.
See the code below or project wiki for details.
@param d: parameter dictionary
@rtype: string
@return: menu html
"""
request = self.request
_ = request.getText
rev = request.rev
page = d['page']
page_recent_changes = wikiutil.getLocalizedPage(request, u'RecentChanges')
page_find_page = wikiutil.getLocalizedPage(request, u'FindPage')
page_help_contents = wikiutil.getLocalizedPage(request, u'HelpContents')
page_help_formatting = wikiutil.getLocalizedPage(request, u'HelpOnFormatting')
page_help_wikisyntax = wikiutil.getLocalizedPage(request, u'HelpOnMoinWikiSyntax')
page_title_index = wikiutil.getLocalizedPage(request, u'TitleIndex')
page_word_index = wikiutil.getLocalizedPage(request, u'WordIndex')
page_front_page = wikiutil.getFrontPage(request)
page_sidebar = Page(request, request.getPragma('sidebar', u'SideBar'))
quicklink = self.menuQuickLink(page)
subscribe = self.menuSubscribe(page)
try:
menu = request.cfg.memodump_menuoverride
except AttributeError:
# default list of items in dropdown menu.
# menu items are assembled in this order.
# see wiki for detailed info on customization.
menu = [
'===== Navigation =====',
'RecentChanges',
'FindPage',
'LocalSiteMap',
'__separator__',
'===== Help =====',
'HelpContents',
'HelpOnMoinWikiSyntax',
'__separator__',
'===== Display =====',