<metaname="description"content="Menu Modules From initial connection to the screens and mods your users interact with, the entire experience is made up of menu entries — And all menu entries found within menu.hjson are backed by Menu Modules. For basic menus, a standard handler is implemented requiring no code. However, if you would like to create a menu that has custom handling, you will very likely be inheriting from from MenuModule. More on this below."/>
<metaproperty="og:description"content="Menu Modules From initial connection to the screens and mods your users interact with, the entire experience is made up of menu entries — And all menu entries found within menu.hjson are backed by Menu Modules. For basic menus, a standard handler is implemented requiring no code. However, if you would like to create a menu that has custom handling, you will very likely be inheriting from from MenuModule. More on this below."/>
{"datePublished":"2023-10-15T23:34:51+00:00","description":"Menu Modules From initial connection to the screens and mods your users interact with, the entire experience is made up of menu entries — And all menu entries found within menu.hjson are backed by Menu Modules. For basic menus, a standard handler is implemented requiring no code. However, if you would like to create a menu that has custom handling, you will very likely be inheriting from from MenuModule. More on this below.","mainEntityOfPage":{"@type":"WebPage","@id":"/enigma-bbs/modding/menu-modules.html"},"publisher":{"@type":"Organization","logo":{"@type":"ImageObject","url":"/enigma-bbs/assets/images/enigma-logo.png"}},"url":"/enigma-bbs/modding/menu-modules.html","@type":"BlogPosting","headline":"Menu Modules","dateModified":"2023-10-15T23:34:51+00:00","@context":"https://schema.org"}</script>
<p>From initial connection to the screens and mods your users interact with, the entire experience is made up of menu entries — And all menu entries found within <ahref="/enigma-bbs/configuration/menu-hjson.html">menu.hjson</a> are backed by <em>Menu Modules</em>. For basic menus, a standard handler is implemented requiring no code. However, if you would like to create a menu that has custom handling, you will very likely be inheriting from from <codeclass="language-plaintext highlighter-rouge">MenuModule</code>. More on this below.</p>
<p><imgclass="emoji"title=":information_source:"alt=":information_source:"src="https://github.githubassets.com/images/icons/emoji/unicode/2139.png"height="20"width="20"> Remember that ENiGMA does not impose any stucture to your system! The “flow” of all <codeclass="language-plaintext highlighter-rouge">menu.hjson</code> entries is up to you!</p>
<p><imgclass="emoji"title=":bulb:"alt=":bulb:"src="https://github.githubassets.com/images/icons/emoji/unicode/1f4a1.png"height="20"width="20"> If the <codeclass="language-plaintext highlighter-rouge">module</code> entry is not present in a <codeclass="language-plaintext highlighter-rouge">menu.hjson</code> entry, the system automatically uses <ahref="/core/standard_menu.js">standard_menu.js</a>.</p>
<h2id="creating-a-new-module">Creating a New Module</h2>
<p>At the highest level, to create a new custom menu or mod, inherit from <codeclass="language-plaintext highlighter-rouge">MenuModule</code> and expose it via the <codeclass="language-plaintext highlighter-rouge">getModule</code> exported method:</p>
<p>Next, override the appropriate methods to add some functionality! Below is an example fragment overriding just <codeclass="language-plaintext highlighter-rouge">initSequence()</code>:</p>
<p><imgclass="emoji"title=":bulb:"alt=":bulb:"src="https://github.githubassets.com/images/icons/emoji/unicode/1f4a1.png"height="20"width="20"> Remember that <em>all</em> menus within ENiGMA are created by inheriting from <codeclass="language-plaintext highlighter-rouge">MenuModule</code>. Take a look at existing examples such as <ahref="/core/wfc.js">WFC</a>, <ahref="/core/nua.js">NUA</a>, <ahref="/core/mrc.js">MRC</a> and more!</p>
<p>To register your module with the system, include a <codeclass="language-plaintext highlighter-rouge">moduleInfo</code> declaration in your exports. The following members are available:</p>
<td>Defines a reverse DNS style package name. Can be used in conjunction with the <codeclass="language-plaintext highlighter-rouge">getModDatabasePath()</code> call form <ahref="/core/database.js">database.js</a> to interact with a database specific to your module (See example below)</td>
<spanclass="na">desc</span><spanclass="p">:</span><spanclass="dl">'</span><spanclass="s1">...a super dope mod, duh.</span><spanclass="dl">'</span><spanclass="p">,</span>
<p>Custom mods often need their own data persistence. This can be acheived with <codeclass="language-plaintext highlighter-rouge">getModDatabsePath()</code> and your <codeclass="language-plaintext highlighter-rouge">moduleInfo</code>’s <codeclass="language-plaintext highlighter-rouge">packageName</code>.</p>
<p>Form handler methods specified by <codeclass="language-plaintext highlighter-rouge">@method:someName</code> in your <codeclass="language-plaintext highlighter-rouge">menu.hjson</code> entries map to those found in your module’s <codeclass="language-plaintext highlighter-rouge">menuMethods</code> object. That is, <codeclass="language-plaintext highlighter-rouge">this.menuMethods</code> and have the following signature <codeclass="language-plaintext highlighter-rouge">(formData, extraArgs, cb)</code>. For example, consider the following <codeclass="language-plaintext highlighter-rouge">menu.hjson</code> fragment:</p>
<p><imgsrc="/enigma-bbs/assets/images/basic_menu_lifecycle.png"alt="Basic Menu Lifecycle"></p>
<p>Methods indicated above with <codeclass="language-plaintext highlighter-rouge">()</code> in their name such as <codeclass="language-plaintext highlighter-rouge">enter()</code> are overridable when inheriting form <codeclass="language-plaintext highlighter-rouge">MenuModule</code>.</p>
<codeclass="language-plaintext highlighter-rouge">enter()</code> is the first to be called. There is no callback. The default implementation is to simply call <codeclass="language-plaintext highlighter-rouge">this.initSequence()</code>.</li>
<li>
<codeclass="language-plaintext highlighter-rouge">displayQueuedInterruptions(callback)</code> is called, and if interruptions are allowed for this menu, any that may be queued will be displayed first.</li>
<li>
<codeclass="language-plaintext highlighter-rouge">beforeArt(callback)</code> is called before any art is displayed. The default implementation will set emulated baud rate, and clear the screen if either are requested by the menu’s <codeclass="language-plaintext highlighter-rouge">config</code> block.</li>
<li>
<codeclass="language-plaintext highlighter-rouge">mciReady(mciData, callback)</code> is called when art is loaded and MCI codes are initialized. The default implementation of a custom <codeclass="language-plaintext highlighter-rouge">MenuModule</code> simply continues. See also <ahref="#standardmcireadyhandlermcidata-callback">standardMCIReadyHandler</a>.</li>
<p>Many helper methods exist and are available to code inheriting from <codeclass="language-plaintext highlighter-rouge">MenuModule</code>. Below are some examples. Poke around at <ahref="../../../core/menu_module.js">menu_module.js</a> to discover more!</p>
<p>Display an asset by <codeclass="language-plaintext highlighter-rouge">name</code> or by supplying an <codeclass="language-plaintext highlighter-rouge">Buffer</code>.
<codeclass="language-plaintext highlighter-rouge">options</code> is an optional Object with any of the following properties:</p>
<ul>
<li>
<codeclass="language-plaintext highlighter-rouge">clearScreen</code> (Boolean): Should the screen be cleared first?</li>
<li>
<codeclass="language-plaintext highlighter-rouge">encoding</code> (String): Encoding of <codeclass="language-plaintext highlighter-rouge">Buffer</code> if used. Defaults to <codeclass="language-plaintext highlighter-rouge">cp437</code>.</li>
<li>
<codeclass="language-plaintext highlighter-rouge">font</code> (String): SyncTERM style font to use.</li>
<li>
<codeclass="language-plaintext highlighter-rouge">trailingLF</code> (Boolean): Should a trailing LF be allowed?</li>
<li>
<codeclass="language-plaintext highlighter-rouge">startRow</code> (Number): Row in which to start drawing at</li>
<p>Prepares the menu’s View Controller for a form of <codeclass="language-plaintext highlighter-rouge">name</code> and <codeclass="language-plaintext highlighter-rouge">formId</code> using the supplied <codeclass="language-plaintext highlighter-rouge">mciMap</code>. <codeclass="language-plaintext highlighter-rouge">callback</code> has the following siguature: <codeclass="language-plaintext highlighter-rouge">(err, viewController, created)</code> where <codeclass="language-plaintext highlighter-rouge">created</code> is <codeclass="language-plaintext highlighter-rouge">true</code> if a new View Controller was made.</p>
<p>The following methods take a single input to specify style, defaulting to <codeclass="language-plaintext highlighter-rouge">short</code>. If your menu or theme <codeclass="language-plaintext highlighter-rouge">config</code> block specifies a cooresponding value such as <codeclass="language-plaintext highlighter-rouge">dateFormat</code> or <codeclass="language-plaintext highlighter-rouge">dateTimeFormat</code>, that value will be used, else standard fallbacks apply:</p>
<p>Where <codeclass="language-plaintext highlighter-rouge">mciData</code> is a Object mapping <ahref="/enigma-bbs/art/mci.html">MCI codes</a> such as <codeclass="language-plaintext highlighter-rouge">TL2</code> to their properties:</p>
<codeclass="language-plaintext highlighter-rouge">focusSGR</code> (Only present if art contained both, ie: <codeclass="language-plaintext highlighter-rouge">TL2^[0;mTL2</code>)</li>
<li>
<codeclass="language-plaintext highlighter-rouge">position</code> (Array of Number): Position in [Row, Column] order</li>
<li>
<codeclass="language-plaintext highlighter-rouge">args</code> (Array): Any arguments to the MCI code</li>
<li>
<codeclass="language-plaintext highlighter-rouge">code</code> (String): The code itself, such as <codeclass="language-plaintext highlighter-rouge">TL</code>
</li>
<li>
<codeclass="language-plaintext highlighter-rouge">id</code> (Number): The MCI code’s ID such as <codeclass="language-plaintext highlighter-rouge">1</code>
<p><imgclass="emoji"title=":information_source:"alt=":information_source:"src="https://github.githubassets.com/images/icons/emoji/unicode/2139.png"height="20"width="20"> Search the code for the above methods to see how they are used in the base system!</p>
<p>Most mods will also derive from <codeclass="language-plaintext highlighter-rouge">MenuModule</code>. Some things to be aware of:</p>
<ul>
<li>Custom mods that bring in their own dependencies must also include their own <codeclass="language-plaintext highlighter-rouge">package.json</code> and other Node requirements</li>
<li>Be sure to use <codeclass="language-plaintext highlighter-rouge">packageName</code> and <codeclass="language-plaintext highlighter-rouge">getModDatabasePath()</code> for any (database) peristence needs.</li>
<li>Custom mods in <codeclass="language-plaintext highlighter-rouge">mods/the_mod_name/</code> and the <codeclass="language-plaintext highlighter-rouge">MenuModule</code> entry point must be within a file of the same name: <codeclass="language-plaintext highlighter-rouge">mods/the_mod_name/the_mod_name.js</code>
</li>
<li>To import ENiGMA modules <codeclass="language-plaintext highlighter-rouge">require()</code> from <codeclass="language-plaintext highlighter-rouge">../../core/</code>