1 # markdown is released under the BSD license 2 # Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later) 3 # Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) 4 # Copyright 2004 Manfred Stienstra (the original version) 5 # 6 # All rights reserved. 7 # 8 # Redistribution and use in source and binary forms, with or without 9 # modification, are permitted provided that the following conditions are met: 10 # 11 # * Redistributions of source code must retain the above copyright 12 # notice, this list of conditions and the following disclaimer. 13 # * Redistributions in binary form must reproduce the above copyright 14 # notice, this list of conditions and the following disclaimer in the 15 # documentation and/or other materials provided with the distribution. 16 # * Neither the name of the <organization> nor the 17 # names of its contributors may be used to endorse or promote products 18 # derived from this software without specific prior written permission. 19 # 20 # THIS SOFTWARE IS PROVIDED BY THE PYTHON MARKDOWN PROJECT ''AS IS'' AND ANY 21 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 # DISCLAIMED. IN NO EVENT SHALL ANY CONTRIBUTORS TO THE PYTHON MARKDOWN PROJECT 24 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 # POSSIBILITY OF SUCH DAMAGE. 31 32 33 """ 34 Tables Extension for Python-Markdown 35 ==================================== 36 37 Added parsing of tables to Python-Markdown. 38 39 A simple example: 40 41 First Header | Second Header 42 ------------- | ------------- 43 Content Cell | Content Cell 44 Content Cell | Content Cell 45 46 Copyright 2009 - [Waylan Limberg](http://achinghead.com) 47 """ 48 49 from __future__ import absolute_import 50 from __future__ import unicode_literals 51 from . import Extension 52 from ..blockprocessors import BlockProcessor 53 from ..util import etree 54 55 class TableProcessor(BlockProcessor): 56 """ Process Tables. """ 57 58 def test(self, parent, block): 59 rows = block.split('\n') 60 return (len(rows) > 2 and '|' in rows[0] and 61 '|' in rows[1] and '-' in rows[1] and 62 rows[1].strip()[0] in ['|', ':', '-']) 63 64 def run(self, parent, blocks): 65 """ Parse a table block and build table. """ 66 block = blocks.pop(0).split('\n') 67 header = block[0].strip() 68 seperator = block[1].strip() 69 rows = block[2:] 70 # Get format type (bordered by pipes or not) 71 border = False 72 if header.startswith('|'): 73 border = True 74 # Get alignment of columns 75 align = [] 76 for c in self._split_row(seperator, border): 77 if c.startswith(':') and c.endswith(':'): 78 align.append('center') 79 elif c.startswith(':'): 80 align.append('left') 81 elif c.endswith(':'): 82 align.append('right') 83 else: 84 align.append(None) 85 # Build table 86 table = etree.SubElement(parent, 'table') 87 thead = etree.SubElement(table, 'thead') 88 self._build_row(header, thead, align, border) 89 tbody = etree.SubElement(table, 'tbody') 90 for row in rows: 91 self._build_row(row.strip(), tbody, align, border) 92 93 def _build_row(self, row, parent, align, border): 94 """ Given a row of text, build table cells. """ 95 tr = etree.SubElement(parent, 'tr') 96 tag = 'td' 97 if parent.tag == 'thead': 98 tag = 'th' 99 cells = self._split_row(row, border) 100 # We use align here rather than cells to ensure every row 101 # contains the same number of columns. 102 for i, a in enumerate(align): 103 c = etree.SubElement(tr, tag) 104 try: 105 c.text = cells[i].strip() 106 except IndexError: 107 c.text = "" 108 if a: 109 c.set('align', a) 110 111 def _split_row(self, row, border): 112 """ split a row of text into list of cells. """ 113 if border: 114 if row.startswith('|'): 115 row = row[1:] 116 if row.endswith('|'): 117 row = row[:-1] 118 return row.split('|') 119 120 121 class TableExtension(Extension): 122 """ Add tables to Markdown. """ 123 124 def extendMarkdown(self, md, md_globals): 125 """ Add an instance of TableProcessor to BlockParser. """ 126 md.parser.blockprocessors.add('table', 127 TableProcessor(md.parser), 128 '<hashheader') 129 130 131 def makeExtension(configs={}): 132 return TableExtension(configs=configs) 133