1 #!/usr/bin/env python 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 7 from xml.dom import minidom 8 from grit import lazy_re 9 from grit.format.policy_templates.writers import xml_formatted_writer 10 11 12 def GetWriter(config): 13 '''Factory method for creating DocWriter objects. 14 See the constructor of TemplateWriter for description of 15 arguments. 16 ''' 17 return DocWriter(['*'], config) 18 19 20 class DocWriter(xml_formatted_writer.XMLFormattedWriter): 21 '''Class for generating policy templates in HTML format. 22 The intended use of the generated file is to upload it on 23 http://dev.chromium.org, therefore its format has some limitations: 24 - No HTML and body tags. 25 - Restricted set of element attributes: for example no 'class'. 26 Because of the latter the output is styled using the 'style' 27 attributes of HTML elements. This is supported by the dictionary 28 self._STYLES[] and the method self._AddStyledElement(), they try 29 to mimic the functionality of CSS classes. (But without inheritance.) 30 31 This class is invoked by PolicyTemplateGenerator to create the HTML 32 files. 33 ''' 34 35 def _GetLocalizedMessage(self, msg_id): 36 '''Returns a localized message for this writer. 37 38 Args: 39 msg_id: The identifier of the message. 40 41 Returns: 42 The localized message. 43 ''' 44 return self.messages['doc_' + msg_id]['text'] 45 46 def _MapListToString(self, item_map, items): 47 '''Creates a comma-separated list. 48 49 Args: 50 item_map: A dictionary containing all the elements of 'items' as 51 keys. 52 items: A list of arbitrary items. 53 54 Returns: 55 Looks up each item of 'items' in 'item_maps' and concatenates the 56 resulting items into a comma-separated list. 57 ''' 58 return ', '.join([item_map[x] for x in items]) 59 60 def _AddTextWithLinks(self, parent, text): 61 '''Parse a string for URLs and add it to a DOM node with the URLs replaced 62 with <a> HTML links. 63 64 Args: 65 parent: The DOM node to which the text will be added. 66 text: The string to be added. 67 ''' 68 # Iterate through all the URLs and replace them with links. 69 out = [] 70 while True: 71 # Look for the first URL. 72 res = self._url_matcher.search(text) 73 if not res: 74 break 75 # Calculate positions of the substring of the URL. 76 url = res.group(0) 77 start = res.start(0) 78 end = res.end(0) 79 # Add the text prior to the URL. 80 self.AddText(parent, text[:start]) 81 # Add a link for the URL. 82 self.AddElement(parent, 'a', {'href': url}, url) 83 # Drop the part of text that is added. 84 text = text[end:] 85 self.AddText(parent, text) 86 87 88 def _AddStyledElement(self, parent, name, style_ids, attrs=None, text=None): 89 '''Adds an XML element to a parent, with CSS style-sheets included. 90 91 Args: 92 parent: The parent DOM node. 93 name: Name of the element to add. 94 style_ids: A list of CSS style strings from self._STYLE[]. 95 attrs: Dictionary of attributes for the element. 96 text: Text content for the element. 97 ''' 98 if attrs == None: 99 attrs = {} 100 101 style = ''.join([self._STYLE[x] for x in style_ids]) 102 if style != '': 103 # Apply the style specified by style_ids. 104 attrs['style'] = style + attrs.get('style', '') 105 return self.AddElement(parent, name, attrs, text) 106 107 def _AddDescription(self, parent, policy): 108 '''Adds a string containing the description of the policy. URLs are 109 replaced with links and the possible choices are enumerated in case 110 of 'string-enum' and 'int-enum' type policies. 111 112 Args: 113 parent: The DOM node for which the feature list will be added. 114 policy: The data structure of a policy. 115 ''' 116 # Replace URLs with links in the description. 117 self._AddTextWithLinks(parent, policy['desc']) 118 # Add list of enum items. 119 if policy['type'] in ('string-enum', 'int-enum'): 120 ul = self.AddElement(parent, 'ul') 121 for item in policy['items']: 122 if policy['type'] == 'int-enum': 123 value_string = str(item['value']) 124 else: 125 value_string = '"%s"' % item['value'] 126 self.AddElement( 127 ul, 'li', {}, '%s = %s' % (value_string, item['caption'])) 128 129 def _AddFeatures(self, parent, policy): 130 '''Adds a string containing the list of supported features of a policy 131 to a DOM node. The text will look like as: 132 Feature_X: Yes, Feature_Y: No 133 134 Args: 135 parent: The DOM node for which the feature list will be added. 136 policy: The data structure of a policy. 137 ''' 138 features = [] 139 # The sorting is to make the order well-defined for testing. 140 keys = policy['features'].keys() 141 keys.sort() 142 for key in keys: 143 key_name = self._FEATURE_MAP[key] 144 if policy['features'][key]: 145 value_name = self._GetLocalizedMessage('supported') 146 else: 147 value_name = self._GetLocalizedMessage('not_supported') 148 features.append('%s: %s' % (key_name, value_name)) 149 self.AddText(parent, ', '.join(features)) 150 151 def _AddListExampleMac(self, parent, policy): 152 '''Adds an example value for Mac of a 'list' policy to a DOM node. 153 154 Args: 155 parent: The DOM node for which the example will be added. 156 policy: A policy of type 'list', for which the Mac example value 157 is generated. 158 ''' 159 example_value = policy['example_value'] 160 self.AddElement(parent, 'dt', {}, 'Mac:') 161 mac = self._AddStyledElement(parent, 'dd', ['.monospace', '.pre']) 162 163 mac_text = ['<array>'] 164 for item in example_value: 165 mac_text.append(' <string>%s</string>' % item) 166 mac_text.append('</array>') 167 self.AddText(mac, '\n'.join(mac_text)) 168 169 def _AddListExampleWindows(self, parent, policy): 170 '''Adds an example value for Windows of a 'list' policy to a DOM node. 171 172 Args: 173 parent: The DOM node for which the example will be added. 174 policy: A policy of type 'list', for which the Windows example value 175 is generated. 176 ''' 177 example_value = policy['example_value'] 178 self.AddElement(parent, 'dt', {}, 'Windows:') 179 win = self._AddStyledElement(parent, 'dd', ['.monospace', '.pre']) 180 win_text = [] 181 cnt = 1 182 key_name = self.config['win_reg_mandatory_key_name'] 183 for item in example_value: 184 win_text.append( 185 '%s\\%s\\%d = "%s"' % 186 (key_name, policy['name'], cnt, item)) 187 cnt = cnt + 1 188 self.AddText(win, '\n'.join(win_text)) 189 190 def _AddListExampleLinux(self, parent, policy): 191 '''Adds an example value for Linux of a 'list' policy to a DOM node. 192 193 Args: 194 parent: The DOM node for which the example will be added. 195 policy: A policy of type 'list', for which the Linux example value 196 is generated. 197 ''' 198 example_value = policy['example_value'] 199 self.AddElement(parent, 'dt', {}, 'Linux:') 200 linux = self._AddStyledElement(parent, 'dd', ['.monospace']) 201 linux_text = [] 202 for item in example_value: 203 linux_text.append('"%s"' % item) 204 self.AddText(linux, '[%s]' % ', '.join(linux_text)) 205 206 def _AddListExample(self, parent, policy): 207 '''Adds the example value of a 'list' policy to a DOM node. Example output: 208 <dl> 209 <dt>Windows:</dt> 210 <dd> 211 Software\Policies\Chromium\DisabledPlugins\0 = "Java" 212 Software\Policies\Chromium\DisabledPlugins\1 = "Shockwave Flash" 213 </dd> 214 <dt>Linux:</dt> 215 <dd>["Java", "Shockwave Flash"]</dd> 216 <dt>Mac:</dt> 217 <dd> 218 <array> 219 <string>Java</string> 220 <string>Shockwave Flash</string> 221 </array> 222 </dd> 223 </dl> 224 225 Args: 226 parent: The DOM node for which the example will be added. 227 policy: The data structure of a policy. 228 ''' 229 examples = self._AddStyledElement(parent, 'dl', ['dd dl']) 230 if self.IsPolicySupportedOnPlatform(policy, 'win'): 231 self._AddListExampleWindows(examples, policy) 232 if self.IsPolicySupportedOnPlatform(policy, 'linux'): 233 self._AddListExampleLinux(examples, policy) 234 if self.IsPolicySupportedOnPlatform(policy, 'mac'): 235 self._AddListExampleMac(examples, policy) 236 237 def _PythonObjectToPlist(self, obj, indent=''): 238 '''Converts a python object to an equivalent XML plist. 239 240 Returns a list of lines.''' 241 obj_type = type(obj) 242 if obj_type == bool: 243 return [ '%s<%s/>' % (indent, 'true' if obj else 'false') ] 244 elif obj_type == int: 245 return [ '%s<integer>%s</integer>' % (indent, obj) ] 246 elif obj_type == str: 247 return [ '%s<string>%s</string>' % (indent, obj) ] 248 elif obj_type == list: 249 result = [ '%s<array>' % indent ] 250 for item in obj: 251 result += self._PythonObjectToPlist(item, indent + ' ') 252 result.append('%s</array>' % indent) 253 return result 254 elif obj_type == dict: 255 result = [ '%s<dict>' % indent ] 256 for key in sorted(obj.keys()): 257 result.append('%s<key>%s</key>' % (indent + ' ', key)) 258 result += self._PythonObjectToPlist(obj[key], indent + ' ') 259 result.append('%s</dict>' % indent) 260 return result 261 else: 262 raise Exception('Invalid object to convert: %s' % obj) 263 264 def _AddDictionaryExampleMac(self, parent, policy): 265 '''Adds an example value for Mac of a 'dict' policy to a DOM node. 266 267 Args: 268 parent: The DOM node for which the example will be added. 269 policy: A policy of type 'dict', for which the Mac example value 270 is generated. 271 ''' 272 example_value = policy['example_value'] 273 self.AddElement(parent, 'dt', {}, 'Mac:') 274 mac = self._AddStyledElement(parent, 'dd', ['.monospace', '.pre']) 275 mac_text = ['<key>%s</key>' % (policy['name'])] 276 mac_text += self._PythonObjectToPlist(example_value) 277 self.AddText(mac, '\n'.join(mac_text)) 278 279 def _AddDictionaryExampleWindows(self, parent, policy): 280 '''Adds an example value for Windows of a 'dict' policy to a DOM node. 281 282 Args: 283 parent: The DOM node for which the example will be added. 284 policy: A policy of type 'dict', for which the Windows example value 285 is generated. 286 ''' 287 self.AddElement(parent, 'dt', {}, 'Windows:') 288 win = self._AddStyledElement(parent, 'dd', ['.monospace', '.pre']) 289 key_name = self.config['win_reg_mandatory_key_name'] 290 example = str(policy['example_value']) 291 self.AddText(win, '%s\\%s = "%s"' % (key_name, policy['name'], example)) 292 293 def _AddDictionaryExampleLinux(self, parent, policy): 294 '''Adds an example value for Linux of a 'dict' policy to a DOM node. 295 296 Args: 297 parent: The DOM node for which the example will be added. 298 policy: A policy of type 'dict', for which the Linux example value 299 is generated. 300 ''' 301 self.AddElement(parent, 'dt', {}, 'Linux:') 302 linux = self._AddStyledElement(parent, 'dd', ['.monospace']) 303 example = str(policy['example_value']) 304 self.AddText(linux, '%s: %s' % (policy['name'], example)) 305 306 def _AddDictionaryExample(self, parent, policy): 307 '''Adds the example value of a 'dict' policy to a DOM node. Example output: 308 <dl> 309 <dt>Windows:</dt> 310 <dd> 311 Software\Policies\Chromium\ProxySettings = "{ 'ProxyMode': 'direct' }" 312 </dd> 313 <dt>Linux:</dt> 314 <dd>"ProxySettings": { 315 "ProxyMode": "direct" 316 } 317 </dd> 318 <dt>Mac:</dt> 319 <dd> 320 <key>ProxySettings</key> 321 <dict> 322 <key>ProxyMode</key> 323 <string>direct</string> 324 </dict> 325 </dd> 326 </dl> 327 328 Args: 329 parent: The DOM node for which the example will be added. 330 policy: The data structure of a policy. 331 ''' 332 examples = self._AddStyledElement(parent, 'dl', ['dd dl']) 333 if self.IsPolicySupportedOnPlatform(policy, 'win'): 334 self._AddDictionaryExampleWindows(examples, policy) 335 if self.IsPolicySupportedOnPlatform(policy, 'linux'): 336 self._AddDictionaryExampleLinux(examples, policy) 337 if self.IsPolicySupportedOnPlatform(policy, 'mac'): 338 self._AddDictionaryExampleMac(examples, policy) 339 340 def _AddExample(self, parent, policy): 341 '''Adds the HTML DOM representation of the example value of a policy to 342 a DOM node. It is simple text for boolean policies, like 343 '0x00000001 (Windows), true (Linux), <true /> (Mac)' in case of boolean 344 policies, but it may also contain other HTML elements. (See method 345 _AddListExample.) 346 347 Args: 348 parent: The DOM node for which the example will be added. 349 policy: The data structure of a policy. 350 351 Raises: 352 Exception: If the type of the policy is unknown or the example value 353 of the policy is out of its expected range. 354 ''' 355 example_value = policy['example_value'] 356 policy_type = policy['type'] 357 if policy_type == 'main': 358 pieces = [] 359 if self.IsPolicySupportedOnPlatform(policy, 'win'): 360 value = '0x00000001' if example_value else '0x00000000' 361 pieces.append(value + ' (Windows)') 362 if self.IsPolicySupportedOnPlatform(policy, 'linux'): 363 value = 'true' if example_value else 'false' 364 pieces.append(value + ' (Linux)') 365 if self.IsPolicySupportedOnPlatform(policy, 'mac'): 366 value = '<true />' if example_value else '<false />' 367 pieces.append(value + ' (Mac)') 368 self.AddText(parent, ', '.join(pieces)) 369 elif policy_type == 'string': 370 self.AddText(parent, '"%s"' % example_value) 371 elif policy_type in ('int', 'int-enum'): 372 pieces = [] 373 if self.IsPolicySupportedOnPlatform(policy, 'win'): 374 pieces.append('0x%08x (Windows)' % example_value) 375 if self.IsPolicySupportedOnPlatform(policy, 'linux'): 376 pieces.append('%d (Linux)' % example_value) 377 if self.IsPolicySupportedOnPlatform(policy, 'mac'): 378 pieces.append('%d (Mac)' % example_value) 379 self.AddText(parent, ', '.join(pieces)) 380 elif policy_type == 'string-enum': 381 self.AddText(parent, '"%s"' % (example_value)) 382 elif policy_type == 'list': 383 self._AddListExample(parent, policy) 384 elif policy_type == 'dict': 385 self._AddDictionaryExample(parent, policy) 386 else: 387 raise Exception('Unknown policy type: ' + policy_type) 388 389 def _AddPolicyAttribute(self, dl, term_id, 390 definition=None, definition_style=None): 391 '''Adds a term-definition pair to a HTML DOM <dl> node. This method is 392 used by _AddPolicyDetails. Its result will have the form of: 393 <dt style="...">...</dt> 394 <dd style="...">...</dd> 395 396 Args: 397 dl: The DOM node of the <dl> list. 398 term_id: A key to self._STRINGS[] which specifies the term of the pair. 399 definition: The text of the definition. (Optional.) 400 definition_style: List of references to values self._STYLE[] that specify 401 the CSS stylesheet of the <dd> (definition) element. 402 403 Returns: 404 The DOM node representing the definition <dd> element. 405 ''' 406 # Avoid modifying the default value of definition_style. 407 if definition_style == None: 408 definition_style = [] 409 term = self._GetLocalizedMessage(term_id) 410 self._AddStyledElement(dl, 'dt', ['dt'], {}, term) 411 return self._AddStyledElement(dl, 'dd', definition_style, {}, definition) 412 413 def _AddSupportedOnList(self, parent, supported_on_list): 414 '''Creates a HTML list containing the platforms, products and versions 415 that are specified in the list of supported_on. 416 417 Args: 418 parent: The DOM node for which the list will be added. 419 supported_on_list: The list of supported products, as a list of 420 dictionaries. 421 ''' 422 ul = self._AddStyledElement(parent, 'ul', ['ul']) 423 for supported_on in supported_on_list: 424 text = [] 425 product = supported_on['product'] 426 platforms = supported_on['platforms'] 427 text.append(self._PRODUCT_MAP[product]) 428 text.append('(%s)' % 429 self._MapListToString(self._PLATFORM_MAP, platforms)) 430 if supported_on['since_version']: 431 since_version = self._GetLocalizedMessage('since_version') 432 text.append(since_version.replace('$6', supported_on['since_version'])) 433 if supported_on['until_version']: 434 until_version = self._GetLocalizedMessage('until_version') 435 text.append(until_version.replace('$6', supported_on['until_version'])) 436 # Add the list element: 437 self.AddElement(ul, 'li', {}, ' '.join(text)) 438 439 def _AddPolicyDetails(self, parent, policy): 440 '''Adds the list of attributes of a policy to the HTML DOM node parent. 441 It will have the form: 442 <dl> 443 <dt>Attribute:</dt><dd>Description</dd> 444 ... 445 </dl> 446 447 Args: 448 parent: A DOM element for which the list will be added. 449 policy: The data structure of the policy. 450 ''' 451 452 dl = self.AddElement(parent, 'dl') 453 data_type = self._TYPE_MAP[policy['type']] 454 if (self.IsPolicySupportedOnPlatform(policy, 'win') and 455 self._REG_TYPE_MAP.get(policy['type'], None)): 456 data_type += ' (%s)' % self._REG_TYPE_MAP[policy['type']] 457 self._AddPolicyAttribute(dl, 'data_type', data_type) 458 if policy['type'] != 'external': 459 # All types except 'external' can be set through platform policy. 460 if self.IsPolicySupportedOnPlatform(policy, 'win'): 461 self._AddPolicyAttribute( 462 dl, 463 'win_reg_loc', 464 self.config['win_reg_mandatory_key_name'] + '\\' + policy['name'], 465 ['.monospace']) 466 if (self.IsPolicySupportedOnPlatform(policy, 'linux') or 467 self.IsPolicySupportedOnPlatform(policy, 'mac')): 468 self._AddPolicyAttribute( 469 dl, 470 'mac_linux_pref_name', 471 policy['name'], 472 ['.monospace']) 473 dd = self._AddPolicyAttribute(dl, 'supported_on') 474 self._AddSupportedOnList(dd, policy['supported_on']) 475 dd = self._AddPolicyAttribute(dl, 'supported_features') 476 self._AddFeatures(dd, policy) 477 dd = self._AddPolicyAttribute(dl, 'description') 478 self._AddDescription(dd, policy) 479 if (self.IsPolicySupportedOnPlatform(policy, 'win') or 480 self.IsPolicySupportedOnPlatform(policy, 'linux') or 481 self.IsPolicySupportedOnPlatform(policy, 'mac')): 482 # Don't add an example for ChromeOS-only policies. 483 if policy['type'] != 'external': 484 # All types except 'external' can be set through platform policy. 485 dd = self._AddPolicyAttribute(dl, 'example_value') 486 self._AddExample(dd, policy) 487 488 def _AddPolicyNote(self, parent, policy): 489 '''If a policy has an additional web page assigned with it, then add 490 a link for that page. 491 492 Args: 493 policy: The data structure of the policy. 494 ''' 495 if 'problem_href' not in policy: 496 return 497 problem_href = policy['problem_href'] 498 div = self._AddStyledElement(parent, 'div', ['div.note']) 499 note = self._GetLocalizedMessage('note').replace('$6', problem_href) 500 self._AddTextWithLinks(div, note) 501 502 def _AddPolicyRow(self, parent, policy): 503 '''Adds a row for the policy in the summary table. 504 505 Args: 506 parent: The DOM node of the summary table. 507 policy: The data structure of the policy. 508 ''' 509 tr = self._AddStyledElement(parent, 'tr', ['tr']) 510 indent = 'padding-left: %dpx;' % (7 + self._indent_level * 14) 511 if policy['type'] != 'group': 512 # Normal policies get two columns with name and caption. 513 name_td = self._AddStyledElement(tr, 'td', ['td', 'td.left'], 514 {'style': indent}) 515 self.AddElement(name_td, 'a', 516 {'href': '#' + policy['name']}, policy['name']) 517 self._AddStyledElement(tr, 'td', ['td', 'td.right'], {}, 518 policy['caption']) 519 else: 520 # Groups get one column with caption. 521 name_td = self._AddStyledElement(tr, 'td', ['td', 'td.left'], 522 {'style': indent, 'colspan': '2'}) 523 self.AddElement(name_td, 'a', {'href': '#' + policy['name']}, 524 policy['caption']) 525 526 def _AddPolicySection(self, parent, policy): 527 '''Adds a section about the policy in the detailed policy listing. 528 529 Args: 530 parent: The DOM node of the <div> of the detailed policy list. 531 policy: The data structure of the policy. 532 ''' 533 # Set style according to group nesting level. 534 indent = 'margin-left: %dpx' % (self._indent_level * 28) 535 if policy['type'] == 'group': 536 heading = 'h2' 537 else: 538 heading = 'h3' 539 parent2 = self.AddElement(parent, 'div', {'style': indent}) 540 541 h2 = self.AddElement(parent2, heading) 542 self.AddElement(h2, 'a', {'name': policy['name']}) 543 if policy['type'] != 'group': 544 # Normal policies get a full description. 545 policy_name_text = policy['name'] 546 if 'deprecated' in policy and policy['deprecated'] == True: 547 policy_name_text += " (" 548 policy_name_text += self._GetLocalizedMessage('deprecated') + ")" 549 self.AddText(h2, policy_name_text) 550 self.AddElement(parent2, 'span', {}, policy['caption']) 551 self._AddPolicyNote(parent2, policy) 552 self._AddPolicyDetails(parent2, policy) 553 else: 554 # Groups get a more compact description. 555 self.AddText(h2, policy['caption']) 556 self._AddStyledElement(parent2, 'div', ['div.group_desc'], 557 {}, policy['desc']) 558 self.AddElement( 559 parent2, 'a', {'href': '#top'}, 560 self._GetLocalizedMessage('back_to_top')) 561 562 # 563 # Implementation of abstract methods of TemplateWriter: 564 # 565 566 def IsDeprecatedPolicySupported(self, policy): 567 return True 568 569 def WritePolicy(self, policy): 570 self._AddPolicyRow(self._summary_tbody, policy) 571 self._AddPolicySection(self._details_div, policy) 572 573 def BeginPolicyGroup(self, group): 574 self.WritePolicy(group) 575 self._indent_level += 1 576 577 def EndPolicyGroup(self): 578 self._indent_level -= 1 579 580 def BeginTemplate(self): 581 # Add a <div> for the summary section. 582 summary_div = self.AddElement(self._main_div, 'div') 583 self.AddElement(summary_div, 'a', {'name': 'top'}) 584 self.AddElement(summary_div, 'br') 585 self._AddTextWithLinks( 586 summary_div, 587 self._GetLocalizedMessage('intro')) 588 self.AddElement(summary_div, 'br') 589 self.AddElement(summary_div, 'br') 590 self.AddElement(summary_div, 'br') 591 # Add the summary table of policies. 592 summary_table = self._AddStyledElement(summary_div, 'table', ['table']) 593 # Add the first row. 594 thead = self.AddElement(summary_table, 'thead') 595 tr = self._AddStyledElement(thead, 'tr', ['tr']) 596 self._AddStyledElement( 597 tr, 'td', ['td', 'td.left', 'thead td'], {}, 598 self._GetLocalizedMessage('name_column_title')) 599 self._AddStyledElement( 600 tr, 'td', ['td', 'td.right', 'thead td'], {}, 601 self._GetLocalizedMessage('description_column_title')) 602 self._summary_tbody = self.AddElement(summary_table, 'tbody') 603 604 # Add a <div> for the detailed policy listing. 605 self._details_div = self.AddElement(self._main_div, 'div') 606 607 def Init(self): 608 dom_impl = minidom.getDOMImplementation('') 609 self._doc = dom_impl.createDocument(None, 'html', None) 610 body = self.AddElement(self._doc.documentElement, 'body') 611 self._main_div = self.AddElement(body, 'div') 612 self._indent_level = 0 613 614 # Human-readable names of supported platforms. 615 self._PLATFORM_MAP = { 616 'win': 'Windows', 617 'mac': 'Mac', 618 'linux': 'Linux', 619 'chrome_os': self.config['os_name'], 620 'android': 'Android', 621 'ios': 'iOS', 622 } 623 # Human-readable names of supported products. 624 self._PRODUCT_MAP = { 625 'chrome': self.config['app_name'], 626 'chrome_frame': self.config['frame_name'], 627 'chrome_os': self.config['os_name'], 628 } 629 # Human-readable names of supported features. Each supported feature has 630 # a 'doc_feature_X' entry in |self.messages|. 631 self._FEATURE_MAP = {} 632 for message in self.messages: 633 if message.startswith('doc_feature_'): 634 self._FEATURE_MAP[message[12:]] = self.messages[message]['text'] 635 # Human-readable names of types. 636 self._TYPE_MAP = { 637 'string': 'String', 638 'int': 'Integer', 639 'main': 'Boolean', 640 'int-enum': 'Integer', 641 'string-enum': 'String', 642 'list': 'List of strings', 643 'dict': 'Dictionary', 644 'external': 'External data reference', 645 } 646 self._REG_TYPE_MAP = { 647 'string': 'REG_SZ', 648 'int': 'REG_DWORD', 649 'main': 'REG_DWORD', 650 'int-enum': 'REG_DWORD', 651 'string-enum': 'REG_SZ', 652 'dict': 'REG_SZ, encoded as a JSON string', 653 } 654 # The CSS style-sheet used for the document. It will be used in Google 655 # Sites, which strips class attributes from HTML tags. To work around this, 656 # the style-sheet is a dictionary and the style attributes will be added 657 # "by hand" for each element. 658 self._STYLE = { 659 'table': 'border-style: none; border-collapse: collapse;', 660 'tr': 'height: 0px;', 661 'td': 'border: 1px dotted rgb(170, 170, 170); padding: 7px; ' 662 'vertical-align: top; width: 236px; height: 15px;', 663 'thead td': 'font-weight: bold;', 664 'td.left': 'width: 200px;', 665 'td.right': 'width: 100%;', 666 'dt': 'font-weight: bold;', 667 'dd dl': 'margin-top: 0px; margin-bottom: 0px;', 668 '.monospace': 'font-family: monospace;', 669 '.pre': 'white-space: pre;', 670 'div.note': 'border: 2px solid black; padding: 5px; margin: 5px;', 671 'div.group_desc': 'margin-top: 20px; margin-bottom: 20px;', 672 'ul': 'padding-left: 0px; margin-left: 0px;' 673 } 674 675 # A simple regexp to search for URLs. It is enough for now. 676 self._url_matcher = lazy_re.compile('(http://[^\\s]*[^\\s\\.])') 677 678 def GetTemplateText(self): 679 # Return the text representation of the main <div> tag. 680 return self._main_div.toxml() 681 # To get a complete HTML file, use the following. 682 # return self._doc.toxml() 683