The MVP pattern in Savvy - nth-iteration/savvy GitHub Wiki

Savvy apps follow the MVP pattern: made up of models, views and presenters.

The Wikipedia description of the MVP pattern is:

  • The model is an interface defining the data to be displayed or otherwise acted upon in the user interface.
  • The view is a passive interface that displays data (the model) and routes user commands (events) to the presenter to act upon that data.
  • The presenter acts upon the model and the view. It retrieves data from repositories (the model), and formats it for display in the view.

In Savvy, models are typically JSON objects. Views are composed of HTML partials and CSS style sheets (including Sass or Less). Presenters are scripts associated with a View and with access to its Model. In Savvy, Presenters may be written in JavaScript, CoffeeScript, TypeScript or C/C++.

Views

Views are central to every Savvy application. Savvy supports four kinds of views:

  • The global view (i.e. the HTML document body)
  • Cards
  • Header
  • Footer

Views are composed from any number of HTML partials and style sheets. In addition to CSS, Savvy supports style sheets written in Sass and Less also.

The global view is defined by HTML and CSS declared in config.xml as a child of the <savvy:deck> tags. Card, header and footer views are defined by HTML and CSS declared as children of <card>, <header> and <footer> tags respectively.

All style sheets in Savvy are scoped to the View, so for example, the same selector can be styled independently in different Views. Style for the global view will cascade down through all Views.

Savvy extends CSS with a vendor at-rule that selects the View:

@-savvy-this {
  /* this view */
}

In the global view, this will select the HTML document body. In other view it will select the card, header or footer.

Presenters

Each View in a Savvy application, including the global view, can have any number of associated Presenter scripts to act upon it. As with Views, Savvy Presenters are declared in config.xml either as a child of the <savvy:deck> tag (global) or as a child of <card>, <header> and <footer>.

Global Presenter code is executed against the JavaScript window object and are accessibly by all Presenter code. All other Presenter code is executed against a View and is executed in its own closure, meaning it is possible to have variables and functions of the same name in different scripts without conflict.

In all views, the JavaScript this object refers to the View. In the case of the global view, this is the JavaScript window object. In the case of all other Views it is the HTML DOM object containing that View.

Models

Ordinarily, JSON objects in Savvy apps are retrieved using HTTP requests from Presenter code.

However, JSON models can also be defined decoratively in the project's config.xml. These files will be automatically parsed and initialised to a given object when the application starts.

JSON files are linked using <json> nodes. A <json> node must have a target="..." attribute. This will be the path in dot notation to the JavaScript object to be initialised with the data.

If the <json> node is a child of the <savvy:deck> node (i.e. in the global position) then the data will be initialised on the JavaScript window object and will be available to all Presenters. If the <json> node is a child of a <card> (i.e. in the View position) then it will be initialised to a descendent of the View and will only be available to that View's Presenters.

For example, the following app.xml include two JSON files:

<savvy:deck>
  <json target="app.config">data/config.json</json>

  <card>
    <json target="user.data">http://api.example.com/rest/user/data</json>
  </card>

  ...

</savvy:deck>

Data from http://api.example.com/rest/user/data will be initialsed to a View-level object to that View's as this.user.data. The JSON file at data/config.json will be initialised globally and accessible by all scripts as app.config.

⚠️ **GitHub.com Fallback** ⚠️