Extension:Page Forms

Description
Semantic Forms is an extension to MediaWiki that allows users to add and edit data using forms. It is heavily tied in with the Semantic MediaWiki extension, and is meant to be used for structured data that has semantic markup. Having Semantic MediaWiki installed is a precondition for the Semantic Forms extension; the code will not fully work without it.

Very simply, Semantic Forms allows you to have forms for adding and editing data on your wiki, without any programming. Forms can be created and edited not just by administrators, but by users themselves.

The main components of Semantic Forms functionality are form definition pages, which exist in a new namespace, 'Form:'. These are pages consisting of markup code which gets parsed when a user goes to add or edit data. Since forms are defined strictly through these definition pages, users can themselves create and edit forms, without the need for any actual programming.

The Semantic Forms extension enforces the use of templates in creating semantic data. It does not support direct semantic markup in data pages; instead, all the semantic markup is meant to be stored indirectly through templates. A form allows a user to populate a pre-defined set of templates for a page (behind the scenes, that data is turned into semantic properties (with Semantic MediaWiki 1.0) or relations and attributes (with previous versions of SMW) once the page is saved).

Forms can also be used to edit the data in an existing page, and you can enable an 'edit with form' tab to show up on any page; see The 'edit with form' tab.

Semantic Forms also supports autocompletion of fields, so users can easily see what the previously-entered values were for a given field. This greatly helps to avoid issues of naming ambiguity, spelling, etc.

Data in a page that doesn't fit into the form, like a free-form text description of the page's subject, doesn't get ignored when the page is edited with a form; instead, it gets placed into a separate input box, called "Free text".

Semantic Forms also provides hooks to let outside code easily define new input types; this is useful for, among other things, new extensions to define input types that use code that they provide.

Semantic Forms also provides other features: a form to create semantic properties/attribute/relations, a form to create templates, a form to create user forms, pages that list all the templates and all the user forms on the site, and others. This documentation covers all the features, but see especially the Special pages section.)

Code and download
You can download the Semantic Forms code in either one of these two compressed files:


 * semantic_forms_0.6.8.tar.gz
 * semantic_forms_0.6.8.zip

You can also download the code directly via SVN from the MediaWiki source code repository, at http://svn.wikimedia.org/svnroot/mediawiki/trunk/extensions/SemanticForms/. From a command line, you can call the following:

To view the code online, including version history for each file, you can go here.

Installation
After you've obtained a 'SemanticForms' directory (either by extracting a compressed file or downloading via SVN), place this directory within the main MediaWiki 'extensions' directory. Then, in the file 'LocalSettings.php' in the main MediaWiki directory, add the following line below the calls for the Semantic MediaWiki extension (both the main 'include_once' line and the 'enableSemantics' line):

You may also wish to change the number value for the new "Form" namespace, defined in SF_Settings.php; by default it is set to 150.

Also, if you have any custom namespaces declared, you should add the following declaration before the 'include_once' call in the file 'LocalSettings.php':

(Or, instead of 150, whatever number you want the "Form" namespace set to.)

Author
Semantic Forms was mostly written by Yaron Koren, reachable at yaron57 -at- gmail.com.

Version
Semantic Forms is currently at version 0.6.8. See the entire version history.

Special pages
The extension defines eight "special" MediaWiki pages:


 * Special:AddData - lets a user add a page using a user-defined form. (See example of page)
 * Special:AddPage - lets a user specify a page name, to be either added or edited depending on whether it already exists. (See example of page) This page is somewhat deprecated.
 * Special:CreateForm - lets a user create a new form for adding/editing data. (See example of page)
 * Special:CreateTemplate - lets a user create a new template. (See example of page)
 * Special:CreateProperty - lets a user create a new property, attribute or relation. (See example of page)
 * Special:EditData - lets a user edit an existing page using a user-defined form. (See example of page)
 * Special:Forms - lists all form pages on the site. (See example of page)
 * Special:Templates - lists all templates on the site. (See example of page)

Code structure
The following are the directories and files in the Semantic Forms extension:

