-
Notifications
You must be signed in to change notification settings - Fork 121
Home
- Home - You are here
- Glossary - List of terms and definitions.
- Utility - Guide to common data types and utility functions.
- Project Structure
- Understanding the Data Model
- Data Storage/Persistence
- Metaprogramming
- Schema Versions
- Mobile Testing
- Mobile Editing Mode
-
/src/App.css
- Styles -
/src/constants.js
- Constant values -
/src/globals.js
- Ugly global variables that should be refactored -
/src/action-creators
- Redux action creators -
/src/components
- React components -
/src/reducers
- Redux reducers -
/src/shortcuts
- Keyboard and gesture shortcuts -
/src/util
- Most application logic can be found in various utility functions
Although em is rendered as a hierarchy, the basic data structure is a graph rather than a tree. Edges connect thoughts and contexts. The main difference from a tree is that nodes may have multiple parents, or in em terminology, thoughts may appear in many contexts (just as contexts can contain many thoughts, thus a many-to-many relationship).
e.g. The thought with value 'x'
appears in contexts ['A', 'B']
and ['C']
:
- A
- B
- x
- B
- C
- x
The thought being edited is tracked by state.cursor
, which is a Path. There are infinitely many paths to a thought, since the context view allows jumping across the hierarchy and circular paths are allowed. Generally paths are converted into contexts to do anything useful.
Given the string value of a thought, you can retrieve a Thought object from the underlying thoughtIndex
using getThought
. This object contains a list of its contexts.
Given a context (e.g. ['A', 'B']
), you can retrieve its thoughts from the underlying contextIndex
using getThoughts
.
See Glossary and Utility for more details.
Thoughts are stored in the underlying objects thoughtIndex
and contextIndex
, which map hashed values to contexts and hashed contexts to values, respectively. These structures are stored in the following locations:
- state (Redux)
- local (indexedDB via localForage)
- remote (Firebase) [optional; if user is logged in]
The syncing logic is a bit ad hoc and in need of refactoring. Syncing is complex due to offline mode.
See: sync.js
Metaprogramming provides the ability to alter em's behavior from within em itself through dynamic thoughts. Dynamic thoughts begin with =
and are hidden unless showHiddenThoughts === true
(toggled in the toolbar). Generally a dynamic thought will affect its parent thought.
-
=hidden
The thought is only displayed whenshowHiddenThoughts === true
. -
=immovable
The thought cannot be moved. -
=label
Display alternative text, but continue using the real text when linking contexts. Hide the real text unless editing. -
=note
Display a note in smaller text underneath the thought. -
=options
Specify a list of allowable subthoughts. -
=readonly
The thought cannot be edited, moved, or extended. -
=uneditable
The thought cannot be edited. -
=unextendable
New subthoughts may not be added to the thought. -
=view
Controls how the thought and its subthoughts are displayed. Values:List
,Table
,Prose
.
User settings are stored as thoughts within __EM__/Settings/
. See INITIAL_SETTINGS
.
The version of the data schema is stored in schemaVersion
, allowing for systematic migrations.
See: SCHEMA_*
constants
Localhost can be tunneled to a public url for mobile testing purposes using ngrok. This is easy to set up but much slower than using the remote debugging functionality of browsers such as Safari.
To allow logins, the ngrok domain must be added to Firebase Authorized Domains.
ngrok http 3333
There is a state variable on mobile called editing
that is true
if there is an active browser selection. When the user closes their mobile keyboard, editing === false
. This allows the user to navigate from thought to thought without opening the keyboard. Thus setCursor
may be called without restoring the browser selection in order to prevent the keyboard from opening. To enter editing
mode, the user initiates a shortcut like newThought
or taps on the cursor thought.
You'll see places like https://github.com/cybersemics/em/blob/dev/src/action-creators/deleteEmptyThought.js#L79-L86 where only setCursor
is called instead of restoreSelection
if isMobile && !editing
in order to prevent the mobile keyboard from opening.