365 lines
15 KiB
Python
365 lines
15 KiB
Python
# -*- coding: iso-8859-1 -*-
|
||
"""
|
||
MoinMoin - Call the GUI editor (FCKeditor)
|
||
|
||
@copyright: (c) Bastian Blank, Florian Festi, Thomas Waldmann
|
||
@license: GNU GPL, see COPYING for details.
|
||
"""
|
||
|
||
from MoinMoin import PageEditor
|
||
import os, time, codecs, re
|
||
|
||
#### HACK SAUVAGE 1/2
|
||
from MoinMoin import caching, config, user, util, wikiutil, error, search
|
||
#### FIN DU HACK 1/2
|
||
from MoinMoin.Page import Page
|
||
from MoinMoin.widget import html
|
||
from MoinMoin.widget.dialog import Status
|
||
from MoinMoin.logfile import editlog, eventlog
|
||
from MoinMoin.util import filesys
|
||
import MoinMoin.util.web
|
||
import MoinMoin.util.mail
|
||
from MoinMoin.parser.wiki import Parser
|
||
|
||
from StringIO import StringIO
|
||
|
||
def execute(pagename, request):
|
||
if not request.user.may.write(pagename):
|
||
_ = request.getText
|
||
Page(request, pagename).send_page(request,
|
||
msg = _('You are not allowed to edit this page.'))
|
||
return
|
||
|
||
PageGraphicalEditor(request, pagename).sendEditor()
|
||
|
||
|
||
class PageGraphicalEditor(PageEditor.PageEditor):
|
||
|
||
def word_rule(self):
|
||
regex = re.compile(r"\(\?<![^)]*?\)")
|
||
word_rule = regex.sub("", Parser.word_rule)
|
||
return repr(word_rule)[1:]
|
||
|
||
def sendEditor(self, **kw):
|
||
"""
|
||
Send the editor form page.
|
||
|
||
@keyword preview: if given, show this text in preview mode
|
||
@keyword staytop: don't go to #preview
|
||
@keyword comment: comment field (when preview is true)
|
||
"""
|
||
from MoinMoin import i18n
|
||
try:
|
||
from MoinMoin.action import SpellCheck
|
||
except ImportError:
|
||
SpellCheck = None
|
||
|
||
request = self.request
|
||
form = self.request.form
|
||
_ = self._
|
||
self.request.http_headers(self.request.nocache)
|
||
|
||
raw_body = ''
|
||
msg = None
|
||
conflict_msg = None
|
||
edit_lock_message = None
|
||
preview = kw.get('preview', None)
|
||
staytop = kw.get('staytop', 0)
|
||
|
||
# check edit permissions
|
||
if not self.request.user.may.write(self.page_name):
|
||
msg = _('You are not allowed to edit this page.')
|
||
elif not self.isWritable():
|
||
msg = _('Page is immutable!')
|
||
elif self.rev:
|
||
# Trying to edit an old version, this is not possible via
|
||
# the web interface, but catch it just in case...
|
||
msg = _('Cannot edit old revisions!')
|
||
else:
|
||
# try to acquire edit lock
|
||
ok, edit_lock_message = self.lock.acquire()
|
||
if not ok:
|
||
# failed to get the lock
|
||
if preview is not None:
|
||
edit_lock_message = _('The lock you held timed out. Be prepared for editing conflicts!'
|
||
) + "<br>" + edit_lock_message
|
||
else:
|
||
msg = edit_lock_message
|
||
|
||
#### HACK SAUVAGE 2/2
|
||
query = search.QueryParser().parse_query(u'Cat<EFBFBD>gorieEditeurGraphiqueInterdit')
|
||
page = search.Page(request, self.page_name)
|
||
if query.search(page):
|
||
msg = _('You cannot use the graphical editor on this page.')
|
||
#### FIN HACK 2/2
|
||
|
||
# Did one of the prechecks fail?
|
||
if msg:
|
||
self.send_page(self.request, msg=msg)
|
||
return
|
||
|
||
# Check for preview submit
|
||
if preview is None:
|
||
title = _('Edit "%(pagename)s"')
|
||
else:
|
||
title = _('Preview of "%(pagename)s"')
|
||
self.set_raw_body(preview, modified=1)
|
||
|
||
# send header stuff
|
||
lock_timeout = self.lock.timeout / 60
|
||
lock_page = wikiutil.escape(self.page_name, quote=1)
|
||
lock_expire = _("Your edit lock on %(lock_page)s has expired!") % {'lock_page': lock_page}
|
||
lock_mins = _("Your edit lock on %(lock_page)s will expire in # minutes.") % {'lock_page': lock_page}
|
||
lock_secs = _("Your edit lock on %(lock_page)s will expire in # seconds.") % {'lock_page': lock_page}
|
||
|
||
# get request parameters
|
||
try:
|
||
text_rows = int(form['rows'][0])
|
||
except StandardError:
|
||
text_rows = self.cfg.edit_rows
|
||
if self.request.user.valid:
|
||
text_rows = int(self.request.user.edit_rows)
|
||
|
||
if preview is not None:
|
||
# Propagate original revision
|
||
rev = int(form['rev'][0])
|
||
|
||
# Check for editing conflicts
|
||
if not self.exists():
|
||
# page does not exist, are we creating it?
|
||
if rev:
|
||
conflict_msg = _('Someone else deleted this page while you were editing!')
|
||
elif rev != self.current_rev():
|
||
conflict_msg = _('Someone else changed this page while you were editing!')
|
||
if self.mergeEditConflict(rev):
|
||
conflict_msg = _("""Someone else saved this page while you were editing!
|
||
Please review the page and save then. Do not save this page as it is!
|
||
Have a look at the diff of %(difflink)s to see what has been changed.""") % {
|
||
'difflink': self.link_to(self.request,
|
||
querystr='action=diff&rev=%d' % rev)
|
||
}
|
||
rev = self.current_rev()
|
||
if conflict_msg:
|
||
# We don't show preview when in conflict
|
||
preview = None
|
||
|
||
elif self.exists():
|
||
# revision of existing page
|
||
rev = self.current_rev()
|
||
else:
|
||
# page creation
|
||
rev = 0
|
||
|
||
# Page editing is done using user language
|
||
self.request.setContentLanguage(self.request.lang)
|
||
|
||
# Setup status message
|
||
status = [kw.get('msg', ''), conflict_msg, edit_lock_message]
|
||
status = [msg for msg in status if msg]
|
||
status = ' '.join(status)
|
||
status = Status(self.request, content=status)
|
||
|
||
wikiutil.send_title(self.request,
|
||
title % {'pagename': self.split_title(self.request),},
|
||
page=self,
|
||
pagename=self.page_name, msg=status,
|
||
html_head=self.lock.locktype and (
|
||
PageEditor._countdown_js % {
|
||
'countdown_script': self.request.theme.externalScript('countdown'),
|
||
'lock_timeout': lock_timeout,
|
||
'lock_expire': lock_expire,
|
||
'lock_mins': lock_mins,
|
||
'lock_secs': lock_secs,
|
||
}) or '',
|
||
editor_mode=1,
|
||
)
|
||
|
||
self.request.write(self.request.formatter.startContent("content"))
|
||
|
||
# Get the text body for the editor field.
|
||
# TODO: what about deleted pages? show the text of the last revision or use the template?
|
||
if preview is not None:
|
||
raw_body = self.get_raw_body()
|
||
elif self.exists():
|
||
# If the page exists, we get the text from the page.
|
||
# TODO: maybe warn if template argument was ignored because the page exists?
|
||
raw_body = self.get_raw_body()
|
||
elif form.has_key('template'):
|
||
# If the page does not exists, we try to get the content from the template parameter.
|
||
template_page = wikiutil.unquoteWikiname(form['template'][0])
|
||
if self.request.user.may.read(template_page):
|
||
raw_body = Page(self.request, template_page).get_raw_body()
|
||
if raw_body:
|
||
self.request.write(_("[Content of new page loaded from %s]") % (template_page,), '<br>')
|
||
else:
|
||
self.request.write(_("[Template %s not found]") % (template_page,), '<br>')
|
||
else:
|
||
self.request.write(_("[You may not read %s]") % (template_page,), '<br>')
|
||
|
||
# Make backup on previews - but not for new empty pages
|
||
if preview and raw_body:
|
||
self._make_backup(raw_body)
|
||
|
||
# Generate default content for new pages
|
||
if not raw_body:
|
||
raw_body = _('Describe %s here.') % (self.page_name,)
|
||
|
||
# send form
|
||
self.request.write('<form id="editor" method="post" action="%s/%s#preview">' % (
|
||
self.request.getScriptname(),
|
||
wikiutil.quoteWikinameURL(self.page_name),
|
||
))
|
||
|
||
# yet another weird workaround for broken IE6 (it expands the text
|
||
# editor area to the right after you begin to type...). IE sucks...
|
||
# http://fplanque.net/2003/Articles/iecsstextarea/
|
||
self.request.write('<fieldset style="border:none;padding:0;">')
|
||
|
||
self.request.write(unicode(html.INPUT(type="hidden", name="action", value="edit")))
|
||
|
||
# Send revision of the page our edit is based on
|
||
self.request.write('<input type="hidden" name="rev" value="%d">' % (rev,))
|
||
|
||
# Save backto in a hidden input
|
||
backto = form.get('backto', [None])[0]
|
||
if backto:
|
||
self.request.write(unicode(html.INPUT(type="hidden", name="backto", value=backto)))
|
||
|
||
# button bar
|
||
button_spellcheck = (SpellCheck and
|
||
'<input class="button" type="submit" name="button_spellcheck" value="%s">'
|
||
% _('Check Spelling')) or ''
|
||
|
||
save_button_text = _('Save Changes')
|
||
cancel_button_text = _('Cancel')
|
||
|
||
if self.cfg.page_license_enabled:
|
||
self.request.write('<p><em>', _(
|
||
"""By hitting '''%(save_button_text)s''' you put your changes under the %(license_link)s.
|
||
If you don't want that, hit '''%(cancel_button_text)s''' to cancel your changes.""") % {
|
||
'save_button_text': save_button_text,
|
||
'cancel_button_text': cancel_button_text,
|
||
'license_link': wikiutil.getSysPage(self.request, self.cfg.page_license_page).link_to(self.request),
|
||
}, '</em></p>')
|
||
|
||
self.request.write('''
|
||
<input class="button" type="submit" name="button_save" value="%s">
|
||
<input class="button" type="submit" name="button_preview" value="%s">
|
||
<input class="button" type="submit" name="button_switch" value="%s">
|
||
%s
|
||
<input class="button" type="submit" name="button_cancel" value="%s">
|
||
<input type="hidden" name="editor" value="gui">
|
||
''' % (save_button_text, _('Preview'), _('Text mode'), button_spellcheck, cancel_button_text,))
|
||
|
||
self.sendconfirmleaving() # TODO update state of flgChange to make this work, see PageEditor
|
||
|
||
# Add textarea with page text
|
||
|
||
# TODO: currently self.language is None at this point. We have
|
||
# to do processing instructions parsing earlier, or move page
|
||
# language into meta file.
|
||
lang = self.language or self.request.cfg.language_default
|
||
contentlangdirection = i18n.getDirection(lang) # 'ltr' or 'rtl'
|
||
uilanguage = self.request.lang
|
||
url_prefix = self.request.cfg.url_prefix
|
||
wikipage = wikiutil.quoteWikinameURL(self.page_name)
|
||
fckbasepath = url_prefix + '/applets/FCKeditor'
|
||
wikiurl = request.getScriptname()
|
||
if not wikiurl or wikiurl[-1] != '/':
|
||
wikiurl += '/'
|
||
themepath = '%s/%s' % (url_prefix, self.request.theme.name)
|
||
smileypath = themepath + '/img'
|
||
# auto-generating a list for SmileyImages does NOT work from here!
|
||
editor_size = int(request.user.edit_rows) * 22 # 22 height_pixels/line
|
||
word_rule = self.word_rule()
|
||
|
||
self.request.write("""
|
||
<script type="text/javascript" src="%(fckbasepath)s/fckeditor.js"></script>
|
||
<script type="text/javascript">
|
||
<!--
|
||
var oFCKeditor = new FCKeditor( 'savetext', '100%%', %(editor_size)s, 'MoinDefault' ) ;
|
||
oFCKeditor.BasePath= '%(fckbasepath)s/' ;
|
||
oFCKeditor.Config['WikiBasePath'] = '%(wikiurl)s' ;
|
||
oFCKeditor.Config['WikiPage'] = '%(wikipage)s' ;
|
||
oFCKeditor.Config['PluginsPath'] = '%(url_prefix)s/applets/moinFCKplugins/' ;
|
||
oFCKeditor.Config['CustomConfigurationsPath'] = '%(url_prefix)s/applets/moinfckconfig.js' ;
|
||
oFCKeditor.Config['WordRule'] = %(word_rule)s ;
|
||
oFCKeditor.Config['SmileyPath'] = '%(smileypath)s/' ;
|
||
oFCKeditor.Config['EditorAreaCSS'] = '%(themepath)s/css/common.css' ;
|
||
oFCKeditor.Config['SkinPath'] = '%(fckbasepath)s/editor/skins/silver/' ;
|
||
oFCKeditor.Config['AutoDetectLanguage'] = false ;
|
||
oFCKeditor.Config['DefaultLanguage'] = '%(uilanguage)s' ;
|
||
oFCKeditor.Config['ContentLangDirection'] = '%(contentlangdirection)s' ;
|
||
oFCKeditor.Value= """ % locals())
|
||
|
||
from MoinMoin.formatter.text_gedit import Formatter
|
||
self.formatter = Formatter(request)
|
||
self.formatter.page = self
|
||
output = request.redirectedOutput(self.send_page_content, request, Parser, raw_body, do_cache=False)
|
||
output = repr(output)
|
||
if output[0] == 'u':
|
||
output = output[1:]
|
||
request.write(output)
|
||
self.request.write(""" ;
|
||
oFCKeditor.Create() ;
|
||
//-->
|
||
</script>
|
||
""")
|
||
self.request.write("<p>")
|
||
self.request.write(_("Comment:"),
|
||
' <input id="editor-comment" type="text" name="comment" value="%s" maxlength="80">' % (
|
||
wikiutil.escape(kw.get('comment', ''), 1), ))
|
||
self.request.write("</p>")
|
||
|
||
# Category selection
|
||
filter = re.compile(self.cfg.page_category_regex, re.UNICODE).search
|
||
cat_pages = self.request.rootpage.getPageList(filter=filter)
|
||
cat_pages.sort()
|
||
cat_pages = [wikiutil.pagelinkmarkup(p) for p in cat_pages]
|
||
cat_pages.insert(0, ('', _('<No addition>', formatted=False)))
|
||
self.request.write("<p>")
|
||
self.request.write(_('Add to: %(category)s') % {
|
||
'category': unicode(util.web.makeSelection('category', cat_pages)),
|
||
})
|
||
if self.cfg.mail_enabled:
|
||
self.request.write('''
|
||
|
||
<input type="checkbox" name="trivial" id="chktrivial" value="1" %(checked)s>
|
||
<label for="chktrivial">%(label)s</label> ''' % {
|
||
'checked': ('', 'checked')[form.get('trivial',['0'])[0] == '1'],
|
||
'label': _("Trivial change"),
|
||
})
|
||
|
||
self.request.write('''
|
||
|
||
<input type="checkbox" name="rstrip" id="chkrstrip" value="1" %(checked)s>
|
||
<label for="chkrstrip">%(label)s</label>
|
||
</p> ''' % {
|
||
'checked': ('', 'checked')[form.get('rstrip',['0'])[0] == '1'],
|
||
'label': _('Remove trailing whitespace from each line')
|
||
})
|
||
|
||
self.request.write("</p>")
|
||
|
||
badwords_re = None
|
||
if preview is not None:
|
||
if SpellCheck and (
|
||
form.has_key('button_spellcheck') or
|
||
form.has_key('button_newwords')):
|
||
badwords, badwords_re, msg = SpellCheck.checkSpelling(self, self.request, own_form=0)
|
||
self.request.write("<p>%s</p>" % msg)
|
||
self.request.write('</fieldset>')
|
||
self.request.write("</form>")
|
||
|
||
|
||
if preview is not None:
|
||
if staytop:
|
||
content_id = 'previewbelow'
|
||
else:
|
||
content_id = 'preview'
|
||
self.send_page(self.request, content_id=content_id, content_only=1,
|
||
hilite_re=badwords_re)
|
||
|
||
self.request.write(self.request.formatter.endContent()) # end content div
|
||
wikiutil.send_footer(self.request, self.page_name)
|
||
|