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