def _finalize(doc): """_finalize :param doc: """ swap_string = "\n".join( " {short!r}: {identifier!r}\n {long!r}: {identifier!r}".format( identifier="+{}_".format(identifier), short=short_, long=long_) for identifier, (short_, long_, __) in doc.abbr["definitions"].items()) logger.debug( "Add abbreviations to vale substitutions:\n{}\n".format(swap_string)) appendix = doc.abbr["appendix"] if appendix: heading = pf.Header(pf.Str("Abbreviations"), identifier="abbreviations", classes=["unnumbered"]) doc.content.append(heading) appendix.sort(key=lambda x: x[0]) appendix = map(lambda x: x[1], appendix) doc.content.append(pf.DefinitionList(*appendix)) if "preamble" in doc.metadata: existing_preamble = doc.metadata["preamble"].content else: existing_preamble = [] doc.metadata["preamble"] = pf.MetaBlocks( *existing_preamble, *[value for key, value in doc.abbr["latex_preamble"].items()], )
def create_header( title_str, doc, level=0, parse_text=False, identifier="", short_title=None ): """ Create a header element. Because headers need to be referenced by later elements, references to the last found header is remembered. """ if not isinstance(doc, pf.Doc): raise ValueError("create_header without Doc element") attributes = {} if short_title == title_str: short_title = None if short_title is not None: # Attach short title as attribute to be picked up later on by generate_innodoc attributes["short_title"] = short_title if parse_text: title = parse_fragment(title_str, doc.metadata["lang"].text)[0].content else: title = destringify(title_str) header = pf.Header( *title, level=level, identifier=identifier, attributes=attributes ) remember(doc, "label", header) return header
def finalize(doc): objectives = materialize_unused(doc, all_ids) unused_section = pfp.find_by_id('missing-objectives', doc) spot = itertools.count(start=unused_section.index + 1) for course in sorted(objectives): identifier = course.lower().replace(" ", "") + "-missing" doc.content.insert( next(spot), pf.Header(pf.Str(course), level=2, identifier=identifier, classes=["unnumbered"])) for header in objectives[course]: unit_list = pf.OrderedList() for objective in objectives[course][header]: if objective.identifier not in referenced_ids: # we've got a handle on the original `pf.Span`, so ask # for its grandparent to get the `pf.ListItem`. unit_list.content.append(objective.ancestor(2)) # Only put the header into the document *if* the unit actually # has learning objectives that were not referenced. if len(unit_list.content): doc.content.insert(next(spot), header) doc.content.insert(next(spot), unit_list) # Any appendices (anything *after* the "missing objectives" section) should # be unnumbered, because numbering gets difficult after that. for elem in doc.content[next(spot):]: if isinstance(elem, pf.Header): elem.classes.append("unnumbered")
def action(elem, doc): if isinstance(elem, pf.CodeBlock): if 'metadata_ref' in elem.classes: slugline = make_slugline(elem, doc) if slugline: return pf.Header(pf.Str(slugline), level=1) else: return [] return elem
def action(elem, doc): if isinstance(elem, pf.Para) and is_title_line(elem): title = get_title_name(elem) chapter_elem = pf.Header(pf.Str(title)) if elem.content[0].text == '$unnumbered': chapter_elem.classes = ['unnumbered'] return chapter_elem elif type(elem) == pf.Header: elem.level += 1
def finalize(doc: pf.Doc): #raise Exception("input file %s header_level %s" % (doc.input_file, doc.header_level)) header = pf.Header(pf.Str(doc.meta_title), level=doc.header_level) doc.content.insert(0, header) doc.content.insert(1, pf.Para(pf.Str(doc.description))) del doc.header_level del doc.input_file del doc.meta_title del doc.description del doc.images_path del doc.out_meta
def action(elem, doc): if isinstance(elem, pf.Doc): version = pkg_resources.get_distribution("panflute").version json_serializer = lambda elem: elem.to_json() raw = json.dumps(elem, default=json_serializer) raw = json.loads(raw) raw = json.dumps(raw, check_circular=False, indent=4, separators=(',', ': ')) disclaimer = pf.Para(pf.Emph(pf.Str('Note: sort order not preserved'))) elem.content = [ pf.Header(pf.Str('Python version:'), level=2), pf.Para(pf.Str(sys.version)), pf.Header(pf.Str('Panflute version:'), level=2), pf.Para(pf.Str(version)), pf.Header(pf.Str('sys.argv:'), level=2), pf.Plain(pf.Str(str(sys.argv))), pf.Header(pf.Str('JSON Input:'), level=2), disclaimer, pf.CodeBlock(raw) ]
def test_handle_mlabel_last_header(self): """MTitle command with a last header element""" mlabel = pf.RawBlock(r"\MLabel{HEADER}") header = pf.Header(pf.Str("headertext")) doc = pf.Doc(header, mlabel, format="latex") elem = doc.content[0] remember(doc, "label", elem) ret = self.commands.handle_mlabel(["HEADER"], elem) self.assertFalse(ret) # pylint: disable=no-member self.assertEqual(header.identifier, "HEADER")
def finalize(doc): content = doc.content title = doc.get_metadata('title').lower().replace(" ", "") + "-" content.append( pf.Header(pf.Str(text="Objectives organized by course outcome"), level=1, classes=['unnumbered'], identifier=title + 'organized')) for outcome in objectives: # turn ":program:" into "Program" header = outcome[1:-1].capitalize() content.append( pf.Header(pf.Str(text=header), level=2, classes=['unlisted', 'unnumbered'], identifier=title + header)) # the list in the dict is already a bunch of `pf.ListItem`, so just add # them in a new `pf.OrderedList` content.append(pf.OrderedList(*objectives[outcome]))
def _finalize(doc): # Add headings for the abstracts if doc.format != "latex": for name in ["abstract", "secondabstract"]: abstract = doc.metadata.content.get(name, None) abstract_name = doc.get_metadata(f"{name}name", name.capitalize()) if abstract: abstract.walk(mathfilter.role_shortcuts) title = pf.Header(pf.Str(abstract_name), level=4) doc.metadata[name].content.list.insert(0, title)
def fenced_action(options, data, element, doc): modalid = options.get('id', 'modal1') title = options.get('title') closebtn = options.get('closebtn', True) size = options.get('size', 'default') size2class = { 'default': None, 'small' : 'modal-sm', 'sm' : 'modal-sm', 'large' : 'modal-lg', 'lg' : 'modal-lg', 'xlarge' : 'modal-xl', 'xl' : 'modal-xl', } components = [] if title: modal_header1 = pf.Header(pf.Str(title), classes=['modal-title'], level=5, identifier=modalid + 'Title') modal_header2 = pf.Div( pf.Div(pf.Para(pf.Str('x')), attributes = {'aria-hidden': "true"}), classes = ['close', 'button'], attributes = { 'type': 'button', 'data-dismiss': 'modal', 'aria-label': 'Close' }) components.append(pf.Div(modal_header1, modal_header2, classes = ['modal-header'])) components.append(pf.Div(*data, classes = ['modal-body'])) if closebtn: components.append(pf.Div( pf.Div(pf.Para(pf.Str('Close')), classes = ['button', 'btn', 'btn-secondary'], attributes = { 'type': 'button', 'data-dismiss': 'modal', }), classes = ['modal-footer'] )) modal_content = pf.Div(*components, classes = ['modal-content']) mainclasses = ['modal-dialog', 'modal-dialog-centered', 'modal-dialog-scrollable'] sizeclass = size2class.get(size) if sizeclass: mainclasses.append(sizeclass) model_dialog = pf.Div(modal_content, classes = mainclasses, attributes = {'role': 'document'}) return pf.Div(model_dialog, classes = ['modal', 'fade'], identifier = modalid, attributes = { 'tabindex' : '-1', 'role' : 'dialog', 'aria-labelledby': modalid + 'Title', 'aria-hidden' : "true" })
def test_remember(self): """It should remember and forget.""" doc = pf.Doc() self.assertIsNone(get_remembered(doc, "somekey")) header = pf.Header() remember(doc, "header", header) rememembered_el = get_remembered(doc, "header") self.assertEqual(rememembered_el, header) self.assertIsNone(get_remembered(doc, "header")) img = pf.Image() remember(doc, "img", img) rememembered_img = get_remembered(doc, "img") self.assertEqual(rememembered_img, img) self.assertIsNone(get_remembered(doc, "img"))
def action(elem, doc): if isinstance(elem, pf.Para) and is_include_line(elem): fn = get_filename(elem) if not os.path.isfile(fn): return with open(fn) as f: raw = f.read() new_elems = pf.convert_text(raw) new_elems.insert( 0, pf.Header(pf.Str('=' * 20), pf.Str('Text Box'), pf.Str('=' * 20))) new_elems.append(pf.Para(pf.Str('=' * 50))) # Alternative A: return new_elems
def finalize(doc): has_backmatter = doc.tables or doc.figures if has_backmatter: pos = doc.backmatter_index # Already searched by prepare() if pos is None: raise IndexError( 'Backmatter not found; add div with identifier "backmatter":\n::: {#backmatter}\n:::\n' ) backmatter = [ pf.RawBlock(r'\clearpage', format='latex'), pf.Header(pf.Str('Figures and Tables'), level=1, identifier='backmatter', classes=['unnumbered']) ] for figure in doc.figures: backmatter.append(figure) for table in doc.tables: backmatter.append(table) doc.content[pos] = pf.Div(*backmatter) pass
def finalize(doc): try: doc.content.insert(0, pf.Header(pf.Str(doc.title), level=1)) except: return doc return doc
def convert(self): doc = panflute.Doc( api_version=(1, 17, 5), metadata={ 'pagetitle': self.title, }, ) doc.content.append(panflute.Header(panflute.Str(self.title))) lists = {} tables = {} table_rows = {} table_cells = {} for chunk in self._attr_chunks(): self.logger.debug(chunk) container = panflute.Para() cdiv = panflute.Div(container) # Handle lists if 'list_class' in chunk[0]['attrs']: lc = chunk[0]['attrs']['list_class'] check_state = None if lc in ['checked', 'unchecked']: check_state = lc lc = 'checklist' ld = chunk[0]['attrs']['list_depth'] # prune any lists that are lower than us, they're finished for i in list(lists.keys()): if i > ld: lists.pop(i) # non-homogenous list types can be immediately adjacent without # ending up merged if ld in lists and lists[ld]['class'] != lc: lists.pop(ld) # checklists are a special case, they can't contain other lists if lc != 'checklist' and lists and lists[1][ 'class'] == 'checklist': lists = {} # make sure any intermediate lists were created, including # the top level because boxnotes for i in range(1, ld + 1): if i not in lists: lists[i] = self._list(lc, i) if i != ld: lists[i]['pf'].content.append(panflute.ListItem()) lp = lists[i]['pf'] if lc == 'checklist': lp = panflute.Div(lp, classes=['checklist']) if i == 1: doc.content.append(lp) else: lists[i - 1]['pf'].content[-1].content.append(lp) # set the container for the other subchunks container = panflute.Plain() cdiv.content = [container] cdiv.classes.append(lc) if check_state: cdiv.classes.append(check_state) lists[ld]['pf'].content.append(panflute.ListItem(cdiv)) if check_state == 'checked': container.content.append(panflute.Str(CHECKED)) elif check_state == 'unchecked': container.content.append(panflute.Str(UNCHECKED)) elif 'table_id' in chunk[-1]['attrs']: table_id = chunk[-1]['attrs']['table_id'] row_id = chunk[-1]['attrs']['table_row'] cell_id = row_id + chunk[-1]['attrs']['table_col'] if table_id not in tables: # There's some magic in the constructor for panflute tables # that isn't exposed in any other way, so we can't create # the table until we've finished populating the rows. # Instead, use a placeholder div to locate it within the # document. tables[table_id] = { 'div': panflute.Div(), 'rows': [], } doc.content.append(tables[table_id]['div']) if row_id not in table_rows: table_rows[row_id] = panflute.TableRow() tables[table_id]['rows'].append(table_rows[row_id]) if cell_id not in table_cells: cdiv = panflute.Div(panflute.Plain()) table_cells[cell_id] = panflute.TableCell(cdiv) table_rows[row_id].content.append(table_cells[cell_id]) container = table_cells[cell_id].content[0].content[0] else: lists = {} doc.content.append(cdiv) if 'align' in chunk[0]['attrs']: cdiv.attributes['style'] = 'text-align: ' + chunk[0]['attrs'][ 'align'] + ';' for subchunk in chunk: if subchunk['newlines'] > 1: # we've had an extra linebreak, no more adding on to lists lists = {} # don't do anything with markers if subchunk['text'] == '*' and 'lmkr' in subchunk['attrs']: continue scont = container if 'href' in subchunk['attrs']: scont = panflute.Link(url=subchunk['attrs']['href']) container.content.append(scont) if 'image' in subchunk['attrs']: scont.content.append( panflute.Image( url=self._image(subchunk['attrs']['author'], subchunk['attrs']['image']))) continue span = panflute.Span() lines = subchunk['text'].splitlines() while lines: subtext = lines.pop(0) span.content.append(panflute.Str(subtext)) if lines: span.content.append(panflute.LineBreak()) if 'font' in subchunk['attrs']: color = subchunk['attrs']['font'].get('color', '000000') size = subchunk['attrs']['font'].get('size', 'medium') span.classes.append('font-size-' + size) span.classes.append('font-color-' + color) # I don't actually know what the possible colors are and I # don't feel like finding out, so just inject it as an # inline style. if color != '000000': span.attributes['style'] = 'color: #' + color + ';' if subchunk['attrs'].get('underline'): span.classes.append('underline') if subchunk['attrs'].get('bold'): span = panflute.Strong(span) if subchunk['attrs'].get('italic'): span = panflute.Emph(span) if subchunk['attrs'].get('strikethrough'): span = panflute.Strikeout(span) scont.content.append(span) # Actually create the tables for x in tables: tables[x]['div'].content.append(panflute.Table(*tables[x]['rows'])) with io.StringIO() as f: panflute.dump(doc, f) return f.getvalue()
def finalize(doc): header = pf.Header(pf.Str(doc.get_metadata('title')), classes=["unnumbered", "course-title"], level=2) doc.content.insert(0, header)
def finalize(doc): ref_section = pf.Header(pf.Str('References'), level=1) ref_section.classes.append('unnumbered') ref_sub_section = pf.Header(pf.Str('References'), level=2) doc.content.append(ref_section) doc.content.append(ref_sub_section)
def plain(elem: Union[panflute.Div, panflute.Header], doc: panflute.Doc) -> Optional[panflute.Div]: """Assemble the plain text version of the acronym list The base plain text output is a bulleted list of acronyms in the following format:: - {short}: {long} in a new :class:`panflute.Div` with the identifier “acronym-list”. If the given element is a :class:`panflute.Div`, the list is placed under a level 1 header with the text “Acronyms” unless the ``name`` or ``level`` attributes are set in which case, the request is honored. The list is sorted by the short version of the acronyms by default unless the ``sort`` attribute is set to “false” (case insensitive) in which case the order is unspecified. If an attribute cannot be interpreted, it is omitted and a warning is logged. Parameters ---------- elem: :class:`panflute.Div` or :class:`panflute.Header` The element to replace doc: :class:`panflute.Doc` The document under consideration. Returns ------- :class:`panflute.Div`, optional: The replacement for the block. """ logger = logging.getLogger(__name__ + ".plain_text") if "acronyms" not in doc.metadata: return None if isinstance(elem, panflute.Header): header = elem elif isinstance(elem, panflute.Div): header = panflute.Header(panflute.Str( elem.attributes.get("name", "Acronyms")), level=elem.attributes.get("level", 1)) else: cls = type(elem) logger.warning(f"Unknown element type {cls}") return None if "sort" in elem.attributes: sort = elem.attributes["sort"].lower() if sort not in ("true", "false"): sort = "true" logger.warning(f"Unknown 'sort' option '{sort}'") else: sort = "true" if sort == "true": acronyms = sorted(doc.acronyms.values(), key=lambda x: x["short"]) else: acronyms = doc.acronyms.values() acrolist = [ panflute.ListItem( panflute.Plain(panflute.Strong(panflute.Str(acro["short"])), panflute.Str(":"), panflute.Space, *panflute.convert_text(acro["long"])[0].content)) for acro in acronyms if acro["list"] ] return panflute.Div(header, panflute.BulletList(*acrolist), identifier="acronym-list")