Add article metadata, turn ordering, and different source format

This commit is contained in:
Jaculabilis 2017-12-10 23:21:46 -06:00
parent d532cf7eee
commit 80f42be74d
21 changed files with 802 additions and 664 deletions

View File

@ -17,25 +17,16 @@ Lexicon Title
logo.png
<<<LOGO_FILENAME<<<
# Sidebar content. Will be read as Lexipython Markdown.
# The title header won't be displayed but needs to be included for the
# parsing to validate. Just ignore it.
>>>SIDEBAR_CONTENT>>>
# Sidebar
# The prompt for the Lexicon. Will be read as HTML and inserted into the
# header directly.
>>>PROMPT>>>
<i>Prompt goes here</i>
<<<PROMPT<<<
//Sidebar content//
<<<SIDEBAR_CONTENT<<<
# Session page content. Will be read as Lexipython Markdown.
# The content header will be displayed as the page title for the session page.
# Session page content. Will be read as HTML and inserted into the body of
# the session page directly.
>>>SESSION_PAGE>>>
# Lexicon Title
**You are [...]**. The index grouping is **[...]**.
For the first turn, give the //Rules// page a read-through. Then come up with the character of your scholar, write an article that's about 100-300 words within your assigned index, and send it to the host.
Consider putting session information here, like the index grouping and turn count, where to send completed entries, index assignments, turn schedule, and so on.
<p>Put session information here, like the index grouping and turn count, where to send completed entries, index assignments, turn schedule, and so on.</p>
<<<SESSION_PAGE<<<
# Index headers. An index is a string of characters, which are the characters

View File

