Welcome to wehjit 0.2.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": {
    "": {
      ".hide": {
        "display": "none !important"
      }, 
      ".numeric": {
        "text-align": "right"
      }, 
      "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.25em"
      }, 
      "input": {
        "border": "none", 
        "margin": "0 0.25em", 
        "padding": "%(padding_input)s"
      }, 
      "label": {
        "margin": "0 0.25em"
      }
    }, 
    "Dialog": {
      "": {
        "background-color": "#fff", 
        "bottom": "1em", 
        "left": "1em", 
        "position": "fixed", 
        "right": "1em", 
        "top": "1em", 
        "z-index": "100"
      }, 
      "div.bar": {
        "background": "%(colorbg_bar)s", 
        "color": "%(color_bar)s", 
        "height": "%(height_bar)s", 
        "left": "0", 
        "line-height": "%(height_bar)s", 
        "position": "absolute", 
        "right": "0", 
        "top": "0"
      }, 
      "div.bar button": {
        "margin": "0 0.5em"
      }, 
      "div.bar label": {
        "margin": "0 0.5em"
      }, 
      "div.center": {
        "float": "left", 
        "font-weight": "bold", 
        "text-align": "center", 
        "width": "33%%"
      }, 
      "div.left": {
        "float": "left", 
        "width": "33%%"
      }, 
      "div.message p": {
        "-moz-border-radius": "100%%", 
        "background-color": "%(colorbg_dialog_message)s", 
        "border-color": "%(colorborder_dialog_summary)s", 
        "border-style": "solid", 
        "border-width": "2px", 
        "font-weight": "bold", 
        "margin": "1em 2em", 
        "padding": "0.5em", 
        "text-align": "center"
      }, 
      "div.message p.error": {
        "border-color": "%(colorborder_dialog_error)s", 
        "color": "%(color_error)s"
      }, 
      "div.right": {
        "text-align": "right"
      }, 
      "div.view": {
        "bottom": "0", 
        "left": "0", 
        "overflow": "auto", 
        "position": "absolute", 
        "right": "0", 
        "text-align": "center", 
        "top": "%(height_bar)s"
      }
    }, 
    "DialogSet": {
      "div.overlay": {
        "background-color": "#000", 
        "bottom": "0", 
        "left": "0", 
        "opacity": "0.5", 
        "position": "fixed", 
        "right": "0", 
        "top": "0", 
        "z-index": "100"
      }
    }, 
    "Display": {
      "": {
        "border-collapse": "collapse", 
        "empty-cells": "show", 
        "margin": "1em 2em"
      }, 
      "td": {
        "line-height": "%(height_bar)s", 
        "padding": "0.25em 0.5em", 
        "text-align": "left", 
        "vertical-align": "top"
      }, 
      "th": {
        "line-height": "%(height_bar)s", 
        "padding": "0.25em 0.5em", 
        "text-align": "right", 
        "vertical-align": "top"
      }, 
      "tr.error": {
        "background-color": "#ddd"
      }
    }, 
    "FieldTable": {
      "": {
        "border-collapse": "collapse", 
        "empty-cells": "show", 
        "margin": "1em 2em"
      }, 
      "td": {
        "padding": "0.25em 0.5em", 
        "text-align": "left", 
        "vertical-align": "top"
      }, 
      "td.error": {
        "color": "%(color_error)s"
      }, 
      "th": {
        "font-weight": "normal", 
        "line-height": "%(height_bar)s", 
        "padding": "0.25em 0.5em", 
        "text-align": "right", 
        "vertical-align": "top"
      }, 
      "tr.error": {
        "background-color": "#ddd"
      }, 
      "tr.required th": {
        "font-weight": "bold"
      }
    }, 
    "Fieldset": {
      "": {
        "-moz-border-radius": "0.75em", 
        "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"
      }
    }, 
    "Grid": {
      "": {
        "bottom": "0", 
        "left": "0", 
        "position": "fixed", 
        "right": "0", 
        "top": "2em"
      }, 
      "div.message": {
        "font-weight": "bold", 
        "height": "%(height_bar)s", 
        "line-height": "%(height_bar)s", 
        "text-align": "center"
      }, 
      "div.message.error": {
        "color": "%(color_error)s !important"
      }, 
      "span.arrow": {
        "font-size": "12pt", 
        "visibility": "hidden"
      }, 
      "table": {
        "border-collapse": "separate", 
        "border-spacing": "2px", 
        "bottom": "0", 
        "cursor": "default", 
        "display": "block", 
        "empty-cells": "show", 
        "font-family": "monospace", 
        "font-size": "%(font_size_mono)s", 
        "left": "0", 
        "overflow-x": "auto", 
        "overflow-y": "hidden", 
        "position": "absolute", 
        "right": "0", 
        "top": "2em", 
        "white-space": "nowrap"
      }, 
      "tbody": {
        "overflow-x": "hidden", 
        "overflow-y": "auto"
      }, 
      "tbody tr": {
        "background-color": "%(colorbg_grid_tr)s"
      }, 
      "tbody tr.selected": {
        "background-color": "%(colorbg_grid_tr_selected)s !important"
      }, 
      "tbody tr:hover": {
        "background-color": "%(colorbg_grid_tr_hover)s"
      }, 
      "td": {
        "padding": "0 0.5em"
      }, 
      "th": {
        "color": "#fff", 
        "padding": "0 0.5em", 
        "text-align": "left"
      }, 
      "th.sort": {
        "color": "yellow"
      }, 
      "th.sort span.arrow": {
        "visibility": "visible"
      }, 
      "th.sortable:hover": {
        "background-color": "%(colorbg_grid_th_hover)s"
      }, 
      "th.space": {
        "width": "100%%"
      }, 
      "thead": {
        "background-color": "%(colorbg_grid_th)s"
      }, 
      "thead input": {
        "border": "0"
      }, 
      "tr": {
        "line-height": "2em"
      }
    }, 
    "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": {
      "": {
        "color": "%(color_bar)s", 
        "cursor": "default", 
        "margin": "0", 
        "padding": "0"
      }, 
      ":hover": {
        "background-color": "%(colorbg_hover_menu)s"
      }, 
      "> span": {
        "color": "%(color_bar)s", 
        "display": "block", 
        "line-height": "%(height_bar)s", 
        "padding": "%(padding_menu)s", 
        "text-decoration": "none", 
        "white-space": "nowrap"
      }, 
      "> ul": {
        "-moz-box-shadow": "black 0.5em 0.5em 0.5em", 
        "background-color": "%(colorbg_bar)s", 
        "border-color": "%(colorborder_menu)s", 
        "border-style": "solid", 
        "border-width": "1px", 
        "list-style-type": "none", 
        "margin": "0", 
        "padding": "0", 
        "position": "fixed", 
        "z-index": "60"
      }
    }, 
    "MenuItem": {
      "": {
        "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": "-moz-linear-gradient(top, %(colorbg_bar_top)s, %(colorbg_bar)s)", 
        "background-color": "%(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_error": "#d02", 
    "color_legend": "#fff", 
    "colorbg": "#fff", 
    "colorbg_bar": "#446", 
    "colorbg_bar_top": "#5b5b7e", 
    "colorbg_code": "#eee", 
    "colorbg_dialog_message": "#eee", 
    "colorbg_grid_th": "#777", 
    "colorbg_grid_th_hover": "#977", 
    "colorbg_grid_tr": "#eee", 
    "colorbg_grid_tr_hover": "#ddd", 
    "colorbg_grid_tr_selected": "#ddf", 
    "colorbg_hover_menu": "#669", 
    "colorbg_legend": "#966", 
    "colorbg_target_menu": "#966", 
    "colorborder_dialog_error": "#b55", 
    "colorborder_dialog_summary": "#595", 
    "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]  ----  */
.hide {
    display: none !important;
}
.numeric {
    text-align: right;
}
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.25em;
}
div.Actions input {
    border: none;
    margin: 0 0.25em;
    padding: 2px;
}
div.Actions label {
    margin: 0 0.25em;
}
/*  ----  Dialog  ----  */
div.Dialog {
    background-color: #fff;
    bottom: 1em;
    left: 1em;
    position: fixed;
    right: 1em;
    top: 1em;
    z-index: 100;
}
div.Dialog div.bar {
    background: #446;
    color: #fff;
    height: 2em;
    left: 0;
    line-height: 2em;
    position: absolute;
    right: 0;
    top: 0;
}
div.Dialog div.bar button {
    margin: 0 0.5em;
}
div.Dialog div.bar label {
    margin: 0 0.5em;
}
div.Dialog div.center {
    float: left;
    font-weight: bold;
    text-align: center;
    width: 33%;
}
div.Dialog div.left {
    float: left;
    width: 33%;
}
div.Dialog div.message p {
    -moz-border-radius: 100%;
    background-color: #eee;
    border-color: #595;
    border-style: solid;
    border-width: 2px;
    font-weight: bold;
    margin: 1em 2em;
    padding: 0.5em;
    text-align: center;
}
div.Dialog div.message p.error {
    border-color: #b55;
    color: #d02;
}
div.Dialog div.right {
    text-align: right;
}
div.Dialog div.view {
    bottom: 0;
    left: 0;
    overflow: auto;
    position: absolute;
    right: 0;
    text-align: center;
    top: 2em;
}
/*  ----  DialogSet  ----  */
div.DialogSet div.overlay {
    background-color: #000;
    bottom: 0;
    left: 0;
    opacity: 0.5;
    position: fixed;
    right: 0;
    top: 0;
    z-index: 100;
}
/*  ----  Display  ----  */
table.Display {
    border-collapse: collapse;
    empty-cells: show;
    margin: 1em 2em;
}
table.Display td {
    line-height: 2em;
    padding: 0.25em 0.5em;
    text-align: left;
    vertical-align: top;
}
table.Display th {
    line-height: 2em;
    padding: 0.25em 0.5em;
    text-align: right;
    vertical-align: top;
}
table.Display tr.error {
    background-color: #ddd;
}
/*  ----  FieldTable  ----  */
table.FieldTable {
    border-collapse: collapse;
    empty-cells: show;
    margin: 1em 2em;
}
table.FieldTable td {
    padding: 0.25em 0.5em;
    text-align: left;
    vertical-align: top;
}
table.FieldTable td.error {
    color: #d02;
}
table.FieldTable th {
    font-weight: normal;
    line-height: 2em;
    padding: 0.25em 0.5em;
    text-align: right;
    vertical-align: top;
}
table.FieldTable tr.error {
    background-color: #ddd;
}
table.FieldTable tr.required th {
    font-weight: bold;
}
/*  ----  Fieldset  ----  */
fieldset.Fieldset {
    -moz-border-radius: 0.75em;
    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;
}
/*  ----  Grid  ----  */
div.Grid {
    bottom: 0;
    left: 0;
    position: fixed;
    right: 0;
    top: 2em;
}
div.Grid div.message {
    font-weight: bold;
    height: 2em;
    line-height: 2em;
    text-align: center;
}
div.Grid div.message.error {
    color: #d02 !important;
}
div.Grid span.arrow {
    font-size: 12pt;
    visibility: hidden;
}
div.Grid table {
    border-collapse: separate;
    border-spacing: 2px;
    bottom: 0;
    cursor: default;
    display: block;
    empty-cells: show;
    font-family: monospace;
    font-size: 10pt;
    left: 0;
    overflow-x: auto;
    overflow-y: hidden;
    position: absolute;
    right: 0;
    top: 2em;
    white-space: nowrap;
}
div.Grid tbody {
    overflow-x: hidden;
    overflow-y: auto;
}
div.Grid tbody tr {
    background-color: #eee;
}
div.Grid tbody tr.selected {
    background-color: #ddf !important;
}
div.Grid tbody tr:hover {
    background-color: #ddd;
}
div.Grid td {
    padding: 0 0.5em;
}
div.Grid th {
    color: #fff;
    padding: 0 0.5em;
    text-align: left;
}
div.Grid th.sort {
    color: yellow;
}
div.Grid th.sort span.arrow {
    visibility: visible;
}
div.Grid th.sortable:hover {
    background-color: #977;
}
div.Grid th.space {
    width: 100%;
}
div.Grid thead {
    background-color: #777;
}
div.Grid thead input {
    border: 0;
}
div.Grid tr {
    line-height: 2em;
}
/*  ----  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 {
    color: #fff;
    cursor: default;
    margin: 0;
    padding: 0;
}
li.Menu:hover {
    background-color: #669;
}
li.Menu > span {
    color: #fff;
    display: block;
    line-height: 2em;
    padding: 0 0.5em;
    text-decoration: none;
    white-space: nowrap;
}
li.Menu > ul {
    -moz-box-shadow: black 0.5em 0.5em 0.5em;
    background-color: #446;
    border-color: #000;
    border-style: solid;
    border-width: 1px;
    list-style-type: none;
    margin: 0;
    padding: 0;
    position: fixed;
    z-index: 60;
}
/*  ----  MenuItem  ----  */
li.MenuItem {
    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: -moz-linear-gradient(top, #5b5b7e, #446);
    background-color: #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;
}