Fri, 07 Feb 2014 18:21:09 +0100
Implemented template filters 'a' to 'f'.
# -*- coding: utf-8 -*- # Copyright (c) 2014 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the Django tags menu handler. """ import os from PyQt4.QtCore import QObject from PyQt4.QtGui import QMenu, QInputDialog from E5Gui.E5Application import e5App from E5Gui import E5FileDialog from .DjangoTagInputDialog import DjangoTagInputDialog class DjangoTagsMenuHandler(QObject): """ Class implementing the Django tags menu handler. """ def __init__(self, ui, parent=None): """ Constructor @param ui reference to the user interface object (UI.UserInterface) @param parent reference to the parent object (QObject) """ super(DjangoTagsMenuHandler, self).__init__(parent) self.__ui = ui self.__findDialog = None def closeAllWindows(self): """ Public method to close all dialogs managed by the handler. """ if self.__findDialog: self.__findDialog.close() def initMenus(self, mainMenu): """ Public method to initialize the various menus. @param mainMenu reference to the main tags menu (QMenu) """ mainMenu.addAction(self.tr("Django Template Tags Locator"), self.__findTemplateTag) mainMenu.addSeparator() mainMenu.addMenu(self.__initTagsMenu()) mainMenu.addMenu(self.__initFiltersMenu()) def __initTagsMenu(self): """ Private method to initialize the tags menu. @return generated menu (QMenu) """ menu = QMenu(self.tr("Tags")) menu.addAction( self.tr("autoescape - Auto Escape Characters"), lambda: self.__applyTemplate("autoescape")) menu.addSeparator() menu.addAction( self.tr("block - Named Block"), lambda: self.__applyTemplate("block")) menu.addSeparator() menu.addAction( self.tr("comment - Multiline Comment"), lambda: self.__applyTemplate("comment")) menu.addAction( self.tr("csrf_token - Cross Site Request Forgery Token"), lambda: self.__applyTemplate("csrf_token")) menu.addAction( self.tr("cycle - Cycle variables each time used"), lambda: self.__applyTemplate("cycle")) menu.addSeparator() menu.addAction( self.tr("debug - Output Debug Information"), lambda: self.__applyTemplate("debug")) menu.addSeparator() menu.addAction( self.tr("extends - Extend a template with variable contents"), lambda: self.__applyTemplate("extendsvariable")) menu.addAction( self.tr("extends - Extend a template with file"), lambda: self.__applyTemplate("extendsfile")) menu.addSeparator() menu.addAction( self.tr("filter - Filtered Block for one or more filters"), lambda: self.__applyTemplate("filter")) menu.addAction( self.tr("firstof - Outputs first argument variable that is True"), lambda: self.__applyTemplate("firstof")) menu.addAction( self.tr("for - For Loop"), lambda: self.__applyTemplate("for")) menu.addAction( self.tr("for...empty - For Loop with fallback for empty loop"), lambda: self.__applyTemplate("for...empty")) menu.addSeparator() # TODO: add 'if...' templates here menu.addAction( self.tr("include - Render template given by variable"), lambda: self.__applyTemplate("includevariable")) menu.addAction( self.tr("include - Render template given by file name"), lambda: self.__applyTemplate("includefile")) menu.addSeparator() menu.addAction( self.tr("load - Load a custom template tag set"), lambda: self.__applyTemplate("load")) menu.addSeparator() menu.addAction( self.tr("now - Display current date and time"), lambda: self.__applyTemplate("now")) menu.addSeparator() menu.addAction( self.tr("regroup - Regroup list of alike objects by a common" " attribute"), lambda: self.__applyTemplate("regroup")) menu.addSeparator() menu.addAction( self.tr("spaceless - Remove whitespace between HTML tags"), lambda: self.__applyTemplate("spaceless")) menu.addAction( self.tr("ssi - Output contents of a given file into the page"), lambda: self.__applyTemplate("ssi")) menu.addAction( self.tr("ssi - Output contents of a given file into the page" " (dialog selection)"), lambda: self.__applyTemplate("ssifile")) menu.addSeparator() menu.addAction( self.tr("templatetag - Output syntax characters used for" " template"), lambda: self.__applyTemplate("templatetag")) menu.addSeparator() menu.addAction( self.tr("url - Return an absolute path reference"), lambda: self.__applyTemplate("url")) menu.addAction( self.tr("url...as - Return an absolute path reference"), lambda: self.__applyTemplate("urlas")) menu.addSeparator() menu.addAction( self.tr("verbatim - Output block contents without rendering"), lambda: self.__applyTemplate("verbatim")) menu.addSeparator() menu.addAction( self.tr("widthratio - Calculate width ratio"), lambda: self.__applyTemplate("verbatim")) menu.addAction( self.tr("with - Cache a complex variable under a simpler name"), lambda: self.__applyTemplate("verbatim")) self.__tagsMenu = menu return menu def __initFiltersMenu(self): """ Private method to initialize the filters menu. @return generated menu (QMenu) """ menu = QMenu(self.tr("Filters")) menu.addAction( self.tr("add - Add variable or string"), lambda: self.__applyTemplate("add")) menu.addAction( self.tr("addslashes - Add slashes before quotes"), lambda: self.__applyTemplate("addslashes")) menu.addSeparator() menu.addAction( self.tr("capfirst - Capitalize first character"), lambda: self.__applyTemplate("capfirst")) menu.addAction( self.tr("center - Center value"), lambda: self.__applyTemplate("center")) menu.addAction( self.tr("cut - Cut characters"), lambda: self.__applyTemplate("cut")) menu.addSeparator() menu.addAction( self.tr("date - Format date"), lambda: self.__applyTemplate("date")) menu.addAction( self.tr("default - Use dafault if False"), lambda: self.__applyTemplate("default")) menu.addAction( self.tr("default_if_none - Use default if None"), lambda: self.__applyTemplate("default_if_none")) menu.addAction( self.tr("dictsort - Sort dictionaries"), lambda: self.__applyTemplate("dictsort")) menu.addAction( self.tr("dictsortreversed - Sort dictionaries reversed"), lambda: self.__applyTemplate("dictsortreversed")) menu.addAction( self.tr("divisibleby - Check divisibility"), lambda: self.__applyTemplate("divisibleby")) menu.addSeparator() menu.addAction( self.tr("escape - Escape as HTML"), lambda: self.__applyTemplate("escape")) menu.addAction( self.tr("escapejs - Escape as JavaScript"), lambda: self.__applyTemplate("escapejs")) menu.addSeparator() menu.addAction( self.tr("filesizeformat - Format file sizes"), lambda: self.__applyTemplate("filesizeformat")) menu.addAction( self.tr("first - First item of a list"), lambda: self.__applyTemplate("first")) menu.addAction( self.tr("fix_ampersands - Replace ampersands"), lambda: self.__applyTemplate("fix_ampersands")) menu.addAction( self.tr("floatformat - Format floating numbers"), lambda: self.__applyTemplate("floatformat")) menu.addAction( self.tr("force_escape - Escape as HTML immediately"), lambda: self.__applyTemplate("force_escape")) menu.addSeparator() self.__filtersMenu = menu return menu def __findTemplateTag(self): """ Private slot to find a template tag and insert its text. """ if self.__findDialog is None: from .FindTemplateTagDialog import FindTemplateTagDialog self.__findDialog = FindTemplateTagDialog() self.__findDialog.tag.connect(self.__applyTemplate) self.__findDialog.show() self.__findDialog.raise_() self.__findDialog.activateWindow() def __applyTemplate(self, tag): """ Private slot to generate and insert the template text. @param tag name of the tag to insert (string) """ editor = e5App().getObject("ViewManager").activeWindow() if editor is None: return templateText, replace = self.__generateTemplateText( tag, editor.selectedText()) if templateText: editor.beginUndoAction() if replace: editor.replaceSelectedText(templateText) else: editor.insert(templateText) editor.endUndoAction() def __generateTemplateText(self, tag, selectedText): """ Private slot to generate the template text. @param tag name of the tag to insert (string) @param selectedText selected text of the current editor (string) @return tuple of generated template text (string), a flag indicating to perform a replace operation (boolean) """ # TODO: complete the tag generation logic replace = False # safe value ok = True templateText = "" #################################################### ## Template Tags ## #################################################### if tag == "autoescape": templateText = ( "{{% autoescape on %}} {0} {{% endautoescape %}}".format( selectedText)) replace = True elif tag == "block": data, ok = DjangoTagInputDialog.getText( None, self.tr("Named Block"), [self.tr("Enter block name:")], ["block_name"]) if ok: templateText = "{{% block {0} %}} {1} {{% endblock %}}".format( data[0], selectedText) replace = True elif tag == "comment": templateText = "{{% comment %}} {0} {{% endcomment %}}".format( selectedText) replace = True elif tag == "csrf_token": templateText = "{% csrf_token %}" elif tag == "cycle": data, ok = DjangoTagInputDialog.getText( None, self.tr("Cycle Variables"), [self.tr("Enter items to cycle, space separated")], ["item1 item2 item3"]) if ok: templateText = "{{% cycle {0} %}}".format(data[0]) elif tag == "debug": templateText = "{% debug %}" elif tag == "extendsvariable": data, ok = DjangoTagInputDialog.getText( None, self.tr("Extends"), [self.tr("Enter variable name:")], ["variable"]) if ok: templateText = "{{% extends {0} %}}".format(data[0]) elif tag == "extendsfile": data, ok = DjangoTagInputDialog.getText( None, self.tr("Extends"), [self.tr("Enter parent file name:")], ["base.html"]) if ok: templateText = '{{% extends "{0}" %}}'.format(data[0]) elif tag == "filter": data, ok = DjangoTagInputDialog.getText( None, self.tr("Tag Filters"), [self.tr("Multiple filters with arguments, pipes separated:")], ["lower|safe"]) if ok: templateText = ( "{{% filter {0} %}} {1} {{% endfilter %}}".format( data[0], selectedText)) replace = True elif tag == "firstof": data, ok = DjangoTagInputDialog.getText( None, self.tr("First Of"), [self.tr("Enter multiple variables, space separated:"), self.tr("Enter fallback value:")], ["var1 var2", "fallback_value"]) if ok: templateText = ( '{{% filter force_escape %}}{{% firstof {0} "{1}" %}}' ' {2} {{% endfilter %}}'.format( data[0], data[1], selectedText)) replace = True elif tag == "for": data, ok = DjangoTagInputDialog.getText( None, self.tr("For Loop"), [self.tr("Enter variable to use for iteration:"), self.tr("Enter sequence to iterate over:")], ["item", "values"]) if ok: templateText = ( "{{% for {0} in {1} %}} {2} {{% endfor %}}".format( data[0], data[1], selectedText)) replace = True elif tag == "for...empty": data, ok = DjangoTagInputDialog.getText( None, self.tr("For Loop"), [self.tr("Enter variable to use for iteration:"), self.tr("Enter sequence to iterate over:"), self.tr("Enter output to use if loop is empty:")], ["item", "values", '"Nothing."']) if ok: templateText = ( "{{% for {0} in {1} %}} {2} {{% empty %}} {3}" " {{% endfor %}}".format( data[0], data[1], selectedText, data[2])) replace = True elif tag == "includevariable": data, ok = DjangoTagInputDialog.getText( None, self.tr("Include"), [self.tr("Enter variable name:")], ["variable"]) if ok: templateText = '{{% include {0} %}}'.format(data[0]) elif tag == "includefile": data, ok = DjangoTagInputDialog.getText( None, self.tr("Include"), [self.tr("Enter file name:")], ["other.html"]) if ok: templateText = '{{% include "{0}" %}}'.format(data[0]) elif tag == "load": data, ok = DjangoTagInputDialog.getText( None, self.tr("Load"), [self.tr("Enter template tag set to load:")], ["foo bar"]) if ok: templateText = '{{% load "{0}" %}}'.format(data[0]) elif tag == "now": dateformat, ok = QInputDialog.getItem( None, self.tr("Now"), self.tr("Current date time format:"), ["DATETIME_FORMAT", "SHORT_DATETIME_FORMAT", "SHORT_DATE_FORMAT", "DATE_FORMAT"], 0, False) if ok: templateText = '{{% now "{0}" %}}'.format(dateformat) elif tag == "regroup": data, ok = DjangoTagInputDialog.getText( None, self.tr("Regroup List"), [self.tr("List Variable:"), self.tr("Common Attribute:"), self.tr("Name of resulting list:")], ["cities", "country", "country_list"]) if ok: templateText = '{{% regroup {0} by {1} as {2} %}}'.format( data[0], data[1], data[2]) elif tag == "spaceless": templateText = "{{% spaceless %}} {0} {{% endspaceless %}}".format( selectedText) replace = True elif tag == "ssi": data, ok = DjangoTagInputDialog.getText( None, self.tr("SSI"), [self.tr("Full path to template:")], ["/tmp/ssi_template.html"]) if ok: templateText = '{{% ssi "{0}" parsed %}}'.format(data[0]) elif tag == "ssifile": ssi = E5FileDialog.getOpenFileName( None, self.tr("SSI"), os.path.expanduser("~"), self.tr("All Files (*)")) if ssi: templateText = '{{% ssi "{0}" parsed %}}'.format(ssi) elif tag == "templatetag": templatetag, ok = QInputDialog.getItem( None, self.tr("Template Tag"), self.tr("Argument:"), ["block", "variable", "brace", "comment"], 0, False) if ok: templateText = ( '{{% templatetag open{0} %}} {1} {{% templatetag' ' close{0} %}}'.format(templatetag, selectedText)) replace = True elif tag == "url": data, ok = DjangoTagInputDialog.getText( None, self.tr("URL"), [self.tr("View method name:"), self.tr("Optional arguments (space separated):")], ["path.to.some_view", "var1 var2"]) if ok: if data[1]: data[1] = ' ' + data[1] templateText = '{{% url "{0}"{1} %}}'.format( data[0], data[1]) elif tag == "urlas": data, ok = DjangoTagInputDialog.getText( None, self.tr("URL...as"), [self.tr("View method name:"), self.tr("Optional arguments (space separated):"), self.tr("URL name:")], ["path.to.some_view", "var1 var2", "url_name"]) if ok: if data[1]: data[1] = ' ' + data[1] templateText = '{{% url "{0}"{1} as {2} %}}'.format( data[0], data[1], data[2]) elif tag == "verbatim": templateText = "{{% verbatim %}} {0} {{% endverbatim %}}".format( selectedText) replace = True elif tag == "widthratio": data, ok = DjangoTagInputDialog.getText( None, self.tr("Width Ratio"), [self.tr("Variable:"), self.tr("Maximum Value:"), self.tr("Maximum Width:")], ["variable", "max_value", "max_width"]) if ok: templateText = "{{% widthratio {0} {1} {2} %}}".format( data[0], data[1], data[2]) elif tag == "with": data, ok = DjangoTagInputDialog.getText( None, self.tr("Cache Variables"), [self.tr("Variables to cache as key=value (space separated):") ], ["variable1=foo.bar variable2=bar.baz"]) if ok: templateText = '{{% with {0} %}} {1} {{% endwith %}}'.format( data[0], selectedText) #################################################### ## Template Filters ## #################################################### elif tag == "add": data, ok = DjangoTagInputDialog.getText( None, self.tr("Add Variable or String"), [self.tr("Variables or String to add:") ], ["variable"]) if ok: templateText = "|add:{0}".format(data[0]) elif tag == "addslashes": templateText = "|addslashes " elif tag == "capfirst": templateText = "|capfirst " elif tag == "center": width, ok = QInputDialog.getInt( None, self.tr("Center Value"), self.tr("Enter width of the output:"), 10, 1, 99, 1) if ok: templateText = '|center:"{0}"'.format(width) elif tag == "cut": data, ok = DjangoTagInputDialog.getText( None, self.tr("Cut Characters"), [self.tr("Characters to cut:") ], [" "]) if ok: templateText = '|cut:"{0}"'.format(data[0]) elif tag == "date": date, ok = QInputDialog.getItem( None, self.tr("Format Date"), self.tr("Enter date format:"), ["DATETIME_FORMAT", "SHORT_DATETIME_FORMAT", "SHORT_DATE_FORMAT", "DATE_FORMAT"], 0, True) if ok: templateText = '|date:"{0}" '.format(date) elif tag == "default": data, ok = DjangoTagInputDialog.getText( None, self.tr("Default Value if False"), [self.tr("Enter default value if result is False:") ], ["nothing"]) if ok: templateText = '|default:"{0}" '.format(data[0]) elif tag == "default_if_none": data, ok = DjangoTagInputDialog.getText( None, self.tr("Default Value if None"), [self.tr("Enter default value if result is None:") ], ["nothing"]) if ok: templateText = '|default:"{0}" '.format(data[0]) elif tag == "dictsort": data, ok = DjangoTagInputDialog.getText( None, self.tr("Sort Dictionaries"), [self.tr("Enter key to sort on:") ], ["key"]) if ok: templateText = '|dictsort:"{0}" '.format(data[0]) elif tag == "dictsortreversed": data, ok = DjangoTagInputDialog.getText( None, self.tr("Sort Dictionaries reversed"), [self.tr("Enter key to sort on:") ], ["key"]) if ok: templateText = '|dictsortreversed:"{0}" '.format(data[0]) elif tag == "divisibleby": divisor, ok = QInputDialog.getInt( None, self.tr("Check Divisibility"), self.tr("Enter divisor value:"), 2, 1, 99, 1) if ok: templateText = '|divisibleby:"{0}" '.format(divisor) elif tag == "escape": templateText = '|escape ' elif tag == "escapejs": templateText = '|escapejs ' elif tag == "filesizeformat": templateText = '|filesizeformat ' elif tag == "first": templateText = '|first ' elif tag == "fix_ampersands": templateText = '|fix_ampersands ' elif tag == "floatformat": decimals, ok = QInputDialog.getInt( None, self.tr("Format Floating Number"), self.tr("Enter number of decimal places:"), 2, -20, 20, 1) if ok: templateText = '|floatformat:"{0}" '.format(decimals) elif tag == "force_escape": templateText = '|force_escape ' #################################################### ## Fallback: return just the tag name ## #################################################### else: templateText = tag return templateText, replace