Documentation for Kicksecure Wiki Devs

From Kicksecure
< Dev
Jump to navigation Jump to search

Layout, Skin, CSS, JavaScript, Links, Header, Footer, CodeSelect, Mobile Frontend, Miscellaneous

Getting Started - MediaWiki Setup (meta)[edit]

Extension CSS Fork[edit]

  • We use the MediaWiki, but a which we wrote ourselves.
  • The extension and the fork in general have 3 options: One to write page specific inline CSS in the MediaWiki page itself. The second option allows to link locally hosted CSS files. The third option allows to link internal CSS pages raw as files
    • Caution: The first option of this ORIGINAL extension (not our fork) for a page specific CSS seems experimental to us, because the CSS text is encoded as a base64 string and imported link so <link rel="stylesheet" href="data:text/css;charset=UTF-8;base64,I3Np...Q7Cn0=">. This is not widely supported in all browsers so this options does not seem reliable and therefore is not recommended for production use!
  • Our fork
    • Usage option 1 - locally hosted: You can reference locally hosted files, e. g. {{#css:/src-copy/Page_Homepage.min.css?hsversion={{Hsversion}}}} . NOTE: For this the file has to be hosted in the locally allowed folder. In our case this is set to /mw-autogen in localSettings.php via the variable $wgCSSPath which belongs to the Extension:CSS . This means our example {{#css:/src-copy/Page_Homepage.min.css?hsversion={{Hsversion}}}} actually (relatively) references the local file /mw-autogen/src-copy/Page_Homepage.min.css?hsversion=...
      • NOTE: Please ALWAYS use the postfix ?hsversion={{Hsversion}}. This ensures that files are always loaded in their currect up-to-date version
    • Usage option 2 - from the DB: You can reference files hosted in the DB, e.g. {{#css:Mediawiki:Your-local-styles.css}} . This calls the file from the wiki. In our fork we allow the admin to set allowed namespaces, so CSS files in these namespaces are not "sanitized" by Mediawiki which sometimes leads to unexpected problems. In our case we set the namespace "MediaWiki:" to be not sanitized
    • [Generally deprecated] Usage option 3 - inline: [This option should only be used for testing or specific use cases where an interaction with wiki content like templates is strictly necessary] You can write inline code, e.g. {{#css: body { background-color: green; } }} . Our fork implements this as a style-tag (instead of a link tag with base64 like the original extension, see above)
  • MediaWiki upstream: feature requests and patches:

Extension HeadScript[edit]

  • We use the MediaWiki to circumvent the usual code inclusion into the <head> area. This is only used where MediaWiki doesn't offer a realistic option to realize a solution otherwise. See LocalSettings.php for the implementation of Headscript
  • Here is a current snapshot of the content that we include via Headscript
<!-- Begin Extension:HeadScript
* server-type  :  production
* Path to scripts : /mw-autogen
* Wiki page: Dev/mediawiki
* Url query parameter "debug" : undefined
* Url query parameter "dontload" : undefined
* $wgResourceLoaderDebug : "" (empty string)
<script id="js-cookie-script" defer fetchpriority="low" src="/libs/jscookie/js.cookie.min.js?hsversion=2"></script>
<link rel="stylesheet" media="print" onload="'all'" href="/libs/Font-Awesome/css/fontawesome.min.css?hsversion=2" fetchpriority="low">
<link rel="stylesheet" media="print" onload="'all'" href="/libs/Font-Awesome/css/solid.min.css?hsversion=2" fetchpriority="low">
<link rel="stylesheet" media="print" onload="'all'" href="/libs/Font-Awesome/css/regular.min.css?hsversion=2" fetchpriority="low">
<link rel="stylesheet" media="print" onload="'all'" href="/libs/Font-Awesome/css/brands.min.css?hsversion=2" fetchpriority="low">

<link rel="stylesheet" fetchpriority="low" media="print" onload="'all'" href="/libs/Prism/prism.css?hsversion=2" >
<script id="highlight-code-script" defer fetchpriority="low" src="/libs/Prism/prism.js?hsversion=2" data-manual></script>

<link rel="stylesheet" href="/mw-autogen/mw-combined-wikicss.min.css?hsversion=2&version=1706693424">
<script defer src="/mw-autogen/mw-combined-wikijs.min.js?hsversion=2&version=1706693424"></script>

<script type="module" defer src="/libs/"></script>

  @font-face { font-family: Roboto; src: url(/libs/Roboto/Roboto-Regular-webfont.woff?hsversion=2); font-display: swap; }
  @font-face { font-family: Roboto; font-weight: 300; src: url(/libs/Roboto/Roboto-Light-webfont.woff?hsversion=2); font-display: swap; }
  @font-face { font-family: Cousine; src: url(/libs/Cousine/Cousine-Regular.woff?hsversion=2); font-display: swap; }
<link rel="preload" href="/libs/Font-Awesome/webfonts/fa-solid-900.woff2?hsversion=2" as="font" crossorigin fetchpriority="low">
<link rel="preload" href="/libs/Font-Awesome/webfonts/fa-regular-400.woff2?hsversion=2" as="font" crossorigin fetchpriority="low">
<link rel="preload" href="/libs/Font-Awesome/webfonts/fa-brands-400.woff2?hsversion=2" as="font" crossorigin fetchpriority="low">
<link rel="preload" href="/libs/Roboto/Roboto-Regular-webfont.woff?hsversion=2" as="font" crossorigin fetchpriority="low">
<link rel="preload" href="/libs/Roboto/Roboto-Light-webfont.woff?hsversion=2" as="font" crossorigin fetchpriority="low">
<link rel="preload" href="/libs/Cousine/Cousine-Regular.woff?hsversion=2" as="font" crossorigin fetchpriority="low">

<link rel="icon" type="image/svg+xml" href="/favicon.svg?hsversion=2" sizes="any">

<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?hsversion=2">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png?hsversion=2">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png?hsversion=2">
<link rel="manifest" href="/site.webmanifest?hsversion=2">

<link rel="mask-icon" href="/safari-pinned-tab.svg?hsversion=2" color="#5bbad5">
<meta name="theme-color" content="#ffffff">

<meta name="msapplication-TileColor" content="#da532c">
<!-- ------------------------
/End Extension:HeadScript -->
  • Solved by this
    • Font-Awesome is included that way
    • Other libraries are included
    • Our general minified css included
    • Our general minified JavaScript included
  • Additional info : In the top comment there are multiple relevant variables printed in their current state
    • server-type indicates if it's production or development
    • Path to scripts : The path where CSS and JS files are situated
    • Wiki page : The actual url page name for the wiki page. This variable can be used in the script
    • debug : This query parameter determines if the minified version or the readable version is printed (if debug = true)
    • dontload : This parameter offers to not load our auto-generated js or css files. There are 3 options: ?dontload=js ?dontload=css and ?dontload=jscss
    • $wgResourceLoaderDebug is a setting for LocalSettings.php where the whole wiki can go into debug mode. Similar to the url parameter debug
  • Our fonts are now also referenced and loaded with preload this way for better performance. This includes Roboto (regular font), Cousine (monospace font for pre, code etc) and Font Awesome (Icons)
    • Regarding preload a good article as a resource is this:
    • If crossorigin is omitted the fonts are loaded twice due to the crossorigin settings on the server
    • Only preload is possible. defer or async is only supported by browsers for scripts but not for fonts.
  • There are also some additions regarding favicons

File auto-generation, Combine, Minify, Host Locally, mw-autogen, src-copy[edit]

  1. We use #Extension HeadScript to include our own auto-generated files in the wiki page
  2. These files are generated from wiki files, through a specific process using our own scripts
    1. We created file config-build-{shared and specific} In this file we describe a build order for all JavaScript files. And also all CSS files.
      • Note that this file has to have a specific structure. Top level are the keywords "wikijs" (JS applied to the whole wiki), "wikicss" (CSS applied to the whole wiki), "skincss" (CSS only if the custom header is present) and "justcopy" (files that will just by copied, not combined). Also there can be the keyword "__comments" at the top which will be ignored by the parse.
      • Every of those keywords has an array of strings below them. These string should all be callable wiki file pages like "MediaWiki:Header.css" etc. Exception: You can use comments if a string STARTS with "//"
    2. Then we created a php build script which has to be executed and combines all files which are mentioned in config-build-{shared and specific} and which are then loaded from the wiki files pages. After that the build script combines all files and saves them to the folder /mw-autogen as a - what we call - "mw-combined"-file and minifies it and saves it to a second file "mw-combined.min" etc.
    3. These files are then called via #Extension_HeadScript and can also be called in their human readable form if the URL has the parameter ?debug=true
    4. The source files are also copied to a subfolder /mw-autogen/src-copy/ for optional use by other software (e. g. forums) on the same web domain. And for each file a minified version is also created in the same folder [filename.ext] + [filename.min.ext]
  3. specific locations
  4. By these measures we drastically improved the load time of the wiki, made it really stable and functional again and circumvented the use of Common.js as also suggested by Wikipedia
  5. NOTE: By using this solution the source files (css js etc) are not directly called when the page is loaded. They are merely the source which the combined, minified files are rendered from. So every time there is a change in the source files it first has to be rendered to the output files.
    • One exception is the use of Extension:CSS where we want to use scripts only on specific pages like so {{#css:/src-copy/Page_Homepage.min.css}}. In this case the source copy folder is very useful

Javascript specific[edit]

  • We decided to not use Mediawiki:Common.js to implement a lot of JavaScript.
    • Calling a lot of JavaScript files via Common.js lead to unexplainable errors in MediaWiki, even small crashes (site not available even when it was) and considerably longer load times.
    • Our speculation is that Common.js or the mw.loader.load uses some pre-parsing to check if JS-files are safe. Other speculation is that it just creates to much load if JavaScript files are always freshly loaded from the wiki db
    • Even Wikipedia states in their
  • Keep code in MediaWiki:Common.js to a minimum as it is unconditionally
  • loaded for all users on every wiki page. If possible create a gadget that is
  • enabled by default instead of adding it here (since gadgets are fully
  • optimized ResourceLoader modules with possibility to add dependencies etc.)
  • Since custom scripts offer additional functionality but might degrade performance or break unrelated functionality (even noJS functionality such as session handling) they have to be handled with care.
  • As earlier discussed in this chapter Mediawiki:Common.js cannot be used to integrate scripts. However we want to know when Common.js is loaded so we can be sure that the core modules are loaded - specifically jQuery and others
  • Therefore we introduced a Javascript specific wrapper which is used only in generated files for Javascript. This wrapper is not listed in the config-build-{shared and specific} under "generaljswrapper". This file is currently The file will be pulled and then split at the keyword "/*WRAPPEDCONTENT*/". The first part comes before all other Javascript. the second part comes after all Javascript.
  • In the Wrapper you will find that we listen to an event called "mediaWikiCommonJsIsLoaded". This event is triggerd in Common.js and is the only use that we have for Common.js
  • The wrapper also introduces the property mwDev globally into the window object. This is basically a variable for us to share data between scripts and other dev strategies. The data is shared in the sub property
  • Also we use this wrapper for the dontload functionality which you can learn more about in our convenience tool Dev/mediawiki#Debug-via-url-modal for this purpose

Javascript source mapping[edit]

  • In order to be very transparent and debug more easily we decided to use a source map for our combined wiki js file
  • This way developers can find problems and study the source code even though the minified JS file is loaded for normal users
  • Some information on uglify
    • This is the official documentation . But it might be a bit confusing
    • This is the command we're using (only [file-dir] is a placeholder) uglifyjs '/[file-dir]/mw-autogen/mw-combined-wikijs.js' --output '/[file-dir]/mw-autogen/mw-combined-wikijs.min.js' --source-map "base='/[file-dir]/mw-autogen',root='/mw-autogen',url='/mw-autogen/'"
      • The first parameter is the source file
      • --output or -o specifies the target file
      • [DEPRECATED-BY-US] --compress removes unnecessary the code. We don't use this anymore because this led to errors of variables being removed that we actually needed. See
      • [DEPRECATED-BY-US] --mangle "minifies" the names in the code (renames to shorter names if possible and if not accessible to external functions). We don't use this anymore because it's error prone linke --compress
      • --source-map creates the source map
        • All it's sub parameters have to be wrapped in one big quote.
        • base - this sub parameter specifies the base path in the file system. This path will be OMITTED in the source map "sources" property. Example: If a file has /[file-dir]/file1.js and base='/[file-dir]' then in sources it will be listed as "sources":["file1.js"] else it would have its full path
        • root - this sub parameter specifies the url route (path) that the browser needs to find the file. This will be added to sourcesRoot in the source map. Example: If a file has /[file-dir]/file1.js and base='/[file-dir]/' (see description above for this part) and root='/public' then in source map it will be listed as "sourceRoot":"/public","sources":["file1.js"] and the browser would find the source file under /public/file1.js
        • url - the url sub parameter is the browser route (path) to the source map. It tells the browser where the source map is located in case the user (most likely developer) requests the source code


Extension CookieToBodyClass[edit]

  • We created our own Mediawiki extension
  • This extension passes cookies through the server back to a CSS class in the body tag
  • This is especially useful for cookies written with Javascript which then in turn can activate CSS styling AS SOON as the page is loaded and NOT JUST when Javascript is finally loaded. This simplifies styling in some cases extremely because there's no need to wait for Javascript to add some crucial class
  • Usage
    • It's as simple as writing a cookie - via Server or Javascript
    • The cookie HAS TO have the prefix "ctbc_" (which stands for CookieToBodyClass). For example "ctbc_myTestCookie"
    • The value given to the cookie has to be CSS class compatible, a regexp representing this is: /^-?[_a-zA-Z]+[_a-zA-Z0-9-]$/. For example "my-testValue"
    • When the page is loaded the next time this will result in a combination of cookie name and value as a body class. For example <body class="ctbc_myTestCookie_my-testValue ...
    • When the dev has chosen a value that is not CSS friendly, for example "my/testValue", the body class will be a CSS compatible error for the dev. For example <body class="ctbc_myTestCookie_ctbc-error_cookie-value-not-css-compatible ...
    • This error is a compromise so the user does not see any error on the site, but also so the dev has a change to identify and / or catch errors
  • Other use cases
    • This is also an excellent tool for testing: The dev can create a cookie just in his own browser like "ctbc_mycookie" and set it to whatever he likes e. g. "2". Not he can write CSS and JS cases to just react conditionally on this cookie existing. CSS body.ctbc_mycookie_2 .my-class{...}. JS if( Cookies.get('ctbc_mycookie') == '2' ) {...}

Extension BodyScript2 - not in use[edit]

  • We created an extension based on the outdated BodyScript-extension and the still active HeadScript extension
  • With the variable $wgBodyScript2Code in LocalSettings.php we can insert Code at the end of <body> with the help of the hook onSkinAfterContent

Extension Flagged Revisions[edit]

  • We use the Extension Flagged to manage content on our wikis. As our content is security and privacy relevant it would not be acceptable to have unexamined content be shown to visitors. However we are always thankful for good content contributions which are mostly accepted. Flagged revisions prevents unchecked content from being shown to visitors and gives a practical way to manage revisions.
  • The top bar will only be shown to admins if there is a pending revision which the admin then can easily accept
  • The bottom bar is always present and gives admins the opportunity to directly accept and unaccept a revision, give a comment and rate the revision in question for accuracy

Extension Dark Mode (Fork)[edit]

  • We use the extension to offer our users a dark mode experience on our Wikis
  • The extension uses a css filter to invert all colors on the page to dark - except images. We add our own CSS to make the look consistent
  • At the current time (2022-10-25) Tor Browser does not support this mode fully (some weird color glitches) because Tor Browser is currently based on an older Firefox version which had problems with this filter. In the future this will probably be fixed
  • We added a custom button to our custom footer to activate dark mode. This button uses the normal functionality of the extension.
  • Our fork enhances the extension by adding a mode for anonymous users. The original extension saves the "dark mode preference" to the personal user settings of a registered user. Non-registered or non-logged-in users (the majority) therefore have no ability to use dark mode. They can activate it, but once they reload or navigate to another page the dark mode is gone. We fix this by saving the dark mode setting to a cookie with the name "usedarkmode" which is ONLY saved if the user is anonymous and is either "0" (off) or "1" (on). Our fork of the extension will check if this cookie is set to one and activate dark mode - but again ONLY if the user is anonymous. Therefore the basic idea of the extension is kept alive, we just enhanced it for another use case.
  • upstreaming:


  • We maintain multiple wikis for different projects which are very similar in some ways, in particular Kicksecure and Whonix at the moment. We therefore decided to reuse general code on all wikis to avoid code duplication, have consistency and simplify maintenance. "General code" means our own small libraries, usually CSS and JavaScript which are hosted within a separate GIT repository
  • As there is no practical import option for pages, templates and widgets in MediaWiki for our purpose we use a "cascading multi-wiki" approach with the assistance of automated scripting.

JS and CSS files - GIT repo and server deploy[edit]

  • Javascript and CSS files are managed in a GIT repository. These files are called source files and are in differen source folders. The shared folder and one folder for each wiki - at the moment Whonix and Kicksecure
  • Note: One single JS file and one CSS files are not managed in this GIT repository: Mediawiki:Common.js and Mediawiki:Common.css. These files are MediaWiki specific files that cannot be managed outside. Their usage is described in the chapter Dev/mediawiki#Structure_of_our_wikis_.28How_to_build.29
  • The development and deployment cycle work as follows
    1. The GIT repository is locally pulled
    2. The files are edited locally
    3. If there are new files or file dependencies change then the local config build json files are edited to reflect the changes
    4. The changes are pushed to the online GIT repository
    5. On the online GIT repo files a build script is executed on the server which does the following for each wiki
      1. Reads the shared config build file and loads the mentioned source files seperated by categories in their given order
      2. Reads the wiki specific config build file and loads the mentioned source files seperated by categories in their given order and adds them after the shared source files
      3. Renders combined Javascript and combined CSS files for each category and then also a minified version for each
      4. All source files are also copied into a src-copy folder
      5. Finally for each wiki the "distribution" files (combined files and src-copy folder files) are then deployed onto the corresponding wiki server
      6. Build logs : Note, you can check the automatically generated build log files after deployment
  • The GIT repo folder structure is as follows
    • build/
      • build-mw-combine.php
      • config-build-kicksecure.json
      • config-build-shared.json
      • config-build-whonix.json
    • src/
      • kicksecure/
      • shared/
      • whonix/
  • The autogen folder for the rendered files on each server have the following folder structure
    • [wiki-autogen-folder]
      • src-copy/* -- copied source files
      • build-log.htm
      • * // combined files
  • Our main scripts are in the src/shared/ source files. These will always be loaded first and come first in the combined files which are generated by the build script
    • Every wiki also has their own source files which will be loaded and combined later than the shared files by the build script
    • Every wiki source folder and shared folder also has a build config file which determins which file is rendered into which combined file and at which position

Pages, Templates and Widgets - publisher subscriber mechanism[edit]

  • Content pages and wiki internal functionality like templates and widgets cannot be stored outside of the wiki.
  • For this reason we use another strategy and another deployment methode utilizing the category Category:MultiWiki.
  • Specifically we use a deploy script that cascades changes from multiwiki files from the publisher wiki (Kicksecure) to all other subscriber wikis.
  • The whole life cycle
    1. Multiwiki pages are given the category multiwiki (how this is done read below)
    2. Multiwiki pages are added, deleted and edited only on the publisher wiki
    3. To avoid confusion and losses due to edits in the subscriber wikis which are later overwritten by "multi wiki deploy cascade" from the publisher wiki there is Dev/mediawiki#EditorMultiwikiNotice which is an indicator for all editors warning if edits of a multiwiki file are not done in the publisher wiki.
    4. The deployment from the publisher wiki to all the other wikis is done by running mw-multi-wiki (ask admin for directions). This copies all pages, templates and widgets in the Category:MultiWiki from the publisher wiki to all the subscriber wikis and overwrites their previous files
  • To add a wiki page to Category:MultiWiki the following text needs to be added to that wiki page. By convention, it should be in the footnotes or section or very bottom the footer of the wiki page.
    1. If it is a wiki page, add:
    2. If it is a wiki template or a widget, add:
  • Examples
  • Practical example instructions for practice : to start mirroring (cascading), from the publisher wiki (Kicksecure wiki) to a subscriber wiki (Whonix wiki), run: mw-multi-wiki . How to test:
    1. Modify a page that is already in Category:MultiWiki such as Testpage in the source wiki.
    2. Then run mw-multi-wiki
    3. Check for example if Testpage was modified in the destination by looking at its content or Testpage
    4. Note : Pages that have not been changed in the source wiki will not result in a recorded change (null edit) in the destination wiki.

Multiwiki definitions[edit]

There are basically 3 categories for files on our wikis

  1. LocalWiki means: for the local wiki only. This file is not part of the cascading MultiWiki auto deploy
  2. LocalSkin means: for the local skin augmentation only. The skin is also influenced by the "LocalWiki" files, but local skin is even more specific
  3. MultiWiki means: for all wikis, but as general as "LocalWiki".

Structure of our wikis (How to build)[edit]

  1. Our wikis rely on a specific methodology to separate the "backend" from "frontend" look which would usually be the same in other MediaWikis. For page visitors we want to show a "local skin augmentation" which is a more optically pleasing look. This is our own "skin" but not realized as a true MediaWiki skin, but as an augmentation via CSS and JS. But as soon as you edit or go on a special page you get the "common look" of our current MediaWiki skin. This is accomplished by using the Template:Header. Only wiki pages which have {{Header}} will have the special look of our local skin augmentation
  2. Entry points / categories
    1. The relevant files are all found in the wiki build files in the git repository. These files have multiple sections. So these files is a great way to see the application structure. Sections:
      1. wikijs : These files will be combined into one file whose methods will be available on the whole wiki even without the skin applied
      2. wikicss : These files will be combined into one file whose styles will be available on the whole wiki even without the skin applied
      3. skincss : These files will be combined into one file whose styles will only be available of the {{Header}} template is included in a page
      4. NOTE: All of the files in these categories are also copied into a separate source file folder and also a minified version of them. Read more here #File_auto-generation.2C_Combine.2C_Minify.2C_Host_Locally.2C_mw-autogen.2C_src-copy
      5. justcopy : These files will NOT be combined in any way. They will just be copied as described above. Note that these files can be mixed and don't need to be exclusively Javascript or CSS
    2. #Extension_HeadScript - Import combined files This extension is used to import the combined files which were rendered from in the JS and CSS build process
    3. Template:Header / LocalSkin - Import CSS files for local skin pages. This template has a double function. It introduces the "local skin augmentation" as well as its header. Files are loaded using #Extension CSS Fork
  3. Important CSS files
    1. Mediawiki:Common.css / MultiWiki - not in use, but MultiWiki, because it's an important system file
    2. / MultiWiki - Define styles which can be used like tools on the site. This file has styles which can be used for all of our wikis. It's general styles which can be used like tools and boilerplate setup styles for things in all wikis which we need to fix
    3. / MultiWiki - Define styles which make up our "basic" style on all our wikis. This file has styles which can be used for all of our wikis. Boilerplate.css is what all our local wikis skins have in common. It is like LocalSkin.css but for all our wikis. It's also only available if the Header (and therefore LocalSkin) is active
      1. / LocalSkin - Define styles for local skin. This file has styles which will only be active on local skin pages
  4. Important JavaScript files
    1. Mediawiki:Common.js / MultiWiki - Trigger / hook to notify our JS that MediaWiki is ready

Creating a new wiki[edit]

When we create a new subscriber wiki we usually do this

  1. We copy the publisher wiki with all files and later delete what is not necessary
  2. We create a new folder in src with the new wiki name in the GIT repository
  3. We create a new build config json file in the build folder of the GIT repository
  4. We modify the build scripts with the new server IP
  5. We modify the mw-multi-wiki script
  6. Then we can start developing the new wiki

New Vector Skin and Skin Preferences[edit]

  • MediaWiki states:

Over the next few years, we will be gradually updating the Vector skin. Legacy Vector will allow you to view the old version of Vector (as of December 2019). To learn more about the updates, go to our project

For the admin: Here are the MediaWiki settings to remove the skin preference choices

  1. Under
    1. remove "Enable responsive mode"
    2. remove "Adapt layout to screen size on mobile"
    3. $wgHiddenPrefs = array( "skin-responsive", );
  2. Under
    1. remove "Vector legacy (2010) (Preview)"
    2. hide 'Vector legacy (2010)'
    3. keep 'Vector 2022'
$wgSkipSkins = [


  • We MediaWiki's default Vector skin as a base.
  • We avoid custom MediaWiki skins as these break every now and then which then would force us to stick with MediaWiki oldstable or LTS, unable to update to MediaWiki stable. [1]
  • We create Template:Footer and a Template:Header which is manually included at the top (header) or bottom (footer) in all relevant content pages such as Documentation, Download, FAQ and so forth.
    • The header template completely replaces the navigation of the Vector skin and has its own style and JavaScript functionality.
    • The footer template also has its own style and JavaScript functionality.
  • The Header template injects CSS styles from internal MediaWiki:CSS files via our Extension:CSS fork.
    • Example: {{#css:/mw-combined-skincss.min.css }}
    • So only on pages where the header is present these CSS files will apply.
    • This means that for example on Special:SpecialPages the unchanged Vector style will be shown.
    • This solution gives us the opportunity to have an appearance like a new skin while also having the fallback to a clean Vector skin.


  • Sometimes Javascript is only needed on specific pages for specific tasks. This happens very rarely.
  • So we created - a LocalWiki file where the page specific JS functions are combined


  • FontAwesome is used as a local webfont to make the site more beautiful.
  • We use our own implementation via mediawiki extension HeadScript. (See #Extension HeadScript)
  • Therefore it is available on all pages.
  • Only works when JavaScript is enabled.
  • Has a graceful no-JS fallback, in that case simply no symbols will be shown.
  • Loaded using CSS (async). Not loaded using JS. Loading using JS would require a different syntax to use FontAwesome.

Usage Examples[edit]

  • FontAwesome is used on all wiki pages because the supermenu symbols use it.
  • Donors cards are using it.
  • Whonix homepage VPN table is using it.

fontawsome font-display: swap[edit] says

When fonts are loaded with default display settings, like font-display="block", browsers will hide text entirely for several seconds instead of showing text with a fallback font.

Font Awesome 5 Free 900 normal

Add font-display: swap

What we currently have:

<link rel="stylesheet" type="text/css" href="/libs/Font-Awesome/css/all.min.css">

<link rel="stylesheet" type="text/css" href="/mw-autogen/mw-combined-wikicss.min.css">

<style type="text/css">
  @font-face { font-family: Roboto; src: url(/libs/Roboto/Roboto-Regular-webfont.woff); font-display: swap; }
  @font-face { font-family: Roboto; font-weight: 300; src: url(/libs/Roboto/Roboto-Light-webfont.woff); font-display: swap; }
  @font-face { font-family: Cousine; src: url(/libs/Cousine/Cousine-Regular.woff); font-display: swap; }
<link rel="preload" href="/libs/Roboto/Roboto-Regular-webfont.woff" as="font" crossorigin fetchpriority=low>
<link rel="preload" href="/libs/Roboto/Roboto-Light-webfont.woff" as="font" crossorigin fetchpriority=low>
<link rel="preload" href="/libs/Cousine/Cousine-Regular.woff" as="font" crossorigin fetchpriority=low>

There are two different ways we currently add fonts.

  • 1) link rel="stylesheet" for font awesome
  • 2) <style type="text/css"> for Roboto / Cousine

Would it make sense to load font awesome the way Roboto is load?


  • The problem is that fontAwesome is loaded in its own CSS file .../Font-Awesome/css/all.min.css - this means that adding and preloading the font is already done by the CSS. It's probably hard to separate this step from
  • There is a very good post about it here with probably the best quote

You cannot mark it swap by default - this will cause random characters to appear (or in the best case squares). This is a very bad UX.

See the explanation from Google: swap gives the font face a zero second block period and an infinite swap period. This means the browser draws text immediately with a fallback if the font face isn’t loaded, but swaps the font face in as soon as it loads.

This behavior is desired for small blocks of text (e.g. headings). For big chunks of texts you should use fallback for big blocks (e.g. article contents). The block setting gives the user no icons on load and loads them as soon as possible, which is better than broken icons blinking into proper icons.

  • 5 - Font Awesome false positive - yes and no. Font Awesome is using explicitly the standard option font-display:block which Lighthouse does not like because it tolerates invisible text up to 3 seconds. But font-display:swap is not really an option, because in this case a standard font is loaded and only when the special font is ready the standard font is replaced. This is terrible for icons because then you have a lot of ugly box-symbols, that are the replaced by real symbols. Dev could however change to font-display:swap which would make Lighthouse happy. Maybe the box placeholder symbols are not as bad as having no icons at all?
  • Patrick: Font Awesome is not used above the fold. Therefore not important to use placeholders.

MediaWiki Default Links[edit]

The default links in the wiki are realized via the MediaWiki Extension

Wiki editor software enhancements[edit]

  • The standard wiki editor software is enhanced in multiple ways
  • Extensions
  • In-wiki improvements
    • We created a Fullscreen mode for the editor, see #EditorFullscreen
    • We created a saving mode which doesn't reload the page, see #Editor SaveAndContinue
    • We created an auto-backup for wikitext which automatically saves your edits to the browser's localStorage, so you don't lose progress when something goes wrong, see #EditorAutoBackup

MediaWiki limitations[edit]

  • Not everything is easily implemented with MediaWiki. One problem we found is that the page content will always be delivered in div#content
  • This leads to problems when elements need repositioning with CSS especially regarding div#mw-data-after-content which will always be rendered after the div#content and which is inconvenient in our case because the footer should be the last thing which can be seen
  • We solved this in the file where we put the whole div#mw-data-after-content with position absolute "above" the footer so it (and for example the Revision bottom bar) is still usable and not hidden by the footer
  • This might be considered a "harmless" hack. Still it can be deactivated by commenting out the lines in the chapter "Flagged revisions Bottom bar" in

Mediawiki parsing - images and links[edit]

  • Mediawiki is evolving and this sometimes leads to legacy breaking changes
    • One very important development is the move from Mediawiki legacy parser to Parsoid, see and
    • This involves changes in how element are rendered which in turn forces Mediawiki users to change CSS and Javascript, possibly also widgets and templates to accomodate the new structures
    • For example thumbnails e.g. [[File:DALL·E 2023-10-24.png]] were previously rendered as simpler <img> tags and are now enclosed in a more elaborate <figure>, <figcation> structure
    • The team of Kicksecure tried to point out flaws with this approach, especially the problem of legacy breaking updates but were pointed to commit messages at least informing wiki users
  • Link inconsistency between links and images also seems to be a problem - with the legacy parser but also with Parsoid
    • The Kicksecure team pointed out that images with a self reference and links the a self reference are handled differently. While a link is rendered to an a-lement with the classes "selflink mw-selflink", there is no such thing with images which are not identifiable as linking to the very page they're on - a contributor said they could prove different on their own system. But this can be demonstrated on this system
      • Self link Dev/mediawiki
      • Compare to link to homepage Homepage
      • Image link to image source
      • Image link to homepage
      • Image link to this page (self link)
      • The images have links and the syntax is correct as the links work, but there is no "selflink mw-selflink" classes present
    • Parsoid is bound to take over in the future. But currently they are working on applying selflink to normal links. So it will probably still take a lot of time for Parsoid to replace the legacy parser - in this issue there was a reference to the image selflink problem that our team brought up. There seems to be current progress however

Implementation Details (in-wiki)[edit]

Crypto QR Code Image Templates[edit]



  • Footer is implemented in Template:Footer (localWiki). This calls a widget that is multiWiki. Footer.js and Footer.css enrich the footer and there are some slight color variations in LocalSkin.css (see Dev/mediawiki#Multiwiki_definitions)
  • There was an old implementation for the footer which is currently not in use via MediaWiki Extension

<div class="our-special-own-footer"></div>

References and Footer[edit]

The footer is structually (html) positioned in the main content area. The vector skin footer is made invisible so there is no overlap. If references are auto-generated by mediawiki then they are below the footer structure and so they are overlapped, this is not desirable. Therefore it is common practice to always write the "references..." keyword in the page so the references headline is generated above the footer structure


  • Deprecated. Reasons: causes issues with caching, keeps MediaWiki busy, might confuse search engines.
  • RandomNews in the footer shows random whonix wews which are fed from Template:RandomNews
  • The Template is not directly imported into the footer widget, because widgets can take Templates as parameters.
  • The RandomNews template is included in the Template:Footer and made display:none via CSS. If Javascript is present then the RandomNews will be moved to the footer and replace the standard text which is in the RandomNews box in the footer. This happens via

Homepage (/wiki/Homepage)[edit]

  • The Homepage is an improved version of the old Kicksecure plain HTML/CSS based
  • It is realized via Widget:Page_Homepage and
  • Visitors can view it under
    • is the canonical domain name.
    • Implemented using
    • uses Disallow: /wiki/Homepage to avoid duplicate search engine indexing.
      • can of course be index normally.
    • while far from being a secret, a technical implementation detail, should not be shown to users as it would confusing.
    • Editing will result in making changes to
  • Structure
    • The page is wrapped in div with the class section-wrapper
    • Right below there are the sections which can be CSS references via .section-wrapper > div. They all have classes as names that start with section-, e. g. section-banner, section-download, section-press
    • Inside every section there is a div directly below the parent which has the class inner-wrapper, which wraps the inner content and helps with positioning. It is also a resource for future designers to design the content via CSS
    • Right below the section-wrapper there can also be other elements
    • h2 is the standard tag for headlines
  • There are special classes for sections which can be used give those sections a special look
    • dark-section : a dark section has a dark background. It can be combined with row-3- and row-5-sections. The dark section spans over the whole page, while the inner content is max 960px
    • row-3-section : These sections have 3 elements on wide displays, 2 on medium displays and 1 on small displays. They are used for testimonials, features or other text heavy tasks
    • row-5-section : The sections have 5 elements on wide displays, 3 on medium displays and 2 on small displays. They are used for icons and low information items
  • There is also a special class for images image-contain which is optional. By default images are in the background with background-size: cover; so the image always fills the whole area but because of the some parts might a cut. While with image-contain the image has background-size: contain; so the image will be fully visible but not cover the whole area. See example below

Creating a new section

  • copy the following structure inside of <div class="section-wrapper"></div> and exchange yourSectionName by something of your choice
<div class="section-yourSectionName">
 <div class="inner-wrapper">
  • put all your content inside of the div with inner-wrapper
  • if you want to use one of the special classes, put them behind section-yourSectionName in the class attribute


  • If you used row-3-section the direct children of inner-wrapper need to look like this
 <i style="background-image:url('/w/images/thumb/path-to-your-image.bmp');" title="Your title"></i>
  Your text and possibly links


 <a class="image image-contain" href="/your-link" target="_blank" title="Your title"
  Your text and possibly links
  • As you can see: The image can be either realized with an i-tag or an a-tag. But if you use an a-tag it needs to have the class "image"
  • Also note there is an example here for the optional use of image-contain, see the explanation of image-contain from above
  • It is also important to note: You can use h4, p and span elements as content


  • If you used row-5-section the direct children of inner-wrapper need to look like this
<a href="/your-link" target="_blank" rel="noopener">
 <img src="/w/images/thumb/path-to-your-image.bmp" alt="Alt description" />
 <span>Your text</span>

Fixed Header Overlap for anchors[edit]

  • We have a fixed header because this is a modern solution which works good for mobile and desktor alike
  • A usual problem with fixed headers however is that the overlap "jump points" / inner page links / anchor links within the page.
    • So you click a link with # and you jump within the current page to the position.
    • However the fixed header appears on top of the element (e.g. a headline) which you therefore can't see
  • We know 3 solutions to this problem
    • The first one is to position and anchor-element (usually <a> but any element with id-attribute works) enough pixels BEFORE the point where you want to jump
      • This is not possible for us, because were using Vector skin and therefore cannot decide the HTML structure
    • The second solution is to use the CSS property scroll-padding-top. This works in most modern browsers but not always reliably when you have a URL with the # jump point already in it
    • The third solution is to give the element a top padding via CSS and counter via the top margin in the other direction (e.g. padding-top: 50px; margin-top: -50px)
  • Because of the structure of mediawiki and vector skin we use solution two: scroll-padding-top and a version of solution three where we give the headline subelement .mw-headline a padding top which does not show up in the content the element is display inline, but most browser jump to the top position

CSS: Chrome anchor bug with special chars[edit]

  • For the fixed header to work we add a padding to the id-element with the class .mw-headline within the headline (h1-h6), so when jumping the header does not overlay on the headline
  • however this is not working with Chrome when there are special characters in the ID at the moment (2022-02-02) and this [bug seems to be known but] by the dev team
  • to be fair, Mediawiki ultimately causes the problem itself by generating anchor IDs with special characters which is forbidden in HTML. Headline: "What is up?" - ID: #what_is_up?
    • Maybe this can be changed by an extension or by a setting in localsettings.php ?

Table of Contents[edit]

  • toc is auto-generated on top of a page or explicitely by markup in the body
  • we modified toc in its looks and appearance (expand/collapse instead of show/hide)
  • we also prevent selection of the toc numbering. This means the text in span.tocnumber will not be selected and copied. This is useful when copying parts of the toc to post somewhere
    • CAUTION: This unfortunately doesn't complete work in Chrome. If you mark a little bit more than one toc bullet point and have a space, newline or a part of the next bullet point then the tocnumber in between will be copied to clipboard by Chrome. This is undesired behaviour but tolerated

Supermenu and Edit Button[edit]

  • The supermenu template Template:Header passes 2 parameters to the widget Widget:Header : $page and $revision
  • By that the edit link is constructed: /w/index.php?title=<!--{$page}-->&action=edit&oldid=<!--{$revision}-->
  • This means that even the current revision has the "oldid" url query parameter which is not necessary, but at the moment (2022-02-02) and for the foreseeable future will not cause any problems.
  • However if there will be a problem in the future simply go to Widget:Header and change the line to /w/index.php?title=<!--{$page}-->&action=edit
  • Upgrade via JS (2023-02-06) in
    • Via Javascipt it is checked whether in the URL there is a query parameter oldid.
    • The presence of this oldid parameter would indicate that the user visits and old page and therefore if he clicks "edit" he wants to edit based on this old version of the page. In this case the edit link in the super menu will stay as described above.
      • For NoJS users this is the only case.
    • On the other hand if the oldid url query parameter is NOT present then the user would not want to edit an oldid version - even if this version happens to be the current one. This is due to us using the Extension Flagged Revisions. If the extension is late (which it sometmes is) then editing with oldid can cause problems.
      • So if the oldid query parameter is not present in the current page url then via Javascript the href attribut of the "edit" link in the super menu will be manipulated. The oldid parameter will be completely deleted while all the other parameters will stay untouched. Therefore making this link a standard edit link for the page

Combined New Custom Header with MediaWiki Custom Header[edit]

For demonstrative purposes only:

Images, Files and usage of thumb[edit]

Best Practices[edit]

  1. Thumbnails have a specific look to them, but sometimes it is unnecessary to have an enlarge button. Therefore we create hide-enlarge, see #hide-enlarge and thumb-hide-enlarge class
    • We first tried to use frame instead of thumb, as in [[File:abc.png|frame|50px]], but the option frame ignores the forced size by design, see
    • Next we tried border as in [[File:abc.png|border|50px]]. This might be useful in some cases, because it does not ignore forced size. But to make it look like thumb is very time consuming
  2. MediaWiki auto-generates thumbs when give specific links. We use this features for HTML pages (widgets) within the wiki. However there is a problem that these images do not upscale or upscale unpreditably.
    • NOTE: We're talking about the thumb link autogen - not the Mediawiki autogen (wrapper) where mediawiki delivers the original if thumb generation does not work like with [[File:...]]
    • Example: Version works while Version doesn't. The original is 1280px large
    • Now it would be great if thumbs would just always work either by upscaling or by just delivering the original image if the thumb is larger than the original. But as it seems with upscaling (AND the original size too) the thumb does not work
    • We solve this problem with the following best practice
      1. Upload all images way larger than needed
      2. If an existing image does not have a large version try to use an AI image upscaling online tool or create a new representative image
      3. Always use thumb-autogen and give the size in which an image is needed. That way bandwidth is saved and we never need to later applay thumb-autogen selectively
      4. Check if the thumb was successfully generated if not you probably need to upload a larger version

Responsive Thumbnails[edit]

  • Thumbnails are by default made responsive. This leads to a cleaner and more predictable look for users and is also better to handle for editors
  • Thumbnails in this context are defined as
    1. all images that are generated by the [[File...|thumb]] syntax in wikitext.
    2. They have the predictable structure: .thumb > .thumbinner [> a.image] > img
    3. They can be in all parts of the document, not just at the top
  • The responsive behavior of thumbnails is the following
    1. Normally a thumbnail floats at the right side of the document
    2. It can have as much size at it needs. But it can only take 100% width of the screen to prevent over-width problems in the page. (In practical applications thumbs will be much smaller than this to allow content floating left of the thumbnails. Default is 300px.)
    3. Once a certain threshold is reached (and below) the thumbnail switches to 100% screen size (and a bit of spacing) and loses floating
    4. NOTE: Because of this behavior thumbnails do NOT need to be wrapped in Dev/mediawiki#ContentImage_.28Template.29_-_image_wrapper_for_overlenght_images

Back To Top Button[edit]

Illustrative, cropped screenshot of the back to the top scrolling button

Figure: Back to the Top Button

  • Back to Top Button is realized via and which are imported in Common.css and Common.js and thereby available for all pages, including Vector styled pages
  • The button is automatically integrated in all pages and created a button which only becomes visible when the user is scrolling and offers the feature to "jump" to the top
  • has one implicit (but not critical) dependency of FontAwesome for its symbol
    • suggestion: If FontAwesome is removed the <i class="fas fa-chevron-up"></i> can be replaced by <span>UP</span>

Printing pages[edit]

  • We made some effort to make all pages printable (physically with a browser)
  • Simply press Ctrl+P or select "Print page" in your browser to print the wiki page to your printer or as a PDF file
  • We added some print specific styles in
    • Especially important: Usually the browser optimizes the web page for printing and does for example not print background-images. We force the browser to print background-images for all elements with the class "image", because those are basically images, just embedded differently via background-image
      • The CSS command for this is "print-color-adjust: exact;" and "-webkit-print-color-adjust: exact;" for @media print.
      • Elements with "image" often have their own style attached to it. So if there are elements which also need to be printed because they are background-images, but cannot have the specific image styles, then we use "bg-image" (e. g. <i class="bg-image" style="background-image:url(...)"></i>) which has no other style attached to it other than being visible in @media print

Instant Page - Fast Navigation Rendering[edit]

  • We use the Javascript library to speed up the internal page navigation. For Nojs users everything stays the same.
    • Normally a user would navigate to an internal page on the wiki and have the browser load the new page when they click the link
    • With instantpage the new page is automatically preloaded (via Ajax) once the user hovers over the link for some milliseconds
    • This way the new page renders very quickly making navigation and staying on the site much more attractive
  • There's a couple of for the usage
    • Normally the preloading would start 65ms (hard coded preset) after hovering (so the user does not load every link which he does not click) to save bandwidth
    • By using the attribute data-instant-intensity="mousedown-only" the developer can make the linked page only preload after mouse button was pressed (but already before it was released) being more reliable to only load links that the user really wants to visit
    • On some pages with many links the wait time for hovering may need to be increased like data-instant-intensity="150" to preload only after the given amount of milliseconds
    • Elements can be shown as soon as they're visible - good for smartphones - by using data-instant-intensity="viewport" to the BODY tag (the value can also be "viewport-all" which is even more liberal)
  • The official repository is and there are some forks.
  • Whonix admin suggested setting link rel attribute to "prerender" instead of "prefetch" (like it is currently in the library). This would result in an even faster page load experience, since not only are the elements already fetch ("prefetch") they are also readily rendered ("prerender") and will seemlessly replace the page once the link is clicked possibly result in an "instant navigation experience"

Cookie Handling via JS Cookies[edit]

  • We are using js-cookie for Cookie Handling
    • We have been using $.cookie and mw.cookie for cookie handling. Both of which are Mediawiki handlers, mw.cookie is the wrapper for the jQuery plugin. However both of them in some cases are not reliably loaded in time. This leads to this error message "$.cookie is not a function" in the browser console or another message that mw.cookie.get / set is undefined.
    • There is a discussion about this issues here but there seems to be no willingness to further investigate by the mediawiki team.
    • That's why we settled for using js-cookie which is small, fast, very well tested and stable
  • In short there are (1) The main object Cookies (2) The method Cookies.get (3) The method Cookies.set (4) The method Cookies.remove → further documentation here

Exclusion of text parts from search engine indexing[edit]

<div class="robots-nocontent"><!--googleoff: index--><!--noindex-->CONTENT<!--/noindex--><!--googleon: index--></div>

Development Rules[edit]

Every developer please follow these rules and consult with the admin. A wiki is a collaborative process so compliance with the rules makes everyone's life easier. Thank you.


  • no external libraries hosted on third party servers
  • locally running Open Source code: yes
  • external libraries preferred from bookworm
  • non-javascript fallbacks required for any new developments
  • Whonix vs Kicksecure website should look different
  • improve from now ~30% design to ~80% design if the remaining ~20% would take \80% of the time
  • keep Dev/CSS in mind
  • screenshot before / after major changes (will be used for public reports)
  • svg is nice as base format but incompatible with Tor Browser maximum security slider setting
  • keep relative link support

MediaWiki Upstream Bugs Reports and Feature Requests[edit]



Using a really small fork:

  • Whonix-Wiki source code folder (MediaWiki including all extensions) (Whonix-Wiki should be renamed to be more generic) contains a patches subfolder which contains all files which are patched. (LocalSettings.php, robots.txt, mediawiki-widgets-extension.json.)
  • The script wiki-fix-permissions on the server deletes the original extensions/Widgets/extension.json file and replaces it with a symlink in the patches folder, file mediawiki-widgets-extension.json.
  • This patch would be no longer required if Allow API (allow API editing pull gets merged.

Wiki convention regarding Widgets:

  • Widgets shall always be wrapped / encapsulated in Templates and (if possible) never be used except via this Template (or another Template using this widget)
  • Reasons
    • Templates are easier to use for wiki editors.
    • Templates support Special:WhatLinksHere, widgets do not. So we can see where a module is used which makes testing and debugging easier
  • Exception:: In some Widgets we use arrays over which we can loop. This works with Widgets but does not work with Templates. This is also how the Extension:Widgets suggests using arrays. See . Moreover the Extension:Widgets does not allow the modifier "explode" which would usually be used to convert a string to an array in the Smarty template engine. That is why we sometimes use widgets instead of templates. To bypass the "findability" problem of widgets you can search #widget:widget_name to find all Widget instances

Templates - in MediaWiki in General[edit]

NOTE : Most templates - especially those with multiple newlines and (allowed) HTML elements - may not be used in lists (numbered / bullet points) at the moment. They do not work there as expected. This is caused by a bug in the MediaWiki parser that has been reported

Developing templates[edit]

When developing templates there are a couple of rules and best practices to go by

  1. Templates with HTML : In MediaWiki it can happen that a template which uses the limited allowed HTML in wikitext works fine on a plain level. But once the template is deployed in special circumstances, for example as a list item, it not only not works but is "ripped apart", meaning the inner elements are rendered not inside but AFTER their parents. This happens due to mediawikis template parser and might even be considered a bug. -> Wikitext Parser Bug when using template inside
    • Example Code # TemplateTest1 <span class="parent"> <span class="child"> Text </span> </span> # Page * Bullet Point 1 * ((TemplateTest1)) (but with real syntax) * Bullet Point 3
    • This results in span.child being rendered after span.parent. But this only happens in special contexts like as a list item. In normal wikitext this works
    • Solution for the time being: Spare all line breaks and unnecessary spaces. The latter because sometimes a space is interpreted as an indentation and leads to rendering as a pre element. Solution example: <span class="parent"><span class="child">Text</span></span>


Performance Testing[edit]

  1. We have implemented a couple of performance testing measures
  2. The test results are documented here: PerformanceTests
  3. The relevant Files are
  4. In MwCombineJsWrapper there is the function window.mwDev.test.pageLoading which measures different (manually triggered) events and outputs the difference between all of them
    1. The two events currently in use are "pageLoadStart" and "pageLoadFinished". These are written to the console directly.
    2. For each event there's the time of occurrence and the diff to all previous events
  5. In MwCombineJsWrapper there is also a functionality which gets activated if the url query parameter ?delayedPageLoad=true is used
    1. This hides the page for 20 seconds after it is loaded and then makes the page reappear
    2. This is done to test whether gtmetrix and pagespeed ignore Javascript or really reander the pages property. Our research from 2022-10-15 shows the both testing pages correctly hid the page and therefore reacted to the javascript correctly
  6. In JsPerformanceTests there are these functions. The can be called in the browser console or in other scripts. mwDev is in the global namespace
    1. mwDev.test.jsJammer = function( bursts = 10, pause = 300, runs = 100 ) : This method will create 1 millions times bursts (of heavy processor load) with pauses in milliseconds for given amount of runs (repetitions). This is to slow down the browser and create a low performance browser scenario for testing reasons.
    2. mwDev.test.scrollPageTest = function( time = 600, runs = 10 ) : This method will scroll the whole page up and down in the give time milliseconds for the given amount of runs (repetitions). One run down will take time to complete. The measurement however is down and up again, so time * 2. Against this will be measured the time it actually took to scroll the page. The difference should give a hint if the page is performing well or not

Development: use files only if needed[edit]

Bug report to upstream[edit]

Sometimes (seldomly) there needs to be a bug report or feature request or suggestion to upstream. Below are the necessary steps for this, demonstrated on a real request which we sent

Example: gerrit patch compare

git clone mediawiki-extension-css

cd mediawiki-extension-css

git fetch refs/changes/96/759196/1

git checkout -b change-759196 FETCH_HEAD

git remote add adre

git fetch adre

git diff -C adre/all-css

Image Optimizations[edit]

Image Optimizations Installation[edit]

sudo apt update sudo apt install mat2 optipng jpegoptim webp

mat2 - strip of metadata[edit]

To strip files of meta data use mat2 on linux.

Strip images of metadata in place - in the directory where you're in. Caution: Might reduce quality or totally break images in case of SVGs!

mat2 image-file-name

If that fails, try:

  • mat2 --lightweight image-file-name
    • Minor space saving effect on images that have been created using gimp.
    • Removes metadata.


  • mat2 --show original-file-name
  • mat2 --show cleaned-file-name

PNG Optimizations[edit]

Specifically for PNG.

optipng -quiet -o7 -zm9 -zc9 -zm9 -zs3 -f5 --strip all -preserve image-file-name

JPG and JPEG Optimizations[edit]

Specifically for JPG and JPEG.

jpegoptim --quiet -o --strip-all image-file-name

Convert to WEBP[edit]

Convert to WEBP.

cwebp -mt -lossless -z 9 input-file-name -o output-file-name.webp

SVG Optimizations[edit]

SVG Optimizations - Introduction[edit]

WARNING: SVG is particularity vulnerable to metadata!

1. Saving the SVG as "optimized" in inkscape as this might be more reliable than scour.

2. Try scour (documented below).

3. Check image quality. If unchanged, keep changes by scour. Otherwise, revert.

4. Try svgo (documented below).

5. Check image quality. If unchanged, keep changes by svgo. Otherwise, revert.

6. Check image for metadata using text editor.

Open in a text editor and search for file paths containing Linux user account name.

7. Check image for metadata using other tool.

TODO: Did we use any? If not, skip.

8. Upload.

9. Done

SVG Optimizations - scour[edit]

WARNING: scour can break the SVG!

scour --enable-viewboxing --enable-id-stripping --enable-comment-stripping --shorten-ids --indent=none -i input-file-name -o output-file-name

SVG Optimizations - svgo[edit]


SVG Optimizer is a (Node.js-based) tool for optimizing SVG vector graphics files.


Install re.sonny.OhMySVG via flatpak.

1. Select your platform.

A : Kicksecure



2. Add flathub repository.

Follow the instructions to Enable Flathub Repository The Web Archive Onion Version .

3. Install the flatpak re.sonny.OhMySVG package.

flatpak install flathub re.sonny.OhMySVG

4. Done.

The procedure of installing re.sonny.OhMySVG is complete.

5. Upgrades notice.

Note: this procedure will not keep the software up-to-date. How to update installation installed by flatpak is also documented on the Operating System Software and Updates wiki page.

B : Kicksecure-Qubes Template


Kicksecure-Qubes Template (kicksecure-17)

2. Add flathub repository.

Follow the instructions to Enable Flathub Repository The Web Archive Onion Version .

3. Install the flatpak re.sonny.OhMySVG package.

http_proxy= https_proxy=$http_proxy flatpak install flathub re.sonny.OhMySVG

4. Done.

The procedure of installing re.sonny.OhMySVG is complete.

5. Upgrades notice.

Note: this procedure will not keep the software up-to-date. How to update installation installed by flatpak is also documented on the Operating System Software and Updates wiki page.

C : Kicksecure-Qubes App Qube

Kicksecure-Qubes App Qube (kicksecure)

2. Add flathub repository.

Follow the instructions to Enable Flathub Repository The Web Archive Onion Version .

3. Install the flatpak re.sonny.OhMySVG package.

flatpak --user install flathub re.sonny.OhMySVG

4. Done.

The procedure of installing re.sonny.OhMySVG is complete.

5. Upgrades notice.

Note: this procedure will not keep the software up-to-date. How to update installation installed by flatpak is also documented on the Operating System Software and Updates wiki page.


flatpak run re.sonny.OhMySVG


Using HTML comments as spacers in Templates[edit]

  • We realized that MediaWiki seems to render (seemingly) unnecessary p-paragraphs if there is a gap between templates used in a page. This leads to unwanted spacing. But if we do not use newlines then the code is very hard to read
  • This seems to be standard behavior and not a bug, as also reported here, especially when dealing with div-elements
  • In this link there is also a suggestion to deal with the problem: adding HTML comments as spacing like so
  • This would also apply for using templates like so


  • This is not the most beautiful solution, but better than the alternative having to write everything in the same line
  • This should not be used permanently. We occasionally use this as a workaround until this is fixed by MediaWiki

Debug Images Cache[edit]

webp images are automatically created from jpg, jpeg and png once per day on the server. Modern web browser are sending the accept HTTP header. The browser is using that header to advertise that the browser supports for example the webp image format. If the HTML markup contains a request for a jpg, jpeg and png but a a webp is already available and the browser supports it, the webp will be delivered instead.

This can sometimes be confusing.

To explicit download the original image format it is the easiest to use a command line downloader such as wget. This works because command line downloaders are in the experience of the author not sending the accept HTTP header. Hence, the server will deliver the actual file and not "upgrade" to webp. For example:

wget ''


curl -O ''

To debug if the image is a jpg, webp or otherwise use the commands.


curl --silent --head '' | grep content-type:

content-type: image/jpeg

curl --silent -H 'accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8' --head '' | grep content-type:

content-type: image/webp

Stage / Staging Server Testing[edit]

  • For each Whonix and for Kicksecure there are staging servers to test new developments and new wiki version as close to production as possible
  • Devs, please ask the admin for details about the IPs and how to setup your system to reach the staged servers
    • If you're on a Linux system admin will ask you to add to lines to your /etc/hosts. Admin also has a shell script available to simplify this process.
    • After that the URLs and will point to the staging servers, not to the production servers.
    • Possible errors : BEWARE however that some browsers that use special proxies or DNS over HTTPS (like Waterfox) will ignore the /etc/hosts file.
    • Please use the following verify method to check whether your system connects to the staging servers correctly
    • And also learn how to use the Dev/mediawiki#StageServerNotice to identify that your browser really shows the staging server
  • Verify IP: To verify whether your switching to the staging server is successful, execute this command on the shell curl --silent --head --header "nocache: true" ""
    • If you're on the staging server the expected outcome is x-server-type: stage, if you're on the production server the expected output is x-server-type: production
    • Note: Linux distribution specific: On Linux systems you can also use nslookup [domain] or dig [domain] +short , for example dig +short to check the URL that your system associates the URL with.
    • Be aware that none of these systems are perfect, so be sure to double check
    • Broken on Debian. Both dig and nslookup are ignoring /etc/hosts. Double checked by Patrick.

Code Resources for MediaWiki[edit]

As inspiration or directly as a code source.

Example Pages for CSS Enhancements[edit]

BIMI Images[edit]

Instructions to create a bimi logo from an inkspace svg (tested method)

  1. open logo in inkscape
  2. Save as -> optimized SVG, choose "remove meta information"
  3. open logo in gedit (or similar)
  4. in svg-tag remove x= and y= attributes and use version="1.2" attribute and add (if not present) baseProfile="tiny-ps" attribute
  5. add title="your-title" attribute directly under svg tag. your-title can be your company or product name
  6. optionally add desc="your-description" directly after title tag. your-description can be a description of your company or product
  7. remove all animations from logo (if present, usally not)
  8. Upload to wiki
  9. Check with


MediaWiki Purge : deleting cached file[edit]

If you click purge on page or use the respective urls (examples below) then the cached file on the server is deleted and you should get the newest version

mediawiki cache purge:

nginx Cache Bypass[edit]

nginx bypass cache example (not really deleting the cache either yet):

If successful, the HTTP response header x-cache-status will show BYPASS.

x-cache-status: BYPASS

MediaWiki special resources[edit]

Those are hard to find via Google, so they are listed here

Special code resources (possibly outdated)[edit]

Debugging CSS JS mw-autogen[edit]

1. Check:

Are all files there?

2. MIME type issues? / content-type: text/html?

Is the file even there?

3. Custom CSS JavaScript Debugging

Debugging Browser Console Errors[edit]

It is useful to enable MediaWiki (JavaScript) debug mode. To do so...

1. go to

2. click edit

3. the link being opened will be:

4. replace action=edit with debug=true

5. press enter to load the page

5. or skip the previous steps and direclty to to

6. consider FAQ with Testpage16 or so

In result in the browser console the scripts in the Debugger part are no longer minified and easier to read.

Search Suggestions Debugging[edit]

  • Vector legacy uses:
    • curl --head
  • Vector 2022 uses:
    • curl --head
    • This was broken in past due to an nginx configuration issue. rest.php was reachable but rest.php/v1/ etc. was not.

Check if scripts are loaded[edit]

These scripts were used for debugging scripts while es special MediaWiki skin was applied

Using a desktop browser with mobile skin these scripts get loaded:

* https://www.{{project_clearnet}}/w/load.php?debug=false&lang=en&modules=jquery%2Cmediawiki&only=scripts&skin=minerva&version=obJk0fES
* https://www.{{project_clearnet}}/w/load.php?debug=false&lang=en&
* '''https://www.{{project_clearnet}}/w/load.php?debug=false&lang=en&'''
* https://www.{{project_clearnet}}/w/load.php?debug=false&lang=en&modules=mobile.toc%7Cmobile.toc.images%7Cskins.minerva.tablet.scripts&skin=minerva&version=6b1c9eeeb881
* https://www.{{project_clearnet}}/w/load.php?debug=false&lang=en&modules=startup&only=scripts&skin=minerva&target=mobile

But using the emulated mobile device with the same skin only these get loaded:

search for


the error only occurs when a mobile device is used and the mobile theme is active

Test user agents[edit]

Test which different responses the server sends to different user agents

curl > 1

curl --user-agent "" > 2

curl > 3

curl --user-agent "" > 4

curl --user-agent "" > 5

curl > 6

meld 1 2

Caching or not caching[edit]

We send a cookie to the server. If the server sends back the same header for both request then caching is off

curl --head --cookie cookie_name=cookie_content

curl --head

TOR browser testing of Javascript scripts to prevent NoScript bugs[edit]

  • It is strongly suggested to to test all new Javascript scripts and modifications with Tor browser or a browser that has NoScript installed but with lowest / off settings
  • NoScript sometimes influences the execution of scripts even if it's set to "not interfere". This can maybe be considered a NoScript Bug. But it is essential to test for NoScript bugs and optimize our scripts to that effect anyways because NoScript is standard on Tor browser and Tor users are a large target community using Whonix and Kicksecure
  • So every time a new script is written or a script is modified check with Tor browser Standard security setting if everything is still working

Using JSHint and other Javascript analysis tools[edit]

Bash script to remove duplicates


#set -x
set -e

test -r js.txt

   "'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz)."

trim_all() {
    # Usage: trim_all "   example   string    "
    set -f
    set -- $*
    printf '%s\n' "$*"
    set +f

while read -r line ; do
  trimmed_line=$(trim_all "$line")
  first_word="${trimmed_line%% *}"
  rest_of_line=$(echo "$trimmed_line" | cut -d' ' -f2-)

  for val in "${skip_values[@]}"; do
    if [ "$rest_of_line" = "$val" ]; then
      continue 2

  echo "'$rest_of_line'"
done < js.txt

EXPORT to new wiki[edit]

If new wiki shall be created which is similar to the current master (Kicksecure) you can use the Export function to export all necessary pages and files (e. g. images) and then import those files in the new clean slate wiki.

CAUTION: This export is different from the export cascade from Kicksecure (master) to the "slave" wikis. All new design and code inventions on the Kicksecure wiki will be mirrored towards the "slave" wikis once they are finalized and tested. See #MultiWiki for more information. But this export here is for creating completely new wikis as a copy of the Kicksecure wiki.

In the last main export event (2022-03-19) the following files were exported. To repeat this process

  1. copy the following files
  2. insert into Special:Export and save the resulting XML-file
  3. go to [new_wiki_domain]/wiki/Special:Import
  4. Use the following Interwiki prefix: en
  5. copy the following list and paste into the import list on the Special:Import page
    CAUTION: This list does not claim to be complete or accurate or up-to-date. If you want to be sure you have to check the complete list and remove old files and add new ones. This list is just meant to save you time. Also be so kind to update the list if you have created a new more accurate up-to-date list.

Show Export List

MediaWiki:Common.js MediaWiki:Common.css MediaWiki:BackToTopButton.js MediaWiki:BackToTopButton.css Template:Download Button Widget:Download Button MediaWiki:Download Button.css MediaWiki:Download Button.js Template:CodeSelect Widget:CodeSelect MediaWiki:CodeSelect.js MediaWiki:CodeSelect.css Template:Archive_link Widget:Archive_link MediaWiki:Archive_link.css MediaWiki:Bootstrap Fixes.css Widget:Subdomain link Template:Subdomain link File:Magnifying-glass.png File:Support-premium.png File:Support-plus.png File:Support-free.png File:Mastodon-logo.png File:Twitter-logo.png File:Reddit-logo.png File:Facebook-logo.png File:Donate-banner.png File:Evolution-host.png MediaWiki:SaveAndContinue.css MediaWiki:SaveAndContinue.js File:Chevron.png File:X.png MediaWiki:Vector.css MediaWiki:EditorFullscreen.js MediaWiki:EditorFullscreen.css MediaWiki:LocalWiki.css MediaWiki:Dev.css MediaWiki:Fonts.css Template:Header Widget:Header MediaWiki:Header.js MediaWiki:Header.css Template:Footer Widget:Footer MediaWiki:Footer.js MediaWiki:Footer.css MediaWiki:ScrollableIndicator.js MediaWiki:Mininav.css MediaWiki:Sitenotice Widget:Sitenotice MediaWiki:Sitenotice_id MediaWiki:Sitenotice.css MediaWiki:Sitenotice.js MediaWiki:Hide siteNotice.css File:Grow-symbol.png File:Qr-logo-v2.png MediaWiki:Donation_Panel.css MediaWiki:Donation_Panel.js Widget:Donation_Panel File:Affiliate 128.png File:CAD 128.png File:CHAPS 128.png File:BACS 128.png File:FasterPay 128.png File:WireTransfer 128.png File:ACH 128.png File:Swift 128.png File:DirectDebit-card-dark 128.png File:Sepa-Last 128.png File:Sepa-card-dark 128.png File:IBAN 128.png File:AUD 128.png File:GBP 128.png File:Discover-card-dark 128.png File:UnionPay-card-dark 128.png File:AmericanExpress-dark 128.png File:Dollar 128.png File:Euro 128.png File:Bank-dark 128.png File:MasterCard-dark 128.png File:Visa-card-dark 128.png MediaWiki:PayViaPaypal.css MediaWiki:PayViaPaypal.js File:Payment-generic-symbol.png File:Crypto-generic-symbol.png File:Credit-card-generic.png File:GiroPay-card-dark-enlarged 128.png Widget:Expand_or_Collapse_All MediaWiki:ExpandAndCollapse.js Widget:FlyInNotification MediaWiki:FlyInNotification.css MediaWiki:FlyInNotification.js MediaWiki:Hide flyInNotification.css Template:Pay bitcoin qr Template:Pay bitcoin qr imgurl Template:Pay monero qr Template:Pay monero qr imgurl Template:Pay ethereum qr Template:Pay ethereum qr imgurl Template:Legal documents Template:Hide all banners Template:Support Choice Donate Template:Payments Donate/Affiliate Link Donate/Bank Wire Donate/Bitcoin Donate/Credit Card Donate/Crypto Donate/EUR Donate/Ethereum Donate/GBP Donate/Monero Donate/PayPal Donate/Tax-Deductible Donate/USD Donate Bitcoin Donate Ethereum Donate Monero Donate by Affiliate Link Template:Donation mininav

USAGE : Module Documentation (Alphabetical order)[edit]

AddMessageToCopiedText (Copyright text injection)[edit]

  • Message injection via javascript has legitimate applications, like original source websites injecting their copyright.
    • Using this hidden text attacks are a less frequent than other attacks but are still relevant attacks on users in the context of phishing and malware. You can read more about them here Shell
    • The Whonix and Kicksecure team uses message injection to insert copyright into copied text from the website (with protected elements like CodeSelect, pre, quotations and others being exempt)
    • This is also intended to be a demonstration of the dangers of "mindless" text copying from websites as described in Shell
  • Details
    • The script is executed on all non-internal pages, meaning all pages NOT starting with /w/index.php
    • The currently protected (exempt from copyright injection) elements are by their selectors pre,code,blockquote,.pre,.code-select,.code-select-target,textarea,.wikiEditor-ui-text,.mw-headline
    • When any other element is selected and ctrl+c is pressed or context-menu>copy is clicked the text that is copied to clipboard gets our copyright message added at the end
    • Mixed selections, like starting in a protected element but in a not-protected element - will also get the copyright injection
  • Relevant files

Anchor - manually placed anchors[edit]

  • Template:Anchor is a span element with the class "manually-placed-anchor"
  • It has 1 anonymous parameter which sets the id attribute for the span element
  • CSS: The element has no dimension and is relatively positioned above it's normal position about the amount that the Header is high. That way if the anchor is called the header does not overlap the anchored position. This is especially useful when referencing headlines
  • It is usually used to manually set anchors to make old links work with new headlines
  • Example: {{Anchor|my_id}} creates <span class="manually-placed-anchor" id="my_id"></span>
  • Relevant files

Anti-Spam email tooltip[edit]

  • Contact emails are sometimes abused by spammers. To deter some of them the template for the email contact has been upgraded to show a tooltip when hovering over it.
    • The tooltip itself can be hovered over too to copy information or click links
    • Icons can be used, instead dots will be used as bullet points as default
  • USAGE :
    • Example (hover to see tooltip):
    • If a dev or editor wants to change the template, empty
      elements will create dot bullet points, font awesome i-elements will create icon bullet points. For font awesome be sure to use fa-fw for unified widths
  • Relevant files

Archive_link (Template)[edit]

  1. Archive_link creates a custom absolute link with an auto-created link to web archive and multiple options. It structurally mimics the MediaWiki extension "Link to archive".
  2. Documentation for wiki editors: Dev/wiki#Links
  3. It is realized via the files
    1. Template:Archive_link
    2. Widget:Archive_link
  4. Detailed Documentation
    1. This template is based on the widget Archive_link and uses styles from Archive_Link.css .
      1. Don't use the widget directly, only the template
    2. It is designed to display an external link in different ways: (A) as link without any additions (B) as a link with small logo links behind it symbolizing alternative addresses (onion or archive)
      1. Caution: As all links are external, the target attribute will be set to "_blank"
    3. Parameters
      1. url | string, default: "" - the url you want to link to
      2. text | string, default: "" - the link text displayed in the main link
      3. archive | string, default: "auto" - if not "none" then there will be a logo link to an archive page of the given url. Options are (A) "auto" - where the archive link is auto-generated from the url (B) "copy" - where the link is exactly copied from the url (useful when url is already from and (C) none - where no logo link is shown
      4. onion | string, default: "none" - if not "none" then there will be a logo link to an onion url. Options are (A) none - no logos is generated (B) "copy" - where the url is copied to the logo link (useful if url is already onion link) and (C) [onion-url] - a real onion url which is an alternative url to the main url. Note: If onion is an url or onion is "copy" then the link will have rel="nofollow" to prevent broken links for search engines. In the case of "copy" the main link will also get "nofollow" because it then is obviously an onion url too

Example Usage

{{Archive_link|text=Whonix Clearnet|url=}}

Box and MBox[edit]

  • These are 2 templates which are used to create special text boxes
  • Template:Box is a container usually for text. Template:Mbox uses Box and integrates an image into it
  • Box uses the design class "info box", see #info-box class
  • Box has these parameters:
    • |text= : text can have every text (including html)
    • |addToClass : addToClass can have every legitimate CSS class to style the class
    • Box can also have one anonymous parameter instead of text {{Box|text=Hello World}} has the same result as {{Box|Hello World}}
  • MBox has the parameters like Box plus:
    • |image= : using an image called via [[File:...]] - NOTE: We highly suggest using the link-parameter of File, because it is rarely sensible to use the link to the image file in this context
    • |icon= : instead of an icon a Fontawesome icon can be used. Here you only have to give the class names name "fas fa-info" or extra classes that will be added to the <i> element like our #Color schemes
  • special class "ib-for-thumb" : This can and should be used for info-box elements (Box and MBox) that are next to the thumbnail. If these have the class "ib-for-thumb" then the info-box will not be very thin and unreadable for small devices but will be cleared and moved to its own line. Examples

{{mbox | image = [[File:Kicksecure-seal.svg|40px|alt=Test]] | icon = fas fa-info cs-red-light | addToClass = ib-for-thumb | text = My Text here }}

Test My Text here

In the above example icon and image are both used which is not very sensible. Mostly either image OR icon is used

{{box | addToClass = ib-for-thumb | text = My Text here }}

My Text here


  1. CodeSelect creates a multiline text area or an inline text field to display code or technical information
    1. It has a button to copy all text to the clipboard
    2. Also all text will be marked if the user clicks into the text area
    3. Is NoJS (no-JavaScript) compatible. In NoJS mode the copying button is not shown but text is markable and copyable. In NoJS CodeSelect in icon mode (data-button-image-src) will completely be hidden.
    4. CodeSelect auto-highlights text which is in specific languages. Supported languages: bash, markup (includes html,xml,svg,mathml,ssml,atom,rss), shell session
  2. These are the files for CodeSelect
    4. Template:CodeSelect
    5. Widget:CodeSelect
  3. USAGE, parameters :
    1. code (mandatory, wikitext) : This parameter can be text of all kinds. It can even be HTML (in HTML mode)
      1. Example : {{CodeSelect|code=echo "Hello World"}} renders to echo "Hello World"
    2. inline (optional, boolean) : This parameter makes the CodeSelect box an inline element which flows with the text instead of a block which it usually is
      1. Example : {{CodeSelect|code=echo "Hello World"|inline=true}} renders to echo "Hello World"
    3. lang (optional, string, default: "bash") : When specified this parameter can select a specific language which should be highlighted in the CodeSelect box (for example: bash). A specific keyword is "none" meaning no highlighting will take place
      1. Example : {{CodeSelect|code=echo "Hello World"|lang=none}} renders to echo "Hello World"
    4. buttonImage (optional, string) : We introduced a mode to now make CodeSelect a simple button to copy code or text to the clipboard. Use buttonImage and the code box changes to a simple button. Add the buttonImage-parameter specifying the image source url.
      1. Note: Don't use the [[File:...]] call, just a url, for example a relative url like /w/images/a/bc/def.jpg
      2. Note: The image gets an automatic hover effect (= -3% brightness), but all is controllable via CSS
      3. Note: buttonImage is usually loaded lazily, meaning the image has the attributes decoding="async" loading="lazy". If you want to prevent this use the parameter buttonImageEager
      4. Example : {{CodeSelect|code=echo "Hello World"|buttonImage=/w/images/8/8c/Supermenu3.png}} renders to echo "Hello World"
      5. Note: buttonImage can also be used with an empty String or just as an empty attribute. In this case the usual copy icon will be shown.
        1. Example : {{CodeSelect|code=echo "Hello World"|buttonImage=}} renders to echo "Hello World"
    5. buttonImageEager (optional, boolean) : Normally buttonImages are loaded lazily. Use this parameter to force eager loading (this omits the attributes decoding="async" loading="lazy"
      1. Example : {{CodeSelect|code=echo "Hello World"|buttonImage=/w/images/8/8c/Supermenu3.png|buttonImageEager=true}} renders to echo "Hello World"
      2. target (optional, string) : This parameter takes a selector of an element in the DOM (id, class, complex selector). If the element is found then CodeSelect will become a button to copy this elements content to clipboard. NOTE: Always be sure to select a specific target where the selector only finds 1 element. Otherwise the first element which is found will be chosen by the algorithm.
      3. Detailed functionality
        1. CodeSelect will be MOVED from its current location in the DOM BELOW the target and inside a helper DIV.
        2. CodeSelect will be in button form, which means it will get the attribute data-button-image-src, but with an empty string (except if this parameter is already specified then this will not be overridden).
        3. CodeSelect will be positioned via CSS over the target element on the top right side.
        4. HIGHLIGHT: Usually the code box of CodeSelect is syntax highlighted. With a target the target gets highlighted instead. This can be prevented by setting the "lang" parameter to "none". NOTE If the target gets highlighted the style of the target might change - for example a pre-element will look more like a code box
        5. Clicking CodeSelect will EITHER select the TEXT content of the target. This is only if the parameter code is NOT GIVEN. OR it will ALWAYS select the content of the code-parameter IF GIVEN. The latter option is optimal for the use case IF the target has some formatting going on and it may be not clear if all browsers will select the text correctly despite the formatting. In this case simply put the correct text into the CodeSelect code and give the element as target. The element's actual content will be ignored in this case.
        6. Clicking on the target element will mark all the text in the target element (but not copy automatically). This mimics the normal behavior of the CodeSelect code area
      4. NOTE: If the target-parameter is used the insertHtmlMode will be ignored (because it's always only text) and the inline parameter will be ignored (because it's positioned and not in the text flow).
      5. Example : {{CodeSelect|target=#my-codeselect-target-example1}} will render to see below
This is
example 1
$ sudo apt "example1"
    1. CodeSelect is realized as a jQuery extension. This is availabe after CodeSelect.js has been initialized (see build order in config-build-{shared and specific}
      1. You can call $(selection).codeSelect(action) - with action currently only allowed as 'init'. This will initialized all CodeSelect boxes in the selection. Double initializations are prevented
    2. CodeSelect is semi-dependent on For highlighting functionality CodeSelect depends on Prism, but CodeSelect can run without
      1. Currently the default is bash. If you want to change the default go to and change defaultLang at the top of the file
      2. The standard bash language definition by Prism was modified by us using the extension syntax Prism.languages['bash'] = Prism.languages.extend('bash', { ... } );. The ".extend" function creates a deep copy of the grammar and assigning it to "Prism.languages['your-language']" creates a new grammar, that will be used. We copied the grammar pattern for the "function" construct from the prism.js file and extended it by some other keywords, see for our application and for more information. If you just want to add more keywords go to to the line var highlightBashAdditionalFunctionNames = [...] at the top and add more function names to the array. NOTE: Be sure to NOT set the async (second) parameter to true when using the "highlightElement" function as it may cause errors due to a likely bug in the Prism software
      3. For a download of newer version in the future go to and choose the languages we support (see above). Ask admin how to implement those files.
    3. insertHtmlMode : This gives the opportunity for Devs to insert structured HTML into the code box, not just text. This is useful if CodeSelect is used in another widget or for special demonstrations. To use it reconstruct the codeSelect widget and just add the class insert-html-mode. NOTE: This parameter sets the parameter lang to "none" because it does not work with highlighting
      1. Example. <span class="code-select">More <b>Info</b> here</span> More Info here vs <span class="code-select insert-mode-html">More <b>Info</b> here</span> More Info here

Community Support Template[edit]

  • To clarify for users that a section or a whole page is not supported by Kicksecure developers there is the Template:Community_Support which renders an info box describing that either the page or the chapter are only supported by the Kicksecure community, not the developers.
    • {{Community_Support}}
    • scope (page|chapter, default:page) : The parameter scope determines the scope of the message. scope=page (default) is red and more pronounces, scope=chapter is more suble
    • See examples below
  • Relevant files

Info COMMUNITY SUPPORT ONLY : THIS WHOLE WIKI PAGE is only supported by the community. Kicksecure developers are very unlikely to provide free support for this content. See Community Support for further information, including implications and possible alternatives.

Info COMMUNITY SUPPORT ONLY : THIS wiki CHAPTER only is only supported by the community. Kicksecure developers are very unlikely to provide free support for this content. See Community Support for further information, including implications and possible alternatives.

ContentImage (Template) - image wrapper for overlenght images[edit]

  • Content images is a term for images used in the content produced. These images usually occur between text, paragraphs, headlines. Sometimes these images can become too large for small display sizes
  • For images which are expected to be too large for some displays, this wrapper template is ideal. Images inside this wrapper will have max-width:100% and height:auto;
  • NOTE : Thumbnails DO NOT need to be wrapped in ContentImage, because they already have a max-width of 100%, read more here: Dev/mediawiki#Responsive_Thumbnails
    • Simply wrap any image that you suspect could be oversize in this wrapper
    • Parameter
      • addToClass (optional, string) : This parameter's text will be added to the class attribute of the content image wrapper container
      • w100 (optional, boolean) : Makes an image always width 100%. This parameter if true will add the class ciw-w100 to the content iamge wrapper container. This will make the container and all its children width: 100%; display: inline-block;. This parameter was introduced as a helper due to a changed in the way images are handled in MediaWiki since version 1.40.
    • Example with wrapper Code {{ContentImage|[[File:Image-too-wide-demonstration.jpg]]}}
    • Example without wrapper
    • Example with wrapper
  • Relevant files


  • This modal is a tool to conveniently generate URLs to debug the page for developers and also to be transparent about script use for page visitors
  • The user can generate a link where scripts are activated and deactivated. You can de/activate selected scripts. But you can also deactivate all (custom) js or all (custom) css or all js and all css
  • These are the relevant files

  • Here you can see the modal
    • (A) is the CodeSelect-Box where you can copy the generated link
    • (B) is a button where you can directly open the generated link
    • (C) is the navigation. Only if you choose "Select JS" you will see (D) the selection of all current scripts. Otherwise you will deactivate all js/css/js+css
    • (D) If you choose "Select JS" you will see all loaded scripts. Click on them to toggle if they should be active or not. You will see that the CodeSelect box will be immediately updated with the new link. Also the button (B) will be immediately updated according to your selection
  • The modal can be conveniently called like any other miniModal, see #Mini_Modal
    • It's dom-id reference is #debug-via-url-modal

The modal also has a toggle button at the top now which de/actives the cookie nocache with the value true. Clicking this button again will delete the cookie again.

  • The cookie communicates to the server that no server cache shall be sent but the fresh current version


  • In this library there are multiple functions which a dev can use as tools.
  • They are saved to the global object mwDev.tool
  • Relevant file:

fileRefsToLinks( selector, linkAttr, query )[edit]

  • mwDev.tool.fileRefsToLinks(...) can be called in the console or every other js and css file
  • It goes through a set of elements and its children, checks the textnodes and replaces texts of the nature /Media(W|w)iki:[^\.]+.(js|css)/ with actual links to the pages while keeping the rest of the text intact
  • selector | jQueryCollection | default $("#mw-content-text *") : This is a jQueryCollection of DOM elements. Only selected elements will be transformed. That's a great way to for example just transform the elements inside one DIV by selecting the DIV descendants with an asterisk '*'
  • linkAttr | object | default { target: '_blank' } : All key-value pairs will be transformed to HTML attribute strings and added to the file links
  • query | object | default { action: 'edit' } : All key-value pairs will be transformed to URL query key-value pairs and added to the URL

DiscoverHiddenElements (Hash anchors)[edit]

  • General overview
    • Sometimes elements, that have ids and are meant as hash anchors, are hidden inside elements that hide content - namely Dev/mediawiki#Tab_Template_.2F_Tab_Content_Controller and mw-collapsible (MediaWiki system element). Hidden elements can be for example citations, the footnotes themselves, headlines and Dev/mediawiki#Anchor_-_manually_placed_anchors, basically all elements that are used as hash anchors. In normal behavior if a hash anchor is referenced by hash, then the page jumps / scrolls to this anchor. However if the anchor is hidden inside another element, there is no jumping / scrolling
    • Discover Hidden Elements is a JS script that fixes this behavior for JS users
    • For NoJS users this problem does not exist as these "partially hiding" elements are fully visible for NoJS users
  • Functionality
    • This script is controlled via hash. All headlines, manual anchors, citations (meaning both, citations to the reflist with "cite_note-..." ids and reverse citations from reflist to the reference with "cite_ref-..." ids) are registered with Dev/mediawiki#Hash_Controller
    • If the hash changes to a hash for an anchor element that is hidden, then all parent elements are activated (all tabs inside tab controllers, all expands in mw-collapsibles) so that the "visibility route" to this hash anchor is activated.
    • Then scrolling is activated and the page scrolls to this hash anchor element
  • Tests and examples: Dev/wikitest#DiscoverHiddenElements
  • Relevant files:

Donation Panel[edit]


  • Kicksecure and Whonix survive on donations and services we provide. To thank our donors we opened the Donor recognition program. It is a voluntary opt-in program only if requested by the donors. For this page we need cards to appropriately thank our donors. Therefore the template DonorCard was developed.
  • The template has 5 levels which are: xs, s, m, l and xl
  • The cards are designed to be responsive meaning they will take as much space as given
  • To see examples look here: Testpage_Donors
  • Relevant files
    • {{DonorCard |logo=Kicksecure-icon-logo.svg |link=Donors |name=John Doe |range=xs |date=2019-01-01 }}
    • The logo is an optional image representing the donor which is implemented using the [[File:...]] Syntax
    • Using link to a url changes the image to a link image. If link is used then a link indicator image is also inserted to let the user know that the image is clickable
    • The name parameter is mandatory and inserts the donor name or name of organization
    • For range there are 6 options: xs, s, m, l, xl and anon. See how each options looks on Testpage_Donors
    • The date parameter simply outputs the date of the donation

Download Button[edit]

  1. The download button template offers a convinient way to show a graphically pleasing download button
  2. The relevant files are
    1. Widget:Download_Button
  3. Usage call the Widget {{#widget:Download_Button...}} with the following parameters
    1. text | string, mandatory - Visible text on the button
    2. url | string, mandatory - The complete url for the download button
    3. os | string/array, optional - Will show all the logos of the named operating systems. Options: linux, windows, osx, qubes, kvm, debian, virtualbox, usb. Multiple logos example: |os=linux|os=windows will generate an array
    4. icon | string (sig|sha,sigf), optional - changes the download icon at the very left of the button to one of 3 options: sig (stands for signature) will display this icon , sha (stands for sha512) will display this icon and sigf (stands for signify) will display this icon . The default is the download icon
    5. onion | string, optional - The url for the onion download. Will be generated as an extra HTML element behind download button
    6. addToClass | string, optional - Will be added to class attribute of wrapper
    7. fontsize | string, optional - If present will be added to style attribute of wrapper as style="font-size: {{{fontsize}}};"
    8. targetBlank | boolean, optional, default: false - If true will be filling the target attribute with "_blank"
    9. redirectUrl | string, optional - If set then after clicking Download and after 1 second the page will be redirected to the given URL
  4. NOTE: We tried using a template to track all usage of the Download_Button. Unfortunately this is technically very unfavorable for this use case. Read Widget:Download_Button for further information. To find the uses of Download_Button, type into search #widget:Download_Button


  • EditorAutoBackup is an in-wiki modification (augmentation) of the wikitext editor. It creates an "saved icon" in the top right corner of the wikitext editor software toolbar. When clicked there will be the wikitext shown of the last edit right after save was clicked and right before the form was sent to the server
    • The functionality is based on JavaScript and on the localStorage of the browser
    • When "saved icon" is clicked the data from the editing form will be saved to the browser's localStorage via JavaScript. As long as the browser doesn't delete the localStorage (be careful TorBrowser might do that when closing the browser) the edited wikitext from (only!) the last save will be saved in localStorage
  • The relevant files are


  • EditorFullscreen is an in-wiki modification (augmentation) of the wikitext editor. Instead of working in a small window the editor has the option to click on the green fullscreen icon on the upper right in the editing line of the editor and set the wikitext editor to fullscreen. If the wikitext editor is in fullscreen mode at the same position there will be the shrink item which restores the wikitext editor to its original windowed size
  • Relevant files:


  • The EditorMultiwikiNotice is an addition to edit pages. The user on an edit page will be notified if he is on a Category:MultiWiki page.
    • If this page is on the master wiki (currently the Kicksecure wiki). Then he will be warned to act with caution because these changes will affect all wikis.
    • If the user is on a slave wiki he is discourages to edit on the page and go to the master wiki instead
    • A link to the multi wiki info page and a direct link to the master edit page are also provided
    • The links tor compatible, meaning: If the user uses and onion domain he will be redirected to the master wiki onion domains, if he uses clearnet the clearnet domain he will be redirected to the master wiki clearnet domain.
    • See Dev/mediawiki#Multiwiki for more information
  • Relevant files:

Editor SaveAndContinue[edit]

  • Editor SaveAndContinue an in-wiki modification (augmentation) of the wikitext editor. It adds a new green button "Save continue" to the form which usually just has a "Save Changes" button. But the standard "Save Changes" button reloads the page and disrupts the workflow. The "Save continue" button saves the form via an AJAX request. After that it shows the resulting page for the editor (person) the check if the page really was successfully saved
  • The relevant files are


  • The important headlines (h1,h2,h3) are enhanced to give the user a better usability experience
  • The edit button is changed from a Text button to an optical button while retaining the original dom structure
  • Also an automatic shareTooltip is added for each important headline, see #Share_Tooltip
  • The Headlines
  • EnhanceHeadlines can be prevented in 2 ways
    • by adding the HTML attribute "data-preventEnhanceHeadlines" to an arbitrary HTML element on the page, e. g. <div data-pageMeta-preventEnhanceHeadlines=""></div> - the content of the attribute is not relevant it can be empty like <div data-pageMeta-preventEnhanceHeadlines></div>. This attribute is just used as a meta control mechanism. If present NO headline on the page will be enhanced
    • or by adding the template Template:PreventEnhanceHeadlines like so {{PreventEnhanceHeadlines}} which renders to <div data-pageMeta-preventEnhanceHeadlines></div> as explained in variant 1
  • The relevant files are

Expand (mw-collapse) alternative labels (Technique)[edit]

  • The mw-collapse class is a wiki internal class to create collapsible elements for Javascript users
  • The design of the toggle button is determined by our skin (Boilerplate.css)
  • But the text content of the toggle button can also be changed. This is a MediaWiki function, so not really a module, but a technique. But it's not very well documented by MediaWiki, so it's mentioned here
  • Usage : There are 2 attributes which can be added to the element which has mw-collapsible
  • Relevant files

Expand Or Collapse All[edit]

  • The Expand Or Collapse All Button is a conveniance feature to deal with page where there are multiple expand/ collapse buttons
    • This only applies to html elements with the class ".mw-collapsible-text", usually divs. Those already have a toggle (expand / collapse) button for each one individually
    • If the Expand Or Collapse All Button is clicked then all ".mw-collapsible-text" elements will be opened
    • If all ".mw-collapsible-text" are already opened then the "Expand All" button will show "Collapse All" and if clicked all ".mw-collapsible-text" elements will be collapsed
  • Relevant files
  • Usage: {{Expand_or_Collapse_All}}

FlyInNotification Module[edit]

  • It is a delayed notification to show a user special information after a period of time of staying on a Kicksecure page.
  • The widget is dismissable and sets a cookie named flyInBannerIdDismissed which is documented in our Cookie_Policy#Preferences.
  • Shown for JavaScript enabled browsers: Yes. Shown for NoScript users: No
    • Note : A dismissable Fly-In-Notification which is also functional for no-JS (NoScript) enabled browsers is too much effort to implement. It would require a MediaWiki extension / PHP.
  • Relevant files
  • The widget is at the moment wiki wide enabled using Template:Footer.
    • If this changes in the future and the devs want to implement it on a page by page basis, it can be implemented by simply adding the template {{FlyInNotification|...}}
    • In the current implementation the fly-in-notification can be disabled using {{#css:/src-copy/Hide_all_banners.min.css}} or generally (and usually) by using Template:Hide_all_banners, i.e. by using the usual wiki syntax to include a wiki template: {{hide_all_banners}}
    • It is already disabled on some pages such as Donation related pages and legal related pages.
    • Dev note: If you want to change this behaviour in the future read to learn how CSS works in tandem with JavaScript to hide the notification
  • NOTE: There is a dedicated Testpage for FlyInNotification, see TestpageForFlyInNotification, there you can also play with some settings which will only affect the page itself
  • USAGE: See Template:Footer for the current implementation as an example
    1. There are options general options, that er set in the Javascript file. And there are parameters being set in Template:Footer
    2. General options
      • currentCookieId: The id which is stored in the cookie. The currentCookieId will be compared to the id in the cookie, if it matches widget will not be shown. Suggestion: increment the id in integer steps if you want to show the user the next new notification
      • waitInSeconds: The time to wait until the notification pops up (is shown to the user)
      • content: HTML content which is defined as a structured string in the JavaScript file
    3. Parameters
      • headline : The headline of the notification
      • imgSrc : The url of the source for the image
      • imgWidth : The width setting for the image
      • imgHeight : The height setting for the image
      • imgLink : A link url where clicking on the image should refer to. This link will also automatically be added to the headline
      • html : HTMl for the body of the notification
      • Example : {{FlyInNotification |imgSrc=/your-image |imgLink=/wiki/Your_page |imgWidth=300 |imgHeight=215 |headline=Your headline |html=Your <b>bold</b> HTML }}

GoogleOff Template[edit]

  • This template offers the option to hide content from search engines either completely or it just prevents them from using it as a snippet
  • Relevant files
  • USAGE : Parameters
    • content (mandatory, wikitext) : The content you want to hide from the search engines
      • {{GoogleOff|content=Wiki text content you want to hide from search engines}}
    • nosnippet (optional, boolean) : Set to true if you want the content to be found but NOT used as a snippet
      • {{GoogleOff|nosnippet=true|content=Wiki text content you want to be found but not used as snippets}}
    • span (optional, boolean) : Set to true if you want the wrapper to be span instead of div. Needed sometimes in specific cases in wikitext.
      • {{GoogleOff|span=true|content=Wiki text content you want to wrap in a span instead of div}}
    • NOTE: The data-nosnippet attribute that prevents search engines from generating a snippet from the GoogleOff area is active for the wrapper element in all cases. But when using the nosnippet=1 parameter this is the only preventive measure and the area can still be crawled, yet not be used as a snippet.

Hash Controller[edit]

  • The Hash of the URL (e. g. in the "anchor1" part) can be a powerful tool to control parts of the page. In its usual use case and for nojs users it makes the browser window jump to the desired location. With Javascript the hash can be used as any data point
  • The hash controller is for developers centralizes the hash behavior as sub category in Dev/mediawiki#DevTools.
  • USAGE : The following functions are available
    • get() : Simply get the current hash as a string. NOTE for Devs : You get the decoded string, meaning special chars are transformed back from their escaped url form to their special char self. Also note that this might be confusing because many browsers show these special chars in their special char form. But as only ascii is allowed in urls their are in reality escaped.
    • set( hash : string ) : Simply set the current hash with a string (without '#')
    • register( id : string, callback : function, requestInitialTrigger : boolean ) : Register a function for a specific id/hash. Meaning: If the URL has/gets this hash then this function will be executed. If requestInitialTrigger is set to true then at the load time of the page all relevant functions will be executed. This execution will only happen ONCE - even if multiple functions set requestInitialTrigger tro true.
    • trigger( initial : string ) : Trigger the checking function. The initial parameter is only needed internally for If the initial-parameter is set to "initial" (verbose for more clarity) then this will only fire if at least one function set requestInitialTrigger to true in the register-function
  • Relevant files

Headline (Template)[edit]

  • There is no way in MediaWiki to create dynamic headlines via a Template. This however is needed sometimes. Usually headlines are written using wikitext and the "=" notation. But sometimes the content of the headline might be given to a template via a parameter, separate from the level of the headline for programming and usability reasons. This is the case in a special case of Template:Tab, see #Tab_Template_.2F_Tab_Content_Controller → "Headlines excluded from TOC" for more information
  • Features
    • Headline will not be listed in TOC
    • auto-generated or manual id
    • adding classes to class attribute
    • HTML Structure like regular MediaWiki headlines, h[1-6] >[headline-id]
  • USAGE : Call the template (not the widget) with these parameters
    • content (mandatory, html) : The HTML content of the headline, simple text or more complex (full) HTML (not only wikitext html)
    • h (optional, [1-6], default: 1) : The level of the headline as known from html. Only the numbers 1-6 are allowed
    • id (optional, default: autogen from content)  : The id is rendered to the html attribute "id".
      • auto-generate : If no id is given then id is auto-generated from content (all non-word-characters are rendered to dashes "-")
      • none : Only if id is set to the special keyword "none" then no id attribute will be rendered
    • addToClass (optional) : Additions to the (optinal) class attribute for the headline
  • Example : Code {{Headline|h=2|content=Test Headline}} → Render

    Test Headline

  • Relevant files

HtmlComment Widget[edit]

  • In MediaWiki templates it is basically impossible to use Html comments and have them rendered on the final page. This is intentional by Mediawiki to reduce unnecessary output. Sometimes however comments are needed
  • Because of that we created the widget HtmlComment. This allows HTML comments in Templates
  • Relevant files
    • {{#widget:HtmlComment|content=Your HTML comment content}}
    • This will create a real HTML comment (which of course is only seen in source code)
    • NOTE: You cannot use wikitext as content

Icon Bullet List[edit]

  • The Icon Bullet List is like a bullet list with Fontawesome icons instead of bullet points
  • Relevant files
  • Usage : call #widget:Icon_Bullet_List. Parameters:
    • item (mandatory, string) : This parameter is separated into two parts, separated by a comma ",". The first part is the content of the <i class="fas..."></i> class parameter for the Fontawesome image. The second part is the text for the bullet points. HTML elements like <b></b> are permitted. NOTE: Only the first comma is a separator, all following commas will not be interpreted and therefore can be used as normal text structuring elements
    • addClass (optional, string) : This parameter is added the the class-attribute of the <ul></ul> parent element for the list. You can use the specific keywords "minimal" and "inverse"
      • minimal = list is as short as its content
      • inverse = darker list + white bullet point) or other classes of your liking
    • fontSize (optional, string) : determines the font-size of the list as a CSS expression like "13px" or "3em". The whole list sizes with the font-size, so it's looks very good in every fontSize
    • span (optional, boolean) : If true then the whole list will be a span element with other direct children span elements as list items. The same styles apply to the list should look the same. This is for special cases, like it's use in Dev/mediawiki#Anti-Spam_email_tooltip
  • Example
|item=fas fa-check,Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points 
|item=fas fa-minus,Negative Points
  • Resulting in

  • Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points Plus Points
  • Negative Points

  • Example using all parameters
    • NOTE: div with white background just for demonstration purposes. Do not use in production.
<div style="background: white; padding: 10px 20px;">
{{#widget:Icon_Bullet_List|addClass=inverse minimal|fontSize=20px
|item=fas fa-star,Standard
|item=fas fa-check cs-green,Plus Points
|item=fas fa-times cs-red,Negative Points
|item=fas fa-minus cs-yellow,Equal Points
|item=fas fa-check cs-blue,Chill Points
  • Resulting in

  • Standard
  • Plus Points
  • Negative Points
  • Equal Points
  • Chill Points

  • NOTE: The colors of the bullet icons is using our color schemes which you can read about here #Color_schemes

Info Tooltip[edit]

  • Info tooltip is a small element to show a tooltip only by using CSS (nojs compatible)
  • Usage
    • give and element the class 'info-tooltip'
    • hide an element inside which will only be shown when user hovers over info button
    • example <span class="info-tooltip"><span>Here's the hidden info</span></span>
    • result Here's the hidden info
  • Relevant files

Intro paragraph and IntroLike[edit]

  1. intro is a template to write multiple paragraphs for the styled intro of a page
    • These paragraphs will be styled as if they were a single box
    • This paragraph is needed for the Extension:Popups, also know as Previews, formerly known as Hovercards because this extension uses the which needs some free unstyled paragraphs at the beginning of a page to generate a content preview (related Extension:TextExtracts feature request: Explicit Definition for TextExtracts
    • This template uses a sophisticated CSS styling to accomplish the intro look while keeping the text as plain paragraphs. This styling works about 95% in all browsers. Only in Firefox there's 5% design flaw because Firefox does not yet support the CSS :has-selector which is needed
    • NOTE: This Template should ONLY be used ONCE PER PAGE. If this specific style is needed somewhere else use Template:IntroLike
    • Relevant files
    • USAGE
      • Normal usage where the text is shown {{intro|Your intro text with wikitext and newlines}}
      • hidden=true: Hidden usage where the text is not know. NOTE: The named parameter can be used everywhere as named parameters in Mediawiki do not affect the referencing of unnamed parameters. {{intro|hidden=true|Your intro text with wikitext and newlines}}
      • thumb=[wiki-image-name]: thumb is optinal and gets a name from an image file that is uploaded to the wiki. The thumb will always be hidden not matter if intro is hidden or not. This is because thumb (specifically the thumb for Extension:Popups) is never intended for the user to see. If the page needs a thumb that the user can also see, then the author can insert a regular thumb as these will also work with Extension:Popups. {{intro|hidden=true|thumb=Kicksecure-icon-logo.png|Your intro text with wikitext and newlines}}
  2. introLike is a template to use if the style of intro paragraph is desired but it's not actually the function of a page intro
    • Relevant files
    • USAGE
      • Call IntroLike and set the required text / wikitext as the first anonymous character
      • Example: {{introLike| Your intro like text with '''wikitext''' and newlines }}
      • NOTE : Be sure to use a newline after the pipe symbol and a newline before the closing double braces


  • A Template to show an image left and right a text or the other way round for decorative purposes
  • Recommended to be used as template, but also available as a widget because as a template there are too many limitations, especially for the style-attribute.
  • It is responsive. And once the screen is smaller than 500px the 2 parts will go width 100% and be below each other with a margin under the image
  • Below 500px the image will ALWAYS be ABOVE the text, to keep a consistent look
  • If the text is longer than the image or the image is longer than the text, the smaller one will always be in the middle
  • Relevant files
  • USAGE : Template {{LeftRightImageText|...}}. Parameters
    • image : The image with should be shown next to the text. NOTE: For this parameter there is a difference between template and widget. In template you simply use the file name for image like "Information-275708-640.png". In the widget you have to use real relative link like "w/images/thumb/7/70/Information-275708-640.png/300px-Information-275708-640.png"
    • imagelink : If you want the image to function as a link give |imagelink=your-link-to-image and the image will behave as a link with hover effect. NOTE: For this parameter there is a difference between template and widget if it's an wiki internal link. In template you simply use the page name like "About". In the widget you have to use real relative link like "/wiki/About"
    • text : The wikitext (template) or html (widget) which should be shown next to the image
    • imageright : If you want to image to be right, use the parameter |imageright=true then the image will be on the right and the text on the left
    • imageAlt : If you want add an alt attribute to the image, use the parameter |imageAlt=Image text when loading errer then the alt attribute will be added and show if browser was unable to load image
    • addToClass : If you want to add classes to the parent element, use the parameter |addToClass=your-classes
      • class promo-style: One specific class for the parent element is "promo-style" which will turn all h3 and p elements to bigger stylized text areas
  • Example template
|imageAlt=Symbol information
This is an interesting product. You might want to hear more about it. This is an interesting product. You might want to hear more about it. 
This is an interesting product. You might want to hear more about it. This is an interesting product. You might want to hear more about it. 
This is an interesting product. You might want to hear more about it. This is an interesting product. You might want to hear more about it. 
  • Example widget
|imageAlt=Symbol information
This is an interesting product. You might want to hear more about it. This is an interesting product. You might want to hear more about it. 
This is an interesting product. You might want to hear more about it. This is an interesting product. You might want to hear more about it. 
This is an interesting product. You might want to hear more about it. This is an interesting product. You might want to hear more about it. 
  • Result for both
Symbol information
This is an interesting product. You might want to hear more about it. This is an interesting product. You might want to hear more about it.

This is an interesting product. You might want to hear more about it. This is an interesting product. You might want to hear more about it.

This is an interesting product. You might want to hear more about it. This is an interesting product. You might want to hear more about it.

Mini Modal[edit]

  1. MiniModal is a modal as a quick way to create lightweight modals
  2. Relevant files are
  3. Usage: implement the modal with this minimal structure <div class="mini-modal" id="your-id-recommended-to-use"></div>
    1. init : MiniModal are lazily initialized when they are shown or hidden (see "show" and "hide"). You can also actively initialize them with $('#your-id-recommended-to-use').miniModal('init'); . A sub div will be created with the underlay and a close button. And the direct content under the .mini-modal div will be moved to the sub-div .content
    2. show / hide : You can programmatically (JavaScript) open the modal with $('#your-id-recommended-to-use').miniModal('show'); and close it with $('#your-id-recommended-to-use').miniModal('hide');
      1. Whenever a modal is opened ("show") the URL will be changed. If not specified otherwise (see "data-url-hash") the url will get a hash-symbol # without any text. This enables the browser to use the back-button to close ("hide") the modal. Whenever the modal is closed the hash-symbol will disappear - including the hash-text if there is any
    3. checkForModalsCalledByHash and data-url-hash : This method can be called on any element, because it's global anyways $(window).miniModal('checkForModalsCalledByHash'); - This will check if any modal has the attribute "data-url-hash" and if this attribute matches the current url-hash. Then this modal is shown. This attribute also forces the url to be changed if the modal is called using the hash sign # plus hash-text. If the attribute is not present the url is changed as described above (see "show/hide")
    4. Events: You can listen to the self-explanatory events $('#your-modal').on('shown.miniModal', fn ); and $('#your-modal').on('hidden.miniModal', fn );

Mini Navigation[edit]

  • Mininav: Mini navigation: Mini navigation is used to have multiple buttons in a row linking to other pages. The outer element must be a <div class="mininav"> the inner element must be a list of elements, for example of links. This will automatically be transformed to the navigation
  • CSS special classes
    • mn-dark CSS class : When this class is added the navigation will become darker. This is useful for light and white backgrounds where the mininav would otherwise not be seen very well
    • mn-[2-4]-lines : Normally the mininav takes 1 line and reserves this space to prevent content shift. The class mn-2-lines added to mininav makes mininav take 2 lines as standard. The other 2 classes take 3 lines and 4 lines respectively. This only concerns the minimal space taken. If the mininav takes more vertical space on smaller devices this has no effect.
  • Link icon
    • If the link starts with an image, then this image will be used as an icon for the link, see example below
    • NOTE 1: The link icon image has to have the Mediawiki parameter link set to empty string |link=. This prevents the file from becoming a file link and renders it to an img tag
    • NOTE 2: The image should have a size of at least 25px, because 25px x 25px is the box in which the image is fitted. A width of 50px is probably optimal
  • Relevant files:

Example 1 :

<div class="mininav"> * [[Homepage]] * [[Homepage]] * [[Homepage]] </div>

renders to :

Example 2 : <div class="mininav mn-dark"> * [[Homepage]] * [[File:Tux.png|50px|link=]][[Homepage]] * [[Homepage]] </div>

renders to :

Non-Responsive Thumbnails classes[edit]

PayViaPaypal module[edit]

  • To offer users to donate via PayPal we offer a form to do so
    • The form is a fully functional PayPal form which combines subscription payment and one time payment by switching input elements (as defined in PayPal's API) according to the user's selection
    • This module is based on JavaScript because PayPal also seems at the moment only fully usable with JavaScript activated
  • Relevant files
  • Usage: To integrate the form into a page simply use <div class="pay-via-paypal-module">[nojs text]</div> and write the text or markup for NoJS users in the div
    • This text will be replaced by the form via JavaScript if JavaScript is activated
    • You can also use "smooth" in the class attribute. This makes the form grow smoothly when it's fully loaded instead of popping into position <div class="pay-via-paypal-module smooth">[nojs text]</div>
    • On any page there can be multiple forms which are each independent of each other
  • Dev Sandbox mode: To use this module in sandbox mode, add the query ?paypalmode=sandbox to the url (e.g.

Pre : <pre>, <div class="pre"> and <pre data-code>[edit]

  • <pre> and <div class="pre"> are two ways to show preformatted code. Both look very similar. The difference is: In pre tags mediawiki does not parse newlines, variables etc, in div.pre it does. So according to usage scenario either pre or div.pre are preferrable
  • <pre data-code> (the attribute is data-code, so it's valid HTML) is useful in many situations where admin would have to write
    . Formally it's just a little shorter, but it's way easier to write. And pre also escapes every content like nowiki does.
    • NOTE : One drawback is that before a pre-tag other elements are most of the time enclosed in p tags, so it's not 100% of a replica of code
  • Relevant files

Example pre:

test pre

Example div.pre

test div.pre

Example code test code

Example pre[data-code]

test pre[data-code]

Quotation (Template)[edit]

NOTE : This template may not be used in lists (numbered / bullet points) at the moment. It does not work there as expected. This is caused by a bug in the MediaWiki parser that has been reported

  • For Quotes without any context normal blockquote can be used
    • Example Code <blockquote>An important quote from a developer</blockquote>
    • Example

      An important quote from a developer

  • But if the editor wants to add an image, the author or other context, they would need to use Template:Quotation which is also "prettier" and more accentuated
    • Use template Quotation with the following parameters
      • quote (wikitext, required) : the quote content
      • image (optional) : The name of the file as it would be on the file page without file: or image: prefix
      • context (wikitext, optional) : the author and other context, including links, right to the (optional) image
  • Relevant Files

Example Code {{Quotation |quote=An important quote from a developer |image=Deep-web-1106648640.jpg |context=Name, Position, Link }}


An important quote from a developer

Name, Position, Link

sd-start (currently retired)[edit]


  • The search is generalized as a modal. Once the user clicks on the search button in the header the modal opens
  • Relevant files
  • Depedencies

Share Tooltip[edit]

  1. A tooltip menu for copying and sharing a url to various social media
  2. You can insert the template and optionally reference an anchor. The hover menu will offer the user different sharing options
  3. Nojs: These sharing tooltips will not be visible for nojs users
  4. JS active: The span element will be used as a wrapper and filled with a complex menu with sharing options for twitter, facebook etc
  5. Relevant files
  6. dev note
    1. ShareTooltip is realized as a jQuery extension. This is availabe after ShareTooltip.js has been initialized (see build order in config-build-{shared and specific}
    2. You can call $(selection).shareTooltip(action) - with action currently only allowed as 'init'. This will initialized all ShareSelect elements in the selection. Double initializations are prevented
  7. Usage
    1. the data-anchor parameter anchor is optional, without it the sharing link is the whole page
      1. NOTE: if you use an anchor this anchor (or an element with this id="my-anchor-id") should exist somewhere on this page
      2. If the data-anchor parameter is set (only then) you can also use the data-chapter parameter which will explicitly set the title of the chapter for various sharing options. If not the title will be fetched from the target element (e. g. if it's a headline, then the text) or if this also fails then the anchor id will be transformed by replacing "_" with space
<span class="share-tooltip" data-anchor="my-anchor-id" data-chapter="My chapter title"></span>


/// Example reference element with id="my-anchor-id" ///

SiteNotice Info and Donation Banners[edit]

  1. The sitenotice is used to communicated current infos to the user. It is used in a very versatile way
  1. Relevant elements
    2. Template:Hide_all_banners
    3. Template:SitenoticeBanner
    4. Widget:SitenoticeBanner
    5. MediaWiki:Sitenotice
    8. Template:Sitenotice_id
  2. Sitenotice is excluded from search engine indexing via #Exclusion_of_text_parts_from_search_engine_indexing
  3. NoJS: For NoJS users there is no option to close the siteNotice
  4. Update info
    1. In the past there were more rules for sitenotice, but this has change due to the new solution. All rules are given below. Also some more files were important back then, not anymore.
    2. In the past we used MediaWiki:Sitenotice_id. However updating this ID came in conflict with the that we're using. That's why it has been replaced with Template:Sitenotice_id which serves the same purpose
  5. History of solution stack
    1. Previously we used the, but this is no longer the case. We have our own solution which enables the sitenotice to be dismissable
    2. The solution needed to be dismissable. Therefore Javascript was involved
    3. But if dismissed banners are closed by Javascript this is too late if the page is loaded because the page will "jump" and have a bad lighthouse content shift score. Therefore the page is hidden by user cookie which is set to the server on request and rendered as a body class which then hides the cookie immediately. This is done by Dev/mediawiki#Extension_CookieToBodyClass Extension:CookieToBodyClass which our SiteNotice solution therefore is dependent on
      1. If the user dismisses a banner he gets a cookie which is active 1 month and then auto-deletes which shows the banner again
    4. We also needed a way to make banners active and non-active. So we introduced a Template. This template in turn uses the widget because widgets can do some things in mediawiki that templates can't
    5. Then we also needed a possibility to not show a banner if it's expired. That is also implemented
    6. And we needed a way to force new banners upon the user - for example if there is an emergency but the user has dismissed the old banner less than a month ago. Therefore we used Sitenotice_id. If this id is changed then the user cookie will not longer hide the banner and he sees the new one which he might dismiss again
  6. USAGE
    1. You usually only touch MediaWiki:Sitenotice, Template:Sitenotice_id and occasionally Everything else is maintained by core developers of this wiki
    2. CREATE BANNER : Open MediaWiki:Sitenotice and create a new instance of Template:SitenoticeBanner with these parameters
      1. html (mandatory) : The content of the banner. You can omit it, but the banner in most cases makes no sense without HTML to fill it
      2. active (optional, default: unset) : This is NECESSARY if you want to activate (show) a banner. If this parameter is omitted or false then the banner will not even be rendered. Use "|active=true" (or True or TRUE) to show the banner. To explicitely state that the banner is inactive you can also write "|active=false"
      3. href (optional) : If it's given then the html is rendered inside of an a-element with href-attribute as href
      4. expires (optional) : This is a UNIX timestamp in seconds. If the banner needs to end on a specific date and the creator does not want to check all of the time this happens automatically and the banner will not even be rendered after this date
      5. id (optional) : Gives the banner an id-attribute for styling. It is recommended to add the individual styles of a banner to or
    3. Banner visibility is global. If the user has dismissed your banner ALL of your banners will be invisible for one month. If you want to reset the banner visibility go to Template:Sitenotice_id and change the ID to a new string. Then whichever current banner (seen or not seen) will be visible again for ALL users
    4. Example code {{SitenoticeBanner |active=true |html=<img class="full-size" decoding="async" loading="lazy" src="/w/images/7/7d/Banner-dev-wanted-slim.jpg" width="960" height="140" alt="Developer wanted for Kicksecure ISO development"> |href=/wiki/Contribute |expires=16776808891 |id=my-banner-id }}
    5. Additional JS functionality: If you need special functionality for some banners put them in under "B : Custom Banners Functionality"
    6. Deactivate all banners: If you want to deactivate all banners (including the flyinnotification) just put this template somewhere on the page Template:Hide_all_banners

SiteNotice End Of Year Banner[edit]

  1. The SiteNotice End Of Year Banner is a complex banner for the donation drive at the end of the year
  2. The banner fulfills several requirements: (1) Responsive mobile / desktop (2) Predictable height to prevent content jumping (3) Content as a slideshow (4) Payment gadget always present or one click away (5) Dismissable (by cookie for 1 week) (6) Portable, so it can be loaded on other pages, in this case the forums (7) Customizable so there can be different content on different pages (i. e. Whonix and Kicksecure)
  3. Relevant files:
    3. Sitenotice_EndOfYear_LocalWiki.js (deprecated)
  4. The main Javascript file is There it provides a function initEndOfYearSitenotice( endOfYearDiv, contentForSlides, donatePageUrl = '/wiki/Donate', isLocalFileSystem = false ) that IS NOT directly executed.
    1. endOfYearDiv needs to be a jquery dom element or a valid CSS selector. It's the element where this whole banner gadget will be prepended (added to the front)
    2. contentForSlides needs to be an HTML-String which will then be added to the banner.
      1. Every slide (direct child) should be a div element to contain your slide content. This is individual content fitting the current wiki.
      2. Crypto: You will have to have an element in your string (e. g. div) which (1) has the attribute data-crypto-addresses (2) is a JSON string (3) and has the keys "payBitcoin", "payMonero" and "payEthereum" with the right addresses as string-values.
      3. Title: If you add an h1-element (also a child, use of HTML inside the h1 is allowed) then this will be used as the title of the end of year sitenotice being displayed at the top. If you don't use an h1-element here then there will be a generic title
    3. donatePageUrl, e. g. "", is the URL where the donate button or "More payment options" button lead the user.
    4. isLocalFileSystem (boolean) indicated if this function is run locally for example on the Kicksecure local browser page. If true then localStorage will be used by Javascript to save when the user dismissed the donation banner
  5. In the styles are defined.
  6. In Sitenotice_EndOfYear_LocalWiki.js (deprecated) the function initEndOfYearSitenotice(...) is called. This must be done for each wiki individually. This is also usually where the content is stored.
  7. When clicking dismiss a data entry into "localStorage" is written with the current date plus 7 days. Before that time the banner will not be shown again. After that time, the banner will be shown again and the data entry will be deleted
  8. History: This functionality was originally using Ajax Calls to get the content. But this was too slow, so all content is stored in Sitenotice_EndOfYear_LocalWiki.js (deprecated) now
  9. For more information how our banners work read #SiteNotice_Info_and_Donation_Banners. The end of year banner uses the expiration functionality and dismiss functionality from sitenotice.
  10. NOTE: If this banner is not in use please deactivate the three files,, Sitenotice_EndOfYear_LocalWiki.js (deprecated) in config-build-{shared and specific} by commenting them our using "//" as described in the Build file itself. Then run mw-combine.php. Deactivating these files saves bandwidth for the user.

Splide homepage sliders[edit]

  • We are using to create sliders on the homepages of our wikis
    • This script seems very mature, we're using the standard theme
    • It is implemented via Dev/mediawiki#Extension_HeadScript
    • This script only works on the homepages, so pages with routes starting with /wiki/Homepage (or just /) or /w/index.php?title=Homepage
  • Relevant files
  • Our script only works on homepages because it checks whether the splide script is loaded
    • The script checks all instances of .mw-collapsible which does also have the class slider-list-if-js
    • All cards are cloned into the slides list, there they are styled and integrated in the slider automatically
    • Structure : Be aware that this only works on the homepages and there's a specific structure needed
      • All slide "templates" (the original cards) have to be an a-element with href attribute and they need to have the class .card-wrapper
      • Exactly below card-wrapper there needs to be .image-wrapper with an img image inside
      • Also below card-wrapper there needs to be a p-element where the text content is stored
      • Also below there can be optionally a headline h2,h3,h4,h5 which is where the headline text is extracted from


  • If the wiki server is a stage server (all wikis have a stage server to test updates an upgrades before they go live)
  • In order for admins to easily see it's a stage server, there in an indicator added automatically via a Javascript script
  • This script checks whether a meta tag
    <meta name="server-type-stage">
    is present. If so the indicator is automatically added just left below the header
  • Relevant files


  1. This template creates a context based link to a subdomain of the wiki project. Works only for the official wiki clearnet and onion domains.
    1. Problem: normally it is optimal to use relative links. This is not possible for subdomains here. But to redirect with an absolute link to a subdomain poses the problem if there are multiple domains for the same website like with whonix where there is also an .onion domain
    2. This template solves the problem by automatically analysing the context (which domain the user is on) and creating the link automatically based on the context
  2. Relevant files
    1. Template:Subdomain_link - only this template should be used by editors
    2. Widget:Subdomain_link - this widget should only be edited by devs
  3. USAGE : Use template {{Subdomain_link|...}} with the following parameters
    1. text | string, default: "" : the text you want to display in your link. The effect of this parameter is influenced by the parameter result. If not |result=link then this parameter text is obsolete
    2. sub | string, default: "" : the subdomain without any special character. If you want, use "forums"
    3. append | string, default: "" : an addition to the link after the domain. Always start with slash "/". Example: "/thread/12387" → ""
    4. result | string, standard: "link" : determines what the widget returns. Options (A) link - then an a-hyperlink will be created (B) url - then only the final url will be created (C) parts - then a string will be created. First part protocol "http", then comma, then "domain", example: "https,"

Tab Template / Tab Content Controller[edit]

  • A tab controller to conveniently show content as tabbed content areas
  • Uses #Mini_Navigation as an auto-generated navbar
  • Features
    • For nojs visitors the content is plainly and fully shown without any navigation
    • Url Hash Feature : For Js users all tabs are rendered as links, so if you right-click a tab it will give you the option to "copy link url". This URL has a hash and if this URL is called then this tab will be opened upon calling. This includes the tabs which are above it (if you have nested tab controllers). So for nojs users this link will jump straight to the headline
    • Linked controllers : Link multiple controllers so they switch in unison
  • Definitions
    • Tab : A button in a same-page navigation where only a part of the page is changed
    • Section : The content which is shown when a tab is clicked
    • Controller : The controller functions as the container / parent / anchor point for the sections and also a parent for the navigation which is generated
    • There are two template components which are needed: the controller and the section. Both are created by using the same multi-purpose template Template:Tab
    • Parameters are different for controller and section
    • Parameters for Controller and Section
      1. type (mandatory, for "controller") : This can be "controller", "section" or nothing. If controller is chosen a controller-component is created. Side note: |type=controller is rather long for a switch. But it was done this way so every new editor clearly sees if this is a controller. If section or nothing is chosen then a section-component is created.
      2. addToClass (optional) : The content of this parameter will be added to the class attribute of the controller or the tab that is created
      3. lines (optional, 2-4) : This parameter accepts the numbers 2-4 and writes the respective classes mn-[2-4]-lines to the mininav. See Dev/mediawiki#Mini_Navigation
    • Parameters for Section
      1. title (mandatory) : This title needs to be gives as a wikitext headline. This headline should integrate in the normal flow and hierarchy of the whole page because for nojs users this is all that they will see.
      2. content (mandatory) : This parameter is where you put all the real wikitext content that is shown when tab is active but hidden when inactive. And always shown for nojs users
        • link-tabs : This is an alternative to having content in a tab. If a single link is given as content (as external link, complex external link [ MediaWiki] or internal link [[Wikipage]]) then the nav point in the navbar will become an external / internal link instead of (standard:) a button to show the content. NOTE : For no-js users the content will be rendered as headline + the link as given.
      3. active (optional, recommended, only "true") : active can only be set to true. This means that the corresponding tab to the section with |active=true will be pre-selected. If this parameter is not set the very first section will always be selected.
        • NOTE : Please avoid settings multiple sections to active, that would be a syntax error
        • NOTE : It is highly recommended to give one tab the active-parameter, because otherwise content shift will occur.
      4. image (optional) : Here an image in wikitext form is given [[File:my-image.png|50px]] to have an image which will be shown on the left of the tab before the tab title in the navbar. NOTE : Be sure to use a small image of max. 60 x 60 pixel.
    • Parameters for Controller
      1. content (mandatory) : For the controller content is different from section. The controller may ONLY have multiple sections - meaning instances of Template:Tab in the section variant - as children
      2. linkid (optional) : This is an internal id to link multiple controllers. This is needed if multiple controllers need to switch in unison. If two or more controllers have this parameter with the same content they will be linked, meaning: All tabs being clicked in one of the navigations will switch the tabs in the other navigations as well. This is synchronized by the number of the tab. Example: You click tab 1 in controller 1 then section 1 in controller 1 is shown AND then tab 1 in controller 2 is also shown as well as section 1 in controller 2.
        • NOTE - different numbers: If there is not the same number of sections in both controllers they will only be synchronized as far as numbers are equal. If you click tab 6 and the other controller only has 3 tabs then the controller with 3 tabs remains unchanged
        • NOTE - link-tabs: If a tab is a link tab then clicking it will not change the other controller
    • Code Examples
      1. create the controller using Tab template with type controller and content {{Tab|type=controller|content=...}}
      2. Create a sections by using Tab template with title and content {{Tab|title= ==section1==|content=Section 1 content}}
    • Further features
      • .tcc-indent CSS class : Special CSS class that needs to be added to a controller via "|addToClass=tcc-indent" to take effect. Every tab content controller with this class will have a white border on the left to indent the content. This is especially useful if tab-content-controllers are nested inside each other and the user still needs to realise the different levels
      • .tcc-dark CSS class: Special CSS class that needs to be added to a controller via "|addToClass=tcc-dark" to take effect. The mininav sub element will automatically get the class "mn-dark" as described here: #Mini_Navigation. The mininav will also get gray borders instead of white ones when using the .tcc-indent class
      • Linked to URL hash
        1. Setting hash via controllers : Tab controllers are linked to url hash. As the tabs are basically generated from headlines, clicking on them changes the URL hash like navigating to a headline via TOC would do
        2. Setting controllers via hash : The other way around is also true. If you call a page with a URL hash that matches the controller tab ID then this tab will be opened when the page is loaded. Also the page will scroll to the correct position
        3. NOTE : nested controllers : This also works recursively with nested controllers. If a nested controller is chosen via hash then all parent controllers are opened too
      • Controllable via TOC : Clicking on the TOC changes the URL and adds a hash. If this hash corresponds to a tab controller tab then this tab will be opened and scrolled to
      • Headlines excluded from TOC : Compatible with #Headline_.28Widget.29 which means that those headlines can be used instead for the title parameter to create headlines excluded from TOC. Use |title={{Headline...}} . See Dev/wikitest#Nested_Tab_Test_:_No_TOC for examples
    • JavaScript functions
      • init : This function is usually automatically called for all elements with the "tab-content-controller" class. But it can be individually called (maybe needed if a tab content controller is constructed later) with $('.my-controller-class').tabContentController('init');
      • select : With this function an element with the classes tcc-tab or tcc-section can be referenced an then select will both select the section and the corresponding tab WITHOUT changing the hash of the page (which happens when you click a tab). Code $('.my-section-or-tab-class').tabContentController('select');
  • Relevant files
  • Full example
{{Tab|title= ===section1===|content=Section 1 content}}
{{Tab|title= ===section2===|content=Section 2 content}}

  • Full Feature Example
|addToClass=tcc-indent tcc-dark
|title= ==Section 1==
|content=Section 1 content
|title= ==Section 2==
|content=Section 2 content
}} <!-- end of tab controller 1 -->

|title= ==Section 3==
|content=Section 3 content
|title= ==Section 4==
|content=Section 4 content
|title= ==Section 5 Link==
}} <!-- end of tab controller 2 -->


  • Sometimes thumbs need to be shown as a gallery on mobile devices. This is the case if there are multiple thumbnails in a row that act as some kind of collective thumbnail for the page
    • This can be easily achieved using the Template ThumbGallery. Simple wrap you thumbs into the template and below 540px display width these thumbnails will become a gallery
    • Example {{ThumbGallery| [[File:Kicksecure-basic-logo.png|thumb|100px|[[Dev/Logo|Kicksecure logo]]]] [[File:Debian.png|thumb|100px|Debian logo]] [[File:Linuxkerneltux.png|thumb|100px|Linux logo]] }}
  • Relevant Files

TOC Level Switcher[edit]

Table of Contents Level Switcher wiki button

Figure: Table of Contents Level Switcher

  1. There is a lot of content on this wiki and there are many headlines on one page. So the table of contents (toc) is sometimes very overwhelming. To improve this experience for the user we created a JavaScript augmentation for the TOC
  2. 3 Buttons are added right of the TOC where you can use the star and show all levels (standard) or click "2" to just show the top 2 levels or click "1" to just show the top level. You can open the levels by using the plus button. And you can see how many children one level has by the number in the brackets on the right. Levels with 0 children will have no plus button to open them
  3. The TOC is not shown at all if there is no level 2 headlines, because then the TOC could do nothing. If there is no level 3 headlines then the "Show level 2" button is not shown for the same reason
  4. TOC level switcher saves your choice to a cookie. But only if you make a choice that is not "all" (wiki default, asterisk symbol)
    1. So if you're someone who always likes to just get the top headlines this will help improve your experience across all pages.
    2. If you want to delete your choice and the whole data point completely from cookie just click the asterisk icon and the cookie will be wiped completely
  5. Relevant files
  6. NOTE: This feature is dependent on the #Extension_CookieToBodyClass

VideoLink (Template)[edit]

  • To have a convenient way to show videos we introduced VideoLink
  • Relevant files
  • USAGE : Only use the template {{VideoLink|...}}
    • videoid: The videoid parameter is valid for all YouTube-link platforms. For each platform there is an icon generated as a link where the videoid is part of the url.
    • text: This is the text that will be shown to the user. The text will be also rendered as a link with YouTube as its target
    • Example : {{VideoLink|videoid=6nHufztdkUI|text=Test video}}
  • For Devs: To introduce new platforms simply copy a link code line in Template:VideoLink and modify the image, the alt description and url

WikitableAutoWrapper and ScrollableIndicator[edit]

  • Motivation
    • Tables have a flexible width auto-adjusting to their content - this means it can have over 100% of the given width.
    • To give the user a smooth experience tables should not surpass 100% width
    • To solve this we created an auto-wrapper for all tables with the "wikitable" class (which is our standard class for styled tables).
  • Functionality
    • This wrapper is applied via Javascript and therefore does not work for nojs users
    • The wrapper always stays 100% width. And if the table is too wide there will be an overflow bar
    • The wrapper also introduces helper elements to indicate overflow for mobile users. There is a "swipe" indicator above and below the table, because many smartphones do not show a scroll bar unless the user is already scrolling
    • Hidden Tables : Sometimes tables are hidden (for example when wrapped in mw-collapsible) and therefore have no dimension. In this case the normal method does not work and would produce wrappers with a height of 0 and result in a faulty layout
      • To fix this we use IntersectionObserver to check if and when a table becomes visible. Only then will the usual Javascript be executed. And the IntersectionObserver will be disconnected to save computing power
      • We also check if IntersectionObserver is available (it's not in old browser) and for those rare cases where it's not we do not apply the Javascript with the WikitableAutoWrapper at all to have at least a readable fallback
    • Special margins : Sometimes a table has special margins. The wrapper has to have those margins because the table gets 0 on all margins to preserve "margin joining" with surrounding elements which otherwise would lead to content shift. Therefore the wrapper automatically gets the computed styles from the table while the tables gets 0 for all margins
  • Relevant files
  • NOTE : This solution replaces the previous solutions "scroll-table" and "scroll-overflow-indicator"

USAGE : CSS Design Documentation (Alphabetical order)[edit]

Col Container[edit]

  • The class .col-container is a functional wrapper to have elements equal items in a horizontal list
  • The class .cc-3 (only works in combination with .col-container) defines a horizontal list with 3 columns
  • The used CSS technique is display:flex;
  • Defined in

Color schemes[edit]

  • There are 4 double color schemes available for usage in different contexts to your liking. Classes:
    • cs-red, cs-red-light
    • cs-green, cs-green-light
    • cs-blue, cs-blue-light
    • cs-yellow, cs-yellow-light
  • Usage: Simply add one of the 8 classes to a class-attribute in an html element of your choice
  • They affect background-color and color
  • They are defined in

Columns: use-2-columns, use-3-columns[edit]

  • These classes can be used on any element, which has display:block or something similar. The content of the element will be automatically grouped in 2 or 3 columns, separated by lines between them.
    • Note that under a certain page with the class will produce only 2 columns or 1 column to be responsive for mobile devices
  • additional class "strict-list-columns" : If the parent element with the class "use-2-columns" or "use-3-columns" also gets the class "strict-list-columns" then lists ul/ol will be kept together in 1 column. This can be broken by inserting <div></div> into a list to break it cleanly into two and let those 2 lists be in different columns
  • sub class "keep-together" : This class can only be effectively used under the "use-2-columns" or "use-3-columns" class. Usually without "keep-together" the 3 columns will be automatically reorganized to occupy as little vertical space as possible. Thereby it will separate line which is sometimes not desirable. To keep lines together wrap them in a span with class "keep together". Example
<div class="use-3-columns">
<li>List element 1</li>
<li><span class="keep-together">List element 2</span></li>

Example 2 in a Template with "strict-list-columns"

<div class="use-3-columns strict-list-columns">
* List element 1
* List element 2
* List element 3
* List element 4

General utiliy style classes[edit]

Special classes are generic classes that are applicable to various html elements. Relevant file mostly

  • class "width-100" : an element gets the style width:100%
  • class "text-align-center" : an element gets the style text-align:center
  • class "vertical-align-middle" : an element gets the style vertical-align:middle
  • class "margin-left-5" (margin-right/top/bottom-0/5/10/20) : adds margin 0, 5, 10 or 20 px in any direction to an element
  • class "vspacer-10" (-0/1/2/3/4/5/10/20/30/50) : block element with no float and 100% width and the given height to make a vertical gap (vspacer = vertical spacer)
  • class "pos-1px-up" (pos-1px/2px/3px-up/down) : positions the element relative and moves it up or down 1, 2 or 3 pixels
  • class "fontsize19" (19/21) : Gives the element font-size: 19px

hide-enlarge and thumb-hide-enlarge class[edit]

  • A thumb image will usually have an enlarge Button to show the images in full. This is sometimes not desirable. But thumb is sometimes the only useful image option (see #Images, Files and usage of thumb). Therefore thumb can be augmented with one of 2 classes hide-enlarge and thumb-hide-enlarge.
  • thumb-hide-enlarge is the general purpose solution for all thumbnails. Simple wrap a division with the class "thumb-hide-enlarge" around the thumbnail
    • example: <div class="thumb-hide-enlarge">[[File:Swift 128.png|thumb|100px|link=|SWIFT]]</div>
    • The enlarge button will be hidden. And the image description text will be centered
  • The second option is a shortcut but only works on thumbnails without the link parameter. You can add the class parameter with the value hide-enlarge to the File-tag
    • example: [[File:Swift 128.png|thumb|100px|link=|class=hide-enlarge|SWIFT]]
    • The effect is the same as with the wrapper

info-box class[edit]

  • used for container elements to give them rounded borders, a white background and a shadow
  • it is used in the Template Box, see: #Box_and_MBox
  • There is a special class "ib-for-thumb". Read about it in #Box_and_MBox

intro-p Intro Paragraph class [DEPRECATED][edit]

    • In the past it was used for an intro paragraph at the box of the page, but can also be used elsewhere to highlight text
    • Allowed secondary usage in the past: <div class="intro-p">Here is your intro-text</div>
  • Now you should always use the template #Intro_paragraph

NoJS classes[edit]

  • The site is generally NoJS compatible. However for JavaScript (JS) users we offer some JS features to make the visit more comfortable.
    • The JS enhanced elements work without JS, but with JS they have full functionality.
  • IMPLEMENTATION: For no-JS users we have special styles which are only applied if the user has JS deactivated
    • These styles make use of the Mediawiki classes "client-nojs" and "client-js" in the <html> top element. These classes are not added via Javascript but on the server-side which prevents content shift and makes it a very good solution
    • In there are also some style for NoJS
    1. We introduced new classes to show content specifically for NoJS or JS users. These classes are
      • .show-for-nojs-only: show content only if the user has no JS activated
      • .show-for-js-only: show content only if the user has JS activated
      • .hide-for-nojs-only: hide content only if the user has no JS activated
      • .hide-for-js-only: hide content only if the user has JS activated
      • Example: <div class="show-for-nojs-only">Text is only show when JS is not active</div>
    2. On the CSS side you can use html.client-nojs .your-element {...} to style it for nojs users or html.client-js .your-element {...} to style it for js users

"NoScript" browser extension: Special style fixes[edit]

USAGE : Server Scripts[edit]

Images Export Import[edit]

There are two different scripts on the server.

  • images-download-from-kicksecure
  • images-download-from-whonix

This was last tested in March 2022 and worked great.

Currently broken due to upstream bug: grabFiles.php broken in MediaWiki 1.38 due to MediaWiki API

Images Export Implementation Details[edit]

Not important. Only for interested readers.

Implemented using The following commands would need to be adjusted and executed on the server.

sudo -u www-data php mediawiki-tools-grabbers/grabFiles.php --url
sudo -u www-data php mediawiki-tools-grabbers/grabFiles.php --url

Rejected tasks[edit]


pagespeed - missing source maps[edit]

related to feautre slider SplideJS

Missing source maps for large first-party JavaScript


  • Problem was checked
  • We're dealing here with our own auto-generated source maps and wiki source maps and a splide source map
  • Hard to say if the source maps are wrong or if pagespeed is wrong
  • Fixing this could take a couple of hours because probably a lot of research is needed (AI could not give quick fix ideas either) into understand source maps in detail, understanding how mediawiki does it, how splide does it and how our autogen (uglify/minify) does it
  • Very probably not feasable

Tor Browser Maximum Security Slider Setting[edit]

Tor Browser Maximum Security Slider Setting - fix logo text version for[edit]

With Tor Browser security slider set to maximum, the logo text looks bad.

This is happening because the SVG cannot be load by Tor Browser - which is OK. But would be nice if the text version could look a bit better.


TODO: please fix, if feasible


  • Done
  • Research was Done. Img not loaded alt text not really stylable except with some workaround (but hack not needed)
  • Admin decided not worth it
  • Dev did some styling so alt text looks decent enough to not be a great distraction

Tor Browser Maximum Security Slider Setting - homepage - SUID Disabler and Permission Hardener too large[edit]

Image for card SUID Disabler and Permission Hardener is too large.


  • Cannot be reproduced
  • Testing in general (with the other task) showed that browser cache busting seems very bad in Tor browser (safest settings). Even with version parameter Tor browser seems to ignore it. After 10 or so reloads it randomly got the new version
  • And this was NOT ONLY on the onion but on the clearnet address as well

Tor Browser Maximum Security Slider Setting - registered sign[edit]

Looks bad.

  • Kicksecure
  • Whonix

TODO: please fix, if feasible


  • Not feasable
  • As Tor browser safest ignores our custom font the font that it loads depends on the user computer and installed fonts there. Any attempt to style will look good on one computer and bad on others

The following tasks have been considered for realization but have been rejected due to the contra arguments.

feature slider - pop out effect bug[edit]

When the slider card on the left pops out, it cuts the text on the left side.

Same for rightmost slider card.


  • Discussed with admin
  • rejected (because user can read fine in normal state)

donation appeal page[edit]

todo: discuss


  • In principle we already have a donation appeal page - that is Donate
  • There the appeal is written on the left side with the image accompanying it
  • Of course this can be more optimized and standalone or look like standalone
  • The key question is: Does admin want this page as a new page or to replace Donate?
    • If it's a new page what would be the exact use case? - Post this page in forums and social media as kind a of "donation landing page" to motivate the own fanbase? - Or motivate new customers? - But then the homepage would be better to first interest users, get them to use Whonix, and then motivate them to donate
    • If it's a replacement, Dev suggests
      1. "scapping" everying that is not needed from the page including footer and work in progress notification.
      2. Keep the header so the user still knows they are on the Whonix wiki and they can navigate back
      3. Stylize the page using HTML via a widget and still using our assets that we build, for example the Paypal widget which could be opened via modal (like Thunderbird does it) or via expandable box

tab controller - closed by default[edit]

todo discuss

  • A) close tab controller by default and only open if user clicks it?
    • maybe bad for seo?
  • B) first tab says "select your platform"?
    • maybe also bad for seo?

Both can look weird. For example the user would be greeted with very little content.

Maybe appropriate for

|title= = Verification Method Selection =
Select either OpenPGP or signify.
}} <!-- close tab: verification method selection -->


  • This could be indeed a useful feature for certain use cases
  • Dev suggests the following solution
|closedInitText=Select either OpenPGP or signify
  • It's solved with a single parameter that is very expressive "Closed initialization text", meaning it's initialized as closed, but you have to give a text so the user knows what's going on
  • This tasks will prob take 2-3 hours also, because the open-by-hash function has to be adjusted for "closed controllers"

CodeSelect spacing bug[edit]

      - $tag:whonix-updatevm $default allow,target={{project_name_gateway_vm}}
      - $tag:whonix-updatevm $anyvm deny

- $tag:whonix-updatevm $default allow,target=kicksecure - $tag:whonix-updatevm $anyvm deny


  • The problem was researched by DEV
  • The problem seems to lie with mediawiki: MediaWiki "eats up" all the white spaces (incl. line breaks) after a parameter declaration "param=", so in the case above in the first line the white spaces are eaten up
  • Dev could research a solution for this if admin wants. Time for a solution probably 30 min, time for a good solution 1h - 1,5h

Remove Edit from Search engine index #2[edit]


  • Research was done. This was found
  • Dev suggests
  • A) Disable it altogether for anons (easy solution, but maybe not wanted)
    • Patrick: Yes. Not a good solution because Kicksecure / Whonix got a lot useful anon contributions.
  • B) NOEDITSECTION is probably not very useful
    • Patrick: True. Same as A).
  • C) CSS might help as you see with the Google quote, but that might be a more complex solution because we would have different solutions for NOJS and JS. And on NOJS it probably would have to be invisible anyways

update #2:

  • question: Does this bug happen with MediaWiki upstream?
    • If yes: todo: Please write a mediawiki bug report draft that EDIT buttons are indexed and this should be prevented by using something similar to our Template:GoogleOff (the div tags, not the template).
    • If no: Is this caused by our EnhanceHeadlines?


Eager image widget[edit]


  • Dev and admin talked about a template or widget which would make it possible to load an image eagerly
  • This does not seem possible without an extension. Widget does not take a rendered template, but only wikitext as plain text. Therefore widget cannot get the dimensions and other attributes of the image. But that would be needed so the widget could replace loading="lazy" with eager
  • Dev thinks the only solution would be an Extension

check integrity of user downloaded files[edit]

does HTML a href support integrity= for user file downloads?

is there any Javascript that i can install on my website that causes on click a file to be downloaded to user's computer and integrity checked?

integrity="sha384-B2v2d...">Download Example File
function downloadAndVerify(url, expectedHash) {
  const link = document.createElement('a');
  link.href = url; = url.split('/').pop();
  link.integrity = expectedHash;

// Example usage:
const url = '';
const expectedHash = 'sha384-B2v2d...';
downloadAndVerify(url, expectedHash);


Imagine that one stores his downloads at C:\CompanyName\RealName\PhoneNumber\Adress\

    • This is due to security risks being exploited in the early days of Javascript, so now Javascript is in a Sandbox
    • In the case of Tails it is possible because the user explicitly selects a filepath in an input:file field and therefore tells the browser. But it's different from a download prompt which is not accessible via Javascript
    • This post has an excellent summary of our problem

      As i've found from years of maintaining download.js, there simply is no way to tell from JS (or likely in general, see below) what a user chooses to do with the download Open/Save dialog. It's a common feature request, and i've looked into it repeatedly over the years. I can say with confidence that it's impossible; I'll joyfully pay 10 times this bounty if someone an demo a mechanical way to determine the post-prompt user action on any file!

  • There might be clever workarounds to seem when the download has started and ended however, because this is also not directly possible
  • But it seems very much so that the complicated way tails is doing it is the only way at the moment.



  1. Downloading via JavaScript can be done in various ways. But StreamSaver is probably the best or even the only option because the files are so large (e.g., 2.2GB for Whonix). If we download them with JavaScript, everything will be held in RAM and could potentially crash the browser. This becomes especially problematic when we also want to calculate the hash.
  2. StreamSaver, on the other hand, breaks the download into small chunks that are manageable for the browser and continually frees up memory.
  3. The problem is: How can we calculate the hash if we only ever get chunks and never the whole file?
  4. If it's possible, and I understand it correctly, then this developer here has described a process. Although I understand that he is loading the file in chunks from the disk. But we should also be able to apply this during the download:
  5. Conclusion: I now believe 70-80% that we can achieve this. But: It can take a while. And I can't make a guaranteed statement up to the "crucial point".
  6. But if admin says that theoretically, the total hash can also be calculated on the chunks, then this article I linked might be correct. And then I think it could work with StreamSaver.js.


Sufficient Color Contrast[edit]

Warning about insufficient contest might be true. As per:

reload content shift[edit]

  • Write a bug report for chrome content shift


  • As a draft, so admin can decide if this should really be reported to MediaWiki team
    • Chrome seems to reload pages from the bottom up
    • So every time there is a vertical content shift ABOVE an element Chrome has "jumping" issues


page reload in Chrome results in vertical content shift


When using Chrome there is bug which occurs when a page is reloaded and there is vertical content shift happening.

As Chrome does seem to reposition the view of the browser window from the page bottom up when there is content shift on the page, Chrome isn't able to position the browser window on the exact same scroll height as before but often a couple of pixels off.

This affects MediaWiki and Wikipedia on longer articles where there is a good chance of at least a bit of content shift is happening.

A problem with this bug is that it seems not very predictable in nature. So to reproduce you have to load 3-5 long articles on MediaWiki / Wikipedia and jump to the middle or lower half and reload the page a couple of times. Scroll up or scroll down a little bit and reload again. Where e. g. in Firefox after reload you would be on the exact same position after reload with Chrome you can often see the page "wander around" moving up or down in increments of a couple of pixels each time.


We cannot really say it's a known chrome bug if no bug report can be found for chrome.

Is it really a chrome bug happening all over the internet? doesn't seem to have this bug. For demonstration:

1. go to a very long page in such as for example

2. reload the page either using F5 or pressing enter in the address bar

This bug only happens for example on when reloading the page.

The bug also doesn't happen on one of the longest pages in the Kicksecure wiki

The bug only seems to happen on Dev/mediawiki.

We could say it's not important enough to investigate this bug because it happens only on one page that isn't focused on users? Otherwise finding out what part results in the content shift would require copying the full content of Dev/mediawiki to a testpage and then keeping removing (bigger) chapters until the bug can no longer be reproduced to find out which part of the wiki markup is causing it.


Minify HTML for wiki.min.js (2023-02-13)[edit]

TODO: discuss


  • Even the main wiki document (, Main_Page, About, FAQ, all pages) has non-minified HTML.
  • Improvement is possible in theory (nginx module pagespeed but currently doesn't seem under active maintenance).
  • JS loads slow, with fetchpriority=low anyhow and is deferred. Therefore file sizes and CPU speed should be neglible.
  • Speed test websites do not suggest to minify HTML.
  • MediaWiki performance team doesn't think it helps:

MediaWiki Special Pages CSS Enhancements[edit]

  • There was an issue that the text logo (vertically long) broke MediaWiki special pages because the logo was too long.
  • There is a solution to create a localWiki CSS file where these types of corrections for wikis are made but not globally (MulitWiki) but locally. This file would have to be referenced in mw-combine.
  • Admin rejected this idea due to complexity and uploads another image instead

MediaWiki Clean vs Unclean Links[edit]

Magic Variables Clearnet/Onion[edit]

  • introduce our own magic variables, especially one to differentiate in templates and widgets between clearnet-request and onion-request
    • This is especially useful in cases where a different link needs to be shown depending if it's onion or clearnet. And if that link is not relative
    • Then give task to dev, so he can fix VirtualBox and remove onion extra link
  • Cumbersome to implement and not that important because there are separate onion download links.

Expand Button new[edit]

  • usually expand areas are created with .mw-collapsible and .mw-collapsible-content
    • But this is a JavaScript solution and does not work for nojs users. For them the area is automatically expanded
  • A new solution would be to create a widget which creates and expand container and button and content area
    • This solution uses checkboxes for nojs users and a js solution for JavaScript users
  • A second widget might me "Expand All / Collapse all button, like on page Documentation
    • For nojs users this might also be a checkbox which works in tandem with the other new widget for Expand buttons
      • A challenge might be that the Expand all checkbox always has to be on the same level as all parent elements of the lower level expand buttons
  • An alternative variant to the Expand all button might be to introduce a parameter to the expand button widget like "nojsexpanded" where the behavior is like with the current mw-collapsible solution and all areas are expanded if JavaScript is not active

Sitenotice no-JS Version[edit]

  • The Sitenotice usually is not dismissable by the user
  • We use Extension:DismissableSiteNotice so the user can click away the Sitenotce
  • But the extension has a big flaw. On line 55 to 75 (see git of the you can see the dev delivers the sitenotice via JavaScript
    • This means the sitenotice is not even visible if the user has JavaScript deactivated.
    • This is not desired behaviour. We want every user to see the notice. And JS users just have the additional luxury of being able to dismiss the sitenotice
  • Solution suggestion
    1. We deactivate Extension:DismissableSiteNotice, because the JavaScript way was a deliberate choice of the dev, so even if we can fix the extension the dev very likely won't accept our solution upstream
    2. Without the extension the Sitenotice will be there for every user.
    3. We write a JavaScript file to make Sitenotice dismissable which saves this info into a cookie similar to Extension:DismissableSiteNotice, so only JS users have the comfort to dismiss a Sitenotice

Patrick said:

CodeSelect Show Copy Contents Feature[edit]

  • pro
    • Would it be possible, and make sense to shop a popup what exactly has been copied to clipboard?
    • Maybe useful for the new donation widget?
    • Maybe useful generally, globally?
  • contra
    • In probably 99.9% of cases the user will immediately insert the contents they just copied into another form or programm. Therefore he will see the full copied content immediately afterwards anyways. So this might be superfluous

pay what you can for donate panel[edit]

  • pro
    • does it
  • contra
    • Confusing for users which might wonder:
      • Do I get the same version if I choose 0?
      • Seems like this cannot be downloaded for free.

External Redirections Enhancements[edit]

status: wait

Waiting for new magic words mediawiki extension. improvements

example external redirect:

  • solution?
    • Can we change
    • {{#externalredirect:}}
    • to
    • {{#externalredirect: {{kicksecure_clearnet_or_onion}}/wiki/OpenPGP}}
    • ?
  • goals:
    • protocol handler respecting redirect.
      • redirect Whonix https visitors to Kicksecure https
      • redirect Whonix onion visitors to Kicksecure onion
  • notices:
    • title: Redirection
    • "You are being redirected. Will redirect in 5 seconds to Kicksecure website."
    • "Whonix is based on Kicksecure"

mininav CSS Improvement[edit]

  • pro
    • The style for example on A) USB_Installation "table abuse" looks a bit nicer than mininav for example B) Dev/website.
    • "table abuse" is shows all navigation options in the same line on mobile which is great.
    • "table abuse" has a nicer border?
    • "table abuse" has a nicer background color?
    • mininav splits it into multiple lines below each other which is non-ideal.
  • contra
    • mininav is designed with modern standards and especially mobile devices in mind
    • the bottom border indicated like with tabs where the user is at
    • the tabs can be on one line or multiple lines and are therefore responsive
    • the design is subtle and nice and integrates with the rest of the visual language (gray background for code, but white for functional elements of the website)

homepage html optimizations[edit]

For Kicksecure and Whonix homepage. To reduce DOM size.

Something doable, useful here?

Instead of using this code;

<div id = ”navigation-main”>


            etc ..



It would be better to use this other one;

<ul id = ”navigation-main”>

    etc ..



  • That would be a small optimization, but nothing substantial for the DOM
  • And it would require a lot of work because styles have to be rewritten, sometimes even JS scripts (at least the references)
  • I advice against it

critical css test[edit]



  • A simplified test if critical CSS inclusion into the head results in faster website speed at all.


  • Making mediawiki use critical CSS. How to integrate this with mediawiki will be considered at a later time in a separate task.



  • 1) Use a browser where you are logged out and have no cookies. This is because cookies and being logged in has an influence on the HTML provided by mediawiki.
  • 2) on /test/ add Kicksecure homepage with the normal HTML document that we have now: kicksecure-hp-normal-not-critical-css.html. This will be needed for speed comparison.
  • 3) create a copy kicksecure-hp-critical-css.html
  • 4) use some tool to extract the critical css. add the critical css to the head. (
  • 5) out-comment all other CSS for a simple test. Search the HTML document for stylesheet. (CSS load with media="print" onload="'all'" can and probably should be ignored and left enabled as it already loads async.)
  • 6) load all other CSS async
  • 7) compare speed of the two different HTML documents


version FCP LCP TBTime CLShift Speed I
normal 1.1s 3.4s 330ms 0 2.2s
coreweb 2.0s 3.8s 360ms 0 2.9s
sitelocity 1.4s 2.3s 360ms 0.186 2.1s
  • Conclusion: It seems that
    • Critical CSS works. But it's not speeding up the page
    • This might be because critical CSS is already very large in both versions
    • sitelocity seems to be better with LCP, but has a content layout shift which is not good
  • Dev cannot clearly say what happened here. Instructions were followed as described on the pages

Maybe Future TODO

MediaWiki:Page_Homepage.css Question[edit]

Only a question.

Could be embedded inline into widget:Page_Homepage? Good idea?

Reason: Potential website speed improvement?

Would get rid of (the only call to index.php), would get rid of 1 additional file to download.

Might not be needed if nginx server side PHP caching speeds this up.


  • Yes, Page_Homepage.css could be embedded
    • Pro: That would improve parallel loading (because the CSS is there earlier). Speed COULD therefore improve a little bit
    • Con: But that would inflate the page even more (which would also negatively impact the PageSpeed "Dom is too large" warning
  • Alternative idea: Load the script directly from /mw-autogen/src-copy folder. This needs some small tweaks, probably in config-build-{shared and specific} and/or mw-combine, but might be reasonably quick

Whonix Homepage Video[edit]

simplify noJS version[edit]

For the more beautiful, feature-rich implementation related to all of these video tasks, would it help if the noJS version would be further simplified?

Potentially acceptable for the homepage noJS version:

  • just show the illustrative image
  • direct link to the video
  • video download link
  • could offer many different quality / size versions
  • YouTube link
  • no need to play inside the homepage

Separate JS version[edit]

Should we add a more pretty video player if JS is available?

The HTML5 player is nice for noJS but has some probably unfixable issues. When playing the video over a slow connection (slow internet; Tor; onion) it starts, is then stuck, loads, play again. That is not very useful. This leads missing the hear the first few seconds of the video and no bearable video experience. Hence above chapter "simplify noJS version".

If we decide to use a JS based video player... Is there a video player for slow connections that

  • can buffer the first 10-20 seconds or so?
  • lower the video quality?

Streaming Protocols - RTSP RTSPS HLS[edit]

What we want is "VOA" - "video on demand". Only playing simple videos. No live streaming.

For adaptive bitrate streaming (lowering the video resolution and quality over slow connections), the server would need to support RTSP (actually RTSPS for better security) and HLS? Patrick did preliminary research and thinks its doable.

research video players[edit]


  • must be Open Source
  • installed to or so (not fetching from third parties such as jsDelivr)
  • can be JS based
  • with HTML5 only (noJS) features are probably limited and no players available?
  • avoid NPM (seems very pretty much doable, players that Patrick has seen are deployed as a single JS file. Trivial to install on the server.)

feature wish list:

  • remember video playback position after reload
  • see also requested features above

review todo:

lazy load player[edit]

If we use a JS based video player, should it be lazy loaded to avoid increasing load times for normal visits?

CSS restyle html5 video controls[edit]

  • Controls always visible because otherwise just a big black area that looks broken over slow connections
  • add additional buttons


remember video playback position after reload[edit]

video gallery[edit]

Would it make sense to add a video gallery / switcher using arrows so users can watch the other two Whonix explainer videos too?


GoogleOff- exclude from google - whonix RAM wiki page[edit]

google search term: "Social Share Button"

(Nobody uses this exact search term. For demonstration purposes only. But it shows that something gets indexed which then shows up in other search results where it should not.)

The following is the Google search results:

See Also Social Share Button

TODO: please exclude "Social Share Button" from google


  • Admin decision needed
  • Dev checked all the instances in Google and checked all the pages for the mentioned Social share button
  • In every case this is in the Share Tooltip Privacy Policy section. The text before "See Social share button" is from the Tooltip. The text after that phrase is from the content page
  • So it could be the case that all these pages have been crawled before the html googleoff wrapper was added to Share Tooltip. Because the wrapper seems correctly used and should prevent google crawling this
  • There could also be a Google bug. Or maybe the used GoogleOff incorrectly still.
  • However if we move forward with this task we probably need to find a way to certainly say what the exact problem is


  • archived and waiting if it goes away, can be re-opened later

CSS class="image"[edit]

CSS class image is used on Whonix homepage.


This is a MediaWiki class:

mediawiki code editor warnings[edit]

For example shows errors.

  • Worth fixing?
  • False-positives?


  • Problem was researched
  • Wiki editor for CSS and Javascript is based on Ace Editor
  • Utility.css was tested with newest version of Ace Editor. No problems were found
  • Dev has also seen warnings in other files, but always ignored them because the CSS works. And usually if there's a relevant problem in a CSS file then the whole file or at least everything after the error does not work
  • Dev thinks that this problem is cause by the Extension either not using the newest Ace editor or not using the newest (not really so new) CSS specifications

Google Mobile-Friendly Test wants larger font sizes[edit]

Google Mobile friendly said that fonts are too small for mobile.

The problem with is that it does not download all CSS due to crawler limits. Its judgement is based on incomplete CSS. Lighthouse does not find any issues.

archived ideas:

Use [[Special:ReplaceText]] to search for mentions of <code>font-size:</code>?

Kicksecure and Whonix wiki.

This is to fix google "font too small" warning.

Use to reverse engineer this?

* Create a few (mobile-only) HTML-only test pages with different font sizes to find out the smallest acceptable font size.
* test with

For example itself uses small fonts and passes the test for itself.

How to see font size in browser console in chromium:

* select text -> right click -> inspect -> <code>computed</code> -> scroll down to font size


Preliminary research. Please check if it does something other than automation which isn't needed yet.


  • After Research Dev would actually recommend using Unlighthouse
  • Cons
    • Yes, it mainly uses Lighthouse and analyses all pages. But it offers a great overview
    • It also does not seem very popular yet, has few reviews and is not listed on AlternativeTo. But the project is also very young (version 0.1.0 released in 2021-12)
  • Pros
    • It scans the whole website like a search engine using robots.txt and sitemaps
    • It has a very intuitive interface, which can be tested here:
    • It lays out the Lighthouse info more clearly, for example with SEO overviews for each page with a SEO score, link counts and ADDS own information like description preview, share image preview
    • For best practices it counts inspector issues, image aspect ratios etc. All Lighthouse functionality but better presented in table form

Web Vitals Extension[edit]

Preliminary research. Please check if it shows something useful we haven't addressed or discused yet.


  • Research was done
  • This plugin basically uses the same metrics as Lighthouse and Pagespeed - concentrating on Largest Contentful Paint, Cumulative Layout Shift and First Input Delay. It basically does the same thing, but presents it in a more practical sense
  • Pros
    • You have and "ambient bagde" - color indicator how a site is doing: red / yellow / green. And you can go through them easily by just clicking the badge
    • It also offers an overlay (click to hide) with more information
    • When using the Console logging then some more metrics are available than in Lighthouse
  • BIG PRO: Whenever clicking an element you can see the FID. And after that every subsequent interaction. This is an "interactive metric" that Lighthouse does not offer
  • Cons
    • It eats some RAM, so only activate when needed
  • Video: Overview by the creator:
  • Video by fireship:

Defer Upstream MediaWiki JavaScript[edit]


<script defer src="/w/load.php?lang=en&modules=startup&only=scripts&raw=1&skin=vector"></script>

Patrick could server side easily rewrite that to:

<script defer src="/w/load.php?lang=en&modules=startup&only=scripts&raw=1&skin=vector"></script>

(Nobody uses script defer but upstream said that is not a syntax error.)

please compare the speed and functionality on on (already existing, caching disabled there)


  • defer and async were introduced due to admin research
  • Upon Dev research it seems that using defer and async together is redundant and not advised
    • async fetches the scripts asynchronously and executes them as soon as they are ready
    • defer does the same but waits for the whole HTML document to be ready and only then executes the script
  • If both are present
    • New browsers will prioritise async and ignore defer
    • Older browser don't know async and will prioritize defer
  • Two tests were written
  • Here are the results as averages after 3 tests each with pagespeed
metric async defer
FCP 1.2s 1.1s
LCP 3.5s 3.4s
Total Block T 440ms 443ms
Speed Index 2.1s 1.9s
  • Dev also tested the functionality and in both cases the pages seemed to perform normal and fast enough for the users
  • Dev recommends using only defer
    • It seems to perform slightly better
    • Most of our customs scripts are designed to perform only after the document is loaded anyways
    • Async would only be sensible where there needs to be a fast loading page (so the document does not have to wait for the scripts), but where there are "non-document asap calculation steps" done in Javascript

Total Blocking Time[edit]

Total Blocking Time went up on google pagespeed for mobile. Ideas why? Anything changed? Related to uglifyjs?


First Contentful Paint 1.6s / 1.7s 1.1s / 1.2s 1.1s / 1.2s 1.1s / 1.1s
Total Blocking Time 50ms / 70ms 370ms / 580ms 110ms / 220ms 370ms / 210ms
Speed Index 1.8s / 1.9s 1.9s / 1.9s 1.6s / 1.4s 1.7s / 1.5s
Largest Contentful Paint 3.3s / 3.4s 3.0s / 3.6s 3.4s / 3.7s 3.4s / 3.0s
    • Analysis
      • It seems the only metric truly affected IS total blocking time, the rest is pretty much the same
      • It seems also obvious that the new scripts - prism and instant page - have a significant impact on TBT, but are NOT the only reason because without scripts (meaning also without combined.min.js) it's still not as fast as before
      • Dev did a diff of OLD and NEW and saw some differences and found that in flyinnotification the image should be decoding="async" loading="lazy" which was already fixed too but didn't change much for pagespeed
      • Dev also thinks it's possible that deferring Javascript leads to a worse TBT, because [Total blocking time] = [Time to interactive] minus [First contentful paint] → so the longer JS is deferred the longer it might take to reach time to interact. That is however just a speculation. This page here is a great overview over the topic - not that this page states "It is important to specify that Time To Interactive is not a standardized indicator. It may therefore evolve. Note also that, although Google has included this metric in the calculation of the Lighthouse and PageSpeed Insights score, its weight has decreased during recent changes in the calculation of the score, to the point that it seems to be bound to disappear eventually."
      • Here is some more explanation for total blocking time and suggestions to improve and possible reasons why it might have increased in our development
    • How to proceed
      • Dev suggests admin to define a course: Invest more time into improving this metric or waiting for this metric to phase out?
      • Because - this was not mentioned before - there were also tests done with gtmetrics which gave very good results and slightly worse results when the "connection" was heavily throttled, indicating that maybe only server speed or dome size could be improved


  • also happens with mediawiki therefore probably a pagespeed bug or less likely a mediawiki issue
  • compare with a few other popular websites if they also have this issue now (which might be just a pagespeed bug)
    • therefore not much time need to be used to analyze if we're causing the issue ourselves
  • check with chromium 112 with built in lighthouse in chromium developer toolbar
    • Lighthouse 10 will be available in Chrome 112, currently scheduled for release on March 29, 2023.
  • Pagespeed performance dropped significantly due to total blocking time

Layout was forced console warning[edit]

On with Firefox (new browser profile).

Layout was forced before the page was fully loaded. If stylesheets are not yet loaded this may cause a flash of unstyled content.


MediaWiki Logo HTTP2 Server Push Preload[edit]

MediaWiki by upstream default sends a response header which does a HTTP/2 Server Push. Example:

link: </w/images/2/2a/Kicksecure-text-logo.svg?b0edc>;rel=preload;as=image

Not on the main HTML document but for the CSS load.php. Example:

MediaWiki by upstream default uses the $wgLogos configuration variable to determine the link to the logo.

However, the hash ?b0edc is auto generated by MediaWiki and after a cursory look at the source code it seems this cannot be disabled.

This causes the following warning with our custom skin:

The resource was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate `as` value and it is preloaded intentionally.

This is because it does not know the hash ?b0edc.

HTTP2 Server Push is being deprecated by upstream browsers:


session cache disable[edit]

In case there are login issues, the following could be attempted:$


Notes by Patrick[edit]


Entry point is always Mediawiki:Common.js?

Dev: Common.js has been transformed into a standalone library and is therefore now marked as Multiwiki. Common.js now imports which is NOT MultiWiki (see Dev/mediawiki#Multiwiki_definitions). This is done so Common.js is a true library and ImportScripts is now LocalWiki specific and there can be individual imports. Note: ImportScripts is loaded at the bottom of the file for call order reasons, therefore every loaded file will have the wikiJsLoader already available.

To disable all, remove all from Mediawiki:Common.js?

Dev: To disable all remove the following line at the bottom of Common.js

mw.loader.load( '/w/index.php?title=MediaWiki:ImportScripts.js&action=raw&ctype=text/javascript' );

What if in the future 1 script breaks? Do all scripts break?

Dev: The wikiJsLoader is totally independent and optional to use. You can call scripts the usual way as before. But now you also have the option to call scripts dependent on each other by using wikiJsLoader. If 1 script breaks this will only affect the script itself and all scripts which are made dependent on this script by using wikiJsLoader. But if those scripts are dependent on a broken script you will have to fix this script anyways to get those scripts running again.

Does a unloadable script show an error in the browser console?

Dev: No. This is because all scripts are loaded asynchronously and the loader is specifically built to load a script only when it is ready. However we could use a timer and show all unloaded scripts after 3 seconds, because it should never take this long to load all the scripts. Or we could write an internal log, which can be called to list all actions by the loader.

What is window.?

Dev: Window is a JS Object representing the browser window. It is always available and represents the "global namespace" where all global objects are referenced.

How can I manually debug, execute,,

Dev: You can manually load as usual

mw.loader.load( '/w/index.php?title=MediaWiki:MiniModal.js&action=raw&ctype=text/javascript' );

Dev: Or you can use the wikiJsLoader as follows. This is only needed recommended for scripts which are dependent on others.

window.wikiJsLoader.register( 'MiniModal', [], false, function() { ... });

window.wikiJsLoader.exec( ['MiniModal'] );

How to print a debug message with variable name and content to browser console?

Dev: A convenient way is to use console

var whateverYouWantVariable = "String or Object or Boolean or a system variable whatever"; "whateverYouWantVariable: ", whateverYouWantVariable );


No longer in use.

load.php caching[edit]

load.php debug mode[edit]

?pagespeed has no effect on CSS or JavaScript loads

  • debug=true

49 JS 12 CSS

  • debug=false

26 JS 1 CSS

instead of


we have

  • load.php?[...]modulename.namespace.tool
  • load.php?[...]modulename.namespace.tool2
  • load.php?[...]modulename.namespace.tool3
  • load.php?[...]differentmodule.tool

Old CSS Checklist[edit]

These are actually done but written as if they are not done:

  • On for example FAQ the long title Frequently Asked Questions - Whonix ™ FAQ breaks the layout on mobile. Because the title is too long, one has to scroll to the right side on mobile to read the title in full. Does the title miss some attribute such as "autowrap", "break line if too long"?
  • Images for example on Main_Page and About are not response rendered smaller on mobile.
  • blockquotes don't really look like a quote. example:


  • beautify breadcrumbs (zB < dev on top of this page)

Wiki Js Loader[edit]

  1. As per now our research shows no option of the MediaWiki mw.loader API to load our own scripts and make them dependent on each other. So user script dependency does not seem to be supported
  2. Therefore we created our own resource loader under window.wikiJsLoader, see Mediawiki:Common.js. The challenge is to provide a mechanism to load modules which are yet unknown and which can only be known once they are loaded and registered due to the asynchronous loading by mw.loader.load
    1. Caution: Circular dependencies are not resolved and will be a roadblock for all batches containing these.
  3. The loader offers 4 methods
    1. register( name, dependencies, waitForCallback, fn ) - This method registers a function (fn,type:function) in the registry, including its module name (name,type:string), its dependencies (depedencies,type:array-of-strings, other user module names) and if the whole mechanism should wait for their callback (waitForCallback,type:boolean)
      1. The function fn will get the following parameters: fn(global, callback). global is the getter-setter described below.
      2. If waitForCallback is true then the registration will not be considered complete until the callback (calback,type:function) is called via callback()
    2. config( key, value ) - sets a wiki js loader configuration. Currently there is only debug (boolean), if true then all outputs will be shonw, not only warnings and errors
    3. global( key, value ) - getter-setter. If only key (type:string) is given then the value will be returned. If key and value are given, then key will be set with value
    4. exec( moduleNames ) - sets in motion the loading process. moduleNames (type:array-of-strings) are names of our dev scripts which shall be called and executed.
      1. First all depedencies will be checked, if they are not met then the script will not execute futher. But if another register process is completed then load will automatically be triggered again to check if NOW all dependencies are met and we can execute further
      2. This way scripts will be able to execute exactly when their dependencies are met, not earlier. This is especially necessary as the mw.loader seems to load our scripts asynchronously
  4. Relevant files
    1. Mediawiki:Common.js

Wiki Js Loader Usage[edit]

1. All JS files which either have dependencies or are dependencies for others should be wrapped into window.wikiJsLoader.register( 'NameOfThisFileWithoutDotJs', ['ModuleDepedency1','ModuleDepedency1'], false, function() { ... });

2. All other files can be implemented as usual

3. All JS files (including with dependencies) can be called via mw.loader.load(...) as usual

4. To actually execute the managed scripts, use the following. This can be used to execute multiple batches of files or just one big batch window.wikiJsLoader.exec( [ 'NameOfThisFileWithoutDotJs1', 'NameOfThisFileWithoutDotJs2' ] );

Wiki Js Loader Debugging[edit]

MediaWiki Gadgets Extension[edit]

It's been decided not to port to MediaWiki Gadgets. The wiki now now extended as per the mechanisms documented above.

Archived notes:


Unfinished: This wiki is a work in progress. Please do not report broken links until this notice is removed, use Search Engines First and contribute improving this wiki.

We believe security software like Kicksecure needs to remain Open Source and independent. Would you help sustain and grow the project? Learn more about our 12 year success story and maybe DONATE!