unify/unify — pull request #145 by stefankolb (2012-09-13 10:15:17+00:00)
Title: Reworked theming

Instead of having a tree-like structure for includes and styles for each appearance selector, there is now a flat list for each appearance selector. This makes extending and overwriting of style definitions much easier and much more reliable, because this way, we can make sure, that styles are applied in the correct order (meaning: First the styles from the root theme and then all styles from all derived themes, if there are any).

**Additional Features**
(some already introduced in earlier commits)
* Multiple inheritance: A theme can now have multiple parent themes
* Multiple includes: A style can now include multiple other styles

**Note**
Whenever a style is requested, the style is resolved in the following order (see examples below for details about includes and style functions):
1. All includes are processed recursively (i.e. if the included style has one or several includes, they are processed, too)
2. All style functions are executed

## Examples ##

### Single theme ###

Let's say we have a single theme called 'Base' with the following style definitions:

```javascript
// ...
'button': {
style: function(states) { // function1
return {
borderColor: 'black',
borderRadius: '3px',
broderStyle: 'solid',
borderWidth: '1px',
}
}
},

'button.blue': {
include: 'button',
style: function(states) { // function2
return {
backgroundColor: 'blue',
borderColor: 'blue'
}
}
}
// ...
```

After the theme was parsed, we end up with a style definition like this:

```javascript
// ...
'button': [
{
theme: 'Base',
key: 'button',
includes: [ ],
styles: [ function1 ]
}
],
'button.blue': [
{
theme: 'Base',
key: 'button.blue',
includes: [ 'button' ],
styles: [ function2 ]
}
],
//...
```

### Multiple themes ###

Let's say, we have a theme called 'Derived', which includes the 'Base' theme from above. In that theme, we have, among others, the following style definitions:

```javascript
// ...
'button.blue': {
include: 'button',
style: function(states) { // function3
return {
backgroundColor: 'darkblue',
borderColor: 'darkblue'
}
}
},

'button.blue.shadow': {
include: 'button.blue',
style: function(states) { // function4
return {
boxShadow: '1px 2px 2px black'
}
}
}

// ...
```

After the theme was parsed, we end up with a style definition like this:

```javascript
// ...
'button.blue': [
{
theme: 'Derived',
key: 'button.blue',
includes: [ 'button' ],
styles: [ function2, function3 ]
}
],
'button.blue.shadow': [
{
theme: 'Derived',
key: 'button.blue.shadow',
includes: [ 'button.blue' ],
styles: [ function4 ]
}
],
//...
```

The style definition for 'button.blue' in the 'Derived' theme would override the style definition for 'button.blue' in the 'Base' theme.

### Clear previous styles ###

Let's say you want to remove any previously applied styles, e.g. those from a base theme. You just need to provide an empty object for that.

```javascript
// Base theme
'button': {
style: function(states) {
return {
borderColor: 'black',
borderRadius: '3px',
broderStyle: 'solid',
borderWidth: '1px',
}
}
}

// Derived theme
'button': { } // <- would remove any styling previously applied
```