Extension:CollaborationKit/Technical documentation

CollaborationKit is a MediaWiki extension that uses ContentHandler, special pages, and EditPage extensions to make it easier to organize on-wiki projects.

Content models
CollaborationKit implements two novel content models: CollaborationHubContent and CollaborationListContent. Both of these content models represent data in JSON according to the schemas defined in CollaborationHubContentSchema.php and CollaborationListContentSchema.php respectively. Pages of either content type are validated against their respective schemas through the schema validation library in EventLogging. Note, however, that this library does not work perfectly, especially since it is not caught up with the latest version of the JSON Schema specification. There are long term plans to integrate a schema validation library in core MediaWiki and use that instead; see Requests for comment/JSON validation.

Each of these content models use a serialization format called text/x-collabkit for editing. The details depend on the content model, but the basic thing is that each high-level key-value pair is represented as one or more lines, separated by a specific number of hyphens, with the order of these blocks of text pre-determined by the serialization/deserialization methods. For sub-objects, key-value pairs are presented, one per line, as key=value. For arrays, each item in the array is one line, with key-value pairs separated by vertical pipes. In some cases, this serialization is used to build the editing interface, minimizing exposure of code-like syntax to the user. The exact JSON stored in the database can be edited directly through the "Edit as JSON" tab, or through the  parameter in the edit URL.

Most forms of page interaction that exist with MediaWiki also work with these content models. They can be deleted, moved, etc. like other pages.

CollaborationHubContent
The CollaborationHubContent model represents "Collaboration Hubs," which are landing pages for on-wiki projects. Collaboration Hubs are essentially shell pages that then transclude other pages, including little content of its own.

The pages that are transcluded are called "features," corresponding to sections on the hub page and (usually) corresponding to project subpages. In addition to the named features, two additional pages are transcluded: the /Announcements subpage, which is wikitext, and /Members, which is CollaborationListContent. These subpages are created upon hub creation via Special:CreateCollaborationHub, but if those subpages don't exist, then the hub handles it gracefully.

Example
A sample Collaboration Hub:

{   "display_name": "Project Hampshire", "introduction": "A WikiProject dedicated to the ceremonial county of Hampshire in the United Kingdom.", "footer": "", "image": "Flag_of_Hampshire.svg", "colour": "red", "content": [ {           "title": "WPX:WikiProject Hampshire/Requests", "image": "quotes", "display_title": "Requests" },       {            "title": "WPX:WikiProject Hampshire/Resources", "image": "book", "display_title": "Resources" }   ] }

Let's break this down:
 * display_name – a name to show other than the actual page title (optional)
 * introduction – Some introductory content. Supports any arbitrary wikitext.
 * footer – To display on the bottom of the page. Supports any arbitrary wikitext; you could use this for navboxes, categories, etc.
 * image – An image to serve as an "icon" for the project. Can be any image accessible on the wiki or a key for one of the "canned icons."
 * colour – Can be one of 23 preset colours. The image and colour collectively are the "hub theme"
 * content – the main body of the project. Each object in this array is a "feature," a project subpage containing something of interest to the project. The parameters for the content object include:
 * title – the full name of the page to transclude. Generally, features are subpages of the project, but they do not have to be!
 * image – an icon to use in the hub's auto-generated table of contents, typically one of the canned icons. As with the image parameter above, you could also use an on-wiki image for this (though it probably won't look as good)
 * display_title – Normally the subpage name would be displayed as the section header and table of contents item (e.g. "X" for "Project:Foo/X"), but this parameter lets you override that.

Announcements are shown below the introduction, members in a box to the right of the introduction, the table of contents and the transcluded pages below that, and the footer below that.

Internally there is an attribute called displaymode, set to one of "normal" or "error." It is only used internally. If the page fails to validate against the schema, the displaymode is set to error, and an error message is shown with a text serialization of the offending JSON, internally represented by an attribute called errortext.

Also defined as part of the schema is a "scope" object, allowing the user to define the scope of the project in terms of included and excluded page titles and categories (including to a specified category recursion depth). If you add a scope object to a hub it will pass validation but not actually do anything.

Transclusion behavior
A note on how features are transcluded: there are different rules for how this works with different content models:
 * wikitext – Generic wikitext pages only have the lead section ("section zero") transcluded. This is intentional; this allows the lead to serve as a teaser or summary, with a link in the feature header that leads people to the full page contents.
 * CollaborationHubContent – Only the hub image and hub introduction are presented. This is partly in keeping with the above principle but also because of implementation issues involving how the MediaWiki parser handles transclusion.
 * CollaborationListContent – In the future this will be highly configurable, but for the time being, the default transclusion options are used, which are defined in the  method and currently are:
 * includeDesc (include list description text): false
 * maxItems (maximum number of items to show per column): 5
 * defaultSort: random
 * offset: 0
 * tags: none
 * mode: normal (as opposed to no-img)
 * showColumnHeaders: true
 * iconWidth: 64px

In theory any arbitrary content model could be transcluded, but this has only been tested on the above three (and the UI does not exactly encourage it).

Editing
CollaborationKit extends the EditPage class to build a custom editor for CollaborationHubContent. The first step is to convert the stored JSON into the text/x-collabkit serialization. The format is as follows:

Display name --- Introduction --- Footer --- Image --- Colour --- Features

That's precisely 23 hyphens between each section. To use the above section, the serialization would look something like this:

