Welcome to wehjit 0.1.0!

wehjit is a Python library for building XHTML widgets for web applications and web pages. It encapusaltes the XML (a Genshi template), CSS, and JavaScript for each widget into a plugin. A tutorial plus full API documentation is available here.

wehjit has some unique features in how it handless CSS. When you create an application (a collection of pages), wehjit will render a single CSS file containing the styles for all the widget plugins that your application uses. Each widget plugin typically provides some default style, but you can override any of this default style via a simple JSON-encoded configuration file. Even with overrides, a single CSS file is rendered.

The details are best explained with an example. The table below contains the exact style information used by these demo pages. The left column contains the total style definition in JavaScript Object Notation (JSON). The right column contains the same style information rendered as CSS.

Style config dumped to JSON Rendered CSS
{
  "styles": {
    "": {
      "body": {
        "background-color": "%(colorbg)s", 
        "color": "%(color)s", 
        "font-family": "%(font_family)s", 
        "font-size": "%(font_size)s"
      }, 
      "code": {
        "background-color": "%(colorbg_code)s", 
        "padding": "1px"
      }, 
      "code, pre": {
        "font-family": "monospace", 
        "font-size": "%(font_size_mono)s"
      }, 
      "input, select, option, textarea, button": {
        "font-family": "monospace", 
        "font-size": "%(font_size_mono)s", 
        "line-height": "%(height_bar)s"
      }, 
      "label.associate": {
        "-moz-appearance": "button", 
        "display": "inline-block", 
        "padding": "0.1em 0.2em"
      }
    }, 
    "Actions": {
      "": {
        "height": "100%%", 
        "text-align": "right"
      }, 
      "> button": {
        "margin": "0 0.5em"
      }, 
      "> label": {
        "margin": "0 0.5em"
      }
    }, 
    "FieldTable": {
      "": {
        "border-collapse": "collapse", 
        "empty-cells": "show", 
        "width": "100%%"
      }, 
      "td": {
        "padding": "2px", 
        "text-align": "left", 
        "vertical-align": "top", 
        "width": "40%%"
      }, 
      "td.error": {
        "color": "#e02", 
        "width": "38%%"
      }, 
      "th": {
        "font-weight": "normal", 
        "line-height": "%(height_bar)s", 
        "padding": "2px", 
        "text-align": "right", 
        "vertical-align": "top", 
        "width": "22%%"
      }, 
      "tr.error": {
        "background-color": "#ddd"
      }, 
      "tr.required label": {
        "font-weight": "bold"
      }
    }, 
    "Fieldset": {
      "": {
        "border": "2px solid %(colorborder_fieldset)s", 
        "margin": "2em 0", 
        "width": "%(width_content)s"
      }, 
      "> legend": {
        "background-color": "%(colorbg_legend)s", 
        "border": "inherit", 
        "color": "%(color_legend)s", 
        "font-weight": "bold", 
        "letter-spacing": "0.15em", 
        "padding": "0 0.5em", 
        "word-spacing": "0.25em"
      }
    }, 
    "H1": {
      "": {
        "font-size": "1.5em", 
        "margin": "0.25em 0"
      }
    }, 
    "HighlighterLexers": {
      "": {
        "font-family": "monospace", 
        "font-size": "%(font_size_mono)s"
      }, 
      "h2": {
        "font-family": "monospace", 
        "font-weight": "normal", 
        "margin-bottom": "0", 
        "margin-top": "1.5em"
      }, 
      "h2 a": {
        "color": "inherit", 
        "text-decoration": "none"
      }, 
      "h2 a:hover": {
        "background-color": "#eee"
      }, 
      "h2:target": {
        "color": "#e02"
      }, 
      "pre": {
        "margin": "0"
      }, 
      "td": {
        "padding": "0.5em 1em", 
        "vertical-align": "top"
      }, 
      "th": {
        "padding": "0.5em 1em", 
        "text-align": "right", 
        "vertical-align": "top"
      }, 
      "tr": {
        "background-color": "#eee"
      }, 
      "tr.even": {
        "background-color": "#ddd"
      }
    }, 
    "Menu": {
      "": {
        "background": "%(colorbg_bar)s", 
        "color": "%(color_bar)s", 
        "cursor": "default", 
        "margin": "0", 
        "padding": "0"
      }, 
      ":hover": {
        "background-color": "%(colorbg_hover_menu)s"
      }, 
      ":hover > ul": {
        "display": "block"
      }, 
      "> span": {
        "color": "%(color_bar)s", 
        "display": "block", 
        "line-height": "%(height_bar)s", 
        "padding": "%(padding_menu)s", 
        "text-decoration": "none", 
        "white-space": "nowrap"
      }, 
      "> ul": {
        "background-color": "%(colorbg_bar)s", 
        "border-color": "%(colorborder_menu)s", 
        "border-style": "solid", 
        "border-width": "1px", 
        "display": "none", 
        "list-style-type": "none", 
        "margin": "0", 
        "padding": "0", 
        "position": "fixed", 
        "z-index": "60"
      }
    }, 
    "MenuItem": {
      "": {
        "background": "%(colorbg_bar)s", 
        "color": "%(color_bar)s", 
        "cursor": "default", 
        "margin": "0", 
        "padding": "0"
      }, 
      ":hover > a": {
        "background": "%(colorbg_hover_menu)s"
      }, 
      "a": {
        "color": "%(color_bar)s", 
        "display": "block", 
        "line-height": "%(height_bar)s", 
        "padding": "%(padding_menu)s", 
        "text-decoration": "none", 
        "white-space": "nowrap"
      }, 
      "a.target": {
        "background-color": "%(colorbg_target_menu)s"
      }
    }, 
    "MenuSet": {
      "": {
        "float": "left", 
        "list-style-type": "none", 
        "margin": "0", 
        "padding": "0"
      }, 
      "> li": {
        "float": "left"
      }
    }, 
    "PasswordRow": {
      "input": {
        "padding": "%(padding_input)s"
      }
    }, 
    "PluginDetails": {
      "": {
        "font-family": "monospace", 
        "font-size": "%(font_size_mono)s"
      }, 
      "h2": {
        "font-family": "monospace", 
        "font-weight": "normal", 
        "margin-bottom": "0", 
        "margin-top": "1.5em"
      }, 
      "h2 a": {
        "color": "inherit", 
        "text-decoration": "none"
      }, 
      "h2 a:hover": {
        "background-color": "#eee"
      }, 
      "h2:target": {
        "color": "#e02"
      }, 
      "pre": {
        "margin": "0"
      }, 
      "td": {
        "padding": "0.5em 1em", 
        "vertical-align": "top"
      }, 
      "th": {
        "padding": "0.5em 1em", 
        "text-align": "right", 
        "vertical-align": "top"
      }, 
      "tr": {
        "background-color": "#eee"
      }, 
      "tr.even": {
        "background-color": "#ddd"
      }
    }, 
    "TextAreaRow": {
      "textarea": {
        "padding": "%(padding_input)s"
      }
    }, 
    "TextRow": {
      "input": {
        "padding": "%(padding_input)s"
      }
    }, 
    "TopBar": {
      "": {
        "background": "%(colorbg_bar)s", 
        "color": "%(color_bar)s", 
        "height": "%(height_bar)s", 
        "left": "0", 
        "line-height": "%(height_bar)s", 
        "position": "fixed", 
        "right": "0", 
        "top": "0", 
        "z-index": "50"
      }
    }, 
    "View": {
      "": {
        "bottom": "0", 
        "left": "0", 
        "overflow": "auto", 
        "padding": "0 1em", 
        "position": "fixed", 
        "right": "0", 
        "top": "%(height_bar)s"
      }
    }, 
    "Welcome": {
      "": {
        "width": "%(width_content)s"
      }, 
      "table": {
        "border-collapse": "separate", 
        "border-spacing": "2px"
      }, 
      "td": {
        "background-color": "#eee", 
        "padding": "0.5em", 
        "vertical-align": "top"
      }, 
      "th": {
        "background-color": "#ddd", 
        "padding": "0.5em"
      }
    }
  }, 
  "vars": {
    "color": "#000", 
    "color_bar": "#fff", 
    "color_legend": "#fff", 
    "colorbg": "#fff", 
    "colorbg_bar": "#446", 
    "colorbg_code": "#eee", 
    "colorbg_hover_menu": "#669", 
    "colorbg_legend": "#966", 
    "colorbg_target_menu": "#966", 
    "colorborder_fieldset": "#966", 
    "colorborder_menu": "#000", 
    "font_family": "sans-serif", 
    "font_size": "11pt", 
    "font_size_mono": "10pt", 
    "height_bar": "2em", 
    "padding_input": "2px", 
    "padding_menu": "0 0.5em", 
    "width_content": "50em"
  }
}
/*  ----  [GLOBAL]  ----  */
body {
    background-color: #fff;
    color: #000;
    font-family: sans-serif;
    font-size: 11pt;
}
code {
    background-color: #eee;
    padding: 1px;
}
code, pre {
    font-family: monospace;
    font-size: 10pt;
}
input, select, option, textarea, button {
    font-family: monospace;
    font-size: 10pt;
    line-height: 2em;
}
label.associate {
    -moz-appearance: button;
    display: inline-block;
    padding: 0.1em 0.2em;
}
/*  ----  Actions  ----  */
div.Actions {
    height: 100%;
    text-align: right;
}
div.Actions > button {
    margin: 0 0.5em;
}
div.Actions > label {
    margin: 0 0.5em;
}
/*  ----  FieldTable  ----  */
table.FieldTable {
    border-collapse: collapse;
    empty-cells: show;
    width: 100%;
}
table.FieldTable td {
    padding: 2px;
    text-align: left;
    vertical-align: top;
    width: 40%;
}
table.FieldTable td.error {
    color: #e02;
    width: 38%;
}
table.FieldTable th {
    font-weight: normal;
    line-height: 2em;
    padding: 2px;
    text-align: right;
    vertical-align: top;
    width: 22%;
}
table.FieldTable tr.error {
    background-color: #ddd;
}
table.FieldTable tr.required label {
    font-weight: bold;
}
/*  ----  Fieldset  ----  */
fieldset.Fieldset {
    border: 2px solid #966;
    margin: 2em 0;
    width: 50em;
}
fieldset.Fieldset > legend {
    background-color: #966;
    border: inherit;
    color: #fff;
    font-weight: bold;
    letter-spacing: 0.15em;
    padding: 0 0.5em;
    word-spacing: 0.25em;
}
/*  ----  H1  ----  */
h1.H1 {
    font-size: 1.5em;
    margin: 0.25em 0;
}
/*  ----  HighlighterLexers  ----  */
div.HighlighterLexers {
    font-family: monospace;
    font-size: 10pt;
}
div.HighlighterLexers h2 {
    font-family: monospace;
    font-weight: normal;
    margin-bottom: 0;
    margin-top: 1.5em;
}
div.HighlighterLexers h2 a {
    color: inherit;
    text-decoration: none;
}
div.HighlighterLexers h2 a:hover {
    background-color: #eee;
}
div.HighlighterLexers h2:target {
    color: #e02;
}
div.HighlighterLexers pre {
    margin: 0;
}
div.HighlighterLexers td {
    padding: 0.5em 1em;
    vertical-align: top;
}
div.HighlighterLexers th {
    padding: 0.5em 1em;
    text-align: right;
    vertical-align: top;
}
div.HighlighterLexers tr {
    background-color: #eee;
}
div.HighlighterLexers tr.even {
    background-color: #ddd;
}
/*  ----  Menu  ----  */
li.Menu {
    background: #446;
    color: #fff;
    cursor: default;
    margin: 0;
    padding: 0;
}
li.Menu:hover {
    background-color: #669;
}
li.Menu:hover > ul {
    display: block;
}
li.Menu > span {
    color: #fff;
    display: block;
    line-height: 2em;
    padding: 0 0.5em;
    text-decoration: none;
    white-space: nowrap;
}
li.Menu > ul {
    background-color: #446;
    border-color: #000;
    border-style: solid;
    border-width: 1px;
    display: none;
    list-style-type: none;
    margin: 0;
    padding: 0;
    position: fixed;
    z-index: 60;
}
/*  ----  MenuItem  ----  */
li.MenuItem {
    background: #446;
    color: #fff;
    cursor: default;
    margin: 0;
    padding: 0;
}
li.MenuItem:hover > a {
    background: #669;
}
li.MenuItem a {
    color: #fff;
    display: block;
    line-height: 2em;
    padding: 0 0.5em;
    text-decoration: none;
    white-space: nowrap;
}
li.MenuItem a.target {
    background-color: #966;
}
/*  ----  MenuSet  ----  */
ul.MenuSet {
    float: left;
    list-style-type: none;
    margin: 0;
    padding: 0;
}
ul.MenuSet > li {
    float: left;
}
/*  ----  PasswordRow  ----  */
tr.PasswordRow input {
    padding: 2px;
}
/*  ----  PluginDetails  ----  */
div.PluginDetails {
    font-family: monospace;
    font-size: 10pt;
}
div.PluginDetails h2 {
    font-family: monospace;
    font-weight: normal;
    margin-bottom: 0;
    margin-top: 1.5em;
}
div.PluginDetails h2 a {
    color: inherit;
    text-decoration: none;
}
div.PluginDetails h2 a:hover {
    background-color: #eee;
}
div.PluginDetails h2:target {
    color: #e02;
}
div.PluginDetails pre {
    margin: 0;
}
div.PluginDetails td {
    padding: 0.5em 1em;
    vertical-align: top;
}
div.PluginDetails th {
    padding: 0.5em 1em;
    text-align: right;
    vertical-align: top;
}
div.PluginDetails tr {
    background-color: #eee;
}
div.PluginDetails tr.even {
    background-color: #ddd;
}
/*  ----  TextAreaRow  ----  */
tr.TextAreaRow textarea {
    padding: 2px;
}
/*  ----  TextRow  ----  */
tr.TextRow input {
    padding: 2px;
}
/*  ----  TopBar  ----  */
div.TopBar {
    background: #446;
    color: #fff;
    height: 2em;
    left: 0;
    line-height: 2em;
    position: fixed;
    right: 0;
    top: 0;
    z-index: 50;
}
/*  ----  View  ----  */
div.View {
    bottom: 0;
    left: 0;
    overflow: auto;
    padding: 0 1em;
    position: fixed;
    right: 0;
    top: 2em;
}
/*  ----  Welcome  ----  */
div.Welcome {
    width: 50em;
}
div.Welcome table {
    border-collapse: separate;
    border-spacing: 2px;
}
div.Welcome td {
    background-color: #eee;
    padding: 0.5em;
    vertical-align: top;
}
div.Welcome th {
    background-color: #ddd;
    padding: 0.5em;
}