- Update to use latest Bindings.
- Test Mode of Beleriand against the Doors of Durin, provide it as an example
in the mode selector.
- Adjust alternate forms of I to favor those most common on the Doors of
Durin.
- Support doubling vowels in all modes, as an alternative to expressing them
with accents.
- Update About page.
+// TODO parse following "w"
+
var TengwarParmaite = require("./tengwar-parmaite");
var Parser = require("./parser");
+var Notation = require("./notation");
var makeDocumentParser = require("./document-parser");
var normalize = require("./normalize");
var punctuation = require("./punctuation");
return callback(makeColumn("short-carrier"));
} else if (primes === 1) {
return callback(makeColumn("short-carrier").addAbove("i"));
+ } else if (primes === 2) {
+ return callback(makeColumn("long-carrier").addAbove("i"));
} else if (primes === 3) {
return callback(makeColumn("long-carrier"));
- } else if (primes === 4) {
- return callback(makeColumn("long-carrier").addAbove("i"));
} else {
return callback(makeColumn("long-carrier").addAbove("i").addError("I only has four variants between short or long and dotted or not."));
}
return function (character) {
if (character === "a") {
return function (character) {
- if (character === "i") {
+ if (character === "a") {
+ return parseTehta(callback, options, previous)("á");
+ } else if (character === "i") {
return callback([previous, makeColumn("yanta").addAbove("a")]);
} else if (character === "u") {
return callback([previous, makeColumn("ure").addAbove("a")]);
} else if (character === "e") {
var tehta = swapDotSlash("e", options);
return function (character) {
- if (character === "u") {
+ if (character === "e") {
+ return parseTehta(callback, options, previous)("é");
+ } else if (character === "u") {
return callback([previous, makeColumn("ure").addAbove(tehta)]);
} else if (previous && previous.canAddAbove("e")) {
return callback([previous.addAbove(tehta)])(character);
} else if (character === "i") {
var iTehta = swapDotSlash("i", options);
return function (character) {
- if (character === "u") {
+ if (character === "i") {
+ return parseTehta(callback, options, previous)("í");
+ } else if (character === "u") {
if (options.iuRising) {
return callback([previous, makeColumn("anna").addAbove(reverseCurls("u", options)).addBelow("y")]);
} else {
};
} else if (character === "o") {
return function (character) {
- if (character === "i") {
+ if (character === "o") {
+ return parseTehta(callback, options, previous)("ó");
+ } else if (character === "i") {
return callback([previous, makeColumn("yanta").addAbove(reverseCurls("o", options))]);
} else if (previous && previous.canAddAbove("o")) {
return callback([previous.addAbove(reverseCurls("o", options))])(character);
};
} else if (character === "u") {
return function (character) {
- if (character === "i") {
+ if (character === "u") {
+ return parseTehta(callback, options, previous)("ú");
+ } else if (character === "i") {
return callback([previous, makeColumn("yanta").addAbove("u")]);
} else if (previous && previous.canAddAbove("u")) {
return callback([previous.addAbove(reverseCurls("u", options))])(character);
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
- <style>
- body {
- width: 40em;
- }
- </style>
+ <link rel="stylesheet" type="text/css" href="page.css">
</head>
- <body>
+ <body><div>
+
+ <h1>Tengwar Transcriber</h1>
<p><em><strong>Usage:</strong></em>
- <a href="index.html">This</a> is a live transcriber from our Latin phonetic
- alphabet to the elvish Tengwar alphabet. Type a message in the bottom
- text area and it will be displayed in the equivalent elvish letters
- in the area above. Copy the link in the address bar and send
- your message to friends and colleagues.</p>
+ <a href="index.html">This</a> is a live transcriber from our Latin
+ phonetic alphabet to the Elvish Tengwar alphabet. Type a message in
+ the bottom text area and it will be displayed in the equivalent Elvish
+ letters in the area above. Copy the link in the address bar and send
+ your message to friends and colleagues. Copy the Wiki text and paste
+ the Tengwar Markup block into an article on a Wiki that
+ <a href="#support-wiki-markup">supports</a> this Tengwar
+ Transcriber.</p>
<p><em><strong>Compatibility:</strong></em> The transcriber may not
work in some browsers because I used fancy early-draft features of some
<p>However, there is a much older
<a href="http://tengwar.art.pl/tengwar/ott/start.php?l=en">tengwar transcriber</a>
that should suffice in the interim.</p>
+
+ <a name="wiki-markup-support"></a>
+ <p><em><strong>Wiki Markup Support:</strong></em> At present, no wikis
+ support Tengwar transcription with this tool. If you maintain a
+ MediaWiki installation and would like to add support for this tool,
+ I’ve published an open-source
+ <a href="https://github.com/kriskowal/tengwarjs/blob/master/mediawiki/tengwar.php">MediaWiki extension</a>.
+ Install that PHP script and incorporate the transcriber’s static assets
+ in your page, which include <code>tengwar.min.js</code>, and the
+ <code>css</code>, <code>ttf</code>, <code>eot</code>, <code>svg</code>,
+ <code>woff</code> files for <code>tengwar-annatar</code> and
+ <code>tengwar-parmaite</code> from
+ <a href="https://github.com/kriskowal/tengwarjs">TengwarJS</a>.</p>
<p><em><strong>Purpose:</strong></em> The transcriber is suitable for
rendering <a href="http://tolkiengateway.net/wiki/Sindarin">Sindarin</a> in
more or the
<a href="http://at.mansbjorkman.net/teng_beleriand.htm">Mode of Beleriand</a>,
and <a href="http://tolkiengateway.net/wiki/Quenay">Quenya</a> in the
- <a href="http://at.mansbjorkman.net/teng_quenya.htm">Classical</a> mode.</p>
-
- <p>The General Use mode is suitable for showing how Sindarin might
- have been written and attempts to be consistent with
- <em>The King’s Letter</em> from J.R.R. Tolkien’s book,
- <a href="http://tolkiengateway.net/wiki/Sauron_Defeated">Sauron Defeated</a>,
- I used the same mode for my
- <a href="http://3rin.gs/"><nobr>Map of Middle-earth</nobr></a>.</p>
-
- <p>I’ve posted some <a href="../samples/index.html">sample
- transcriptions</a> in various modes.</p>
+ <a href="http://at.mansbjorkman.net/teng_quenya.htm">Classical</a>
+ mode. The <a href="modes.html">Mode Selector</a> provides information,
+ options, and instructions for comparing Tengwar modes, fonts, and the
+ supported languages.</p>
<p><em><strong>Technical details:</strong></em>
The transcriber gives you the option of using either the italic of
in the untypable regions of a single font because of technical
limitations of rendering fonts in web browsers. Particularly, a font
cannot paint outside its container, so a tehta rendered alone in a span
- would be rendered invisible.
+ would be invisible.
<p><em>Tengwar Annatar’s</em> italic resembles the <em>Ring
Inscription</em> from <em>The Lord of the Rings</em>, presumably in
alphabet, Johan’s Annatar provides some glyphs in an alternate font.</p>
<p>Because of limitations in rendering text on the web and the
- peculiarities of elvish fonts, it was not possible to alternate between
+ peculiarities of Elvish fonts, it was not possible to alternate between
the normal and alternate fonts in this application. Instead, I’ve
created a custom version of the font that incorporates the alternate
glyphs I needed for this mode using code points that are not so
rotated U-hook tehtar that were less prone to overlap with the
underlying tengwar.</p>
- <p>The particular limitation is that diacritics in elvish have no width
+ <p>The particular limitation is that diacritics in Elvish have no width
and are drawn before the cursor. Some of the diacritics I use are in
the alternate font. To put an alternate diacritic over the previous
tengwa, consonant, glyph, you have to put it in a
precisely where they need to be or providing ligatures for difficult
placements.</p>
- <p>In the interim, I’ve engaged in the process of manually verifying
- the placement and use of diacritics for every
- combination of tengwa and tehta for
- <a href="../combinations/tengwar-parmaite.html">both</a>
- <a href="../combinations/tengwar-annatar.html">fonts</a></p>
-
- <p>If you take a look under the hood, the transcriber is a CommonJS
- module, suitable for use both with a NodeJS package available in NPM as
- <code>tengwar</code> and usable as a browser script with the minified
- bundle.</p>
+ <p>If you take a look
+ <a href="https://github.com/kriskowal/tengwarjs">under the bonnet</a>,
+ the transcriber is a CommonJS module, suitable for use both with a
+ NodeJS package available in NPM as <code>tengwar</code> and usable as a
+ browser script with the minified bundle.</p>
<p>Further work might include:</p>
<li>More modes of transcription, particularly phonetic and
orthographic English and Quenya.</li>
<li>Tie-in with IPA dictionaries of various languages</li>
- <li>Tie-in with elvish dictionary for special-cases</li>
+ <li>Tie-in with Elvish dictionary for special-cases</li>
<li>Display intermediate encoding that shows the names of each
tengwa and tehta in every cluster.</li>
<li>Search the dictionary, encyclopedia, and map.</li>
})();
</script>
- </body>
+ </div></body>
</html>
<title>Tengwar Transcriber</title>
<link rel="stylesheet" type="text/css" href="node_modules/tengwar/tengwar-parmaite.css">
<link rel="stylesheet" type="text/css" href="node_modules/tengwar/tengwar-annatar.css">
- <link rel="stylesheet" type="text/css" href="index.css">
+ <link rel="stylesheet" type="text/css" href="app.css">
</head>
- <body class="annatar">
+ <body>
<noscript>
<br>This transcriber makes extensive use
},
"heightPx": {
- dependencies: "state.height",
- get: function () {
- return this.state.height + "px";
+ "<-": "state.height",
+ convert: function (height) {
+ return height + "px";
},
- set: function (height) {
- this.state.height = parseInt(height, 10);
+ revert: function (height) {
+ return parseInt(height, 10);
}
},
"mode": {
- dependencies: "state.mode",
- get: function () {
- return modes[this.state.mode] || modes['general-use'];
+ args: ["state.mode"],
+ compute: function (mode) {
+ return modes[mode] || modes['general-use'];
}
},
"font": {
- dependencies: "state.font",
- get: function () {
- return fonts[this.state.font] || modes['annatar'];
+ args: ["state.font"],
+ compute: function (font) {
+ return fonts[font] || modes['annatar'];
}
},
- "transcription": {
- dependencies: ["mode", "font", "state.q"],
- get: function () {
+ "outputElement.innerHTML": {
+ args: ["mode", "font", "state.q", "state.options"],
+ compute: function (mode, font, input, flags) {
var options = {
- font: this.font,
+ font: font,
block: true
};
- this.state.options.forEach(function (flag) {
+ flags.forEach(function (flag) {
flag = flag.replace(/\-(\w)/g, function ($, $1) {
return $1.toUpperCase();
});
options[flag] = true;
});
- return this.mode.transcribe(this.state.q, options);
+ return mode.transcribe(input, options);
}
},
- "outputElement.innerHTML": {
- "<-": "transcription"
+ "selectModeElement.href": {
+ "<-": "'modes.html' + searchString"
},
"searchString": {
- dependencies: ["state.q", "state.mode", "state.font", "state.height", "state.options"],
- get: function () {
- if (!this.state)
- return;
- delete this.state[""]; // XXX QS bug interprets empty array as & and back to an empty assignment
+ args: ["state.q", "state.mode", "state.font", "state.height", "state.options"],
+ compute: function () {
+ var state = this.state;
+
+ // remove things that QS can't seem to handle
+ delete state[""]; // XXX QS bug interprets empty array as & and back to an empty assignment
+ if (state.options.length == 0) {
+ delete state.options;
+ }
var string = "?" + QS.stringify(this.state);
window.history.replaceState(this.state, "", string);
+
+ state.options = state.options || [];
return string;
}
},
- "selectModeElement.href": {
- "<-": "'modes.html' + searchString"
+ "wikiTextElement.href": {
+ "<-": "'data:text/plain;charset=utf-8,' + wikiText"
},
"wikiText": {
- "dependencies": ["state.q", "state.mode", "state.font", "state.height", "state.options"],
- get: function () {
- var text = this.state.q;
- var font = this.state.font;
- var mode = [this.state.mode].concat(this.state.options).filter(Boolean).join(" ");
+ args: ["state.q", "state.mode", "state.font", "state.height", "state.options"],
+ compute: function (text, mode, font, height, flags) {
+ var modeLine = [mode].concat(flags).filter(Boolean).join(" ");
if (/\n/.test(text)) {
return encodeURIComponent(
"<tengwarblock " +
"font=\"" + font + "\" " +
"mode=\"" + mode + "\">\n" +
- text +
+ encodeHtml(text) +
"\n</tengwarblock>"
);
} else {
"<tengwar " +
"font=\"" + font + "\" " +
"mode=\"" + mode + "\">" +
- text +
+ encodeHtml(text) +
"</tengwar>"
);
}
}
- },
-
- "wikiTextElement.href": {
- "<-": "'data:text/plain,' + wikiText"
}
});
}
});
+function encodeHtml(string) {
+ return String(string)
+ .replace(/&/g, "&")
+ .replace(/</g, "<")
+ .replace(/>/g, ">");
+}
+
<title>Tengwar Transcriber</title>
<link rel="stylesheet" type="text/css" href="node_modules/tengwar/tengwar-parmaite.css">
<link rel="stylesheet" type="text/css" href="node_modules/tengwar/tengwar-annatar.css">
- <link rel="stylesheet" type="text/css" href="modes.css">
+ <link rel="stylesheet" type="text/css" href="page.css">
<script src="node_modules/mr/bootstrap.js" data-module="modes"></script>
</head>
<body><div>
+
<h1>Modes of the Tengwar</h1>
+ <h3><em>For a Tengar Transcriber</em></h3>
<ul>
<li><a href="#general-use">General Use Mode</a></li>
</ul>
<li><a href="#beleriand">Mode of Beleriand</a></li>
<ul>
+ <li><a href="#doors-of-durin">Doors of Durin</a></li>
<li><a href="#kings-letter-beleriand">The First Version of the King’s Letter</a></li>
</ul>
</ul>
<h3>As in the third version of <em><a class="dagger" href="http://tolkiengateway.net/wiki/King's_Letter">The King’s Letter</a></em></h3>
<div>
- <span class="dynamic-tengwar"
+ <span id="kings-letter-general-use-tengwar"
+ class="dynamic-tengwar"
data-tengwar="Elessar Telcontar: Aragorn Arathornion Edhelharn, aran Gondor ar Hîr i Mbair Annui, anglennatha i Varanduiniant erin dolothen Ethuil, egor ben genediad Drannail erin Gwirith edwen."
data-mode="general-use"
data-font="parmaite">
<h3>As in <em><a class="dagger" href="http://tolkiengateway.net/wiki/Ring_Verse">The One Ring Inscription</a></em></h3>
<div>
- <span class="dynamic-tengwar"
- data-tengwar=">ashnazgdurbatulûk, ashnazggimbatul<
- ashnazgthrakatulûk, aghburzumishikrimpatul"
+ <span id="black-speech-tengwar"
+ class="dynamic-tengwar"
+ data-tengwar=">ashnazgdurbatulûk, ashnazggimbatul< ashnazgthrakatulûk, aghburzumishikrimpatul"
data-mode="general-use black-speech"
data-font="annatar">
Rendering… (Requires JavaScript and Web Fonts)
<h3>As in <em><a class="dagger" href="http://tolkiengateway.net/wiki/Nam%C3%A1ri%C3%AB">The Namárië Poem</a></em></h3>
<div>
- <span class="dynamic-tengwar"
- data-tengwar="Ai! laurië lantar lassi súrinen,
- Yéni únótimë ve rámar aldaron!"
+ <span id="namarie-tengwar"
+ class="dynamic-tengwar"
+ data-tengwar="Ai! laurië lantar lassi súrinen, Yéni únótimë ve rámar aldaron!"
data-mode="classical"
data-font="parmaite">
</span>
<hr>
+ <a name="doors-of-durin"></a>
+ <h2><a class="dagger" href="http://at.mansbjorkman.net/teng_beleriand.htm">Mode of Beleriand</a></h2>
+ <h3>As on the <em><a class="dagger" href="http://tolkiengateway.net/wiki/Doors_of_Durin">Doors of Durin</a></em>, Moria</h3>
+
+ <div>
+ <span id="doors-of-durin-tengwar"
+ class="dynamic-tengwar"
+ data-tengwar="Ennyn Durin Aran Mori'a - Pedo Mellon a Mi''nno. Im Narvi hain echant. Celebri''mbor o Eregi'on teithant i'' thi'w hi'n."
+ data-mode="beleriand"
+ data-font="parmaite">
+ Rendering… (Requires JavaScript and Web Fonts)
+ </span>
+ <button id="doors-of-durin-button">Select</button>
+ </div>
+
+ <blockquote>
+ Ennyn Durin Aran Moria — Pedo Mellon a Minno.<br>
+ Im Narvi hain echant. Celebrimbor o Eregion teithant i thiw hin.
+ </blockquote>
+
+ <blockquote>
+ The Doors of Durin, Lord of Moria — Speak, friend, and enter.<br>
+ I, Narvi, made them. Celebrimbor of Hollin drew these signs.
+ </blockquote>
+
+ <p>The Mode of Beleriand uses a tengwa for nearly every vowel
+ <em>and</em> consonant. Diacritics (marks) are applied to lengthen
+ vowels, merge vowels into diphthongs (glides), or precede a consonant
+ with the corresponding nasal, like NT and MB.</p>
+
+ <p>This particular example, from <em>The Fellowship of the Ring</em>
+ uses inconsistent variations of the letter I. An I can be represented
+ by a short or long carrier, with or without a dot above, and three
+ variants are used in the attested inscription. 0–3 tick marks
+ after an I tell the transcriber which variant to use.</p>
+
+
+ <hr>
+
+
<a name="kings-letter-beleriand"></a>
<h2><a class="dagger" href="http://at.mansbjorkman.net/teng_beleriand.htm">Mode of Beleriand</a></h2>
<h3>As in the first version of <em><a class="dagger" href="http://tolkiengateway.net/wiki/King's_Letter">The King’s Letter</a></em></h3>
<div>
- <span class="dynamic-tengwar"
+ <span id="kings-letter-beleriand-tengwar"
+ class="dynamic-tengwar"
data-tengwar="Elessar Telcontar: Aragorn Arathornion Edhelharn, aran Gondor ar Hîr i Mbair Annui, anglennatha i Varanduiniant erin dolothen Ethuil, egor ben genediad Drannail erin Gwirith edwen."
data-mode="beleriand"
data-font="parmaite">
<a name="general-use"></a>
<h2><a class="dagger" href="http://at.mansbjorkman.net/teng_quenya.htm">General Use Mode</a></h2>
+ <p>General Use Mode uses diacritics to represent vowels, usually above
+ the tengwa the vowel precedes. General Use mode is suitable for
+ representing most languages and was used mostl colloquial languages in
+ Middle-earth in the Third Age.</p>
+
<table id="general-use-table">
<tr><th colspan="3">Font</th></tr>
<td>
<td><span class="general-use-font" data-tengwar="
rats cats'
- bats'', rats''',
+ bats'' rats'''
cats'''' bats'''''
" data-mode="general-use"></span>
<td>
</td>
</tr>
+ <tr><th colspan="3">Long Vowels</th></tr>
+ <tr>
+ <td>
+ <td><span class="general-use-font" data-tengwar="aa ee ii oo uu" data-mode="beleriand"></span>
+ </td>
+ <td>
+ Long vowels can be expressed by doubling the vowel.
+ Although Tolkien would never have expressed a
+ transliteration to the Latin alphabet in that way, the
+ transcriber tollerates it as a convenience for typists who
+ are not familiar with how to use accents with their
+ keyboard.
+ </td>
+ </tr>
+
<tr><th colspan="3">Orthographic E</th></tr>
<tr>
<td>
<td><span class="general-use-font" data-tengwar="love'" data-mode="general-use"></span>
<td><code>love'</code>, silent E for orthographic English
- (transliterated by letter instead of sound).
+ (transliterated by letter instead of sound).</td>
</tr>
</table>
<a name="classical"></a>
<h2><a class="dagger" href="http://at.mansbjorkman.net/teng_quenya.htm">Classical Mode</a></h2>
+ <p>Classical Mode uses diacritics for vowels, usually above the tengwa
+ they <em>follow</em>. The mode is optimal for expressing
+ <a class="dagger" href="http://tolkiengateway.net/wiki/Quenya">Quenya</a>,
+ the elder language of the Elves, but does not provide the full palette
+ of sounds necessary for many other languages including English and
+ Sindarin.</p>
+
<table>
<tr><th colspan="3">Font</th></tr>
<tr>
<td>
<input type="radio"
- id="classical-falling-iu"
+ id="classical-iu-falling"
name="classical-iu"
checked>
</td>
</td>
</tr>
+ <tr><th colspan="3">Long Vowels</th></tr>
+ <tr>
+ <td>
+ <td><span class="classical-font" data-tengwar="aa ee ii oo uu" data-mode="beleriand"></span>
+ </td>
+ <td>
+ Long vowels can be expressed by doubling the vowel.
+ Although Tolkien would never have expressed a
+ transliteration to the Latin alphabet in that way, the
+ transcriber tollerates it as a convenience for typists who
+ are not familiar with how to use accents with their
+ keyboard.
+ </td>
+ </tr>
+
</table>
<a name="beleriand"></a>
<h2><a class="dagger" href="http://at.mansbjorkman.net/teng_beleriand.htm">Mode of Beleriand</a></h2>
+ <p>The Mode of Beleriand uses a tengwa for nearly every vowel
+ <em>and</em> consonant. Diacritics (marks) are applied to lengthen
+ vowels, merge vowels into diphthongs (glides), or precede a consonant
+ with the corresponding nasal, like NT and MB, but full tengwa are used
+ for most vowels and consonants.</p>
+
<table>
<tr><th colspan="3">Font</th></tr>
</td>
</tr>
+ <tr><th colspan="3">Long Vowels</th></tr>
+ <tr>
+ <td>
+ <td><span class="beleriand-font" data-tengwar="aa ee ii oo uu yy" data-mode="beleriand"></span>
+ </td>
+ <td>
+ Long vowels can be expressed by doubling the vowel.
+ Although Tolkien would never have expressed a
+ transliteration to the Latin alphabet in that way, the
+ transcriber tollerates it as a convenience for typists who
+ are not familiar with how to use accents with their
+ keyboard.
+ </td>
+ </tr>
+
+ <tr><th colspan="3">Variations of I</th></tr>
+ <tr>
+ <td>
+ <td><span class="beleriand-font" data-tengwar="
+ i i' i'' i'''
+ ii ii'
+ " data-mode="beleriand"></span>
+ </td>
+ <td>
+ <code>i i' i'' i'''</code><br>
+ <code>í í'</code> <em>or</em> <code>ii ii'</code>
+ </td>
+ </tr>
</table>
<p><button id="beleriand-button">Select</button></p>
+
+ <script src="http://static.getclicky.com/js" type="text/javascript"></script>
+ <script type="text/javascript">clicky.init(237383);</script>
+ <noscript><p><img alt="Clicky" width="1" height="1" src="http://in.getclicky.com/237383ns.gif" /></p></noscript>
+
+ <script type="text/javascript">
+ var _gaq = _gaq || [];
+ _gaq.push(['_setAccount', 'UA-25808349-1']);
+ _gaq.push(['_setDomainName', '.3rin.gs']);
+ _gaq.push(['_trackPageview']);
+ (function() {
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+ })();
+ </script>
+
</div></body>
</html>
q: "",
mode: "general-use",
font: "annatar",
- options: [],
height: void 0
}
}
-if (inputState.q === "Mae Govannen, Arda!") {
+if (inputState.q === "Mae govannen, Arda!") {
inputState.q = "";
}
+inputState.options = inputState.options || [];
var traceAll = false;
},
"mode": {
- "dependencies": "state.mode",
- "get": function () {
- return modes[this.state.mode];
+ "args": ["state.mode"],
+ "compute": function (mode) {
+ return modes[mode];
}
},
- "font": {
- "dependencies": "state.font",
- "get": function () {
- return fonts[this.state.font];
+ "options.font": {
+ "args": ["state.font"],
+ "compute": function (font) {
+ return fonts[font];
}
},
- "options.font": {"<-": "font"},
-
- "transcription": {
- "dependencies": ["options.font", "mode", "input"],
- "get": function () {
- var options = this.mode.makeOptions(this.options);
- return this.mode.transcribe(this.input, options);
+ "element.innerHTML": {
+ "args": ["options.font", "mode", "input", "options"],
+ "compute": function (font, mode, input, options) {
+ var options = mode.makeOptions(options);
+ return mode.transcribe(input, options);
}
- },
-
- "element.innerHTML": {"<-": "transcription"},
+ }
});
}
// template modes
Button(document.getElementById("kings-letter-general-use-button"), {
- q: inputState.q || "Elessar Telcontar: Aragorn Arathornion Edhelharn, aran Gondor ar Hîr i Mbair Annui, anglennatha i Varanduiniant erin dolothen Ethuil, egor ben genediad Drannail erin Gwirith edwen.",
+ q: document.getElementById("kings-letter-general-use-tengwar").dataset.tengwar,
font: "parmaite",
mode: "general-use",
options: []
});
Button(document.getElementById("kings-letter-beleriand-button"), {
- q: inputState.q || "Elessar Telcontar: Aragorn Arathornion Edhelharn, aran Gondor ar Hîr i Mbair Annui, anglennatha i Varanduiniant erin dolothen Ethuil, egor ben genediad Drannail erin Gwirith edwen.",
+ q: document.getElementById("kings-letter-beleriand-tengwar").dataset.tengwar,
+ font: "parmaite",
+ mode: "beleriand",
+ options: []
+});
+
+Button(document.getElementById("doors-of-durin-button"), {
+ q: document.getElementById("doors-of-durin-tengwar").dataset.tengwar,
font: "parmaite",
mode: "beleriand",
options: []
});
Button(document.getElementById("black-speech-button"), {
- q: inputState.q || ">ashnazgdurbatulûk, ashnazggimbatul<\nashnazgthrakatulûk, aghburzumishikrimpatul",
+ q: document.getElementById("black-speech-tengwar").dataset.tengwar,
font: "annatar",
mode: "general-use",
options: ["black-speech"]
});
Button(document.getElementById("namarie-button"), {
- q: inputState.q || "Ai! laurië lantar lassi súrinen,\nYéni únótimë ve rámar aldaron!",
+ q: document.getElementById("namarie-tengwar").dataset.tengwar,
font: "parmaite",
mode: "classical",
options: []
["general-use", "classical", "beleriand"].forEach(function (mode) {
var state = states[mode];
state.q = inputState.q || "";
- state.options.swap(0, states[mode].options.length, inputState.options);
+ state.options.swap(0, states[mode].options.length, inputState.options.filter(function (option) {
+ return option && option !== "undefined";
+ }));
});
}
a {
- text-decoration: none;
- color: #700;
-}
-
-a.dagger:after {
- content: "†";
+ color: #a00;
}
table {
white-space: nowrap;
}
+label {
+ display: block;
+ cursor: pointer;
+}
+
hr {
border: solid #500 1px;
}
// put the previous tehta over the appropriate carrier
// then follow up with this tengwa.
return parseTengwaAnnotations(function (column) {
- return callback([makeCarrier(tehta), column]);
+ return callback([makeCarrier(tehta, options), column]);
}, column);
}
} else {
}
return parseTengwaAnnotations(function (carrier) {
return callback([carrier]);
- }, makeCarrier(tehta));
+ }, makeCarrier(tehta, options));
} else {
return function (character) {
if (Parser.isBreak(character)) {
}, options, tehta);
});
- function makeCarrier(tehta) {
- if (shorterVowels[tehta]) {
- return makeColumn("long-carrier").addAbove(shorterVowels[tehta]);
- } else {
- return makeColumn("short-carrier").addAbove(tehta);
- }
+}
+
+function makeCarrier(tehta, options) {
+ var font = options.font;
+ var makeColumn = font.makeColumn;
+ if (tehta === "á") {
+ return makeColumn("wilya").addAbove("a");
+ } else if (shorterVowels[tehta]) {
+ return makeColumn("long-carrier").addAbove(shorterVowels[tehta]);
+ } else {
+ return makeColumn("short-carrier").addAbove(tehta);
}
}
function parseTehta(callback) {
return function (character) {
- if (tengwaTehtar.indexOf(character) !== -1) {
+ if (character === "") {
+ return callback();
+ } else if (lengthenableVowels.indexOf(character) !== -1) {
+ return function (nextCharacter) {
+ if (nextCharacter === character) {
+ return callback(longerVowels[character]);
+ } else {
+ return callback(character)(nextCharacter);
+ }
+ };
+ } else if (nonLengthenableVowels.indexOf(character) !== -1) {
return callback(character);
} else {
return callback()(character);
};
}
-var tengwaTehtar = "aeiouóú";
+var lengthenableVowels = "aeiou";
+var longerVowels = {"a": "á", "e": "é", "i": "í", "o": "ó", "u": "ú"};
+var nonLengthenableVowels = "aeióú";
+var tehtarThatCanBeAddedAbove = "aeiouóú";
var vowels = "aeiouáéíóú";
var shorterVowels = {"á": "a", "é": "e", "í": "i", "ó": "o", "ú": "u"};
var reverseCurls = {"o": "u", "u": "o", "ó": "ú", "ú": "ó"};
var swapDotSlash = {"i": "e", "e": "i"};
function canAddAboveTengwa(tehta) {
- return tengwaTehtar.indexOf(tehta) !== -1;
+ return tehtarThatCanBeAddedAbove.indexOf(tehta) !== -1;
}
function parseTengwa(callback, options, tehta) {
} else if (character === "y") {
return callback(makeColumn("wilya").addBelow("y"));
// TODO consider alt: return callback(makeColumn("long-carrier").addAbove("i"));
- } else if (character === "á") {
- return callback(makeColumn("wilya").addAbove("a"));
- } else if (shorterVowels[character] && tengwaTehtar.indexOf(character) == -1) {
- return callback(makeColumn("long-carrier").addAbove(shorterVowels[character]));
+ } else if (shorterVowels[character]) {
+ return callback(makeCarrier(character, options).addAbove(shorterVowels[character]));
} else {
return callback()(character);
}
--- /dev/null
+
+var Beleriand = require("../beleriand");
+var tests = require("./beleriand");
+
+describe("beleriand", function () {
+ Object.keys(tests).forEach(function (input) {
+ it("should encode " + input, function () {
+ expect(Beleriand.encode(input, {
+ })).toEqual(tests[input]);
+ });
+ });
+});
+
--- /dev/null
+module.exports = {
+
+ // Doors of Durin
+ "Ennyn": "yanta;numen;silme-nuquerna;ore",
+ "Durin": "ando;ure;romen;short-carrier;ore",
+ "Aran": "round-carrier;romen;round-carrier;ore",
+ "Mori'a": "vala;anna;romen;short-carrier:i;round-carrier",
+ "Pedo": "parma;yanta;ando;anna",
+ "Mellon": "vala;yanta;lambe;lambe;anna;ore",
+ "a": "round-carrier",
+ "Mi'nno.": "vala;short-carrier:i;numen;anna;full-stop",
+ "Im": "short-carrier;vala",
+ "Narvi": "ore;round-carrier;romen;ampa;short-carrier",
+ "hain": "hyarmen;round-carrier:í;ore",
+ "echant.": "yanta;harma;round-carrier;tinco:tilde-above;full-stop",
+ "Celebri''mbor": "calma;yanta;lambe;yanta;umbar;romen;long-carrier:i;umbar:tilde-above;anna;romen",
+ "o": "anna",
+ "Eregi'on": "yanta;romen;yanta;anga;short-carrier:i;anna;ore",
+ "teithant": "tinco;yanta:í;thule;round-carrier;tinco:tilde-above",
+ "i''": "long-carrier:i",
+ "thiw": "thule;short-carrier;wilya",
+ "hi'n.": "hyarmen;short-carrier:i;ore;full-stop"
+
+};
"hlóce": "halla;lambe:ó;calma:e", // attested
"hríve": "halla;romen;long-carrier:i;vala:e", // attested
"hyarmen": "hyarmen:a,y;ore;malta:e;numen",
- //"hyarmen(classical)": "hyarmen:a;romen;malta:e;numen",
- //"hyarmen(classical,aha)": "hyarmen:a,y;romen;malta:e;numen",
"lambe": "lambe:a;umbar:e",
"moria": "malta:o;romen:i;short-carrier:a",
"namárië": "numen:a;malta;long-carrier:a;romen:i;short-carrier:e",
+ "namaarië": "numen:a;malta;long-carrier:a;romen:i;short-carrier:e",
"silme": "silme-nuquerna:i;lambe;malta:e",
"syi": "silme:y;short-carrier:i", //*
"thúlë": "thule:ú;lambe:e",
"tyelpe": "tinco:e,y;lambe;parma:e",
"vanwa": "vala:a;numen;wilya:a",
"yuldar": "anna:u,y;alda:a;ore",
+
+ // long vowels
+ "á": "long-carrier:a",
+ "aa": "long-carrier:a",
+ "é": "long-carrier:e",
+ "ee": "long-carrier:e",
+ "í": "long-carrier:i",
+ "ii": "long-carrier:i",
+ "ó": "long-carrier:o",
+ "oo": "long-carrier:o",
+ "ú": "long-carrier:u",
+ "uu": "long-carrier:u"
+
};
"allys": "lambe:a,y,s-final,tilde-below",
"alyssa": "lambe:a,y;silme:tilde-below;short-carrier:a",
"ls": "lambe:s-final",
- "ls'": "lambe:s-flourish"
+ "ls'": "lambe:s-flourish",
+
+ // long vowels
+ "á": "wilya:a",
+ "aa": "wilya:a",
+ "é": "long-carrier:e",
+ "ee": "long-carrier:e",
+ "í": "long-carrier:i",
+ "ii": "long-carrier:i",
+ "ó": "long-carrier:o",
+ "oo": "long-carrier:o",
+ "ú": "long-carrier:u",
+ "uu": "long-carrier:u"
};