Project Hampshire --- A WikiProject dedicated to the ceremonial county of Hampshire in the United Kingdom. ---

--- Flag_of_Hampshire.svg --- red --- WPX:WikiProject Hampshire/Requests|image=quotes|display_title=Requests WPX:WikiProject Hampshire/Resources|image=book|display_title=Resources

Each of those sections correspond to input fields on the form.

Let's look more closely at the bottom section. Each line corresponds to a transcluded feature. The first, unlabeled parameter is the full page title. Each subsequent parameter is optional, but includes  which can be a filename or canned icon, and   to use a label other than the subpage name.

If you have JavaScript enabled, the colour dropdown and image input field are replaced with a "hub theme" widget. The image selector in particular makes use of the "media search" widget, formerly a part of VisualEditor but upstreamed to core MediaWiki in 2016.

CollaborationListContent
The CollaborationListContent model represents "Collaboration Lists," which are lists of page titles with associated pictures, notes, and other attributes. The main goal of this content model is to allow users to develop lists of pages to work on that are visually appealing and can be selectively transcluded. In other words, one does not need to transclude the entire list. Through the  ParserFunction, different criteria can be applied. This way, large lists can be embedded in other pages without it being overwhelming.

Example
{   "options": {}, "displaymode": "normal", "description": "Help us with these tasks!", "columns": [ {           "items": [ {                   "title": "Heather Macy", "notes": "Predicted class: Stub" },               {                    "title": "Judith L. Rapoport", "notes": "Predicted class: C"               }, {                   "title": "Catherine King (scientist)", "notes": "Predicted class: C"               } ],           "label": "Assess for quality", "notes": "Determine the quality of these articles" },       {            "items": [ {                   "title": "Monika Auweter-Kurtz", "notes": "German physicist • More information on Wikidata" },               {                    "title": "Maja Žvanut", "notes": "Slovene art historian • More information on Wikidata" },               {                    "title": "Selda Ekiz", "notes": "No English description available • More information on Wikidata" }           ],            "label": "From Wikidata", "notes": "Automatically generated list of missing articles" }   ] }

There are three metadata fields and one large object containing the structured contents of the page:
 * The options object is used to define specific configuration settings for the list. Currently this is not exposed in the UI, and is mostly used internally to render lists in different ways (including by the parserfunction).
 * displaymode is either normal (for a regular list) or members (for a list of project members). There is also a third setting, error, used internally for hubs that do not pass validation. The display mode is not surfaced in the UI, and this is intentional – users should generally not arbitrarily switch between regular lists and member lists. (They technically can, but it makes no sense to.)
 * description refers to opening introductory text and accepts any arbitrary wikitext

Finally, there is the columns array, which is where the content lives. All lists are divided into columns; a flat list technically has one column. There is a hardcoded limit of ten columns on each page. As with the page-wide metadata, each column has these fields:
 * label, which is the text label for the column (optional).
 * notes, a short description placed under the label (also optional).

Within each object in the columns is the list array, containing a list of page titles. Each entry on the list is represented as an object and there is a hardcoded limit of 2000 items per column. The data in each object includes:
 * title, the full page title
 * notes, some short text to place after the title, typically describing the task that needs to be done (optional)
 * image, an image to be shown alongside the list entry. This is optional, and CollaborationKit will try to fetch an image through the PageImages API (if installed and enabled) if no image is specified. Otherwise, a generic page icon will be displayed.
 * link, to link to a page other than the stated page title. This is optional because by default the link is to the corresponding on-wiki page title. If you set this to false there will be no link at all, but you can only do this while editing the JSON directly because otherwise the deserializer will assume you are linking to an on-wiki page called "False" ( as opposed to  ). External links are not supported.

Editing
As with CollaborationHubContent, CollaborationListContent makes use of a serialization to build an editing interface. One of the goals of this interface is to facilitate "bulk editing," whereby someone can dump a whole list of page titles at once instead of inserting them one at a time.

The format is as follows: Description --- Options --- Contents

Within the options block, each individual option is a key-value pair separated by an equals sign. Display mode, technically not an option but a separate attribute altogether, is also included in this block, written in all caps as  to "signify its specialness" according to a comment in the source code.

The contents section is further divided into columns. As noted above, all lists have at least one column. An individual column looks like this:

-~-~- Assess for quality|notes=Determine the quality of these articles - Heather Macy|Predicted class: Stub Judith L. Rapoport|Predicted class: C Catherine King (scientist)|Predicted class: C

That's nine hyphens, a tilde, a hyphen, another tilde, nine more hyphens, a line of text, and then a line of 21 hyphens. Within the line of text is the name of the column, with an optional  parameter separated by a vertical pipe. There must be text here. If you do not want a header for this column, set the name to  in all lowercase letters; this will be interpreted as "do not present a title here." (You do not need to do this when editing JSON directly.) Each individual list item is per line, following a syntax of  with no named parameter. Parameters are separated by vertical pipe; the remaining parameters (image, link) are optional.

Users can also edit the list directly through the list itself through the use of JavaScript widgets. Associated with each list items are three buttons: one to delete the item, another to re-position it via drag-and-drop, and another to edit its values. Those edits are made via the MediaWiki API. At the bottom of each column is an "add" button that makes use of the same UI as the per-item editor.

Special pages
CollaborationKit implements two special pages: Special:CreateCollaborationHub and Special:CreateHubFeature.