@ -8,21 +8,23 @@ import re # For parsing lex content
import io # For writing pages out as UTF-8
import networkx # For pagerank analytics
from collections import defaultdict # For rank inversion in statistics
from urllib import parse
# Utility functions for handling titles and filenames
# Short utility functions for handling titles
def titlecase(s):
"""Enforces capitalization of titles."""
s = s.strip()
return s[:1].capitalize() + s[1:]
def as_filename(s):
"""Makes a string filename-safe."""
# Strip out <, >, :, ", ', /, \, |, ?, and *
s = re.sub(r"[<>:\"'/\\|?*]", '', s)
# Strip out Unicode for -
s = re.sub(r"[^\x00-\x7F]+", '-', s)
# Strip out whitespace for _
s = re.sub(r"\s+", '_', s)
def titleescape(s):
"""Makes an article title filename-safe."""
s = s.strip()
s = re.sub(r"\s+", '_', s) # Replace whitespace with _
s = parse.quote(s) # Encode all other characters
s = re.sub(r"%", "", s) # Strip encoding %s
if len(s) > 64: # If the result is unreasonably long,
s = hex(abs(hash(s)))[2:] # Replace it with a hex hash
return s
def titlestrip(s):
@ -32,130 +34,207 @@ def titlestrip(s):
if s.startswith("A "): return s[2:]
return s
def link_formatter(written_articles):
# Main article class
class LexiconArticle:
"""
Creates a lambda that formats citation links and handles the phantom class.
Input: written_articles, a list of article titles to format as live links
Output: a lambda (fid, alias, title) -> link_string
A Lexicon article and its metadata.
Members:
author string: the author of the article
turn integer: the turn the article was written for
title string: the article title
title_filesafe string: the title, escaped, used for filenames
content string: the HTML content, with citations replaced by format hooks
citations dict from format hook string to tuple of link alias and link target title
wcites list: titles of written articles cited
pcites list: titles of phantom articles cited
citedby list: titles of articles that cite this
The last three are filled in by populate().
"""
return lambda fid, alias, title: "<a href=\"{1}.html\"{2}>{0}</a>".format(
alias, as_filename(title),
"" if title in written_articles else " class=\"phantom\""
)
def __init__(self, author, turn, title, content, citations):
"""
Creates a LexiconArticle object with the given parameters.
"""
self.author = author
self.turn = turn
self.title = title
self.title_filesafe = titleescape(title)
self.content = content
self.citations = citations
self.wcites = set()
self.pcites = set()
self.citedby = set()
@staticmethod
def from_file_raw(raw_content):
"""
Parses the contents of a Lexipython source file into a LexiconArticle
object. If the source file is malformed, returns None.
"""
headers = raw_content.split('\n', 3)
if len(headers) != 4:
print("Header read error")
return None
author_header, turn_header, title_header, content_raw = headers
# Validate and sanitize the author header
if not author_header.startswith("# Author:"):
print("Author header missing")
return None
author = author_header[9:].strip()
# Validate and sanitize the turn header
if not turn_header.startswith("# Turn:"):
print("Turn header missing")
return None
turn = None
try:
turn = int(turn_header[7:].strip())
except:
print("Turn header error")
return None
# Validate and sanitize the title header
if not title_header.startswith("# Title:"):
print("Title header missing")
return None
title = titlecase(title_header[8:])
# Parse the content and extract citations
paras = re.split("\n\n+", content_raw.strip())
content = ""
citations = {}
format_id = 1
if not paras:
print("No content")
for para in paras:
# Escape angle brackets
para = re.sub("<", "&lt;", para)
para = re.sub(">", "&gt;", para)
# Replace bold and italic marks with tags
para = re.sub(r"//([^/]+)//", r"<i>\1</i>", para)
para = re.sub(r"\*\*([^*]+)\*\*", r"<b>\1</b>", para)
# Replace \\LF with <br>LF
para = re.sub(r"\\\\\n", "<br>\n", para)
# Abstract citations into the citation record
link_match = re.search(r"\[\[(([^|\[\]]+)\|)?([^|\[\]]+)\]\]", para)
while link_match:
# Identify the citation text and cited article
cite_text = link_match.group(2) if link_match.group(2) else link_match.group(3)
cite_title = titlecase(link_match.group(3))
# Record the citation
citations["c"+str(format_id)] = (cite_text, cite_title)
# Stitch the format id in place of the citation
para = para[:link_match.start(0)] + "{c"+str(format_id)+"}" + para[link_match.end(0):]
format_id += 1 # Increment to the next format citation
link_match = re.search(r"\[\[(([^|\[\]]+)\|)?([^|\[\]]+)\]\]", para)
# Convert signature to right-aligned
if para[:1] == '~':
para = "<hr><span class=\"signature\"><p>" + para[1:] + "</p></span>\n"
else:
para = "<p>" + para + "</p>\n"
content += para
return LexiconArticle(author, turn, title, content, citations)
def build_page_content(self):
"""
Formats citations into the article content as normal HTML links
and returns the result.
"""
format_map = {
format_id: "<a href=\"{1}.html\"{2}>{0}</a>".format(
cite_tuple[0], titleescape(cite_tuple[1]),
"" if cite_tuple[1] in self.wcites else " class=\"phantom\"")
for format_id, cite_tuple in self.citations.items()
}
return self.content.format(**format_map)
def build_page_citeblock(self, prev_target, next_target):
"""
Builds the citeblock content HTML for use in regular article pages.
For each defined target, links the target page as Previous or Next.
"""
citeblock = "<div class=\"content citeblock\">\n"
# Prev/next links
if next_target is not None:
citeblock += "<p style=\"float:right\"><a href=\"{}.html\">Next &#8594;</a></p>\n".format(titleescape(next_target))
if prev_target is not None:
citeblock += "<p><a href=\"{}.html\">&#8592; Previous</a></p>\n".format(titleescape(prev_target))
elif next_target is not None:
citeblock += "<p>&nbsp;</p>\n"
# Citations
cites_links = [
"<a href=\"{1}.html\"{2}>{0}</a>".format(
title, titleescape(title),
"" if title in self.wcites else " class=\"phantom\"")
for title in sorted(self.wcites | self.pcites)]
cites_str = " | ".join(cites_links)
if len(cites_str) < 1: cites_str = "--"
citeblock += "<p>Citations: {}</p>\n".format(cites_str)
# Citedby
citedby_links = [
"<a href=\"{1}.html\">{0}</a>".format(
title, titleescape(title))
for title in self.citedby]
citedby_str = " | ".join(citedby_links)
if len(citedby_str) < 1: citedby_str = "--"
citeblock += "<p>Cited by: {}</p>\n</div>\n".format(citedby_str)
return citeblock
# Parsing functions for source intake
def parse_lex_header(header_para):
def parse_from_directory(directory):
"""
Parses the header paragraph of a lex file.
Input: header_para, raw header paragraph from the lex file
Output: {"error": <error message>} if there was an error, otherwise
{"title": <article title>, "filename": <article filename>}
"""
# The title, which is also translated to the filename, heads the article after the #
title_match = re.match("#(.+)", header_para)
if not title_match:
return {"error": "No match for title"}
title = titlecase(title_match.group(1).strip())
if not title:
return {"error": "Could not parse header as title"}
return {"title": title, "filename": as_filename(title)}
def parse_lex_content(paras):
"""
Parses the content paragraphs of a lex file.
Input: paras, a list of raw paragraphs from the lex file
Output: {"error": <error message>} if there was an error, otherwise
{"content": <article HTML content>,
"citations": {<format id>: (link text, link target)}}
"""
parsed = {"content": "", "citations": {}}
format_id = 1 # Each citation will be ID'd by {c#} for formatting later
for para in paras:
# Escape angle brackets
para = re.sub("<", "&lt;", para)
para = re.sub(">", "&gt;", para)
# Replace bold and italic marks with tags
para = re.sub(r"\*\*([^*]+)\*\*", r"<b>\1</b>", para)
para = re.sub(r"\/\/([^\/]+)\/\/", r"<i>\1</i>", para)
# Replace \\LF with <br>LF
para = re.sub(r"\\\\\n", "<br>\n", para)
# Abstract citations into the citation record
link_match = re.search(r"\[\[(([^|\[\]]+)\|)?([^|\[\]]+)\]\]", para)
while link_match:
# Identify the citation text and cited article
cite_text = link_match.group(2) if link_match.group(2) else link_match.group(3)
cite_title = titlecase(link_match.group(3).strip())
# Record the citation
parsed["citations"]["c"+str(format_id)] = (cite_text, cite_title)
# Stitch the format id in place of the citation
para = para[:link_match.start(0)] + "{c"+str(format_id)+"}" + para[link_match.end(0):]
format_id += 1 # Increment to the next format citation
link_match = re.search(r"\[\[(([^|\[\]]+)\|)?([^|\[\]]+)\]\]", para)
# Convert signature to right-aligned
if para[:1] == '~':
para = "<hr><span class=\"signature\"><p>" + para[1:] + "</p></span>\n"
else:
para = "<p>" + para + "</p>\n"
parsed["content"] += para
if not parsed["content"]:
return {"error": "No content parsed"}
return parsed
def parse_lex(lex_contents):
"""
Parses the contents of a lex file into HTML and abstracts citations.
Input: lex_contents, the read contents of a lex file
Output: A dictionary in the following format:
{"title": <article title>, "filename": <article filename>,
"content": <article HTML content>,
"citations": {<format id>: (link text, link target)}}
"""
parsed_article = {}
# Split the file into paragraphs
paras = re.split("\n\n+", lex_contents)
# Parse the title from the header
title_parsed = parse_lex_header(paras.pop(0))
if "error" in title_parsed:
return title_parsed
parsed_article.update(title_parsed)
# Parse each paragraph
content_parsed = parse_lex_content(paras)
if "error" in content_parsed:
return content_parsed
parsed_article.update(content_parsed)
# Return the fully abstracted article
return parsed_article
def parse_lex_from_directory(directory):
"""
Reads and parses each lex file in the given directory.
Reads and parses each source file in the given directory.
Input: directory, the path to the folder to read
Output: a list of parsed lex file structures
Output: a list of parsed articles
"""
lexes = []
print("Reading lex files from", directory)
articles = []
print("Reading source files from", directory)
for filename in os.listdir(directory):
path = directory + filename
# Read only .lex files
if path[-4:] == ".lex":
print(" Parsing", path)
with open(path, "r", encoding="utf8") as lex_file:
lex_raw = lex_file.read()
parsed_lex = parse_lex(lex_raw)
if "error" in parsed_lex:
print(" ERROR:", parsed_lex["error"])
# Read only .txt files
if filename[-4:] == ".txt":
print(" Parsing", filename)
with open(path, "r", encoding="utf8") as src_file:
raw = src_file.read()
article = LexiconArticle.from_file_raw(raw)
if article is None:
print(" ERROR")
else:
print(" success:", parsed_lex["title"])
lexes.append(parsed_lex)
return lexes
print(" success:", article.title)
articles.append(article)
return articles
def populate(lexicon_articles):
"""
Given a list of lexicon articles, fills out citation information
for each article and creates phantom pages for missing articles.
"""
article_by_title = {article.title : article for article in lexicon_articles}
# Determine all articles that exist or should exist
extant_titles = set([citation[1] for article in lexicon_articles for citation in article.citations])
# Interlink all citations
for article in lexicon_articles:
for cite_tuple in article.citations.values():
target = cite_tuple[1]
# Create article objects for phantom citations
if target not in article_by_title:
article_by_title[target] = LexiconArticle(None, sys.maxsize, target, "<p><i>This entry hasn't been written yet.</i></p>", {})
# Interlink citations
if article_by_title[target].author is None:
article.pcites.add(target)
else:
article.wcites.add(target)
article_by_title[target].citedby.add(article.title)
return list(article_by_title.values())
def load_resource(filename, cache={}):
"""Loads files from the resources directory with caching."""
if filename not in cache:
cache[filename] = open("resources/" + filename, "r", encoding="utf8").read()
return cache[filename]
def load_config():
"""Loads values from the config file."""
config = {}
with open("lexicon.cfg", "r", encoding="utf8") as f:
line = f.readline()
@ -178,193 +257,72 @@ def load_config():
raise SystemExit("Reached EOF while reading config value {}".format(conf))
config[conf] = conf_value.strip()
# Check that all necessary values were configured
for config_value in ['LEXICON_TITLE', 'SIDEBAR_CONTENT', 'SESSION_PAGE', "INDEX_LIST"]:
for config_value in ['LEXICON_TITLE', 'PROMPT', 'SESSION_PAGE', "INDEX_LIST"]:
if config_value not in config:
raise SystemExit("Error: {} not set in lexipython.cfg".format(config_value))
return config
# Building functions for output
# Build functions
def make_cite_map(lex_list):
def build_contents_page(articles, config):
"""
Compiles all citation information into a single map.
Input: lex_list, a list of lex structures
Output: a map from article titles to cited titles
Builds the full HTML of the contents page.
"""
cite_map = {}
for lex in lex_list:
cited_titles = [cite_tuple[1] for format_id, cite_tuple in lex["citations"].items()]
cite_map[lex["title"]] = sorted(set(cited_titles), key=titlestrip)
return cite_map
def format_content(lex, format_func):
"""
Formats citations into the lex content according to the provided function.
Input: lex, a lex structure
formatted_key, the key to store the formatted content under
format_func, a function matching (fid, alias, dest) -> citation HTML
Output: lex content formatted according to format_func
"""
format_map = {
format_id: format_func(format_id, cite_tuple[0], cite_tuple[1])
for format_id, cite_tuple in lex["citations"].items()
}
return lex["content"].format(**format_map)
def citation_lists(title, cite_map):
"""
Returns the citation lists for an article.
Input: title, an article title
cite_map, generated by make_cite_map
Output: a list of cited article titles
a list of titles of article citing this article
"""
citers = [citer_title
for citer_title, cited_titles in cite_map.items()
if title in cited_titles]
return cite_map[title] if title in cite_map else [], citers
def build_article_page(lex, cite_map, config):
"""
Builds the full HTML of an article page.
Input: lex, a lex structure
cite_map, generated by make_cite_map
config, a dict of config values
Output: the full HTML as a string
"""
lf = link_formatter(cite_map.keys())
# Build the article content
content = format_content(lex, lf)
# Build the article citeblock
cites, citedby = citation_lists(lex["title"], cite_map)
cites_str = " | ".join([lf(None, title, title) for title in cites])
if len(cites_str) < 1: cites_str = "--"
citedby_str = " | ".join([lf(None, title, title) for title in citedby])
if len(citedby_str) < 1: citedby_str = "--"
citeblock = ""\
"<div class=\"content citeblock\">\n"\
"<p>Citations: {cites}</p>\n"\
"<p>Cited by: {citedby}</p>\n"\
"</div>\n".format(
cites=cites_str,
citedby=citedby_str)
# Fill in the entry skeleton
entry_skeleton = load_resource("entry-page.html")
css = load_resource("lexicon.css")
return entry_skeleton.format(
title=lex["title"],
lexicon=config["LEXICON_TITLE"],
css=css,
logo=config["LOGO_FILENAME"],
sidebar=config["SIDEBAR_HTML"],
content=content,
citeblock=citeblock)
def build_phantom_page(title, cite_map, config):
"""
Builds the full HTML of a phantom page.
Input: title, the phantom title
cite_map, generated by make_cite_map
config, a dict of config values
Output: the full HTML as a string
"""
lf = link_formatter(cite_map.keys())
# Fill in the content with filler
content = "<p><i>This entry hasn't been written yet.</i></p>"
# Build the stub citeblock
cites, citedby = citation_lists(title, cite_map)
citedby_str = " | ".join([lf(None, title, title) for title in citedby])
citeblock = ""\
"<div class=\"content citeblock\">\n"\
"<p>Cited by: {citedby}</p>\n"\
"</div>\n".format(
citedby=citedby_str)
# Fill in the entry skeleton
entry_skeleton = load_resource("entry-page.html")
css = load_resource("lexicon.css")
return entry_skeleton.format(
title=title,
lexicon=config["LEXICON_TITLE"],
css=css,
logo=config["LOGO_FILENAME"],
sidebar=config["SIDEBAR_HTML"],
content=content,
citeblock=citeblock)
def build_stub_page(title, cite_map, config):
"""
Builds the full HTML of a stub page.
Input: title, the stub title
cite_map, generated by make_cite_map
config, a dict of config values
Output: the full HTML as a string
"""
lf = link_formatter(cite_map.keys())
# Fill in the content with filler
content = "<p>[The handwriting is completely illegible.]</p>\n"\
"<hr><span class=\"signature\"><p>Ersatz Scrivener</p></span>\n"
# Build the stub citeblock
citedby = [citer_title
for citer_title, cited_titles in cite_map.items()
if title in cited_titles]
citedby_str = " | ".join([lf(None, title, title) for title in citedby])
citeblock = ""\
"<div class=\"content citeblock\">\n"\
"<p>Citations: [Illegible]</p>\n"\
"<p>Cited by: {citedby}</p>\n"\
"</div>\n".format(
citedby=citedby_str)
# Fill in the entry skeleton
entry_skeleton = load_resource("entry-page.html")
css = load_resource("lexicon.css")
return entry_skeleton.format(
title=title,
lexicon=config["LEXICON_TITLE"],
css=css,
logo=config["LOGO_FILENAME"],
sidebar=config["SIDEBAR_HTML"],
content=content,
citeblock=citeblock)
def build_index_page(cite_map, config):
"""
Builds the full HTML of the index page.
Input: cite_map, generated by make_cite_map
config, a dict of config values
Output: the HTML of the index page
"""
# Count up all the titles
titles = set(cite_map.keys()) | set([title for cited_titles in cite_map.values() for title in cited_titles])
titles = sorted(set(titles), key=titlestrip)
content = ""
if len(titles) == len(cite_map.keys()):
content = "<p>There are <b>{0}</b> entries in this lexicon.</p>\n<ul>\n".format(len(titles))
# Article counts
phantom_count = len([article for article in articles if article.author is None])
if phantom_count == 0:
content = "<p>There are <b>{0}</b> entries in this lexicon.</p>\n<ul>\n".format(len(articles))
else:
content = "<p>There are <b>{0}</b> entries, <b>{1}</b> written and <b>{2}</b> phantom.</p>\n<ul>\n".format(
len(titles), len(cite_map.keys()), len(titles) - len(cite_map.keys()))
# Write all of the entries out as links under their indices
lf = link_formatter(cite_map.keys())
content = "<p>There are <b>{0}</b> entries, <b>{1}</b> written and <b>{2}</b> phantom.</p>\n".format(
len(articles), len(articles) - phantom_count, phantom_count)
# Prepare article links
link_by_title = {article.title : "<a href=\"../article/{1}.html\"{2}>{0}</a>".format(
article.title, article.title_filesafe,
"" if article.author is not None else " class=\"phantom\"")
for article in articles}
# Write the articles in alphabetical order
content += load_resource("contents.html")
content += "<div id=\"index-order\" style=\"display:block\">\n<ul>\n"
indices = config["INDEX_LIST"].split("\n")
alphabetical_order = sorted(articles, key=lambda a: a.title)
check_off = list(alphabetical_order)
for index_str in indices:
content += "<h3>{0}</h3>".format(index_str)
index_titles = []
for c in index_str.upper():
for title in titles:
if (titlestrip(title)[0] == c):
index_titles.append(title)
for title in index_titles:
titles.remove(title)
content += "<h3>{0}</h3>\n".format(index_str)
for article in alphabetical_order:
if (titlestrip(article.title)[0].upper() in index_str):
check_off.remove(article)
content += "<li>"
content += link_by_title[article.title]
content += "</li>\n"
if len(check_off) > 0:
content += "<h3>&c.</h3>\n".format(index_str)
for article in check_off:
content += "<li>"
content += lf(None, title, title)
content += link_by_title[article.title]
content += "</li>\n"
if len(titles) > 0:
content += "<h3>&c.</h3>".format(index_str)
for title in titles:
content += "</ul>\n</div>\n"
# Write the articles in turn order
content += "<div id=\"turn-order\" style=\"display:none\">\n<ul>\n"
latest_turn = max([article.turn for article in articles if article.author is not None])
turn_order = sorted(articles, key=lambda a: (a.turn, a.title))
check_off = list(turn_order)
for turn_num in range(1, latest_turn + 1):
content += "<h3>Turn {0}</h3>\n".format(turn_num)
for article in turn_order:
if article.turn == turn_num:
check_off.remove(article)
content += "<li>"
content += link_by_title[article.title]
content += "</li>\n"
if len(check_off) > 0:
content += "<h3>Unwritten</h3>\n"
for article in check_off:
content += "<li>"
content += lf(None, title, title)
content += link_by_title[article.title]
content += "</li>\n"
content += "</ul>\n"
# Fill in the entry skeleton
content += "</ul>\n</div>\n"
# Fill in the page skeleton
entry_skeleton = load_resource("entry-page.html")
css = load_resource("lexicon.css")
return entry_skeleton.format(
@ -372,15 +330,13 @@ def build_index_page(cite_map, config):
lexicon=config["LEXICON_TITLE"],
css=css,
logo=config["LOGO_FILENAME"],
sidebar=config["SIDEBAR_HTML"],
prompt=config["PROMPT"],
content=content,
citeblock="")
def build_rules_page(config):
"""
Builds the full HTML of the rules page.
Input: config, a dict of config values
Output: the HTML of the rules page
"""
content = load_resource("rules.html")
# Fill in the entry skeleton
@ -391,15 +347,13 @@ def build_rules_page(config):
lexicon=config["LEXICON_TITLE"],
css=css,
logo=config["LOGO_FILENAME"],
sidebar=config["SIDEBAR_HTML"],
prompt=config["PROMPT"],
content=content,
citeblock="")
def build_formatting_page(config):
"""
Builds the full HTML of the formatting page.
Input: config, a dict of config values
Output: the HTML of the formatting page
"""
content = load_resource("formatting.html")
# Fill in the entry skeleton
@ -410,40 +364,35 @@ def build_formatting_page(config):
lexicon=config["LEXICON_TITLE"],
css=css,
logo=config["LOGO_FILENAME"],
sidebar=config["SIDEBAR_HTML"],
prompt=config["PROMPT"],
content=content,
citeblock="")
def build_session_page(config):
"""
Builds the full HTML of the session page.
Input: config, a dict of config values
Output: the HTML of the session page
"""
session_lex = parse_lex(config["SESSION_PAGE"])
content = format_content(session_lex, lambda fid,alias,dest: "<u>" + alias + "</u>")
# Fill in the entry skeleton
entry_skeleton = load_resource("entry-page.html")
css = load_resource("lexicon.css")
return entry_skeleton.format(
title=session_lex["title"],
title=config["LEXICON_TITLE"],
lexicon=config["LEXICON_TITLE"],
css=css,
logo=config["LOGO_FILENAME"],
sidebar=config["SIDEBAR_HTML"],
content=content,
prompt=config["PROMPT"],
content=config["SESSION_PAGE"],
citeblock="")
def build_statistics_page(cite_map, config):
def build_statistics_page(articles, config):
"""
Builds the full HTML of the statistics page.
Input: citation_map, a dictionary returned by make_cite_map
config, a dict of config values
Output: the HTML of the statistics page
"""
content = ""
# Compute the pagerank
content += "<p><u>Top 10 by page rank:</u><br>\n"
cite_map = {article.title : [cite_tuple[1] for cite_tuple in article.citations.values()] for article in articles}
# Pages by pagerank
content += "<div class=\"moveable\">\n"
content += "<p><u>Top 10 pages by page rank:</u><br>\n"
G = networkx.Graph()
for citer, citeds in cite_map.items():
for cited in citeds:
@ -451,18 +400,22 @@ def build_statistics_page(cite_map, config):
ranks = networkx.pagerank(G)
sranks = sorted(ranks.items(), key=lambda x: x[1], reverse=True)
ranking = list(enumerate(map(lambda x: x[0], sranks)))
content += "<br>\n".join(map(lambda x: "{0} - {1}".format(x[0]+1, x[1]), ranking[:10]))
content += "<br>\n".join(map(lambda x: "{0} &ndash; {1}".format(x[0]+1, x[1]), ranking[:10]))
content += "</p>\n"
# Count the top number of citations made from
content += "</div>\n"
# Top numebr of citations made
content += "<div class=\"moveable\">\n"
content += "<p><u>Most citations made from:</u><br>\n"
citation_tally = [(kv[0], len(kv[1])) for kv in cite_map.items()]
citation_count = defaultdict(list)
for title, count in citation_tally: citation_count[count].append(title)
content += "<br>\n".join(map(
lambda kv: "{0} - {1}".format(kv[0], "; ".join(kv[1])),
lambda kv: "{0} &ndash; {1}".format(kv[0], "; ".join(kv[1])),
sorted(citation_count.items(), reverse=True)[:3]))
content += "</p>\n"
# Count the top number of citations made to
content += "</div>\n"
# Top number of times cited
content += "<div class=\"moveable\">\n"
content += "<p><u>Most citations made to:</u><br>\n"
all_cited = set([title for cites in cite_map.values() for title in cites])
cited_by_map = { cited: [citer for citer in cite_map.keys() if cited in cite_map[citer]] for cited in all_cited }
@ -470,13 +423,43 @@ def build_statistics_page(cite_map, config):
cited_count = defaultdict(list)
for title, count in cited_tally: cited_count[count].append(title)
content += "<br>\n".join(map(
lambda kv: "{0} - {1}".format(kv[0], "; ".join(kv[1])),
lambda kv: "{0} &ndash; {1}".format(kv[0], "; ".join(kv[1])),
sorted(cited_count.items(), reverse=True)[:3]))
#cited_count = map(lambda kv: (kv[0], len(kv[1])), cited_by_map.items())
#cited_count_sort = sorted(cited_count, key=lambda x: x[1], reverse=True)
#top_cited_count = [kv for kv in cited_count_sort if kv[1] >= cited_count_sort[:5][-1][1]]
#content += "<br>\n".join(map(lambda x: "{0} - {1}".format(x[1], x[0]), top_cited_count))
content += "</p>\n"
content += "</div>\n"
# Author pageranks
content += "<div class=\"moveable\">\n"
content += "<p><u>Author total page rank:</u><br>\n"
authors = sorted(set([article.author for article in articles if article.author is not None]))
articles_by = {author : [a for a in articles if a.author == author] for author in authors}
author_rank = {author : sum(map(lambda a: ranks[a.title], articles)) for author, articles in articles_by.items()}
content += "<br>\n".join(map(
lambda kv: "{0} &ndash; {1}".format(kv[0], round(kv[1], 3)),
sorted(author_rank.items(), key=lambda t:-t[1])))
content += "</p>\n"
content += "</div>\n"
# Author citations made
content += "<div class=\"moveable\">\n"
content += "<p><u>Citations made by author</u><br>\n"
author_cite_count = {author : sum(map(lambda a:len(a.wcites | a.pcites), articles)) for author, articles in articles_by.items()}
content += "<br>\n".join(map(
lambda kv: "{0} &ndash; {1}".format(kv[0], kv[1]),
sorted(author_cite_count.items(), key=lambda t:-t[1])))
content += "</p>\n"
content += "</div>\n"
# Author cited count
content += "<div class=\"moveable\">\n"
content += "<p><u>Citations made to author</u><br>\n"
cited_times = {author : 0 for author in authors}
for article in articles:
if article.author is not None:
cited_times[article.author] += len(article.citedby)
content += "<br>\n".join(map(
lambda kv: "{0} &ndash; {1}".format(kv[0], kv[1]),
sorted(cited_times.items(), key=lambda t:-t[1])))
content += "</p>\n"
content += "</div>\n"
# Fill in the entry skeleton
entry_skeleton = load_resource("entry-page.html")
css = load_resource("lexicon.css")
@ -485,78 +468,100 @@ def build_statistics_page(cite_map, config):
lexicon=config["LEXICON_TITLE"],
css=css,
logo=config["LOGO_FILENAME"],
sidebar=config["SIDEBAR_HTML"],
prompt=config["PROMPT"],
content=content,
citeblock="")
def build_graphviz_file(cite_map):
"""
Builds a citation graph in dot format for Graphviz.
"""
result = []
result.append("digraph G {\n")
# Node labeling
written_entries = list(cite_map.keys())
phantom_entries = set([title for cites in cite_map.values() for title in cites if title not in written_entries])
node_labels = [title[:20] for title in written_entries + list(phantom_entries)]
node_names = [hash(i) for i in node_labels]
for i in range(len(node_labels)):
result.append("{} [label=\"{}\"];\n".format(node_names[i], node_labels[i]))
# Edges
for citer in written_entries:
for cited in cite_map[citer]:
result.append("{}->{};\n".format(hash(citer[:20]), hash(cited[:20])))
# Return result
result.append("overlap=false;\n}\n")
return "".join(result)#"…"
# Summative functions
def command_build(argv):
if len(argv) >= 3 and (argv[2] != "partial" and argv[2] != "full"):
print("unknown build type: " + argv[2])
return
# Set up the entries
# Load content
config = load_config()
sidebar_parsed = parse_lex(config["SIDEBAR_CONTENT"])
config["SIDEBAR_HTML"] = format_content(sidebar_parsed, lambda fid,alias,dest: alias)
lexes = parse_lex_from_directory("raw/")
cite_map = make_cite_map(lexes)
written_entries = cite_map.keys()
phantom_entries = set([title for cites in cite_map.values() for title in cites if title not in written_entries])
# Clear the folder
print("Clearing old HTML files")
for filename in os.listdir("out/"):
if filename[-5:] == ".html":
os.remove("out/" + filename)
# Write the written entries
print("Writing written articles...")
for lex in lexes:
page = build_article_page(lex, cite_map, config)
with open("out/" + lex["filename"] + ".html", "w", encoding="utf8") as f:
f.write(page)
print(" Wrote " + lex["title"])
# Write the unwritten entries
if len(phantom_entries) > 0:
if len(argv) < 3 or argv[2] == "partial":
print("Writing phantom articles...")
for title in phantom_entries:
page = build_phantom_page(title, cite_map, config)
with open("out/" + as_filename(title) + ".html", "w", encoding="utf8") as f:
f.write(page)
print(" Wrote " + title)
elif argv[2] == "full":
print("Writing stub articles...")
for title in phantom_entries:
page = build_stub_page(title, cite_map, config)
with open("out/" + as_filename(title) + ".html", "w", encoding="utf8") as f:
f.write(page)
print(" Wrote " + title)
else:
print("ERROR: build type was " + argv[2])
return
# Write the default pages
print("Writing default pages")
page = build_rules_page(config)
with open("out/rules.html", "w", encoding="utf8") as f:
f.write(page)
print(" Wrote Rules")
page = build_formatting_page(config)
with open("out/formatting.html", "w", encoding="utf8") as f:
f.write(page)
print(" Wrote Formatting")
page = build_index_page(cite_map, config)
entry_skeleton = load_resource("entry-page.html")
css = load_resource("lexicon.css")
articles = [article for article in parse_from_directory("raw/") if article is not None]
written_titles = [article.title for article in articles]
articles = sorted(populate(articles), key=lambda a: (a.turn, a.title))
#print(articles[13].title_filesafe)
#return
phantom_titles = [article.title for article in articles if article.title not in written_titles]
# Write the redirect page
print("Writing redirect page...")
with open("out/index.html", "w", encoding="utf8") as f:
f.write(page)
print(" Wrote Index")
page = build_session_page(config)
with open("out/session.html", "w", encoding="utf8") as f:
f.write(page)
f.write(load_resource("redirect.html").format(lexicon=config["LEXICON_TITLE"]))
# Write the article pages
print("Deleting old article pages...")
for filename in os.listdir("out/article/"):
if filename[-5:] == ".html":
os.remove("out/article/" + filename)
print("Writing article pages...")
l = len(articles)
for idx in range(l):
article = articles[idx]
with open("out/article/" + article.title_filesafe + ".html", "w", encoding="utf8") as f:
content = article.build_page_content()
citeblock = article.build_page_citeblock(
None if idx == 0 else articles[idx - 1].title,
None if idx == l-1 else articles[idx + 1].title)
article_html = entry_skeleton.format(
title = article.title,
lexicon = config["LEXICON_TITLE"],
css = css,
logo = config["LOGO_FILENAME"],
prompt = config["PROMPT"],
content = content,
citeblock = citeblock)
f.write(article_html)
print(" Wrote " + article.title)
# Write default pages
print("Writing default pages...")
with open("out/contents/index.html", "w", encoding="utf8") as f:
f.write(build_contents_page(articles, config))
print(" Wrote Contents")
with open("out/rules/index.html", "w", encoding="utf8") as f:
f.write(build_rules_page(config))
print(" Wrote Rules")
with open("out/formatting/index.html", "w", encoding="utf8") as f:
f.write(build_formatting_page(config))
print(" Wrote Formatting")
with open("out/session/index.html", "w", encoding="utf8") as f:
f.write(build_session_page(config))
print(" Wrote Session")
page = build_statistics_page(cite_map, config)
with open("out/stats.html", "w", encoding="utf8") as f:
f.write(page)
with open("out/statistics/index.html", "w", encoding="utf8") as f:
f.write(build_statistics_page(articles, config))
print(" Wrote Statistics")
# Write auxiliary files
# TODO: write graphviz file
# TODO: write compiled lexicon page
def main():
if len(sys.argv) < 2:
print("Available commands:")

