Insieme a Leo abbiamo terminato lo sviluppo di un paio di macro per il wiki italiano di Ubuntu.
La prima di queste è la macro [[Indice]], che va a sostituire [[TableOfContents]], fornita di base con MoinMoin. La sintassi della macro di default è molto semplice e prevede un solo parametro facoltativo, ovvero la profondità delle sezioni elencate nell’indice. Ecco un esempio:
[[TableOfContents(2)]]
Il risultato è simile al seguente (lo screen si rifà alla pagina Sicurezza/AppArmor):
Se si sostituisce tale macro con questa
[[Indice(depth=2)]]
Il risultato sarà molto più accattivante:
Oltre al parametro depth ve ne sono altri due, align e style: il primo è utile per specificare il posizionamento della tabella (unico valore non accettato è center), il secondo consente invece di adattare lo stile dell’indice a quello di un determinato portale.
Altro discorso per la macro [[VersioniSupportate]]: prima del nostro intervento per inserire la tabella delle versioni in una pagina bisognava utilizzare la macro [[Include]] con una sintassi simile alla seguente, facendo attenzione a inserire una riga per ogni versione:
[[Include(StrumentiWiki/Versioni)]] [[Include(StrumentiWiki/Hardy)]] [[Include(StrumentiWiki/Gutsy)]] [[Include(StrumentiWiki/Feisty)]] [[Include(StrumentiWiki/Versioni2)]]
Il risultato era rappresentato dall’inclusione, nella pagina corrente, di una tabellina contenente le versioni specificate fra la prima e l’ultima riga. Ora, con la macro [[VersioniSupportate]], tutto è più semplice: basta include, fra i parametri della macro, l’elenco dei nomi in codice delle versioni supportate, come nel seguente esempio:
[[VersioniSupportate(hardy gutsy feisty)]]
Ecco una dimostrazione grafica:
Poichè l’accesso ai sorgenti delle macro non è libero, ho pensato di pubblicare qui tutto il codice modificato insieme con Leo.
Ecco il file Indice.py:
# -*- coding: iso-8859-1 -*- """ MoinMoin - TableOfContents Macro Optional integer argument: maximal depth of listing. @copyright: 2000, 2001, 2002 by Jürgen Hermann <jh@web.de> @license: GNU GPL, see COPYING for details. """ import re, sha from MoinMoin import config, wikiutil #Dependencies = ["page"] Dependencies = ["time"] # works around MoinMoinBugs/TableOfContentsLacksLinks # from macro Include (keep in sync!) _arg_heading = r'(?P<heading>,)\s*(|(?P<hquote>[\'"])(?P<htext>.+?)(?P=hquote))' _arg_level = r',\s*(?P<level>\d*)' _arg_from = r'(,\s*from=(?P<fquote>[\'"])(?P<from>.+?)(?P=fquote))?' _arg_to = r'(,\s*to=(?P<tquote>[\'"])(?P<to>.+?)(?P=tquote))?' _arg_sort = r'(,\s*sort=(?P<sort>(ascending|descending)))?' _arg_items = r'(,\s*items=(?P<items>\d+))?' _arg_skipitems = r'(,\s*skipitems=(?P<skipitems>\d+))?' _arg_titlesonly = r'(,\s*(?P<titlesonly>titlesonly))?' _arg_editlink = r'(,\s*(?P<editlink>editlink))?' _args_re_pattern = r'^(?P<name>[^,]+)(%s(%s)?%s%s%s%s%s%s%s)?$' % ( _arg_heading, _arg_level, _arg_from, _arg_to, _arg_sort, _arg_items, _arg_skipitems, _arg_titlesonly, _arg_editlink) # from Include, too, but with extra htext group around header text _title_re = r"^(?P<heading>(?P<hmarker>=+)\s(?P<htext>.*)\s(?P=hmarker))$" class TableOfContents: """ TOC Macro wraps all global variables without disturbing threads """ def __init__(self, macro, args): self.macro = macro self._ = self.macro.request.getText self.inc_re = re.compile(r"^\[\[Include\((.*)\)\]\]") self.arg_re = re.compile(_args_re_pattern) self.head_re = re.compile(_title_re) # single lines only self.pre_re = re.compile(r'\{\{\{.+?\}\}\}', re.S) self.result = [] self.baseindent = 0 self.indent = 0 self.lineno = 0 self.titles = {} self.include_macro = None self.align_list = ['left', 'right'] self.style_list = ['Server', 'InternetRete', 'AmministrazioneSistema', 'Multimedia', 'Sicurezza', 'Programmazione', 'Giochi', 'Hardware', 'AmbienteGrafico', 'Emulatori', 'Grafica', 'Radioamatori', 'Ufficio', 'Architettura64Bit', 'Installazione'] try: self.mindepth = int(macro.request.getPragma('section-numbers', 1)) except (ValueError, TypeError): self.mindepth = 1 (self.maxdepth, self.align, self.style) = self.__readParams(args) def __args_to_dict(self, args): args_dict = dict() if(args!=None): args_list = args.split() for argument in args_list: if '=' in argument: temp = argument.split('=') args_dict[temp[0]] = temp[1] # else: # altrimenti lancia un'eccezione # raise Exception('ExceptionArguments: l\'argomento "%s" non e\' valido. Utilizzare [[Indice(depth=INTERO align=left|right)]]'% argument ) return args_dict def __readParams(self, args): argsDict = self.__args_to_dict(args) maxdepth = 99 # maxdepth default value align = 'right' # align default value style = '' # style default value if argsDict != {}: # se il dizionario non è vuoto if argsDict.has_key('depth'): # se è stata impostata una profondità... try: maxdepth = max(int(argsDict['depth']), 1) # ...settala except (ValueError, TypeError, KeyError): raise Exception('ExceptionArguments: l\'argomento %s non e\' valido.'% depth ) if argsDict.has_key('align'): if argsDict['align'] in self.align_list: # se è stato impostato un allineamento valido... align = argsDict['align'] # ...settalo else: raise Exception('ExceptionArguments: l\'argomento %s non e\' valido.'% argsDict['align'] ) if argsDict.has_key('style'): # se lo style è personalizzato if argsDict['style'] in self.style_list: # controlla che sia valido style = '-%s' % argsDict['style'] # se lo è, imposta lo style else: # altrimenti lancia un'eccezione raise Exception('ExceptionArguments: l\'argomento %s non e\' valido.'% argsDict['style'] ) return (maxdepth, align, style) # restituisci il risultato def IncludeMacro(self, *args, **kwargs): if self.include_macro is None: self.include_macro = wikiutil.importPlugin(self.macro.request.cfg, 'macro', "Include") return self.pre_re.sub('',apply(self.include_macro, args, kwargs)).split('\n') def run(self): _ = self._ # Just a toc styled style = self.style # Creating header for toc by div structure self.result.append('<div class="toc%s" style="float:%s;">' % (style, self.align)) self.result.append(self.macro.formatter.div(1, css_class=("toc-top-sx%s" % style))) self.result.append(self.macro.formatter.div(0)) self.result.append(self.macro.formatter.div(1, css_class="toc-top-dx%s" % style)) self.result.append(self.macro.formatter.div(0)) self.result.append(self.macro.formatter.div(1)) self.result.append(self.macro.formatter.div(1, css_class="toc-core%s" % style)) self.result.append('<strong>Indice</strong>') # Instead of "Indice", these lines open a <p>, print "Contenuti" and close </p> self.result.append(self.macro.formatter.paragraph(1, css_class="toc-core-heading%s" % style)) #self.result.append(self.macro.formatter.escapedText(_('Contents'))) self.result.append(self.macro.formatter.paragraph(0)) self.process_lines(self.pre_re.sub('',self.macro.parser.raw).split('\n'), self.macro.formatter.page.page_name) # Close pending lists for i in range(self.baseindent, self.indent): self.result.append(self.macro.formatter.listitem(0)) self.result.append(self.macro.formatter.number_list(0)) # Closing toc-core div self.result.append(self.macro.formatter.div(0)) self.result.append(self.macro.formatter.div(0)) # Creting footer for toc by div structure self.result.append(self.macro.formatter.div(1, css_class="toc-bottom-sx%s" % style)) self.result.append(self.macro.formatter.div(0)) self.result.append(self.macro.formatter.div(1, css_class="toc-bottom-dx%s" % style)) self.result.append(self.macro.formatter.div(0)) # Closing toc div self.result.append(self.macro.formatter.div(0)) return ''.join(self.result) def process_lines(self, lines, pagename): for line in lines: # Filter out the headings self.lineno = self.lineno + 1 match = self.inc_re.match(line) if match: # this is an [[Include()]] line. # now parse the included page and do the work on it. ## get heading and level from Include() line. tmp = self.arg_re.match(match.group(1)) if tmp and tmp.group("name"): inc_pagename = tmp.group("name") else: # no pagename? ignore it continue if tmp.group("heading") and tmp.group("hquote"): if tmp.group("htext"): heading = tmp.group("htext") else: heading = inc_pagename if tmp.group("level"): level = int(tmp.group("level")) else: level = 1 inc_page_lines = ["%s %s %s" %("=" * level, heading, "=" * level)] else: inc_page_lines = [] inc_page_lines = inc_page_lines + self.IncludeMacro(self.macro, match.group(1), called_by_toc=1) self.process_lines(inc_page_lines, inc_pagename) else: self.parse_line(line, pagename) def parse_line(self, line, pagename): # FIXME this also finds "headlines" in {{{ code sections }}}: match = self.head_re.match(line) if not match: return title_text = match.group('htext').strip() pntt = pagename + title_text self.titles.setdefault(pntt, 0) self.titles[pntt] += 1 # Get new indent level newindent = len(match.group('hmarker')) if newindent > self.maxdepth: return if newindent < self.mindepth: return if not self.indent: self.baseindent = newindent - 1 self.indent = self.baseindent # Close lists for i in range(0,self.indent-newindent): self.result.append(self.macro.formatter.listitem(0)) self.result.append(self.macro.formatter.number_list(0)) # Open Lists for i in range(0,newindent-self.indent): self.result.append(self.macro.formatter.number_list(1)) self.result.append(self.macro.formatter.listitem(1)) # Add the heading unique_id = '' if self.titles[pntt] > 1: unique_id = '-%d' % (self.titles[pntt],) # close last listitem if same level if self.indent == newindent: self.result.append(self.macro.formatter.listitem(0)) if self.indent >= newindent: self.result.append(self.macro.formatter.listitem(1)) self.result.append(self.macro.formatter.anchorlink(1, "head-" + sha.new(pntt.encode(config.charset)).hexdigest() + unique_id) + self.macro.formatter.text(title_text) + self.macro.formatter.anchorlink(0)) # Set new indent level self.indent = newindent def execute(macro, args): toc=TableOfContents(macro,args) return toc.run()
Infine, il file VersioniSupportate.py, contenente il sorgente della macro [[VersioniSupportate]]:
# -*- coding: iso-8859-1 -*- from MoinMoin import config, wikiutil def execute(self, args): if args == '': raise Exception('ExceptionArguments: inserire il nome di almeno un rilascio di Ubuntu nella macro VersioniSupportate.') pageRelease = { 'dapper': "DapperNoteDiRilascio", 'feisty': "7.04tour", 'gutsy': "GutsyNoteDiRilascio", 'hardy': 'HardyNoteDiRilascio'} numRelease = { 'dapper': " 6.06", 'feisty': " 7.04", 'gutsy': ' 7.10', 'hardy': ' 8.04' } nameRelease = { 'warty': 'deprecated', 'hoary': 'deprecated', 'breezy': 'deprecated', 'edgy': 'deprecated', 'dapper': "Dapper Drake", 'feisty': "Feisty Fawn", 'gutsy': 'Gutsy Gibbon', 'hardy': 'Hardy Heron' } self.result = [] # Creating header self.result.append(self.formatter.div(1, css_class="supported-releases")) self.result.append(self.formatter.div(1, css_class="toc-top-sx")) self.result.append(self.formatter.div(0)) self.result.append(self.formatter.div(1, css_class="toc-top-dx")) self.result.append(self.formatter.div(0)) self.result.append(self.formatter.div(1, css_class="supported-releases-core")) # Preparing to cycle self.result.append('<p class="supported-releases-heading">Versioni supportate:</p>') # Cycling args for arg in args.split(): # If it's a typing mistake if arg not in nameRelease: ## HiHiHi :D :D :D EasterEgg writen with AlessioTreglia help raise Exception('ExceptionRelease: le prestazioni sessuali di MefistoRQ nei confronti di MiloCasagrande non sono state convincenti per avere il rilascio di "%s".'% arg ) pass # If it's deprecated if nameRelease[arg] == 'deprecated': pass else: self.result.append('Ubuntu %s <a href="/%s">%s</a><br />' % (numRelease[arg], pageRelease[arg], nameRelease[arg])) # Closing div supported-release-core self.result.append(self.formatter.div(0)) # Creating footer self.result.append(self.formatter.div(1, css_class="toc-bottom-sx")) self.result.append(self.formatter.div(0)) self.result.append(self.formatter.div(1, css_class="toc-bottom-dx")) self.result.append(self.formatter.div(0)) self.result.append(self.formatter.div(0)) return ''.join(self.result)
Ou, 🙂
Vedo mezzo planet sputtanato con questo post, -.-‘
😛
p.s. Inserisci il file come allegati scaricabili, -.-‘
Avevo inserito il tag `more`, sinceramente non so spiegarmi il perchè…