from html5tagger import Document, E, HTML import shutil import markdown import html from pathlib import Path #TODO re-think navigation bar. Think of way to add option to display navigation bar entry differently if you're currently on that page. def generateNavigationBar(lines, pagetitle): global navbar navbar = E rawhtml = False htmlstring = "" for id, line in enumerate(lines): #parse raw HTML rawhtml, navbar, htmlstring = parseRawHTML(navbar, line, htmlstring, rawhtml, id, len(lines)) #parse navigation bar (custom format) if not rawhtml: if ";" in line: #experimental dropdown parsing, to be removed or used soon #contents = [] #if "|" in line: # contents.append(line.split("|")) #else: # contents.append(line) #for entry in contents: title, link = line.split(";", 1) #mark currently open tab as active when it is open if link.strip() == pagetitle + ".page": navbar = navbar(HTML("
")) link = "#" elif link.strip() == homepage + ".page": link = "/" else: link = link.replace(" ", "-").replace(".page", "").lower() #div class for styling navbar = navbar(HTML("
")) #link and end of div if link == "#": navbar = navbar.li(HTML("" + title + "
")) else: navbar = navbar.li(HTML("" + title + "")) else: print("Error: invalid navbar entry, line " + str(id + 1) + " content: " + line) exit() return navbar def generateFooter(lines): global footer footer = E rawhtml = False htmlstring = "" for id, line in enumerate(lines): #parse raw HTML rawhtml, footer, htmlstring = parseRawHTML(footer, line, htmlstring, rawhtml, id, len(lines)) #parse markdown if not rawhtml: footer = footer.li(HTML(parseMarkdown(footer, line))) def parseRawHTML(doc, line, htmlstring, rawhtml, id, maxlines): #raw html start if line.strip() == ">": rawhtml = True htmlstring = "" #parse indented raw html elif rawhtml: if line.startswith(" "): #experimental markdown inside HTML support htmlstring = htmlstring + html.unescape(markdown.markdown(html.escape(line.strip()))) #if indented html was the last line, this is needed for it to not be ignored #since this is the end of the file, we will not set rawhtml to False. if maxlines - id == 1: doc.div(HTML(htmlstring)) else: rawhtml = False doc.div(HTML(htmlstring)) htmlstring = "" return rawhtml, doc, htmlstring def parseMarkdown(doc, line): #do not allow HTML in markdown line = html.escape(line.strip()) return markdown.markdown(line) def generateLines(title, lines): title = title.replace(".page", "") doc = Document(title, lang="en") rawhtml = False htmlstring = "" for id, line in enumerate(lines): #parse raw HTML rawhtml, doc, htmlstring = parseRawHTML(doc, line, htmlstring, rawhtml, id, len(lines)) #parse markdown if not rawhtml: doc = doc(HTML(parseMarkdown(doc, line))) generatePage(title, doc) def generatePage(title, doc): global pages global titles if 'pages' not in globals(): pages = [] if 'titles' not in globals(): titles = [] navbarfile = Path(__file__).parent.joinpath('navbar') if navbarfile.exists(): with navbarfile.open('r') as navbarfile: navbar = generateNavigationBar(navbarfile.readlines(), title) if 'footer' in globals(): pages.append(str(E.ul(navbar)) + str(doc) + str(E.ul(footer))) else: pages.append(str(E.ul(navbar)) + str(doc)) else: print("No 'navbar' file found, there will be no navigation bar.") if 'footer' in globals(): pages.append(str(doc) + str(E.ul(footer))) else: pages.append(str(doc)) titles.append(title) def writePages(): global pages global titles #TODO only delete files that aren't present in newest site generation #deleting contents of folder without deleting the folder, to increase compatibility with various systems #for root, dirs, files in os.walk('./website-output'): # for f in files: # os.unlink(os.path.join(root, f)) # for d in dirs: # rmtree(os.path.join(root, d)) for id, page in enumerate(pages): foldername = "" #creates ./website-output/pagetitle/index.html file if it is not homepage if titles[id] != homepage: foldername = titles[id].replace(" ", "-").lower() outputpath = Path(__file__).parent.joinpath("website-output") dirpath = outputpath.joinpath(foldername) dirpath.mkdir(parents=True, exist_ok=True) filepath = dirpath.joinpath("index.html") if filepath.exists(): with filepath.open('r') as newpage: if newpage.read() == page: print("Page not changed: " + titles[id]) continue with filepath.open('w') as newpage: newpage.write(page) print("Written changed page: " + titles[id]) #resources respath = Path(__file__).parent.joinpath("resources") if respath.exists(): #shutil.copytree copies timestamp too shutil.copytree(respath, outputpath, dirs_exist_ok=True) #check if folders are named correctly for folder in outputpath.iterdir(): if folder.is_dir(): #rename folder name format from "About Page" to "about-page" bettername = folder.name.replace(" ", "-").lower() if folder.name != bettername: newpath = outputpath.joinpath(bettername) #example: resources folder is "About", page got auto-created earlier as "about" (from About.page), let's copy "About" resources to "about" and delete "About" if newpath.exists(): shutil.copytree(folder, newpath, dirs_exist_ok=True) shutil.rmtree(folder) else: shutil.move(str(folder), newpath) def main(): #if homepage is at Home.page, set homepage to "Home" global homepage homepage = "Home" footerfile = Path(__file__).parent.joinpath('footer') if footerfile.exists(): with footerfile.open('r') as footerfile: generateFooter(footerfile.readlines()) else: print("No 'footer' file found, there will be no footer.") pagescount = 0 for file in Path(__file__).parent.iterdir(): if file.is_file(): if file.suffix == ".page": pagescount += 1 with file.open('r') as page: generateLines(file.stem, page.readlines()) print("Found " + str(pagescount) + " pages") #write all pages to files writePages() if __name__ == "__main__": main()