Improve index sorting options
This commit is contained in:
parent
1f702b5af4
commit
3ac0b2c738
|
@ -28,11 +28,21 @@ class LexiconPage:
|
||||||
total_kwargs = {**self.kwargs, **kwargs}
|
total_kwargs = {**self.kwargs, **kwargs}
|
||||||
return self.skeleton.format(**total_kwargs)
|
return self.skeleton.format(**total_kwargs)
|
||||||
|
|
||||||
def build_contents_page(page, articles, index_list):
|
def article_matches_index(index_type, pattern, article):
|
||||||
|
if index_type == "char":
|
||||||
|
return utils.titlesort(article.title)[0].upper() in pattern.upper()
|
||||||
|
if index_type == "prefix":
|
||||||
|
return article.title.startswith(pattern)
|
||||||
|
if index_type == "etc":
|
||||||
|
return True
|
||||||
|
raise ValueError("Unknown index type: '{}'".format(index_type))
|
||||||
|
|
||||||
|
def build_contents_page(config, page, articles):
|
||||||
"""
|
"""
|
||||||
Builds the full HTML of the contents page.
|
Builds the full HTML of the contents page.
|
||||||
"""
|
"""
|
||||||
content = "<div class=\"contentblock\">"
|
content = "<div class=\"contentblock\">"
|
||||||
|
|
||||||
# Head the contents page with counts of written and phantom articles
|
# Head the contents page with counts of written and phantom articles
|
||||||
phantom_count = len([article for article in articles if article.player is None])
|
phantom_count = len([article for article in articles if article.player is None])
|
||||||
if phantom_count == 0:
|
if phantom_count == 0:
|
||||||
|
@ -40,32 +50,68 @@ def build_contents_page(page, articles, index_list):
|
||||||
else:
|
else:
|
||||||
content += "<p>There are <b>{0}</b> entries, <b>{1}</b> written and <b>{2}</b> phantom.</p>\n".format(
|
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)
|
len(articles), len(articles) - phantom_count, phantom_count)
|
||||||
|
|
||||||
# Prepare article links
|
# Prepare article links
|
||||||
link_by_title = {article.title : "<a href=\"../article/{1}.html\"{2}>{0}</a>".format(
|
link_by_title = {article.title : "<a href=\"../article/{1}.html\"{2}>{0}</a>".format(
|
||||||
article.title, article.title_filesafe,
|
article.title, article.title_filesafe,
|
||||||
" class=\"phantom\"" if article.player is None else "")
|
" class=\"phantom\"" if article.player is None else "")
|
||||||
for article in articles}
|
for article in articles}
|
||||||
# Write the articles in alphabetical order
|
|
||||||
content += utils.load_resource("contents.html")
|
# Determine index order
|
||||||
content += "<div id=\"index-order\" style=\"display:none\">\n<ul>\n"
|
indices = config['INDEX_LIST'].split("\n")
|
||||||
indices = index_list.split("\n")
|
index_by_pri = {}
|
||||||
alphabetical_order = sorted(
|
index_list_order = []
|
||||||
|
for index in indices:
|
||||||
|
match = re.match(r"([^[:]+)(\[([-\d]+)\])?:(.+)", index)
|
||||||
|
index_type = match.group(1)
|
||||||
|
pattern = match.group(4)
|
||||||
|
try:
|
||||||
|
pri_s = match.group(3)
|
||||||
|
pri = int(pri_s) if pri_s else 0
|
||||||
|
except:
|
||||||
|
raise TypeError("Could not parse index pri '{}' in '{}'".format(pri_s, index))
|
||||||
|
if pri not in index_by_pri:
|
||||||
|
index_by_pri[pri] = []
|
||||||
|
index_by_pri[pri].append((index_type, pattern))
|
||||||
|
index_list_order.append(pattern)
|
||||||
|
|
||||||
|
# Assign articles to indices
|
||||||
|
articles_by_index = {pattern: [] for pattern in index_list_order}
|
||||||
|
titlesort_order = sorted(
|
||||||
articles,
|
articles,
|
||||||
key=lambda a: utils.titlesort(a.title))
|
key=lambda a: utils.titlesort(a.title))
|
||||||
check_off = list(alphabetical_order)
|
for article in titlesort_order:
|
||||||
for index_str in indices:
|
# Find the first index that matches
|
||||||
content += "<h3>{0}</h3>\n".format(index_str)
|
matched = False
|
||||||
for article in alphabetical_order:
|
for pri, indices in sorted(index_by_pri.items(), reverse=True):
|
||||||
if (utils.titlesort(article.title)[0].upper() in index_str):
|
for index_type, pattern in indices:
|
||||||
check_off.remove(article)
|
# Try to match the index
|
||||||
content += "<li>{}</li>\n".format(link_by_title[article.title])
|
if article_matches_index(index_type, pattern, article):
|
||||||
if len(check_off) > 0:
|
articles_by_index[pattern].append(article)
|
||||||
content += "<h3>&c.</h3>\n"
|
matched = True
|
||||||
for article in check_off:
|
# Break out once a match is found
|
||||||
|
if matched:
|
||||||
|
break
|
||||||
|
if matched:
|
||||||
|
break
|
||||||
|
if not matched:
|
||||||
|
raise KeyError("No index matched article '{}'".format(article.title))
|
||||||
|
|
||||||
|
# Write index order div
|
||||||
|
content += utils.load_resource("contents.html")
|
||||||
|
content += "<div id=\"index-order\" style=\"display:{}\">\n<ul>\n".format(
|
||||||
|
"block" if config["DEFAULT_SORT"] == "index" else "none")
|
||||||
|
for pattern in index_list_order:
|
||||||
|
# Write the index header
|
||||||
|
content += "<h3>{0}</h3>\n".format(pattern)
|
||||||
|
# Write all matches articles
|
||||||
|
for article in articles_by_index[pattern]:
|
||||||
content += "<li>{}</li>\n".format(link_by_title[article.title])
|
content += "<li>{}</li>\n".format(link_by_title[article.title])
|
||||||
content += "</ul>\n</div>\n"
|
content += "</ul>\n</div>\n"
|
||||||
# Write the articles in turn order
|
|
||||||
content += "<div id=\"turn-order\" style=\"display:none\">\n<ul>\n"
|
# Write turn order div
|
||||||
|
content += "<div id=\"turn-order\" style=\"display:{}\">\n<ul>\n".format(
|
||||||
|
"block" if config["DEFAULT_SORT"] == "turn" else "none")
|
||||||
turn_numbers = [article.turn for article in articles if article.player is not None]
|
turn_numbers = [article.turn for article in articles if article.player is not None]
|
||||||
first_turn, last_turn = min(turn_numbers), max(turn_numbers)
|
first_turn, last_turn = min(turn_numbers), max(turn_numbers)
|
||||||
turn_order = sorted(
|
turn_order = sorted(
|
||||||
|
@ -83,6 +129,31 @@ def build_contents_page(page, articles, index_list):
|
||||||
for article in check_off:
|
for article in check_off:
|
||||||
content += "<li>{}</li>\n".format(link_by_title[article.title])
|
content += "<li>{}</li>\n".format(link_by_title[article.title])
|
||||||
content += "</ul>\n</div>\n"
|
content += "</ul>\n</div>\n"
|
||||||
|
|
||||||
|
# Write by-player div
|
||||||
|
content += "<div id=\"player-order\" style=\"display:{}\">\n<ul>\n".format(
|
||||||
|
"block" if config["DEFAULT_SORT"] == "player" else "none")
|
||||||
|
articles_by_player = {}
|
||||||
|
extant_phantoms = False
|
||||||
|
for article in turn_order:
|
||||||
|
if article.player is not None:
|
||||||
|
if article.player not in articles_by_player:
|
||||||
|
articles_by_player[article.player] = []
|
||||||
|
articles_by_player[article.player].append(article)
|
||||||
|
else:
|
||||||
|
extant_phantoms = True
|
||||||
|
for player, player_articles in sorted(articles_by_player.items()):
|
||||||
|
content += "<h3>{0}</h3>\n".format(player)
|
||||||
|
for article in player_articles:
|
||||||
|
content += "<li>{}</li>\n".format(link_by_title[article.title])
|
||||||
|
if extant_phantoms:
|
||||||
|
content += "<h3>Unwritten</h3>\n"
|
||||||
|
for article in titlesort_order:
|
||||||
|
if article.player is None:
|
||||||
|
content += "<li>{}</li>\n".format(link_by_title[article.title])
|
||||||
|
content += "</ul>\n</div>\n"
|
||||||
|
|
||||||
|
content += "</div>\n"
|
||||||
# Fill in the page skeleton
|
# Fill in the page skeleton
|
||||||
return page.format(title="Index", content=content)
|
return page.format(title="Index", content=content)
|
||||||
|
|
||||||
|
@ -477,6 +548,15 @@ def latex_from_directory(directory):
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
def parse_sort_type(sort):
|
||||||
|
if sort in "?byindex":
|
||||||
|
return "?byindex"
|
||||||
|
if sort in "?byturn":
|
||||||
|
return "?byturn"
|
||||||
|
if sort in "?byplayer":
|
||||||
|
return "?byplayer"
|
||||||
|
return ""
|
||||||
|
|
||||||
def build_all(path_prefix, lexicon_name):
|
def build_all(path_prefix, lexicon_name):
|
||||||
"""
|
"""
|
||||||
Builds all browsable articles and pages in the Lexicon.
|
Builds all browsable articles and pages in the Lexicon.
|
||||||
|
@ -490,7 +570,7 @@ def build_all(path_prefix, lexicon_name):
|
||||||
lexicon=config["LEXICON_TITLE"],
|
lexicon=config["LEXICON_TITLE"],
|
||||||
logo=config["LOGO_FILENAME"],
|
logo=config["LOGO_FILENAME"],
|
||||||
prompt=config["PROMPT"],
|
prompt=config["PROMPT"],
|
||||||
sort=config["DEFAULT_SORT"])
|
sort=parse_sort_type(config["DEFAULT_SORT"]))
|
||||||
# Parse the written articles
|
# Parse the written articles
|
||||||
articles = LexiconArticle.parse_from_directory(os.path.join(lex_path, "src"))
|
articles = LexiconArticle.parse_from_directory(os.path.join(lex_path, "src"))
|
||||||
# Once they've been populated, the articles list has the titles of all articles
|
# Once they've been populated, the articles list has the titles of all articles
|
||||||
|
@ -528,7 +608,7 @@ def build_all(path_prefix, lexicon_name):
|
||||||
# Write default pages
|
# Write default pages
|
||||||
print("Writing default pages...")
|
print("Writing default pages...")
|
||||||
with open(pathto("contents", "index.html"), "w", encoding="utf-8") as f:
|
with open(pathto("contents", "index.html"), "w", encoding="utf-8") as f:
|
||||||
f.write(build_contents_page(page, articles, config["INDEX_LIST"]))
|
f.write(build_contents_page(config, page, articles))
|
||||||
print(" Wrote Contents")
|
print(" Wrote Contents")
|
||||||
with open(pathto("rules", "index.html"), "w", encoding="utf-8") as f:
|
with open(pathto("rules", "index.html"), "w", encoding="utf-8") as f:
|
||||||
f.write(build_rules_page(page))
|
f.write(build_rules_page(page))
|
||||||
|
|
|
@ -1,28 +1,54 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
contentsToggle = function() {
|
const order = {
|
||||||
var b = document.getElementById("toggle-button");
|
INDEX: "index",
|
||||||
var i = document.getElementById("index-order");
|
TURN: "turn",
|
||||||
var t = document.getElementById("turn-order");
|
PLAYER: "player",
|
||||||
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";
|
|
||||||
}
|
}
|
||||||
|
var currentOrder = order.INDEX;
|
||||||
|
setOrder = function(orderType)
|
||||||
|
{
|
||||||
|
if (orderType == order.INDEX) {
|
||||||
|
document.getElementById("index-order").style.display = "block";
|
||||||
|
document.getElementById("turn-order").style.display = "none";
|
||||||
|
document.getElementById("player-order").style.display = "none";
|
||||||
|
document.getElementById("toggle-button").innerText = "Switch to turn order";
|
||||||
|
currentOrder = order.INDEX;
|
||||||
|
}
|
||||||
|
else if (orderType == order.TURN) {
|
||||||
|
document.getElementById("index-order").style.display = "none";
|
||||||
|
document.getElementById("turn-order").style.display = "block";
|
||||||
|
document.getElementById("player-order").style.display = "none";
|
||||||
|
document.getElementById("toggle-button").innerText = "Switch to player order";
|
||||||
|
currentOrder = order.TURN;
|
||||||
|
}
|
||||||
|
else if (orderType == order.PLAYER) {
|
||||||
|
document.getElementById("index-order").style.display = "none";
|
||||||
|
document.getElementById("turn-order").style.display = "none";
|
||||||
|
document.getElementById("player-order").style.display = "block";
|
||||||
|
document.getElementById("toggle-button").innerText = "Switch to index order";
|
||||||
|
currentOrder = order.PLAYER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contentsToggle = function() {
|
||||||
|
if (currentOrder == order.INDEX)
|
||||||
|
setOrder(order.TURN);
|
||||||
|
else if (currentOrder == order.TURN)
|
||||||
|
setOrder(order.PLAYER);
|
||||||
|
else if (currentOrder == order.PLAYER)
|
||||||
|
setOrder(order.INDEX);
|
||||||
}
|
}
|
||||||
window.onload = function(){
|
window.onload = function(){
|
||||||
if (location.search.search("byturn") > 0)
|
|
||||||
{
|
|
||||||
document.getElementById("turn-order").style.display = "block";
|
|
||||||
document.getElementById("toggle-button").innerText = "Switch to index order";
|
|
||||||
}
|
|
||||||
if (location.search.search("byindex") > 0)
|
if (location.search.search("byindex") > 0)
|
||||||
{
|
{
|
||||||
document.getElementById("index-order").style.display = "block";
|
setOrder(order.INDEX);
|
||||||
document.getElementById("toggle-button").innerText = "Switch to turn order";
|
}
|
||||||
|
if (location.search.search("byturn") > 0)
|
||||||
|
{
|
||||||
|
setOrder(order.TURN);
|
||||||
|
}
|
||||||
|
if (location.search.search("byplayer") > 0)
|
||||||
|
{
|
||||||
|
setOrder(order.PLAYER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -24,10 +24,12 @@ logo.png
|
||||||
<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>
|
<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<<<
|
<<<SESSION_PAGE<<<
|
||||||
|
|
||||||
# Index headers. An index header is declared as id:pattern or id[pri]:pattern.
|
# Index headers.
|
||||||
# An article is sorted under the first index it matches. Indices are checked
|
# An index header is declared as id:pattern or id[pri]:pattern. An article is
|
||||||
# first in descending order of pri and in list order at each value of pri.
|
# sorted under the first index it matches. Matches are checked in descending
|
||||||
# An undefined pri value is 0.
|
# order of pri, and in list order for indices of equal pri. An undefined pri
|
||||||
|
# value is 0. After matching is done, indices are written in list order
|
||||||
|
# regardless of pri. Index patterns must be unique, regardless of index type.
|
||||||
# A character index has id "char". An article matches a character index if the
|
# A character index has id "char". An article matches a character index if the
|
||||||
# first letter of its title is one of the characters in the index's pattern.
|
# first letter of its title is one of the characters in the index's pattern.
|
||||||
# A prefix index has id "prefix". An article matches a prefix index if the
|
# A prefix index has id "prefix". An article matches a prefix index if the
|
||||||
|
@ -47,7 +49,7 @@ etc:&c.
|
||||||
<<<INDEX_LIST<<<
|
<<<INDEX_LIST<<<
|
||||||
|
|
||||||
# The default sorting to use on the contents page.
|
# The default sorting to use on the contents page.
|
||||||
# Allowed values are "turn", "player", and "index"
|
# Allowed values are "index", "turn", and "player"
|
||||||
>>>DEFAULT_SORT>>>
|
>>>DEFAULT_SORT>>>
|
||||||
index
|
index
|
||||||
<<<DEFAULT_SORT<<<
|
<<<DEFAULT_SORT<<<
|
||||||
|
|
Loading…
Reference in New Issue