View File

@ -1,42 +0,0 @@
<html>
<head>
<title>Example page | Lexicon Title</title>
<style>
body { background-color: #eeeeee; margin: 10px; }
div#header { background-color: #ffffff; margin: 10px 0; padding: 8px; box-shadow: 2px 2px 10px #888888; }
div.header-option { display:inline-block; margin-right: 20px; }
div#sidebar-outer { width: 140px; background-color: #ffffff; float:left; box-shadow: 2px 2px 10px #888888; padding: 5px; }
div#sidebar-inner { padding: 5px; }
img#logo { width: 140px; }
div.content { margin-left: 160px; margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; }
a.phantom { color: #cc2200; }
div.citeblock a.phantom { font-style: italic; }
span.signature { text-align: right; }
</style>
</head>
<body>
<div id="header">
<div class="header-option"><h2 style="margin:0px;">Lexicon Title</h2></div>
<div class="header-option"><a href="./rules.html">Rules</a></div>
<div class="header-option"><a href="./formatting.html">Formatting</a></div>
<div class="header-option"><a href="./index.html">Index</a></div>
<div class="header-option"><a href="./session.html">Session</a></div>
<div class="header-option"><a href="./stats.html">Statistics</a></div>
</div>
<div id="sidebar-outer">
<img id="logo" src="logo.png">
<div id="sidebar-inner">
<p><i>Sidebar content</i></p>
</div>
</div>
<div class="content">
<h1>Example page</h1>
<p>This is an example page.</p>
<hr><span class="signature"><p>Signature</p></span>
</div>
<div class="content citeblock">
<p>Citations: </p>
<p>Cited by: </p>
</div>
</body>
</html>

View File

@ -0,0 +1,49 @@
<html>
<head>
<title>Example page | Lexicon Title</title>
<!--<link rel="shortcut icon" href="favicon.png" />-->
<style>
body { background-color: #eeeeee; margin: 10px; }
div#header { background-color: #ffffff; margin: 10px 0; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
img#logo { float:left; margin:8px; max-width: 140px; }
div#header p { margin:10px; }
div.content { margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
a.phantom { color: #cc2200; }
div.citeblock a.phantom { font-style: italic; }
span.signature { text-align: right; }
div.moveable { float: left; margin: 8px; }
div.moveable p { margin: 0px; }
</style>
</head>
<body>
<div id="header">
<img id="logo" src="../logo.png">
<p><span style="font-size:1.5em;">Lexicon Title</span></p>
<p>
<a href="../contents">Contents</a> &mdash;
<a href="../rules/">Rules</a> &mdash;
<a href="../formatting/">Formatting</a> &mdash;
<a href="../session/">Session</a> &mdash;
<a href="../statistics/">Statistics</a>
</p>
<p><i>Prompt goes here</i></p>
</div>
<div class="content">
<h1>Example page</h1>
<p>This is an example page.
Some words are <i>italicized</i>,
and some words are <b>bolded</b>.
All of these sentences are part of the same paragraph.</p>
<p>This is a new paragraph.<br>
Unlike the last paragraph, this line will be after a line break within the paragraph.</p>
<p>This is an <a href="Phantom_page.html" class="phantom">example citation</a>. You can also cite a <a href="Phantom_page.html" class="phantom">phantom page</a> with just the title.</p>
<hr><span class="signature"><p>Dr. X. Amplepage</p></span>
</div>
<div class="content citeblock">
<p style="float:right"><a href="Phantom_page.html">Next &#8594;</a></p>
<p>&nbsp;</p>
<p>Citations: <a href="Phantom_page.html" class="phantom">Phantom page</a></p>
<p>Cited by: --</p>
</div>
</body>
</html>

View File

@ -0,0 +1,40 @@
<html>
<head>
<title>Phantom page | Lexicon Title</title>
<!--<link rel="shortcut icon" href="favicon.png" />-->
<style>
body { background-color: #eeeeee; margin: 10px; }
div#header { background-color: #ffffff; margin: 10px 0; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
img#logo { float:left; margin:8px; max-width: 140px; }
div#header p { margin:10px; }
div.content { margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
a.phantom { color: #cc2200; }
div.citeblock a.phantom { font-style: italic; }
span.signature { text-align: right; }
div.moveable { float: left; margin: 8px; }
div.moveable p { margin: 0px; }
</style>
</head>
<body>
<div id="header">
<img id="logo" src="../logo.png">
<p><span style="font-size:1.5em;">Lexicon Title</span></p>
<p>
<a href="../contents">Contents</a> &mdash;
<a href="../rules/">Rules</a> &mdash;
<a href="../formatting/">Formatting</a> &mdash;
<a href="../session/">Session</a> &mdash;
<a href="../statistics/">Statistics</a>
</p>
<p><i>Prompt goes here</i></p>
</div>
<div class="content">
<h1>Phantom page</h1>
<p><i>This entry hasn't been written yet.</i></p></div>
<div class="content citeblock">
<p><a href="Example_page.html">&#8592; Previous</a></p>
<p>Citations: --</p>
<p>Cited by: <a href="Example_page.html">Example page</a></p>
</div>
</body>
</html>

75
out/contents/index.html Normal file
View File

@ -0,0 +1,75 @@
<html>
<head>
<title>Index of Lexicon Title | Lexicon Title</title>
<!--<link rel="shortcut icon" href="favicon.png" />-->
<style>
body { background-color: #eeeeee; margin: 10px; }
div#header { background-color: #ffffff; margin: 10px 0; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
img#logo { float:left; margin:8px; max-width: 140px; }
div#header p { margin:10px; }
div.content { margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
a.phantom { color: #cc2200; }
div.citeblock a.phantom { font-style: italic; }
span.signature { text-align: right; }
div.moveable { float: left; margin: 8px; }
div.moveable p { margin: 0px; }
</style>
</head>
<body>
<div id="header">
<img id="logo" src="../logo.png">
<p><span style="font-size:1.5em;">Lexicon Title</span></p>
<p>
<a href="../contents">Contents</a> &mdash;
<a href="../rules/">Rules</a> &mdash;
<a href="../formatting/">Formatting</a> &mdash;
<a href="../session/">Session</a> &mdash;
<a href="../statistics/">Statistics</a>
</p>
<p><i>Prompt goes here</i></p>
</div>
<div class="content">
<h1>Index of Lexicon Title</h1>
<p>There are <b>2</b> entries, <b>1</b> written and <b>1</b> phantom.</p>
<script type="text/javascript">
contentsToggle = function() {
var b = document.getElementById("toggle-button")
var i = document.getElementById("index-order");
var t = document.getElementById("turn-order");
if (t.style.display == "none") {
i.style.display = "none"
t.style.display = "block"
b.innerText = "Switch to index order"
} else {
i.style.display = "block"
t.style.display = "none"
b.innerText = "switch to turn order"
}
}
</script>
<button id="toggle-button" onClick="javascript:contentsToggle()">Switch to turn order</button>
<div id="index-order" style="display:block">
<ul>
<h3>ABC</h3>
<h3>DEF</h3>
<li><a href="../article/Example_page.html">Example page</a></li>
<h3>GHI</h3>
<h3>JKL</h3>
<h3>MNO</h3>
<h3>PQRS</h3>
<li><a href="../article/Phantom_page.html" class="phantom">Phantom page</a></li>
<h3>TUV</h3>
<h3>WXYZ</h3>
</ul>
</div>
<div id="turn-order" style="display:none">
<ul>
<h3>Turn 1</h3>
<li><a href="../article/Example_page.html">Example page</a></li>
<h3>Unwritten</h3>
<li><a href="../article/Phantom_page.html" class="phantom">Phantom page</a></li>
</ul>
</div>
</div>
</body>
</html>

View File

@ -1,52 +0,0 @@
<html>
<head>
<title>Formatting | Lexicon Title</title>
<style>
body { background-color: #eeeeee; margin: 10px; }
div#header { background-color: #ffffff; margin: 10px 0; padding: 8px; box-shadow: 2px 2px 10px #888888; }
div.header-option { display:inline-block; margin-right: 20px; }
div#sidebar-outer { width: 140px; background-color: #ffffff; float:left; box-shadow: 2px 2px 10px #888888; padding: 5px; }
div#sidebar-inner { padding: 5px; }
img#logo { width: 140px; }
div.content { margin-left: 160px; margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; }
a.phantom { color: #cc2200; }
div.citeblock a.phantom { font-style: italic; }
span.signature { text-align: right; }
</style>
</head>
<body>
<div id="header">
<div class="header-option"><h2 style="margin:0px;">Lexicon Title</h2></div>
<div class="header-option"><a href="./rules.html">Rules</a></div>
<div class="header-option"><a href="./formatting.html">Formatting</a></div>
<div class="header-option"><a href="./index.html">Index</a></div>
<div class="header-option"><a href="./session.html">Session</a></div>
<div class="header-option"><a href="./stats.html">Statistics</a></div>
</div>
<div id="sidebar-outer">
<img id="logo" src="logo.png">
<div id="sidebar-inner">
<p><i>Sidebar content</i></p>
</div>
</div>
<div class="content">
<h1>Formatting</h1>
<p>Lexipython provides support for a limited amount of Markdown-esque formatting. The parsing rules that will be applied are as follows:</p>
<p>Entries must begin with a header declaring the entry title. Format this header as "# Title", e.g. "# Formatting". This is the name that citations to your entry will use.</p>
<p>Two line breaks begin a new paragraph. Lines separated by a single line break will be part of the same paragraph, unless the line is ended by a double backslash:<br>
&nbsp;&nbsp;Sample \\<br>
&nbsp;&nbsp;text <br>
&nbsp;&nbsp;here <br>
in your markdown produces<br>
&nbsp;&nbsp;Sample <br>
&nbsp;&nbsp;text
here <br>
in the generated page.</p>
<p>Text bounded by ** will be bolded: **bold** produces <b>bold</b>. Text bounded by // will be italicized: //italics// produces <i>italics</i>.</p>
<p>To cite another Lexicon entry, use double brackets. Text in double brackets will cite and link to the entry of the same name: [[Example page]] produces <a href="Example_page.html" class="phantom">Example page</a>. Text in double brackets split with a | will alias the link as the left text and link to the entry with the name of the right text: [[this text|Example page]] produces <a href="Example_page.html" class="phantom">this text</a>. <b>You must be precise in the entry title you cite to.</b> Citations to "Example" vs. "The Example" will point to different entries and create different phantoms, and your GM will probably have to clean up after you.
<p>Entries should end with a footer signing the entry with its author. Format this footer as "~ Signature". Signature lines will be set apart by a horizotal rule and right-aligned:</p>
<span class="signature"><p> Signature</p></span>
</div>
</body>
</html>

58
out/formatting/index.html Normal file
View File

@ -0,0 +1,58 @@
<html>
<head>
<title>Formatting | Lexicon Title</title>
<!--<link rel="shortcut icon" href="favicon.png" />-->
<style>
body { background-color: #eeeeee; margin: 10px; }
div#header { background-color: #ffffff; margin: 10px 0; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
img#logo { float:left; margin:8px; max-width: 140px; }
div#header p { margin:10px; }
div.content { margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
a.phantom { color: #cc2200; }
div.citeblock a.phantom { font-style: italic; }
span.signature { text-align: right; }
div.moveable { float: left; margin: 8px; }
div.moveable p { margin: 0px; }
</style>
</head>
<body>
<div id="header">
<img id="logo" src="../logo.png">
<p><span style="font-size:1.5em;">Lexicon Title</span></p>
<p>
<a href="../contents">Contents</a> &mdash;
<a href="../rules/">Rules</a> &mdash;
<a href="../formatting/">Formatting</a> &mdash;
<a href="../session/">Session</a> &mdash;
<a href="../statistics/">Statistics</a>
</p>
<p><i>Prompt goes here</i></p>
</div>
<div class="content">
<h1>Formatting</h1>
<p>Lexipython provides support for a limited amount of Markdown-esque formatting.</p>
<pre style="background:#eeeeee">
# Author: Authorname
# Turn: 1
# Title: Example page
This is an example page.
Some words are //italicized//,
and some words are **bolded**.
All of these sentences are part of the same paragraph.
This is a new paragraph.\\
Unlike the last paragraph, this line will be after a line break within the paragraph.
This is an [[example citation|Phantom page]]. You can also cite a [[phantom page]] with just the title.
~Dr. X. Amplepage
</pre>
<p>Each turn, fill out the header with your author information, the current turn, and the title of your entry. It doesn't really matter what the <i>Author</i> field is, except that it must be the same across all articles you write.</p>
<p>Two line breaks begins a new paragraph. A single line break does nothing, unless the line is neded by a double backslash (\\).</p>
<p>Text bounded by ** will be bolded: **bold** produces <b>bold</b>. Text bounded by // will be italicized: //italics// produces <i>italics</i>.</p>
<p>To cite another Lexicon entry, use double brackets. Text in double brackets will cite and link to the entry of the same name: [[Example page]] produces <a href="Example_page.html" class="phantom">Example page</a>. Text in double brackets split with a | will alias the link as the left text and link to the entry with the name of the right text: [[this text|Example page]] produces <a href="Example_page.html" class="phantom">this text</a>. <b>You must be precise in the entry title you cite to.</b> Citations to "Example" vs. "The Example" will point to different entries and create different phantoms, and your GM will probably have to clean up after you.</p>
<p>Beginning a paragraph with ~ will right-align it and place a horizontal line above it. Use this for signing your entry with your scholar's name.</p>
</div>
</body>
</html>

View File

@ -1,40 +1,9 @@
<html>
<head>
<title>Index of Lexicon Title | Lexicon Title</title>
<style>
body { background-color: #eeeeee; margin: 10px; }
div#header { background-color: #ffffff; margin: 10px 0; padding: 8px; box-shadow: 2px 2px 10px #888888; }
div.header-option { display:inline-block; margin-right: 20px; }
div#sidebar-outer { width: 140px; background-color: #ffffff; float:left; box-shadow: 2px 2px 10px #888888; padding: 5px; }
div#sidebar-inner { padding: 5px; }
img#logo { width: 140px; }
div.content { margin-left: 160px; margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; }
a.phantom { color: #cc2200; }
div.citeblock a.phantom { font-style: italic; }
span.signature { text-align: right; }
</style>
<title>Lexicon Title</title>
<meta http-equiv="refresh" content="0; url=contents/" />
</head>
<body>
<div id="header">
<div class="header-option"><h2 style="margin:0px;">Lexicon Title</h2></div>
<div class="header-option"><a href="./rules.html">Rules</a></div>
<div class="header-option"><a href="./formatting.html">Formatting</a></div>
<div class="header-option"><a href="./index.html">Index</a></div>
<div class="header-option"><a href="./session.html">Session</a></div>
<div class="header-option"><a href="./stats.html">Statistics</a></div>
</div>
<div id="sidebar-outer">
<img id="logo" src="logo.png">
<div id="sidebar-inner">
<p><i>Sidebar content</i></p>
</div>
</div>
<div class="content">
<h1>Index of Lexicon Title</h1>
<p>There are <b>1</b> entries in this lexicon.</p>
<ul>
<h3>ABC</h3><h3>DEF</h3><li><a href="Example_page.html">Example page</a></li>
<h3>GHI</h3><h3>JKL</h3><h3>MNO</h3><h3>PQRS</h3><h3>TUV</h3><h3>WXYZ</h3></ul>
</div>
<p>Redirecting to <a href="contents/">Lexicon Title</a>...</p>
</body>
</html>

View File

@ -1,33 +1,32 @@
<html>
<head>
<title>Rules | Lexicon Title</title>
<!--<link rel="shortcut icon" href="favicon.png" />-->
<style>
body { background-color: #eeeeee; margin: 10px; }
div#header { background-color: #ffffff; margin: 10px 0; padding: 8px; box-shadow: 2px 2px 10px #888888; }
div.header-option { display:inline-block; margin-right: 20px; }
div#sidebar-outer { width: 140px; background-color: #ffffff; float:left; box-shadow: 2px 2px 10px #888888; padding: 5px; }
div#sidebar-inner { padding: 5px; }
img#logo { width: 140px; }
div.content { margin-left: 160px; margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; }
div#header { background-color: #ffffff; margin: 10px 0; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
img#logo { float:left; margin:8px; max-width: 140px; }
div#header p { margin:10px; }
div.content { margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
a.phantom { color: #cc2200; }
div.citeblock a.phantom { font-style: italic; }
span.signature { text-align: right; }
div.moveable { float: left; margin: 8px; }
div.moveable p { margin: 0px; }
</style>
</head>
<body>
<div id="header">
<div class="header-option"><h2 style="margin:0px;">Lexicon Title</h2></div>
<div class="header-option"><a href="./rules.html">Rules</a></div>
<div class="header-option"><a href="./formatting.html">Formatting</a></div>
<div class="header-option"><a href="./index.html">Index</a></div>
<div class="header-option"><a href="./session.html">Session</a></div>
<div class="header-option"><a href="./stats.html">Statistics</a></div>
</div>
<div id="sidebar-outer">
<img id="logo" src="logo.png">
<div id="sidebar-inner">
<p><i>Sidebar content</i></p>
</div>
<img id="logo" src="../logo.png">
<p><span style="font-size:1.5em;">Lexicon Title</span></p>
<p>
<a href="../contents">Contents</a> &mdash;
<a href="../rules/">Rules</a> &mdash;
<a href="../formatting/">Formatting</a> &mdash;
<a href="../session/">Session</a> &mdash;
<a href="../statistics/">Statistics</a>
</p>
<p><i>Prompt goes here</i></p>
</div>
<div class="content">
<h1>Rules</h1>

View File

@ -1,39 +0,0 @@
<html>
<head>
<title>Lexicon Proximum | Lexicon Title</title>
<style>
body { background-color: #eeeeee; margin: 10px; }
div#header { background-color: #ffffff; margin: 10px 0; padding: 8px; box-shadow: 2px 2px 10px #888888; }
div.header-option { display:inline-block; margin-right: 20px; }
div#sidebar-outer { width: 140px; background-color: #ffffff; float:left; box-shadow: 2px 2px 10px #888888; padding: 5px; }
div#sidebar-inner { padding: 5px; }
img#logo { width: 140px; }
div.content { margin-left: 160px; margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; }
a.phantom { color: #cc2200; }
div.citeblock a.phantom { font-style: italic; }
span.signature { text-align: right; }
</style>
</head>
<body>
<div id="header">
<div class="header-option"><h2 style="margin:0px;">Lexicon Title</h2></div>
<div class="header-option"><a href="./rules.html">Rules</a></div>
<div class="header-option"><a href="./formatting.html">Formatting</a></div>
<div class="header-option"><a href="./index.html">Index</a></div>
<div class="header-option"><a href="./session.html">Session</a></div>
<div class="header-option"><a href="./stats.html">Statistics</a></div>
</div>
<div id="sidebar-outer">
<img id="logo" src="logo.png">
<div id="sidebar-inner">
<p><i>Sidebar content</i></p>
</div>
</div>
<div class="content">
<h1>Lexicon Proximum</h1>
<p><b>You are [...]</b>. The index grouping is <b>[...]</b>.</p>
<p>For the first turn, give the <i>Rules</i> page a read-through. Then come up with the character of your scholar, write an article that's about 100-300 words within your assigned index, and send it to the host.</p>
<p>Consider putting session information here, like the index grouping and turn count, where to send completed entries, index assignments, turn schedule, and so on.</p>
</div>
</body>
</html>

35
out/session/index.html Normal file
View File

@ -0,0 +1,35 @@
<html>
<head>
<title>Lexicon Title | Lexicon Title</title>
<!--<link rel="shortcut icon" href="favicon.png" />-->
<style>
body { background-color: #eeeeee; margin: 10px; }
div#header { background-color: #ffffff; margin: 10px 0; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
img#logo { float:left; margin:8px; max-width: 140px; }
div#header p { margin:10px; }
div.content { margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
a.phantom { color: #cc2200; }
div.citeblock a.phantom { font-style: italic; }
span.signature { text-align: right; }
div.moveable { float: left; margin: 8px; }
div.moveable p { margin: 0px; }
</style>
</head>
<body>
<div id="header">
<img id="logo" src="../logo.png">
<p><span style="font-size:1.5em;">Lexicon Title</span></p>
<p>
<a href="../contents">Contents</a> &mdash;
<a href="../rules/">Rules</a> &mdash;
<a href="../formatting/">Formatting</a> &mdash;
<a href="../session/">Session</a> &mdash;
<a href="../statistics/">Statistics</a>
</p>
<p><i>Prompt goes here</i></p>
</div>
<div class="content">
<h1>Lexicon Title</h1>
<p>Put session information here, like the index grouping and turn count, where to send completed entries, index assignments, turn schedule, and so on.</p></div>
</body>
</html>

61
out/statistics/index.html Normal file
View File

@ -0,0 +1,61 @@
<html>
<head>
<title>Statistics | Lexicon Title</title>
<!--<link rel="shortcut icon" href="favicon.png" />-->
<style>
body { background-color: #eeeeee; margin: 10px; }
div#header { background-color: #ffffff; margin: 10px 0; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
img#logo { float:left; margin:8px; max-width: 140px; }
div#header p { margin:10px; }
div.content { margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
a.phantom { color: #cc2200; }
div.citeblock a.phantom { font-style: italic; }
span.signature { text-align: right; }
div.moveable { float: left; margin: 8px; }
div.moveable p { margin: 0px; }
</style>
</head>
<body>
<div id="header">
<img id="logo" src="../logo.png">
<p><span style="font-size:1.5em;">Lexicon Title</span></p>
<p>
<a href="../contents">Contents</a> &mdash;
<a href="../rules/">Rules</a> &mdash;
<a href="../formatting/">Formatting</a> &mdash;
<a href="../session/">Session</a> &mdash;
<a href="../statistics/">Statistics</a>
</p>
<p><i>Prompt goes here</i></p>
</div>
<div class="content">
<h1>Statistics</h1>
<div class="moveable">
<p><u>Top 10 pages by page rank:</u><br>
1 &ndash; Example page<br>
2 &ndash; Phantom page</p>
</div>
<div class="moveable">
<p><u>Most citations made from:</u><br>
2 &ndash; Example page<br>
0 &ndash; Phantom page</p>
</div>
<div class="moveable">
<p><u>Most citations made to:</u><br>
1 &ndash; Phantom page</p>
</div>
<div class="moveable">
<p><u>Author total page rank:</u><br>
Authorname &ndash; 0.5</p>
</div>
<div class="moveable">
<p><u>Citations made by author</u><br>
Authorname &ndash; 1</p>
</div>
<div class="moveable">
<p><u>Citations made to author</u><br>
Authorname &ndash; 0</p>
</div>
</div>
</body>
</html>

View File

@ -1,42 +0,0 @@
<html>
<head>
<title>Statistics | Lexicon Title</title>
<style>
body { background-color: #eeeeee; margin: 10px; }
div#header { background-color: #ffffff; margin: 10px 0; padding: 8px; box-shadow: 2px 2px 10px #888888; }
div.header-option { display:inline-block; margin-right: 20px; }
div#sidebar-outer { width: 140px; background-color: #ffffff; float:left; box-shadow: 2px 2px 10px #888888; padding: 5px; }
div#sidebar-inner { padding: 5px; }
img#logo { width: 140px; }
div.content { margin-left: 160px; margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; }
a.phantom { color: #cc2200; }
div.citeblock a.phantom { font-style: italic; }
span.signature { text-align: right; }
</style>
</head>
<body>
<div id="header">
<div class="header-option"><h2 style="margin:0px;">Lexicon Title</h2></div>
<div class="header-option"><a href="./rules.html">Rules</a></div>
<div class="header-option"><a href="./formatting.html">Formatting</a></div>
<div class="header-option"><a href="./index.html">Index</a></div>
<div class="header-option"><a href="./session.html">Session</a></div>
<div class="header-option"><a href="./stats.html">Statistics</a></div>
</div>
<div id="sidebar-outer">
<img id="logo" src="logo.png">
<div id="sidebar-inner">
<p><i>Sidebar content</i></p>
</div>
</div>
<div class="content">
<h1>Statistics</h1>
<p><u>Top 10 by page rank:</u><br>
</p>
<p><u>Most citations made from:</u><br>
0 - Example page</p>
<p><u>Most citations made to:</u><br>
</p>
</div>
</body>
</html>

View File

@ -1,6 +0,0 @@
# Example page
This is an example **page**.\\
[[This is an example //citation//.|Phantom page]]
~Signature

15
raw/example-page.txt Normal file
View File

@ -0,0 +1,15 @@
# Author: Authorname
# Turn: 1
# Title: Example page
This is an example page.
Some words are //italicized//,
and some words are **bolded**.
All of these sentences are part of the same paragraph.
This is a new paragraph.\\
Unlike the last paragraph, this line will be after a line break within the paragraph.
This is an [[example citation|Phantom page]]. You can also cite a [[phantom page]] with just the title.
~Dr. X. Amplepage

17
resources/contents.html Normal file
View File

@ -0,0 +1,17 @@
<script type="text/javascript">
contentsToggle = function() {
var b = document.getElementById("toggle-button")
var i = document.getElementById("index-order");
var t = document.getElementById("turn-order");
if (t.style.display == "none") {
i.style.display = "none"
t.style.display = "block"
b.innerText = "Switch to index order"
} else {
i.style.display = "block"
t.style.display = "none"
b.innerText = "switch to turn order"
}
}
</script>
<button id="toggle-button" onClick="javascript:contentsToggle()">Switch to turn order</button>

View File

@ -1,23 +1,23 @@
<html>
<head>
<title>{title} | {lexicon}</title>
<!--<link rel="shortcut icon" href="favicon.png" />-->
<style>
{css}
</style>
</head>
<body>
<div id="header">
<div class="header-option"><h2 style="margin:0px;">{lexicon}</h2></div>
<div class="header-option"><a href="rules.html">Rules</a></div>
<div class="header-option"><a href="formatting.html">Formatting</a></div>
<div class="header-option"><a href="index.html">Index</a></div>
<div class="header-option"><a href="session.html">Session</a></div>
<div class="header-option"><a href="stats.html">Statistics</a></div>
</div>
<div id="sidebar-outer">
<img id="logo" src="{logo}">
<div id="sidebar-inner">
{sidebar}</div>
<img id="logo" src="../{logo}">
<p><span style="font-size:1.5em;">{lexicon}</span></p>
<p>
<a href="../contents">Contents</a> &mdash;
<a href="../rules/">Rules</a> &mdash;
<a href="../formatting/">Formatting</a> &mdash;
<a href="../session/">Session</a> &mdash;
<a href="../statistics/">Statistics</a>
</p>
<p>{prompt}</p>
</div>
<div class="content">
<h1>{title}</h1>

View File

@ -1,27 +1,23 @@
<p>Lexipython provides support for a limited amount of Markdown-esque formatting. The parsing rules that will be applied are as follows:</p>
<p>Entries must begin with a header declaring the entry title. Format this header as "# Title", e.g. "# Formatting". This is the name that citations to your entry will use.</p>
<p>Two line breaks begin a new paragraph. Lines separated by a single line break will be part of the same paragraph, unless the line is ended by a double backslash:<br>
&nbsp;&nbsp;Sample \\<br>
&nbsp;&nbsp;text <br>
&nbsp;&nbsp;here <br>
in your markdown produces<br>
&nbsp;&nbsp;Sample <br>
&nbsp;&nbsp;text
here <br>
in the generated page.</p>
<p>Text bounded by ** will be bolded: **bold** produces <b>bold</b>. Text bounded by // will be italicized: //italics// produces <i>italics</i>.</p>
<p>To cite another Lexicon entry, use double brackets. Text in double brackets will cite and link to the entry of the same name: [[Example page]] produces <a href="Example_page.html" class="phantom">Example page</a>. Text in double brackets split with a | will alias the link as the left text and link to the entry with the name of the right text: [[this text|Example page]] produces <a href="Example_page.html" class="phantom">this text</a>. <b>You must be precise in the entry title you cite to.</b> Citations to "Example" vs. "The Example" will point to different entries and create different phantoms, and your GM will probably have to clean up after you.
<p>Entries should end with a footer signing the entry with its author. Format this footer as "~ Signature". Signature lines will be set apart by a horizotal rule and right-aligned:</p>
<span class="signature"><p> Signature</p></span>
<p>Here is an example lexicon file:</p>
<p>Lexipython provides support for a limited amount of Markdown-esque formatting.</p>
<pre style="background:#eeeeee">
# Example page
# Author: Authorname
# Turn: 1
# Title: Example page
This is an example **page**.\\
[[This is an example //citation//.|Phantom page]]
This is an example page.
Some words are //italicized//,
and some words are **bolded**.
All of these sentences are part of the same paragraph.
~Signature
This is a new paragraph.\\
Unlike the last paragraph, this line will be after a line break within the paragraph.
This is an [[example citation|Phantom page]]. You can also cite a [[phantom page]] with just the title.
~Dr. X. Amplepage
</pre>
<p>Each turn, fill out the header with your author information, the current turn, and the title of your entry. It doesn't really matter what the <i>Author</i> field is, except that it must be the same across all articles you write.</p>
<p>Two line breaks begins a new paragraph. A single line break does nothing, unless the line is neded by a double backslash (\\).</p>
<p>Text bounded by ** will be bolded: **bold** produces <b>bold</b>. Text bounded by // will be italicized: //italics// produces <i>italics</i>.</p>
<p>To cite another Lexicon entry, use double brackets. Text in double brackets will cite and link to the entry of the same name: [[Example page]] produces <a href="Example_page.html" class="phantom">Example page</a>. Text in double brackets split with a | will alias the link as the left text and link to the entry with the name of the right text: [[this text|Example page]] produces <a href="Example_page.html" class="phantom">this text</a>. <b>You must be precise in the entry title you cite to.</b> Citations to "Example" vs. "The Example" will point to different entries and create different phantoms, and your GM will probably have to clean up after you.</p>
<p>Beginning a paragraph with ~ will right-align it and place a horizontal line above it. Use this for signing your entry with your scholar's name.</p>

View File

@ -1,10 +1,10 @@
body { background-color: #eeeeee; margin: 10px; }
div#header { background-color: #ffffff; margin: 10px 0; padding: 8px; box-shadow: 2px 2px 10px #888888; }
div.header-option { display:inline-block; margin-right: 20px; }
div#sidebar-outer { width: 140px; background-color: #ffffff; float:left; box-shadow: 2px 2px 10px #888888; padding: 5px; }
div#sidebar-inner { padding: 5px; }
img#logo { width: 140px; }
div.content { margin-left: 160px; margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; }
div#header { background-color: #ffffff; margin: 10px 0; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
img#logo { float:left; margin:8px; max-width: 140px; }
div#header p { margin:10px; }
div.content { margin-top: 10px; background-color: #ffffff; padding: 10px; box-shadow: 2px 2px 10px #888888; overflow: hidden; }
a.phantom { color: #cc2200; }
div.citeblock a.phantom { font-style: italic; }
span.signature { text-align: right; }
div.moveable { float: left; margin: 8px; }
div.moveable p { margin: 0px; }

9
resources/redirect.html Normal file
View File

@ -0,0 +1,9 @@
<html>
<head>
<title>{lexicon}</title>
<meta http-equiv="refresh" content="0; url=contents/" />
</head>
<body>
<p>Redirecting to <a href="contents/">{lexicon}</a>...</p>
</body>
</html>