imbroglio
Version:
a tool for making browser-based interactive fiction
248 lines (234 loc) • 6.98 kB
JavaScript
// Generated by IcedCoffeeScript 1.8.0-d
(function() {
var $, assert, choiceChars, compile, error, hashchange, mkElem, mkText, newGame, prepare, quote, restore, stdlib, turn, _ref;
choiceChars = 'abcdefghijklmnopqrstuvwxyz0123456789';
error = function(msg) {
throw new Error(msg);
};
assert = require('assert');
$ = require('jquery');
_ref = require('./compiler'), quote = _ref.quote, stdlib = _ref.stdlib, prepare = _ref.prepare;
mkText = function(s) {
return window.document.createTextNode(s);
};
mkElem = function(tag, children, attrs) {
var child, k, result, v, _i, _len;
if (children == null) {
children = [];
}
if (attrs == null) {
attrs = {};
}
result = window.document.createElement(tag);
for (k in attrs) {
v = attrs[k];
result.setAttribute(k, v);
}
for (_i = 0, _len = children.length; _i < _len; _i++) {
child = children[_i];
if (child) {
result.appendChild(child);
}
}
return result;
};
exports.compile = compile = function(src) {
var firstPassage, passages, render;
passages = {};
firstPassage = null;
(function() {
var lastPassage, m, re;
re = /(?:^\s*\n?|\n\n)#\s*([^\n]*\S)\s*\n/g;
lastPassage = null;
while (m = re.exec(src)) {
if (lastPassage) {
lastPassage.endIndex = m.index;
}
lastPassage = {
name: m[1],
startIndex: re.lastIndex
};
assert(!(lastPassage.name in passages), lastPassage.name);
passages[lastPassage.name] = lastPassage;
firstPassage || (firstPassage = lastPassage);
}
if (!lastPassage) {
error('no passages found');
}
lastPassage.endIndex = src.length;
})();
(function() {
var k, v, _fn;
_fn = function() {
v.src = src.substring(v.startIndex, v.endIndex);
v.mungedSrc = v.src.replace(/\[\[([^\]]*)\]\]/g, function(outer, inner, index) {
var m, offset, target, text;
offset = index + v.startIndex;
text = target = inner;
if (m = /^(.*)->\s*([^<>]*[^\s<>])\s*$/.exec(inner)) {
text = m[1];
target = m[2];
} else if (m = /^\s*([^<>]*[^\s<>])\s*<-(.*)$/.exec(inner)) {
target = m[1];
text = m[2];
}
if (!(target in passages)) {
error("bad link target '" + target + "' at " + outer + ", passage " + k + ", offset " + offset);
}
return "#\{imbroglio.mkLink " + (quote(target)) + ", " + (quote(text)) + "}";
});
v.prepared = prepare(v.mungedSrc, {
argNames: ['imbroglio'],
thisVar: 'imbroglio.state',
handleError: function(e) {
console.log(e);
if (e.error instanceof Error) {
throw e.error;
} else if (e.error) {
return error(e.error);
} else {
return error(e);
}
}
});
};
for (k in passages) {
v = passages[k];
_fn();
}
})();
render = function(passage, result) {
var linkCount, links, mkLink, moves, state, stateJSON;
if (result == null) {
result = {};
}
moves = result.moves || (result.moves = '');
links = {};
linkCount = 0;
mkLink = function(target, text) {
var choiceChar, el;
if (linkCount >= choiceChars.length) {
error("too many links, passage " + passage.name + ", target [" + target + "], text [" + text + "]");
}
choiceChar = choiceChars[linkCount++];
el = mkElem('a', [mkText(text)], {
"class": 'choice',
href: "#!" + moves + choiceChar
});
links[choiceChar] = {
el: el,
target: target
};
return el;
};
state = JSON.parse(result.stateJSON || '{}');
result.passageElem = passage.prepared(stdlib({
mkLink: mkLink,
state: state
}));
stateJSON = result.stateJSON = JSON.stringify(state);
result.choose = function(ch) {
var link;
if (!(link = links[ch])) {
console.log("invalid move " + ch + " from passage " + passage.name);
return null;
}
return render(passages[link.target], {
moves: "" + moves + ch,
chosenElem: link.el,
stateJSON: stateJSON
});
};
return result;
};
return function() {
return render(firstPassage);
};
};
newGame = turn = null;
restore = function(moves) {
var $output, $p, ch, last, prevTurn, _i, _len, _ref1;
if ((turn != null ? turn.moves : void 0) === moves) {
return;
}
$('#loading').show();
$('.pane').hide();
$('#game').hide();
$output = $('#output');
if (!turn) {
turn = newGame();
$output.empty();
$output.append(turn.passageElem);
} else {
last = function() {
var children;
children = $output.children();
if (children.length) {
return $(children.get(children.length - 1));
} else {
return children;
}
};
while (turn.moves !== moves.slice(0, turn.moves.length)) {
last().remove();
turn = turn.prevTurn;
}
last().find('.chosen').removeClass('chosen');
}
_ref1 = moves.slice(turn.moves.length);
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
ch = _ref1[_i];
prevTurn = turn;
if (!(turn = turn.choose(ch))) {
$('#404-pane').show();
$('#loading').hide();
return;
}
turn.prevTurn = prevTurn;
$(turn.chosenElem).addClass('chosen');
$output.append(turn.passageElem);
}
$('#game').show();
$('#loading').hide();
$p = $(turn.passageElem);
window.scrollTo(0, $p.offset().top);
};
hashchange = function() {
var hash, m, target;
hash = window.location.hash.replace(/^#/, '');
if (m = /^!(.*)$/.exec(hash)) {
return restore(m[1]);
}
turn = target = null;
if (m = /^\/([a-z][a-z-]*)$/.exec(hash)) {
target = $("#" + m[1] + "-pane");
}
if (!(target != null ? target.length : void 0)) {
target = $('#home');
}
$('#game').hide();
$('#output').empty();
$('.pane').hide();
target.show();
$('#loading').hide();
window.scrollTo(0, 0);
};
exports.start = function(src) {
newGame = compile(src);
return $(function() {
(function() {
var m, _ref1;
m = /([^\/]+)$/.exec(((_ref1 = window.location) != null ? _ref1.pathname : void 0) || '');
if (m) {
$('a[href="#"], a[href="#/"]').attr('href', m[1]);
}
})();
$(window).on('hashchange', function(e) {
e.preventDefault();
hashchange();
return true;
});
hashchange();
});
};
}).call(this);