Library for manipulating text ranges and selections, and assorted other programs that use that
bililiteRange.evim.js puts all of the other projects together. It creates a text editor from an element, using 
bililiteRange.ex.js commands
and using my toolbar project to create buttons, and my status
project to display messages and errors.
<div id=toolbar></div>
<textarea id=editor></textarea>
<div id=statusbar></div>
or
<div id=toolbar></div>
<pre contenteditable id=editor></pre>
<div id=statusbar></div>
rng.evim(document.getElementById('toolbar'), document.getElementById('statusbar'));
The first argument to evim is the element to contain the toolbar, and the second is the element to contain the message line and 
the input element for ex commands.
An editor with live Markdown conversion and some silly toolbar buttons and key mappings.
It includes a number of key mappings that are based on VIM, but that I found more useful.
All commands start with ctrl-o (like evim).
There are really only four commands:
ctrl-o : allows entry of any ex command. To accomodate my fat fingers, ctrl-o ;, ctrl-o ctrl-: and ctrl-o ctrl-; also bring up the command entry box.ctrl-o [fF] any-character Finds the next (for f) or previous (for F) occurence of the character. Works for printable characters
only, not space, tab or newline.ctrl-o [verb] [object] uses bililiteRange find to select “objects”.ctrl-o j joins lines.Possible values for verb include:
range.bounds('to', object, true).bounds('endbounds')t: go to the end of the current object. Mnemonic: “to”. Uses range.bounds('to', object, false).bounds('endbounds')b: go to the beginning of the current object. Mnemonic: “back”. Uses range.bounds('from', object, false).bounds('startbounds')B: go to the end of the previous object. Mnemonic: “really back”. Uses range.bounds('from', object, true).bounds('startbounds')i: select the entire current object (but not the separators). Mnemonic: “inner”. Uses range.bounds('whole', object, false)a: select the entire current object and its separators (for some objects, only the ending separators). Mnemonic: “all”. Uses 
range.bounds('whole', object, true); see that for which separators are selectedPossible values for object include (see the documentation for the definitions of these objects):
w: wordW: bigwords: sentencep: paragraph[: section(: parentheses': single-quote delimited quote": double-quote delimited quote<: angle-bracket delimited strings (uses rng.bounds('to', [/</, />/])When evim is called, rng.data.global and rng.data.autoindent are set to true. A listener
for map events is set up (see below) to create buttons and key mappings, and
rng.ex('source .exrc') is executed. So rng.data.reader should be set appropriately 
before calling $.fn.ex. For example, with the default reader on localStorage, you could do:
localStorage.setItem('.exrc', `
	file untitled
	set magic off
	map ^s write
	map ^b sendkeys "<strong>{selection}{mark}</strong>"
	map! Save command=write observe=savestatus
`);
evim allows for two kinds of map: map creates key mappings, and map! creates toolbar buttons. The ex 
command map triggers a map event with a left hand side and a right hand side (they are separated by the first space; use
quotes to include spaces in the left hand side.
For key mappings, the left hand side is the key descriptor to pass to the keydown handler, using my keymap
 project. The right hand side is the ex command to execute with the current selection as the default address.
So, in the .exrc above, ctrl-S is mapped to range.ex('%%write') (the %% address means the current selection).
control-B is mapped to a sendkeys command to surround the selection with the <strong> tag.
To map multiple keys, put the left hand side in quotes:
rng.ex('map "^o j" join');
For buttons, the left hand side is the name of the button. There are two syntaxes for the right hand side. The simple one is just the command:
rng.ex('map! Hello append Hello');
This does:
toolbar.button(lefthandside, righthandside); // in this case, toolbar.button('Hello', 'append Hello'); 
The complex syntax is in the form: command="command string" title="Tooltip title" observe="attribute to observe" (in any order, and all but command are optional).
This does:
button = toolbar.button(lefthandside, command, title);
if (observe) toolbar.observerElement(button, observe);
So buttons can be set to observe changes in the element (remembering that monitored bililiteRange data changes attributes named, for instance data-foo). The button will
then get a class equal to the value of the attribute of the range element named observe.
So
rng.ex('map! Save command=write observe=data-savestatus' title="Save the text to the current file");`
will do:
button = toolbar.button('Save', 'write', 'Save the text to the current file');
toolbar.observerElement(button, 'data-savestatus');
and the savestatus option is set to dirty when the text is edited and clean when it is saved, so the class of the button will change and you can use CSS to
style it appropriately.
See the documentation for toolbar for the details about toolbars and buttons.