-
Notifications
You must be signed in to change notification settings - Fork 0
Overview
A level is represented by rows of inline divs (cells) inside the #view
node,
it is created through the renderView
function. Each cell has an onclick listener,
which alters the cell or cells' textContent
and backgroundColor
attributes
based on the current properties of the mouseTool
object.
The mouseTool
holds two properties: tool
and char
. The tool
is an event
handler which first determines whether its associated action can be performed,
and if so, performs the action.
The lowest-level function responsible for editing a cell is applyEdit
, which
takes a cell and a character. Whenever a user edits a cell, the tool will
call applyEdit
and pass the mouseTool
's char
value to it. The cell's new
text content will be set to the char, and its corresponding background color
will be looked up in the PALETTE
constant.
The PALETTE
object holds every available character and associates a color
and a short description with it, for example:
'+': {color: 'rgb(255, 100, 100)', help: 'lava'}
Similarly, the TOOLS
array holds all of the available tool functions. It also
stores an icon name which will be assigned to the tool's selection button in the
UI.
Two tools are implemented: a brush
which simply edits a cell through applyEdit
and a fill
tool which implements a scanline flood fill algorithm.
A simple array-wrapping HistoryStack
class serves to store information about
edited cells. Each record in the stack
property of HistoryStack
is an object
which holds an array of cells altered by an action and a character value to which
they should be restored.
The reason for introducing a custom class was the need to be able to allow
interaction between a stack and a UI element through event handling.
Every time a method which alters the stack, such as pop
is called, a custom
historyupdate
event is dispatched to the document
, which handles it and alters
the state of undo and redo UI buttons accordingly.
To simplify moving through history states there are two instances of HistoryStack
:
past
and future
. Every time a user makes an alteration to the level, the
future
stack is emptied and a history record is pushed to the past
stack.
When undo
or redo
is called, a record is popped from a corresponding stack,
and the cells in it are looped through and restored to the previous state by
applyEdit
using the character in the record.
The opposite stack receives a new record that holds the same list of cells
and their prior textContent
.
When the past
grows too large, older records are removed by calling the drop
method.
Storing palette and tool values in objects, allows looping through them to easily
create as many corresponding UI buttons on the fly as needed. Creation of buttons
is abstracted by the createButton
function, while other UI elements are either
present in the initial HTML template (see index.html), or created dynamically
through simple DOM manipulation.
As there are only two mouse tools in this editor, and it's not likely that more
will be implemented, not to clutter the layout, undo and redo buttons are
attached to the same node, though their function is different from that of the
mouse tools.
Undo and redo buttons get enabled and disabled as the document
tracks the historyupdate
events.
Clicking this will append a span.dialog
element to the menu,
containing two <input>
fields and two buttons, dialogYes
and dialogNo
.
The former will attempt to call renderView
with the input as parameters, while
the latter will remove the <span>
from the document.
This will similarly create a <span>
element with the dialog class, but with
a single <textarea>
for user input. Clicking dialogYes
will first determine if
the string can be interpreted as a grid (i.e. consists of lines of equal length),
then call renderView
, with the calculated grid measurements and will loop through
the characters in the string, trying to call applyEdit
with the current character
and the corresponding cell. If a character is not present in PALETTE
, and an error
message will be displayed in the info
<textarea>
at the bottom of the toolbar.
Clicking the copy button will call a copyLevel
function, which will loop through
the cell divs and append their textContent
to an output string, additionally appending
a newline after every row. The following trick is used to hand out the string to
the user.
The info
's textContent
is set to the output string, then selected,
copied to clipboard and finally removed from the info
. Like this:
info.textContent = level;
info.select();
document.execCommand('Copy');
info.textContent = 'level copied to clipboard';
The user can then paste the string into their text editor to use with their program.
A <textarea>
where information about actions and UI elements appears. It was
initially used to display the level as a string, but as seen above it no longer
does that directly. The following css rules are used to hide the cursor, preserve
newlines for copying and prevent resizing:
.info {
resize: none;
white-space: pre-line;
color: transparent; /* text (and cursor as well) is now hidden */
text-shadow: 0 0 0 white; /* but a shadow with no offset is drawn for text*/
}
The icons are Google's material icons, currently displayed as an icon font and are
linked in the <head>
of index.html.