from django import template from django.template.base import TextNode, VariableNode, TemplateSyntaxError from copy import copy register = template.Library() @register.tag( name = "menu" ) def do_menu( parser, token ): tag_name, menu_name, opt_name = token.split_contents() return MenuNode( menu_name, opt_name ) class MenuNode( template.Node ): def __init__( self, menu_name, opt_name ): self.menu_name = menu_name self.opt_name = opt_name def _replaceUrlText( self, opt, active ): active_ = copy( active ) for i in range( 0, len( active ) ): node = active_[ i ] if isinstance( node, VariableNode ): if node.filter_expression.token == u'text': active_[ i ] = TextNode( opt[ 1 ][ 0 ].s ) elif node.filter_expression.token == u'url': active_[ i ] = TextNode( opt[ 0 ] ) return active_ def render( self, context ): menu = context[ '_menus' ][ self.menu_name ] active = menu[ '_defmenu_active' ] inactive = menu[ '_defmenu_inactive' ] opts = menu[ '_defmenu_opts' ] opt = opts[ self.opt_name ] result_list = [] for opt_name in opts: opt = opts[ opt_name ] if self.opt_name == opt_name: result_list.append( ( self._replaceUrlText( opt, active ) ).render( context ) ) else: result_list.append( ( self._replaceUrlText( opt, inactive ) ).render( context ) ) result_list.reverse() return " ".join( result_list ) @register.tag( name = 'defmenu' ) def do_defmenu( parser, token ): nodelist = parser.parse( ( 'enddefmenu', ) ) parser.delete_first_token() tag_name, menu_name = token.split_contents() return DefMenuNode( nodelist, menu_name ) class DefMenuNode( template.Node ): def __init__( self, nodelist, menu_name ): self.nodelist = nodelist self.menu_name = menu_name def render( self, context ): output = self.nodelist.render( context ) # applye children here if '_menus' not in context: context[ '_menus' ] = {} menu_name = self.menu_name context[ '_menus' ][ menu_name ] = {} menu = context[ '_menus' ][ menu_name ] try: menu[ '_defmenu_active' ] = context[ '_defmenu_active' ] except KeyError: raise TemplateSyntaxError( "An {% active %} block is not found inside the {% defmenu %} block." ) try: menu[ '_defmenu_inactive' ] = context[ '_defmenu_inactive' ] except KeyError: raise TemplateSyntaxError( "An {% inactive %} block is not found inside the {% defmenu %} block." ) try: menu[ '_defmenu_opts' ] = context[ '_defmenu_opts' ] except KeyError: raise TemplateSyntaxError( "The {% defmenu %} block must have at least one {% opt %} block inside." ) del context[ '_defmenu_active' ] del context[ '_defmenu_inactive' ] del context[ '_defmenu_opts' ] return "" @register.tag( name = 'active' ) def do_active( parser, token ): nodelist = parser.parse( ( 'endactive', ) ) parser.delete_first_token() return ActiveNode( nodelist ) class ActiveNode( template.Node ): def __init__( self, nodelist ): self.nodelist = nodelist def render( self, context ): context[ '_defmenu_active' ] = self.nodelist @register.tag( name = 'inactive' ) def do_inactive( parser, token ): nodelist = parser.parse( ( 'endinactive', ) ) parser.delete_first_token() return InactiveNode( nodelist ) class InactiveNode( template.Node ): def __init__( self, nodelist ): self.nodelist = nodelist def render( self, context ): context[ '_defmenu_inactive' ] = self.nodelist @register.tag( name = 'opt' ) def do_opt( parser, token ): nodelist = parser.parse( ( 'endopt', ) ) parser.delete_first_token() tag_name, name, url = token.split_contents() return OptNode( nodelist, name, url ) class OptNode( template.Node ): def __init__( self, nodelist, name, url ): self.nodelist = nodelist self.name = name self.url = url def render( self, context ): if '_defmenu_opts' not in context: context['_defmenu_opts' ] = {} context[ '_defmenu_opts' ].update( { self.name: ( self.url, self.nodelist ) } )