Mercurial > p > roundup > code
comparison roundup/cgi/templating.py @ 4740:fe9568a6cbd6
Untangle template selection logic from template loading functionality.
| author | anatoly techtonik <techtonik@gmail.com> |
|---|---|
| date | Tue, 15 Jan 2013 00:10:01 +0300 |
| parents | dfa516063571 |
| children | 9cc6d463cfbe |
comparison
equal
deleted
inserted
replaced
| 4739:94be76e04140 | 4740:fe9568a6cbd6 |
|---|---|
| 75 def __str__(self): | 75 def __str__(self): |
| 76 return self._('You are not allowed to %(action)s ' | 76 return self._('You are not allowed to %(action)s ' |
| 77 'items of class %(class)s') % { | 77 'items of class %(class)s') % { |
| 78 'action': self.action, 'class': self.klass} | 78 'action': self.action, 'class': self.klass} |
| 79 | 79 |
| 80 def find_template(dir, name, view): | |
| 81 """ Find a template in the nominated dir | |
| 82 """ | |
| 83 # find the source | |
| 84 if view: | |
| 85 filename = '%s.%s'%(name, view) | |
| 86 else: | |
| 87 filename = name | |
| 88 | |
| 89 # try old-style | |
| 90 src = os.path.join(dir, filename) | |
| 91 if os.path.exists(src): | |
| 92 return (src, filename) | |
| 93 | |
| 94 # try with a .html or .xml extension (new-style) | |
| 95 for extension in '.html', '.xml': | |
| 96 f = filename + extension | |
| 97 src = os.path.join(dir, f) | |
| 98 if os.path.exists(src): | |
| 99 return (src, f) | |
| 100 | |
| 101 # no view == no generic template is possible | |
| 102 if not view: | |
| 103 raise NoTemplate, 'Template file "%s" doesn\'t exist'%name | |
| 104 | |
| 105 # try _generic template for the view | |
| 106 generic = '_generic.%s'%view | |
| 107 src = os.path.join(dir, generic) | |
| 108 if os.path.exists(src): | |
| 109 return (src, generic) | |
| 110 | |
| 111 # finally, try _generic.html | |
| 112 generic = generic + '.html' | |
| 113 src = os.path.join(dir, generic) | |
| 114 if os.path.exists(src): | |
| 115 return (src, generic) | |
| 116 | |
| 117 raise NoTemplate('No template file exists for templating "%s" ' | |
| 118 'with template "%s" (neither "%s" nor "%s")'%(name, view, | |
| 119 filename, generic)) | |
| 120 | |
| 121 class LoaderBase: | 80 class LoaderBase: |
| 122 """Base for engine-specific template Loader class.""" | 81 """ Base for engine-specific template Loader class.""" |
| 123 def precompileTemplates(self): | 82 def precompileTemplates(self): |
| 124 """ Go through a directory and precompile all the templates therein | 83 """ Go through a directory and precompile all the templates therein |
| 125 """ | 84 """ |
| 126 for filename in os.listdir(self.dir): | 85 for filename in os.listdir(self.dir): |
| 127 # skip subdirs | 86 # skip subdirs |
| 135 else: | 94 else: |
| 136 continue | 95 continue |
| 137 | 96 |
| 138 # remove extension | 97 # remove extension |
| 139 filename = filename[:-len(extension)] | 98 filename = filename[:-len(extension)] |
| 140 | 99 self.load(filename) |
| 141 # load the template | 100 |
| 142 if '.' in filename: | 101 def load(self, tplname): |
| 143 name, view = filename.split('.', 1) | |
| 144 self.load(name, view) | |
| 145 else: | |
| 146 self.load(filename, None) | |
| 147 | |
| 148 def load(self, name, view=None): | |
| 149 """ Load template and return template object with render() method. | 102 """ Load template and return template object with render() method. |
| 150 | 103 |
| 151 "name" and "view" are used to select the template, which in | 104 "tplname" is a template name. For filesystem loaders it is a |
| 152 most cases will be "name.view". If "view" is None, then a | 105 filename without extensions, typically in the "classname.view" |
| 153 template called "name" will be selected. | 106 format. |
| 154 | 107 """ |
| 155 If the file "name.view" doesn't exist, we look for | 108 raise NotImplementedError |
| 156 "_generic.view" as a fallback. | 109 |
| 157 """ | 110 def check(self, name): |
| 158 # [ ] document default 'home' template and other special pages | 111 """ Check if template with the given name exists. Return None or |
| 112 a tuple (src, filename) that can be reused in load() method. | |
| 113 """ | |
| 159 raise NotImplementedError | 114 raise NotImplementedError |
| 160 | 115 |
| 161 def __getitem__(self, name): | 116 def __getitem__(self, name): |
| 162 """Special method to access templates by loader['name']""" | 117 """Special method to access templates by loader['name']""" |
| 163 view = None | |
| 164 if '.' in name: | |
| 165 name, view = name.split('.', 1) | |
| 166 try: | 118 try: |
| 167 return self.load(name, view) | 119 return self.load(name) |
| 168 except NoTemplate, message: | 120 except NoTemplate, message: |
| 169 raise KeyError, message | 121 raise KeyError, message |
| 122 | |
| 170 | 123 |
| 171 def get_loader(dir, engine_name): | 124 def get_loader(dir, engine_name): |
| 172 if engine_name == 'chameleon': | 125 if engine_name == 'chameleon': |
| 173 import engine_chameleon as engine | 126 import engine_chameleon as engine |
| 174 else: | 127 else: |
| 698 req = HTMLRequest(self._client) | 651 req = HTMLRequest(self._client) |
| 699 req.classname = self.classname | 652 req.classname = self.classname |
| 700 req.update(kwargs) | 653 req.update(kwargs) |
| 701 | 654 |
| 702 # new template, using the specified classname and request | 655 # new template, using the specified classname and request |
| 703 pt = self._client.instance.templates.load(self.classname, name) | 656 # [ ] this code is too similar to client.renderContext() |
| 657 tplname = self._client.selectTemplate(self.classname, name) | |
| 658 pt = self._client.instance.templates.load(tplname) | |
| 704 | 659 |
| 705 # use our fabricated request | 660 # use our fabricated request |
| 706 args = { | 661 args = { |
| 707 'ok_message': self._client.ok_message, | 662 'ok_message': self._client.ok_message, |
| 708 'error_message': self._client.error_message | 663 'error_message': self._client.error_message |
| 843 # make link if hrefable | 798 # make link if hrefable |
| 844 if (self._props.has_key(prop_n) and | 799 if (self._props.has_key(prop_n) and |
| 845 isinstance(self._props[prop_n], hyperdb.Link)): | 800 isinstance(self._props[prop_n], hyperdb.Link)): |
| 846 classname = self._props[prop_n].classname | 801 classname = self._props[prop_n].classname |
| 847 try: | 802 try: |
| 848 template = find_template(self._db.config.TEMPLATES, | 803 template = self._client.selectTemplate(classname, 'item') |
| 849 classname, 'item') | 804 if template.startswith('_generic.'): |
| 850 if template[1].startswith('_generic'): | |
| 851 raise NoTemplate, 'not really...' | 805 raise NoTemplate, 'not really...' |
| 852 except NoTemplate: | 806 except NoTemplate: |
| 853 pass | 807 pass |
| 854 else: | 808 else: |
| 855 id = self._klass.get(self._nodeid, prop_n, None) | 809 id = self._klass.get(self._nodeid, prop_n, None) |
| 915 comments[classname] = self._( | 869 comments[classname] = self._( |
| 916 "The linked class %(classname)s no longer exists" | 870 "The linked class %(classname)s no longer exists" |
| 917 ) % locals() | 871 ) % locals() |
| 918 labelprop = linkcl.labelprop(1) | 872 labelprop = linkcl.labelprop(1) |
| 919 try: | 873 try: |
| 920 template = find_template(self._db.config.TEMPLATES, | 874 template = self._client.selectTemplate(classname, |
| 921 classname, 'item') | 875 'item') |
| 922 if template[1].startswith('_generic'): | 876 if template.startswith('_generic.'): |
| 923 raise NoTemplate, 'not really...' | 877 raise NoTemplate, 'not really...' |
| 924 hrefable = 1 | 878 hrefable = 1 |
| 925 except NoTemplate: | 879 except NoTemplate: |
| 926 hrefable = 0 | 880 hrefable = 0 |
| 927 | 881 |
| 1085 name = self._klass.get(self._nodeid, 'name') | 1039 name = self._klass.get(self._nodeid, 'name') |
| 1086 req.updateFromURL(self._klass.get(self._nodeid, 'url') + | 1040 req.updateFromURL(self._klass.get(self._nodeid, 'url') + |
| 1087 '&@queryname=%s'%urllib.quote(name)) | 1041 '&@queryname=%s'%urllib.quote(name)) |
| 1088 | 1042 |
| 1089 # new template, using the specified classname and request | 1043 # new template, using the specified classname and request |
| 1090 pt = self._client.instance.templates.load(req.classname, 'search') | 1044 # [ ] the custom logic for search page doesn't belong to |
| 1045 # generic templating module (techtonik) | |
| 1046 tplname = self._client.selectTemplate(req.classname, 'search') | |
| 1047 pt = self._client.instance.templates.load(tplname) | |
| 1091 # The context for a search page should be the class, not any | 1048 # The context for a search page should be the class, not any |
| 1092 # node. | 1049 # node. |
| 1093 self._client.nodeid = None | 1050 self._client.nodeid = None |
| 1094 | 1051 |
| 1095 # use our fabricated request | 1052 # use our fabricated request |
