You have probably noticed that some of the MoinMoin wikis out there look differently than others: for example, the python wiki has an unique look, matching the rest of the python website. This is done by using a custom-made theme. We will see how to make such a theme yourself.
What's in a theme?
In MoinMoin themes consist of two main parts:
- a plugin that tells the wiki what elements should it show and in what order they should appear,
- a stylesheet, together with all images, that tells it how these elements should look like and where on the page they should be placed.
The plugin part is just a Python file, stored together with all other MoinMoin plugins in one of two places:
- the system-wide directory, where the MoinMoin sources were installed. For example it may be /usr/lib/python2.5/site-packages/MoinMoin/theme/modern.py
- the wiki-specific directory, where all the data of a certain wiki is kept, for example /var/wiki/MyWiki/data/plugin/theme/my_theme.py. The location of this data directory is specified in the wikiconfig.py file of the wiki, in data_dir variable. You will probably want to put your custom themes in the wiki-specific location, as the global one may be overwritten by upgrades. You may however like to look at the default MoinMoin themes, stored in the global location -- to see how they are made and reuse parts of them.
The style part of your theme is not executed by the wiki directly, but instead is downloaded by your browser -- so you could, in theory, put it anywhere in the Internet. It is however convenient to put everything in one place -- in the wiki's htdocs directory, for example in /var/www/htdocs/MyTheme/. These files must be served by your web server, so make sure that they have appropriate permissions and are available at the address specified in your wiki's wikiconfig.py with the url_prefix_static variable. The style part may contain even hundreds of files, so they are organized into directories for convenience:
- htdocs/theme_name is the base directory of your theme.
- htdocs/theme_name/css contains the style sheets, in particular:
- common.css is the main style sheet, always loaded.
- screen.css is loaded when the page is displayed on the screen.
- print.css is used in the print view and when the page is being printed.
- projection.css is for the slide show.
- msie.css is only used when the browser is Microsoft Internet Explorer, because that browser interprets CSS rules differently and sometimes you need additional code to make it look good.
- htdocs/theme_name/img stores various images and icons used by the style.
First steps
The simplest thing we can do is to take an existing theme and change its styles a little -- for example, change the colors or images. Our plugin part will be just inheriting everything from an existing theme -- for example, from Modern. It should look something like this:
Note that you could inherit from any built-in theme by just changing the import and class lines. We will see later how to inherit from ThemeBase to create themes from scratch. For now we will concentrate on changing the looks, not the behavior, and most of this can be done by just manipulating the style sheets.
This is the minimal amount of code we need. It takes the Modern theme and inherits everything from it, changing only the theme's name. The execute function is needed as a glue, every theme has it. Once you have put this theme in your theme directory, it should become selectable from the UserPreferences. It lacks any stylesheets, so it will probably look pretty plain -- like any other unstyled web page.
Remember that if you are using anything else than simple CGI, for example you run a standalone MoinMoin locally, or use mod_wsgi or mod_fastcgi, you might need to restart MoinMoin to see the new theme (and to see any other change you make in the Python files).
Now we can copy all the files from htdocs/modern to a new directory, htdocs/mytheme. After you do it, and fix the file permissions, your new theme should look identically to the Modern theme. Now we can start customizing.
Changing some colors
Colors in cascading style sheets are usually specified using a hexadecimal notation of their red, green and blue components. Almost any graphical program will let you see the components of a color. Some, like GIMP, even display a ready to copy and paste representation of it -- but you can also edit the colors by hand. For example, #ffffff is white -- it means 255 red, 255 green and 255 blue -- that is the maximum for all components. You can also write it in shorter from, #fff; When there are only 3 digits, each of them is just repeated twice. You can get black with #000 and red with #f00. After a little training you will be able to tell the hex values of a color by just looking at it. Or maybe not.
Let us try and change the color of the heading background. It is defined in the css/screen.css file -- there should be something like this in it:
#header { margin: 1px; padding: 1px; background: #E7E7E7; line-height: 1.1em; }
We can edit the line that says 'background' and put a different color in there. For example, we can put in there background: #3d4551; to bring back the bluish color that older versions of MoinMoin used.
#header { margin: 1px; padding: 1px; background: #3d4551; line-height: 1.1em; }
Note that the exact code shown in these examples may be different from the one in your version of MoinMoin -- even the built-in themes are changing to take advantage of new browser features and fix bugs.
Whenever you see something like #XXXXXX or #XXX in the stylesheets, it's some color you can change. Often you will want to do a search and replace for one particular color, to change it to something else everywhere it appears.
Classes, IDs and selectors
You have probably already noticed a certain pattern in the CSS files. They mostly contain rules in the form:
identifiers { style specifications }
The indetifiers part tells which part of the page the style should be applied to, and the style specifications tell how it should look like. The identifiers usually come in one of three flavors:
- HTML tag name -- this is just a single word, like "div", "span" or "body". They correspond to the tags in page's HTML source, such as <div>, <span> or <body>, and they make the style apply to all the contents of that tag.
- Class name -- this is a tag name with a class name, or just a class name alone. For example "div.table-of-contents", "a.nonexistent" or simply ".comment", ".warning", ".strike". They affect the HTML tags that have appropriate class attribute specified: <div class="table-of-contents">, <a href="..." class="nonexistent"> or <p class="comment">, <div class="warning">, <span class="strike">.
- Tag ID -- this is similar to classes, except instead of period ".", a number symbol "#" is used: "div#header", "#content". These affect tags with specified ID set, like <div id="header"> or <div id="content">. The main difference between classes and IDs is that there can be only one tag with given ID on a page. These identifiers can be joined, usually in two ways:
- identifier1, identifier2 -- this will affect tags specified both by identifier1 and identifier2, just as if the rule was written twice.
- identifier1 identifier2 -- this will affect tags specified by identifier2, but only those that are inside tags specified by identifier1. For example #header a will affect all links inside the header -- but not the links in the content or footer.
You can read a much better and more detailed description of these rules in the Specification of CSS selectors, but this should get us going at the start.
The style properties
Inside the {...} you put so called "properties", that describe the looks of the specified element. You can find the full list of CSS properties in the specification, but we will discuss some of them in closer detail here.
Colors
There are basically three groups of properties that affect colors. The color property sets the color for the text displayed inside the given element. You can use it to change the color of normal text, the colors of links, colors of emphasized text, etc. It's pretty simple to use, for example:
body { color: #888; }
will change the default text color for the whole page to light gray. The background-color property is similar, except that it changes the color of the "paper" under the selected element. You can abbreviate it to background, which also accepts various options for using a background image and aligning it. Example of using background:
#header { background: #000; }
This will set the background of the header to black, resulting in a large black rectangle on top of every wiki. It's generally a good idea to always use color and background properties together, so that the text is always visible on top of the background. Setting background to black without changing the color might result in black text on black background.
The third group of properties that affect colors consists of border-color and all the -left, -right, -top and -bottom variants. They can also be abbreviated to border, which takes additional options about the border's thickness and style. For example:
pre { border: 4px dotted red; }
will make all preformatted code blocks display a border of thick red dots. There are some more, rarely used properties that can use colors, like outline-color or text-shadow -- we won't cover them here.