This frontend application serves the cozy-contacts browser app. It relies on the server views/index.jade
for its base markup and exported globales, which are relocated in the imports
module (use require('imports')
to get them).
You'll need a valid node.js/npm environment to develop the app. We use Brunch as build tool and bower for the dependencies so you want them installed on your system:
$ npm -g i brunch bower
Before trying to develop the front app, you need to load its dependencies:
npm i
bower install
NOTE: we currently use Bower as deps manager to avoid deps in the app repository. We'll replace it by npm node_modules packages when Brunch will be stable enough to use it for the vendor files.
You should be aware of the app libraries in use:
- Backbone is used for a quick and valid components architecture, like models
- Marionette is the framework used upon Backbone to have a more clever and easier way to deal with views (like layouts, regions, and views switching)
- BackboneProjections offers a lean way to keep context collections (like search filtering, etc) consistent over the whole app
- Backbone.ViewModel keeps logics externally to views rendering part, and gets contextual stores
- cozy-vcard is a cozy tailored lib to deal with vcard format parsing and generation
The app is organized in the following way:
app
├── assets # App static assets (like fonts from cozy-proxy)
├── collections # Collections. Can be root-ones (like contacts
│ ├── charindex.coffee # and tags) or projections over the last.
│ ├── contacts.coffee
│ ├── duplicates.coffee
│ ├── search.coffee
│ └── tags.coffee
├── lib
│ ├── behaviors # Behaviors are chunks of code used in
│ │ ├── confirm.coffee # composition for marionette Views.
│ │ ├── dialog.coffee # (NOTE: the behaviors are not specifics to
│ │ ├── dropdown.coffee # contacts and will be moved to cozy-ui soon)
│ │ ├── form.coffee
│ │ ├── index.coffee
│ │ ├── keyboard.coffee
│ │ ├── navigator.coffee
│ │ └── pickavatar.coffee
│ ├── regions # Regions extra-app top-classes
│ │ └── dialogs.coffee
│ ├── views # Views extra-app templates and top-classes
│ │ ├── templates
│ │ │ ├── base
│ │ │ │ ├── alert.jade
│ │ │ │ └── dialog.jade
│ │ │ └── confirm.jade
│ │ └── confirm.coffee
│ ├── contacts_listener.coffee # Listener are client-side realtime adapter
│ ├── i18n.coffee # Localization abstraction tool
│ └── tags_listener.coffee
├── locales
├── models # Root data models
│ ├── config.coffee
│ ├── contact.coffee
│ └── tag.coffee
├── routes # Default routes and subroutes
│ ├── contacts.coffee
│ ├── index.coffee
│ └── tags.coffee
├── styles
│ ├── app # App related styles and layouts
│ ├── base # Base styles using Cozy-ui as fondation
│ ├── components # Each components can use its own style
│ └── main.styl
├── views # Views components, including templates
│ ├── contacts # and models logics.
│ ├── duplicates # Each "top-component" (contacts, labels, etc)
│ ├── labels # as its dedicated group.
│ ├── models # Models are inherited from Backbone.ViewModel
│ │ ├── app.coffee # and contains internal conponents stores and
│ │ ├── contact.coffee # logics. They can be shared across components
│ │ ├── group.coffee # (such as AppViewModel).
│ │ └── merge.coffee
│ ├── settings
│ ├── templates # Templates use Jade as templating engine,
│ │ ├── contacts # and reflect views components dir structure.
│ │ │ └── components
│ │ ├── duplicates
│ │ ├── labels
│ │ ├── layouts
│ │ ├── settings
│ │ └── tools
│ ├── tools
│ └── app_layout.coffee # App layout childView switching part
├── application.coffee # Application boostraping
├── config.coffee # Const config
└── initialize.coffee # Env initialization
So, what happens when you request an URL in the front app ? Here is the step-by-step workflow:
- Environment is initialized (
initialize.coffee
):
- sets a color palette use in the app
- register behaviors for the app
- bind localization tool (Polyglot) to the browser context
- starts app
- Initialize the app (
application.coffee
)
- initialize the AppViewModel from the config model
- prepare the collections (roots and search projection) and app layout
- starts the router
- Then, when application is ready (
application.coffee
), it complete the following tasks:
- fetch contacts and tags from the server
- render the layout
- start the history stack
- Router (
routes/index
)starts in parallel and match the path to the relevant subroute. Note that frequenly, routes ensure the collections are properly fetched before dealing with actions. - Layout (
views/app_layout.coffee
) renders, starting its childViews (the drawer, the toolbar, the list) and starts the dialogs if needed - In parallel, each instanciated component gets or creates its ViewModel and render in the viewport
Now you've got a basic knowledge of how the app works. The main concepts are:
- There's only 2 collections (one for contacts, one for tags) stored into the app. It should not be more, as they represent the data. So all other collections are only projections of the last
- There's no more models as long as there's nothing more data to represent
- Some data may be more flexible when using internal Collections. It's in use for datapoints in contact models, as long as they are just a collection of a bunch of datapoints. They do not declares explicits models and collections, just use the Backbone defaults
- components should not call others components API, but instead trigger events. Components responsibles of actions will catch them (like ViewModels and their associated views) to react to those events
- the views should never do things by themselves
If you follow this principles, all things will cascade cleverly and smoothly through your app.
Now go to read the code ;).