Turn yoru browser into a terminal. WebOnion is a fully extensible SDK for building powerful browser based applications, with a CLI interface.
- Help manager that auto generates a help table for your application
- Commands history navigation like in real terminals
- Built in get input from user feature
- Various tools to deal with the UI
npm i web-onion
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
import { WebOnionSDK } from 'web-onion/dist/web-onion';
const WO = new WebOnionSDK();
// make sure that the DOM is ready
$(document).ready(() => WO.initialize());
Build your bundle and serve your application. You should see the WebOnion's interface.
WebOnion is meant to be an SDK for building applications that runs on commands. To build your application, you will use the WebOnionSDK
object. This object exposes a method called addConfigurationsToDispatcher()
.
This method takes one parameter which is an array of WODispatcherConfiguration
objects.
interface WODispatcherConfiguration {
desc: string;
flags?: string[];
command: string;
aliases?: string[];
action: (flags: string[]) => void;
}
This is the building block of your application.
- command: The full name of your command. For example
list
- desc: The description for this command. This field will be used when generating the help for the user. For example
Lists all the folders in the directoy
- flags: An array of strings with all the possible flags. For example:
['files', 'folders']
- aliases: An array of strings with all the aliases. For example:
['l', 'll', 'ls']
- action: A function that takes one parameter. This parameter will be the flags passed by the user.
Inside the action you can build your command logic, let's see a quick example.
We will create a command called test-me
. We will provide one alias tm
and three flags ['f1', 'f2', 'f3']
.
In the configuration, three properties are required.
- command
- action
- desc
Note that you declare the flags normally, while the user will have to use them with the specified notation, which by default is a double dash: --flag-name
.
import {WebOnionSDK} from 'web-onion/dist/web-onion';
const WO = new WebOnionSDK();
WO.addConfigurationsToDispatcher([
{
command: 'list',
flags: [
{
flag: 'f1',
desc: 'Flag one desc'
},
{
flag: 'f2',
desc: 'Flag two desc'
},
{
flag: 'f3',
desc: 'Flag three desc'
}
],
aliases: ['l', 'll', 'ls'],
desc: 'My first awesome command',
action: (flags: WOFlag[]) => {
if (!flags.length) {
alert('Command fired test-me without any flag');
return;
}
if (flags.find(f => f.flag === 'f1')) {
alert('Fired command test-me with flag --f1');
return;
}
if (flags.find(f => f.flag === 'f2')) {
alert('Fired command test-me with flag --f2');
return;
}
if (flags.find(f => f.flag === 'f3')) {
alert('Fired command test-me with flag --f3');
return;
}
flags.forEach(f => {
if (f.flag.split(':').length && f.flag.split(':')[1] && f.flag.split(':')[1].split('=')[0] === 'value') {
const val = f.flag.split(':').length && f.flag.split(':')[1].split('=')[1];
alert('Fired command test-me with flag --f3 and with value: ' + val);
return;
}
alert('Unknown flag for this command');
});
}
}
]);
$(document).ready(() => WO.initialize());
While the first four statements are pretty simple to understand, the last one can be a bit tricky. But it's not that complex once you get what it does.
Note that you can also run the same command using the given aliases.
Suppose to have this command list --f3:value=33
The last statement:
- splits each flag by the
:
character, obtaining['f3', 'value=33']
- takes the second value in the array:
value=33
- splits the value by the
=
character, obtaining['value', '33']
- takes the second value in the array. The value passed along with the flag
Using this trick you can build advanced and complex commands.
If you'd like to contribute with new features or bugfixes to this repo, there is already a demo project set up inside WebOnion.
Inside the src/demo
folder, you will find a demo.ts
file that includes the WebOnionSDK. It sets some demo configurations (these configurations may changes from release to release, since are the demo features, used for development.) and finally initializes the SDK.
If you take a look to the index.html
file, that includes JQuery, you will notice that also a demo-bundle.js
file is included too.
This is a webpack bundle. You don't need to setup any configuration, it's allready defined inside the webpack.config.js
file for you, however feel free to adjust it to your needs. Just don't include it inside the PR. (if any)
All you need to do, is to develop your demo environment starting from the src/demo/demo.ts
file. When you're ready, run this npm command:
npm run demo
This will give you a brand new dist
folder, just load the index.html
file inside that folder, and test your changes in the browser.
Adds the array of dispatcher configurations to the current configurations.
- @param:
{WODispatcherConfiguration[]} configurations
- @memberof:
WebOnionSDK
Initializes the SDK with the given configurations
- @memberof:
WebOnionSDK
Returns the loading screen timeout if set. Null will be returned otherwise
- @return:
{(number | null)}
- @memberof:
WebOnionSDK
Returns true if the input gets cleared after each ENTER press. False otherwise
- @return:
{boolean}
- @memberof:
WebOnionSDK
Returns true if the input focuses automatically when double clicking on the console. False otherwise
- @return:
{boolean}
- @memberof:
WebOnionSDK
Returns the array containing the dispatcher configurations
- @type:
{WODispatcherConfiguration[]}
- @memberof:
WebOnionSDK
Enables or disables the input autofocus when double-clicking on the console
- @param:
{boolean} value
- @memberof:
WebOnionSDK
Enables or disables the input field auto clear on each ENTER press
- @param:
{boolean} value
- @memberof:
WebOnionSDK
Sets the amount of time to wait before the legacy loading screen hides
- @param:
{number} value
- @memberof:
WebOnionSDK
WebOnion offers two libraries for handling the inputs and the outputs.
WOInput
handles all the interactions with the userWOOutput
handles all the output related operations
We access these libraries from the WebOnionSDK
object:
import {WebOnionSDK} from 'web-onion/dist/web-onion';
const WO = new WebOnionSDK();
WO.out_lib // WOOut library
WO.input_lib // WOInput library
Shows the legacy loading screen
- @memberof:
WOOutput
Prints a message to the console.
- @param:
{string}
message The text of the message - @param:
{WOSeverityEnum}
severity The severity of the message - @memberof:
WOOutput
Clears the console from the content
- @memberof:
WOOutput
Prints a message styled as title according to the current style in use
- @param:
{string} text
- @memberof:
WOOutput
Prints a message styled as title, surrounded with borders according to the current style in use
- @param:
{string} text
- @param:
{boolean} full_width=true
- @memberof:
WOOutput
Prints a list of key value pairs.
- @param:
{{ key: string, value: string }[]} set
- @param:
{string} [space_char=' ']
- @memberof:
WOOutput
Clears the input field
- @memberof:
WOInput
Focuses the cursor in the input field
- @memberof:
WOInput
Prompts the user with a question and takes a callback that will be executed when the user continues by pressing ENTER and providing a value through the input-field.
- @param:
{string} message
- @param:
{WebOnionSDK} sdk
- @param:
{string} dataKey
- @param:
{() => void} callback
- @param:
{WOSeverityEnum} [severity=WOSeverityEnum.message]
- @memberof:
WOInput
This method is a powerful tool that you can use to interact with the user. Besides the message, the sdk and the callback function parameters, it takes a dataKey
parameter. A string, which will be the identifier used by WebOnion to store the user's answer to the message prompted. This value gets stored in the browser's session storage prefixed by @wo-user-data-
and followed by the dataKey
value.
The same library exposes a method to retrieve the data stored by the prompt, and it can be used anytime to retrieve values stored previously. This method is called getInputData()
Gets the input data saved previously from the storage. If the given dataKey matches one identifier in the storage, the value will be returned. Otherwise null will be returned
- @param:
{string} dataKey
- @returns:
{(string | null)}
- @memberof:
WOInput
Prints a table that illustrates all the registered commands. With the respective description, aliases, and flags for each command.
- @param:
{WebOnionSDK} sdk
- @memberof:
WOHelpManager
This class exposes various methods to handle DOM mutations. Its just a wrapper over JQuery. It was created to organize all DOM mutations into a single place.
Appends the given element or string to the desired HTML element. The third parameter is optional, if set to true, it will append the given element to the last match of the selector element.
- @param:
{string} to
- @param:
{HTMLElement | string} element
- @param:
{boolean?} appendToLastMatch
- @memberof:
WORenderer
Sets the value to the given element (used with inputs)
- @param:
{string} to
- @param:
{any} newVal
- @memberof:
WORenderer
Returns the value from the element (used with inputs)
- @param:
{string} of
- @returns:
{(string | undefined)}
- @memberof:
WORenderer
Sets the focus on the element (used with inputs)
- @param:
{string} to
- @memberof:
WORenderer
Returns the HTML element that matches the selector. Undefined otherwise
The second parameter is optional, if the selector finds multiple matches, it will return the desired match.
Undefined is returned if the match cannot be found, or the whichOneIfMultiple
has an illegal index.
- @param:
{string} whichElement
- @param:
{number?} whichOneIfMultiple
- @returns:
{(HTMLElement | undefined)}
- @memberof:
WORenderer
Takes an array of WOCssRuleSet
and applies the rules on the desired element.
- @param:
{string} to
- @param:
{WOCssRuleSet[]} cssRulesSet
- @memberof:
WORenderer
Starts a listener on the given element for a keypress event. When the user presses the keycode to catch, the callback will be executed. The last optional parameter tells to the method to remove the listener after the callback has been executed.
- @param:
{string} element
- @param:
{number} keyCodeToCatch
- @param:
{() => void} callback
- @param:
{boolean = true} disposeListenerAfterCallbackExec
- @memberof:
WORenderer
Starts a listener for double clicks on the given element. When the double click is catched, the callback is executed.
- @param:
{string} element
- @param:
{() => void} callback
- @memberof:
WORenderer
Returns true or false wheter the element has or not the given class.
- @param:
{string} element
- @param:
{string} className
- @returns:
{boolean}
- @memberof:
WORenderer
Adds the given class to the desired element
- @param:
{string} to
- @param:
{string} className
- @memberof:
WORenderer
Removes the given class from the desired element
- @param:
{string} element
- @param:
{string} className
- @memberof:
WORenderer
Removes the entire element from the DOM
- @param:
{string} element
- @memberof:
WORenderer
Operates setting the given element on the ::after
of the selector used.
- @param:
{string} element
- @param:
{HTMLElement | string} elementToSet
- @memberof:
WORenderer
Scrolls to the top of the given element with the given scroll amount.
- @param:
{string} onWhichElement
- @param:
{number} scrollAmount
- @memberof:
WORenderer
Flushes the given element
- @param:
{string} whichElement
- @memberof:
WORenderer
interface WOCommandSet {
command: string | null;
flags: string[] | null;
}
interface WOSDKConfiguration {
dispatcher: WODispatcherConfiguration[];
input_field: {
clear_after_submit: boolean
};
general: {
theme: string,
loading_screen_time?: number
}
}
interface WODispatcherConfiguration {
command: string;
aliases?: string[];
flags?: string[];
action: (flags: string[]) => void
}
interface WOFlag {
flag: string;
desc: string;
}
interface WOCssRuleSet {
rule: string;
value: string;
}
The severity types of the messages printed out by the WOOut
and WOIn
libraries.
enum WOSeverityEnum {
message = 0,
error = 1,
warning = 2,
info = 3
}
There will be a getter and a setter, along with a new entry in the main configuration object that will allow you to change the console's theme. Right now is fixed to Matrix.css
It will be bossible to print out subtitles along with titles and boxed titles
It will be added a set of methods to this library that will handle complex outputs, like tables, images, special data presentation layouts and so on.
There will be a library that will handle the autcompletition process for the current commands set
If you like this project please help me with your feedback. Found a bug? Want a feature? Want some help? Feel free to open a Issue on GitHub.
We use SemVer for versioning.
This project is licensed under the MIT License - see the LICENSE.md file for details