web client, also applied in electron and webview based desktop app.
Code was splited in layers, and communicate by events and methods (on vue $ref
instance).
Each Layer produces an individual dist file, so they can be used seperately.
- View Layer: render views fro user state / note list / background tasks / note editor / note preview etc.
- Controller Layer: hold the global state, work with Model Layer and UI layer.
- Model Layer: local cache / data storage / network io etc. May be different in different platforms, but try to keep the same API as much as possible.
- SDK for TooNote API: data fetch / post for TooNote API.
The final WebClient for TooNote will be built in different combines. for example:
- Editor Version: Just the Editor in View Layer, plus a little logic code to open/save files. No storage or note management included.
- Lite Version: View Layer + Controller Layer + Model Layer (for local usage), No need to connect the server, No login, No data sync.
- Full Version: View Layer + Controller Layer + Model Layer + TooNote SDK, the full functional TooNote version, data stores in remote server of TooNote.
The UI includes the followings:
Sidebar
UserInfo
show information of current login user.NoteTree
show the index of a notebook.
Editor
the markdown editor.Preview
preview of current content in editor.
The interface of View Layer is an instance of WebClientView
, includes the following members:
app
the main Vue app instance, it will emit events and provide several methods to interact with external world. You should call$mount()
method to mount the app to the container DOM element in page.setData()
a method to inject data for each UI part.
The state of view is totally decided by the data it receives. In order to inject the data from outside world, you shoud call setData()
method of View Layer.
const userInfo = {
name: 'TooBug',
avatarUrl: 'https://avatars3.githubusercontent.com/u/1243593?s=100&v=4',
labels: ['SVIP'],
}
webClientView.setData('userInfo', userInfo);
The value of data should be a plain object. You can call the method any times as you wish, View Layer will respond to the data change, and show the latest UI.
But, for better performance, you should not override the original data object (userInfo
in this example), in any case, you should just update the value of a member. (for example, userInfo.name = 'TooooBug'
.)
Full list of data name and structure:
userInfo
used byUserInfo
componentname
user nameavatarUrl
url of user avatarlabels
an array of labels
editor
used byEditor
component andPreview
componentcontent
the content (in markdown)
notebook
current notebook, used byNoteTree
componenttitle
title of notebookcategories
an array of categories in notebook{category}
the element of the array above (this key not exist){key}
the key of above object property means the category name, for examplecategory1
{value}
an array of notes.{note}
the element of the array above (this key not exist)id
note idtitle
note title
An example of notebook:
{
title: 'notebook1',
categories: {
'category1': [{
id: '1',
title: 'note1'
}, {
id: '2',
title: 'note2'
}],
'category2': [{
id: '3',
title: 'note3'
}, {
id: '4',
title: 'note4'
}],
}
}
Events are emitted when user interact with the UI. Each event follows the following format:
- event name:
prefix.eventName
the prefix will be the module. Modules may not map to the UI parts. - event data: in an object.
Full list of events:
note
prefix, means note related eventsnote.new
create a new notedata
event datacontext
type
context type,category
|note
id
category id or note id
from
the source of event, value can bemenu
|noteTree
|shortcut
note.delete
delete a notedata
event dataid
noteId
note.rename
note.move
note.switchActive
switch current active notedata
event dataid
noteId
category
prefix, means category related eventsnotebook
prefix, means notebook related eventseditor
prefix, means editor related eventseditor.change
content changededitor.scroll
editor view scrolled
preview
prefix, means preview related eventspreview.linkClick
user clicked the link in preview
user
prefix, means user related eventsuser.login
loginuser.logout
logout
In most cases, you should inject an data item to control the behavior of View Layer. But in some cases, call a method is an easier way to go.
preivew.scrollTo(y)
scroll preview section toy
px.
Hold the global state, work with Model Layer and UI layer. Since it's called WebClient, it will work like tranditional web application: just hold little data in client side. Most user actions will trigger network communications.
local cache / data storage / network io etc. May be different in different platforms, but try to keep the same API as much as possible.
data fetch / post for TooNote API.