def wrap(self): if DEBUG: print("Wrapping list item...") p_style, list_level, list_type = get_current_li(self.section.extra) self.cell_object.add_paragraph(style=p_style) numbered = False if list_type == ORDERED_LIST_NAME: numbered = True utils.list_number(self.cell_object.cell, self.cell_object.paragraph, level=list_level, num=numbered) if isinstance(self.section.contents, str): insert_text(self.cell_object, self.section.contents) return temp_section = MarkdownSection('markdown', self.section.contents, {}, {}) temp_section.propagate_extra('inline', True) markdown.invoke(self.cell_object, temp_section, invoked_from_wrapper=True)
def insert(self): if DEBUG: print("Adding list...") list_data = self.section.contents if isinstance(list_data, dict) and len(list_data) != 1: list_data = [list_data] if isinstance(list_data, dict) and len(list_data) == 1: # Create the parent title wrapper_table = self.cell_object.cell.add_table(rows=2, cols=1) title_cell = wrapper_table.cell(0, 0) title_text = list(list_data.keys())[0] insert_text(title_cell, title_text, self.style['title']) # Create a list in a list because this is a grouped list co = CellObject(wrapper_table.cell(1, 0)) table_data = list_data[title_text] invoke(co, Section('list', table_data, self.section.layout, {})) else: table.invoke(self.cell_object, Section('table', list_data, self.section.layout, {'list_style': True}))
def wrap(self, invoked_from_wrapper=False): # Handle called from another wrapper. items = self.section.contents if not isinstance(items, list): raise ValueError('ItemsSection does not have valid contents ' + '(must be a list)') table_width = max(items, key=lambda x: x['endCol']).get('endCol') row_count = max(items, key=lambda x: x.get('index', 0)).get('index') + 1 item_table = self.cell_object.cell.add_table(rows=row_count, cols=table_width) if DEBUG: item_table.style = DEFAULT_TABLE_STYLE for item in items: row, col, col_to_merge = item.get( 'index', 0), item.get('startCol'), item.get('endCol') current_cell = item_table.cell(row, col) current_cell.merge(item_table.cell(row, col_to_merge - 1)) field_name = item.get("fieldName", "") field_name = field_name[0].upper() + field_name[1:] field_name = f'{field_name}: ' if item.get('displayType', self.display_types['ROW']) == \ self.display_types['CARD']: field_name += '\n' insert_text(current_cell, field_name, self.style['key']) insert_text(current_cell, item.get("data", ""), self.style['value'])
def insert(self): if DEBUG: print('Adding number...') table = self.cell_object.cell.add_table(rows=1, cols=1) if DEBUG: table.style = 'Table Grid' # add background color background_color = self.section.layout.get('style', {}).get( 'backgroundColor', '')[1:] # Add the main number inner_cell = table.cell(0, 0) style_cell(inner_cell, color_hex=background_color) main_number = CellObject(inner_cell) sign = self.section.layout.get('sign', '') sign = '' if sign is None else sign insert_text(main_number, str(self.section.contents) + sign, self.style['main']) main_number.add_paragraph(add_run=True) insert_text(main_number, str(self.section.extra['title']), self.style['title'])
def insert(self): if DEBUG: print('Adding horizontal line...') self.cell_object.add_paragraph(add_run=False) insert_text(self.cell_object, '⎯' * DEFAULT_HR_DASHES_SIZE, style={PYDOCX_TEXT_ALIGN: 'center'})
def insert(self): if DEBUG: print('Adding link...') insert_text(self.cell_object, self.section.contents) add_hyperlink_into_run(self.cell_object.paragraph, self.cell_object.run, self.section.extra['href'])
def insert(self): if DEBUG: print('Adding date...') try: formatted_date = get_formatted_date(self.section.contents, self.section.layout) except ParserError as e: formatted_date = 'n/a' insert_text(self.cell_object, formatted_date)
def insert(self): if DEBUG: print('Adding number...') table = self.cell_object.cell.add_table(rows=1, cols=1) if DEBUG: table.style = 'Table Grid' # Add the main number inner_cell = table.cell(0, 0) style_cell(inner_cell) main_number = CellObject(inner_cell) insert_text(main_number, str(self.section.contents), self.style['main']) main_number.add_paragraph(add_run=True) insert_text(main_number, str(self.section.extra['title']), self.style['title'])
def insert(self): if DEBUG: print('Adding text...') default_date_format = '%m %b %Y %H:%M:%S %SZ' formatted_date = "N/A" date = moment.date(self.section.contents) if self.section.contents == '': formatted_date = moment.now().strftime(default_date_format) elif self.section.layout: layout = self.section.layout if "format" in layout: formatted_date = date.format(layout["format"]) else: formatted_date = date.strftime(default_date_format) insert_text(self.cell_object, formatted_date)
def insert(self): if DEBUG: print('Adding error element...') style = { 'bold': False, 'color': '#ff0013', 'fontSize': 10, 'underline': False, 'strikethrough': False, 'italic': False } # Add some padding table = self.cell_object.cell.add_table(rows=1, cols=1) if DEBUG: table.style = 'Table Grid' inner_cell = table.cell(0, 0) style_cell(inner_cell, {"top": 50, "bottom": 50}) error_message = f'ERROR GENERATING SECTION ({self.section.contents})' utils.insert_text(inner_cell, error_message, style)
def insert(self): if DEBUG: print("Adding table...") table_data = self.section.contents if 'tableColumns' not in self.section.layout: return if 'readableHeaders' in self.section.layout: ordered = self.section.layout['tableColumns'] readable_headers = self.section.layout['readableHeaders'].values() table_columns = fix_order(ordered, readable_headers) else: table_columns = self.section.layout['tableColumns'] for i, header_text in enumerate(table_columns): if not isinstance(header_text, str): table_columns.remove(header_text) if 'title' in self.section.extra: table = self.cell_object.cell.add_table(rows=2, cols=len(table_columns)) title = table.cell(0, 0) title.merge(table.cell(0, len(table_columns) - 1)) insert_text(title, self.section.extra['title'], self.style['title']) hdr_cells = table.rows[1].cells else: table = self.cell_object.cell.add_table(rows=2, cols=len(table_columns)) hdr_cells = table.rows[0].cells table.style = DEFAULT_TABLE_STYLE if 'list_style' in self.section.extra and self.section.extra[ 'list_style']: table.style = None for i, header_text in enumerate(table_columns): insert_text(hdr_cells[i], header_text, self.style['text']) for r in table_data: row_cells = table.add_row().cells for i, header_text in enumerate(table_columns): if header_text not in r: continue # Old json format can have 'Avatars', which are images if isinstance(r[header_text], dict) and \ r[header_text]['type'] == 'image': row_temp = r[header_text] s = Section(row_temp['type'], row_temp['data'], {}, {}) co = CellObject(row_cells[i], add_run=False) image.invoke(co, s) else: insert_text(row_cells[i], r[header_text], self.style['text'])
def wrap(self, invoked_from_wrapper=False): # Handle called from another wrapper. items = self.section.contents if not isinstance(items, list): raise ValueError('ItemsSection does not have valid contents ' + '(must be a list)') table_width = max(items, key=lambda x: x['endCol']).get('endCol') row_count = max(items, key=lambda x: x.get('index', 0)).get('index') + 1 title_offset = 0 has_title = 'title' in self.section.extra if has_title: title_offset += 1 item_table = self.cell_object.cell.add_table(rows=row_count + title_offset, cols=table_width) if DEBUG: item_table.style = DEFAULT_TABLE_STYLE if has_title: section_title = self.section.extra['title'] insert_text(item_table.cell(0, 0), section_title + '\n', self.style['title']) for item in items: row, col, col_to_merge = item.get( 'index', 0 + title_offset), item.get('startCol'), item.get('endCol') current_cell = item_table.cell(row + title_offset, col) current_cell.merge( item_table.cell(row + title_offset, col_to_merge - 1)) field_name = item.get("fieldName", "") field_type = item.get("fieldType", "shortText") field_name = field_name[0].upper() + field_name[1:] field_name = f'{field_name}: ' if item.get('displayType', self.display_types['ROW']) == \ self.display_types['CARD']: field_name += '\n' data = item.get("data", "") insert_text(current_cell, field_name, self.style['key']) if field_type == 'grid': table.invoke( self.cell_object, SectionObject('table', data, self.section.layout, {})) else: insert_text(current_cell, data, self.style['value'])
def insert(self): if DEBUG: print("Adding trend...") table = self.cell_object.cell.add_table(rows=2, cols=4) # add background color background_color = self.section.layout.get('style', {}).get('backgroundColor', '')[1:] # Add the main number current_sum = self.section.contents['currSum'] inner_cell = table.cell(0, 1) style_cell(inner_cell, color_hex=background_color) main_number = CellObject(inner_cell) insert_text(main_number, str(current_sum), self.style['main']) # Add the trend number previous_sum = self.section.contents['prevSum'] # Fix for the percentages divider = previous_sum if previous_sum == 0: divider = 1 change = ((current_sum - previous_sum) * 100) / divider if change < 0: direction = '▼' # Down arrow elif change == 0: direction = '= ' else: direction = '▲' # Up arrow if change > 999.0: change = '> 999' elif change < -999.0: change = '< -999' else: change = "{0:.2f}".format(change) value_percent = f'{direction}{change}%' inner_cell = table.cell(0, 2) style_cell(inner_cell, color_hex=background_color) trend_number = CellObject(inner_cell) insert_text(trend_number, value_percent, self.style['trend']) # Add the title third_cell = table.cell(1, 1) style_cell(third_cell, color_hex=background_color) table.cell(1, 2).merge(third_cell) title = CellObject(third_cell) insert_text(title, str(self.section.extra['title']), self.style['title'])
def insert(self): if DEBUG: print("Adding trend...") table = self.cell_object.cell.add_table(rows=2, cols=4) # Add the main number current_sum = self.section.contents['currSum'] inner_cell = table.cell(0, 1) style_cell(inner_cell) main_number = CellObject(inner_cell) insert_text(main_number, str(current_sum), self.style['main']) # Add the trend number previous_sum = self.section.contents['prevSum'] # Fix for the percentages if previous_sum == 0: previous_sum = 1 change = (current_sum * 100) / previous_sum if change < 0: direction = '⏷' # Down arrow elif change == 0: direction = '= ' else: direction = '⏶' # Up arrow change = "{0:.2f}".format(change) value_percent = f'{direction}{change}%' inner_cell = table.cell(0, 2) style_cell(inner_cell) trend_number = CellObject(inner_cell) insert_text(trend_number, value_percent, self.style['trend']) # Add the title third_cell = table.cell(1, 1) style_cell(third_cell) table.cell(1, 2).merge(third_cell) title = CellObject(third_cell) insert_text(title, str(self.section.extra['title']), self.style['title'])
def insert(self): if DEBUG: print("Adding table...") table_data = self.section.contents if isinstance(table_data, dict): table_data = table_data.get('data', table_data) # If table columns isn't present, use the dict values of the table data # as table columns (kind of like list). if 'tableColumns' not in self.section.layout: self.section.layout['tableColumns'] = list(table_data[0].keys()) # Use and order according to readableHeaders if present. if 'readableHeaders' in self.section.layout: ordered = self.section.layout['tableColumns'] readable_headers = self.section.layout['readableHeaders'] table_columns = fix_order(ordered, readable_headers) else: table_columns = self.section.layout['tableColumns'] # Quick fix, word crashes on more than MAX_MS_TABLE_COLS_LIMIT # (64 right now) columns. # See: https://stackoverflow.com/questions/36921010/docx-does-not-support-more-than-63-columns-in-a-table table_columns = table_columns[0:MAX_MS_TABLE_COLS_LIMIT] for i, row_title in enumerate(table_columns): if not isinstance(row_title, str): table_columns.remove(row_title) if 'title' in self.section.extra: table = self.cell_object.cell.add_table(rows=2, cols=len(table_columns)) title = table.cell(0, 0) title.merge(table.cell(0, len(table_columns) - 1)) insert_text(title, self.section.extra['title'], self.style['title']) hdr_cells = table.rows[1].cells else: table = self.cell_object.cell.add_table(rows=1, cols=len(table_columns)) hdr_cells = table.rows[0].cells table.style = DEFAULT_TABLE_STYLE if 'list_style' in self.section.extra and self.section.extra[ 'list_style']: table.style = None for i, row_title in enumerate(table_columns): insert_text(hdr_cells[i], row_title, self.style['text']) for row_item in table_data: row_cells = table.add_row().cells for i, row_title in enumerate(table_columns): if row_title not in row_item: continue # Old json format can have 'Avatars', which are images if isinstance(row_item[row_title], dict) and \ row_item[row_title]['type'] == 'image': insert_table_image(row_item, row_title, row_cells[i]) else: insert_text(row_cells[i], str(row_item[row_title]), self.style['text'])
def wrap(self, invoked_from_wrapper=False): # Handle called from another wrapper. md_section_list = None if isinstance(self.section.contents, list): md_section_list = self.section.contents elif invoked_from_wrapper and \ isinstance(self.section.contents.contents, str): md_section_list = [self.section.contents] if not isinstance(md_section_list, list): raise ValueError('Markdown section does not have valid contents ' + '(must be a list)') for section in md_section_list: # === Start wrappers === if section.type == MD_TYPE_DIV: temp_section = MarkdownSection('markdown', section.contents, {}, {}) invoke(self.cell_object, temp_section) continue if section.type == MD_TYPE_CODE: md_code.invoke(self.cell_object, section) self.cell_object.update_paragraph() continue if section.type == MD_TYPE_QUOTE: md_blockquote.invoke(self.cell_object, section) self.cell_object.update_paragraph() continue if section.type == MD_TYPE_UNORDERED_LIST: md_ul.invoke(self.cell_object, section) self.cell_object.update_paragraph() continue if section.type == MD_TYPE_ORDERED_LIST: md_ol.invoke(self.cell_object, section) self.cell_object.update_paragraph() continue if section.type == MD_TYPE_LIST_ITEM: md_li.invoke(self.cell_object, section) continue if section.type == MD_TYPE_TABLE: table_html = section.extra['original_html'] t = PyQuery(table_html) headers = [i.find('th') for i in t.find('tr').items()][0] headers = [c.text() for c in headers.items()] rows = [ i.find('td') for i in t.find('tr').items() if i.find('td') ] data = [] for row in rows: r = { headers[i]: c.text() for i, c in enumerate(row.items()) } data.append(r) s = Section("table", data, {"tableColumns": headers}, {}) table.invoke(self.cell_object, s) continue # Fix wrapped: # (Some times there are elements which contain other elements, # but are not considered one of the declared wrappers) if isinstance(section.contents, list): is_inside_wrapper = False if 'inline' in section.extra: is_inside_wrapper = True if section.type == 'span': section.propagate_extra('check_newline', True, only_multiple_children=False) # TODO: Fix problem with H1 no newline even if in span. temp_section = MarkdownSection('markdown', section.contents, {}, section.extra, section.attrs) invoke(self.cell_object, temp_section, invoked_from_wrapper=is_inside_wrapper) continue # === Elements === if section.type in SHOULD_NEW_LINE and section.get_extra( 'check_newline'): self.cell_object.add_paragraph() if section.type == MD_TYPE_HORIZONTAL_LINE: md_hr.invoke(self.cell_object, section) continue # Add a block (newline) if not called from a wrapper # (Should come after hr) if not invoked_from_wrapper: self.cell_object.add_paragraph() if section.type in MD_TYPES_HEADERS: # We want to keep the h{1...6} for styling insert_header(self.cell_object, section.contents, header=section.type) continue if section.type in [MD_TYPE_TEXT, MD_TYPE_INLINE_TEXT]: if invoked_from_wrapper: self.cell_object.add_run() insert_text(self.cell_object, section) continue if section.type == MD_TYPE_LINK: md_link.invoke(self.cell_object, section) continue if section.type == MD_TYPE_IMAGE: md_image.invoke(self.cell_object, section) continue raise ValueError(f'Section type is not defined: {section.type}')
def insert(self): if DEBUG: print("Adding duration...") contents = self.section.contents days = '0' hours = '0' minutes = '0' if contents: result = 0 if len(contents) > 0 and isinstance( contents[0]['data'], list) and len(contents[0]['data']) > 0: result = contents[0]['data'][0] days = floor(result / (3600 * 24)) result -= days * 3600 * 24 hours = floor(result / 3600) result -= hours * 3600 minutes = floor(result / 60) days = format_number(days) hours = format_number(hours) minutes = format_number(minutes) # Split the table as so: # +---------------+ # | Title | # +---------------+ # | H |:| M |:| S | # +---+-+---+-+---+ # .cell(row, col) set_cell_margins(self.cell_object.cell, {"top": 50}) table = self.cell_object.cell.add_table(rows=2, cols=5) if DEBUG: table.style = 'Table Grid' title_cell = table.cell(0, 0) style_cell(title_cell) title_cell.merge(table.cell(0, 4)) title = DEFAULT_DURATION_TITLE if 'title' in self.section.extra: title = self.section.extra['title'] elif len(contents ) > 0 and 'name' in contents[0] and contents[0]['name'] != '': title = contents['data']['name'] insert_text(title_cell, title, self.style['title']) # Days days_cell = table.cell(1, 0) style_cell(days_cell) insert_text(days_cell, days, self.style['duration']) insert_text(days_cell, DURATION_DAYS_LABEL, self.style['label'], add_run=True) # Add first colon colon_right = table.cell(1, 1) style_cell(colon_right) insert_text(colon_right, ':', self.style['duration']) # Hours hours_cell = table.cell(1, 2) style_cell(hours_cell) insert_text(hours_cell, hours, self.style['duration']) insert_text(hours_cell, DURATION_HOURS_LABEL, self.style['label'], add_run=True) # Add second colon colon_left = table.cell(1, 3) style_cell(colon_left) insert_text(colon_left, ':', self.style['duration']) # Minutes minutes_cell = table.cell(1, 4) style_cell(minutes_cell) insert_text(minutes_cell, minutes, self.style['duration'], add_run=True) insert_text(minutes_cell, DURATION_MINUTES_LABEL, self.style['label'], add_run=True)
def insert(self): if DEBUG: print("Adding table...") table_data = self.section.contents if isinstance(table_data, dict): table_data = table_data.get('data', table_data) if 'tableColumns' not in self.section.layout: # Quick dirty fix for test - will be refactored in upcoming PR self.section.layout['tableColumns'] = list(table_data[0].keys()) # Fix new lists if isinstance(table_data, dict): wrapper_table = self.cell_object.cell.add_table( rows=2, cols=len(table_data.keys())) i = 0 # Add the wrapping headers for wrapper_header, table_contents in table_data.items(): hdr = wrapper_table.cell(0, i) insert_text(hdr, wrapper_header, self.style['title']) body = wrapper_table.cell(1, i) c = CellObject(body) # Hacky but will do the job invoke(c, Section('table', table_contents, {}, {})) i += 1 return if 'readableHeaders' in self.section.layout: ordered = self.section.layout['tableColumns'] readable_headers = self.section.layout['readableHeaders'] table_columns = fix_order(ordered, readable_headers) else: table_columns = self.section.layout['tableColumns'] # Quick fix, word crashes on more than 64 columns. # See: https://stackoverflow.com/questions/36921010/docx-does-not-support-more-than-63-columns-in-a-table table_columns = table_columns[0:63] for i, header_text in enumerate(table_columns): if not isinstance(header_text, str): table_columns.remove(header_text) if 'title' in self.section.extra: table = self.cell_object.cell.add_table(rows=2, cols=len(table_columns)) title = table.cell(0, 0) title.merge(table.cell(0, len(table_columns) - 1)) insert_text(title, self.section.extra['title'], self.style['title']) hdr_cells = table.rows[1].cells else: table = self.cell_object.cell.add_table(rows=2, cols=len(table_columns)) hdr_cells = table.rows[0].cells table.style = DEFAULT_TABLE_STYLE if 'list_style' in self.section.extra and self.section.extra[ 'list_style']: table.style = None for i, header_text in enumerate(table_columns): insert_text(hdr_cells[i], header_text, self.style['text']) if len(table_columns) > 63: # TODO: add error. pass for r in table_data: row_cells = table.add_row().cells for i, header_text in enumerate(table_columns): if header_text not in r: continue # Old json format can have 'Avatars', which are images if isinstance(r[header_text], dict) and \ r[header_text]['type'] == 'image': row_temp = r[header_text] s = Section(row_temp['type'], row_temp['data'], {}, {}) co = CellObject(row_cells[i], add_run=False) image.invoke(co, s) else: insert_text(row_cells[i], r[header_text], self.style['text'])