/includes


 * SF_FormClasses.inc - defines three classes - SFForm, SFTemplateInForm and SFFormTemplateField - that represent the components of a user-defined form, and handle the creation of a form definition file.
 * SF_FormEditTab.php - a tab that shows up on data pages to let the user edit them with a form, if a default form for this page's category has been specified.
 * SF_FormPrinter.inc - defines a class, SFFormPrinter, that handles the display and running of a user-created form.
 * SF_GlobalFunctions.php - functions and constants used by the rest of the Semantic Forms code.
 * SF_ParserFunctions.php - defines parser functions (currently two - 'forminput' and 'arraymap')
 * SF_Settings.php - various settings for Semantic Forms.
 * SF_TemplateField.inc - defines a class, SFTemplateField, used in both creating templates and displaying user-created forms.

/languages


 * SF_LanguageEn.php - English-language text
 * SF_LanguageFr.php - French-language text
 * SF_LanguageHe.php - Hebrew-language text
 * SF_LanguageNl.php - Dutch-language text
 * SF_LanguagePt_br.php - Brazilian-Portuguese-language text
 * SF_LanguageZh_cn.php - Mainland-Chinese-language text
 * SF_LanguageZh_tw.php - Taiwanese-Chinese-language text

/libs


 * scriptaculous-js-1.7.0/ - the entire script.aculo.us JavaScript library; used for auto-completion in the forms

/skins


 * scriptaculous.css - CSS file used by script.aculo.us
 * SF_main.css - main CSS file for Semantic Forms

/specials


 * SF_AddData.php - defines the 'AddData' special page
 * SF_AddPage.php - defines the 'AddPage' special page
 * SF_CreateForm.php - defines the 'CreateForm' special page
 * SF_CreateTemplate.php - defines the 'CreateTemplate' special page
 * SF_CreateProperty.php - defines the 'CreateProperty' special page
 * SF_EditData.php - defines the 'EditData' special page
 * SF_Forms.php - defines the 'Forms' special page
 * SF_Templates.php - defines the 'Templates' special page

Getting started
So, you've set up all the software on your site. Now what? Now it's time to create the structures to hold, display and enable adding and editing of your data; thankfully all of this can be done simply by creating various wiki pages. You should take the following steps:


 * Figure out your data structure. What types of pages will the site have? What data will be contained on each one? You can change all of this around later, but it's good to have a starting plan.


 * Create properties, or attributes and relations. The basic building blocks of any semantic site are the connections between data, which in Semantic MediaWiki 1.0 are known as properties, and in older versions of SMW are known as attributes and relations. A property/attribute/relation is used to specify a single piece of information about the topic of this page. In the case of pre-1.0 versions of SMW, an attribute is a standalone field, while a relation represents another page on the wiki; in SMW 1.0, a property can be either, depending on whether its type is "page" or something else. Every property, attribute or relation used be defined separately on your wiki, in either the "Property", "Attribute:" or "Relation:" namespace. The easiest way to do that is to use the 'CreateProperty' special page (see above).


 * Create templates. A template sets the display of the data on a page, holds the markup to turn the data into actual semantic information, and (often) defines the page as being of a certain category, and thus of a certain page type. There will generally be one template per page type, although sometimes a single page type will have more than one template, especially if certain fields can have more than one value (see "Multiple values for the same field" below). The easiest way to create templates is using the 'CreateTemplate' special page (see above).


 * Create forms. Now you can create forms to allow users to easily add and edit pages of various types. There should be one form per page type; a form should populate the template or templates that this page type contains. As before, there's a special page to create new forms: 'CreateForm' (see above). See below for documentation on the special markup language used to define forms.One common request is for these three special pages ('CreateProperty', 'CreateTemplate' and 'CreateForm') to be able to edit existing property/template/form pages, and not just create new ones. However, this is programatically much harder to implement than creating new pages, because it requires parsing. For the foreseeable future, modifying existing pages for properties, templates and forms will have to be done by hand.


 * Enable links to forms. Once you have the forms in place, you need to have ways for the users to access them. These include: adding links to add data in the sidebar and elsewhere; enabling each page that's editable with a form to have an 'edit with form' tab at the top; and having red-links to nonexistent pages point to a form for creating them. All three of these possibilities are explained further below.


 * Add aggregation. Why bother storing all this data semantically in the first place? One big advantage is that it allows for aggregation - displaying all the pages that have the same relationship to a page or a set of values. For instance, let's say you have a page type that contains, as one of its fields, the country that this item is located in. You can then have a separate page type, for countries, that uses a template that holds an inline query, so that every country will show a list of the entities located in that country. See the inline queries page in the SMW documentation for more information on how to do this.


 * Customize. Once the structure is in place, you can customize all you want - changing the look-and-feel of the entire wiki, of the various templates, and of the forms, and adding and changing fields. You should also add data to the site (using your new forms), to make sure that everything is displaying the way you would want it to.

Form markup language
Forms are defined using a set of tags that specify templates and fields within those templates. HTML can be freely embedded anywhere outside of the tags. The allowed tags are:


 * - Specifies a template name, and declares that all of the following fields (until end template is reached) will be those of this template. The name immediately following the for template declaration is the name of the template. Allowed properties of this tag are:
 * label text - Specifies a label to be placed in a square around the entire set of this template's fields in the form.
 * - Specifies that the user can change the number of instances of this template in the form, allowing multiple (or zero) occurrences; see "Multiple values for the same field", below.
 * dropdown name - Similar to multiple, but allows for a single dropdown input in the form to add instances of each template labelled as chooser, instead of each such template requiring its own 'Add' button.
 * - Sets the caption in the form's dropdown for adding instances of this template; must be set in conjunction with chooser option.
 * - Specifies that only fields in the form that correspond to fields used by the template should get turned into form elements.


 * - Ends the range of a template. There are no properties for this tag.


 * - Specifies a field to be placed in a form. It can be either a template field or, if it's the page title or free text field, standalone. The name immediately following the field declaration is the name of the field. Allowed properties of this tag are:
 * input type - Specifies the type of input this field will have in the form: allowed values are text</tt>, textarea</tt>, date</tt>, datetime</tt>, datetime with timezone</tt>, radiobutton</tt>, checkbox</tt>, listbox</tt> and checkboxes</tt>. If a field corresponds to a semantic property, attribute or relation, the form will usually have the correct input type by default; otherwise the default is text</tt>.
 * size - Used for text entries. Specifies the width of the text entry.
 * num rows - Used for textarea entries. Specifies the number of rows.
 * num cols - Used for textarea entries. Specifies the number of columns.
 * - Specifies that a field must be filled in by the user.
 * - Specifies that a field will be hidden in the form: used to preserve values in edited pages.
 * - Specifies that a field will be editable only by admins/sysops and disabled for all other users.
 * category name - Used for text entries. Specifies that there should be Javascript "autocompletion" on this input, using a list of the pages within the specified category (and all its subcategories). Autocompletion is on by default for fields that correspond to relations; if autocomplete on</tt> is included but category name</tt> is left blank, autocompletion is disabled.
 * namespace name - Similar to, but gets all the pages that belong to a certain namespace.
 * default value - Specifies a default value for this field. For date-related fields, default=now</tt> will set the value to the current date and possibly time.
 * page title - Specifies a page whose contents should be preloaded into this field (used only for free text</tt> field)
 * delimiter - Specifies the delimiter character or string this field should use, if it represents a list of values; the default is ", ".


 * There are two special fields a form should contain that are not part of any templates:


 * - Not a form element, but is translated into a text string of the title of the page being created or edited.
 * - A textarea that holds all the text on the page that does not fit into any of the templates specified in the form. Allowed properties for this field are rows</tt>, cols</tt>, <tt>hidden</tt>, <tt>restricted</tt> and <tt>preload</tt>.


 * - One of seven inputs that, by default, appear at the bottom of every form. The text immediately after "standard input|" is the name of this input - the six allowed values are "save" (for the "Save page" button"), "preview" (for the "Show preview" button), "changes" (for the "Show changes" button), "summary" (for the "Summary" text field), "minor edit" (for the "This is a minor edit" checkbox), "watch" (for the "Watch this page" checkbox) and "cancel" (for the "Cancel" link). Additional properties that can be set for this tag are:
 * label name - Specifies the text associated with this input on the form. By default, the text for any standard input is set in that wiki's relevant language file.


 * So, for example, the button for "Save page" would be specified with " ". If no  tags are included in the form definition, all six will appear at the bottom of the form, just as they do for regular "Edit" pages. However, if even one such tag is included, then only those inputs which have been included will be displayed, in the order, and with the HTML, that they appear in in the form definition.

Allowed input types for data types
Each defined Semantic MediaWiki data type has a default input type, and in some cases a default input size as well. Additionally, some data types have special handling if the field holds a delimited list of values, instead of just a single value.

Here are the defaults and the other allowed input types for each data type, for single values:

And here are the default and other allowed input types for delimited lists of a certain data type, enabled by the use of the "#arraymap" function:

Example
Here is the source code for the 'Item' form definition page at Discourse DB:

Opinion item: Author: Source: Date: URL: Quote: Author: Topic: Position: Stance: Item name: Free text:

Note the presence of HTML within the code. This markup was created using the Create Form page, and based around the templates Item, Additional author, Opinion, and Reference. You can see the working form at this add data page ; the form itself is created on-the-fly from the form definition file. In the 'Items' category page, if you click on any of the pages, you can see the 'edit with form' tab on the top right-hand side. If you click on that tab, you can see this same form, this time populated with the data contained in that page.

Note also the 'page title' field, which is a special field, outside of any template, that should be present in the form. This field displays the title of the page - it is pre-populated, and can't be edited.

Enabling users to add data
It's possible to have a form for adding data that requires the user to specify the title of the page in question. However, this is a risky approach, because it means that, if a page with this name already exists in the wiki, it will get overwritten. That's why adding data is, by default, structured as a two-part process: first the user inputs a page title, and then he/she is sent to a form for either adding or editing that page, depending on whether or not the page already exists.

There are two ways to do the initial page input:


 * Use 'AddPage' - the user can go to /Special:AddPage; a form name can optionally be specified in the URL, so it looks like /Special:AddPage/form-name. If no form name is specified, a dropdown of all available forms in the wiki will appear next to the input for the page name, letting the user choose.
 * Use the 'forminput' parser function - adding this tag to any page will create a form like AddPage's, but more customizable. Here is the generic call for the tag:




 * All arguments are optional.  is the name of the SF form to be used; if it is left empty, a dropdown will appear, letting the user choose among all existing forms.   represents the size of the text input (default is 25), and   is the starting value of the input (default is blank).   is the text that will appear on the "submit" button, and   is the set of values that you want passed in through the query string to the form.

Adding pages of a specific namespace
You can have a page-input form create pages within a specific namespace (like 'User:') by default, without forcing users to type in that namespace every time. If you're using 'AddPage', you can do so by setting the URL to something like " http://mywiki.com/Special:AddPage/ form-name/Namespace:namespace-name". If you're using the 'forminput' tag, the "query_string" value should include 'namespace=namespace-name'.

Preloading data
You may want a form to already contain some data when the user goes to it. (Note that this only applies to adding new data; for editing an existing page, there is no way to set the contents of the form to anything other then the current contents of that page.) There are various ways to do this:


 * Specify a "default" value for whatever fields you want to have a value for in the form.
 * Specify a "preload" page for the "free text" field, which will preload the free text field with the contents of that page.
 * Add a "preload=..." value to the query string for 'AddPage', so the URL looks like " http://mywiki.com/Special:AddPage/ form-name?preload=preload-page-name; this will preload the entire form with the contents of that page.
 * Similarly, you can add 'preload=preload-page-name' to the 'query_string' value in the 'forminput' call.
 * Add a value for a specific field to the URL query string for 'AddPage'; the URL would look like " http://mywiki.com/Special:AddPage/ form-name/page-name?template-name[field-name]=field-value.
 * And, as expected, you can add "template-name[field-name]=field-value" to the 'query_string' value in the 'forminput' call.

Multiple values for the same field
There may be fields for which you want the user to be able to enter multiple values. There are two ways to do this:


 * The standard way - create a template for just that field, and then include the new template in the form, with a 'multiple' property. The example above, for the 'Item' form, contains three such templates. If you look at the form that this definition generates, you can see that there are three buttons labelled 'Add another'. Clicking on any one of these will create a new instance of that template and its field(s). The user can add and remove such instances to match the number of values they want to have for each field.


 * The easier way - you can allow users to put all the values in one field, separated by commas or some other string. To do this, the template should contain the Semantic Forms parser function '#arraymap', which applies a mapping on each section of a delimited string. If you have a form that populates the field 'author', and you want the values for that field to be separated by commas and to each get the semantic relation 'Has author', you could add the following to the template code, in place of a regular semantic tag: <tt> </tt> Essentially this function 'maps' the relation tag onto each comma-delimited value in the field. The user can thus enter all the values on the same line, with or without spaces around the commas. If each of these values is part of an enumerated list, you can make things even easier for the user by making the input of type "listbox" or "checkboxes", which will let the user easily select a set of values from a list, and place all these values in a delimited string within the page itself.

If you use the 'CreateTemplate' page to create a template, an option exists to let you automatically enter this parser function in the template for any field that can take more than one value.

The advantage of the 'easier' way is that it's easier (in some cases, much easier) for users to enter values. The advantage of the 'standard' way is that it allows for auto-completion during data entry.

The 'edit with form' tab
There are two ways to get the 'edit with form' tab to appear for specific pages. The first, and recommended, way, is to use categories. To enable a page to have a tab in this way, you must first define that page as belonging to a specific category - categories are the standard Semantic MediaWiki approach to defining a page's type. The best way to match pages with a category is to place a 'Category' tag inside the main template that defines this page type; that way, every page that uses this template will become part of this category.

Once you have done that, you should place the semantic relation 'Has default form' in the page for that category; the tag should look like <tt> Has default form::Form: form-name</tt>.

As an example of this approach, see the "Magazine" template source code on Discourse DB, which defines any page that includes it to be of category "Magazines"; then the "Magazines" category source code, which specifies the "Magazine" form as the default form for this category. Then, see the page for Newsweek magazine, which uses the "Magazine" template, and thus belongs to category "Magazines", and thus gets an "edit with form" tab at the top; this tab then links to editing with the "Magazine" form. And there you have it.

The second possible way is to match the pages' namespace to a form. You can do that by placing a 'Has default form' relation in the page defining that namespace. If, for instance, your wiki is called 'MyWiki', and the namespace you want to associate with a form is 'User', the page in which you need to add the relation will probably be called 'MyWiki:User' (you may need to create this page). If the namespace you want a default form for is the main one (i.e., the one with no name, you will need to create and add this relation to the page called 'MyWiki:Main', or whatever the main namespace is called in the language of this wiki. Once you've added this relation, every page within that namespace will have that form associated with it, unless it already belongs to a category that has an associated form (categories take precedence over namespaces).

Pointing red links to 'add data' form
On MediaWiki, links to nonexistent pages are called 'red links', because they are usually colored red. By default, these links go to a page for adding this article to the wiki using the standard edit form. However, if such an article is the object of a semantic relation, it's possible to get such a link to point to the correct Semantic Forms 'add data' form instead.

This is done in two parts:


 * you must make a small modification to a file in the main MediaWiki code - the code change can be found here.


 * you must add the semantic relation 'Has default form' (see "The 'edit with form' tab") to the page for the relation that such an article is the object of.

As an example, see this page. Both the author and the source are red-linked, but the links take you to forms for adding these two pages (please do not actually fill out and submit these forms, because that would ruin the example). That is enabled by 'Has default form' relations in the pages for both the relations 'Was written by' and 'Was published by'.

Note also that, if you've made that MediaWiki code change, and you've defined a namespace as having a default form, red-links that go to a page within that namespace will also go to the right 'add data' form, without any extra work needed.

Sometimes, when a page with red links is first created, the red links will point (incorrectly) to the standard edit URL, and not to the form URL; the correct URL will only appear at some point later. That happens because of caching on the wiki. You can very easily disable caching, if you want to get around this problem; see the instructions here.

Defining new inputs
There are two kinds of hooks one can use to define new inputs: input-type hooks and semantic-type hooks. The first let you register a function that creates an input based on an input-type name in the form definition, and the second let you register a function for a specific semantic type (like "Integer", etc.); which is especially useful if you want to override Semantic Forms' own handling. To create a new input type, you just need to create a function with the following structure:

function my_input_html($cur_value, $input_name, $is_mandatory, $is_disabled, $field_args) { ... }

This function needs to return an array of two elements: the first is the HTML text that will be displayed on the page for this input, and the second is whatever Javascript text should be added at the top of the page to enable both this input's running and its validation (this value can be null).

The function also has to be registered, with code that looks like this:

global $sfgFormPrinter; $sfgFormPrinter->setInputTypeHook('myinput', 'my_input_html', array);

Where 'myinput' is the name of the input that users are meant to insert in the form. To register it as a semantic-type input instead (in this case, for Integers), change that second line to:

$sfgFormPrinter->setSemanticTypeHook($smwgContLang->smwDatatypeLabels['smw_integer'], false, 'my_input_html', array);

The second argument to  specifies whether this is a hook for a single integer, or for a delimited list of integers (false means it's a single value).

In the declaration of, the first parameter is the current value of this field (which is sometimes null); the second parameter is the HTML name that this input should have, so that the system knows where among the POST variables to find the value for this input; the third parameter indicates whether this field is mandatory for the user; the fourth indicates whether it's disabled (meaning, the user can't edit); and, finally, the fifth parameter,  , is a hash representing all the other properties defined for this input in the form definition: you can specify special properties that can be set in the form for this input. So, for instance, if the form contains a line reading:

....then, when  is called,   will contain the "color=orange" and "height=200" key-value pairs, which the function can do whatever it wants to with.

For an example of the use of Semantic Forms hooks, see the code for the Semantic Google Maps extension ; you can see this code in action here.

Common problems

 * If you've just set up your wiki and you want the URL of every page to look shorter and more like Wikipedia's, this short URL page explains how.


 * If you get an error on any page reading something like "Table 'smw_relations' doesn't exist" or "Table 'smw_attributes' doesn't exist", it means you haven't installed, or haven't finished installing, the Semantic MediaWiki extension. If you've set up the SMW code and added the right lines to LocalSettings.php, probably all you need to do is create the new semantic database tables - go to 'Special:SMWAdmin' and press the button.


 * If you have Semantic MediaWiki 1.0 installed, and certain elements are not fully working, that's because SF doesn't yet fully support SMW 1.0 (though it should). Make sure that you have the latest version of SMW 1.0 installed, and feel free to report any problems you experience to the mailing list.


 * To get rid of the semantic "factbox" that appears at the bottom of most pages, go to the file "includes/SMW_Settings.php" within the main Semantic MediaWiki directory, uncomment the line that says "$smwgShowFactbox = SMW_FACTBOX_HIDDEN;", and comment out the line before it.


 * You can change the way dates are outputted by the forms by adding the line "$wgAmericanDates = true" to the main MediaWiki LocalSettings.php file. By default, dates are printed out as "2007/6/20"; making this change will set dates to instead be printed out as "January 20, 2007" (with the month name dependent on the language of the wiki).


 * If you want users to only edit a subset of all the templates on the page, you can make the other templates hidden on the form by setting each field they contain to be "hidden", within the form definition.


 * If a page (which we'll call Page A) gets transcluded in another page (which we'll call Page B), and Page A belongs to a category that's associated with a form, it can have the unfortunate side effect of making Page B a member of that category as well, thus giving Page B an "edit with form" tab at the top, even if such a tab is not appropriate. You can solve this problem by putting the category declaration in Page A within a " " block, which will make Page A a member of that category but not Page B.

Sites that use Semantic Forms
This is not a comprehensive listing, but here are some sites that use Semantic Forms in conjunction with Semantic MediaWiki:


 * 3D Game Comparison (without Semantic MediaWiki)
 * BusyTonight
 * Creative Commons Wiki
 * DataFed Wiki
 * Discourse DB
 * Electronic Literature Organization Archive-It Project
 * Faceted Curriculum Project
 * MographWiki
 * Nomicapolis
 * ORCA Support Network Wiki
 * Placeography
 * Protege Wiki
 * Technical Presentations
 * Wikimaas - Independent City Guide Maastricht

Mailing list
The mailing list for Semantic Forms is on Google Groups, at http://groups.google.com/group/semantic-forms. The list is intended for announcements, discussions about the functionality, ideas for new features, and bug reports. You must be a member to post.

Bugs and feature requests
You can submit bug reports and requests for new features at MediaWiki's Bugzilla, here.

The current list of known bugs and requested features for Semantic Forms can be found here.

Contributing patches to the project
If you found some bug and fixed it, or if you wrote code for a new feature, please create a patch by going to the main "SemanticForms" directory, and typing:

svn diff >descriptivename.patch

Then go to the relevant bug report in Bugzilla, or create one if one doesn't exist (note, again, that Bugzilla is used for both bugs and feature requests), and attach this patch file to it.

If, for any reason, you don't wish to use Bugzilla, feel free to simply send this patch, with a description, to the Semantic Forms mailing list.

Donate
Semantic Forms was created and is developed on a strictly volunteer basis, with no funding whatsoever; all donations are welcome. You can donate to the project here.