diff -r 058bb3dc685f -r 0b59724cb3f2 cubicweb/ext/tal.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cubicweb/ext/tal.py Sat Jan 16 13:48:51 2016 +0100 @@ -0,0 +1,273 @@ +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of CubicWeb. +# +# CubicWeb is free software: you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 2.1 of the License, or (at your option) +# any later version. +# +# CubicWeb is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with CubicWeb. If not, see . +"""provides simpleTAL extensions for CubicWeb + +""" + +__docformat__ = "restructuredtext en" + +import sys +import re +from os.path import exists, isdir, join +from logging import getLogger +from StringIO import StringIO + +from simpletal import simpleTAL, simpleTALES + +from logilab.common.decorators import cached + +LOGGER = getLogger('cubicweb.tal') + + +class LoggerAdapter(object): + def __init__(self, tal_logger): + self.tal_logger = tal_logger + + def debug(self, msg): + LOGGER.debug(msg) + + def warn(self, msg): + LOGGER.warning(msg) + + def __getattr__(self, attrname): + return getattr(self.tal_logger, attrname) + + +class CubicWebContext(simpleTALES.Context): + """add facilities to access entity / resultset""" + + def __init__(self, options=None, allowPythonPath=1): + simpleTALES.Context.__init__(self, options, allowPythonPath) + self.log = LoggerAdapter(self.log) + + def update(self, context): + for varname, value in context.items(): + self.addGlobal(varname, value) + + def addRepeat(self, name, var, initialValue): + simpleTALES.Context.addRepeat(self, name, var, initialValue) + +# XXX FIXME need to find a clean to define OPCODE values for extensions +I18N_CONTENT = 18 +I18N_REPLACE = 19 +RQL_EXECUTE = 20 +# simpleTAL uses the OPCODE values to define priority over commands. +# TAL_ITER should have the same priority than TAL_REPEAT (i.e. 3), but +# we can't use the same OPCODE for two different commands without changing +# the simpleTAL implementation. Another solution would be to totally override +# the REPEAT implementation with the ITER one, but some specific operations +# (involving len() for instance) are not implemented for ITER, so we prefer +# to keep both implementations for now, and to fool simpleTAL by using a float +# number between 3 and 4 +TAL_ITER = 3.1 + + +# FIX simpleTAL HTML 4.01 stupidity +# (simpleTAL never closes tags like INPUT, IMG, HR ...) +simpleTAL.HTML_FORBIDDEN_ENDTAG.clear() + +class CubicWebTemplateCompiler(simpleTAL.HTMLTemplateCompiler): + """extends default compiler by adding i18n:content commands""" + + def __init__(self): + simpleTAL.HTMLTemplateCompiler.__init__(self) + self.commandHandler[I18N_CONTENT] = self.compile_cmd_i18n_content + self.commandHandler[I18N_REPLACE] = self.compile_cmd_i18n_replace + self.commandHandler[RQL_EXECUTE] = self.compile_cmd_rql + self.commandHandler[TAL_ITER] = self.compile_cmd_tal_iter + + def setTALPrefix(self, prefix): + simpleTAL.TemplateCompiler.setTALPrefix(self, prefix) + self.tal_attribute_map['i18n:content'] = I18N_CONTENT + self.tal_attribute_map['i18n:replace'] = I18N_REPLACE + self.tal_attribute_map['rql:execute'] = RQL_EXECUTE + self.tal_attribute_map['tal:iter'] = TAL_ITER + + def compile_cmd_i18n_content(self, argument): + # XXX tal:content structure=, text= should we support this ? + structure_flag = 0 + return (I18N_CONTENT, (argument, False, structure_flag, self.endTagSymbol)) + + def compile_cmd_i18n_replace(self, argument): + # XXX tal:content structure=, text= should we support this ? + structure_flag = 0 + return (I18N_CONTENT, (argument, True, structure_flag, self.endTagSymbol)) + + def compile_cmd_rql(self, argument): + return (RQL_EXECUTE, (argument, self.endTagSymbol)) + + def compile_cmd_tal_iter(self, argument): + original_id, (var_name, expression, end_tag_symbol) = \ + simpleTAL.HTMLTemplateCompiler.compileCmdRepeat(self, argument) + return (TAL_ITER, (var_name, expression, self.endTagSymbol)) + + def getTemplate(self): + return CubicWebTemplate(self.commandList, self.macroMap, self.symbolLocationTable) + + def compileCmdAttributes (self, argument): + """XXX modified to support single attribute + definition ending by a ';' + + backport this to simpleTAL + """ + # Compile tal:attributes into attribute command + # Argument: [(attributeName, expression)] + + # Break up the list of attribute settings first + commandArgs = [] + # We only want to match semi-colons that are not escaped + argumentSplitter = re.compile(r'(?