mirror of
https://github.com/Oreolek/raconteur.git
synced 2024-05-17 00:08:16 +03:00
Separate qualities and element helper into modules
This commit is contained in:
parent
ac4baabb42
commit
b3568bc5cf
|
@ -35,7 +35,8 @@ var bundle = function () {
|
|||
.pipe(buffer())
|
||||
.pipe(sourcemaps.init({
|
||||
loadMaps: true,
|
||||
includeContent: true
|
||||
includeContent: true,
|
||||
debug: true
|
||||
}))
|
||||
.on('error', gutil.log.bind(gutil, 'Sourcemaps Error'))
|
||||
.pipe(sourcemaps.write('./'))
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
var situation = require('raconteur/situation.js'),
|
||||
$ = require('jquery'),
|
||||
undum = require('undum-commonjs'),
|
||||
tools = require('raconteur/tools.js');
|
||||
tools = require('raconteur/tools.js'),
|
||||
elements = require('raconteur/elements.js'),
|
||||
qualities = require('raconteur/qualities.js');
|
||||
|
||||
var a = situation.a,
|
||||
span = situation.span,
|
||||
qualities = situation.qualities;
|
||||
var a = elements.a,
|
||||
span = elements.span;
|
||||
|
||||
undum.game.id = "my_game_id";
|
||||
undum.game.version = "1.0";
|
||||
|
|
144
lib/elements.js
Normal file
144
lib/elements.js
Normal file
|
@ -0,0 +1,144 @@
|
|||
/* Element Helpers */
|
||||
/*
|
||||
While you can write HTML elements by hand, those helpers make it easier to
|
||||
place anchors (especially with special purpose) and spans.
|
||||
|
||||
They define a monadic interface:
|
||||
|
||||
a.id('my-link').content('link').writer('my-ref')
|
||||
-> <a id="my-link" href="./_writer_my-ref">link</a>
|
||||
|
||||
span -> <span></span>
|
||||
|
||||
The object supplies a toString() method that outputs the tag. Element
|
||||
helpers are immutable, so theoretically this should be safe from side
|
||||
effects. This interface allows the safe definition of templates which
|
||||
can be used and modified at will, for instance:
|
||||
|
||||
let mySpanClass = span.class('myclass'); // -> <span class="myclass"></span>
|
||||
mySpanClass.content("Hello!"); // -> <span class="myclass">Hello!</span>
|
||||
|
||||
Methods on an elementHelper return a new elementHelper that inherits from
|
||||
itself. Since those objects (should be) immutable by being frozen when they
|
||||
are created, this is semantically equivalent to returning a copy but more
|
||||
efficient in terms
|
||||
|
||||
Methods:
|
||||
class :: String -> elementHelper
|
||||
Returns a new elementHelper with the given class added.
|
||||
|
||||
classes :: [String] -> elementHelper
|
||||
Returns a new elementHelper with the given classes.
|
||||
|
||||
id :: String -> elementHelper
|
||||
Returns a new elementHelper with the given id.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
var md = require('markdown-it');
|
||||
|
||||
var markdown = new md({
|
||||
typographer: true,
|
||||
html: true
|
||||
});
|
||||
|
||||
var elementHelper = function (element) {
|
||||
this.element = element;
|
||||
this._classes = [];
|
||||
};
|
||||
|
||||
var elementSetterGen = function (prop) {
|
||||
return function (value) {
|
||||
return Object.freeze(Object.create(this, {
|
||||
[prop]: {value}
|
||||
}));
|
||||
};
|
||||
};
|
||||
|
||||
elementHelper.prototype.classes = function (newClasses) {
|
||||
return Object.freeze(Object.create(this, {
|
||||
_classes: {
|
||||
value: newClasses
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
elementHelper.prototype.class = function (newClass) {
|
||||
return this.classes(this._classes.concat(newClass));
|
||||
};
|
||||
|
||||
elementHelper.prototype.id = elementSetterGen("_id");
|
||||
elementHelper.prototype.type = elementSetterGen("_linkType");
|
||||
elementHelper.prototype.content = elementSetterGen("_content");
|
||||
elementHelper.prototype.ref = elementSetterGen("_ref");
|
||||
elementHelper.prototype.url = elementHelper.prototype.ref;
|
||||
elementHelper.prototype.situation = elementHelper.prototype.ref;
|
||||
elementHelper.prototype.once = () => this.class('once');
|
||||
|
||||
var linkTypeGen = function (type) {
|
||||
return function (ref) {
|
||||
return this.type(type).ref(ref);
|
||||
}
|
||||
};
|
||||
|
||||
elementHelper.prototype.writer = linkTypeGen("writer");
|
||||
elementHelper.prototype.replacer = linkTypeGen("replacer");
|
||||
elementHelper.prototype.inserter = linkTypeGen("inserter");
|
||||
elementHelper.prototype.action = linkTypeGen("action");
|
||||
|
||||
elementHelper.prototype.toString = function () {
|
||||
var classes = "",
|
||||
classString = "",
|
||||
idString = "",
|
||||
hrefString= "",
|
||||
contentString = "";
|
||||
|
||||
if (this._classes) {
|
||||
classes += this._classes.join(' ');
|
||||
}
|
||||
if (this._linkType) {
|
||||
classes += (' ' + this._linkType);
|
||||
}
|
||||
if (classes) {
|
||||
classString = ` class="${classes}"`;
|
||||
}
|
||||
|
||||
if (this._id) {
|
||||
idString = ` id="${this._id}"`;
|
||||
}
|
||||
|
||||
if (this.element === "a") {
|
||||
if (this._linkType) {
|
||||
if (this._linkType === "action") {
|
||||
hrefString = ` href="./${this._ref}"`;
|
||||
} else {
|
||||
hrefString = ` href="./_${this._linkType}_${this._ref}"`;
|
||||
}
|
||||
} else {
|
||||
hrefString = ` href="${this._ref}"`;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._content) {
|
||||
contentString = markdown.renderInline(this._content);
|
||||
}
|
||||
|
||||
return `<${this.element}${classString}${idString}${hrefString}>${contentString}</${this.element}>`;
|
||||
};
|
||||
|
||||
var a_proto = Object.freeze(new elementHelper("a"));
|
||||
var span_proto = Object.freeze(new elementHelper("span"));
|
||||
|
||||
var a = function (content) {
|
||||
if (content) return a_proto.content(content);
|
||||
return a_proto;
|
||||
};
|
||||
|
||||
var span = function (content) {
|
||||
if (content) return span_proto.content(content);
|
||||
return span_proto;
|
||||
};
|
||||
|
||||
module.exports.a = a;
|
||||
module.exports.span = span;
|
54
lib/qualities.js
Normal file
54
lib/qualities.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
Quality definition function
|
||||
|
||||
Meant to be called only once in the main story source file, this definition
|
||||
is passed a spec to define qualities. The spec is an object containing quality
|
||||
groups as objects, which contain qualities that themselves hold definitions.
|
||||
*/
|
||||
|
||||
var undum = require('undum-commonjs');
|
||||
|
||||
var qualities = function (spec) {
|
||||
Object.keys(spec).forEach(function(group) {
|
||||
/* The special "name" and "options" properties are passed on. */
|
||||
var groupName = (spec[group].name === undefined) ? null : spec[group].name;
|
||||
var groupOpts = (spec[group].options === undefined) ? {} : spec[group].options;
|
||||
undum.game.qualityGroups[group] = new undum.QualityGroup(groupName, groupOpts);
|
||||
Object.keys(spec[group]).forEach(function(quality) {
|
||||
if (quality === "name" || quality === "options") return;
|
||||
undum.game.qualities[quality] = spec[group][quality](group);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var qualityShim = {
|
||||
integer: "IntegerQuality",
|
||||
nonZeroInteger: "NonZeroIntegerQuality",
|
||||
numeric: "NumericQuality",
|
||||
fudgeAdjectives: "FudgeAdjectivesQuality",
|
||||
onOff: "OnOffQuality",
|
||||
yesNo: "YesNoQuality"
|
||||
};
|
||||
|
||||
Object.keys(qualityShim).forEach(function (key) {
|
||||
qualities[key] = function (title, spec={}) {
|
||||
return function (group) {
|
||||
spec.group = group;
|
||||
return new undum[qualityShim[key]](title, spec);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
/*
|
||||
WordScaleQuality has a different interface (naughty!) so it has to be
|
||||
defined by hand.
|
||||
*/
|
||||
|
||||
qualities.wordScale = function (title, words, spec={}) {
|
||||
return function (group) {
|
||||
spec.group = group;
|
||||
return new undum.WordScaleQuality(title, words, spec);
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = qualities;
|
215
lib/situation.js
215
lib/situation.js
|
@ -3,7 +3,7 @@ var undum = require('undum-commonjs'),
|
|||
$ = require('jquery');
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
Undularity is a rethought API for Undum, featuring more usable interfaces
|
||||
Raconteur is a rethought API for Undum, featuring more usable interfaces
|
||||
which coalesce as a DSL for defining Undum stories.
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -27,7 +27,7 @@ String.prototype.normaliseTabs = function () {
|
|||
|
||||
/* Agnostic Call */
|
||||
/*
|
||||
Many properties in Undularity can be either a String, or a function that
|
||||
Many properties in Raconteur can be either a String, or a function that
|
||||
takes some objects from the game state (character, system, and the current
|
||||
situation) and returns a String. Or in Haskell terms:
|
||||
String | (CharacterObject -> SystemObject -> SituationString -> String)
|
||||
|
@ -69,8 +69,8 @@ String.prototype.fade = function () {
|
|||
|
||||
/* Situations ----------------------------------------------------------------
|
||||
|
||||
The prototype UndularitySituation is the basic spec for situations
|
||||
created with Undularity. It should be able to handle any use case for Undum.
|
||||
The prototype RaconteurSituation is the basic spec for situations
|
||||
created with Raconteur. It should be able to handle any use case for Undum.
|
||||
|
||||
Properties:
|
||||
|
||||
|
@ -116,7 +116,7 @@ String.prototype.fade = function () {
|
|||
|
||||
*/
|
||||
|
||||
var UndularitySituation = function (spec) {
|
||||
var RaconteurSituation = function (spec) {
|
||||
undum.Situation.call(this, spec);
|
||||
|
||||
// Add all properties of the spec to the object, indiscriminately.
|
||||
|
@ -130,7 +130,7 @@ var UndularitySituation = function (spec) {
|
|||
|
||||
};
|
||||
|
||||
UndularitySituation.inherits(undum.Situation);
|
||||
RaconteurSituation.inherits(undum.Situation);
|
||||
|
||||
/*
|
||||
Undum calls Situation.enter every time a situation is entered, and
|
||||
|
@ -138,10 +138,10 @@ UndularitySituation.inherits(undum.Situation);
|
|||
and a string referencing the previous situation, or null if there is
|
||||
none (ie, for the starting situation).
|
||||
|
||||
Undularity's version of enter is set up to fulfill most use cases.
|
||||
Raconteur's version of enter is set up to fulfill most use cases.
|
||||
*/
|
||||
|
||||
UndularitySituation.prototype.enter = function (character, system, f) {
|
||||
RaconteurSituation.prototype.enter = function (character, system, f) {
|
||||
|
||||
this.visited++;
|
||||
|
||||
|
@ -167,13 +167,13 @@ UndularitySituation.prototype.enter = function (character, system, f) {
|
|||
(Ie, a link that doesn't point at another situation or an external URL) is
|
||||
clicked.
|
||||
|
||||
Undularity's version of act() is set up to implement commonly used
|
||||
Raconteur's version of act() is set up to implement commonly used
|
||||
functionality: "writer" links, "replacer" links, "inserter" links, and
|
||||
generic "action" links that call functions which access the underlying
|
||||
Undum API.
|
||||
*/
|
||||
|
||||
UndularitySituation.prototype.act = function (character, system, action) {
|
||||
RaconteurSituation.prototype.act = function (character, system, action) {
|
||||
var actionClass,
|
||||
self = this;
|
||||
|
||||
|
@ -219,199 +219,8 @@ UndularitySituation.prototype.act = function (character, system, action) {
|
|||
|
||||
};
|
||||
|
||||
/* Element Helpers */
|
||||
/*
|
||||
While you can write HTML elements by hand, those helpers make it easier to
|
||||
place anchors (especially with special purpose) and spans.
|
||||
|
||||
They define a monadic interface:
|
||||
|
||||
a.id('my-link').content('link').writer('my-ref')
|
||||
-> <a id="my-link" href="./_writer_my-ref">link</a>
|
||||
|
||||
span -> <span></span>
|
||||
|
||||
The object supplies a toString() method that outputs the tag. Element
|
||||
helpers are immutable, so theoretically this should be safe from side
|
||||
effects. This interface allows the safe definition of templates which
|
||||
can be used and modified at will, for instance:
|
||||
|
||||
let mySpanClass = span.class('myclass'); // -> <span class="myclass"></span>
|
||||
mySpanClass.content("Hello!"); // -> <span class="myclass">Hello!</span>
|
||||
|
||||
Methods on an elementHelper return a new elementHelper that inherits from
|
||||
itself. Since those objects (should be) immutable by being frozen when they
|
||||
are created, this is semantically equivalent to returning a copy but more
|
||||
efficient in terms
|
||||
|
||||
Methods:
|
||||
class :: String -> elementHelper
|
||||
Returns a new elementHelper with the given class added.
|
||||
|
||||
classes :: [String] -> elementHelper
|
||||
Returns a new elementHelper with the given classes.
|
||||
|
||||
id :: String -> elementHelper
|
||||
Returns a new elementHelper with the given id.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
var elementHelper = function (element) {
|
||||
this.element = element;
|
||||
this._classes = [];
|
||||
};
|
||||
|
||||
var elementSetterGen = function (prop) {
|
||||
return function (value) {
|
||||
return Object.freeze(Object.create(this, {
|
||||
[prop]: {value}
|
||||
}));
|
||||
};
|
||||
};
|
||||
|
||||
elementHelper.prototype.classes = function (newClasses) {
|
||||
return Object.freeze(Object.create(this, {
|
||||
_classes: {
|
||||
value: newClasses
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
elementHelper.prototype.class = function (newClass) {
|
||||
return this.classes(this._classes.concat(newClass));
|
||||
};
|
||||
|
||||
elementHelper.prototype.id = elementSetterGen("_id");
|
||||
elementHelper.prototype.type = elementSetterGen("_linkType");
|
||||
elementHelper.prototype.content = elementSetterGen("_content");
|
||||
elementHelper.prototype.ref = elementSetterGen("_ref");
|
||||
elementHelper.prototype.url = elementHelper.prototype.ref;
|
||||
elementHelper.prototype.situation = elementHelper.prototype.ref;
|
||||
elementHelper.prototype.once = () => this.class('once');
|
||||
|
||||
var linkTypeGen = function (type) {
|
||||
return function (ref) {
|
||||
return this.type(type).ref(ref);
|
||||
}
|
||||
};
|
||||
|
||||
elementHelper.prototype.writer = linkTypeGen("writer");
|
||||
elementHelper.prototype.replacer = linkTypeGen("replacer");
|
||||
elementHelper.prototype.inserter = linkTypeGen("inserter");
|
||||
elementHelper.prototype.action = linkTypeGen("action");
|
||||
|
||||
elementHelper.prototype.toString = function () {
|
||||
var classes = "",
|
||||
classString = "",
|
||||
idString = "",
|
||||
hrefString= "",
|
||||
contentString = "";
|
||||
|
||||
if (this._classes) {
|
||||
classes += this._classes.join(' ');
|
||||
}
|
||||
if (this._linkType) {
|
||||
classes += (' ' + this._linkType);
|
||||
}
|
||||
if (classes) {
|
||||
classString = ` class="${classes}"`;
|
||||
}
|
||||
|
||||
if (this._id) {
|
||||
idString = ` id="${this._id}"`;
|
||||
}
|
||||
|
||||
if (this.element === "a") {
|
||||
if (this._linkType) {
|
||||
if (this._linkType === "action") {
|
||||
hrefString = ` href="./${this._ref}"`;
|
||||
} else {
|
||||
hrefString = ` href="./_${this._linkType}_${this._ref}"`;
|
||||
}
|
||||
} else {
|
||||
hrefString = ` href="${this._ref}"`;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._content) {
|
||||
contentString = markdown.renderInline(this._content);
|
||||
}
|
||||
|
||||
return `<${this.element}${classString}${idString}${hrefString}>${contentString}</${this.element}>`;
|
||||
};
|
||||
|
||||
var a_proto = Object.freeze(new elementHelper("a"));
|
||||
var span_proto = Object.freeze(new elementHelper("span"));
|
||||
|
||||
var a = function (content) {
|
||||
if (content) return a_proto.content(content);
|
||||
return a_proto;
|
||||
};
|
||||
|
||||
var span = function (content) {
|
||||
if (content) return span_proto.content(content);
|
||||
return span_proto;
|
||||
};
|
||||
|
||||
/*
|
||||
Quality definition function
|
||||
|
||||
Meant to be called only once in the main story source file, this definition
|
||||
is passed a spec to define qualities. The spec is an object containing quality
|
||||
groups as objects, which contain qualities that themselves hold definitions.
|
||||
*/
|
||||
|
||||
var qualities = function (spec) {
|
||||
Object.keys(spec).forEach(function(group) {
|
||||
/* The special "name" and "options" properties are passed on. */
|
||||
var groupName = (spec[group].name === undefined) ? null : spec[group].name;
|
||||
var groupOpts = (spec[group].options === undefined) ? {} : spec[group].options;
|
||||
undum.game.qualityGroups[group] = new undum.QualityGroup(groupName, groupOpts);
|
||||
Object.keys(spec[group]).forEach(function(quality) {
|
||||
if (quality === "name" || quality === "options") return;
|
||||
undum.game.qualities[quality] = spec[group][quality](group);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var qualityShim = {
|
||||
integer: "IntegerQuality",
|
||||
nonZeroInteger: "NonZeroIntegerQuality",
|
||||
numeric: "NumericQuality",
|
||||
fudgeAdjectives: "FudgeAdjectivesQuality",
|
||||
onOff: "OnOffQuality",
|
||||
yesNo: "YesNoQuality"
|
||||
};
|
||||
|
||||
Object.keys(qualityShim).forEach(function (key) {
|
||||
qualities[key] = function (title, spec={}) {
|
||||
return function (group) {
|
||||
spec.group = group;
|
||||
return new undum[qualityShim[key]](title, spec);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
/*
|
||||
WordScaleQuality has a different interface (naughty!) so it has to be
|
||||
defined by hand.
|
||||
*/
|
||||
|
||||
qualities.wordScale = function (title, words, spec={}) {
|
||||
return function (group) {
|
||||
spec.group = group;
|
||||
return new undum.WordScaleQuality(title, words, spec);
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = function (name, spec) {
|
||||
spec.name = name;
|
||||
undum.game.situations[name] = new UndularitySituation(spec);
|
||||
};
|
||||
|
||||
module.exports.a = a;
|
||||
module.exports.span = span;
|
||||
|
||||
module.exports.qualities = qualities;
|
||||
undum.game.situations[name] = new RaconteurSituation(spec);
|
||||
};
|
9
raconteur.sublime-project
Normal file
9
raconteur.sublime-project
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"folders":
|
||||
[
|
||||
{
|
||||
"path": ".",
|
||||
"folder_exclude_patterns": ["node_modules", "devel/build"]
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue