diff --git a/templates.py b/templates.py index e656c65..86227b5 100644 --- a/templates.py +++ b/templates.py @@ -1,7 +1,11 @@ +import re import os import os.path import sys +PREPROCESS_RE = re.compile("^\s*#") +INCLUDE_RE = re.compile('^\s*#include\s*"(\w+)"') + class Templates (object): def __init__(self, templatedirs, extension): self.extension = extension @@ -23,11 +27,27 @@ class Templates (object): def get_in(self, templatedir, name): filename = self.get_template_filename(templatedir, name) f = open(filename, "r") - template = f.read() + template = self.read_template(f); f.close() self.cached_templates[name] = template return template + def read_template(self, f): + res = "" + for line in f.readlines(): + if PREPROCESS_RE.match(line): + res += self.preprocessline(line) + else: + res += line + return res + + def preprocessline(self, line): + m = INCLUDE_RE.match(line) + if m: + return self.get(m.group(1)) + else: + raise Exception("Bad preprocessor line '%s' in template." % line) + def get_template_filename(self, templatedir, name): return os.path.join(templatedir, self.extension, diff --git a/templates/html/begin.html b/templates/html/begin.html index f02ae4c..3d3b600 100644 --- a/templates/html/begin.html +++ b/templates/html/begin.html @@ -2,202 +2,15 @@ - - Gamebook Title Here +#include "viewport" +#include "title" - +#include "intro"
diff --git a/templates/html/collections.html b/templates/html/collections.html new file mode 100644 index 0000000..21a866c --- /dev/null +++ b/templates/html/collections.html @@ -0,0 +1,2 @@ +
+
diff --git a/templates/html/collectiontemplate.html b/templates/html/collectiontemplate.html new file mode 100644 index 0000000..99a73d8 --- /dev/null +++ b/templates/html/collectiontemplate.html @@ -0,0 +1,5 @@ +
+ + +
+
diff --git a/templates/html/end.html b/templates/html/end.html index 0b8ce3f..c3cc145 100644 --- a/templates/html/end.html +++ b/templates/html/end.html @@ -1,14 +1,7 @@ -
-
-
- - -
- +#include "collections" +#include "collectiontemplate" diff --git a/templates/html/endscript.html b/templates/html/endscript.html new file mode 100644 index 0000000..926a878 --- /dev/null +++ b/templates/html/endscript.html @@ -0,0 +1,3 @@ +if (this.gamebook) { + gamebook.turnTo(1); +} diff --git a/templates/html/script.html b/templates/html/script.html new file mode 100644 index 0000000..9c7c7a0 --- /dev/null +++ b/templates/html/script.html @@ -0,0 +1,168 @@ + var gamebook = { + 'player' : { + 'currentSection' : null, + 'collections' : {}, + + 'collect' : function(type, name) { + this.collections[type] = { + 'name' : name, + 'contents' : [], + 'add' : function(what) { + if (this.contents.indexOf(what) === -1 + && !(what in gamebook.dropped[type])) { + this.contents.push(what); + this.contents.sort(); + } + }, + 'drop' : function(what) { + var i = this.contents.indexOf(what); + if (i >= 0) { + this.contents.splice(i, 1); + gamebook.dropped[type][what] = true; + } + }, + 'has' : function(what) { + return this.contents.indexOf(what) >= 0; + } + }; + gamebook.dropped[type] = {}; + gamebook.addCollectionView(type, name); + }, + + 'add' : function(type, what) { + this.collections[type].add(what); + gamebook.updateCollectionsView(); + }, + + 'drop' : function(type, what) { + this.collections[type].drop(what); + gamebook.updateCollectionsView(); + }, + + 'has' : function(type, what) { + return this.collections[type].has(what); + } + }, + + 'sections' : {}, + + 'turnToFunctions' : {}, + + 'dropped' : {}, + + 'addSection' : function(nr, element) { + var section = {'element' : element, 'nr' : nr}; + this.sections[nr] = section; + }, + + 'turnTo' : function(nr) { + console.log("Turning to " + nr + "."); + if (!nr in this.sections) { + throw new Exception("Can not turn to non-existing section " + + nr + "."); + } + this.displaySection(nr); + }, + + 'displaySection' : function(nr) { + if (this.player.currentSection) { + this.player.currentSection.element.style.display = 'none'; + } + var e = this.sections[nr].element; + this.runActions(e.getElementsByClassName('sectiontext')[0]); + e.style.display = 'block'; + this.player.currentSection = gamebook.sections[nr]; + }, + + 'runActions' : function(e) { + var enableNextLink = true; + var hasXorScope = false; + var hasAutoScope = false; + var xorEnableNext = false; + var autoDisableAllRemainingLinks = false; + Array.prototype.forEach.call(e.childNodes, function(c) { + if (/sectionref$/.test(c.className)) { + if (enableNextLink && !autoDisableAllRemainingLinks) { + gamebook.enableLink(c); + if (hasAutoScope) { + autoDisableAllRemainingLinks = true; + } + } else { + gamebook.disableLink(c); + } + enableNextLink = !(hasXorScope && !xorEnableNext); + hasAutoScope = false; + hasXorScope = false; + } else if (c.className === 'collect') { + gamebook.player.collect(c.dataset.type, c.dataset.name); + } else if (c.className === 'add') { + gamebook.player.add(c.dataset.type, c.dataset.what); + } else if (c.className === 'drop') { + gamebook.player.drop(c.dataset.type, c.dataset.what); + } else if (c.className === 'has') { + enableNextLink = gamebook.player.has(c.dataset.type, + c.dataset.what); + console.log("has " + c.dataset.type + + " " + c.dataset.what + " " + enableNextLink); + } else if (c.className === 'hasnot') { + enableNextLink = !gamebook.player.has(c.dataset.type, + c.dataset.what); + console.log("has not " + c.dataset.type + + " " + c.dataset.what + " " + enableNextLink); + } else if (c.className === 'xor') { + hasXorScope = true; + xorEnableNext = !enableNextLink; + } else if (c.className === 'auto') { + hasAutoScope = true; + } + }); + }, + + 'enableLink' : function(e) { + e.addEventListener('click', + gamebook.getTurnToFunction(e.dataset.ref)); + e.className = "enabledsectionref"; + }, + + 'disableLink' : function(e) { + e.removeEventListener('click', + gamebook.getTurnToFunction(e.dataset.ref)); + e.className = "disabledsectionref"; + }, + + 'addCollectionView' : function(type, name) { + var ce = document.getElementById('collections'); + var template = document.getElementById('collectionTemplate'); + var e = template.cloneNode(true); + e.className = "collection"; + e.getElementsByClassName('collectionheading')[0].innerHTML = name; + e.dataset.type = type; + ce.appendChild(e); + }, + + 'updateCollectionsView' : function() { + var ce = document.getElementById('collections'); + Array.prototype.forEach.call(ce.childNodes, function(c) { + if (c.className === 'collection') { + var type = c.dataset.type; + var collection = gamebook.player.collections[type]; + var cc = c.getElementsByClassName('collectioncontents')[0]; + cc.innerHTML = collection.contents.join(', '); + } + }); + }, + + 'getTurnToFunction' : function(nr) { + if (nr in this.turnToFunctions) { + return this.turnToFunctions[nr]; + } else { + var f = function () { + gamebook.turnTo(nr); + }; + this.turnToFunctions[nr] = f; + return f; + } + } + + }; + diff --git a/templates/html/style.html b/templates/html/style.html new file mode 100644 index 0000000..559e702 --- /dev/null +++ b/templates/html/style.html @@ -0,0 +1,20 @@ + .enabledsectionref {font-weight: bold; cursor: pointer;} + .disabledsectionref {font-weight: bold; color: #aaa; cursor: not-allowed;} + .sectionnumber {font-weight: bolder; + margin-left: 50%%; + margin-right: 50%%;} + .section {display: none; width: 90%%; margin-left: 5%%; margin-right: 5%%;} + .sectiontext {margin-top: 0.5em;} + .gamebook {max-width: 30em; padding: 1em; width: 100%%; font-size: 133%%;} + .collections {margin-top: 4em;} + .collection {background: #ddd; margin-top: 1em;} + .collectionheading {} + .collectionheading::after {content: ": ";} + .collectioncontents {} + .collect {} + .add {font-weight: bold;} + .found {font-weight: bold; cursor: pointer;} + .drop {font-style: italic;} + .has {font-style: italic;} + .hasnot {font-style: italic;} + .collectionTemplate {display: none;} diff --git a/templates/html/title.html b/templates/html/title.html new file mode 100644 index 0000000..d94d5a6 --- /dev/null +++ b/templates/html/title.html @@ -0,0 +1 @@ + Gamebook diff --git a/templates/html/viewport.html b/templates/html/viewport.html new file mode 100644 index 0000000..81d7f88 --- /dev/null +++ b/templates/html/viewport.html @@ -0,0 +1,2 @@ + diff --git a/templates/tex/begin.tex b/templates/tex/begin.tex index bd5a759..64fc6ff 100644 --- a/templates/tex/begin.tex +++ b/templates/tex/begin.tex @@ -1,10 +1,9 @@ -\documentclass[A5,twocolumn]{article} +#include "documentclass" \usepackage[utf8]{inputenc} \usepackage[T1]{fontenc} \usepackage[hidelinks]{hyperref} -\usepackage[top=3.3cm, bottom=3.3cm, left=2cm, right=2cm]{geometry} - +#include "geometry" \newif\ifpdf \ifx\pdfoutput\undefined \pdffalse @@ -16,7 +15,7 @@ \fi \fi -\title{Gamebook} +#include "title" \author{} \date{} diff --git a/templates/tex/documentclass.tex b/templates/tex/documentclass.tex new file mode 100644 index 0000000..979305c --- /dev/null +++ b/templates/tex/documentclass.tex @@ -0,0 +1 @@ +\documentclass[A5,twocolumn]{article} diff --git a/templates/tex/geometry.tex b/templates/tex/geometry.tex new file mode 100644 index 0000000..7d18bd0 --- /dev/null +++ b/templates/tex/geometry.tex @@ -0,0 +1 @@ +\usepackage[top=3.3cm, bottom=3.3cm, left=2cm, right=2cm]{geometry} diff --git a/templates/tex/title.tex b/templates/tex/title.tex new file mode 100644 index 0000000..62886d1 --- /dev/null +++ b/templates/tex/title.tex @@ -0,0 +1 @@ +\title{Gamebook} diff --git a/todo.org b/todo.org index 531e24b..f56020d 100644 --- a/todo.org +++ b/todo.org @@ -1,4 +1,4 @@ -* TODO [27/59] [45%] +* TODO [28/59] [47%] - [X] Debug output - [X] DOT output - [X] LaTeX output @@ -36,7 +36,7 @@ - [ ] Book option to set author - [ ] Book option to set date - [ ] Quote strings to not break formatting. -- [ ] Include other templates from a template. +- [X] Include other templates from a template. - [ ] Template for book introduction (including rules etc) Sections with some markup (has number 0?) are added as chapters of introduction, otherwise formatted identical to other sections.