template_data_source.py revision 868fa2fe829687343ffae624259930155e16dbd8
1# Copyright (c) 2012 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import logging 6 7from branch_utility import BranchUtility 8from docs_server_utils import FormatKey 9from file_system import FileNotFoundError 10from third_party.handlebar import Handlebar 11import url_constants 12 13_EXTENSIONS_URL = '/chrome/extensions' 14 15_STRING_CONSTANTS = { 16 'app': 'app', 17 'apps_title': 'Apps', 18 'extension': 'extension', 19 'extensions_title': 'Extensions', 20 'events': 'events', 21 'methods': 'methods', 22 'properties': 'properties', 23 } 24 25def _MakeChannelDict(channel_name): 26 channel_dict = { 27 'channels': [{'name': name} for name in BranchUtility.GetAllChannelNames()], 28 'current': channel_name 29 } 30 for channel in channel_dict['channels']: 31 if channel['name'] == channel_name: 32 channel['isCurrent'] = True 33 return channel_dict 34 35class TemplateDataSource(object): 36 """Renders Handlebar templates, providing them with the context in which to 37 render. 38 39 Also acts as a data source itself, providing partial Handlebar templates to 40 those it renders. 41 42 Each instance of TemplateDataSource is bound to a Request so that it can 43 render templates with request-specific data (such as Accept-Language); use 44 a Factory to cheaply construct these. 45 """ 46 47 class Factory(object): 48 """A factory to create lightweight TemplateDataSource instances bound to 49 individual Requests. 50 """ 51 def __init__(self, 52 channel_name, 53 api_data_source_factory, 54 api_list_data_source_factory, 55 intro_data_source_factory, 56 samples_data_source_factory, 57 sidenav_data_source_factory, 58 compiled_fs_factory, 59 ref_resolver_factory, 60 public_template_path, 61 private_template_path, 62 base_path): 63 self._branch_info = _MakeChannelDict(channel_name) 64 self._api_data_source_factory = api_data_source_factory 65 self._api_list_data_source_factory = api_list_data_source_factory 66 self._intro_data_source_factory = intro_data_source_factory 67 self._samples_data_source_factory = samples_data_source_factory 68 self._sidenav_data_source_factory = sidenav_data_source_factory 69 self._cache = compiled_fs_factory.Create(self._CreateTemplate, 70 TemplateDataSource) 71 self._ref_resolver = ref_resolver_factory.Create() 72 self._public_template_path = public_template_path 73 self._private_template_path = private_template_path 74 self._static_resources = '%s/static' % base_path 75 76 def _CreateTemplate(self, template_name, text): 77 return Handlebar(self._ref_resolver.ResolveAllLinks(text)) 78 79 def Create(self, request, path): 80 """Returns a new TemplateDataSource bound to |request|. 81 """ 82 return TemplateDataSource( 83 self._branch_info, 84 self._api_data_source_factory.Create(request), 85 self._api_list_data_source_factory.Create(), 86 self._intro_data_source_factory.Create(), 87 self._samples_data_source_factory.Create(request), 88 self._sidenav_data_source_factory.Create(path), 89 self._cache, 90 self._public_template_path, 91 self._private_template_path, 92 self._static_resources) 93 94 def __init__(self, 95 branch_info, 96 api_data_source, 97 api_list_data_source, 98 intro_data_source, 99 samples_data_source, 100 sidenav_data_source, 101 cache, 102 public_template_path, 103 private_template_path, 104 static_resources): 105 self._branch_info = branch_info 106 self._api_list_data_source = api_list_data_source 107 self._intro_data_source = intro_data_source 108 self._samples_data_source = samples_data_source 109 self._api_data_source = api_data_source 110 self._sidenav_data_source = sidenav_data_source 111 self._cache = cache 112 self._public_template_path = public_template_path 113 self._private_template_path = private_template_path 114 self._static_resources = static_resources 115 116 def Render(self, template_name): 117 """This method will render a template named |template_name|, fetching all 118 the partial templates needed from |self._cache|. Partials are retrieved 119 from the TemplateDataSource with the |get| method. 120 """ 121 template = self.GetTemplate(self._public_template_path, template_name) 122 if not template: 123 return None 124 # TODO error handling 125 render_data = template.render({ 126 'api_list': self._api_list_data_source, 127 'apis': self._api_data_source, 128 'branchInfo': self._branch_info, 129 'intros': self._intro_data_source, 130 'sidenavs': self._sidenav_data_source, 131 'partials': self, 132 'samples': self._samples_data_source, 133 'static': self._static_resources, 134 'apps_samples_url': url_constants.GITHUB_BASE, 135 # TODO(kalman): this is wrong, it's always getting from trunk, but meh 136 # it hardly ever shows up (only in the "cannot fetch samples" message). 137 # In fact I don't even know if it can show up anymore due the samples data 138 # being persisent. In any case, when the channel distinctions are gone 139 # this can go away, so, double meh. 140 'extensions_samples_url': url_constants.EXTENSIONS_SAMPLES, 141 'strings': _STRING_CONSTANTS, 142 'true': True, 143 'false': False 144 }) 145 if render_data.errors: 146 logging.error('Handlebar error(s) rendering %s:\n%s' % 147 (template_name, ' \n'.join(render_data.errors))) 148 return render_data.text 149 150 def get(self, key): 151 return self.GetTemplate(self._private_template_path, key) 152 153 def GetTemplate(self, base_path, template_name): 154 try: 155 return self._cache.GetFromFile( 156 '/'.join((base_path, FormatKey(template_name)))) 157 except FileNotFoundError as e: 158 return None 159