def advanced_ui(macro): """ Returns the code for the advanced search user interface @param macro: current macro instance """ _ = macro._ f = macro.formatter request = macro.request disabledIfMoinSearch = not request.cfg.xapian_search and \ ' disabled="disabled"' or '' search_boxes = ''.join([ f.table_row(1), f.table_cell(1, attrs={ 'rowspan': '5', 'class': 'searchfor' }), f.text(_('Search for items')), f.table_cell(0), ''.join([ ''.join([ f.table_row(1), f.table_cell(1), f.text(txt), f.table_cell(0), f.table_cell(1), f.rawHTML(input_field), f.table_cell(0), f.table_row(0), ]) for txt, input_field in ( (_('containing all the following terms'), '<input type="text" name="and_terms" size="30" value="%s">' % (form_get(request, 'and_terms', escaped=True) or form_get(request, 'value', escaped=True))), (_('containing one or more of the following terms'), '<input type="text" name="or_terms" size="30" value="%s">' % form_get(request, 'or_terms', escaped=True)), (_('not containing the following terms'), '<input type="text" name="not_terms" size="30" value="%s">' % form_get(request, 'not_terms', escaped=True)), #('containing only one of the following terms', # '<input type="text" name="xor_terms" size="30" value="%s">' # % form_get(request, 'xor_terms', escaped=True)), # TODO: dropdown-box? (_('last modified since (e.g. 2 weeks before)'), '<input type="text" name="mtime" size="30" value="%s">' % form_get(request, 'mtime', escaped=True)), ) ]) ]) # category selection categories = form_get(request, 'categories') c_select = makeSelection('categories', [('', _('any category'))] + [(cat, '%s' % cat) for cat in getCategories(request)], categories, 3, True) # language selection searchedlang = form_get(request, 'language') langs = dict([(lang, lmeta['x-language-in-english']) for lang, lmeta in languages.items()]) userlang = macro.request.lang lang_select = makeSelection('language', [('', _('any language')), (userlang, langs[userlang])] + sorted(langs.items(), key=lambda i: i[1]), searchedlang, 3, True) # mimetype selection # mimetypes.types_map has non-ascii encoded bytestrings sometimes! coding = sys.getdefaultencoding( ) # same call used by stdlib mimetypes.py on win32 if coding == 'ascii': # we might get 'ascii' coding = 'utf-8' # but we upgrade to utf-8, which is sometimes used for /etc/mime.types decode = lambda s: s.decode(coding, 'replace' ) # use 'replace' -> never crash mimetype = form_get(request, 'mimetype') mt_select = makeSelection( 'mimetype', [('', _('any mimetype'))] + [(type, 'all %s files' % type) for type in getMimetypes()] + [(decode(m[1]), '*%s - %s' % (decode(m[0]), decode(m[1]))) for m in sorted(mimetypes.types_map.items())], mimetype, 3, True) # misc search options (checkboxes) search_options = ''.join([ ''.join([ f.table_row(1), f.table_cell(1, attrs={'class': 'searchfor'}), txt[0], f.table_cell(0), f.table_cell(1, colspan=2), unicode(txt[1]), txt[2], f.table_cell(0), f.table_row(0), ]) for txt in ((_('Categories'), unicode(c_select), ''), (_('Language'), unicode(lang_select), ''), (_('File Type'), unicode(mt_select), ''), ('', html.INPUT(type='checkbox', name='titlesearch', value='1', checked=form_get(request, 'titlesearch', escaped=True), id='titlesearch'), '<label for="titlesearch">%s</label>' % _('Search only in titles')), ('', html.INPUT(type='checkbox', name='case', value='1', checked=form_get(request, 'case', escaped=True), id='case'), '<label for="case">%s</label>' % _('Case-sensitive search')), ('', html.INPUT(type='checkbox', name='excludeunderlay', value='1', checked=form_get(request, 'excludeunderlay', escaped=True), id='excludeunderlay'), '<label for="excludeunderlay">%s</label>' % _('Exclude underlay')), ('', html.INPUT(type='checkbox', name='nosystemitems', value='1', checked=form_get(request, 'nosystemitems', escaped=True), id='nosystempages'), '<label for="nosystempages">%s</label>' % _('No system items')), ('', html.INPUT(type='checkbox', name='historysearch', value='1', checked=form_get(request, 'historysearch', escaped=True), disabled=(not request.cfg.xapian_search or not request.cfg.xapian_index_history), id='historysearch'), '<label for="historysearch">%s</label>' % _('Search in all page revisions'))) ]) # the dialogue return f.rawHTML('\n'.join([ u'<form method="get" action="%s">' % macro.request.href(macro.request.formatter.page.page_name), u'<div>', u'<input type="hidden" name="action" value="fullsearch">', u'<input type="hidden" name="advancedsearch" value="1">', f.table(1, attrs={'tableclass': 'advancedsearch'}), search_boxes, search_options, f.table_row(1), f.table_cell(1, attrs={ 'class': 'submit', 'colspan': '3' }), u'<input type="submit" value="%s">' % _('Go get it!'), f.table_cell(0), f.table_row(0), f.table(0), u'</div>', u'</form>', ]))
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 from MoinMoin.action import SpellCheck request = self.request form = request.form _ = self._ 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 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 # Did one of the prechecks fail? if msg: request.theme.add_msg(msg, "error") self.send_page() return # Emit http_headers after checks (send_page) request.disableHttpCaching(level=2) # check if we want to load a draft use_draft = None if 'button_load_draft' in form: wanted_draft_timestamp = int(form.get('draft_ts', '0')) if wanted_draft_timestamp: draft = self._load_draft() if draft is not None: draft_timestamp, draft_rev, draft_text = draft if draft_timestamp == wanted_draft_timestamp: use_draft = draft_text # Check for draft / normal / preview submit if use_draft is not None: title = _('Draft of "%(pagename)s"') # Propagate original revision rev = int(form['draft_rev']) self.set_raw_body(use_draft, modified=1) preview = use_draft elif preview is None: title = _('Edit "%(pagename)s"') else: title = _('Preview of "%(pagename)s"') # Propagate original revision rev = request.rev 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']) except StandardError: text_rows = self.cfg.edit_rows if request.user.valid: text_rows = int(request.user.edit_rows) if preview is not None: # 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!""") 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 self.setConflict(bool(conflict_msg)) # Page editing is done using user language request.setContentLanguage(request.lang) # 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() if use_draft: request.write(_("[Content loaded from draft]"), '<br>') 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 'template' in request.values: # If the page does not exist, we try to get the content from the template parameter. template_page = wikiutil.unquoteWikiname(request.values['template']) template_page_escaped = wikiutil.escape(template_page) if request.user.may.read(template_page): raw_body = Page(request, template_page).get_raw_body() if raw_body: request.write(_("[Content of new page loaded from %s]") % (template_page_escaped, ), '<br>') else: request.write(_("[Template %s not found]") % (template_page_escaped, ), '<br>') else: request.write(_("[You may not read %s]") % (template_page_escaped, ), '<br>') # Make backup on previews - but not for new empty pages if not use_draft and preview and raw_body: self._save_draft(raw_body, rev) draft_message = None loadable_draft = False if preview is None: draft = self._load_draft() if draft is not None: draft_timestamp, draft_rev, draft_text = draft if draft_text != raw_body: loadable_draft = True page_rev = rev draft_timestamp_str = request.user.getFormattedDateTime(draft_timestamp) draft_message = _(u"'''<<BR>>Your draft based on revision %(draft_rev)d (saved %(draft_timestamp_str)s) can be loaded instead of the current revision %(page_rev)d by using the load draft button - in case you lost your last edit somehow without saving it.''' A draft gets saved for you when you do a preview, cancel an edit or unsuccessfully save.", wiki=True, percent=True) % locals() # Setup status message status = [kw.get('msg', ''), conflict_msg, edit_lock_message, draft_message] status = [msg for msg in status if msg] status = ' '.join(status) status = Status(request, content=status) request.theme.add_msg(status, "error") request.theme.send_title( title % {'pagename': self.split_title(), }, page=self, html_head=self.lock.locktype and ( PageEditor._countdown_js % { 'countdown_script': request.theme.externalScript('countdown'), 'lock_timeout': lock_timeout, 'lock_expire': lock_expire, 'lock_mins': lock_mins, 'lock_secs': lock_secs, }) or '', editor_mode=1, allow_doubleclick=1, ) request.write(request.formatter.startContent("content")) # Generate default content for new pages if not raw_body: raw_body = _('Describe %s here.') % (self.page_name, ) # send form request.write('<form id="editor" method="post" action="%s#preview">' % ( request.href(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/ request.write('<fieldset style="border:none;padding:0;">') request.write(unicode(html.INPUT(type="hidden", name="action", value="edit"))) # Send revision of the page our edit is based on request.write('<input type="hidden" name="rev" value="%d">' % (rev, )) # Add src format (e.g. 'wiki') into a hidden form field, so that # we can load the correct converter after POSTing. request.write('<input type="hidden" name="format" value="%s">' % self.pi['format']) # Create and send a ticket, so we can check the POST request.write('<input type="hidden" name="ticket" value="%s">' % wikiutil.createTicket(request)) # Save backto in a hidden input backto = request.values.get('backto') if backto: request.write(unicode(html.INPUT(type="hidden", name="backto", value=backto))) # button bar button_spellcheck = '<input class="button" type="submit" name="button_spellcheck" value="%s">' % _('Check Spelling') save_button_text = _('Save Changes') cancel_button_text = _('Cancel') if self.cfg.page_license_enabled: 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.""", wiki=True) % { 'save_button_text': save_button_text, 'cancel_button_text': cancel_button_text, 'license_link': wikiutil.getLocalizedPage(request, self.cfg.page_license_page).link_to(request), }, '</em></p>') 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"> ''' % (save_button_text, _('Preview'), _('Text mode'), )) if loadable_draft: request.write(''' <input class="button" type="submit" name="button_load_draft" value="%s" onClick="flgChange = false;"> <input type="hidden" name="draft_ts" value="%d"> <input type="hidden" name="draft_rev" value="%d"> ''' % (_('Load Draft'), draft_timestamp, draft_rev)) request.write(''' %s <input class="button" type="submit" name="button_cancel" value="%s"> <input type="hidden" name="editor" value="gui"> ''' % (button_spellcheck, cancel_button_text, )) if self.cfg.mail_enabled: request.write(''' <script type="text/javascript"> function toggle_trivial(CheckedBox) { TrivialBoxes = document.getElementsByName("trivial"); for (var i = 0; i < TrivialBoxes.length; i++) TrivialBoxes[i].checked = CheckedBox.checked; } </script> <input type="checkbox" name="trivial" id="chktrivialtop" value="1" %(checked)s onclick="toggle_trivial(this)"> <label for="chktrivialtop">%(label)s</label> ''' % { 'checked': ('', 'checked')[form.get('trivial', '0') == '1'], 'label': _("Trivial change"), }) from MoinMoin.security.textcha import TextCha request.write(TextCha(request).render()) self.sendconfirmleaving() # TODO update state of flgChange to make this work, see PageEditor # Add textarea with page text lang = self.pi.get('language', request.cfg.language_default) contentlangdirection = i18n.getDirection(lang) # 'ltr' or 'rtl' uilanguage = request.lang url_prefix_static = request.cfg.url_prefix_static url_prefix_local = request.cfg.url_prefix_local wikipage = wikiutil.quoteWikinameURL(self.page_name) fckbasepath = request.cfg.url_prefix_fckeditor wikiurl = request.script_root + '/' themepath = '%s/%s' % (url_prefix_static, request.theme.name) smileypath = themepath + '/img' # auto-generating a list for SmileyImages does NOT work from here! text_rows = int(request.user.edit_rows) if not text_rows: # if no specific value is given for editor height, but 0, we # compute the rows from the raw_body line count plus some # extra rows for adding new text in the editor. Maybe this helps # with the "double slider" usability issue, esp. for devices like # the iphone where you can't operate both sliders. current_rows = len(raw_body.split('\n')) text_rows = max(10, int(current_rows * 1.5)) editor_size = text_rows * 22 # 22 height_pixels/line word_rule = self.word_rule() 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_local)s/applets/moinFCKplugins/' ; oFCKeditor.Config['CustomConfigurationsPath'] = '%(url_prefix_local)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, raw_body, format=self.pi['format'], do_cache=False) output = repr(output) if output[0] == 'u': output = output[1:] request.write(output) request.write(""" ; oFCKeditor.Create() ; //--> </script> """) request.write("<p>") request.write(_("Comment:"), ' <input id="editor-comment" type="text" name="comment" value="%s" size="80" maxlength="200">' % ( wikiutil.escape(kw.get('comment', ''), 1), )) request.write("</p>") # Category selection filterfn = self.cfg.cache.page_category_regexact.search cat_pages = request.rootpage.getPageList(filter=filterfn) cat_pages.sort() cat_pages = [wikiutil.pagelinkmarkup(p) for p in cat_pages] cat_pages.insert(0, ('', _('<No addition>'))) request.write("<p>") request.write(_('Add to: %(category)s') % { 'category': unicode(web.makeSelection('category', cat_pages)), }) if self.cfg.mail_enabled: request.write(''' <input type="checkbox" name="trivial" id="chktrivial" value="1" %(checked)s onclick="toggle_trivial(this)"> <label for="chktrivial">%(label)s</label> ''' % { 'checked': ('', 'checked')[form.get('trivial', '0') == '1'], 'label': _("Trivial change"), }) 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') == '1'], 'label': _('Remove trailing whitespace from each line') }) request.write("</p>") badwords_re = None if preview is not None: if 'button_spellcheck' in form or 'button_newwords' in form: badwords, badwords_re, msg = SpellCheck.checkSpelling(self, request, own_form=0) request.write("<p>%s</p>" % msg) request.write('</fieldset>') request.write("</form>") if preview is not None: if staytop: content_id = 'previewbelow' else: content_id = 'preview' self.send_page(content_id=content_id, content_only=1, hilite_re=badwords_re) request.write(request.formatter.endContent()) # end content div request.theme.send_footer(self.page_name) request.theme.send_closing_html()
def testMakeSelectWithSelectedItem(self): """util.web: creating html select with selected item""" expected = self.expected.replace('value="two"', 'selected value="two"') result = unicode(web.makeSelection('test', self.values, 'two', size=1)) assert result == expected
def advanced_ui(macro): """ Returns the code for the advanced search user interface @param macro: current macro instance """ _ = macro._ f = macro.formatter request = macro.request disabledIfMoinSearch = not request.cfg.xapian_search and \ ' disabled="disabled"' or '' search_boxes = ''.join([ f.table_row(1), f.table_cell(1, attrs={'rowspan': '5', 'class': 'searchfor'}), f.text(_('Search for items')), f.table_cell(0), ''.join([''.join([ f.table_row(1), f.table_cell(1), f.text(txt), f.table_cell(0), f.table_cell(1), f.rawHTML(input_field), f.table_cell(0), f.table_row(0), ]) for txt, input_field in ( (_('containing all the following terms'), '<input type="text" name="and_terms" size="30" value="%s">' % (form_get(request, 'and_terms', escaped=True) or form_get(request, 'value', escaped=True))), (_('containing one or more of the following terms'), '<input type="text" name="or_terms" size="30" value="%s">' % form_get(request, 'or_terms', escaped=True)), (_('not containing the following terms'), '<input type="text" name="not_terms" size="30" value="%s">' % form_get(request, 'not_terms', escaped=True)), #('containing only one of the following terms', # '<input type="text" name="xor_terms" size="30" value="%s">' # % form_get(request, 'xor_terms', escaped=True)), # TODO: dropdown-box? (_('last modified since (e.g. 2 weeks before)'), '<input type="text" name="mtime" size="30" value="%s">' % form_get(request, 'mtime', escaped=True)), )]) ]) # category selection categories = form_get(request, 'categories') c_select = makeSelection('categories', [('', _('any category'))] + [(cat, '%s' % cat) for cat in getCategories(request)], categories, 3, True) # language selection searchedlang = form_get(request, 'language') langs = dict([(lang, lmeta['x-language-in-english']) for lang, lmeta in languages.items()]) userlang = macro.request.lang lang_select = makeSelection('language', [('', _('any language')), (userlang, langs[userlang])] + sorted(langs.items(), key=lambda i: i[1]), searchedlang, 3, True) # mimetype selection mimetype = form_get(request, 'mimetype') mt_select = makeSelection('mimetype', [('', _('any mimetype'))] + [(type, 'all %s files' % type) for type in getMimetypes()] + [(m[1], '*%s - %s' % m) for m in sorted(mimetypes.types_map.items())], mimetype, 3, True) # misc search options (checkboxes) search_options = ''.join([ ''.join([ f.table_row(1), f.table_cell(1, attrs={'class': 'searchfor'}), txt[0], f.table_cell(0), f.table_cell(1, colspan=2), unicode(txt[1]), txt[2], f.table_cell(0), f.table_row(0), ]) for txt in ( (_('Categories'), unicode(c_select), ''), (_('Language'), unicode(lang_select), ''), (_('File Type'), unicode(mt_select), ''), ('', html.INPUT(type='checkbox', name='titlesearch', value='1', checked=form_get(request, 'titlesearch', escaped=True), id='titlesearch'), '<label for="titlesearch">%s</label>' % _('Search only in titles')), ('', html.INPUT(type='checkbox', name='case', value='1', checked=form_get(request, 'case', escaped=True), id='case'), '<label for="case">%s</label>' % _('Case-sensitive search')), ('', html.INPUT(type='checkbox', name='excludeunderlay', value='1', checked=form_get(request, 'excludeunderlay', escaped=True), id='excludeunderlay'), '<label for="excludeunderlay">%s</label>' % _('Exclude underlay')), ('', html.INPUT(type='checkbox', name='nosystemitems', value='1', checked=form_get(request, 'nosystemitems', escaped=True), id='nosystempages'), '<label for="nosystempages">%s</label>' % _('No system items')), ('', html.INPUT(type='checkbox', name='historysearch', value='1', checked=form_get(request, 'historysearch', escaped=True), disabled=(not request.cfg.xapian_search or not request.cfg.xapian_index_history), id='historysearch'), '<label for="historysearch">%s</label>' % _('Search in all page revisions')) ) ]) # the dialogue return f.rawHTML('\n'.join([ u'<form method="get" action="%s">' % macro.request.href(macro.request.formatter.page.page_name), u'<div>', u'<input type="hidden" name="action" value="fullsearch">', u'<input type="hidden" name="advancedsearch" value="1">', f.table(1, attrs={'tableclass': 'advancedsearch'}), search_boxes, search_options, f.table_row(1), f.table_cell(1, attrs={'class': 'submit', 'colspan': '3'}), u'<input type="submit" value="%s">' % _('Go get it!'), f.table_cell(0), f.table_row(0), f.table(0), u'</div>', u'</form>', ]))
def testMakeSelectNoSelection2(self): """util.web: creating html select with non existing selection""" expected = self.expected result = unicode(web.makeSelection('test', self.values, 'three', size=1)) assert result == expected
def testMakeSelectWithSelectedItem(self): """util.web: creating html select with selected item""" expected = self.expected.replace('value="two"', 'selected value="two"') result = unicode(web.makeSelection('test', self.values, 'two')) self.assertEqual(result, expected, 'Expected "%(expected)s" but got "%(result)s"' % locals())
def testMakeSelectNoSelection(self): """util.web: creating html select with non existing selection""" expected = self.expected result = unicode(web.makeSelection('test', self.values, 'three')) self.assertEqual(result, expected, 'Expected "%(expected)s" but got "%(result)s"' % locals())
def testMakeSelectNoSelection2(self): """util.web: creating html select with non existing selection""" expected = self.expected result = unicode( web.makeSelection('test', self.values, 'three', size=1)) assert result == expected